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