Kate
katetextrange.cpp
Go to the documentation of this file.
00001 /* This file is part of the Kate project. 00002 * 00003 * Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org> 00004 * 00005 * Based on code of the SmartCursor/Range by: 00006 * Copyright (C) 2003-2005 Hamish Rodda <rodda@kde.org> 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public License 00019 * along with this library; see the file COPYING.LIB. If not, write to 00020 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 * Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "katetextrange.h" 00025 #include "katetextbuffer.h" 00026 00027 namespace Kate { 00028 00029 TextRange::TextRange (TextBuffer &buffer, const KTextEditor::Range &range, InsertBehaviors insertBehavior, EmptyBehavior emptyBehavior) 00030 : m_buffer (buffer) 00031 , m_start (buffer, this, range.start(), (insertBehavior & ExpandLeft) ? Kate::TextCursor::StayOnInsert : Kate::TextCursor::MoveOnInsert) 00032 , m_end (buffer, this, range.end(), (insertBehavior & ExpandRight) ? Kate::TextCursor::MoveOnInsert : Kate::TextCursor::StayOnInsert) 00033 , m_view (0) 00034 , m_feedback (0) 00035 , m_zDepth (0.0) 00036 , m_attributeOnlyForViews (false) 00037 , m_invalidateIfEmpty (emptyBehavior == InvalidateIfEmpty) 00038 { 00039 // remember this range in buffer 00040 m_buffer.m_ranges.insert (this); 00041 00042 // check if range now invalid, there can happen no feedback, as m_feedback == 0 00043 checkValidity (); 00044 } 00045 00046 TextRange::~TextRange () 00047 { 00051 m_feedback = 0; 00052 00053 // remove range from m_ranges 00054 fixLookup (m_start.line(), m_end.line(), -1, -1); 00055 00056 // remove this range from the buffer 00057 m_buffer.m_ranges.remove (this); 00058 00064 if (m_attribute) 00065 m_buffer.notifyAboutRangeChange (m_view, m_start.line(), m_end.line(), true /* we have a attribute */); 00066 } 00067 00068 void TextRange::setInsertBehaviors (InsertBehaviors _insertBehaviors) 00069 { 00073 if (_insertBehaviors == insertBehaviors ()) 00074 return; 00075 00079 m_start.setInsertBehavior ((_insertBehaviors & ExpandLeft) ? KTextEditor::MovingCursor::StayOnInsert : KTextEditor::MovingCursor::MoveOnInsert); 00080 m_end.setInsertBehavior ((_insertBehaviors & ExpandRight) ? KTextEditor::MovingCursor::MoveOnInsert : KTextEditor::MovingCursor::StayOnInsert); 00081 00085 if (m_attribute || m_feedback) 00086 m_buffer.notifyAboutRangeChange (m_view, m_start.line(), m_end.line(), true /* we have a attribute */); 00087 } 00088 00089 KTextEditor::MovingRange::InsertBehaviors TextRange::insertBehaviors () const 00090 { 00091 InsertBehaviors behaviors = DoNotExpand; 00092 00093 if (m_start.insertBehavior() == KTextEditor::MovingCursor::StayOnInsert) 00094 behaviors = behaviors & ExpandLeft; 00095 00096 if (m_end.insertBehavior() == KTextEditor::MovingCursor::MoveOnInsert) 00097 behaviors = behaviors & ExpandRight; 00098 00099 return behaviors; 00100 } 00101 00102 void TextRange::setEmptyBehavior (EmptyBehavior emptyBehavior) 00103 { 00107 if (m_invalidateIfEmpty == (emptyBehavior == InvalidateIfEmpty)) 00108 return; 00109 00113 m_invalidateIfEmpty = (emptyBehavior == InvalidateIfEmpty); 00114 00118 if (end() <= start()) 00119 setRange (KTextEditor::Range::invalid()); 00120 } 00121 00122 void TextRange::setRange (const KTextEditor::Range &range) 00123 { 00124 // avoid work if nothing changed! 00125 if (range == toRange()) 00126 return; 00127 00128 // remember old line range 00129 int oldStartLine = m_start.line(); 00130 int oldEndLine = m_end.line(); 00131 00132 // change start and end cursor 00133 m_start.setPosition (range.start ()); 00134 m_end.setPosition (range.end ()); 00135 00136 // check if range now invalid, don't emit feedback here, will be handled below 00137 // otherwise you can't delete ranges in feedback! 00138 checkValidity (oldStartLine, oldEndLine, false); 00139 00140 // no attribute or feedback set, be done 00141 if (!m_attribute && !m_feedback) 00142 return; 00143 00144 // get full range 00145 int startLineMin = oldStartLine; 00146 if (oldStartLine == -1 || (m_start.line() != -1 && m_start.line() < oldStartLine)) 00147 startLineMin = m_start.line(); 00148 00149 int endLineMax = oldEndLine; 00150 if (oldEndLine == -1 || m_end.line() > oldEndLine) 00151 endLineMax = m_end.line(); 00152 00157 m_buffer.notifyAboutRangeChange (m_view, startLineMin, endLineMax, m_attribute); 00158 00159 // perhaps need to notify stuff! 00160 if (m_feedback) { 00161 // do this last: may delete this range 00162 if (!toRange().isValid()) 00163 m_feedback->rangeInvalid (this); 00164 else if (toRange().isEmpty()) 00165 m_feedback->rangeEmpty (this); 00166 } 00167 } 00168 00169 void TextRange::checkValidity (int oldStartLine, int oldEndLine, bool notifyAboutChange) 00170 { 00174 if (!m_start.isValid() || !m_end.isValid() || (m_invalidateIfEmpty && m_end <= m_start)) { 00175 m_start.setPosition (-1, -1); 00176 m_end.setPosition (-1, -1); 00177 } 00178 00182 if (!m_invalidateIfEmpty && m_end < m_start) 00183 m_end.setPosition (m_start); 00184 00185 // fix lookup 00186 fixLookup (oldStartLine, oldEndLine, m_start.line(), m_end.line()); 00187 00188 // perhaps need to notify stuff! 00189 if (notifyAboutChange && m_feedback) { 00190 m_buffer.notifyAboutRangeChange (m_view, m_start.line(), m_end.line(), false /* attribute not interesting here */); 00191 00192 // do this last: may delete this range 00193 if (!toRange().isValid()) 00194 m_feedback->rangeInvalid (this); 00195 else if (toRange().isEmpty()) 00196 m_feedback->rangeEmpty (this); 00197 } 00198 } 00199 00200 void TextRange::fixLookup (int oldStartLine, int oldEndLine, int startLine, int endLine) 00201 { 00202 // nothing changed? 00203 if (oldStartLine == startLine && oldEndLine == endLine) 00204 return; 00205 00206 // now, not both can be invalid 00207 Q_ASSERT (oldStartLine >= 0 || startLine >= 0); 00208 Q_ASSERT (oldEndLine >= 0 || endLine >= 0); 00209 00210 // get full range 00211 int startLineMin = oldStartLine; 00212 if (oldStartLine == -1 || (startLine != -1 && startLine < oldStartLine)) 00213 startLineMin = startLine; 00214 00215 int endLineMax = oldEndLine; 00216 if (oldEndLine == -1 || endLine > oldEndLine) 00217 endLineMax = endLine; 00218 00219 // get start block 00220 int blockIndex = m_buffer.blockForLine (startLineMin); 00221 Q_ASSERT (blockIndex >= 0); 00222 00223 // remove this range from m_ranges 00224 for (; blockIndex < m_buffer.m_blocks.size(); ++blockIndex) { 00225 // get block 00226 TextBlock *block = m_buffer.m_blocks[blockIndex]; 00227 00228 // either insert or remove range 00229 if ((endLine < block->startLine()) || (startLine >= (block->startLine() + block->lines()))) 00230 block->removeRange (this); 00231 else 00232 block->updateRange (this); 00233 00234 // ok, reached end block 00235 if (endLineMax < (block->startLine() + block->lines())) 00236 return; 00237 } 00238 00239 // we should not be here, really, then endLine is wrong 00240 Q_ASSERT (false); 00241 } 00242 00243 void TextRange::setView (KTextEditor::View *view) 00244 { 00248 if (view == m_view) 00249 return; 00250 00254 m_view = view; 00255 00260 if (m_attribute || m_feedback) 00261 m_buffer.notifyAboutRangeChange (0, m_start.line(), m_end.line(), m_attribute); 00262 } 00263 00264 void TextRange::setAttribute ( KTextEditor::Attribute::Ptr attribute ) 00265 { 00269 m_attribute = attribute; 00270 00275 m_buffer.notifyAboutRangeChange (m_view, m_start.line(), m_end.line(), m_attribute); 00276 } 00277 00278 void TextRange::setFeedback (KTextEditor::MovingRangeFeedback *feedback) 00279 { 00283 if (feedback == m_feedback) 00284 return; 00285 00289 m_feedback = feedback; 00290 00295 m_buffer.notifyAboutRangeChange (m_view, m_start.line(), m_end.line(), m_attribute); 00296 } 00297 00298 void TextRange::setAttributeOnlyForViews (bool onlyForViews) 00299 { 00303 m_attributeOnlyForViews = onlyForViews; 00304 } 00305 00306 void TextRange::setZDepth (qreal zDepth) 00307 { 00311 if (zDepth == m_zDepth) 00312 return; 00313 00317 m_zDepth = zDepth; 00318 00322 if (m_attribute) 00323 m_buffer.notifyAboutRangeChange (m_view, m_start.line(), m_end.line(), m_attribute); 00324 } 00325 00326 KTextEditor::Document *Kate::TextRange::document () const 00327 { 00328 return m_buffer.document(); 00329 } 00330 00331 }
KDE 4.6 API Reference