1  /****************************************************************************
2 **
3 ** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
4 **
5 ** This file is part of the Edyuk project <http://edyuk.org>
6 **
7 ** This file may be used under the terms of the GNU General Public License
8 ** version 3 as published by the Free Software Foundation and appearing in the
9 ** file GPL.txt included in the packaging of this file.
10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 **
14 ****************************************************************************/
15 
16 /*!
17 	\file qdocumentcursor.cpp
18 	\brief Implementation of the QDocumentCursor class
19 */
20 
21 #include "qdocumentcursor.h"
22 
23 /*!
24 	\ingroup document
25 	@{
26 */
27 
28 #include "qdocument_p.h"
29 
30 #include "qdocumentline.h"
31 
32 /*!
33 	\class QDocumentCursor
34 
35 	\brief A cursor to navigate within documents and edit them
36 
37 	QDocumentCursor is a central class of the public API.
38 
39 	It is the best (as in fastest and easiest) way to iterate over
40 	the content of a document.
41 
42 	It is also the only class that allows to perform editing operations.
43 
44 	A cursor position is defined by a line number and a text position
45 	within the line.
46 
47 	Every cursor can have one or two cursor positions. In the later
48 	case, they delimit a selection. The first position set (before
49 	selecting) is referred to as the "anchor" and the other (if it
50 	is different from the anchor) is the actual cursor position.
51 
52 	When the cursor does not have a selection, querying informations about
53 	the anchor has the same result as querying informations about the cursor
54 	position.
55 
56 	Informations you can get about both the anchor and the posiotion :
57 	<ul>
58 	<li>the line number : the logical line to which the cursor position points inside the document
59 	<li>the column number : the logical text column to which the cursor position points to, inside the pointed line.
60 	<li>the wrapped line offset : when a cursor resides on a wrapped line, this indicates in which part of
61 	the wrapped line it does
62 	<li>the document position : document (x, y) coordinates corresponding to the place the cursor is drawn
63 	</ul>
64 
65 	The visual line to which a given cursor resides can be obtained as follows :
66 
67 	\code
68 	int visual_line = cursor.document()->visualLine(cursor.lineNumber()) + cursor.wrappedLineOffset();
69 	\endcode
70 
71 	\note The line and column numbers passed to/returned by a cursor method
72 	always start at zero.
73 
74 	\note Quick overview of the various coordinate systems :
75 	<ul>
76 		<li>document coordinates aka viewport coordinates : (x, y) coords, in pixels, origin at the top left corner of
77 		the rectangle occupied by the very first line of the document
78 		<li>text coordinates : (line, column) in logical units (number of lines, number of characters)
79 		<li>visual text coordinates : (line, column) in logical units but with a different mapping
80 	</ul>
81 */
82 
QDocumentCursor(QDocument * doc)83 QDocumentCursor::QDocumentCursor(QDocument *doc)
84  : QObject(nullptr),m_handle(new QDocumentCursorHandle(doc))
85 {
86 	m_handle->ref();
87 }
88 
QDocumentCursor(const QDocumentCursor & from,const QDocumentCursor & to)89 QDocumentCursor::QDocumentCursor(const QDocumentCursor& from, const QDocumentCursor& to): QObject(nullptr){
90 	Q_ASSERT(from.document() == to.document());
91 	Q_ASSERT(from.handle());
92 	Q_ASSERT(to.handle());
93 	Q_ASSERT(from.hasSelection() == false);
94 	Q_ASSERT(to.hasSelection() == false);
95 
96 	m_handle = new QDocumentCursorHandle(from.document());
97 	m_handle->m_endLine = from.lineNumber();
98 	m_handle->m_endOffset = from.columnNumber();
99 	m_handle->m_begLine = to.lineNumber();
100 	m_handle->m_begOffset = to.columnNumber();
101 }
102 
QDocumentCursor(const QDocumentCursor & cursor)103 QDocumentCursor::QDocumentCursor(const QDocumentCursor& cursor)
104  : QObject(nullptr),m_handle(nullptr)
105 {
106 	if ( cursor.m_handle )
107 	{
108 		m_handle = cursor.m_handle->clone(true);
109 		m_handle->ref();
110 	}
111 }
112 
QDocumentCursor(const QDocumentCursor & cursor,const bool cloneAutoUpdateFlag)113 QDocumentCursor::QDocumentCursor(const QDocumentCursor& cursor, const bool cloneAutoUpdateFlag)
114  : QObject(nullptr),m_handle(nullptr)
115 {
116 	if ( cursor.m_handle )
117 	{
118 		m_handle = cursor.m_handle->clone(cloneAutoUpdateFlag);
119 		m_handle->ref();
120 	}
121 }
122 
123 
124 
QDocumentCursor(QDocument * doc,int line,int column,int lineTo,int columnTo)125 QDocumentCursor::QDocumentCursor(QDocument *doc, int line, int column, int lineTo, int columnTo)
126  : QObject(nullptr),m_handle(new QDocumentCursorHandle(doc, line, column, lineTo, columnTo))
127 {
128 	m_handle->ref();
129 }
130 
131 /*
132 QDocumentCursor::QDocumentCursor(const QDocumentLine& line, int column)
133  : m_handle(new QDocumentCursorHandle(line.document(), line.lineNumber()))
134 {
135 	m_handle->ref();
136 
137 	m_handle->setColumnNumber(column);
138 	//movePosition(qMin(column, line.length()));
139 }
140 */
141 
QDocumentCursor(QDocumentCursorHandle * handle)142 QDocumentCursor::QDocumentCursor(QDocumentCursorHandle *handle)
143  : QObject(nullptr),m_handle(handle)
144 {
145 	if ( m_handle )
146 		m_handle->ref();
147 }
148 
~QDocumentCursor()149 QDocumentCursor::~QDocumentCursor()
150 {
151 	if ( m_handle )
152 		m_handle->deref();
153 }
154 
clone(bool cloneAutoUpdatedFlag) const155 QDocumentCursor QDocumentCursor::clone(bool cloneAutoUpdatedFlag) const
156 {
157 	return m_handle ? QDocumentCursor(m_handle->clone(cloneAutoUpdatedFlag)) : QDocumentCursor();
158 }
159 
operator =(const QDocumentCursor & c)160 QDocumentCursor& QDocumentCursor::operator = (const QDocumentCursor& c)
161 {
162 	#if 0
163 	if ( m_handle )
164 		m_handle->deref();
165 
166 	m_handle = c.m_handle ? c.m_handle->clone() : 0;
167 	//m_handle = c.m_handle;
168 
169 	if ( m_handle )
170 		m_handle->ref();
171 	#endif
172 
173 	if ( c.m_handle )
174 	{
175 		if ( m_handle )
176 		{
177 			m_handle->copy(c.m_handle); //warning: this is inconsistent, a copied cursor is never auto updated,
178 		} else {                            //but the clones is. (there was however a reason for this behaviour)
179 			m_handle = c.m_handle->clone(true);
180 			m_handle->ref();
181 		}
182 	} else if ( m_handle ) {
183 
184 		//qWarning("Setting a cursor to null");
185 
186 		m_handle->deref();
187         m_handle = nullptr;
188 	}
189 
190 	return *this;
191 }
192 
193 /*!
194 	\brief comparision operator
195 
196 	\note If any of the operand is an invalid cursor, false is returned
197 */
operator ==(const QDocumentCursor & c) const198 bool QDocumentCursor::operator == (const QDocumentCursor& c) const
199 {
200 	if ( !m_handle || !c.m_handle )
201 		return false;
202 
203 	return m_handle->eq(c.m_handle);
204 }
205 
206 /*!
207 	\brief comparision operator
208 
209 	\note If any of the operand is an invalid cursor, true is returned (to preserve logical consistency with == )
210 */
operator !=(const QDocumentCursor & c) const211 bool QDocumentCursor::operator != (const QDocumentCursor& c) const
212 {
213 	if ( !m_handle || !c.m_handle )
214 		return true;
215 
216 	return !m_handle->eq(c.m_handle);
217 }
218 
219 /*!
220 	\brief comparision operator
221 
222 	\note If any of the operand is an invalid cursor, false is returned
223 */
operator <(const QDocumentCursor & c) const224 bool QDocumentCursor::operator < (const QDocumentCursor& c) const
225 {
226 	if ( !m_handle || !c.m_handle )
227 		return false;
228 
229 	return m_handle->lt(c.m_handle);
230 }
231 
232 /*!
233 	\brief comparision operator
234 
235 	\note If any of the operand is an invalid cursor, false is returned
236 */
operator >(const QDocumentCursor & c) const237 bool QDocumentCursor::operator > (const QDocumentCursor& c) const
238 {
239 	if ( !m_handle || !c.m_handle )
240 		return false;
241 
242 	return m_handle->gt(c.m_handle);
243 }
244 
245 /*!
246 	\brief comparision operator
247 
248 	\note If any of the operand is an invalid cursor, false is returned
249 */
operator <=(const QDocumentCursor & c) const250 bool QDocumentCursor::operator <= (const QDocumentCursor& c) const
251 {
252 	if ( !m_handle || !c.m_handle )
253 		return false;
254 
255 	return m_handle->lt(c.m_handle) || m_handle->eq(c.m_handle);
256 }
257 
258 /*!
259 	\brief comparision operator
260 
261 	\note If any of the operand is an invalid cursor, false is returned
262 */
operator >=(const QDocumentCursor & c) const263 bool QDocumentCursor::operator >= (const QDocumentCursor& c) const
264 {
265 	if ( !m_handle || !c.m_handle )
266 		return false;
267 
268 	return m_handle->gt(c.m_handle) || m_handle->eq(c.m_handle);
269 }
270 
271 /*!
272 	\brief comparision operator
273 */
isNull() const274 bool QDocumentCursor::isNull() const
275 {
276 	return !m_handle || !m_handle->document() || !line().isValid();
277 }
278 
beginBoundaryLarger(const QDocumentCursor & c) const279 bool QDocumentCursor::beginBoundaryLarger (const QDocumentCursor& c) const{
280 	if (!m_handle || !c.m_handle) return false;
281 	int line1, col1;
282 	m_handle->beginBoundary(line1,col1);
283 	int line2, col2;
284 	c.m_handle->beginBoundary(line2,col2);
285 	if (line1==line2)
286 		return col1>col2;
287 	else
288 		return line1>line2;
289 }
290 
equalBoundaries(const QDocumentCursor & c) const291 bool QDocumentCursor::equalBoundaries(const QDocumentCursor& c) const{
292 	if (!m_handle) return false;
293 	if (m_handle == c.m_handle) return true;
294 	return m_handle->equalBoundaries(c.m_handle);
295 }
296 
equal(const QDocumentCursor & c) const297 bool QDocumentCursor::equal(const QDocumentCursor& c) const{
298 	if (!m_handle) return false;
299 	if (m_handle == c.m_handle) return true;
300 	return m_handle->equal(c.m_handle);
301 }
302 
303 
304 /*!
305   Returns if my right boundary is larger (line/offset) than c
306 */
endBoundaryLarger(const QDocumentCursor & c) const307 bool QDocumentCursor::endBoundaryLarger (const QDocumentCursor& c) const{
308 	if (!m_handle || !c.m_handle) return false;
309 	int line1, col1;
310 	m_handle->endBoundary(line1,col1);
311 	int line2, col2;
312 	c.m_handle->endBoundary(line2,col2);
313 	if (line1==line2)
314 		return col1>col2;
315 	else
316 		return line1>line2;
317 }
318 
beginBoundary(int & begline,int & begcol) const319 void QDocumentCursor::beginBoundary(int& begline, int& begcol) const{
320 	if (!m_handle) {
321 		begline=-1;
322 		begcol=-1;
323 		return;
324 	}
325 	m_handle->beginBoundary(begline, begcol);
326 }
endBoundary(int & endline,int & endcol) const327 void QDocumentCursor::endBoundary(int& endline, int& endcol) const{
328 	if (!m_handle) {
329 		endline=-1;
330 		endcol=-1;
331 		return;
332 	}
333 	m_handle->endBoundary(endline, endcol);
334 }
boundaries(int & begline,int & begcol,int & endline,int & endcol) const335 void QDocumentCursor::boundaries(int& begline, int& begcol, int& endline, int& endcol) const{
336 	if (!m_handle) {
337 		begline=begcol=endline=endcol=-1;
338 		return;
339 	}
340 	m_handle->boundaries(begline,begcol,endline,endcol);
341 }
342 
343 
344 /*!
345 	\brief comparision operator
346 */
isValid() const347 bool QDocumentCursor::isValid() const
348 {
349 	return m_handle && m_handle->document() && line().isValid();
350 }
351 
352 /*!
353 	\return whether the cursor is at the end of the document
354 */
atEnd() const355 bool QDocumentCursor::atEnd() const
356 {
357 	return m_handle ? m_handle->atEnd() : false;
358 }
359 
360 /*!
361 	\return whether the cursor is at the begining of the document
362 */
atStart() const363 bool QDocumentCursor::atStart() const
364 {
365 	return m_handle ? m_handle->atStart() : false;
366 }
367 
368 /*!
369 	\return whether the cursor is at the end of a block
370 */
atBlockEnd() const371 bool QDocumentCursor::atBlockEnd() const
372 {
373 	return m_handle ? m_handle->atBlockEnd() : false;
374 }
375 
376 /*!
377 	\return whether the cursor is at the start of a block
378 */
atBlockStart() const379 bool QDocumentCursor::atBlockStart() const
380 {
381 	return m_handle ? m_handle->atBlockStart() : false;
382 }
383 
384 /*!
385 	\return whether the cursor is at the end of a line
386 
387 	\note this may only differ from atBlockEnd() on wrapped lines
388 */
atLineEnd() const389 bool QDocumentCursor::atLineEnd() const
390 {
391 	return m_handle ? m_handle->atLineEnd() : false;
392 }
393 
394 /*!
395 	\return whether the cursor is at the start of a line
396 
397 	\note this may only differ from atBlockStart() on wrapped lines
398 */
atLineStart() const399 bool QDocumentCursor::atLineStart() const
400 {
401 	return m_handle ? m_handle->atLineStart() : false;
402 }
403 
404 /*!
405 	\return the document on which this cursor operates
406 */
document() const407 QDocument* QDocumentCursor::document() const
408 {
409     return m_handle ? m_handle->document() : nullptr;
410 }
411 
412 /*!
413 	\return the text column of the anchor
414 */
anchorColumnNumber() const415 int QDocumentCursor::anchorColumnNumber() const
416 {
417 	return m_handle ? m_handle->anchorColumnNumber() : -1;
418 }
419 
startLineNumber() const420 int QDocumentCursor::startLineNumber() const{
421 	return m_handle ? m_handle->startLineNumber() : -1;
422 }
startColumnNumber() const423 int QDocumentCursor::startColumnNumber() const{
424 	return m_handle ? m_handle->startColumnNumber() : -1;
425 }
426 
endLineNumber() const427 int QDocumentCursor::endLineNumber() const{
428 	return m_handle ? m_handle->endLineNumber() : -1;
429 }
endColumnNumber() const430 int QDocumentCursor::endColumnNumber() const{
431 	return m_handle ? m_handle->endColumnNumber() : -1;
432 }
433 
434 
435 /*!
436 	\return the "visual" text column of the cursor
437 
438 	\note this may only differ from columnNumber() when there are tabs on the line
439 */
visualColumnNumber() const440 int QDocumentCursor::visualColumnNumber() const
441 {
442 	return m_handle ? m_handle->visualColumnNumber() : -1;
443 }
444 
445 /*!
446 	\return the text column of the cursor
447 */
columnNumber() const448 int QDocumentCursor::columnNumber() const
449 {
450 	return m_handle ? m_handle->columnNumber() : -1;
451 }
452 
453 
setLineNumber(int l,MoveMode m)454 void QDocumentCursor::setLineNumber(int l, MoveMode m)
455 {
456 	if ( m_handle )
457 		m_handle->setLineNumber(l, m);
458 }
459 
460 /*!
461 	\brief Set the text column of the cursor
462 	\param c text column to set
463 	\param m move mode (determines whether text will be selected)
464 */
setColumnNumber(int c,MoveMode m)465 void QDocumentCursor::setColumnNumber(int c, MoveMode m)
466 {
467 	if ( m_handle )
468 		m_handle->setColumnNumber(c, m);
469 }
470 
setAnchorLineNumber(int c) const471 void QDocumentCursor::setAnchorLineNumber(int c) const{
472 	if ( m_handle )
473 		m_handle->setAnchorLineNumber(c);
474 }
475 
setAnchorColumnNumber(int c) const476 void QDocumentCursor::setAnchorColumnNumber(int c) const{
477 	if ( m_handle )
478 		m_handle->setAnchorColumnNumber(c);
479 }
480 
481 
482 /*!
483 	\return The line number to which the cursor points
484 */
lineNumber() const485 int QDocumentCursor::lineNumber() const
486 {
487 	return m_handle ? m_handle->lineNumber() : -1;
488 }
489 
490 /*!
491 	\return The line number to which the cursor points
492 */
anchorLineNumber() const493 int QDocumentCursor::anchorLineNumber() const
494 {
495 	return m_handle ? m_handle->anchorLineNumber() : -1;
496 }
497 
498 /*!
499 	\return The wrapped line on which the cursor resides
500 
501 	Wrapped line are "sublines" of logical lines.
502 */
wrappedLineOffset() const503 int QDocumentCursor::wrappedLineOffset() const
504 {
505 	return line().wrappedLineForCursor(columnNumber());
506 }
507 
508 /*!
509 	\return The line number on which the anchor resides
510 */
anchorWrappedLineOffset() const511 int QDocumentCursor::anchorWrappedLineOffset() const
512 {
513 	return anchorLine().wrappedLineForCursor(anchorColumnNumber());
514 }
515 
516 /*!
517 	\return the document position at which the cursor is
518 
519 	Document position and viewport position are two terms used interchangeably.
520 	The only difference is the former refers to model perception (QDocument)
521 	whereas the later refers to view perception (QEditor)
522 */
documentPosition() const523 QPointF QDocumentCursor::documentPosition() const
524 {
525     return m_handle ? m_handle->documentPosition() : QPointF();
526 }
527 
528 /*!
529 	\return the document position of the anchor
530 */
anchorDocumentPosition() const531 QPointF QDocumentCursor::anchorDocumentPosition() const
532 {
533     return m_handle ? m_handle->anchorDocumentPosition() : QPointF();
534 }
535 
documentRegion() const536 QPolygonF QDocumentCursor::documentRegion() const
537 {
538     return m_handle ? m_handle->documentRegion() : QPolygonF();
539 }
540 
541 /*!
542 	\return The line object on which the cursor resides
543 */
line() const544 QDocumentLine QDocumentCursor::line() const
545 {
546 	return m_handle ? m_handle->line() : QDocumentLine();
547 }
548 
549 /*!
550 	\return The line object on which the anchor resides
551 */
anchorLine() const552 QDocumentLine QDocumentCursor::anchorLine() const
553 {
554 	return m_handle ? m_handle->anchorLine() : QDocumentLine();
555 }
556 
557 /*!
558 	\brief Shift cursor position (text column) by a number of columns (characters)
559 */
shift(int offset)560 void QDocumentCursor::shift(int offset)
561 {
562 	if ( m_handle )
563 		m_handle->shift(offset);
564 }
565 
566 /*!
567 	\brief Set the text position of the cursor (within the whole document)
568 
569 	Remark made about position() applies.
570 */
setPosition(int pos,MoveMode m)571 void QDocumentCursor::setPosition(int pos, MoveMode m)
572 {
573 	if ( m_handle )
574 		m_handle->setPosition(pos, m);
575 }
576 
577 /*!
578 	\brief Moves the cursor position
579 	\param offset number of times the selected move will be done
580 	\param op movement type
581 	\param m movement mode (whether to select)
582 	\return true on succes
583 */
movePosition(int offset,MoveOperation op,MoveMode m)584 bool QDocumentCursor::movePosition(int offset, MoveOperation op, MoveMode m)
585 {
586 	return m_handle ? m_handle->movePosition(offset, op, m) : false;
587 }
588 
589 /*!
590 	\brief Jump to another cursor position
591 	\param line target line number
592 	\param colum target text column
593 */
moveTo(int line,int column,MoveMode m)594 void QDocumentCursor::moveTo(int line, int column, MoveMode m)
595 {
596 	if ( m_handle )
597 		m_handle->moveTo(line, column,m);
598 }
599 
600 
601 /*!
602 	\brief Jump to the position of another cursor
603 	\param c target cursor
604 */
moveTo(const QDocumentCursor & c,MoveMode m)605 void QDocumentCursor::moveTo(const QDocumentCursor &c, MoveMode m)
606 {
607 	if ( m_handle )
608 		m_handle->moveTo(c,m);
609 }
610 
611 /*!
612 	\brief Jump to another cursor position
613 	\param l target line
614 	\param column target text column
615 
616 	\note Calls QDocumentLine::lineNumber() => SLOW : avoid whenever possible
617 */
618 /*void QDocumentCursor::moveTo(const QDocumentLine &l, int column, MoveMode m)
619 {
620 	if ( m_handle )
621 		m_handle->moveTo(l.lineNumber(), column, m);
622 }*/
623 
624 /*!
625 	\return the character at the position immediately after the cursor
626 */
nextChar() const627 QChar QDocumentCursor::nextChar() const
628 {
629 	return m_handle ? m_handle->nextChar() : QChar();
630 }
631 
632 /*!
633 	\return the character at the position immediately before the cursor
634 */
previousChar() const635 QChar QDocumentCursor::previousChar() const
636 {
637 	return m_handle ? m_handle->previousChar() : QChar();
638 }
639 
640 /*!
641 	\brief Delete the character at the position immediately after the cursor
642 */
deleteChar()643 void QDocumentCursor::deleteChar()
644 {
645 	if ( m_handle )
646 		m_handle->deleteChar();
647 }
648 
649 /*!
650 	\brief Delete the character at the position immediately before the cursor
651 */
deletePreviousChar()652 void QDocumentCursor::deletePreviousChar()
653 {
654 	if ( m_handle )
655 		m_handle->deletePreviousChar();
656 }
657 
658 /*!
659 	\brief erase the whole line the cursor is on, newline included
660 */
eraseLine()661 void QDocumentCursor::eraseLine()
662 {
663 	if ( m_handle )
664 		m_handle->eraseLine();
665 }
666 
667 /*!
668 	\brief insert a new line at the cursor position
669 */
insertLine(bool keepAnchor)670 void QDocumentCursor::insertLine(bool keepAnchor)
671 {
672 	if ( m_handle )
673 		m_handle->insertText("\n", keepAnchor);
674 }
675 
676 /*!
677 	\brief insert some text at the cursor position
678 
679 	Selected text will be removed before insertion happens.
680 
681 	\note Nothing happens if \a s is empty
682 */
insertText(const QString & s,bool keepAnchor)683 void QDocumentCursor::insertText(const QString& s, bool keepAnchor)
684 {
685 	if ( m_handle )
686 		m_handle->insertText(s, keepAnchor);
687 }
688 
689 /*!
690 	\return A cursor pointing at the position of the selection start.
691 
692 	Selection start is the position of the selection that is nearest to document start.
693 
694 	\note an invalid cursor is returned when the cursor does not have a selection
695 */
selectionStart() const696 QDocumentCursor QDocumentCursor::selectionStart() const
697 {
698 	return m_handle ? m_handle->selectionStart() : QDocumentCursor();
699 }
700 
701 /*!
702 	\return A cursor pointing at the position of the selection end.
703 
704 	Selection end is the position of the selection that is nearest to document end.
705 
706 	\note an invalid cursor is returned when the cursor does not have a selection
707 */
selectionEnd() const708 QDocumentCursor QDocumentCursor::selectionEnd() const
709 {
710 	return m_handle ? m_handle->selectionEnd() : QDocumentCursor();
711 }
712 
713 /*!
714 	\return A cursor pointing at the position of the anchor.
715 */
anchorCursor() const716 QDocumentCursor QDocumentCursor::anchorCursor() const
717 {
718 	return m_handle ? m_handle->anchorCursor() : QDocumentCursor();
719 }
720 
721 /*!
722 	\return The selected text
723 */
selectedText() const724 QString QDocumentCursor::selectedText() const
725 {
726 	return m_handle ? m_handle->selectedText() : QString();
727 }
728 
729 
730 /*!
731 	\brief Remove the selected text
732 */
removeSelectedText()733 void QDocumentCursor::removeSelectedText()
734 {
735 	if ( m_handle )
736 		m_handle->removeSelectedText();
737 }
738 
739 /*!
740 	\brief Replace the selected text
741 
742 	This method differs from insertText() in two ways :
743 	<ul>
744 		<li>if \a text is empty the selection WILL be removed
745 		<li>after the replacement happens this command will
746 		cause the cursor to select the new text (note that this
747 		information is NOT preserved by the undo/redo stack
748 		however).
749 	</ul>
750 */
replaceSelectedText(const QString & text)751 void QDocumentCursor::replaceSelectedText(const QString& text)
752 {
753 	if ( m_handle )
754 		m_handle->replaceSelectedText(text);
755 }
756 
757 /*!
758 	\brief Begin an edit block
759 
760 	Edit blocks are command groups. All the commands in an edit block
761 	are executed in a row when the edit block is ended with endEditBlock().
762 
763 	Edit blocks are considered as a single command as far as the undo/redo
764 	stack is concerned.
765 
766 	Edit blocks can be nested but that isn't of much use
767 */
beginEditBlock()768 void QDocumentCursor::beginEditBlock()
769 {
770 	if ( m_handle )
771 		m_handle->beginEditBlock();
772 }
773 
774 /*!
775 	\brief End an edit block
776 */
endEditBlock()777 void QDocumentCursor::endEditBlock()
778 {
779 	if ( m_handle )
780 		m_handle->endEditBlock();
781 }
782 
783 /*!
784 	\return Whether the cursor is silent
785 */
isSilent() const786 bool QDocumentCursor::isSilent() const
787 {
788 	return m_handle ? m_handle->isSilent() : true;
789 }
790 
791 /*!
792 	\brief Set whether the cursor is silent
793 */
setSilent(bool y)794 void QDocumentCursor::setSilent(bool y)
795 {
796 	if ( m_handle )
797 		m_handle->setSilent(y);
798 
799 }
800 
801 /*!
802 	\return whether the cursor is auto updated
803 
804 	An auto updated cursor will remain on the actual line it points
805 	to when the document is modified.
806 
807 	\code
808 	QDocumentCursor c1(10, 0, document), c2(10, 0, document), c(5, 0, document);
809 
810 	c1.setAutoUpdated(true);
811 
812 	c.insertLine();
813 
814 	// at this point c2 still points to line 10 whereas c1 points to line 11
815 	\endcode
816 */
isAutoUpdated() const817 bool QDocumentCursor::isAutoUpdated() const
818 {
819 	return m_handle ? m_handle->isAutoUpdated() : true;
820 }
821 
822 /*!
823 	\brief Set whether the cursor is aut updated
824 */
setAutoUpdated(bool y)825 void QDocumentCursor::setAutoUpdated(bool y)
826 {
827 	if ( m_handle )
828 		m_handle->setAutoUpdated(y);
829 }
830 
isAutoErasable() const831 bool QDocumentCursor::isAutoErasable() const{
832 	return m_handle ? m_handle->isAutoErasable() : true;
833 }
setAutoErasable(bool y)834 void QDocumentCursor::setAutoErasable(bool y){
835 	if ( m_handle )
836 		m_handle->setAutoErasable(y);
837 }
838 
839 
840 /*!
841 	\brief Refresh the column memory of the cursor
842 
843 	This set the current column memory to the current column position.
844 
845 	\note It is not recommended to call that yourself. The various
846 	movement method should do that perfectly fine.
847 */
refreshColumnMemory()848 void QDocumentCursor::refreshColumnMemory()
849 {
850 	if ( m_handle )
851 		m_handle->refreshColumnMemory();
852 
853 }
854 
855 /*!
856 	\return Whether the cursor has column memory
857 
858 	The column memory is a feature that allow a cursor
859 	to remember its biggest column number so that moving
860 	back and forth (with movePosition()) on lines of
861 	different width does not result in the column to change.
862 
863 */
hasColumnMemory() const864 bool QDocumentCursor::hasColumnMemory() const
865 {
866 	return m_handle ? m_handle->hasColumnMemory() : false;
867 }
868 
869 /*!
870 	\brief Set whether the cursor use column memory
871 */
setColumnMemory(bool y)872 void QDocumentCursor::setColumnMemory(bool y)
873 {
874 	if ( m_handle )
875 		m_handle->setColumnMemory(y);
876 
877 }
878 
879 /*!
880 	\return whether the cursor has a selection
881 */
hasSelection() const882 bool QDocumentCursor::hasSelection() const
883 {
884 	return m_handle ? m_handle->hasSelection() : false;
885 }
886 
887 /*!
888  * \return true if there is an selection and the anchor is before the cursor
889  */
isForwardSelection() const890 bool QDocumentCursor::isForwardSelection() const
891 {
892 	return m_handle ? m_handle->isForwardSelection() : false;
893 }
894 
895 /*!
896 	\brief clear the selection
897 */
clearSelection()898 void QDocumentCursor::clearSelection()
899 {
900 	if ( m_handle )
901 		m_handle->clearSelection();
902 
903 }
904 
905 /*!
906  * \brief exchanges cursor and anchor positions
907  */
flipSelection()908 void QDocumentCursor::flipSelection() {
909 	if ( m_handle )
910 		m_handle->flipSelection();
911 }
912 
913 /*!
914 	\brief Select something
915 */
select(SelectionType t)916 void QDocumentCursor::select(SelectionType t)
917 {
918 	if ( m_handle )
919 		m_handle->select(t);
920 
921 }
922 
923 /*!
924 	\brief Expand a current selection
925 */
expandSelect(QDocumentCursor::SelectionType t)926 void QDocumentCursor::expandSelect(QDocumentCursor::SelectionType t)
927 {
928 	if ( m_handle )
929 		m_handle->expandSelect(t);
930 }
931 
932 /*!
933 	\brief Set the selection boundary
934 
935 	Select text between the current cursor anchor and the one
936 	of \a c.
937 
938 	\note We mean ANCHOR. If the cursor already has a selection the
939 	anchor will not change, but the position will be set to that of
940 	\a c.
941 */
setSelectionBoundary(const QDocumentCursor & c)942 void QDocumentCursor::setSelectionBoundary(const QDocumentCursor& c)
943 {
944 	if ( m_handle )
945 		m_handle->setSelectionBoundary(c);
946 }
947 
select(int line,int column,int lineTo,int columnTo)948 void QDocumentCursor::select(int line, int column, int lineTo, int columnTo){
949 	if ( m_handle )
950 		m_handle->select(line, column, lineTo, columnTo);
951 }
952 
selectColumns(int column,int columnTo)953 void QDocumentCursor::selectColumns(int column, int columnTo){
954 	if ( m_handle )
955 		m_handle->select(lineNumber(), column, lineNumber(), columnTo);
956 }
957 
958 /*!
959 	\return whether the given cursor c is within the selection of this (ignores selection of c)
960 */
isWithinSelection(const QDocumentCursor & c) const961 bool QDocumentCursor::isWithinSelection(const QDocumentCursor& c) const
962 {
963 	return m_handle ? m_handle->isWithinSelection(c) : false;
964 }
965 
966 /*!
967   Creates a new cursor whose selection is the largest region which is contained in the selection of both
968   (returns c if c has no selection but is within the selection of c and returns an invalid cursor if
969   this has no selection)
970 */
intersect(const QDocumentCursor & c) const971 QDocumentCursor QDocumentCursor::intersect(const QDocumentCursor& c) const{
972 	return m_handle ? m_handle->intersect(c) : QDocumentCursor();
973 }
974 
975 /*!
976   Sets the selection given by lbeg/cbeg/lend/cend to the largest selection which is contained in
977   the selection of this cursor and the passed boundaries
978   (it sets all to -1 if such a selection doesn't exists)
979 */
intersectBoundaries(int & lbeg,int & cbeg,int & lend,int & cend) const980 void QDocumentCursor::intersectBoundaries(int& lbeg, int& cbeg, int& lend, int& cend) const{
981 	if (m_handle)
982 		m_handle->intersectBoundaries(lbeg, cbeg, lend, cend);
983 }
984 
985 
986 
getMatchingPair(QDocumentCursor & from,QDocumentCursor & to,bool maximal) const987 void QDocumentCursor::getMatchingPair(QDocumentCursor& from, QDocumentCursor& to, bool maximal) const{
988 	if (m_handle)
989 		m_handle->getMatchingPair(from, to, maximal);
990 	else
991 		from = to = QDocumentCursor();
992 
993 }
994 
995 /*!
996 	\return selection information
997 
998 	\note The QDocumentSelection object is not updated if the selection
999 	changes later on : use it right away and do not store it.
1000 */
selection() const1001 QDocumentSelection QDocumentCursor::selection() const
1002 {
1003 	QDocumentSelection s;
1004 
1005 	if ( isNull() || !hasSelection() )
1006 	{
1007 		qDebug("NULL selection");
1008 
1009 		s.startLine = -1;
1010 		s.endLine = -1;
1011 
1012 		s.start = -1;
1013 		s.end = -1;
1014 	} else if ( m_handle->m_begLine == m_handle->m_endLine ) {
1015 
1016 		s.startLine = m_handle->m_begLine;
1017 		s.endLine = m_handle->m_begLine;
1018 
1019 		s.start = qMin(m_handle->m_begOffset, m_handle->m_endOffset);
1020 		s.end = qMax(m_handle->m_begOffset, m_handle->m_endOffset);
1021 
1022 	} else if ( m_handle->m_begLine > m_handle->m_endLine ) {
1023 
1024 		s.startLine = m_handle->m_endLine;
1025 		s.endLine = m_handle->m_begLine;
1026 
1027 		s.start = m_handle->m_endOffset;
1028 		s.end = m_handle->m_begOffset;
1029 
1030 		//qDebug("[(%i,%i);(%i,%i)]", s.startLine.lineNumber(), s.start, s.endLine.lineNumber(), s.end);
1031 	} else {
1032 		s.startLine = m_handle->m_begLine;
1033 		s.endLine = m_handle->m_endLine;
1034 
1035 		s.start = m_handle->m_begOffset;
1036 		s.end = m_handle->m_endOffset;
1037 
1038 		//qDebug("[(%i,%i);(%i,%i)]", s.startLine.lineNumber(), s.start, s.endLine.lineNumber(), s.end);
1039 	}
1040 
1041 	return s;
1042 }
1043 
isRTL() const1044 bool QDocumentCursor::isRTL() const{
1045 	return m_handle && m_handle->isRTL();
1046 }
1047 
sort(QDocumentCursor & from,QDocumentCursor & to)1048 void QDocumentCursor::sort(QDocumentCursor& from, QDocumentCursor& to){
1049 	if (from < to) return;
1050 	QDocumentCursorHandle* temp = to.m_handle;
1051 	to.m_handle = from.m_handle;
1052 	from.m_handle = temp;
1053 }
1054 
1055 /*! @} */
1056 
1057