katesupercursor.cpp

00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2003 Hamish Rodda <rodda@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "katesupercursor.h"
00020 #include "katesupercursor.moc"
00021 
00022 #include "katedocument.h"
00023 
00024 #include <kdebug.h>
00025 
00026 #include <qobjectlist.h>
00027 
00028 KateSuperCursor::KateSuperCursor(KateDocument* doc, bool privateC, const KateTextCursor& cursor, QObject* parent, const char* name)
00029   : QObject(parent, name)
00030   , KateDocCursor(cursor.line(), cursor.col(), doc)
00031   , Kate::Cursor ()
00032   , m_doc (doc)
00033 {
00034   m_moveOnInsert = false;
00035   m_lineRemoved = false;
00036   m_privateCursor = privateC;
00037 
00038   m_doc->addSuperCursor (this, privateC);
00039 }
00040 
00041 KateSuperCursor::KateSuperCursor(KateDocument* doc, bool privateC, int lineNum, int col, QObject* parent, const char* name)
00042   : QObject(parent, name)
00043   , KateDocCursor(lineNum, col, doc)
00044   , Kate::Cursor ()
00045   , m_doc (doc)
00046 {
00047   m_moveOnInsert = false;
00048   m_lineRemoved = false;
00049   m_privateCursor = privateC;
00050 
00051   m_doc->addSuperCursor (this, privateC);
00052 }
00053 
00054 KateSuperCursor::~KateSuperCursor ()
00055 {
00056   m_doc->removeSuperCursor (this, m_privateCursor);
00057 }
00058 
00059 void KateSuperCursor::position(uint *pline, uint *pcol) const
00060 {
00061   KateDocCursor::position(pline, pcol);
00062 }
00063 
00064 bool KateSuperCursor::setPosition(uint line, uint col)
00065 {
00066   if (line == uint(-2) && col == uint(-2)) { delete this; return true; }
00067   return KateDocCursor::setPosition(line, col);
00068 }
00069 
00070 bool KateSuperCursor::insertText(const QString& s)
00071 {
00072   return KateDocCursor::insertText(s);
00073 }
00074 
00075 bool KateSuperCursor::removeText(uint nbChar)
00076 {
00077   return KateDocCursor::removeText(nbChar);
00078 }
00079 
00080 QChar KateSuperCursor::currentChar() const
00081 {
00082   return KateDocCursor::currentChar();
00083 }
00084 
00085 bool KateSuperCursor::atStartOfLine() const
00086 {
00087   return col() == 0;
00088 }
00089 
00090 bool KateSuperCursor::atEndOfLine() const
00091 {
00092   return col() >= (int)m_doc->kateTextLine(line())->length();
00093 }
00094 
00095 bool KateSuperCursor::moveOnInsert() const
00096 {
00097   return m_moveOnInsert;
00098 }
00099 
00100 void KateSuperCursor::setMoveOnInsert(bool moveOnInsert)
00101 {
00102   m_moveOnInsert = moveOnInsert;
00103 }
00104 
00105 void KateSuperCursor::setLine(int lineNum)
00106 {
00107   int tempLine = line(), tempcol = col();
00108   KateDocCursor::setLine(lineNum);
00109 
00110   if (tempLine != line() || tempcol != col())
00111     emit positionDirectlyChanged();
00112 }
00113 
00114 void KateSuperCursor::setCol(int colNum)
00115 {
00116   KateDocCursor::setCol(colNum);
00117 }
00118 
00119 void KateSuperCursor::setPos(const KateTextCursor& pos)
00120 {
00121   KateDocCursor::setPos(pos);
00122 }
00123 
00124 void KateSuperCursor::setPos(int lineNum, int colNum)
00125 {
00126   KateDocCursor::setPos(lineNum, colNum);
00127 }
00128 
00129 void KateSuperCursor::editTextInserted(uint line, uint col, uint len)
00130 {
00131   if (m_line == int(line))
00132   {
00133     if ((m_col > int(col)) || (m_moveOnInsert && (m_col == int(col))))
00134     {
00135       bool insertedAt = m_col == int(col);
00136 
00137       m_col += len;
00138 
00139       if (insertedAt)
00140         emit charInsertedAt();
00141 
00142       emit positionChanged();
00143       return;
00144     }
00145   }
00146 
00147   emit positionUnChanged();
00148 }
00149 
00150 void KateSuperCursor::editTextRemoved(uint line, uint col, uint len)
00151 {
00152   if (m_line == int(line))
00153   {
00154     if (m_col > int(col))
00155     {
00156       if (m_col > int(col + len))
00157       {
00158         m_col -= len;
00159       }
00160       else
00161       {
00162         bool prevCharDeleted = m_col == int(col + len);
00163 
00164         m_col = col;
00165 
00166         if (prevCharDeleted)
00167           emit charDeletedBefore();
00168         else
00169           emit positionDeleted();
00170       }
00171 
00172       emit positionChanged();
00173       return;
00174 
00175     }
00176     else if (m_col == int(col))
00177     {
00178       emit charDeletedAfter();
00179     }
00180   }
00181 
00182   emit positionUnChanged();
00183 }
00184 
00185 void KateSuperCursor::editLineWrapped(uint line, uint col, bool newLine)
00186 {
00187   if (newLine && (m_line > int(line)))
00188   {
00189     m_line++;
00190 
00191     emit positionChanged();
00192     return;
00193   }
00194   else if ( (m_line == int(line)) && (m_col > int(col)) || (m_moveOnInsert && (m_col == int(col))) )
00195   {
00196     m_line++;
00197     m_col -= col;
00198 
00199     emit positionChanged();
00200     return;
00201   }
00202 
00203   emit positionUnChanged();
00204 }
00205 
00206 void KateSuperCursor::editLineUnWrapped(uint line, uint col, bool removeLine, uint length)
00207 {
00208   if (removeLine && (m_line > int(line+1)))
00209   {
00210     m_line--;
00211 
00212     emit positionChanged();
00213     return;
00214   }
00215   else if ( (m_line == int(line+1)) && (removeLine || (m_col < int(length))) )
00216   {
00217     m_line = line;
00218     m_col += col;
00219 
00220     emit positionChanged();
00221     return;
00222   }
00223   else if ( (m_line == int(line+1)) && (m_col >= int(length)) )
00224   {
00225     m_col -= length;
00226 
00227     emit positionChanged();
00228     return;
00229   }
00230 
00231   emit positionUnChanged();
00232 }
00233 
00234 void KateSuperCursor::editLineInserted (uint line)
00235 {
00236   if (m_line >= int(line))
00237   {
00238     m_line++;
00239 
00240     emit positionChanged();
00241     return;
00242   }
00243 
00244   emit positionUnChanged();
00245 }
00246 
00247 void KateSuperCursor::editLineRemoved(uint line)
00248 {
00249   if (m_line > int(line))
00250   {
00251     m_line--;
00252 
00253     emit positionChanged();
00254     return;
00255   }
00256   else if (m_line == int(line))
00257   {
00258     m_line = (line <= m_doc->lastLine()) ? line : (line - 1);
00259     m_col = 0;
00260 
00261     emit positionDeleted();
00262 
00263     emit positionChanged();
00264     return;
00265   }
00266 
00267   emit positionUnChanged();
00268 }
00269 
00270 KateSuperCursor::operator QString()
00271 {
00272   return QString("[%1,%1]").arg(line()).arg(col());
00273 }
00274 
00275 KateSuperRange::KateSuperRange(KateSuperCursor* start, KateSuperCursor* end, QObject* parent, const char* name)
00276   : QObject(parent, name)
00277   , m_start(start)
00278   , m_end(end)
00279   , m_evaluate(false)
00280   , m_startChanged(false)
00281   , m_endChanged(false)
00282   , m_deleteCursors(false)
00283   , m_allowZeroLength(false)
00284 {
00285   init();
00286 }
00287 
00288 KateSuperRange::KateSuperRange(KateDocument* doc, const KateRange& range, QObject* parent, const char* name)
00289   : QObject(parent, name)
00290   , m_start(new KateSuperCursor(doc, true, range.start()))
00291   , m_end(new KateSuperCursor(doc, true, range.end()))
00292   , m_evaluate(false)
00293   , m_startChanged(false)
00294   , m_endChanged(false)
00295   , m_deleteCursors(true)
00296   , m_allowZeroLength(false)
00297 {
00298   init();
00299 }
00300 
00301 KateSuperRange::KateSuperRange(KateDocument* doc, const KateTextCursor& start, const KateTextCursor& end, QObject* parent, const char* name)
00302   : QObject(parent, name)
00303   , m_start(new KateSuperCursor(doc, true, start))
00304   , m_end(new KateSuperCursor(doc, true, end))
00305   , m_evaluate(false)
00306   , m_startChanged(false)
00307   , m_endChanged(false)
00308   , m_deleteCursors(true)
00309   , m_allowZeroLength(false)
00310 {
00311   init();
00312 }
00313 
00314 void KateSuperRange::init()
00315 {
00316   Q_ASSERT(isValid());
00317   if (!isValid())
00318     kdDebug(13020) << superStart() << " " << superEnd() << endl;
00319 
00320   insertChild(m_start);
00321   insertChild(m_end);
00322 
00323   setBehaviour(DoNotExpand);
00324 
00325   // Not necessarily the best implementation
00326   connect(m_start, SIGNAL(positionDirectlyChanged()),  SIGNAL(contentsChanged()));
00327   connect(m_end, SIGNAL(positionDirectlyChanged()),  SIGNAL(contentsChanged()));
00328 
00329   connect(m_start, SIGNAL(positionChanged()),  SLOT(slotEvaluateChanged()));
00330   connect(m_end, SIGNAL(positionChanged()),  SLOT(slotEvaluateChanged()));
00331   connect(m_start, SIGNAL(positionUnChanged()), SLOT(slotEvaluateUnChanged()));
00332   connect(m_end, SIGNAL(positionUnChanged()), SLOT(slotEvaluateUnChanged()));
00333   connect(m_start, SIGNAL(positionDeleted()), SIGNAL(boundaryDeleted()));
00334   connect(m_end, SIGNAL(positionDeleted()), SIGNAL(boundaryDeleted()));
00335 }
00336 
00337 KateSuperRange::~KateSuperRange()
00338 {
00339   if (m_deleteCursors)
00340   {
00341     //insertChild(m_start);
00342     //insertChild(m_end);
00343     delete m_start;
00344     delete m_end;
00345   }
00346 }
00347 
00348 KateTextCursor& KateSuperRange::start()
00349 {
00350   return *m_start;
00351 }
00352 
00353 const KateTextCursor& KateSuperRange::start() const
00354 {
00355   return *m_start;
00356 }
00357 
00358 KateTextCursor& KateSuperRange::end()
00359 {
00360   return *m_end;
00361 }
00362 
00363 const KateTextCursor& KateSuperRange::end() const
00364 {
00365   return *m_end;
00366 }
00367 
00368 KateSuperCursor& KateSuperRange::superStart()
00369 {
00370   return *m_start;
00371 }
00372 
00373 const KateSuperCursor& KateSuperRange::superStart() const
00374 {
00375   return *m_start;
00376 }
00377 
00378 KateSuperCursor& KateSuperRange::superEnd()
00379 {
00380   return *m_end;
00381 }
00382 
00383 const KateSuperCursor& KateSuperRange::superEnd() const
00384 {
00385   return *m_end;
00386 }
00387 
00388 int KateSuperRange::behaviour() const
00389 {
00390   return (m_start->moveOnInsert() ? DoNotExpand : ExpandLeft) | (m_end->moveOnInsert() ? ExpandRight : DoNotExpand);
00391 }
00392 
00393 void KateSuperRange::setBehaviour(int behaviour)
00394 {
00395   m_start->setMoveOnInsert(behaviour & ExpandLeft);
00396   m_end->setMoveOnInsert(!(behaviour & ExpandRight));
00397 }
00398 
00399 bool KateSuperRange::isValid() const
00400 {
00401   return superStart() <= superEnd();
00402 }
00403 
00404 bool KateSuperRange::owns(const KateTextCursor& cursor) const
00405 {
00406   if (!includes(cursor)) return false;
00407 
00408   if (children())
00409     for (QObjectListIt it(*children()); *it; ++it)
00410       if ((*it)->inherits("KateSuperRange"))
00411         if (static_cast<KateSuperRange*>(*it)->owns(cursor))
00412           return false;
00413 
00414   return true;
00415 }
00416 
00417 bool KateSuperRange::includes(const KateTextCursor& cursor) const
00418 {
00419   return isValid() && cursor >= superStart() && cursor < superEnd();
00420 }
00421 
00422 bool KateSuperRange::includes(uint lineNum) const
00423 {
00424   return isValid() && (int)lineNum >= superStart().line() && (int)lineNum <= superEnd().line();
00425 }
00426 
00427 bool KateSuperRange::includesWholeLine(uint lineNum) const
00428 {
00429   return isValid() && ((int)lineNum > superStart().line() || ((int)lineNum == superStart().line() && superStart().atStartOfLine())) && ((int)lineNum < superEnd().line() || ((int)lineNum == superEnd().line() && superEnd().atEndOfLine()));
00430 }
00431 
00432 bool KateSuperRange::boundaryAt(const KateTextCursor& cursor) const
00433 {
00434   return isValid() && (cursor == superStart() || cursor == superEnd());
00435 }
00436 
00437 bool KateSuperRange::boundaryOn(uint lineNum) const
00438 {
00439   return isValid() && (superStart().line() == (int)lineNum || superEnd().line() == (int)lineNum);
00440 }
00441 
00442 void KateSuperRange::slotEvaluateChanged()
00443 {
00444   if (sender() == static_cast<QObject*>(m_start)) {
00445     if (m_evaluate) {
00446       if (!m_endChanged) {
00447         // Only one was changed
00448         evaluateEliminated();
00449 
00450       } else {
00451         // Both were changed
00452         evaluatePositionChanged();
00453         m_endChanged = false;
00454       }
00455 
00456     } else {
00457       m_startChanged = true;
00458     }
00459 
00460   } else {
00461     if (m_evaluate) {
00462       if (!m_startChanged) {
00463         // Only one was changed
00464         evaluateEliminated();
00465 
00466       } else {
00467         // Both were changed
00468         evaluatePositionChanged();
00469         m_startChanged = false;
00470       }
00471 
00472     } else {
00473       m_endChanged = true;
00474     }
00475   }
00476 
00477   m_evaluate = !m_evaluate;
00478 }
00479 
00480 void KateSuperRange::slotEvaluateUnChanged()
00481 {
00482   if (sender() == static_cast<QObject*>(m_start)) {
00483     if (m_evaluate) {
00484       if (m_endChanged) {
00485         // Only one changed
00486         evaluateEliminated();
00487         m_endChanged = false;
00488 
00489       } else {
00490         // Neither changed
00491         emit positionUnChanged();
00492       }
00493     }
00494 
00495   } else {
00496     if (m_evaluate) {
00497       if (m_startChanged) {
00498         // Only one changed
00499         evaluateEliminated();
00500         m_startChanged = false;
00501 
00502       } else {
00503         // Neither changed
00504         emit positionUnChanged();
00505       }
00506     }
00507   }
00508 
00509   m_evaluate = !m_evaluate;
00510 }
00511 
00512 void KateSuperRange::slotTagRange()
00513 {
00514   emit tagRange(this);
00515 }
00516 
00517 void KateSuperRange::evaluateEliminated()
00518 {
00519   if (superStart() == superEnd()) {
00520       if (!m_allowZeroLength) emit eliminated();
00521     }
00522   else
00523     emit contentsChanged();
00524 }
00525 
00526 void KateSuperRange::evaluatePositionChanged()
00527 {
00528   if (superStart() == superEnd())
00529     emit eliminated();
00530   else
00531     emit positionChanged();
00532 }
00533 
00534 int KateSuperCursorList::compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2)
00535 {
00536   if (*(static_cast<KateSuperCursor*>(item1)) == *(static_cast<KateSuperCursor*>(item2)))
00537     return 0;
00538 
00539   return *(static_cast<KateSuperCursor*>(item1)) < *(static_cast<KateSuperCursor*>(item2)) ? -1 : 1;
00540 }
00541 
00542 KateSuperRangeList::KateSuperRangeList(bool autoManage, QObject* parent, const char* name)
00543   : QObject(parent, name)
00544   , m_autoManage(autoManage)
00545   , m_connect(true)
00546   , m_trackingBoundaries(false)
00547 {
00548   setAutoManage(autoManage);
00549 }
00550 
00551 KateSuperRangeList::KateSuperRangeList(const QPtrList<KateSuperRange>& rangeList, QObject* parent, const char* name)
00552   : QObject(parent, name)
00553   , m_autoManage(false)
00554   , m_connect(false)
00555   , m_trackingBoundaries(false)
00556 {
00557   appendList(rangeList);
00558 }
00559 
00560 void KateSuperRangeList::appendList(const QPtrList<KateSuperRange>& rangeList)
00561 {
00562   for (QPtrListIterator<KateSuperRange> it = rangeList; *it; ++it)
00563     append(*it);
00564 }
00565 
00566 void KateSuperRangeList::clear()
00567 {
00568   for (KateSuperRange* range = first(); range; range = next())
00569     emit rangeEliminated(range);
00570 
00571   QPtrList<KateSuperRange>::clear();
00572 }
00573 
00574 void KateSuperRangeList::connectAll()
00575 {
00576   if (!m_connect) {
00577     m_connect = true;
00578     for (KateSuperRange* range = first(); range; range = next()) {
00579       connect(range, SIGNAL(destroyed(QObject*)), SLOT(slotDeleted(QObject*)));
00580       connect(range, SIGNAL(eliminated()), SLOT(slotEliminated()));
00581     }
00582   }
00583 }
00584 
00585 bool KateSuperRangeList::autoManage() const
00586 {
00587   return m_autoManage;
00588 }
00589 
00590 void KateSuperRangeList::setAutoManage(bool autoManage)
00591 {
00592   m_autoManage = autoManage;
00593   setAutoDelete(m_autoManage);
00594 }
00595 
00596 QPtrList<KateSuperRange> KateSuperRangeList::rangesIncluding(const KateTextCursor& cursor)
00597 {
00598   sort();
00599 
00600   QPtrList<KateSuperRange> ret;
00601 
00602   for (KateSuperRange* r = first(); r; r = next())
00603     if (r->includes(cursor))
00604       ret.append(r);
00605 
00606   return ret;
00607 }
00608 
00609 QPtrList<KateSuperRange> KateSuperRangeList::rangesIncluding(uint line)
00610 {
00611   sort();
00612 
00613   QPtrList<KateSuperRange> ret;
00614 
00615   for (KateSuperRange* r = first(); r; r = next())
00616     if (r->includes(line))
00617       ret.append(r);
00618 
00619   return ret;
00620 }
00621 
00622 bool KateSuperRangeList::rangesInclude(const KateTextCursor& cursor)
00623 {
00624   for (KateSuperRange* r = first(); r; r = next())
00625     if (r->includes(cursor))
00626       return true;
00627 
00628   return false;
00629 }
00630 
00631 void KateSuperRangeList::slotEliminated()
00632 {
00633   if (sender()) {
00634     KateSuperRange* range = static_cast<KateSuperRange*>(const_cast<QObject*>(sender()));
00635     emit rangeEliminated(range);
00636 
00637     if (m_trackingBoundaries) {
00638       m_columnBoundaries.removeRef(range->m_start);
00639       m_columnBoundaries.removeRef(range->m_end);
00640     }
00641 
00642     if (m_autoManage)
00643       removeRef(range);
00644 
00645     if (!count())
00646       emit listEmpty();
00647   }
00648 }
00649 
00650 void KateSuperRangeList::slotDeleted(QObject* range)
00651 {
00652   //kdDebug(13020)<<"KateSuperRangeList::slotDeleted"<<endl;
00653   KateSuperRange* r = static_cast<KateSuperRange*>(range);
00654 
00655   if (m_trackingBoundaries) {
00656       m_columnBoundaries.removeRef(r->m_start);
00657       m_columnBoundaries.removeRef(r->m_end);
00658   }
00659 
00660   int index = findRef(r);
00661   if (index != -1)
00662     take(index);
00663   //else kdDebug(13020)<<"Range not found in list"<<endl;
00664 
00665   if (!count())
00666       emit listEmpty();
00667 }
00668 
00669 KateSuperCursor* KateSuperRangeList::firstBoundary(const KateTextCursor* start)
00670 {
00671   if (!m_trackingBoundaries) {
00672     m_trackingBoundaries = true;
00673 
00674     for (KateSuperRange* r = first(); r; r = next()) {
00675       m_columnBoundaries.append(&(r->superStart()));
00676       m_columnBoundaries.append(&(r->superEnd()));
00677     }
00678   }
00679 
00680   m_columnBoundaries.sort();
00681 
00682   if (start)
00683     // OPTIMISE: QMap with QPtrList for each line? (==> sorting issues :( )
00684     for (KateSuperCursor* c = m_columnBoundaries.first(); c; c = m_columnBoundaries.next())
00685       if (*start <= *c)
00686         break;
00687 
00688   return m_columnBoundaries.current();
00689 }
00690 
00691 KateSuperCursor* KateSuperRangeList::nextBoundary()
00692 {
00693   KateSuperCursor* current = m_columnBoundaries.current();
00694 
00695   // make sure the new cursor is after the current cursor; multiple cursors with the same position can be in the list.
00696   if (current)
00697     while (m_columnBoundaries.next())
00698       if (*(m_columnBoundaries.current()) != *current)
00699         break;
00700 
00701   return m_columnBoundaries.current();
00702 }
00703 
00704 KateSuperCursor* KateSuperRangeList::currentBoundary()
00705 {
00706   return m_columnBoundaries.current();
00707 }
00708 
00709 int KateSuperRangeList::compareItems(QPtrCollection::Item item1, QPtrCollection::Item item2)
00710 {
00711   if (static_cast<KateSuperRange*>(item1)->superStart() == static_cast<KateSuperRange*>(item2)->superStart()) {
00712     if (static_cast<KateSuperRange*>(item1)->superEnd() == static_cast<KateSuperRange*>(item2)->superEnd()) {
00713       return 0;
00714     } else {
00715       return static_cast<KateSuperRange*>(item1)->superEnd() < static_cast<KateSuperRange*>(item2)->superEnd() ? -1 : 1;
00716     }
00717   }
00718 
00719   return static_cast<KateSuperRange*>(item1)->superStart() < static_cast<KateSuperRange*>(item2)->superStart() ? -1 : 1;
00720 }
00721 
00722 QPtrCollection::Item KateSuperRangeList::newItem(QPtrCollection::Item d)
00723 {
00724   if (m_connect) {
00725     connect(static_cast<KateSuperRange*>(d), SIGNAL(destroyed(QObject*)), SLOT(slotDeleted(QObject*)));
00726     connect(static_cast<KateSuperRange*>(d), SIGNAL(eliminated()), SLOT(slotEliminated()));
00727     connect(static_cast<KateSuperRange*>(d), SIGNAL(tagRange(KateSuperRange*)), SIGNAL(tagRange(KateSuperRange*)));
00728 
00729     // HACK HACK
00730     static_cast<KateSuperRange*>(d)->slotTagRange();
00731   }
00732 
00733   if (m_trackingBoundaries) {
00734     m_columnBoundaries.append(&(static_cast<KateSuperRange*>(d)->superStart()));
00735     m_columnBoundaries.append(&(static_cast<KateSuperRange*>(d)->superEnd()));
00736   }
00737 
00738   return QPtrList<KateSuperRange>::newItem(d);
00739 }
00740 
00741 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Home | KDE Accessibility Home | Description of Access Keys