00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "KoTextIterator.h"
00020 #include "KoTextParag.h"
00021 #include "KoTextView.h"
00022 #include <kfinddialog.h>
00023 #include <kdebug.h>
00024 #include <assert.h>
00025
00026
00027
00036 void KoTextIterator::init( const QValueList<KoTextObject *> & lstObjects, KoTextView* textView, int options )
00037 {
00038 Q_ASSERT( !lstObjects.isEmpty() );
00039
00040 m_lstObjects.clear();
00041 m_firstParag = 0;
00042 m_firstIndex = 0;
00043 m_options = options;
00044
00045
00046 if ( options & KFindDialog::FromCursor )
00047 {
00048 if ( textView ) {
00049 m_firstParag = textView->cursor()->parag();
00050 m_firstIndex = textView->cursor()->index();
00051 } else {
00052
00053 m_options &= ~KFindDialog::FromCursor;
00054 kdWarning(32500) << "FromCursor specified, but no textview?" << endl;
00055 }
00056 }
00057
00058 bool forw = ! ( options & KFindDialog::FindBackwards );
00059
00060
00061 if ( textView && ( options & KFindDialog::SelectedText ) )
00062 {
00063 KoTextObject* textObj = textView->textObject();
00064 KoTextCursor c1 = textObj->textDocument()->selectionStartCursor( KoTextDocument::Standard );
00065 KoTextCursor c2 = textObj->textDocument()->selectionEndCursor( KoTextDocument::Standard );
00066 if ( !m_firstParag )
00067 {
00068 m_firstParag = forw ? c1.parag() : c2.parag();
00069 m_firstIndex = forw ? c1.index() : c2.index();
00070 }
00071 m_lastParag = forw ? c2.parag() : c1.parag();
00072 m_lastIndex = forw ? c2.index() : c1.index();
00073
00074 m_lstObjects.append( textObj );
00075 m_currentTextObj = m_lstObjects.begin();
00076 }
00077 else
00078 {
00079
00080 m_lstObjects = lstObjects;
00081 if ( textView && (options & KFindDialog::FromCursor) )
00082 {
00083 KoTextObject* initialFirst = m_lstObjects.first();
00084
00085
00086 if ( forw ) {
00087 while( m_lstObjects.first() != textView->textObject() ) {
00088 KoTextObject* textobj = m_lstObjects.front();
00089 m_lstObjects.pop_front();
00090 m_lstObjects.push_back( textobj );
00091 if ( m_lstObjects.first() == initialFirst ) {
00092 kdWarning(32500) << "Didn't manage to find " << textView->textObject() << " in the list of textobjects!!!" << endl;
00093 break;
00094 }
00095 }
00096 } else {
00097 while( m_lstObjects.last() != textView->textObject() ) {
00098 KoTextObject* textobj = m_lstObjects.back();
00099 m_lstObjects.pop_back();
00100 m_lstObjects.push_front( textobj );
00101 if ( m_lstObjects.first() == initialFirst ) {
00102 kdWarning(32500) << "Didn't manage to find " << textView->textObject() << " in the list of textobjects!!!" << endl;
00103 break;
00104 }
00105 }
00106 }
00107 }
00108
00109 KoTextParag* firstParag = m_lstObjects.first()->textDocument()->firstParag();
00110 int firstIndex = 0;
00111 KoTextParag* lastParag = m_lstObjects.last()->textDocument()->lastParag();
00112 int lastIndex = lastParag->length()-1;
00113 if ( !m_firstParag )
00114 {
00115 m_firstParag = forw ? firstParag : lastParag;
00116 m_firstIndex = forw ? firstIndex : lastIndex;
00117 }
00118
00119 m_lastParag = forw ? lastParag : firstParag;
00120 m_lastIndex = forw ? lastIndex : firstIndex;
00121 m_currentTextObj = forw ? m_lstObjects.begin() : m_lstObjects.fromLast();
00122 }
00123
00124 assert( *m_currentTextObj );
00125 assert( m_firstParag );
00126 assert( m_lastParag );
00127 Q_ASSERT( (*m_currentTextObj)->isVisible() );
00128 m_currentParag = m_firstParag;
00129 #ifdef DEBUG_ITERATOR
00130 kdDebug(32500) << "KoTextIterator::init from(" << *m_currentTextObj << "," << m_firstParag->paragId() << ") - to(" << (forw?m_lstObjects.last():m_lstObjects.first()) << "," << m_lastParag->paragId() << "), " << m_lstObjects.count() << " textObjects." << endl;
00131 QValueList<KoTextObject *>::Iterator it = m_lstObjects.begin();
00132 for( ; it != m_lstObjects.end(); ++it )
00133 kdDebug(32500) << (*it) << " " << (*it)->name() << endl;
00134 #endif
00135 Q_ASSERT( (*m_currentTextObj)->textDocument() == m_currentParag->textDocument() );
00136 Q_ASSERT( (forw?m_lstObjects.last():m_lstObjects.first())->textDocument() == m_lastParag->textDocument() );
00137
00138 connectTextObjects();
00139 }
00140
00141 void KoTextIterator::restart()
00142 {
00143 if( m_lstObjects.isEmpty() )
00144 return;
00145 m_currentParag = m_firstParag;
00146 bool forw = ! ( m_options & KFindDialog::FindBackwards );
00147 Q_ASSERT( ! (m_options & KFindDialog::FromCursor) );
00148 if ( (m_options & KFindDialog::FromCursor) || forw )
00149 m_currentTextObj = m_lstObjects.begin();
00150 else
00151 m_currentTextObj = m_lstObjects.fromLast();
00152 if ( !(*m_currentTextObj)->isVisible() )
00153 nextTextObject();
00154 #ifdef DEBUG_ITERATOR
00155 if ( m_currentParag )
00156 kdDebug(32500) << "KoTextIterator::restart from(" << *m_currentTextObj << "," << m_currentParag->paragId() << ") - to(" << (forw?m_lstObjects.last():m_lstObjects.first()) << "," << m_lastParag->paragId() << "), " << m_lstObjects.count() << " textObjects." << endl;
00157 else
00158 kdDebug(32500) << "KoTextIterator::restart - nowhere to go!" << endl;
00159 #endif
00160 }
00161
00162 void KoTextIterator::connectTextObjects()
00163 {
00164 QValueList<KoTextObject *>::Iterator it = m_lstObjects.begin();
00165 for( ; it != m_lstObjects.end(); ++it ) {
00166 connect( (*it), SIGNAL( paragraphDeleted( KoTextParag* ) ),
00167 this, SLOT( slotParagraphDeleted( KoTextParag* ) ) );
00168 connect( (*it), SIGNAL( paragraphModified( KoTextParag*, int, int, int ) ),
00169 this, SLOT( slotParagraphModified( KoTextParag*, int, int, int ) ) );
00170
00171
00172
00173
00174 }
00175 }
00176
00177 void KoTextIterator::slotParagraphModified( KoTextParag* parag, int modifyType, int pos, int length )
00178 {
00179 if ( parag == m_currentParag )
00180 emit currentParagraphModified( modifyType, pos, length );
00181 }
00182
00183 void KoTextIterator::slotParagraphDeleted( KoTextParag* parag )
00184 {
00185 #ifdef DEBUG_ITERATOR
00186 kdDebug(32500) << "KoTextIterator::slotParagraphDeleted " << parag << " (" << parag->paragId() << ")" << endl;
00187 #endif
00188
00189
00190
00191 if ( parag == m_lastParag )
00192 {
00193 if ( m_lastParag->prev() ) {
00194 m_lastParag = m_lastParag->prev();
00195 m_lastIndex = m_lastParag->length()-1;
00196 } else {
00197 m_lastParag = m_lastParag->next();
00198 m_lastIndex = 0;
00199 }
00200 }
00201 if ( parag == m_firstParag )
00202 {
00203 if ( m_firstParag->prev() ) {
00204 m_firstParag = m_firstParag->prev();
00205 m_firstIndex = m_firstParag->length()-1;
00206 } else {
00207 m_firstParag = m_firstParag->next();
00208 m_firstIndex = 0;
00209 }
00210 }
00211 if ( parag == m_currentParag )
00212 {
00213 operator++();
00214 emit currentParagraphDeleted();
00215 }
00216 #ifdef DEBUG_ITERATOR
00217 if ( m_currentParag )
00218 kdDebug(32500) << "KoTextIterator: firstParag:" << m_firstParag << " (" << m_firstParag->paragId() << ") - lastParag:" << m_lastParag << " (" << m_lastParag->paragId() << ") m_currentParag:" << m_currentParag << " (" << m_currentParag->paragId() << ")" << endl;
00219 #endif
00220 }
00221
00222
00223 void KoTextIterator::operator++()
00224 {
00225 if ( !m_currentParag ) {
00226 kdDebug(32500) << k_funcinfo << " called past the end" << endl;
00227 return;
00228 }
00229 if ( m_currentParag == m_lastParag ) {
00230 m_currentParag = 0L;
00231 #ifdef DEBUG_ITERATOR
00232 kdDebug(32500) << "KoTextIterator++: done, after last parag " << m_lastParag << endl;
00233 #endif
00234 return;
00235 }
00236 bool forw = ! ( m_options & KFindDialog::FindBackwards );
00237 KoTextParag* parag = forw ? m_currentParag->next() : m_currentParag->prev();
00238 if ( parag )
00239 {
00240 m_currentParag = parag;
00241 }
00242 else
00243 {
00244 nextTextObject();
00245 }
00246 #ifdef DEBUG_ITERATOR
00247 if ( m_currentParag )
00248 kdDebug(32500) << "KoTextIterator++ (" << *m_currentTextObj << "," <<
00249 m_currentParag->paragId() << ")" << endl;
00250 else
00251 kdDebug(32500) << "KoTextIterator++ (at end)" << endl;
00252 #endif
00253 }
00254
00255 void KoTextIterator::nextTextObject()
00256 {
00257 bool forw = ! ( m_options & KFindDialog::FindBackwards );
00258 do {
00259 if ( forw ) {
00260 ++m_currentTextObj;
00261 if ( m_currentTextObj == m_lstObjects.end() )
00262 m_currentParag = 0L;
00263 else
00264 m_currentParag = (*m_currentTextObj)->textDocument()->firstParag();
00265 } else {
00266 if ( m_currentTextObj == m_lstObjects.begin() )
00267 m_currentParag = 0L;
00268 else
00269 {
00270 --m_currentTextObj;
00271 m_currentParag = (*m_currentTextObj)->textDocument()->lastParag();
00272 }
00273 }
00274 }
00275
00276 while ( m_currentParag && !(*m_currentTextObj)->isVisible() );
00277 #ifdef DEBUG_ITERATOR
00278 if ( m_currentParag )
00279 kdDebug(32500) << k_funcinfo << " m_currentTextObj=" << (*m_currentTextObj) << endl;
00280 #endif
00281 }
00282
00283 bool KoTextIterator::atEnd() const
00284 {
00285
00286 return m_currentParag == 0L;
00287 }
00288
00289 int KoTextIterator::currentStartIndex() const
00290 {
00291 return currentTextAndIndex().first;
00292 }
00293
00294 QString KoTextIterator::currentText() const
00295 {
00296 return currentTextAndIndex().second;
00297 }
00298
00299 QPair<int, QString> KoTextIterator::currentTextAndIndex() const
00300 {
00301 Q_ASSERT( m_currentParag );
00302 Q_ASSERT( m_currentParag->string() );
00303 QString str = m_currentParag->string()->toString();
00304 str.truncate( str.length() - 1 );
00305 bool forw = ! ( m_options & KFindDialog::FindBackwards );
00306 if ( m_currentParag == m_firstParag )
00307 {
00308 if ( m_firstParag == m_lastParag )
00309 return forw ? qMakePair( m_firstIndex, str.mid( m_firstIndex, m_lastIndex - m_firstIndex ) )
00310 : qMakePair( m_lastIndex, str.mid( m_lastIndex, m_firstIndex - m_lastIndex ) );
00311 else
00312 return forw ? qMakePair( m_firstIndex, str.mid( m_firstIndex ) )
00313 : qMakePair( 0, str.left( m_firstIndex ) );
00314 }
00315 if ( m_currentParag == m_lastParag )
00316 {
00317 return forw ? qMakePair( 0, str.left( m_lastIndex ) )
00318 : qMakePair( m_lastIndex, str.mid( m_lastIndex ) );
00319 }
00320
00321 return qMakePair( 0, str );
00322 }
00323
00324 bool KoTextIterator::hasText() const
00325 {
00326
00327 bool forw = ! ( m_options & KFindDialog::FindBackwards );
00328 int strLength = m_currentParag->string()->length() - 1;
00329 if ( m_currentParag == m_firstParag )
00330 {
00331 if ( m_firstParag == m_lastParag )
00332 return m_firstIndex < m_lastIndex;
00333 else
00334 return forw ? m_firstIndex < strLength
00335 : m_firstIndex > 0;
00336 }
00337 if ( m_currentParag == m_lastParag )
00338 return forw ? m_lastIndex > 0
00339 : m_lastIndex < strLength;
00340 return strLength > 0;
00341 }
00342
00343 void KoTextIterator::setOptions( int options )
00344 {
00345 if ( m_options != options )
00346 {
00347 bool wasBack = (m_options & KFindDialog::FindBackwards);
00348 bool isBack = (options & KFindDialog::FindBackwards);
00349 if ( wasBack != isBack )
00350 {
00351 qSwap( m_firstParag, m_lastParag );
00352 qSwap( m_firstIndex, m_lastIndex );
00353 if ( m_currentParag == 0 )
00354 {
00355 #ifdef DEBUG_ITERATOR
00356 kdDebug(32500) << k_funcinfo << "was done -> reinit" << endl;
00357 #endif
00358 restart();
00359 }
00360 }
00361 bool wasFromCursor = (m_options & KFindDialog::FromCursor);
00362 bool isFromCursor = (options & KFindDialog::FromCursor);
00363
00364
00365 if ( wasFromCursor && !isFromCursor )
00366 {
00367
00368
00369
00370 if ( ! (options & KFindDialog::SelectedText ) )
00371 {
00372
00373
00374 KoTextParag* firstParag = m_lstObjects.first()->textDocument()->firstParag();
00375 int firstIndex = 0;
00376 KoTextParag* lastParag = m_lstObjects.last()->textDocument()->lastParag();
00377 int lastIndex = lastParag->length()-1;
00378 m_firstParag = (!isBack) ? firstParag : lastParag;
00379 m_firstIndex = (!isBack) ? firstIndex : lastIndex;
00380 #ifdef DEBUG_ITERATOR
00381 kdDebug(32500) << "setOptions: FromCursor removed. New m_firstParag=" << m_firstParag << " (" << m_firstParag->paragId() << ") isBack=" << isBack << endl;
00382 #endif
00383 }
00384 }
00385 m_options = options;
00386 }
00387 }
00388
00389 #include "KoTextIterator.moc"