• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katesmartcursor.cpp

Go to the documentation of this file.
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 "katesmartcursor.h"
00020 
00021 #include "katedocument.h"
00022 #include "katesmartmanager.h"
00023 #include "katesmartcursornotifier.h"
00024 #include "katesmartrange.h"
00025 
00026 #include <kdebug.h>
00027 
00028 //#define DEBUG_KATESMARTCURSOR
00029 
00030 KateSmartCursor::KateSmartCursor(const KTextEditor::Cursor& position, KTextEditor::Document* doc, KTextEditor::SmartCursor::InsertBehavior insertBehavior)
00031   : KTextEditor::SmartCursor(position, doc, insertBehavior)
00032   , m_oldGroupLineStart(-1)
00033   , m_lastPosition(position)
00034   , m_feedbackEnabled(false)
00035   , m_isInternal(false)
00036   , m_lastPositionNeeded(false)
00037   , m_bypassTranslation(0)
00038   , m_notifier(0L)
00039   , m_watcher(0L)
00040 {
00041   if (position.line() > kateDocument()->lastLine()) {
00042     kWarning() << "Attempted to set cursor position " << position << " past end of document " << doc->documentRange();
00043     m_line = -1;
00044     m_column = -1;
00045   }
00046 
00047   // Replace straight line number with smartgroup + line offset
00048   m_smartGroup = kateDocument()->smartManager()->groupForLine(m_line);
00049   m_line = m_line - m_smartGroup->startLine();
00050   m_smartGroup->joined(this);
00051 
00052 #ifdef DEBUG_KATESMARTCURSOR
00053   kDebug() << "Cursor created at " << *this;
00054 #endif
00055 }
00056 
00057 KateSmartCursor::KateSmartCursor( KTextEditor::Document * doc, KTextEditor::SmartCursor::InsertBehavior insertBehavior )
00058   : KTextEditor::SmartCursor(KTextEditor::Cursor(), doc, insertBehavior)
00059   , m_oldGroupLineStart(-1)
00060   , m_feedbackEnabled(false)
00061   , m_isInternal(false)
00062   , m_lastPositionNeeded(false)
00063   , m_bypassTranslation(0)
00064   , m_notifier(0L)
00065   , m_watcher(0L)
00066 {
00067   // Replace straight line number with smartgroup + line offset
00068   m_smartGroup = kateDocument()->smartManager()->groupForLine(m_line);
00069   m_line = m_line - m_smartGroup->startLine();
00070   m_smartGroup->joined(this);
00071 
00072 #ifdef DEBUG_KATESMARTCURSOR
00073   kDebug() << this << "Cursor created at " << *this;
00074 #endif
00075 }
00076 
00077 KateSmartCursor::~KateSmartCursor()
00078 {
00079   if (m_notifier) {
00080     emit m_notifier->deleted(this);
00081     delete m_notifier;
00082   }
00083 
00084   if (m_watcher)
00085     m_watcher->deleted(this);
00086 
00087   if (!kateDocument()->smartManager()->isClearing())
00088     m_smartGroup->leaving(this);
00089 }
00090 
00091 KateSmartCursor::operator QString()
00092 {
00093   return QString("[%1,%1]").arg(line()).arg(column());
00094 }
00095 
00096 KateDocument* KateSmartCursor::kateDocument() const
00097 {
00098   return static_cast<KateDocument*>(document());
00099 }
00100 
00101 bool KateSmartCursor::isValid( ) const
00102 {
00103   return line() >= 0 && column() >= 0 && line() <= kateDocument()->lastLine() && column() <= kateDocument()->lineLength(line());
00104 }
00105 
00106 bool KateSmartCursor::isValid(const Cursor& position) const
00107 {
00108   return position.line() >= 0 && position.line() <= kateDocument()->lastLine() && position.column() >= 0 && position.column() <= kateDocument()->lineLength(position.line());
00109 }
00110 
00111 bool KateSmartCursor::atEndOfLine( ) const
00112 {
00113   return line() >= 0 && line() <= kateDocument()->lastLine() && column() >= kateDocument()->lineLength(line());
00114 }
00115 
00116 void KateSmartCursor::checkFeedback()
00117 {
00118   bool feedbackNeeded = m_watcher || m_notifier;
00119 
00120   m_lastPositionNeeded = feedbackNeeded || (range() && static_cast<KateSmartRange*>(range())->feedbackEnabled());
00121 
00122   if (m_feedbackEnabled != feedbackNeeded) {
00123     m_smartGroup->changeCursorFeedback(this);
00124     m_feedbackEnabled = feedbackNeeded;
00125   }
00126 }
00127 
00128 int KateSmartCursor::line( ) const
00129 {
00130   return m_smartGroup->startLine() + m_line;
00131 }
00132 
00133 void KateSmartCursor::setLine( int _line )
00134 {
00135   setPositionInternal(KTextEditor::Cursor(_line, m_column), false);
00136 }
00137 
00138 void KateSmartCursor::setPositionInternal( const KTextEditor::Cursor & pos, bool internal )
00139 {
00140   // Shortcut if there's no change :)
00141   if (*this == pos)
00142     return;
00143 
00144   KTextEditor::Cursor old = *this;
00145 
00146   // Remember this position if the feedback system needs it
00147   if (m_lastPositionNeeded)
00148     m_lastPosition = *this;
00149 
00150   // Deal with crossing a smart group border
00151   bool haveToChangeGroups = !m_smartGroup->containsLine(pos.line());
00152   if (haveToChangeGroups) {
00153     m_smartGroup->leaving(this);
00154     m_smartGroup = kateDocument()->smartManager()->groupForLine(pos.line());
00155   }
00156 
00157   // Set the new position
00158   m_line = pos.line() - m_smartGroup->newStartLine();
00159   m_column = pos.column();
00160 
00161   // Finish dealing with crossing a smart group border
00162   if (haveToChangeGroups) {
00163     m_smartGroup->joined(this);
00164   }
00165 
00166   // Forget this position change if the feedback system doesn't need it
00167   if (!m_lastPositionNeeded)
00168     m_lastPosition = *this;
00169 
00170   // Adjustments only needed for non-internal position changes...
00171   if (!internal)
00172     // Tell the range about this
00173     cursorChangedDirectly(old);
00174 
00175 #ifdef DEBUG_KATESMARTCURSOR
00176   kDebug() << this << "Cursor moved from" << old << "to" << *this;
00177 #endif
00178 }
00179 
00180 KTextEditor::SmartCursorNotifier* KateSmartCursor::notifier( )
00181 {
00182   if (!m_notifier) {
00183     m_notifier = new KateSmartCursorNotifier();
00184     checkFeedback();
00185   }
00186   return m_notifier;
00187 }
00188 
00189 void KateSmartCursor::deleteNotifier( )
00190 {
00191   delete m_notifier;
00192   m_notifier = 0L;
00193   checkFeedback();
00194 }
00195 
00196 void KateSmartCursor::setWatcher( KTextEditor::SmartCursorWatcher * watcher )
00197 {
00198   m_watcher = watcher;
00199   checkFeedback();
00200 }
00201 
00202 bool KateSmartCursor::translate( const KateEditInfo & edit )
00203 {
00204 #ifdef DEBUG_KATESMARTCURSOR
00205   kDebug() << this << "Translating cursor" << *this << "from " << edit.oldRange() << "to" << edit.newRange() << edit.editSource() << &edit;
00206 #endif
00207 
00208   if (m_bypassTranslation) {
00209     if (m_bypassTranslation == &edit) {
00210       // This cursor has already been moved for this edit
00211       m_bypassTranslation = 0;
00212       return true;
00213     }
00214 
00215     m_bypassTranslation = 0;
00216   }
00217 
00218   // If this cursor is before the edit, no action is required
00219   if (*this < edit.start())
00220     return false;
00221 
00222   // Calculate the new position
00223   KTextEditor::Cursor newPos;
00224 
00225   // If this cursor is on a line affected by the edit
00226   if (edit.oldRange().overlapsLine(line())) {
00227     // If this cursor is at the start of the edit
00228     if (*this == edit.start()) {
00229       // And it doesn't need to move, no action is required
00230       if (insertBehavior() == KTextEditor::SmartCursor::StayOnInsert)
00231         return false;
00232     }
00233 
00234     if (edit.oldRange().contains(*this)) {
00235       if (insertBehavior() == KTextEditor::SmartCursor::MoveOnInsert)
00236         newPos = edit.newRange().end();
00237       else
00238         newPos = edit.start();
00239 
00240     } else {
00241       newPos = *this + edit.translate();
00242     }
00243 
00244   } else {
00245     // just need to adjust line number
00246     newPos.setPosition(line() + edit.translate().line(), column());
00247   }
00248 
00249   if (newPos != *this) {
00250     // Catch corner case where the range is non-expanding, is zero length, and then the
00251     // start cursor would otherwise be placed before the end cursor.
00252     if (KTextEditor::SmartRange* range = smartRange()) {
00253       if (&(range->smartStart()) == this) {
00254         if (*this == edit.start()) {
00255           if (range->insertBehavior() == KTextEditor::SmartRange::DoNotExpand) {
00256             if (range->end() == *this) {
00257               KateSmartCursor* end = static_cast<KateSmartCursor*>(&(range->smartEnd()));
00258               end->setPositionInternal(newPos);
00259               // Don't let the end cursor get translated again
00260               end->m_bypassTranslation = &edit;
00261             }
00262           }
00263         }
00264       }
00265     }
00266 
00267     setPositionInternal(newPos);
00268     return true;
00269   }
00270 
00271   return false;
00272 }
00273 
00274 bool KateSmartCursor::cursorMoved( ) const
00275 {
00276   bool ret = m_oldGroupLineStart != m_smartGroup->startLine();
00277   m_oldGroupLineStart = m_smartGroup->startLine();
00278   return ret;
00279 }
00280 
00281 void KateSmartCursor::setLineInternal( int newLine, bool internal )
00282 {
00283   setPositionInternal(KTextEditor::Cursor(newLine, column()), internal);
00284 }
00285 
00286 void KateSmartCursor::translated(const KateEditInfo & edit)
00287 {
00288   if (*this < edit.start()) {
00289     if (!range() || !static_cast<KateSmartRange*>(range())->feedbackEnabled())
00290       m_lastPosition = *this;
00291     return;
00292   }
00293 
00294   // We can rely on m_lastPosition because it is updated in translate(), otherwise just shifted() is called
00295   if (m_lastPosition != *this) {
00296     // position changed
00297     if (m_notifier)
00298       emit m_notifier->positionChanged(this);
00299     if (m_watcher)
00300       m_watcher->positionChanged(this);
00301   }
00302 
00303   if (!edit.oldRange().isEmpty() && edit.start() <= m_lastPosition && edit.oldRange().end() >= m_lastPosition) {
00304     if (edit.start() == m_lastPosition) {
00305       // character deleted after
00306       if (m_notifier)
00307         emit m_notifier->characterDeleted(this, false);
00308       if (m_watcher)
00309         m_watcher->characterDeleted(this, false);
00310 
00311     } else if (edit.oldRange().end() == m_lastPosition) {
00312       // character deleted before
00313       if (m_notifier)
00314         emit m_notifier->characterDeleted(this, true);
00315       if (m_watcher)
00316         m_watcher->characterDeleted(this, true);
00317 
00318     } else {
00319       // position deleted
00320       if (m_notifier)
00321         emit m_notifier->positionDeleted(this);
00322       if (m_watcher)
00323         m_watcher->positionDeleted(this);
00324     }
00325   }
00326 
00327   if (!edit.newRange().isEmpty()) {
00328     if (*this == edit.newRange().start()) {
00329       // character inserted after
00330       if (m_notifier)
00331         emit m_notifier->characterInserted(this, false);
00332       if (m_watcher)
00333         m_watcher->characterInserted(this, false);
00334 
00335     } else if (*this == edit.newRange().end()) {
00336       // character inserted before
00337       if (m_notifier)
00338         emit m_notifier->characterInserted(this, true);
00339       if (m_watcher)
00340         m_watcher->characterInserted(this, true);
00341     }
00342   }
00343 
00344   if (!range() || !static_cast<KateSmartRange*>(range())->feedbackEnabled())
00345     m_lastPosition = *this;
00346 }
00347 
00348 void KateSmartCursor::shifted( )
00349 {
00350   Q_ASSERT(m_lastPosition != *this);
00351 
00352   // position changed
00353   if (m_notifier)
00354     emit m_notifier->positionChanged(this);
00355   if (m_watcher)
00356     m_watcher->positionChanged(this);
00357 
00358   if (!range() || !static_cast<KateSmartRange*>(range())->feedbackEnabled())
00359     m_lastPosition = *this;
00360 }
00361 
00362 void KateSmartCursor::migrate( KateSmartGroup * newGroup )
00363 {
00364   int lineNum = line();
00365   m_smartGroup = newGroup;
00366   m_line = lineNum - m_smartGroup->startLine();
00367 }
00368 
00369 void KateSmartCursor::setPosition( const KTextEditor::Cursor & pos )
00370 {
00371   if (pos.line() > kateDocument()->lastLine()) {
00372     kWarning() << "Attempted to set cursor position " << pos << " past end of document " << document()->documentRange();
00373     setPositionInternal(invalid(), false);
00374     return;
00375   }
00376 
00377   setPositionInternal(pos, false);
00378 }
00379 
00380 void KateSmartCursor::resetLastPosition( )
00381 {
00382   m_lastPosition = *this;
00383 }
00384 
00385 bool KateSmartCursor::hasNotifier( ) const
00386 {
00387   return m_notifier;
00388 }
00389 
00390 KTextEditor::SmartCursorWatcher * KateSmartCursor::watcher( ) const
00391 {
00392   return m_watcher;
00393 }
00394 
00395 void KateSmartCursor::unbindFromRange( )
00396 {
00397   setRange(0L);
00398 }
00399 
00400 void KateSmartCursor::setInternal( )
00401 {
00402   m_isInternal = true;
00403 }
00404 
00405 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal