source: trunk/src/gui/widgets/qtextedit.cpp@ 966

Last change on this file since 966 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 79.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qtextedit_p.h"
43#include "qlineedit.h"
44#include "qtextbrowser.h"
45
46#ifndef QT_NO_TEXTEDIT
47#include <qfont.h>
48#include <qpainter.h>
49#include <qevent.h>
50#include <qdebug.h>
51#include <qmime.h>
52#include <qdrag.h>
53#include <qclipboard.h>
54#include <qmenu.h>
55#include <qstyle.h>
56#include <qtimer.h>
57#include "private/qtextdocumentlayout_p.h"
58#include "qtextdocument.h"
59#include "private/qtextdocument_p.h"
60#include "qtextlist.h"
61#include "private/qtextcontrol_p.h"
62
63#include <qtextformat.h>
64#include <qdatetime.h>
65#include <qapplication.h>
66#include <limits.h>
67#include <qtexttable.h>
68#include <qvariant.h>
69
70#include <qinputcontext.h>
71#endif
72
73QT_BEGIN_NAMESPACE
74
75
76#ifndef QT_NO_TEXTEDIT
77static inline bool shouldEnableInputMethod(QTextEdit *textedit)
78{
79 return !textedit->isReadOnly();
80}
81
82class QTextEditControl : public QTextControl
83{
84public:
85 inline QTextEditControl(QObject *parent) : QTextControl(parent) {}
86
87 virtual QMimeData *createMimeDataFromSelection() const {
88 QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
89 if (!ed)
90 return QTextControl::createMimeDataFromSelection();
91 return ed->createMimeDataFromSelection();
92 }
93 virtual bool canInsertFromMimeData(const QMimeData *source) const {
94 QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
95 if (!ed)
96 return QTextControl::canInsertFromMimeData(source);
97 return ed->canInsertFromMimeData(source);
98 }
99 virtual void insertFromMimeData(const QMimeData *source) {
100 QTextEdit *ed = qobject_cast<QTextEdit *>(parent());
101 if (!ed)
102 QTextControl::insertFromMimeData(source);
103 else
104 ed->insertFromMimeData(source);
105 }
106};
107
108QTextEditPrivate::QTextEditPrivate()
109 : control(0),
110 autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false),
111 lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0),
112 wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), clickCausedFocus(0),
113 textFormat(Qt::AutoText)
114{
115 ignoreAutomaticScrollbarAdjustment = false;
116 preferRichText = false;
117 showCursorOnInitialShow = true;
118 inDrag = false;
119}
120
121void QTextEditPrivate::createAutoBulletList()
122{
123 QTextCursor cursor = control->textCursor();
124 cursor.beginEditBlock();
125
126 QTextBlockFormat blockFmt = cursor.blockFormat();
127
128 QTextListFormat listFmt;
129 listFmt.setStyle(QTextListFormat::ListDisc);
130 listFmt.setIndent(blockFmt.indent() + 1);
131
132 blockFmt.setIndent(0);
133 cursor.setBlockFormat(blockFmt);
134
135 cursor.createList(listFmt);
136
137 cursor.endEditBlock();
138 control->setTextCursor(cursor);
139}
140
141void QTextEditPrivate::init(const QString &html)
142{
143 Q_Q(QTextEdit);
144 control = new QTextEditControl(q);
145 control->setPalette(q->palette());
146
147 QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(updateMicroFocus()));
148 QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars()));
149 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(_q_repaintContents(QRectF)));
150 QObject::connect(control, SIGNAL(visibilityRequest(QRectF)), q, SLOT(_q_ensureVisible(QRectF)));
151 QObject::connect(control, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
152 q, SLOT(_q_currentCharFormatChanged(QTextCharFormat)));
153
154 QObject::connect(control, SIGNAL(textChanged()), q, SIGNAL(textChanged()));
155 QObject::connect(control, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
156 QObject::connect(control, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
157 QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool)));
158 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
159 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
160
161 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));
162
163 QTextDocument *doc = control->document();
164 // set a null page size initially to avoid any relayouting until the textedit
165 // is shown. relayoutDocument() will take care of setting the page size to the
166 // viewport dimensions later.
167 doc->setPageSize(QSize(0, 0));
168 doc->documentLayout()->setPaintDevice(viewport);
169 doc->setDefaultFont(q->font());
170 doc->setUndoRedoEnabled(false); // flush undo buffer.
171 doc->setUndoRedoEnabled(true);
172
173 if (!html.isEmpty())
174 control->setHtml(html);
175
176 hbar->setSingleStep(20);
177 vbar->setSingleStep(20);
178
179 viewport->setBackgroundRole(QPalette::Base);
180 q->setAcceptDrops(true);
181 q->setFocusPolicy(Qt::WheelFocus);
182 q->setAttribute(Qt::WA_KeyCompression);
183 q->setAttribute(Qt::WA_InputMethodEnabled);
184
185#ifndef QT_NO_CURSOR
186 viewport->setCursor(Qt::IBeamCursor);
187#endif
188#ifdef Q_WS_WIN
189 setSingleFingerPanEnabled(true);
190#endif
191}
192
193void QTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
194{
195 if (!contentsRect.isValid()) {
196 viewport->update();
197 return;
198 }
199 const int xOffset = horizontalOffset();
200 const int yOffset = verticalOffset();
201 const QRectF visibleRect(xOffset, yOffset, viewport->width(), viewport->height());
202
203 QRect r = contentsRect.intersected(visibleRect).toAlignedRect();
204 if (r.isEmpty())
205 return;
206
207 r.translate(-xOffset, -yOffset);
208 viewport->update(r);
209}
210
211void QTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode)
212{
213 QTextCursor cursor = control->textCursor();
214 bool moved = false;
215 qreal lastY = control->cursorRect(cursor).top();
216 qreal distance = 0;
217 // move using movePosition to keep the cursor's x
218 do {
219 qreal y = control->cursorRect(cursor).top();
220 distance += qAbs(y - lastY);
221 lastY = y;
222 moved = cursor.movePosition(op, moveMode);
223 } while (moved && distance < viewport->height());
224
225 if (moved) {
226 if (op == QTextCursor::Up) {
227 cursor.movePosition(QTextCursor::Down, moveMode);
228 vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
229 } else {
230 cursor.movePosition(QTextCursor::Up, moveMode);
231 vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
232 }
233 }
234 control->setTextCursor(cursor);
235}
236
237#ifndef QT_NO_SCROLLBAR
238static QSize documentSize(QTextControl *control)
239{
240 QTextDocument *doc = control->document();
241 QAbstractTextDocumentLayout *layout = doc->documentLayout();
242
243 QSize docSize;
244
245 if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
246 docSize = tlayout->dynamicDocumentSize().toSize();
247 int percentageDone = tlayout->layoutStatus();
248 // extrapolate height
249 if (percentageDone > 0)
250 docSize.setHeight(docSize.height() * 100 / percentageDone);
251 } else {
252 docSize = layout->documentSize().toSize();
253 }
254
255 return docSize;
256}
257
258void QTextEditPrivate::_q_adjustScrollbars()
259{
260 if (ignoreAutomaticScrollbarAdjustment)
261 return;
262 ignoreAutomaticScrollbarAdjustment = true; // avoid recursion, #106108
263
264 QSize viewportSize = viewport->size();
265 QSize docSize = documentSize(control);
266
267 // due to the recursion guard we have to repeat this step a few times,
268 // as adding/removing a scroll bar will cause the document or viewport
269 // size to change
270 // ideally we should loop until the viewport size and doc size stabilize,
271 // but in corner cases they might fluctuate, so we need to limit the
272 // number of iterations
273 for (int i = 0; i < 4; ++i) {
274 hbar->setRange(0, docSize.width() - viewportSize.width());
275 hbar->setPageStep(viewportSize.width());
276
277 vbar->setRange(0, docSize.height() - viewportSize.height());
278 vbar->setPageStep(viewportSize.height());
279
280 // if we are in left-to-right mode widening the document due to
281 // lazy layouting does not require a repaint. If in right-to-left
282 // the scroll bar has the value zero and it visually has the maximum
283 // value (it is visually at the right), then widening the document
284 // keeps it at value zero but visually adjusts it to the new maximum
285 // on the right, hence we need an update.
286 if (q_func()->isRightToLeft())
287 viewport->update();
288
289 _q_showOrHideScrollBars();
290
291 const QSize oldViewportSize = viewportSize;
292 const QSize oldDocSize = docSize;
293
294 // make sure the document is layouted if the viewport width changes
295 viewportSize = viewport->size();
296 if (viewportSize.width() != oldViewportSize.width())
297 relayoutDocument();
298
299 docSize = documentSize(control);
300 if (viewportSize == oldViewportSize && docSize == oldDocSize)
301 break;
302 }
303 ignoreAutomaticScrollbarAdjustment = false;
304}
305#endif
306
307// rect is in content coordinates
308void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect)
309{
310 const QRect rect = _rect.toRect();
311 if ((vbar->isVisible() && vbar->maximum() < rect.bottom())
312 || (hbar->isVisible() && hbar->maximum() < rect.right()))
313 _q_adjustScrollbars();
314 const int visibleWidth = viewport->width();
315 const int visibleHeight = viewport->height();
316 const bool rtl = q_func()->isRightToLeft();
317
318 if (rect.x() < horizontalOffset()) {
319 if (rtl)
320 hbar->setValue(hbar->maximum() - rect.x());
321 else
322 hbar->setValue(rect.x());
323 } else if (rect.x() + rect.width() > horizontalOffset() + visibleWidth) {
324 if (rtl)
325 hbar->setValue(hbar->maximum() - (rect.x() + rect.width() - visibleWidth));
326 else
327 hbar->setValue(rect.x() + rect.width() - visibleWidth);
328 }
329
330 if (rect.y() < verticalOffset())
331 vbar->setValue(rect.y());
332 else if (rect.y() + rect.height() > verticalOffset() + visibleHeight)
333 vbar->setValue(rect.y() + rect.height() - visibleHeight);
334}
335
336/*!
337 \class QTextEdit
338 \brief The QTextEdit class provides a widget that is used to edit and display
339 both plain and rich text.
340
341 \ingroup richtext-processing
342
343
344 \tableofcontents
345
346 \section1 Introduction and Concepts
347
348 QTextEdit is an advanced WYSIWYG viewer/editor supporting rich
349 text formatting using HTML-style tags. It is optimized to handle
350 large documents and to respond quickly to user input.
351
352 QTextEdit works on paragraphs and characters. A paragraph is a
353 formatted string which is word-wrapped to fit into the width of
354 the widget. By default when reading plain text, one newline
355 signifies a paragraph. A document consists of zero or more
356 paragraphs. The words in the paragraph are aligned in accordance
357 with the paragraph's alignment. Paragraphs are separated by hard
358 line breaks. Each character within a paragraph has its own
359 attributes, for example, font and color.
360
361 QTextEdit can display images, lists and tables. If the text is
362 too large to view within the text edit's viewport, scroll bars will
363 appear. The text edit can load both plain text and HTML files (a
364 subset of HTML 3.2 and 4).
365
366 If you just need to display a small piece of rich text use QLabel.
367
368 The rich text support in Qt is designed to provide a fast, portable and
369 efficient way to add reasonable online help facilities to
370 applications, and to provide a basis for rich text editors. If
371 you find the HTML support insufficient for your needs you may consider
372 the use of QtWebKit, which provides a full-featured web browser
373 widget.
374
375 The shape of the mouse cursor on a QTextEdit is Qt::IBeamCursor by default.
376 It can be changed through the viewport()'s cursor property.
377
378 \section1 Using QTextEdit as a Display Widget
379
380 QTextEdit can display a large HTML subset, including tables and
381 images.
382
383 The text is set or replaced using setHtml() which deletes any
384 existing text and replaces it with the text passed in the
385 setHtml() call. If you call setHtml() with legacy HTML, and then
386 call toHtml(), the text that is returned may have different markup,
387 but will render the same. The entire text can be deleted with clear().
388
389 Text itself can be inserted using the QTextCursor class or using the
390 convenience functions insertHtml(), insertPlainText(), append() or
391 paste(). QTextCursor is also able to insert complex objects like tables
392 or lists into the document, and it deals with creating selections
393 and applying changes to selected text.
394
395 By default the text edit wraps words at whitespace to fit within
396 the text edit widget. The setLineWrapMode() function is used to
397 specify the kind of line wrap you want, or \l NoWrap if you don't
398 want any wrapping. Call setLineWrapMode() to set a fixed pixel width
399 \l FixedPixelWidth, or character column (e.g. 80 column) \l
400 FixedColumnWidth with the pixels or columns specified with
401 setLineWrapColumnOrWidth(). If you use word wrap to the widget's width
402 \l WidgetWidth, you can specify whether to break on whitespace or
403 anywhere with setWordWrapMode().
404
405 The find() function can be used to find and select a given string
406 within the text.
407
408 If you want to limit the total number of paragraphs in a QTextEdit,
409 as it is for example open useful in a log viewer, then you can use
410 QTextDocument's maximumBlockCount property for that.
411
412 \section2 Read-only Key Bindings
413
414 When QTextEdit is used read-only the key bindings are limited to
415 navigation, and text may only be selected with the mouse:
416 \table
417 \header \i Keypresses \i Action
418 \row \i Up \i Moves one line up.
419 \row \i Down \i Moves one line down.
420 \row \i Left \i Moves one character to the left.
421 \row \i Right \i Moves one character to the right.
422 \row \i PageUp \i Moves one (viewport) page up.
423 \row \i PageDown \i Moves one (viewport) page down.
424 \row \i Home \i Moves to the beginning of the text.
425 \row \i End \i Moves to the end of the text.
426 \row \i Alt+Wheel
427 \i Scrolls the page horizontally (the Wheel is the mouse wheel).
428 \row \i Ctrl+Wheel \i Zooms the text.
429 \row \i Ctrl+A \i Selects all text.
430 \endtable
431
432 The text edit may be able to provide some meta-information. For
433 example, the documentTitle() function will return the text from
434 within HTML \c{<title>} tags.
435
436 \section1 Using QTextEdit as an Editor
437
438 All the information about using QTextEdit as a display widget also
439 applies here.
440
441 The current char format's attributes are set with setFontItalic(),
442 setFontWeight(), setFontUnderline(), setFontFamily(),
443 setFontPointSize(), setTextColor() and setCurrentFont(). The current
444 paragraph's alignment is set with setAlignment().
445
446 Selection of text is handled by the QTextCursor class, which provides
447 functionality for creating selections, retrieving the text contents or
448 deleting selections. You can retrieve the object that corresponds with
449 the user-visible cursor using the textCursor() method. If you want to set
450 a selection in QTextEdit just create one on a QTextCursor object and
451 then make that cursor the visible cursor using setTextCursor(). The selection
452 can be copied to the clipboard with copy(), or cut to the clipboard with
453 cut(). The entire text can be selected using selectAll().
454
455 When the cursor is moved and the underlying formatting attributes change,
456 the currentCharFormatChanged() signal is emitted to reflect the new attributes
457 at the new cursor position.
458
459 QTextEdit holds a QTextDocument object which can be retrieved using the
460 document() method. You can also set your own document object using setDocument().
461 QTextDocument emits a textChanged() signal if the text changes and it also
462 provides a isModified() function which will return true if the text has been
463 modified since it was either loaded or since the last call to setModified
464 with false as argument. In addition it provides methods for undo and redo.
465
466 \section2 Drag and Drop
467
468 QTextEdit also supports custom drag and drop behavior. By default,
469 QTextEdit will insert plain text, HTML and rich text when the user drops
470 data of these MIME types onto a document. Reimplement
471 canInsertFromMimeData() and insertFromMimeData() to add support for
472 additional MIME types.
473
474 For example, to allow the user to drag and drop an image onto a QTextEdit,
475 you could the implement these functions in the following way:
476
477 \snippet doc/src/snippets/textdocument-imagedrop/textedit.cpp 0
478
479 We add support for image MIME types by returning true. For all other
480 MIME types, we use the default implementation.
481
482 \snippet doc/src/snippets/textdocument-imagedrop/textedit.cpp 1
483
484 We unpack the image from the QVariant held by the MIME source and insert
485 it into the document as a resource.
486
487 \section2 Editing Key Bindings
488
489 The list of key bindings which are implemented for editing:
490 \table
491 \header \i Keypresses \i Action
492 \row \i Backspace \i Deletes the character to the left of the cursor.
493 \row \i Delete \i Deletes the character to the right of the cursor.
494 \row \i Ctrl+C \i Copy the selected text to the clipboard.
495 \row \i Ctrl+Insert \i Copy the selected text to the clipboard.
496 \row \i Ctrl+K \i Deletes to the end of the line.
497 \row \i Ctrl+V \i Pastes the clipboard text into text edit.
498 \row \i Shift+Insert \i Pastes the clipboard text into text edit.
499 \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
500 \row \i Shift+Delete \i Deletes the selected text and copies it to the clipboard.
501 \row \i Ctrl+Z \i Undoes the last operation.
502 \row \i Ctrl+Y \i Redoes the last operation.
503 \row \i Left \i Moves the cursor one character to the left.
504 \row \i Ctrl+Left \i Moves the cursor one word to the left.
505 \row \i Right \i Moves the cursor one character to the right.
506 \row \i Ctrl+Right \i Moves the cursor one word to the right.
507 \row \i Up \i Moves the cursor one line up.
508 \row \i Down \i Moves the cursor one line down.
509 \row \i PageUp \i Moves the cursor one page up.
510 \row \i PageDown \i Moves the cursor one page down.
511 \row \i Home \i Moves the cursor to the beginning of the line.
512 \row \i Ctrl+Home \i Moves the cursor to the beginning of the text.
513 \row \i End \i Moves the cursor to the end of the line.
514 \row \i Ctrl+End \i Moves the cursor to the end of the text.
515 \row \i Alt+Wheel \i Scrolls the page horizontally (the Wheel is the mouse wheel).
516 \endtable
517
518 To select (mark) text hold down the Shift key whilst pressing one
519 of the movement keystrokes, for example, \e{Shift+Right}
520 will select the character to the right, and \e{Shift+Ctrl+Right} will select the word to the right, etc.
521
522 \sa QTextDocument, QTextCursor, {Application Example},
523 {Syntax Highlighter Example}, {Rich Text Processing}
524*/
525
526/*!
527 \property QTextEdit::plainText
528 \since 4.3
529
530 This property gets and sets the text editor's contents as plain
531 text. Previous contents are removed and undo/redo history is reset
532 when the property is set.
533
534 If the text edit has another content type, it will not be replaced
535 by plain text if you call toPlainText(). The only exception to this
536 is the non-break space, \e{nbsp;}, that will be converted into
537 standard space.
538
539 By default, for an editor with no contents, this property contains
540 an empty string.
541
542 \sa html
543*/
544
545/*!
546 \property QTextEdit::undoRedoEnabled
547 \brief whether undo and redo are enabled
548
549 Users are only able to undo or redo actions if this property is
550 true, and if there is an action that can be undone (or redone).
551*/
552
553/*!
554 \enum QTextEdit::LineWrapMode
555
556 \value NoWrap
557 \value WidgetWidth
558 \value FixedPixelWidth
559 \value FixedColumnWidth
560*/
561
562/*!
563 \enum QTextEdit::AutoFormattingFlag
564
565 \value AutoNone Don't do any automatic formatting.
566 \value AutoBulletList Automatically create bullet lists (e.g. when
567 the user enters an asterisk ('*') in the left most column, or
568 presses Enter in an existing list item.
569 \value AutoAll Apply all automatic formatting. Currently only
570 automatic bullet lists are supported.
571*/
572
573#ifdef QT3_SUPPORT
574/*!
575 \enum QTextEdit::CursorAction
576 \compat
577
578 \value MoveBackward
579 \value MoveForward
580 \value MoveWordBackward
581 \value MoveWordForward
582 \value MoveUp
583 \value MoveDown
584 \value MoveLineStart
585 \value MoveLineEnd
586 \value MoveHome
587 \value MoveEnd
588 \value MovePageUp
589 \value MovePageDown
590
591 \omitvalue MovePgUp
592 \omitvalue MovePgDown
593*/
594#endif
595
596/*!
597 Constructs an empty QTextEdit with parent \a
598 parent.
599*/
600QTextEdit::QTextEdit(QWidget *parent)
601 : QAbstractScrollArea(*new QTextEditPrivate, parent)
602{
603 Q_D(QTextEdit);
604 d->init();
605}
606
607/*!
608 \internal
609*/
610QTextEdit::QTextEdit(QTextEditPrivate &dd, QWidget *parent)
611 : QAbstractScrollArea(dd, parent)
612{
613 Q_D(QTextEdit);
614 d->init();
615}
616
617/*!
618 Constructs a QTextEdit with parent \a parent. The text edit will display
619 the text \a text. The text is interpreted as html.
620*/
621QTextEdit::QTextEdit(const QString &text, QWidget *parent)
622 : QAbstractScrollArea(*new QTextEditPrivate, parent)
623{
624 Q_D(QTextEdit);
625 d->init(text);
626}
627
628#ifdef QT3_SUPPORT
629/*!
630 Use one of the constructors that doesn't take the \a name
631 argument and then use setObjectName() instead.
632*/
633QTextEdit::QTextEdit(QWidget *parent, const char *name)
634 : QAbstractScrollArea(*new QTextEditPrivate, parent)
635{
636 Q_D(QTextEdit);
637 d->init();
638 setObjectName(QString::fromAscii(name));
639}
640#endif
641
642
643/*!
644 Destructor.
645*/
646QTextEdit::~QTextEdit()
647{
648}
649
650/*!
651 Returns the point size of the font of the current format.
652
653 \sa setFontFamily() setCurrentFont() setFontPointSize()
654*/
655qreal QTextEdit::fontPointSize() const
656{
657 Q_D(const QTextEdit);
658 return d->control->textCursor().charFormat().fontPointSize();
659}
660
661/*!
662 Returns the font family of the current format.
663
664 \sa setFontFamily() setCurrentFont() setFontPointSize()
665*/
666QString QTextEdit::fontFamily() const
667{
668 Q_D(const QTextEdit);
669 return d->control->textCursor().charFormat().fontFamily();
670}
671
672/*!
673 Returns the font weight of the current format.
674
675 \sa setFontWeight() setCurrentFont() setFontPointSize() QFont::Weight
676*/
677int QTextEdit::fontWeight() const
678{
679 Q_D(const QTextEdit);
680 return d->control->textCursor().charFormat().fontWeight();
681}
682
683/*!
684 Returns true if the font of the current format is underlined; otherwise returns
685 false.
686
687 \sa setFontUnderline()
688*/
689bool QTextEdit::fontUnderline() const
690{
691 Q_D(const QTextEdit);
692 return d->control->textCursor().charFormat().fontUnderline();
693}
694
695/*!
696 Returns true if the font of the current format is italic; otherwise returns
697 false.
698
699 \sa setFontItalic()
700*/
701bool QTextEdit::fontItalic() const
702{
703 Q_D(const QTextEdit);
704 return d->control->textCursor().charFormat().fontItalic();
705}
706
707/*!
708 Returns the text color of the current format.
709
710 \sa setTextColor()
711*/
712QColor QTextEdit::textColor() const
713{
714 Q_D(const QTextEdit);
715 return d->control->textCursor().charFormat().foreground().color();
716}
717
718/*!
719 \since 4.4
720
721 Returns the text background color of the current format.
722
723 \sa setTextBackgroundColor()
724*/
725QColor QTextEdit::textBackgroundColor() const
726{
727 Q_D(const QTextEdit);
728 return d->control->textCursor().charFormat().background().color();
729}
730
731/*!
732 Returns the font of the current format.
733
734 \sa setCurrentFont() setFontFamily() setFontPointSize()
735*/
736QFont QTextEdit::currentFont() const
737{
738 Q_D(const QTextEdit);
739 return d->control->textCursor().charFormat().font();
740}
741
742/*!
743 Sets the alignment of the current paragraph to \a a. Valid
744 alignments are Qt::AlignLeft, Qt::AlignRight,
745 Qt::AlignJustify and Qt::AlignCenter (which centers
746 horizontally).
747*/
748void QTextEdit::setAlignment(Qt::Alignment a)
749{
750 Q_D(QTextEdit);
751 QTextBlockFormat fmt;
752 fmt.setAlignment(a);
753 QTextCursor cursor = d->control->textCursor();
754 cursor.mergeBlockFormat(fmt);
755 d->control->setTextCursor(cursor);
756}
757
758/*!
759 Returns the alignment of the current paragraph.
760
761 \sa setAlignment()
762*/
763Qt::Alignment QTextEdit::alignment() const
764{
765 Q_D(const QTextEdit);
766 return d->control->textCursor().blockFormat().alignment();
767}
768
769/*!
770 Makes \a document the new document of the text editor.
771
772 \note The editor \e{does not take ownership of the document} unless it
773 is the document's parent object. The parent object of the provided document
774 remains the owner of the object.
775
776 The editor does not delete the current document, even if it is a child of the editor.
777
778 \sa document()
779*/
780void QTextEdit::setDocument(QTextDocument *document)
781{
782 Q_D(QTextEdit);
783 d->control->setDocument(document);
784 d->updateDefaultTextOption();
785 d->relayoutDocument();
786}
787
788/*!
789 Returns a pointer to the underlying document.
790
791 \sa setDocument()
792*/
793QTextDocument *QTextEdit::document() const
794{
795 Q_D(const QTextEdit);
796 return d->control->document();
797}
798
799/*!
800 Sets the visible \a cursor.
801*/
802void QTextEdit::setTextCursor(const QTextCursor &cursor)
803{
804 Q_D(QTextEdit);
805 d->control->setTextCursor(cursor);
806}
807
808/*!
809 Returns a copy of the QTextCursor that represents the currently visible cursor.
810 Note that changes on the returned cursor do not affect QTextEdit's cursor; use
811 setTextCursor() to update the visible cursor.
812 */
813QTextCursor QTextEdit::textCursor() const
814{
815 Q_D(const QTextEdit);
816 return d->control->textCursor();
817}
818
819/*!
820 Sets the font family of the current format to \a fontFamily.
821
822 \sa fontFamily() setCurrentFont()
823*/
824void QTextEdit::setFontFamily(const QString &fontFamily)
825{
826 QTextCharFormat fmt;
827 fmt.setFontFamily(fontFamily);
828 mergeCurrentCharFormat(fmt);
829}
830
831/*!
832 Sets the point size of the current format to \a s.
833
834 Note that if \a s is zero or negative, the behavior of this
835 function is not defined.
836
837 \sa fontPointSize() setCurrentFont() setFontFamily()
838*/
839void QTextEdit::setFontPointSize(qreal s)
840{
841 QTextCharFormat fmt;
842 fmt.setFontPointSize(s);
843 mergeCurrentCharFormat(fmt);
844}
845
846/*!
847 \fn void QTextEdit::setFontWeight(int weight)
848
849 Sets the font weight of the current format to the given \a weight,
850 where the value used is in the range defined by the QFont::Weight
851 enum.
852
853 \sa fontWeight(), setCurrentFont(), setFontFamily()
854*/
855void QTextEdit::setFontWeight(int w)
856{
857 QTextCharFormat fmt;
858 fmt.setFontWeight(w);
859 mergeCurrentCharFormat(fmt);
860}
861
862/*!
863 If \a underline is true, sets the current format to underline;
864 otherwise sets the current format to non-underline.
865
866 \sa fontUnderline()
867*/
868void QTextEdit::setFontUnderline(bool underline)
869{
870 QTextCharFormat fmt;
871 fmt.setFontUnderline(underline);
872 mergeCurrentCharFormat(fmt);
873}
874
875/*!
876 If \a italic is true, sets the current format to italic;
877 otherwise sets the current format to non-italic.
878
879 \sa fontItalic()
880*/
881void QTextEdit::setFontItalic(bool italic)
882{
883 QTextCharFormat fmt;
884 fmt.setFontItalic(italic);
885 mergeCurrentCharFormat(fmt);
886}
887
888/*!
889 Sets the text color of the current format to \a c.
890
891 \sa textColor()
892*/
893void QTextEdit::setTextColor(const QColor &c)
894{
895 QTextCharFormat fmt;
896 fmt.setForeground(QBrush(c));
897 mergeCurrentCharFormat(fmt);
898}
899
900/*!
901 \since 4.4
902
903 Sets the text background color of the current format to \a c.
904
905 \sa textBackgroundColor()
906*/
907void QTextEdit::setTextBackgroundColor(const QColor &c)
908{
909 QTextCharFormat fmt;
910 fmt.setBackground(QBrush(c));
911 mergeCurrentCharFormat(fmt);
912}
913
914/*!
915 Sets the font of the current format to \a f.
916
917 \sa currentFont() setFontPointSize() setFontFamily()
918*/
919void QTextEdit::setCurrentFont(const QFont &f)
920{
921 QTextCharFormat fmt;
922 fmt.setFont(f);
923 mergeCurrentCharFormat(fmt);
924}
925
926/*!
927 \since 4.2
928
929 Undoes the last operation.
930
931 If there is no operation to undo, i.e. there is no undo step in
932 the undo/redo history, nothing happens.
933
934 \sa redo()
935*/
936void QTextEdit::undo()
937{
938 Q_D(QTextEdit);
939 d->control->undo();
940}
941
942void QTextEdit::redo()
943{
944 Q_D(QTextEdit);
945 d->control->redo();
946}
947
948/*!
949 \fn void QTextEdit::undo() const
950 \fn void QTextEdit::redo() const
951 \overload
952
953 Use the non-const overload instead.
954*/
955
956/*!
957 \fn void QTextEdit::redo()
958 \since 4.2
959
960 Redoes the last operation.
961
962 If there is no operation to redo, i.e. there is no redo step in
963 the undo/redo history, nothing happens.
964
965 \sa undo()
966*/
967
968#ifndef QT_NO_CLIPBOARD
969/*!
970 Copies the selected text to the clipboard and deletes it from
971 the text edit.
972
973 If there is no selected text nothing happens.
974
975 \sa copy() paste()
976*/
977
978void QTextEdit::cut()
979{
980 Q_D(QTextEdit);
981 d->control->cut();
982}
983
984/*!
985 Copies any selected text to the clipboard.
986
987 \sa copyAvailable()
988*/
989
990void QTextEdit::copy()
991{
992 Q_D(QTextEdit);
993 d->control->copy();
994}
995
996/*!
997 Pastes the text from the clipboard into the text edit at the
998 current cursor position.
999
1000 If there is no text in the clipboard nothing happens.
1001
1002 To change the behavior of this function, i.e. to modify what
1003 QTextEdit can paste and how it is being pasted, reimplement the
1004 virtual canInsertFromMimeData() and insertFromMimeData()
1005 functions.
1006
1007 \sa cut() copy()
1008*/
1009
1010void QTextEdit::paste()
1011{
1012 Q_D(QTextEdit);
1013 d->control->paste();
1014}
1015#endif
1016
1017/*!
1018 Deletes all the text in the text edit.
1019
1020 Note that the undo/redo history is cleared by this function.
1021
1022 \sa cut() setPlainText() setHtml()
1023*/
1024void QTextEdit::clear()
1025{
1026 Q_D(QTextEdit);
1027 // clears and sets empty content
1028 d->control->clear();
1029}
1030
1031
1032/*!
1033 Selects all text.
1034
1035 \sa copy() cut() textCursor()
1036 */
1037void QTextEdit::selectAll()
1038{
1039 Q_D(QTextEdit);
1040 d->control->selectAll();
1041}
1042
1043/*! \internal
1044*/
1045bool QTextEdit::event(QEvent *e)
1046{
1047 Q_D(QTextEdit);
1048#ifndef QT_NO_CONTEXTMENU
1049 if (e->type() == QEvent::ContextMenu
1050 && static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
1051 Q_D(QTextEdit);
1052 ensureCursorVisible();
1053 const QPoint cursorPos = cursorRect().center();
1054 QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
1055 ce.setAccepted(e->isAccepted());
1056 const bool result = QAbstractScrollArea::event(&ce);
1057 e->setAccepted(ce.isAccepted());
1058 return result;
1059 } else if (e->type() == QEvent::ShortcutOverride
1060 || e->type() == QEvent::ToolTip) {
1061 d->sendControlEvent(e);
1062 }
1063#endif // QT_NO_CONTEXTMENU
1064#ifdef QT_KEYPAD_NAVIGATION
1065 if (e->type() == QEvent::EnterEditFocus || e->type() == QEvent::LeaveEditFocus) {
1066 if (QApplication::keypadNavigationEnabled())
1067 d->sendControlEvent(e);
1068 }
1069#endif
1070 return QAbstractScrollArea::event(e);
1071}
1072
1073/*! \internal
1074*/
1075
1076void QTextEdit::timerEvent(QTimerEvent *e)
1077{
1078 Q_D(QTextEdit);
1079 if (e->timerId() == d->autoScrollTimer.timerId()) {
1080 QRect visible = d->viewport->rect();
1081 QPoint pos;
1082 if (d->inDrag) {
1083 pos = d->autoScrollDragPos;
1084 visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
1085 -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
1086 } else {
1087 const QPoint globalPos = QCursor::pos();
1088 pos = d->viewport->mapFromGlobal(globalPos);
1089 QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
1090 mouseMoveEvent(&ev);
1091 }
1092 int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
1093 int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
1094 int delta = qMax(deltaX, deltaY);
1095 if (delta >= 0) {
1096 if (delta < 7)
1097 delta = 7;
1098 int timeout = 4900 / (delta * delta);
1099 d->autoScrollTimer.start(timeout, this);
1100
1101 if (deltaY > 0)
1102 d->vbar->triggerAction(pos.y() < visible.center().y() ?
1103 QAbstractSlider::SliderSingleStepSub
1104 : QAbstractSlider::SliderSingleStepAdd);
1105 if (deltaX > 0)
1106 d->hbar->triggerAction(pos.x() < visible.center().x() ?
1107 QAbstractSlider::SliderSingleStepSub
1108 : QAbstractSlider::SliderSingleStepAdd);
1109 }
1110 }
1111#ifdef QT_KEYPAD_NAVIGATION
1112 else if (e->timerId() == d->deleteAllTimer.timerId()) {
1113 d->deleteAllTimer.stop();
1114 clear();
1115 }
1116#endif
1117}
1118
1119/*!
1120 Changes the text of the text edit to the string \a text.
1121 Any previous text is removed.
1122
1123 \a text is interpreted as plain text.
1124
1125 Note that the undo/redo history is cleared by this function.
1126
1127 \sa toPlainText()
1128*/
1129
1130void QTextEdit::setPlainText(const QString &text)
1131{
1132 Q_D(QTextEdit);
1133 d->control->setPlainText(text);
1134 d->preferRichText = false;
1135}
1136
1137/*!
1138 \fn QString QTextEdit::toPlainText() const
1139
1140 Returns the text of the text edit as plain text.
1141
1142 \sa QTextEdit::setPlainText()
1143 */
1144
1145
1146/*!
1147 \property QTextEdit::html
1148
1149 This property provides an HTML interface to the text of the text edit.
1150
1151 toHtml() returns the text of the text edit as html.
1152
1153 setHtml() changes the text of the text edit. Any previous text is
1154 removed and the undo/redo history is cleared. The input text is
1155 interpreted as rich text in html format.
1156
1157 \note It is the responsibility of the caller to make sure that the
1158 text is correctly decoded when a QString containing HTML is created
1159 and passed to setHtml().
1160
1161 By default, for a newly-created, empty document, this property contains
1162 text to describe an HTML 4.0 document with no body text.
1163
1164 \sa {Supported HTML Subset}, plainText
1165*/
1166
1167#ifndef QT_NO_TEXTHTMLPARSER
1168void QTextEdit::setHtml(const QString &text)
1169{
1170 Q_D(QTextEdit);
1171 d->control->setHtml(text);
1172 d->preferRichText = true;
1173}
1174#endif
1175
1176/*! \reimp
1177*/
1178void QTextEdit::keyPressEvent(QKeyEvent *e)
1179{
1180 Q_D(QTextEdit);
1181
1182#ifdef QT_KEYPAD_NAVIGATION
1183 switch (e->key()) {
1184 case Qt::Key_Select:
1185 if (QApplication::keypadNavigationEnabled()) {
1186 // code assumes linksaccessible + editable isn't meaningful
1187 if (d->control->textInteractionFlags() & Qt::TextEditable) {
1188 setEditFocus(!hasEditFocus());
1189 } else {
1190 if (!hasEditFocus())
1191 setEditFocus(true);
1192 else {
1193 QTextCursor cursor = d->control->textCursor();
1194 QTextCharFormat charFmt = cursor.charFormat();
1195 if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard)
1196 || !cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
1197 e->accept();
1198 return;
1199 }
1200 }
1201 }
1202 }
1203 break;
1204 case Qt::Key_Back:
1205 case Qt::Key_No:
1206 if (!QApplication::keypadNavigationEnabled()
1207 || (QApplication::keypadNavigationEnabled() && !hasEditFocus())) {
1208 e->ignore();
1209 return;
1210 }
1211 break;
1212 default:
1213 if (QApplication::keypadNavigationEnabled()) {
1214 if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {
1215 if (e->text()[0].isPrint())
1216 setEditFocus(true);
1217 else {
1218 e->ignore();
1219 return;
1220 }
1221 }
1222 }
1223 break;
1224 }
1225#endif
1226#ifndef QT_NO_SHORTCUT
1227
1228 Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
1229
1230 if (tif & Qt::TextSelectableByKeyboard){
1231 if (e == QKeySequence::SelectPreviousPage) {
1232 e->accept();
1233 d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
1234 return;
1235 } else if (e ==QKeySequence::SelectNextPage) {
1236 e->accept();
1237 d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
1238 return;
1239 }
1240 }
1241 if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
1242 if (e == QKeySequence::MoveToPreviousPage) {
1243 e->accept();
1244 d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
1245 return;
1246 } else if (e == QKeySequence::MoveToNextPage) {
1247 e->accept();
1248 d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
1249 return;
1250 }
1251 }
1252
1253 if (!(tif & Qt::TextEditable)) {
1254 switch (e->key()) {
1255 case Qt::Key_Space:
1256 e->accept();
1257 if (e->modifiers() & Qt::ShiftModifier)
1258 d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
1259 else
1260 d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
1261 break;
1262 default:
1263 d->sendControlEvent(e);
1264 if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
1265 if (e->key() == Qt::Key_Home) {
1266 d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
1267 e->accept();
1268 } else if (e->key() == Qt::Key_End) {
1269 d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
1270 e->accept();
1271 }
1272 }
1273 if (!e->isAccepted()) {
1274 QAbstractScrollArea::keyPressEvent(e);
1275 }
1276 }
1277 return;
1278 }
1279#endif // QT_NO_SHORTCUT
1280
1281 {
1282 QTextCursor cursor = d->control->textCursor();
1283 const QString text = e->text();
1284 if (cursor.atBlockStart()
1285 && (d->autoFormatting & AutoBulletList)
1286 && (text.length() == 1)
1287 && (text.at(0) == QLatin1Char('-') || text.at(0) == QLatin1Char('*'))
1288 && (!cursor.currentList())) {
1289
1290 d->createAutoBulletList();
1291 e->accept();
1292 return;
1293 }
1294 }
1295
1296 d->sendControlEvent(e);
1297#ifdef QT_KEYPAD_NAVIGATION
1298 if (!e->isAccepted()) {
1299 switch (e->key()) {
1300 case Qt::Key_Up:
1301 case Qt::Key_Down:
1302 if (QApplication::keypadNavigationEnabled()) {
1303 // Cursor position didn't change, so we want to leave
1304 // these keys to change focus.
1305 e->ignore();
1306 return;
1307 }
1308 break;
1309 case Qt::Key_Back:
1310 if (!e->isAutoRepeat()) {
1311 if (QApplication::keypadNavigationEnabled()) {
1312 if (document()->isEmpty() || !(d->control->textInteractionFlags() & Qt::TextEditable)) {
1313 setEditFocus(false);
1314 e->accept();
1315 } else if (!d->deleteAllTimer.isActive()) {
1316 e->accept();
1317 d->deleteAllTimer.start(750, this);
1318 }
1319 } else {
1320 e->ignore();
1321 return;
1322 }
1323 }
1324 break;
1325 default: break;
1326 }
1327 }
1328#endif
1329}
1330
1331/*! \reimp
1332*/
1333void QTextEdit::keyReleaseEvent(QKeyEvent *e)
1334{
1335#ifdef QT_KEYPAD_NAVIGATION
1336 Q_D(QTextEdit);
1337 if (QApplication::keypadNavigationEnabled()) {
1338 if (!e->isAutoRepeat() && e->key() == Qt::Key_Back
1339 && d->deleteAllTimer.isActive()) {
1340 d->deleteAllTimer.stop();
1341 QTextCursor cursor = d->control->textCursor();
1342 QTextBlockFormat blockFmt = cursor.blockFormat();
1343
1344 QTextList *list = cursor.currentList();
1345 if (list && cursor.atBlockStart()) {
1346 list->remove(cursor.block());
1347 } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1348 blockFmt.setIndent(blockFmt.indent() - 1);
1349 cursor.setBlockFormat(blockFmt);
1350 } else {
1351 cursor.deletePreviousChar();
1352 }
1353 setTextCursor(cursor);
1354 e->accept();
1355 return;
1356 }
1357 }
1358#endif
1359 e->ignore();
1360}
1361
1362/*!
1363 Loads the resource specified by the given \a type and \a name.
1364
1365 This function is an extension of QTextDocument::loadResource().
1366
1367 \sa QTextDocument::loadResource()
1368*/
1369QVariant QTextEdit::loadResource(int type, const QUrl &name)
1370{
1371 Q_UNUSED(type);
1372 Q_UNUSED(name);
1373 return QVariant();
1374}
1375
1376/*! \reimp
1377*/
1378void QTextEdit::resizeEvent(QResizeEvent *e)
1379{
1380 Q_D(QTextEdit);
1381
1382 if (d->lineWrap == NoWrap) {
1383 QTextDocument *doc = d->control->document();
1384 QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
1385
1386 if (!doc->pageSize().isNull()
1387 && alignmentProperty.type() == QVariant::Bool
1388 && !alignmentProperty.toBool()) {
1389
1390 d->_q_adjustScrollbars();
1391 return;
1392 }
1393 }
1394
1395 if (d->lineWrap != FixedPixelWidth
1396 && e->oldSize().width() != e->size().width())
1397 d->relayoutDocument();
1398 else
1399 d->_q_adjustScrollbars();
1400}
1401
1402void QTextEditPrivate::relayoutDocument()
1403{
1404 QTextDocument *doc = control->document();
1405 QAbstractTextDocumentLayout *layout = doc->documentLayout();
1406
1407 if (QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout)) {
1408 if (lineWrap == QTextEdit::FixedColumnWidth)
1409 tlayout->setFixedColumnWidth(lineWrapColumnOrWidth);
1410 else
1411 tlayout->setFixedColumnWidth(-1);
1412 }
1413
1414 QTextDocumentLayout *tlayout = qobject_cast<QTextDocumentLayout *>(layout);
1415 QSize lastUsedSize;
1416 if (tlayout)
1417 lastUsedSize = tlayout->dynamicDocumentSize().toSize();
1418 else
1419 lastUsedSize = layout->documentSize().toSize();
1420
1421 // ignore calls to _q_adjustScrollbars caused by an emission of the
1422 // usedSizeChanged() signal in the layout, as we're calling it
1423 // later on our own anyway (or deliberately not) .
1424 const bool oldIgnoreScrollbarAdjustment = ignoreAutomaticScrollbarAdjustment;
1425 ignoreAutomaticScrollbarAdjustment = true;
1426
1427 int width = viewport->width();
1428 if (lineWrap == QTextEdit::FixedPixelWidth)
1429 width = lineWrapColumnOrWidth;
1430 else if (lineWrap == QTextEdit::NoWrap) {
1431 QVariant alignmentProperty = doc->documentLayout()->property("contentHasAlignment");
1432 if (alignmentProperty.type() == QVariant::Bool && !alignmentProperty.toBool()) {
1433
1434 width = 0;
1435 }
1436 }
1437
1438 doc->setPageSize(QSize(width, -1));
1439 if (tlayout)
1440 tlayout->ensureLayouted(verticalOffset() + viewport->height());
1441
1442 ignoreAutomaticScrollbarAdjustment = oldIgnoreScrollbarAdjustment;
1443
1444 QSize usedSize;
1445 if (tlayout)
1446 usedSize = tlayout->dynamicDocumentSize().toSize();
1447 else
1448 usedSize = layout->documentSize().toSize();
1449
1450 // this is an obscure situation in the layout that can happen:
1451 // if a character at the end of a line is the tallest one and therefore
1452 // influencing the total height of the line and the line right below it
1453 // is always taller though, then it can happen that if due to line breaking
1454 // that tall character wraps into the lower line the document not only shrinks
1455 // horizontally (causing the character to wrap in the first place) but also
1456 // vertically, because the original line is now smaller and the one below kept
1457 // its size. So a layout with less width _can_ take up less vertical space, too.
1458 // If the wider case causes a vertical scroll bar to appear and the narrower one
1459 // (narrower because the vertical scroll bar takes up horizontal space)) to disappear
1460 // again then we have an endless loop, as _q_adjustScrollBars sets new ranges on the
1461 // scroll bars, the QAbstractScrollArea will find out about it and try to show/hide
1462 // the scroll bars again. That's why we try to detect this case here and break out.
1463 //
1464 // (if you change this please also check the layoutingLoop() testcase in
1465 // QTextEdit's autotests)
1466 if (lastUsedSize.isValid()
1467 && !vbar->isHidden()
1468 && viewport->width() < lastUsedSize.width()
1469 && usedSize.height() < lastUsedSize.height()
1470 && usedSize.height() <= viewport->height())
1471 return;
1472
1473 _q_adjustScrollbars();
1474}
1475
1476void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
1477{
1478 const int xOffset = horizontalOffset();
1479 const int yOffset = verticalOffset();
1480
1481 QRect r = e->rect();
1482 p->translate(-xOffset, -yOffset);
1483 r.translate(xOffset, yOffset);
1484
1485 QTextDocument *doc = control->document();
1486 QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
1487
1488 // the layout might need to expand the root frame to
1489 // the viewport if NoWrap is set
1490 if (layout)
1491 layout->setViewport(viewport->rect());
1492
1493 control->drawContents(p, r, q_func());
1494
1495 if (layout)
1496 layout->setViewport(QRect());
1497}
1498
1499/*! \fn void QTextEdit::paintEvent(QPaintEvent *event)
1500
1501This event handler can be reimplemented in a subclass to receive paint events passed in \a event.
1502It is usually unnecessary to reimplement this function in a subclass of QTextEdit.
1503
1504\warning The underlying text document must not be modified from within a reimplementation
1505of this function.
1506*/
1507void QTextEdit::paintEvent(QPaintEvent *e)
1508{
1509 Q_D(QTextEdit);
1510 QPainter p(d->viewport);
1511 d->paint(&p, e);
1512}
1513
1514void QTextEditPrivate::_q_currentCharFormatChanged(const QTextCharFormat &fmt)
1515{
1516 Q_Q(QTextEdit);
1517 emit q->currentCharFormatChanged(fmt);
1518#ifdef QT3_SUPPORT
1519 // compat signals
1520 emit q->currentFontChanged(fmt.font());
1521 emit q->currentColorChanged(fmt.foreground().color());
1522#endif
1523}
1524
1525void QTextEditPrivate::updateDefaultTextOption()
1526{
1527 QTextDocument *doc = control->document();
1528
1529 QTextOption opt = doc->defaultTextOption();
1530 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1531
1532 if (lineWrap == QTextEdit::NoWrap)
1533 opt.setWrapMode(QTextOption::NoWrap);
1534 else
1535 opt.setWrapMode(wordWrap);
1536
1537 if (opt.wrapMode() != oldWrapMode)
1538 doc->setDefaultTextOption(opt);
1539}
1540
1541/*! \reimp
1542*/
1543void QTextEdit::mousePressEvent(QMouseEvent *e)
1544{
1545 Q_D(QTextEdit);
1546#ifdef QT_KEYPAD_NAVIGATION
1547 if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
1548 setEditFocus(true);
1549#endif
1550 d->sendControlEvent(e);
1551}
1552
1553/*! \reimp
1554*/
1555void QTextEdit::mouseMoveEvent(QMouseEvent *e)
1556{
1557 Q_D(QTextEdit);
1558 d->inDrag = false; // paranoia
1559 const QPoint pos = e->pos();
1560 d->sendControlEvent(e);
1561 if (!(e->buttons() & Qt::LeftButton))
1562 return;
1563 QRect visible = d->viewport->rect();
1564 if (visible.contains(pos))
1565 d->autoScrollTimer.stop();
1566 else if (!d->autoScrollTimer.isActive())
1567 d->autoScrollTimer.start(100, this);
1568}
1569
1570/*! \reimp
1571*/
1572void QTextEdit::mouseReleaseEvent(QMouseEvent *e)
1573{
1574 Q_D(QTextEdit);
1575 d->sendControlEvent(e);
1576 if (d->autoScrollTimer.isActive()) {
1577 d->autoScrollTimer.stop();
1578 ensureCursorVisible();
1579 }
1580 if (!isReadOnly() && rect().contains(e->pos()))
1581 d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
1582 d->clickCausedFocus = 0;
1583}
1584
1585/*! \reimp
1586*/
1587void QTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
1588{
1589 Q_D(QTextEdit);
1590 d->sendControlEvent(e);
1591}
1592
1593/*! \reimp
1594*/
1595bool QTextEdit::focusNextPrevChild(bool next)
1596{
1597 Q_D(const QTextEdit);
1598 if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
1599 return false;
1600 return QAbstractScrollArea::focusNextPrevChild(next);
1601}
1602
1603#ifndef QT_NO_CONTEXTMENU
1604/*!
1605 \fn void QTextEdit::contextMenuEvent(QContextMenuEvent *event)
1606
1607 Shows the standard context menu created with createStandardContextMenu().
1608
1609 If you do not want the text edit to have a context menu, you can set
1610 its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
1611 customize the context menu, reimplement this function. If you want
1612 to extend the standard context menu, reimplement this function, call
1613 createStandardContextMenu() and extend the menu returned.
1614
1615 Information about the event is passed in the \a event object.
1616
1617 \snippet doc/src/snippets/code/src_gui_widgets_qtextedit.cpp 0
1618*/
1619void QTextEdit::contextMenuEvent(QContextMenuEvent *e)
1620{
1621 Q_D(QTextEdit);
1622 d->sendControlEvent(e);
1623}
1624#endif // QT_NO_CONTEXTMENU
1625
1626#ifndef QT_NO_DRAGANDDROP
1627/*! \reimp
1628*/
1629void QTextEdit::dragEnterEvent(QDragEnterEvent *e)
1630{
1631 Q_D(QTextEdit);
1632 d->inDrag = true;
1633 d->sendControlEvent(e);
1634}
1635
1636/*! \reimp
1637*/
1638void QTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
1639{
1640 Q_D(QTextEdit);
1641 d->inDrag = false;
1642 d->autoScrollTimer.stop();
1643 d->sendControlEvent(e);
1644}
1645
1646/*! \reimp
1647*/
1648void QTextEdit::dragMoveEvent(QDragMoveEvent *e)
1649{
1650 Q_D(QTextEdit);
1651 d->autoScrollDragPos = e->pos();
1652 if (!d->autoScrollTimer.isActive())
1653 d->autoScrollTimer.start(100, this);
1654 d->sendControlEvent(e);
1655}
1656
1657/*! \reimp
1658*/
1659void QTextEdit::dropEvent(QDropEvent *e)
1660{
1661 Q_D(QTextEdit);
1662 d->inDrag = false;
1663 d->autoScrollTimer.stop();
1664 d->sendControlEvent(e);
1665}
1666
1667#endif // QT_NO_DRAGANDDROP
1668
1669/*! \reimp
1670 */
1671void QTextEdit::inputMethodEvent(QInputMethodEvent *e)
1672{
1673 Q_D(QTextEdit);
1674#ifdef QT_KEYPAD_NAVIGATION
1675 if (d->control->textInteractionFlags() & Qt::TextEditable
1676 && QApplication::keypadNavigationEnabled()
1677 && !hasEditFocus())
1678 setEditFocus(true);
1679#endif
1680 d->sendControlEvent(e);
1681 ensureCursorVisible();
1682}
1683
1684/*!\reimp
1685*/
1686void QTextEdit::scrollContentsBy(int dx, int dy)
1687{
1688 Q_D(QTextEdit);
1689 if (isRightToLeft())
1690 dx = -dx;
1691 d->viewport->scroll(dx, dy);
1692}
1693
1694/*!\reimp
1695*/
1696QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1697{
1698 Q_D(const QTextEdit);
1699 QVariant v = d->control->inputMethodQuery(property);
1700 const QPoint offset(-d->horizontalOffset(), -d->verticalOffset());
1701 if (v.type() == QVariant::RectF)
1702 v = v.toRectF().toRect().translated(offset);
1703 else if (v.type() == QVariant::PointF)
1704 v = v.toPointF().toPoint() + offset;
1705 else if (v.type() == QVariant::Rect)
1706 v = v.toRect().translated(offset);
1707 else if (v.type() == QVariant::Point)
1708 v = v.toPoint() + offset;
1709 return v;
1710}
1711
1712/*! \reimp
1713*/
1714void QTextEdit::focusInEvent(QFocusEvent *e)
1715{
1716 Q_D(QTextEdit);
1717 if (e->reason() == Qt::MouseFocusReason) {
1718 d->clickCausedFocus = 1;
1719 }
1720 QAbstractScrollArea::focusInEvent(e);
1721 d->sendControlEvent(e);
1722}
1723
1724/*! \reimp
1725*/
1726void QTextEdit::focusOutEvent(QFocusEvent *e)
1727{
1728 Q_D(QTextEdit);
1729 QAbstractScrollArea::focusOutEvent(e);
1730 d->sendControlEvent(e);
1731}
1732
1733/*! \reimp
1734*/
1735void QTextEdit::showEvent(QShowEvent *)
1736{
1737 Q_D(QTextEdit);
1738 if (!d->anchorToScrollToWhenVisible.isEmpty()) {
1739 scrollToAnchor(d->anchorToScrollToWhenVisible);
1740 d->anchorToScrollToWhenVisible.clear();
1741 d->showCursorOnInitialShow = false;
1742 } else if (d->showCursorOnInitialShow) {
1743 d->showCursorOnInitialShow = false;
1744 ensureCursorVisible();
1745 }
1746}
1747
1748/*! \reimp
1749*/
1750void QTextEdit::changeEvent(QEvent *e)
1751{
1752 Q_D(QTextEdit);
1753 QAbstractScrollArea::changeEvent(e);
1754 if (e->type() == QEvent::ApplicationFontChange
1755 || e->type() == QEvent::FontChange) {
1756 d->control->document()->setDefaultFont(font());
1757 } else if(e->type() == QEvent::ActivationChange) {
1758 if (!isActiveWindow())
1759 d->autoScrollTimer.stop();
1760 } else if (e->type() == QEvent::EnabledChange) {
1761 e->setAccepted(isEnabled());
1762 d->control->setPalette(palette());
1763 d->sendControlEvent(e);
1764 } else if (e->type() == QEvent::PaletteChange) {
1765 d->control->setPalette(palette());
1766 } else if (e->type() == QEvent::LayoutDirectionChange) {
1767 d->sendControlEvent(e);
1768 }
1769}
1770
1771/*! \reimp
1772*/
1773#ifndef QT_NO_WHEELEVENT
1774void QTextEdit::wheelEvent(QWheelEvent *e)
1775{
1776 Q_D(QTextEdit);
1777 if (!(d->control->textInteractionFlags() & Qt::TextEditable)) {
1778 if (e->modifiers() & Qt::ControlModifier) {
1779 const int delta = e->delta();
1780 if (delta < 0)
1781 zoomOut();
1782 else if (delta > 0)
1783 zoomIn();
1784 return;
1785 }
1786 }
1787 QAbstractScrollArea::wheelEvent(e);
1788 updateMicroFocus();
1789}
1790#endif
1791
1792#ifndef QT_NO_CONTEXTMENU
1793/*! This function creates the standard context menu which is shown
1794 when the user clicks on the text edit with the right mouse
1795 button. It is called from the default contextMenuEvent() handler.
1796 The popup menu's ownership is transferred to the caller.
1797
1798 We recommend that you use the createStandardContextMenu(QPoint) version instead
1799 which will enable the actions that are sensitive to where the user clicked.
1800*/
1801
1802QMenu *QTextEdit::createStandardContextMenu()
1803{
1804 Q_D(QTextEdit);
1805 return d->control->createStandardContextMenu(QPointF(), this);
1806}
1807
1808/*!
1809 \since 4.4
1810 This function creates the standard context menu which is shown
1811 when the user clicks on the text edit with the right mouse
1812 button. It is called from the default contextMenuEvent() handler
1813 and it takes the \a position of where the mouse click was.
1814 This can enable actions that are sensitive to the position where the user clicked.
1815 The popup menu's ownership is transferred to the caller.
1816*/
1817
1818QMenu *QTextEdit::createStandardContextMenu(const QPoint &position)
1819{
1820 Q_D(QTextEdit);
1821 return d->control->createStandardContextMenu(position, this);
1822}
1823#endif // QT_NO_CONTEXTMENU
1824
1825/*!
1826 returns a QTextCursor at position \a pos (in viewport coordinates).
1827*/
1828QTextCursor QTextEdit::cursorForPosition(const QPoint &pos) const
1829{
1830 Q_D(const QTextEdit);
1831 return d->control->cursorForPosition(d->mapToContents(pos));
1832}
1833
1834/*!
1835 returns a rectangle (in viewport coordinates) that includes the
1836 \a cursor.
1837 */
1838QRect QTextEdit::cursorRect(const QTextCursor &cursor) const
1839{
1840 Q_D(const QTextEdit);
1841 if (cursor.isNull())
1842 return QRect();
1843
1844 QRect r = d->control->cursorRect(cursor).toRect();
1845 r.translate(-d->horizontalOffset(),-d->verticalOffset());
1846 return r;
1847}
1848
1849/*!
1850 returns a rectangle (in viewport coordinates) that includes the
1851 cursor of the text edit.
1852 */
1853QRect QTextEdit::cursorRect() const
1854{
1855 Q_D(const QTextEdit);
1856 QRect r = d->control->cursorRect().toRect();
1857 r.translate(-d->horizontalOffset(),-d->verticalOffset());
1858 return r;
1859}
1860
1861
1862/*!
1863 Returns the reference of the anchor at position \a pos, or an
1864 empty string if no anchor exists at that point.
1865*/
1866QString QTextEdit::anchorAt(const QPoint& pos) const
1867{
1868 Q_D(const QTextEdit);
1869 return d->control->anchorAt(d->mapToContents(pos));
1870}
1871
1872/*!
1873 \property QTextEdit::overwriteMode
1874 \since 4.1
1875 \brief whether text entered by the user will overwrite existing text
1876
1877 As with many text editors, the text editor widget can be configured
1878 to insert or overwrite existing text with new text entered by the user.
1879
1880 If this property is true, existing text is overwritten, character-for-character
1881 by new text; otherwise, text is inserted at the cursor position, displacing
1882 existing text.
1883
1884 By default, this property is false (new text does not overwrite existing text).
1885*/
1886
1887bool QTextEdit::overwriteMode() const
1888{
1889 Q_D(const QTextEdit);
1890 return d->control->overwriteMode();
1891}
1892
1893void QTextEdit::setOverwriteMode(bool overwrite)
1894{
1895 Q_D(QTextEdit);
1896 d->control->setOverwriteMode(overwrite);
1897}
1898
1899/*!
1900 \property QTextEdit::tabStopWidth
1901 \brief the tab stop width in pixels
1902 \since 4.1
1903
1904 By default, this property contains a value of 80 pixels.
1905*/
1906
1907int QTextEdit::tabStopWidth() const
1908{
1909 Q_D(const QTextEdit);
1910 return qRound(d->control->document()->defaultTextOption().tabStop());
1911}
1912
1913void QTextEdit::setTabStopWidth(int width)
1914{
1915 Q_D(QTextEdit);
1916 QTextOption opt = d->control->document()->defaultTextOption();
1917 if (opt.tabStop() == width || width < 0)
1918 return;
1919 opt.setTabStop(width);
1920 d->control->document()->setDefaultTextOption(opt);
1921}
1922
1923/*!
1924 \since 4.2
1925 \property QTextEdit::cursorWidth
1926
1927 This property specifies the width of the cursor in pixels. The default value is 1.
1928*/
1929int QTextEdit::cursorWidth() const
1930{
1931 Q_D(const QTextEdit);
1932 return d->control->cursorWidth();
1933}
1934
1935void QTextEdit::setCursorWidth(int width)
1936{
1937 Q_D(QTextEdit);
1938 d->control->setCursorWidth(width);
1939}
1940
1941/*!
1942 \property QTextEdit::acceptRichText
1943 \brief whether the text edit accepts rich text insertions by the user
1944 \since 4.1
1945
1946 When this propery is set to false text edit will accept only
1947 plain text input from the user. For example through clipboard or drag and drop.
1948
1949 This property's default is true.
1950*/
1951
1952bool QTextEdit::acceptRichText() const
1953{
1954 Q_D(const QTextEdit);
1955 return d->control->acceptRichText();
1956}
1957
1958void QTextEdit::setAcceptRichText(bool accept)
1959{
1960 Q_D(QTextEdit);
1961 d->control->setAcceptRichText(accept);
1962}
1963
1964/*!
1965 \class QTextEdit::ExtraSelection
1966 \since 4.2
1967 \brief The QTextEdit::ExtraSelection structure provides a way of specifying a
1968 character format for a given selection in a document
1969*/
1970
1971/*!
1972 \variable QTextEdit::ExtraSelection::cursor
1973 A cursor that contains a selection in a QTextDocument
1974*/
1975
1976/*!
1977 \variable QTextEdit::ExtraSelection::format
1978 A format that is used to specify a foreground or background brush/color
1979 for the selection.
1980*/
1981
1982/*!
1983 \since 4.2
1984 This function allows temporarily marking certain regions in the document
1985 with a given color, specified as \a selections. This can be useful for
1986 example in a programming editor to mark a whole line of text with a given
1987 background color to indicate the existence of a breakpoint.
1988
1989 \sa QTextEdit::ExtraSelection, extraSelections()
1990*/
1991void QTextEdit::setExtraSelections(const QList<ExtraSelection> &selections)
1992{
1993 Q_D(QTextEdit);
1994 d->control->setExtraSelections(selections);
1995}
1996
1997/*!
1998 \since 4.2
1999 Returns previously set extra selections.
2000
2001 \sa setExtraSelections()
2002*/
2003QList<QTextEdit::ExtraSelection> QTextEdit::extraSelections() const
2004{
2005 Q_D(const QTextEdit);
2006 return d->control->extraSelections();
2007}
2008
2009/*!
2010 This function returns a new MIME data object to represent the contents
2011 of the text edit's current selection. It is called when the selection needs
2012 to be encapsulated into a new QMimeData object; for example, when a drag
2013 and drop operation is started, or when data is copyied to the clipboard.
2014
2015 If you reimplement this function, note that the ownership of the returned
2016 QMimeData object is passed to the caller. The selection can be retrieved
2017 by using the textCursor() function.
2018*/
2019QMimeData *QTextEdit::createMimeDataFromSelection() const
2020{
2021 Q_D(const QTextEdit);
2022 return d->control->QTextControl::createMimeDataFromSelection();
2023}
2024
2025/*!
2026 This function returns true if the contents of the MIME data object, specified
2027 by \a source, can be decoded and inserted into the document. It is called
2028 for example when during a drag operation the mouse enters this widget and it
2029 is necessary to determine whether it is possible to accept the drag and drop
2030 operation.
2031
2032 Reimplement this function to enable drag and drop support for additional MIME types.
2033 */
2034bool QTextEdit::canInsertFromMimeData(const QMimeData *source) const
2035{
2036 Q_D(const QTextEdit);
2037 return d->control->QTextControl::canInsertFromMimeData(source);
2038}
2039
2040/*!
2041 This function inserts the contents of the MIME data object, specified
2042 by \a source, into the text edit at the current cursor position. It is
2043 called whenever text is inserted as the result of a clipboard paste
2044 operation, or when the text edit accepts data from a drag and drop
2045 operation.
2046
2047 Reimplement this function to enable drag and drop support for additional MIME types.
2048 */
2049void QTextEdit::insertFromMimeData(const QMimeData *source)
2050{
2051 Q_D(QTextEdit);
2052 d->control->QTextControl::insertFromMimeData(source);
2053}
2054
2055/*!
2056 \property QTextEdit::readOnly
2057 \brief whether the text edit is read-only
2058
2059 In a read-only text edit the user can only navigate through the
2060 text and select text; modifying the text is not possible.
2061
2062 This property's default is false.
2063*/
2064
2065bool QTextEdit::isReadOnly() const
2066{
2067 Q_D(const QTextEdit);
2068 return !(d->control->textInteractionFlags() & Qt::TextEditable);
2069}
2070
2071void QTextEdit::setReadOnly(bool ro)
2072{
2073 Q_D(QTextEdit);
2074 Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
2075 if (ro) {
2076 flags = Qt::TextSelectableByMouse;
2077#ifndef QT_NO_TEXTBROWSER
2078 if (qobject_cast<QTextBrowser *>(this))
2079 flags |= Qt::TextBrowserInteraction;
2080#endif
2081 } else {
2082 flags = Qt::TextEditorInteraction;
2083 }
2084 d->control->setTextInteractionFlags(flags);
2085 setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));
2086}
2087
2088/*!
2089 \property QTextEdit::textInteractionFlags
2090 \since 4.2
2091
2092 Specifies how the widget should interact with user input.
2093
2094 The default value depends on whether the QTextEdit is read-only
2095 or editable, and whether it is a QTextBrowser or not.
2096*/
2097
2098void QTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2099{
2100 Q_D(QTextEdit);
2101 d->control->setTextInteractionFlags(flags);
2102}
2103
2104Qt::TextInteractionFlags QTextEdit::textInteractionFlags() const
2105{
2106 Q_D(const QTextEdit);
2107 return d->control->textInteractionFlags();
2108}
2109
2110/*!
2111 Merges the properties specified in \a modifier into the current character
2112 format by calling QTextCursor::mergeCharFormat on the editor's cursor.
2113 If the editor has a selection then the properties of \a modifier are
2114 directly applied to the selection.
2115
2116 \sa QTextCursor::mergeCharFormat()
2117 */
2118void QTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)
2119{
2120 Q_D(QTextEdit);
2121 d->control->mergeCurrentCharFormat(modifier);
2122}
2123
2124/*!
2125 Sets the char format that is be used when inserting new text to \a
2126 format by calling QTextCursor::setCharFormat() on the editor's
2127 cursor. If the editor has a selection then the char format is
2128 directly applied to the selection.
2129 */
2130void QTextEdit::setCurrentCharFormat(const QTextCharFormat &format)
2131{
2132 Q_D(QTextEdit);
2133 d->control->setCurrentCharFormat(format);
2134}
2135
2136/*!
2137 Returns the char format that is used when inserting new text.
2138 */
2139QTextCharFormat QTextEdit::currentCharFormat() const
2140{
2141 Q_D(const QTextEdit);
2142 return d->control->currentCharFormat();
2143}
2144
2145/*!
2146 \property QTextEdit::autoFormatting
2147 \brief the enabled set of auto formatting features
2148
2149 The value can be any combination of the values in the
2150 AutoFormattingFlag enum. The default is AutoNone. Choose
2151 AutoAll to enable all automatic formatting.
2152
2153 Currently, the only automatic formatting feature provided is
2154 AutoBulletList; future versions of Qt may offer more.
2155*/
2156
2157QTextEdit::AutoFormatting QTextEdit::autoFormatting() const
2158{
2159 Q_D(const QTextEdit);
2160 return d->autoFormatting;
2161}
2162
2163void QTextEdit::setAutoFormatting(AutoFormatting features)
2164{
2165 Q_D(QTextEdit);
2166 d->autoFormatting = features;
2167}
2168
2169/*!
2170 Convenience slot that inserts \a text at the current
2171 cursor position.
2172
2173 It is equivalent to
2174
2175 \snippet doc/src/snippets/code/src_gui_widgets_qtextedit.cpp 1
2176 */
2177void QTextEdit::insertPlainText(const QString &text)
2178{
2179 Q_D(QTextEdit);
2180 d->control->insertPlainText(text);
2181}
2182
2183/*!
2184 Convenience slot that inserts \a text which is assumed to be of
2185 html formatting at the current cursor position.
2186
2187 It is equivalent to:
2188
2189 \snippet doc/src/snippets/code/src_gui_widgets_qtextedit.cpp 2
2190
2191 \note When using this function with a style sheet, the style sheet will
2192 only apply to the current block in the document. In order to apply a style
2193 sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
2194 instead.
2195 */
2196#ifndef QT_NO_TEXTHTMLPARSER
2197void QTextEdit::insertHtml(const QString &text)
2198{
2199 Q_D(QTextEdit);
2200 d->control->insertHtml(text);
2201}
2202#endif // QT_NO_TEXTHTMLPARSER
2203
2204/*!
2205 Scrolls the text edit so that the anchor with the given \a name is
2206 visible; does nothing if the \a name is empty, or is already
2207 visible, or isn't found.
2208*/
2209void QTextEdit::scrollToAnchor(const QString &name)
2210{
2211 Q_D(QTextEdit);
2212 if (name.isEmpty())
2213 return;
2214
2215 if (!isVisible()) {
2216 d->anchorToScrollToWhenVisible = name;
2217 return;
2218 }
2219
2220 QPointF p = d->control->anchorPosition(name);
2221 const int newPosition = qRound(p.y());
2222 if ( d->vbar->maximum() < newPosition )
2223 d->_q_adjustScrollbars();
2224 d->vbar->setValue(newPosition);
2225}
2226
2227/*!
2228 \fn QTextEdit::zoomIn(int range)
2229
2230 Zooms in on the text by making the base font size \a range
2231 points larger and recalculating all font sizes to be the new size.
2232 This does not change the size of any images.
2233
2234 \sa zoomOut()
2235*/
2236void QTextEdit::zoomIn(int range)
2237{
2238 QFont f = font();
2239 const int newSize = f.pointSize() + range;
2240 if (newSize <= 0)
2241 return;
2242 f.setPointSize(newSize);
2243 setFont(f);
2244}
2245
2246/*!
2247 \fn QTextEdit::zoomOut(int range)
2248
2249 \overload
2250
2251 Zooms out on the text by making the base font size \a range points
2252 smaller and recalculating all font sizes to be the new size. This
2253 does not change the size of any images.
2254
2255 \sa zoomIn()
2256*/
2257void QTextEdit::zoomOut(int range)
2258{
2259 zoomIn(-range);
2260}
2261
2262/*!
2263 \since 4.2
2264 Moves the cursor by performing the given \a operation.
2265
2266 If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.
2267 This is the same effect that the user achieves when they hold down the Shift key
2268 and move the cursor with the cursor keys.
2269
2270 \sa QTextCursor::movePosition()
2271*/
2272void QTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
2273{
2274 Q_D(QTextEdit);
2275 d->control->moveCursor(operation, mode);
2276}
2277
2278/*!
2279 \since 4.2
2280 Returns whether text can be pasted from the clipboard into the textedit.
2281*/
2282bool QTextEdit::canPaste() const
2283{
2284 Q_D(const QTextEdit);
2285 return d->control->canPaste();
2286}
2287
2288#ifndef QT_NO_PRINTER
2289/*!
2290 \since 4.3
2291 Convenience function to print the text edit's document to the given \a printer. This
2292 is equivalent to calling the print method on the document directly except that this
2293 function also supports QPrinter::Selection as print range.
2294
2295 \sa QTextDocument::print()
2296*/
2297void QTextEdit::print(QPrinter *printer) const
2298{
2299 Q_D(const QTextEdit);
2300 d->control->print(printer);
2301}
2302#endif // QT _NO_PRINTER
2303
2304/*! \property QTextEdit::tabChangesFocus
2305 \brief whether \gui Tab changes focus or is accepted as input
2306
2307 In some occasions text edits should not allow the user to input
2308 tabulators or change indentation using the \gui Tab key, as this breaks
2309 the focus chain. The default is false.
2310
2311*/
2312
2313bool QTextEdit::tabChangesFocus() const
2314{
2315 Q_D(const QTextEdit);
2316 return d->tabChangesFocus;
2317}
2318
2319void QTextEdit::setTabChangesFocus(bool b)
2320{
2321 Q_D(QTextEdit);
2322 d->tabChangesFocus = b;
2323}
2324
2325/*!
2326 \property QTextEdit::documentTitle
2327 \brief the title of the document parsed from the text.
2328
2329 By default, for a newly-created, empty document, this property contains
2330 an empty string.
2331*/
2332
2333/*!
2334 \property QTextEdit::lineWrapMode
2335 \brief the line wrap mode
2336
2337 The default mode is WidgetWidth which causes words to be
2338 wrapped at the right edge of the text edit. Wrapping occurs at
2339 whitespace, keeping whole words intact. If you want wrapping to
2340 occur within words use setWordWrapMode(). If you set a wrap mode of
2341 FixedPixelWidth or FixedColumnWidth you should also call
2342 setLineWrapColumnOrWidth() with the width you want.
2343
2344 \sa lineWrapColumnOrWidth
2345*/
2346
2347QTextEdit::LineWrapMode QTextEdit::lineWrapMode() const
2348{
2349 Q_D(const QTextEdit);
2350 return d->lineWrap;
2351}
2352
2353void QTextEdit::setLineWrapMode(LineWrapMode wrap)
2354{
2355 Q_D(QTextEdit);
2356 if (d->lineWrap == wrap)
2357 return;
2358 d->lineWrap = wrap;
2359 d->updateDefaultTextOption();
2360 d->relayoutDocument();
2361}
2362
2363/*!
2364 \property QTextEdit::lineWrapColumnOrWidth
2365 \brief the position (in pixels or columns depending on the wrap mode) where text will be wrapped
2366
2367 If the wrap mode is FixedPixelWidth, the value is the number of
2368 pixels from the left edge of the text edit at which text should be
2369 wrapped. If the wrap mode is FixedColumnWidth, the value is the
2370 column number (in character columns) from the left edge of the
2371 text edit at which text should be wrapped.
2372
2373 By default, this property contains a value of 0.
2374
2375 \sa lineWrapMode
2376*/
2377
2378int QTextEdit::lineWrapColumnOrWidth() const
2379{
2380 Q_D(const QTextEdit);
2381 return d->lineWrapColumnOrWidth;
2382}
2383
2384void QTextEdit::setLineWrapColumnOrWidth(int w)
2385{
2386 Q_D(QTextEdit);
2387 d->lineWrapColumnOrWidth = w;
2388 d->relayoutDocument();
2389}
2390
2391/*!
2392 \property QTextEdit::wordWrapMode
2393 \brief the mode QTextEdit will use when wrapping text by words
2394
2395 By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.
2396
2397 \sa QTextOption::WrapMode
2398*/
2399
2400QTextOption::WrapMode QTextEdit::wordWrapMode() const
2401{
2402 Q_D(const QTextEdit);
2403 return d->wordWrap;
2404}
2405
2406void QTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
2407{
2408 Q_D(QTextEdit);
2409 if (mode == d->wordWrap)
2410 return;
2411 d->wordWrap = mode;
2412 d->updateDefaultTextOption();
2413}
2414
2415/*!
2416 Finds the next occurrence of the string, \a exp, using the given
2417 \a options. Returns true if \a exp was found and changes the
2418 cursor to select the match; otherwise returns false.
2419*/
2420bool QTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
2421{
2422 Q_D(QTextEdit);
2423 return d->control->find(exp, options);
2424}
2425
2426/*!
2427 \fn void QTextEdit::copyAvailable(bool yes)
2428
2429 This signal is emitted when text is selected or de-selected in the
2430 text edit.
2431
2432 When text is selected this signal will be emitted with \a yes set
2433 to true. If no text has been selected or if the selected text is
2434 de-selected this signal is emitted with \a yes set to false.
2435
2436 If \a yes is true then copy() can be used to copy the selection to
2437 the clipboard. If \a yes is false then copy() does nothing.
2438
2439 \sa selectionChanged()
2440*/
2441
2442/*!
2443 \fn void QTextEdit::currentCharFormatChanged(const QTextCharFormat &f)
2444
2445 This signal is emitted if the current character format has changed, for
2446 example caused by a change of the cursor position.
2447
2448 The new format is \a f.
2449
2450 \sa setCurrentCharFormat()
2451*/
2452
2453/*!
2454 \fn void QTextEdit::selectionChanged()
2455
2456 This signal is emitted whenever the selection changes.
2457
2458 \sa copyAvailable()
2459*/
2460
2461/*!
2462 \fn void QTextEdit::cursorPositionChanged()
2463
2464 This signal is emitted whenever the position of the
2465 cursor changed.
2466*/
2467
2468/*!
2469 \since 4.2
2470
2471 Sets the text edit's \a text. The text can be plain text or HTML
2472 and the text edit will try to guess the right format.
2473
2474 Use setHtml() or setPlainText() directly to avoid text edit's guessing.
2475*/
2476void QTextEdit::setText(const QString &text)
2477{
2478 Q_D(QTextEdit);
2479 Qt::TextFormat format = d->textFormat;
2480 if (d->textFormat == Qt::AutoText)
2481 format = Qt::mightBeRichText(text) ? Qt::RichText : Qt::PlainText;
2482#ifndef QT_NO_TEXTHTMLPARSER
2483 if (format == Qt::RichText || format == Qt::LogText)
2484 setHtml(text);
2485 else
2486#endif
2487 setPlainText(text);
2488}
2489
2490#ifdef QT3_SUPPORT
2491/*!
2492 Use the QTextCursor class instead.
2493*/
2494void QTextEdit::moveCursor(CursorAction action, QTextCursor::MoveMode mode)
2495{
2496 Q_D(QTextEdit);
2497 if (action == MovePageUp) {
2498 d->pageUpDown(QTextCursor::Up, mode);
2499 return;
2500 } else if (action == MovePageDown) {
2501 d->pageUpDown(QTextCursor::Down, mode);
2502 return;
2503 }
2504
2505 QTextCursor cursor = d->control->textCursor();
2506 QTextCursor::MoveOperation op = QTextCursor::NoMove;
2507 switch (action) {
2508 case MoveBackward: op = QTextCursor::Left; break;
2509 case MoveForward: op = QTextCursor::Right; break;
2510 case MoveWordBackward: op = QTextCursor::WordLeft; break;
2511 case MoveWordForward: op = QTextCursor::WordRight; break;
2512 case MoveUp: op = QTextCursor::Up; break;
2513 case MoveDown: op = QTextCursor::Down; break;
2514 case MoveLineStart: op = QTextCursor::StartOfLine; break;
2515 case MoveLineEnd: op = QTextCursor::EndOfLine; break;
2516 case MoveHome: op = QTextCursor::Start; break;
2517 case MoveEnd: op = QTextCursor::End; break;
2518 default: return;
2519 }
2520 cursor.movePosition(op, mode);
2521 d->control->setTextCursor(cursor);
2522}
2523
2524/*!
2525 Use the QTextCursor class instead.
2526*/
2527void QTextEdit::moveCursor(CursorAction action, bool select)
2528{
2529 moveCursor(action, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
2530}
2531
2532/*!
2533 Executes keyboard action \a action.
2534
2535 Use the QTextCursor class instead.
2536
2537 \sa textCursor()
2538*/
2539void QTextEdit::doKeyboardAction(KeyboardAction action)
2540{
2541 Q_D(QTextEdit);
2542 QTextCursor cursor = d->control->textCursor();
2543 switch (action) {
2544 case ActionBackspace: cursor.deletePreviousChar(); break;
2545 case ActionDelete: cursor.deleteChar(); break;
2546 case ActionReturn: cursor.insertBlock(); break;
2547 case ActionKill: {
2548 QTextBlock block = cursor.block();
2549 if (cursor.position() == block.position() + block.length() - 2)
2550 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
2551 else
2552 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
2553 cursor.deleteChar();
2554 break;
2555 }
2556 case ActionWordBackspace:
2557 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
2558 cursor.deletePreviousChar();
2559 break;
2560 case ActionWordDelete:
2561 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
2562 cursor.deleteChar();
2563 break;
2564 }
2565 d->control->setTextCursor(cursor);
2566}
2567
2568/*!
2569 Returns all the text in the text edit as plain text.
2570*/
2571QString QTextEdit::text() const
2572{
2573 Q_D(const QTextEdit);
2574 if (d->textFormat == Qt::RichText || d->textFormat == Qt::LogText || (d->textFormat == Qt::AutoText && d->preferRichText))
2575 return d->control->toHtml();
2576 else
2577 return d->control->toPlainText();
2578}
2579
2580
2581/*!
2582 Sets the text format to format \a f.
2583
2584 \sa textFormat()
2585*/
2586void QTextEdit::setTextFormat(Qt::TextFormat f)
2587{
2588 Q_D(QTextEdit);
2589 d->textFormat = f;
2590}
2591
2592/*!
2593 Returns the text format.
2594
2595 \sa setTextFormat()
2596*/
2597Qt::TextFormat QTextEdit::textFormat() const
2598{
2599 Q_D(const QTextEdit);
2600 return d->textFormat;
2601}
2602
2603#endif // QT3_SUPPORT
2604
2605/*!
2606 Appends a new paragraph with \a text to the end of the text edit.
2607
2608 \note The new paragraph appended will have the same character format and
2609 block format as the current paragraph, determined by the position of the cursor.
2610
2611 \sa currentCharFormat(), QTextCursor::blockFormat()
2612*/
2613
2614void QTextEdit::append(const QString &text)
2615{
2616 Q_D(QTextEdit);
2617 QTextBlock lastBlock = d->control->document()->lastBlock();
2618 const bool atBottom = isReadOnly() ? d->verticalOffset() >= d->vbar->maximum() :
2619 d->control->textCursor().atEnd();
2620 d->control->append(text);
2621 if (atBottom)
2622 d->vbar->setValue(d->vbar->maximum());
2623}
2624
2625/*!
2626 Ensures that the cursor is visible by scrolling the text edit if
2627 necessary.
2628*/
2629void QTextEdit::ensureCursorVisible()
2630{
2631 Q_D(QTextEdit);
2632 d->control->ensureCursorVisible();
2633}
2634
2635/*!
2636 \enum QTextEdit::KeyboardAction
2637
2638 \compat
2639
2640 \value ActionBackspace
2641 \value ActionDelete
2642 \value ActionReturn
2643 \value ActionKill
2644 \value ActionWordBackspace
2645 \value ActionWordDelete
2646*/
2647
2648/*!
2649 \fn bool QTextEdit::find(const QString &exp, bool cs, bool wo)
2650
2651 Use the find() overload that takes a QTextDocument::FindFlags
2652 argument.
2653*/
2654
2655/*!
2656 \fn void QTextEdit::sync()
2657
2658 Does nothing.
2659*/
2660
2661/*!
2662 \fn void QTextEdit::setBold(bool b)
2663
2664 Use setFontWeight() instead.
2665*/
2666
2667/*!
2668 \fn void QTextEdit::setUnderline(bool b)
2669
2670 Use setFontUnderline() instead.
2671*/
2672
2673/*!
2674 \fn void QTextEdit::setItalic(bool i)
2675
2676 Use setFontItalic() instead.
2677*/
2678
2679/*!
2680 \fn void QTextEdit::setFamily(const QString &family)
2681
2682 Use setFontFamily() instead.
2683*/
2684
2685/*!
2686 \fn void QTextEdit::setPointSize(int size)
2687
2688 Use setFontPointSize() instead.
2689*/
2690
2691/*!
2692 \fn bool QTextEdit::italic() const
2693
2694 Use fontItalic() instead.
2695*/
2696
2697/*!
2698 \fn bool QTextEdit::bold() const
2699
2700 Use fontWeight() >= QFont::Bold instead.
2701*/
2702
2703/*!
2704 \fn bool QTextEdit::underline() const
2705
2706 Use fontUnderline() instead.
2707*/
2708
2709/*!
2710 \fn QString QTextEdit::family() const
2711
2712 Use fontFamily() instead.
2713*/
2714
2715/*!
2716 \fn int QTextEdit::pointSize() const
2717
2718 Use int(fontPointSize()+0.5) instead.
2719*/
2720
2721/*!
2722 \fn bool QTextEdit::hasSelectedText() const
2723
2724 Use textCursor().hasSelection() instead.
2725*/
2726
2727/*!
2728 \fn QString QTextEdit::selectedText() const
2729
2730 Use textCursor().selectedText() instead.
2731*/
2732
2733/*!
2734 \fn bool QTextEdit::isUndoAvailable() const
2735
2736 Use document()->isUndoAvailable() instead.
2737*/
2738
2739/*!
2740 \fn bool QTextEdit::isRedoAvailable() const
2741
2742 Use document()->isRedoAvailable() instead.
2743*/
2744
2745/*!
2746 \fn void QTextEdit::insert(const QString &text)
2747
2748 Use insertPlainText() instead.
2749*/
2750
2751/*!
2752 \fn bool QTextEdit::isModified() const
2753
2754 Use document()->isModified() instead.
2755*/
2756
2757/*!
2758 \fn QColor QTextEdit::color() const
2759
2760 Use textColor() instead.
2761*/
2762
2763/*!
2764 \fn void QTextEdit::textChanged()
2765
2766 This signal is emitted whenever the document's content changes; for
2767 example, when text is inserted or deleted, or when formatting is applied.
2768*/
2769
2770/*!
2771 \fn void QTextEdit::undoAvailable(bool available)
2772
2773 This signal is emitted whenever undo operations become available
2774 (\a available is true) or unavailable (\a available is false).
2775*/
2776
2777/*!
2778 \fn void QTextEdit::redoAvailable(bool available)
2779
2780 This signal is emitted whenever redo operations become available
2781 (\a available is true) or unavailable (\a available is false).
2782*/
2783
2784/*!
2785 \fn void QTextEdit::currentFontChanged(const QFont &font)
2786
2787 Use currentCharFormatChanged() instead.
2788*/
2789
2790/*!
2791 \fn void QTextEdit::currentColorChanged(const QColor &color)
2792
2793 Use currentCharFormatChanged() instead.
2794*/
2795
2796/*!
2797 \fn void QTextEdit::setModified(bool m)
2798
2799 Use document->setModified() instead.
2800*/
2801
2802/*!
2803 \fn void QTextEdit::setColor(const QColor &color)
2804
2805 Use setTextColor() instead.
2806*/
2807#endif // QT_NO_TEXTEDIT
2808
2809QT_END_NAMESPACE
2810
2811#include "moc_qtextedit.cpp"
Note: See TracBrowser for help on using the repository browser.