/* This file is part of the KDE libraries Copyright (C) 2003 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "katesupercursor.h" #include "katesupercursor.moc" #include "katedocument.h" #include #include KateSuperCursor::KateSuperCursor(KateDocument* doc, bool privateC, const KateTextCursor& cursor, TQObject* parent, const char* name) : TQObject(parent, name) , KateDocCursor(cursor.line(), cursor.col(), doc) , Kate::Cursor () , m_doc (doc) { m_moveOnInsert = false; m_lineRemoved = false; m_privateCursor = privateC; m_doc->addSuperCursor (this, privateC); } KateSuperCursor::KateSuperCursor(KateDocument* doc, bool privateC, int lineNum, int col, TQObject* parent, const char* name) : TQObject(parent, name) , KateDocCursor(lineNum, col, doc) , Kate::Cursor () , m_doc (doc) { m_moveOnInsert = false; m_lineRemoved = false; m_privateCursor = privateC; m_doc->addSuperCursor (this, privateC); } KateSuperCursor::~KateSuperCursor () { m_doc->removeSuperCursor (this, m_privateCursor); } void KateSuperCursor::position(uint *pline, uint *pcol) const { KateDocCursor::position(pline, pcol); } bool KateSuperCursor::setPosition(uint line, uint col) { if (line == uint(-2) && col == uint(-2)) { delete this; return true; } return KateDocCursor::setPosition(line, col); } bool KateSuperCursor::insertText(const TQString& s) { return KateDocCursor::insertText(s); } bool KateSuperCursor::removeText(uint nbChar) { return KateDocCursor::removeText(nbChar); } TQChar KateSuperCursor::currentChar() const { return KateDocCursor::currentChar(); } bool KateSuperCursor::atStartOfLine() const { return col() == 0; } bool KateSuperCursor::atEndOfLine() const { return col() >= (int)m_doc->kateTextLine(line())->length(); } bool KateSuperCursor::moveOnInsert() const { return m_moveOnInsert; } void KateSuperCursor::setMoveOnInsert(bool moveOnInsert) { m_moveOnInsert = moveOnInsert; } void KateSuperCursor::setLine(int lineNum) { int tempLine = line(), tempcol = col(); KateDocCursor::setLine(lineNum); if (tempLine != line() || tempcol != col()) emit positionDirectlyChanged(); } void KateSuperCursor::setCol(int colNum) { KateDocCursor::setCol(colNum); } void KateSuperCursor::setPos(const KateTextCursor& pos) { KateDocCursor::setPos(pos); } void KateSuperCursor::setPos(int lineNum, int colNum) { KateDocCursor::setPos(lineNum, colNum); } void KateSuperCursor::editTextInserted(uint line, uint col, uint len) { if (m_line == int(line)) { if ((m_col > int(col)) || (m_moveOnInsert && (m_col == int(col)))) { bool insertedAt = m_col == int(col); m_col += len; if (insertedAt) emit charInsertedAt(); emit positionChanged(); return; } } emit positionUnChanged(); } void KateSuperCursor::editTextRemoved(uint line, uint col, uint len) { if (m_line == int(line)) { if (m_col > int(col)) { if (m_col > int(col + len)) { m_col -= len; } else { bool prevCharDeleted = m_col == int(col + len); m_col = col; if (prevCharDeleted) emit charDeletedBefore(); else emit positionDeleted(); } emit positionChanged(); return; } else if (m_col == int(col)) { emit charDeletedAfter(); } } emit positionUnChanged(); } void KateSuperCursor::editLineWrapped(uint line, uint col, bool newLine) { if (newLine) { if (m_line > int(line) || (m_line == int(line) && m_col >= int(col))) { if(m_line == int(line)) m_col -= col; m_line++; emit positionChanged(); return; } } else if ( (m_line == int(line)) && (m_col > int(col)) || (m_moveOnInsert && (m_col == int(col))) ) { m_line++; m_col -= col; emit positionChanged(); return; } emit positionUnChanged(); } void KateSuperCursor::editLineUnWrapped(uint line, uint col, bool removeLine, uint length) { if (removeLine && (m_line > int(line+1))) { m_line--; emit positionChanged(); return; } else if ( (m_line == int(line+1)) && (removeLine || (m_col < int(length))) ) { m_line = line; m_col += col; emit positionChanged(); return; } else if ( (m_line == int(line+1)) && (m_col >= int(length)) ) { m_col -= length; emit positionChanged(); return; } emit positionUnChanged(); } void KateSuperCursor::editLineInserted (uint line) { if (m_line >= int(line)) { m_line++; emit positionChanged(); return; } emit positionUnChanged(); } void KateSuperCursor::editLineRemoved(uint line) { if (m_line > int(line)) { m_line--; emit positionChanged(); return; } else if (m_line == int(line)) { m_line = (line <= m_doc->lastLine()) ? line : (line - 1); m_col = 0; emit positionDeleted(); emit positionChanged(); return; } emit positionUnChanged(); } KateSuperCursor::operator TQString() { return TQString("[%1,%1]").arg(line()).arg(col()); } KateSuperRange::KateSuperRange(KateSuperCursor* start, KateSuperCursor* end, TQObject* parent, const char* name) : TQObject(parent, name) , m_start(start) , m_end(end) , m_evaluate(false) , m_startChanged(false) , m_endChanged(false) , m_deleteCursors(false) , m_allowZeroLength(false) { init(); } KateSuperRange::KateSuperRange(KateDocument* doc, const KateRange& range, TQObject* parent, const char* name) : TQObject(parent, name) , m_start(new KateSuperCursor(doc, true, range.start())) , m_end(new KateSuperCursor(doc, true, range.end())) , m_evaluate(false) , m_startChanged(false) , m_endChanged(false) , m_deleteCursors(true) , m_allowZeroLength(false) { init(); } KateSuperRange::KateSuperRange(KateDocument* doc, const KateTextCursor& start, const KateTextCursor& end, TQObject* parent, const char* name) : TQObject(parent, name) , m_start(new KateSuperCursor(doc, true, start)) , m_end(new KateSuperCursor(doc, true, end)) , m_evaluate(false) , m_startChanged(false) , m_endChanged(false) , m_deleteCursors(true) , m_allowZeroLength(false) { init(); } void KateSuperRange::init() { Q_ASSERT(isValid()); if (!isValid()) kdDebug(13020) << superStart() << " " << superEnd() << endl; insertChild(m_start); insertChild(m_end); setBehaviour(DoNotExpand); // Not necessarily the best implementation connect(m_start, TQT_SIGNAL(positionDirectlyChanged()), TQT_SIGNAL(contentsChanged())); connect(m_end, TQT_SIGNAL(positionDirectlyChanged()), TQT_SIGNAL(contentsChanged())); connect(m_start, TQT_SIGNAL(positionChanged()), TQT_SLOT(slotEvaluateChanged())); connect(m_end, TQT_SIGNAL(positionChanged()), TQT_SLOT(slotEvaluateChanged())); connect(m_start, TQT_SIGNAL(positionUnChanged()), TQT_SLOT(slotEvaluateUnChanged())); connect(m_end, TQT_SIGNAL(positionUnChanged()), TQT_SLOT(slotEvaluateUnChanged())); connect(m_start, TQT_SIGNAL(positionDeleted()), TQT_SIGNAL(boundaryDeleted())); connect(m_end, TQT_SIGNAL(positionDeleted()), TQT_SIGNAL(boundaryDeleted())); } KateSuperRange::~KateSuperRange() { if (m_deleteCursors) { //insertChild(m_start); //insertChild(m_end); delete m_start; delete m_end; } } KateTextCursor& KateSuperRange::start() { return *m_start; } const KateTextCursor& KateSuperRange::start() const { return *m_start; } KateTextCursor& KateSuperRange::end() { return *m_end; } const KateTextCursor& KateSuperRange::end() const { return *m_end; } KateSuperCursor& KateSuperRange::superStart() { return *m_start; } const KateSuperCursor& KateSuperRange::superStart() const { return *m_start; } KateSuperCursor& KateSuperRange::superEnd() { return *m_end; } const KateSuperCursor& KateSuperRange::superEnd() const { return *m_end; } int KateSuperRange::behaviour() const { return (m_start->moveOnInsert() ? DoNotExpand : ExpandLeft) | (m_end->moveOnInsert() ? ExpandRight : DoNotExpand); } void KateSuperRange::setBehaviour(int behaviour) { m_start->setMoveOnInsert(behaviour & ExpandLeft); m_end->setMoveOnInsert(!(behaviour & ExpandRight)); } bool KateSuperRange::isValid() const { return superStart() <= superEnd(); } bool KateSuperRange::owns(const KateTextCursor& cursor) const { if (!includes(cursor)) return false; if (!childrenListObject().isEmpty()) for (TQObjectListIt it(childrenListObject()); *it; ++it) if ((*it)->inherits("KateSuperRange")) if (static_cast(*it)->owns(cursor)) return false; return true; } bool KateSuperRange::includes(const KateTextCursor& cursor) const { return isValid() && cursor >= superStart() && cursor < superEnd(); } bool KateSuperRange::includes(uint lineNum) const { return isValid() && (int)lineNum >= superStart().line() && (int)lineNum <= superEnd().line(); } bool KateSuperRange::includesWholeLine(uint lineNum) const { return isValid() && ((int)lineNum > superStart().line() || ((int)lineNum == superStart().line() && superStart().atStartOfLine())) && ((int)lineNum < superEnd().line() || ((int)lineNum == superEnd().line() && superEnd().atEndOfLine())); } bool KateSuperRange::boundaryAt(const KateTextCursor& cursor) const { return isValid() && (cursor == superStart() || cursor == superEnd()); } bool KateSuperRange::boundaryOn(uint lineNum) const { return isValid() && (superStart().line() == (int)lineNum || superEnd().line() == (int)lineNum); } void KateSuperRange::slotEvaluateChanged() { if (sender() == static_cast(m_start)) { if (m_evaluate) { if (!m_endChanged) { // Only one was changed evaluateEliminated(); } else { // Both were changed evaluatePositionChanged(); m_endChanged = false; } } else { m_startChanged = true; } } else { if (m_evaluate) { if (!m_startChanged) { // Only one was changed evaluateEliminated(); } else { // Both were changed evaluatePositionChanged(); m_startChanged = false; } } else { m_endChanged = true; } } m_evaluate = !m_evaluate; } void KateSuperRange::slotEvaluateUnChanged() { if (sender() == static_cast(m_start)) { if (m_evaluate) { if (m_endChanged) { // Only one changed evaluateEliminated(); m_endChanged = false; } else { // Neither changed emit positionUnChanged(); } } } else { if (m_evaluate) { if (m_startChanged) { // Only one changed evaluateEliminated(); m_startChanged = false; } else { // Neither changed emit positionUnChanged(); } } } m_evaluate = !m_evaluate; } void KateSuperRange::slotTagRange() { emit tagRange(this); } void KateSuperRange::evaluateEliminated() { if (superStart() == superEnd()) { if (!m_allowZeroLength) emit eliminated(); } else emit contentsChanged(); } void KateSuperRange::evaluatePositionChanged() { if (superStart() == superEnd()) emit eliminated(); else emit positionChanged(); } int KateSuperCursorList::compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2) { if (*(static_cast(item1)) == *(static_cast(item2))) return 0; return *(static_cast(item1)) < *(static_cast(item2)) ? -1 : 1; } KateSuperRangeList::KateSuperRangeList(bool autoManage, TQObject* parent, const char* name) : TQObject(parent, name) , m_autoManage(autoManage) , m_connect(true) , m_trackingBoundaries(false) { setAutoManage(autoManage); } KateSuperRangeList::KateSuperRangeList(const TQPtrList& rangeList, TQObject* parent, const char* name) : TQObject(parent, name) , m_autoManage(false) , m_connect(false) , m_trackingBoundaries(false) { appendList(rangeList); } void KateSuperRangeList::appendList(const TQPtrList& rangeList) { for (TQPtrListIterator it = rangeList; *it; ++it) append(*it); } void KateSuperRangeList::clear() { for (KateSuperRange* range = first(); range; range = next()) emit rangeEliminated(range); TQPtrList::clear(); } void KateSuperRangeList::connectAll() { if (!m_connect) { m_connect = true; for (KateSuperRange* range = first(); range; range = next()) { connect(range, TQT_SIGNAL(destroyed(TQObject*)), TQT_SLOT(slotDeleted(TQObject*))); connect(range, TQT_SIGNAL(eliminated()), TQT_SLOT(slotEliminated())); } } } bool KateSuperRangeList::autoManage() const { return m_autoManage; } void KateSuperRangeList::setAutoManage(bool autoManage) { m_autoManage = autoManage; setAutoDelete(m_autoManage); } TQPtrList KateSuperRangeList::rangesIncluding(const KateTextCursor& cursor) { sort(); TQPtrList ret; for (KateSuperRange* r = first(); r; r = next()) if (r->includes(cursor)) ret.append(r); return ret; } TQPtrList KateSuperRangeList::rangesIncluding(uint line) { sort(); TQPtrList ret; for (KateSuperRange* r = first(); r; r = next()) if (r->includes(line)) ret.append(r); return ret; } bool KateSuperRangeList::rangesInclude(const KateTextCursor& cursor) { for (KateSuperRange* r = first(); r; r = next()) if (r->includes(cursor)) return true; return false; } void KateSuperRangeList::slotEliminated() { if (sender()) { KateSuperRange* range = static_cast(const_cast(TQT_TQOBJECT_CONST(sender()))); emit rangeEliminated(range); if (m_trackingBoundaries) { m_columnBoundaries.removeRef(range->m_start); m_columnBoundaries.removeRef(range->m_end); } if (m_autoManage) removeRef(range); if (!count()) emit listEmpty(); } } void KateSuperRangeList::slotDeleted(TQObject* range) { //kdDebug(13020)<<"KateSuperRangeList::slotDeleted"<(range); if (m_trackingBoundaries) { m_columnBoundaries.removeRef(r->m_start); m_columnBoundaries.removeRef(r->m_end); } int index = findRef(r); if (index != -1) take(index); //else kdDebug(13020)<<"Range not found in list"<superStart())); m_columnBoundaries.append(&(r->superEnd())); } } m_columnBoundaries.sort(); if (start) // OPTIMISE: TQMap with TQPtrList for each line? (==> sorting issues :( ) for (KateSuperCursor* c = m_columnBoundaries.first(); c; c = m_columnBoundaries.next()) if (*start <= *c) break; return m_columnBoundaries.current(); } KateSuperCursor* KateSuperRangeList::nextBoundary() { KateSuperCursor* current = m_columnBoundaries.current(); // make sure the new cursor is after the current cursor; multiple cursors with the same position can be in the list. if (current) while (m_columnBoundaries.next()) if (*(m_columnBoundaries.current()) != *current) break; return m_columnBoundaries.current(); } KateSuperCursor* KateSuperRangeList::currentBoundary() { return m_columnBoundaries.current(); } int KateSuperRangeList::compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2) { if (static_cast(item1)->superStart() == static_cast(item2)->superStart()) { if (static_cast(item1)->superEnd() == static_cast(item2)->superEnd()) { return 0; } else { return static_cast(item1)->superEnd() < static_cast(item2)->superEnd() ? -1 : 1; } } return static_cast(item1)->superStart() < static_cast(item2)->superStart() ? -1 : 1; } TQPtrCollection::Item KateSuperRangeList::newItem(TQPtrCollection::Item d) { if (m_connect) { connect(static_cast(d), TQT_SIGNAL(destroyed(TQObject*)), TQT_SLOT(slotDeleted(TQObject*))); connect(static_cast(d), TQT_SIGNAL(eliminated()), TQT_SLOT(slotEliminated())); connect(static_cast(d), TQT_SIGNAL(tagRange(KateSuperRange*)), TQT_SIGNAL(tagRange(KateSuperRange*))); // HACK HACK static_cast(d)->slotTagRange(); } if (m_trackingBoundaries) { m_columnBoundaries.append(&(static_cast(d)->superStart())); m_columnBoundaries.append(&(static_cast(d)->superEnd())); } return TQPtrList::newItem(d); } // kate: space-indent on; indent-width 2; replace-tabs on;