00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qtextcontrol_p.h"
00025 #include "qtextcontrol_p_p.h"
00026 #include "qlineedit.h"
00027
00028 #ifndef QT_NO_TEXTCONTROL
00029
00030 #include <qfont.h>
00031 #include <qpainter.h>
00032 #include <qevent.h>
00033 #include <qdebug.h>
00034 #include <qmime.h>
00035 #include <qdrag.h>
00036 #include <qclipboard.h>
00037 #include <qmenu.h>
00038 #include <qstyle.h>
00039 #include <qtimer.h>
00040 #include "private/qtextdocumentlayout_p.h"
00041 #include "private/qtextedit_p.h"
00042 #include "qtextdocument.h"
00043 #include "private/qtextdocument_p.h"
00044 #include "qtextlist.h"
00045 #include "private/qtextcontrol_p.h"
00046 #include "qgraphicssceneevent.h"
00047
00048 #include <qtextformat.h>
00049 #include <qdatetime.h>
00050 #include <qapplication.h>
00051 #include <limits.h>
00052 #include <qtexttable.h>
00053 #include <qvariant.h>
00054 #include <qurl.h>
00055 #include <qdesktopservices.h>
00056 #include <qinputcontext.h>
00057
00058 #ifndef QT_NO_SHORTCUT
00059 #include <qkeysequence.h>
00060 #define ACCEL_KEY(k) QString::fromLatin1("\t") + QString(QKeySequence( Qt::CTRL | Qt::Key_ ## k ))
00061 #else
00062 #define ACCEL_KEY(k) QString("\tCtrl+" #k)
00063 #endif
00064
00065
00066 static QTextLine currentTextLine(const QTextCursor &cursor)
00067 {
00068 const QTextBlock block = cursor.block();
00069 if (!block.isValid())
00070 return QTextLine();
00071
00072 const QTextLayout *layout = block.layout();
00073 if (!layout)
00074 return QTextLine();
00075
00076 const int relativePos = cursor.position() - block.position();
00077 return layout->lineForTextPosition(relativePos);
00078 }
00079
00080 QTextControlPrivate::QTextControlPrivate()
00081 : doc(0), cursorOn(false), cursorIsFocusIndicator(false),
00082 interactionFlags(Qt::TextEditorInteraction),
00083 #ifndef QT_NO_DRAGANDDROP
00084 mousePressed(false), mightStartDrag(false),
00085 #endif
00086 lastSelectionState(false), ignoreAutomaticScrollbarAdjustement(false),
00087 overwriteMode(false),
00088 acceptRichText(true),
00089 preeditCursor(0), hideCursor(false),
00090 hasFocus(false),
00091 layoutDirection(QApplication::layoutDirection()),
00092 isEnabled(true),
00093 hadSelectionOnMousePress(false),
00094 openExternalLinks(false)
00095 {}
00096
00097 bool QTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
00098 {
00099 #ifdef QT_NO_SHORTCUT
00100 Q_UNUSED(e);
00101 #endif
00102
00103 Q_Q(QTextControl);
00104 if (cursor.isNull())
00105 return false;
00106
00107 const QTextCursor oldSelection = cursor;
00108 const int oldCursorPos = cursor.position();
00109
00110 QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
00111 QTextCursor::MoveOperation op = QTextCursor::NoMove;
00112
00113 if (false) {
00114 }
00115 #ifndef QT_NO_SHORTCUT
00116 if (e == QKeySequence::MoveToNextChar) {
00117 op = QTextCursor::Right;
00118 }
00119 else if (e == QKeySequence::MoveToPreviousChar) {
00120 op = QTextCursor::Left;
00121 }
00122 else if (e == QKeySequence::SelectNextChar) {
00123 op = QTextCursor::Right;
00124 mode = QTextCursor::KeepAnchor;
00125 }
00126 else if (e == QKeySequence::SelectPreviousChar) {
00127 op = QTextCursor::Left;
00128 mode = QTextCursor::KeepAnchor;
00129 }
00130 else if (e == QKeySequence::SelectNextWord) {
00131 op = QTextCursor::WordRight;
00132 mode = QTextCursor::KeepAnchor;
00133 }
00134 else if (e == QKeySequence::SelectPreviousWord) {
00135 op = QTextCursor::WordLeft;
00136 mode = QTextCursor::KeepAnchor;
00137 }
00138 else if (e == QKeySequence::SelectStartOfLine) {
00139 op = QTextCursor::StartOfLine;
00140 mode = QTextCursor::KeepAnchor;
00141 }
00142 else if (e == QKeySequence::SelectEndOfLine) {
00143 op = QTextCursor::EndOfLine;
00144 mode = QTextCursor::KeepAnchor;
00145 }
00146 else if (e == QKeySequence::SelectStartOfBlock) {
00147 op = QTextCursor::StartOfBlock;
00148 mode = QTextCursor::KeepAnchor;
00149 }
00150 else if (e == QKeySequence::SelectEndOfBlock) {
00151 op = QTextCursor::EndOfBlock;
00152 mode = QTextCursor::KeepAnchor;
00153 }
00154 else if (e == QKeySequence::SelectStartOfDocument) {
00155 op = QTextCursor::Start;
00156 mode = QTextCursor::KeepAnchor;
00157 }
00158 else if (e == QKeySequence::SelectEndOfDocument) {
00159 op = QTextCursor::End;
00160 mode = QTextCursor::KeepAnchor;
00161 }
00162 else if (e == QKeySequence::SelectPreviousLine) {
00163 op = QTextCursor::Up;
00164 mode = QTextCursor::KeepAnchor;
00165 }
00166 else if (e == QKeySequence::SelectNextLine) {
00167 op = QTextCursor::Down;
00168 mode = QTextCursor::KeepAnchor;
00169 {
00170 QTextBlock block = cursor.block();
00171 QTextLine line = currentTextLine(cursor);
00172 if (!block.next().isValid()
00173 && line.isValid()
00174 && line.lineNumber() == block.layout()->lineCount() - 1)
00175 op = QTextCursor::End;
00176 }
00177 }
00178 else if (e == QKeySequence::SelectNextLine) {
00179 op = QTextCursor::Down;
00180 mode = QTextCursor::KeepAnchor;
00181 {
00182 QTextBlock block = cursor.block();
00183 QTextLine line = currentTextLine(cursor);
00184 if (!block.next().isValid()
00185 && line.isValid()
00186 && line.lineNumber() == block.layout()->lineCount() - 1)
00187 op = QTextCursor::End;
00188 }
00189 }
00190 else if (e == QKeySequence::MoveToNextWord) {
00191 op = QTextCursor::WordRight;
00192 }
00193 else if (e == QKeySequence::MoveToPreviousWord) {
00194 op = QTextCursor::WordLeft;
00195 }
00196 else if (e == QKeySequence::MoveToEndOfBlock) {
00197 op = QTextCursor::EndOfBlock;
00198 }
00199 else if (e == QKeySequence::MoveToStartOfBlock) {
00200 op = QTextCursor::StartOfBlock;
00201 }
00202 else if (e == QKeySequence::MoveToNextLine) {
00203 op = QTextCursor::Down;
00204 }
00205 else if (e == QKeySequence::MoveToPreviousLine) {
00206 op = QTextCursor::Up;
00207 }
00208 else if (e == QKeySequence::MoveToPreviousLine) {
00209 op = QTextCursor::Up;
00210 }
00211 else if (e == QKeySequence::MoveToStartOfLine) {
00212 op = QTextCursor::StartOfLine;
00213 }
00214 else if (e == QKeySequence::MoveToEndOfLine) {
00215 op = QTextCursor::EndOfLine;
00216 }
00217 else if (e == QKeySequence::MoveToStartOfDocument) {
00218 op = QTextCursor::Start;
00219 }
00220 else if (e == QKeySequence::MoveToEndOfDocument) {
00221 op = QTextCursor::End;
00222 }
00223 #endif // QT_NO_SHORTCUT
00224 else {
00225 return false;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 const bool moved = cursor.movePosition(op, mode);
00239 q->ensureCursorVisible();
00240
00241 if (moved) {
00242 if (cursor.position() != oldCursorPos)
00243 emit q->cursorPositionChanged();
00244 emit q->microFocusChanged();
00245 }
00246 #ifdef QT_KEYPAD_NAVIGATION
00247 else if (QApplication::keypadNavigationEnabled()
00248 && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) {
00249 return false;
00250 }
00251 #endif
00252
00253 selectionChanged();
00254
00255 repaintOldAndNewSelection(oldSelection);
00256
00257 return true;
00258 }
00259
00260 void QTextControlPrivate::updateCurrentCharFormat()
00261 {
00262 Q_Q(QTextControl);
00263
00264 QTextCharFormat fmt = cursor.charFormat();
00265 if (fmt == lastCharFormat)
00266 return;
00267 lastCharFormat = fmt;
00268
00269 emit q->currentCharFormatChanged(fmt);
00270 emit q->microFocusChanged();
00271 }
00272
00273 void QTextControlPrivate::indent()
00274 {
00275 QTextBlockFormat blockFmt = cursor.blockFormat();
00276
00277 QTextList *list = cursor.currentList();
00278 if (!list) {
00279 QTextBlockFormat modifier;
00280 modifier.setIndent(blockFmt.indent() + 1);
00281 cursor.mergeBlockFormat(modifier);
00282 } else {
00283 QTextListFormat format = list->format();
00284 format.setIndent(format.indent() + 1);
00285
00286 if (list->itemNumber(cursor.block()) == 1)
00287 list->setFormat(format);
00288 else
00289 cursor.createList(format);
00290 }
00291 }
00292
00293 void QTextControlPrivate::outdent()
00294 {
00295 QTextBlockFormat blockFmt = cursor.blockFormat();
00296
00297 QTextList *list = cursor.currentList();
00298
00299 if (!list) {
00300 QTextBlockFormat modifier;
00301 modifier.setIndent(blockFmt.indent() - 1);
00302 cursor.mergeBlockFormat(modifier);
00303 } else {
00304 QTextListFormat listFmt = list->format();
00305 listFmt.setIndent(listFmt.indent() - 1);
00306 list->setFormat(listFmt);
00307 }
00308 }
00309
00310 void QTextControlPrivate::gotoNextTableCell()
00311 {
00312 QTextTable *table = cursor.currentTable();
00313 QTextTableCell cell = table->cellAt(cursor);
00314
00315 int newColumn = cell.column() + cell.columnSpan();
00316 int newRow = cell.row();
00317
00318 if (newColumn >= table->columns()) {
00319 newColumn = 0;
00320 ++newRow;
00321 if (newRow >= table->rows())
00322 table->insertRows(table->rows(), 1);
00323 }
00324
00325 cell = table->cellAt(newRow, newColumn);
00326 cursor = cell.firstCursorPosition();
00327 }
00328
00329 void QTextControlPrivate::gotoPreviousTableCell()
00330 {
00331 QTextTable *table = cursor.currentTable();
00332 QTextTableCell cell = table->cellAt(cursor);
00333
00334 int newColumn = cell.column() - 1;
00335 int newRow = cell.row();
00336
00337 if (newColumn < 0) {
00338 newColumn = table->columns() - 1;
00339 --newRow;
00340 if (newRow < 0)
00341 return;
00342 }
00343
00344 cell = table->cellAt(newRow, newColumn);
00345 cursor = cell.firstCursorPosition();
00346 }
00347
00348 void QTextControlPrivate::createAutoBulletList()
00349 {
00350 cursor.beginEditBlock();
00351
00352 QTextBlockFormat blockFmt = cursor.blockFormat();
00353
00354 QTextListFormat listFmt;
00355 listFmt.setStyle(QTextListFormat::ListDisc);
00356 listFmt.setIndent(blockFmt.indent() + 1);
00357
00358 blockFmt.setIndent(0);
00359 cursor.setBlockFormat(blockFmt);
00360
00361 cursor.createList(listFmt);
00362
00363 cursor.endEditBlock();
00364 }
00365
00366 void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
00367 {
00368 Q_Q(QTextControl);
00369
00370
00371
00372 const QTextCharFormat charFormatForInsertion = cursor.charFormat();
00373
00374 bool clearDocument = true;
00375 if (!doc) {
00376 palette = QApplication::palette("QTextControl");
00377
00378 if (document) {
00379 doc = document;
00380 clearDocument = false;
00381 } else {
00382 doc = new QTextDocument(q);
00383 }
00384
00385 QObject::connect(doc->documentLayout(), SIGNAL(update(QRectF)), q, SIGNAL(updateRequest(QRectF)));
00386 QObject::connect(doc->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), q, SIGNAL(documentSizeChanged(QSizeF)));
00387 cursor = QTextCursor(doc);
00388
00389
00390
00391 QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection()));
00392 QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor)));
00393
00394
00395 QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged()));
00396 QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
00397 QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
00398 }
00399
00400 doc->setUndoRedoEnabled(false);
00401
00402
00403 QObject::disconnect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged()));
00404
00405 if (!text.isEmpty()) {
00406
00407
00408
00409
00410
00411
00412 cursor = QTextCursor();
00413 if (format == Qt::PlainText) {
00414 QTextCursor formatCursor(doc);
00415
00416
00417
00418 formatCursor.beginEditBlock();
00419 doc->setPlainText(text);
00420 doc->setUndoRedoEnabled(false);
00421 formatCursor.select(QTextCursor::Document);
00422 formatCursor.setCharFormat(charFormatForInsertion);
00423 formatCursor.endEditBlock();
00424 } else {
00425 doc->setHtml(text);
00426 doc->setUndoRedoEnabled(false);
00427 }
00428 cursor = QTextCursor(doc);
00429 } else if (clearDocument) {
00430 doc->clear();
00431 cursor.movePosition(QTextCursor::Start);
00432 QTextBlockFormat blockFmt;
00433 blockFmt.setLayoutDirection(layoutDirection);
00434 cursor.mergeBlockFormat(blockFmt);
00435 cursor.setCharFormat(charFormatForInsertion);
00436 }
00437
00438 QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged()));
00439 emit q->textChanged();
00440 doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
00441 _q_updateCurrentCharFormatAndSelection();
00442 doc->setModified(false);
00443 q->ensureCursorVisible();
00444 emit q->cursorPositionChanged();
00445 }
00446
00447 void QTextControlPrivate::startDrag()
00448 {
00449 #ifndef QT_NO_DRAGANDDROP
00450 Q_Q(QTextControl);
00451 mousePressed = false;
00452 if (!contextWidget)
00453 return;
00454 QMimeData *data = q->createMimeDataFromSelection();
00455
00456 QDrag *drag = new QDrag(contextWidget);
00457 drag->setMimeData(data);
00458
00459 Qt::DropActions actions = Qt::CopyAction;
00460 if (interactionFlags & Qt::TextEditable)
00461 actions |= Qt::MoveAction;
00462 Qt::DropAction action = drag->start(actions);
00463
00464 if (action == Qt::MoveAction && drag->target() != contextWidget)
00465 cursor.removeSelectedText();
00466 #endif
00467 }
00468
00469 void QTextControlPrivate::setCursorPosition(const QPointF &pos)
00470 {
00471 const int cursorPos = doc->documentLayout()->hitTest(pos, Qt::FuzzyHit);
00472 if (cursorPos == -1)
00473 return;
00474 cursor.setPosition(cursorPos);
00475 }
00476
00477 void QTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
00478 {
00479 cursor.setPosition(pos, mode);
00480
00481 if (mode != QTextCursor::KeepAnchor) {
00482 selectedWordOnDoubleClick = QTextCursor();
00483 selectedLineOnDoubleClick = QTextCursor();
00484 }
00485 }
00486
00487 void QTextControlPrivate::repaintCursor()
00488 {
00489 Q_Q(QTextControl);
00490 emit q->updateRequest(q->cursorRect());
00491 }
00492
00493 void QTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
00494 {
00495 Q_Q(QTextControl);
00496 QRectF updateRect = selectionRect() | selectionRect(oldSelection);
00497
00498 if (cursor.hasSelection()
00499 && oldSelection.hasSelection()
00500 && cursor.currentFrame() == oldSelection.currentFrame()
00501 && !cursor.hasComplexSelection()
00502 && !oldSelection.hasComplexSelection()
00503 && cursor.anchor() == oldSelection.anchor()) {
00504 QTextCursor differenceSelection(doc);
00505 differenceSelection.setPosition(oldSelection.position());
00506 differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
00507 emit q->updateRequest(selectionRect(differenceSelection));
00508 } else {
00509 if (!oldSelection.isNull())
00510 emit q->updateRequest(selectionRect(oldSelection));
00511 emit q->updateRequest(selectionRect());
00512 }
00513 }
00514
00515 void QTextControlPrivate::selectionChanged()
00516 {
00517 Q_Q(QTextControl);
00518 bool current = cursor.hasSelection();
00519 if (current == lastSelectionState)
00520 return;
00521
00522 lastSelectionState = current;
00523 emit q->copyAvailable(current);
00524 emit q->selectionChanged();
00525 emit q->microFocusChanged();
00526 }
00527
00528 void QTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
00529 {
00530 updateCurrentCharFormat();
00531 selectionChanged();
00532 }
00533
00534 #ifndef QT_NO_CLIPBOARD
00535 void QTextControlPrivate::setClipboardSelection()
00536 {
00537 QClipboard *clipboard = QApplication::clipboard();
00538 if (!cursor.hasSelection() || !clipboard->supportsSelection())
00539 return;
00540 Q_Q(QTextControl);
00541 QMimeData *data = q->createMimeDataFromSelection();
00542 clipboard->setMimeData(data, QClipboard::Selection);
00543 }
00544 #endif
00545
00546 void QTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
00547 {
00548 Q_Q(QTextControl);
00549 if (someCursor.isCopyOf(cursor)) {
00550 emit q->cursorPositionChanged();
00551 emit q->microFocusChanged();
00552 }
00553 }
00554
00555 void QTextControlPrivate::setBlinkingCursorEnabled(bool enable)
00556 {
00557 Q_Q(QTextControl);
00558 if (enable && QApplication::cursorFlashTime() > 0) {
00559 cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
00560 cursorOn = true;
00561 } else {
00562 cursorBlinkTimer.stop();
00563 cursorOn = false;
00564 }
00565 repaintCursor();
00566 }
00567
00568 void QTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
00569 {
00570 Q_Q(QTextControl);
00571
00572
00573 if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
00574 && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
00575 q->setTextCursor(selectedWordOnDoubleClick);
00576 return;
00577 }
00578
00579 QTextCursor curs = selectedWordOnDoubleClick;
00580 curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
00581
00582 if (!curs.movePosition(QTextCursor::StartOfWord))
00583 return;
00584 const int wordStartPos = curs.position();
00585
00586 const int blockPos = curs.block().position();
00587 const QPointF blockCoordinates = doc->documentLayout()->blockBoundingRect(curs.block()).topLeft();
00588
00589 QTextLine line = currentTextLine(curs);
00590 if (!line.isValid())
00591 return;
00592
00593 const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
00594
00595 if (!curs.movePosition(QTextCursor::EndOfWord))
00596 return;
00597 const int wordEndPos = curs.position();
00598
00599 const QTextLine otherLine = currentTextLine(curs);
00600 if (otherLine.textStart() != line.textStart()
00601 || wordEndPos == wordStartPos)
00602 return;
00603
00604 const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
00605
00606 if (mouseXPosition < wordStartX || mouseXPosition > wordEndX)
00607 return;
00608
00609
00610
00611 if (suggestedNewPosition < selectedWordOnDoubleClick.position())
00612 cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
00613 else
00614 cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
00615
00616 const qreal differenceToStart = mouseXPosition - wordStartX;
00617 const qreal differenceToEnd = wordEndX - mouseXPosition;
00618
00619 if (differenceToStart < differenceToEnd)
00620 setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
00621 else
00622 setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
00623 }
00624
00625 void QTextControlPrivate::extendLinewiseSelection(int suggestedNewPosition)
00626 {
00627 Q_Q(QTextControl);
00628
00629
00630 if (suggestedNewPosition >= selectedLineOnDoubleClick.selectionStart()
00631 && suggestedNewPosition <= selectedLineOnDoubleClick.selectionEnd()) {
00632 q->setTextCursor(selectedLineOnDoubleClick);
00633 return;
00634 }
00635
00636 if (suggestedNewPosition < selectedLineOnDoubleClick.position()) {
00637 cursor.setPosition(selectedLineOnDoubleClick.selectionEnd());
00638 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
00639 cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
00640 } else {
00641 cursor.setPosition(selectedLineOnDoubleClick.selectionStart());
00642 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
00643 cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
00644 }
00645 }
00646
00647 void QTextControlPrivate::_q_deleteSelected()
00648 {
00649 if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
00650 return;
00651 cursor.removeSelectedText();
00652 }
00653
00654 void QTextControl::undo()
00655 {
00656 Q_D(QTextControl);
00657 d->doc->undo(&d->cursor);
00658 ensureCursorVisible();
00659 }
00660
00661 void QTextControl::redo()
00662 {
00663 Q_D(QTextControl);
00664 d->doc->redo(&d->cursor);
00665 ensureCursorVisible();
00666 }
00667
00668 QTextControl::QTextControl(QObject *parent)
00669 : QObject(*new QTextControlPrivate, parent)
00670 {
00671 Q_D(QTextControl);
00672 d->setContent();
00673 }
00674
00675 QTextControl::QTextControl(const QString &text, QObject *parent)
00676 : QObject(*new QTextControlPrivate, parent)
00677 {
00678 Q_D(QTextControl);
00679 d->setContent(Qt::RichText, text);
00680 }
00681
00682 QTextControl::QTextControl(QTextDocument *doc, QObject *parent)
00683 : QObject(*new QTextControlPrivate, parent)
00684 {
00685 Q_D(QTextControl);
00686 d->setContent(Qt::RichText, QString(), doc);
00687 }
00688
00689 QTextControl::~QTextControl()
00690 {
00691 }
00692
00693 void QTextControl::setDocument(QTextDocument *document)
00694 {
00695 Q_D(QTextControl);
00696 if (d->doc == document)
00697 return;
00698
00699 d->doc->disconnect(this);
00700 d->doc->documentLayout()->disconnect(this);
00701 d->doc->documentLayout()->setPaintDevice(0);
00702
00703 if (d->doc->parent() == this)
00704 delete d->doc;
00705
00706 d->doc = 0;
00707 d->setContent(Qt::RichText, QString(), document);
00708 }
00709
00710 QTextDocument *QTextControl::document() const
00711 {
00712 Q_D(const QTextControl);
00713 return d->doc;
00714 }
00715
00716 void QTextControl::setTextCursor(const QTextCursor &cursor)
00717 {
00718 Q_D(QTextControl);
00719 const bool posChanged = cursor.position() != d->cursor.position();
00720 const QTextCursor oldSelection = d->cursor;
00721 d->cursor = cursor;
00722 d->_q_updateCurrentCharFormatAndSelection();
00723 ensureCursorVisible();
00724 d->repaintOldAndNewSelection(oldSelection);
00725 if (posChanged)
00726 emit cursorPositionChanged();
00727 }
00728
00729 QTextCursor QTextControl::textCursor() const
00730 {
00731 Q_D(const QTextControl);
00732 return d->cursor;
00733 }
00734
00735 #ifndef QT_NO_CLIPBOARD
00736
00737 void QTextControl::cut()
00738 {
00739 Q_D(QTextControl);
00740 if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
00741 return;
00742 copy();
00743 d->cursor.removeSelectedText();
00744 }
00745
00746 void QTextControl::copy()
00747 {
00748 Q_D(QTextControl);
00749 if (!d->cursor.hasSelection())
00750 return;
00751 QMimeData *data = createMimeDataFromSelection();
00752 QApplication::clipboard()->setMimeData(data);
00753 }
00754
00755 void QTextControl::paste()
00756 {
00757 const QMimeData *md = QApplication::clipboard()->mimeData();
00758 if (md)
00759 insertFromMimeData(md);
00760 }
00761 #endif
00762
00763 void QTextControl::clear()
00764 {
00765 Q_D(QTextControl);
00766
00767 d->setContent();
00768 }
00769
00770
00771 void QTextControl::selectAll()
00772 {
00773 Q_D(QTextControl);
00774 d->cursor.select(QTextCursor::Document);
00775 d->selectionChanged();
00776 emit updateRequest(QRectF(QPointF(), d->doc->documentLayout()->documentSize()));
00777 }
00778
00779 void QTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
00780 {
00781 QMatrix m;
00782 m.translate(coordinateOffset.x(), coordinateOffset.y());
00783 processEvent(e, m, contextWidget);
00784 }
00785
00786 void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget)
00787 {
00788
00789 Q_D(QTextControl);
00790 if (d->interactionFlags & Qt::NoTextInteraction)
00791 return;
00792
00793 d->contextWidget = contextWidget;
00794
00795 if (!d->contextWidget) {
00796 switch (e->type()) {
00797 #ifndef QT_NO_GRAPHICSVIEW
00798 case QEvent::GraphicsSceneMouseMove:
00799 case QEvent::GraphicsSceneMousePress:
00800 case QEvent::GraphicsSceneMouseRelease:
00801 case QEvent::GraphicsSceneMouseDoubleClick:
00802 case QEvent::GraphicsSceneContextMenu:
00803 case QEvent::GraphicsSceneHoverEnter:
00804 case QEvent::GraphicsSceneHoverMove:
00805 case QEvent::GraphicsSceneHoverLeave:
00806 case QEvent::GraphicsSceneHelp:
00807 case QEvent::GraphicsSceneDragEnter:
00808 case QEvent::GraphicsSceneDragMove:
00809 case QEvent::GraphicsSceneDragLeave:
00810 case QEvent::GraphicsSceneDrop: {
00811 QGraphicsSceneEvent *ev = static_cast<QGraphicsSceneEvent *>(e);
00812 d->contextWidget = ev->widget();
00813 break;
00814 }
00815 #endif // QT_NO_GRAPHICSVIEW
00816 default: break;
00817 };
00818 }
00819
00820 switch (e->type()) {
00821 case QEvent::KeyPress:
00822 d->keyPressEvent(static_cast<QKeyEvent *>(e));
00823 break;
00824 case QEvent::MouseButtonPress: {
00825 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
00826 d->mousePressEvent(ev->button(), matrix.map(ev->pos()), ev->modifiers(),
00827 ev->buttons(), ev->globalPos());
00828 break; }
00829 case QEvent::MouseMove: {
00830 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
00831 d->mouseMoveEvent(ev->buttons(), matrix.map(ev->pos()));
00832 break; }
00833 case QEvent::MouseButtonRelease: {
00834 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
00835 d->mouseReleaseEvent(ev->button(), matrix.map(ev->pos()));
00836 break; }
00837 case QEvent::MouseButtonDblClick: {
00838 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
00839 d->mouseDoubleClickEvent(e, ev->button(), matrix.map(ev->pos()));
00840 break; }
00841 case QEvent::InputMethod:
00842 d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
00843 break;
00844 case QEvent::ContextMenu: {
00845 QContextMenuEvent *ev = static_cast<QContextMenuEvent *>(e);
00846 d->contextMenuEvent(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
00847 break; }
00848
00849 case QEvent::FocusIn:
00850 case QEvent::FocusOut:
00851 d->focusEvent(static_cast<QFocusEvent *>(e));
00852 break;
00853
00854 case QEvent::EnabledChange:
00855 d->isEnabled = e->isAccepted();
00856 break;
00857
00858 #ifndef QT_NO_DRAGANDDROP
00859 case QEvent::DragEnter: {
00860 QDragEnterEvent *ev = static_cast<QDragEnterEvent *>(e);
00861 if (d->dragEnterEvent(e, ev->mimeData()))
00862 ev->acceptProposedAction();
00863 break;
00864 }
00865 case QEvent::DragLeave:
00866 d->dragLeaveEvent();
00867 break;
00868 case QEvent::DragMove: {
00869 QDragMoveEvent *ev = static_cast<QDragMoveEvent *>(e);
00870 if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
00871 ev->acceptProposedAction();
00872 break;
00873 }
00874 case QEvent::Drop: {
00875 QDropEvent *ev = static_cast<QDropEvent *>(e);
00876 if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->proposedAction(), ev->source()))
00877 ev->acceptProposedAction();
00878 break;
00879 }
00880 #endif
00881
00882 #ifndef QT_NO_GRAPHICSVIEW
00883 case QEvent::GraphicsSceneMousePress: {
00884 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
00885 d->mousePressEvent(ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
00886 ev->screenPos());
00887 break; }
00888 case QEvent::GraphicsSceneMouseMove: {
00889 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
00890 d->mouseMoveEvent(ev->buttons(), matrix.map(ev->pos()));
00891 break; }
00892 case QEvent::GraphicsSceneMouseRelease: {
00893 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
00894 d->mouseReleaseEvent(ev->button(), matrix.map(ev->pos()));
00895 break; }
00896 case QEvent::GraphicsSceneMouseDoubleClick: {
00897 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
00898 d->mouseDoubleClickEvent(e, ev->button(), matrix.map(ev->pos()));
00899 break; }
00900 case QEvent::GraphicsSceneContextMenu: {
00901 QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e);
00902 d->contextMenuEvent(ev->screenPos(), matrix.map(ev->pos()), contextWidget);
00903 break; }
00904
00905 case QEvent::GraphicsSceneHoverMove: {
00906 QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e);
00907 d->mouseMoveEvent(Qt::NoButton, matrix.map(ev->pos()));
00908 break; }
00909
00910 case QEvent::GraphicsSceneDragEnter: {
00911 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
00912 if (d->dragEnterEvent(e, ev->mimeData()))
00913 ev->acceptProposedAction();
00914 break; }
00915 case QEvent::GraphicsSceneDragLeave:
00916 d->dragLeaveEvent();
00917 break;
00918 case QEvent::GraphicsSceneDragMove: {
00919 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
00920 if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
00921 ev->acceptProposedAction();
00922 break; }
00923 case QEvent::GraphicsSceneDrop: {
00924 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
00925 if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->proposedAction(), ev->source()))
00926 ev->acceptProposedAction();
00927 break; }
00928 #endif // QT_NO_GRAPHICSVIEW
00929
00930 case QEvent::ShortcutOverride:
00931 if (d->interactionFlags & Qt::TextEditable) {
00932 QKeyEvent* ke = static_cast<QKeyEvent *>(e);
00933 if (ke->modifiers() == Qt::NoModifier
00934 || ke->modifiers() == Qt::ShiftModifier
00935 || ke->modifiers() == Qt::KeypadModifier) {
00936 if (ke->key() < Qt::Key_Escape) {
00937 ke->accept();
00938 } else {
00939 switch (ke->key()) {
00940 case Qt::Key_Return:
00941 case Qt::Key_Enter:
00942 case Qt::Key_Delete:
00943 case Qt::Key_Home:
00944 case Qt::Key_End:
00945 case Qt::Key_Backspace:
00946 case Qt::Key_Left:
00947 case Qt::Key_Right:
00948 ke->accept();
00949 default:
00950 break;
00951 }
00952 }
00953 } else if (ke->modifiers() & Qt::ControlModifier) {
00954 switch (ke->key()) {
00955 case Qt::Key_C:
00956 case Qt::Key_V:
00957 case Qt::Key_X:
00958 case Qt::Key_Y:
00959 case Qt::Key_Z:
00960 case Qt::Key_Left:
00961 case Qt::Key_Right:
00962 case Qt::Key_Up:
00963 case Qt::Key_Down:
00964 case Qt::Key_Home:
00965 case Qt::Key_End:
00966 #if !defined(Q_WS_MAC)
00967 case Qt::Key_Insert:
00968 case Qt::Key_Delete:
00969 #endif
00970 ke->accept();
00971 default:
00972 break;
00973 }
00974 }
00975 }
00976
00977 default:
00978 break;
00979 }
00980 }
00981
00982 bool QTextControl::event(QEvent *e)
00983 {
00984 return QObject::event(e);
00985 }
00986
00987 void QTextControl::timerEvent(QTimerEvent *e)
00988 {
00989 Q_D(QTextControl);
00990 if (e->timerId() == d->cursorBlinkTimer.timerId()) {
00991 d->cursorOn = !d->cursorOn;
00992
00993 if (d->cursor.hasSelection())
00994 d->cursorOn &= (QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected)
00995 != 0);
00996
00997 d->repaintCursor();
00998 } else if (e->timerId() == d->trippleClickTimer.timerId()) {
00999 d->trippleClickTimer.stop();
01000 }
01001 }
01002
01003 void QTextControl::setPlainText(const QString &text)
01004 {
01005 Q_D(QTextControl);
01006 d->setContent(Qt::PlainText, text);
01007 }
01008
01009 void QTextControl::setHtml(const QString &text)
01010 {
01011 Q_D(QTextControl);
01012 d->setContent(Qt::RichText, text);
01013 }
01014
01015 void QTextControlPrivate::keyPressEvent(QKeyEvent *e)
01016 {
01017 Q_Q(QTextControl);
01018 #ifndef QT_NO_SHORTCUT
01019 if (e == QKeySequence::SelectAll) {
01020 e->accept();
01021 q->selectAll();
01022 return;
01023 }
01024 #ifndef QT_NO_CLIPBOARD
01025 else if (e == QKeySequence::Copy) {
01026 e->accept();
01027 q->copy();
01028 return;
01029 }
01030 #endif
01031 #endif // QT_NO_SHORTCUT
01032
01033 if (interactionFlags & Qt::TextSelectableByKeyboard
01034 && cursorMoveKeyEvent(e))
01035 goto accept;
01036
01037 if (interactionFlags & Qt::LinksAccessibleByKeyboard) {
01038 if ((e->key() == Qt::Key_Return
01039 || e->key() == Qt::Key_Enter
01040 #ifdef QT_KEYPAD_NAVIGATION
01041 || e->key() == Qt::Key_Select
01042 #endif
01043 )
01044 && cursor.hasSelection()) {
01045
01046 e->accept();
01047
01048 QTextCursor tmp = cursor;
01049 if (tmp.selectionStart() != tmp.position())
01050 tmp.setPosition(tmp.selectionStart());
01051 tmp.movePosition(QTextCursor::NextCharacter);
01052 const QString href = tmp.charFormat().anchorHref();
01053 if (!href.isEmpty()) {
01054 #ifndef QT_NO_DESKTOPSERVICES
01055 if (openExternalLinks)
01056 QDesktopServices::openUrl(href);
01057 else
01058 #endif
01059 emit q->linkActivated(href);
01060 }
01061 return;
01062 }
01063 }
01064
01065 if (!(interactionFlags & Qt::TextEditable)) {
01066 e->ignore();
01067 return;
01068 }
01069
01070 if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
01071 QTextBlockFormat fmt;
01072 fmt.setLayoutDirection((e->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
01073 cursor.mergeBlockFormat(fmt);
01074 goto accept;
01075 }
01076
01077
01078
01079
01080
01081 repaintSelection();
01082
01083 if (e->key() == Qt::Key_Backspace && !e->modifiers()) {
01084 QTextBlockFormat blockFmt = cursor.blockFormat();
01085 QTextList *list = cursor.currentList();
01086 if (list && cursor.atBlockStart()) {
01087 list->remove(cursor.block());
01088 } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
01089 blockFmt.setIndent(blockFmt.indent() - 1);
01090 cursor.setBlockFormat(blockFmt);
01091 } else {
01092 cursor.deletePreviousChar();
01093 }
01094 goto accept;
01095 } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
01096 if (e->modifiers() & Qt::ControlModifier)
01097 cursor.insertText(QString(QChar::LineSeparator));
01098 else
01099 cursor.insertBlock();
01100 e->accept();
01101 goto accept;
01102 }
01103
01104 if (false) {
01105 }
01106 #ifndef QT_NO_SHORTCUT
01107 else if (e == QKeySequence::Undo) {
01108 q->undo();
01109 }
01110 else if (e == QKeySequence::Redo) {
01111 q->redo();
01112 }
01113 #ifndef QT_NO_CLIPBOARD
01114 else if (e == QKeySequence::Cut) {
01115 q->cut();
01116 }
01117 else if (e == QKeySequence::Paste) {
01118 q->paste();
01119 }
01120 #endif
01121 else if (e == QKeySequence::Delete) {
01122 cursor.deleteChar();
01123 }
01124 else if (e == QKeySequence::DeleteEndOfWord) {
01125 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
01126 cursor.deleteChar();
01127 }
01128 else if (e == QKeySequence::DeleteStartOfWord) {
01129 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
01130 cursor.deleteChar();
01131 }
01132 else if (e == QKeySequence::DeleteEndOfLine) {
01133 QTextBlock block = cursor.block();
01134 if (cursor.position() == block.position() + block.length() - 2)
01135 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
01136 else
01137 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
01138 cursor.deleteChar();
01139 }
01140 #endif // QT_NO_SHORTCUT
01141 else {
01142 goto process;
01143 }
01144 goto accept;
01145
01146 process:
01147 {
01148 QString text = e->text();
01149 if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
01150 if (overwriteMode
01151
01152
01153 && !cursor.hasSelection()
01154 && !cursor.atBlockEnd())
01155 cursor.deleteChar();
01156
01157 cursor.insertText(text);
01158 selectionChanged();
01159 } else {
01160 e->ignore();
01161 return;
01162 }
01163 }
01164
01165 accept:
01166
01167 e->accept();
01168 cursorOn = true;
01169
01170 q->ensureCursorVisible();
01171
01172 updateCurrentCharFormat();
01173 }
01174
01175 QVariant QTextControl::loadResource(int type, const QUrl &name)
01176 {
01177 #ifdef QT_NO_TEXTEDIT
01178 Q_UNUSED(type);
01179 Q_UNUSED(name);
01180 #else
01181 if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(parent()))
01182 return textEdit->loadResource(type, name);
01183 #endif
01184 return QVariant();
01185 }
01186
01187 QRectF QTextControlPrivate::rectForPosition(int position) const
01188 {
01189 const QTextBlock block = doc->findBlock(position);
01190 if (!block.isValid())
01191 return QRectF();
01192 const QAbstractTextDocumentLayout *docLayout = doc->documentLayout();
01193 const QTextLayout *layout = block.layout();
01194 const QPointF layoutPos = docLayout->blockBoundingRect(block).topLeft();
01195 int relativePos = position - block.position();
01196 if (preeditCursor != 0) {
01197 int preeditPos = layout->preeditAreaPosition();
01198 if (relativePos == preeditPos)
01199 relativePos += preeditCursor;
01200 else if (relativePos > preeditPos)
01201 relativePos += layout->preeditAreaText().length();
01202 }
01203 QTextLine line = layout->lineForTextPosition(relativePos);
01204
01205 int cursorWidth;
01206 {
01207 bool ok = false;
01208 #ifndef QT_NO_PROPERTIES
01209 cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
01210 #endif
01211 if (!ok)
01212 cursorWidth = 1;
01213 }
01214
01215 QRectF r;
01216
01217 if (line.isValid())
01218 r = QRectF(layoutPos.x() + line.cursorToX(relativePos) - 5 - cursorWidth, layoutPos.y() + line.y(),
01219 2 * cursorWidth + 10, line.ascent() + line.descent()+1.);
01220 else
01221 r = QRectF(layoutPos.x() - 5 - cursorWidth, layoutPos.y(), 2 * cursorWidth + 10, 10);
01222
01223 return r;
01224 }
01225
01226 QRectF QTextControlPrivate::selectionRect(const QTextCursor &cursor) const
01227 {
01228 QRectF r = rectForPosition(cursor.selectionStart());
01229
01230 if (cursor.hasComplexSelection() && cursor.currentTable()) {
01231 QTextTable *table = cursor.currentTable();
01232
01233 r = doc->documentLayout()->frameBoundingRect(table);
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 } else if (cursor.hasSelection()) {
01276 const int position = cursor.selectionStart();
01277 const int anchor = cursor.selectionEnd();
01278 const QTextBlock posBlock = doc->findBlock(position);
01279 const QTextBlock anchorBlock = doc->findBlock(anchor);
01280 if (posBlock == anchorBlock && posBlock.layout()->lineCount()) {
01281 const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
01282 const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
01283
01284 const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
01285 const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
01286 r = QRectF();
01287 for (int i = firstLine; i <= lastLine; ++i) {
01288 r |= posBlock.layout()->lineAt(i).rect().toRect();
01289 }
01290 r.translate(doc->documentLayout()->blockBoundingRect(posBlock).topLeft());
01291 } else {
01292 QRectF anchorRect = rectForPosition(cursor.selectionEnd());
01293 r |= anchorRect;
01294 QRectF frameRect(doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
01295 r.setLeft(frameRect.left());
01296 r.setRight(frameRect.right());
01297 }
01298 if (r.isValid())
01299 r.adjust(-1, -1, 1, 1);
01300 }
01301
01302 return r;
01303 }
01304
01305 void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
01306 Qt::MouseButtons buttons, const QPoint &globalPos)
01307 {
01308 Q_Q(QTextControl);
01309 cursorIsFocusIndicator = false;
01310
01311 if (interactionFlags & Qt::LinksAccessibleByMouse) {
01312 anchorOnMousePress = q->anchorAt(pos);
01313 }
01314 if (!(button & Qt::LeftButton))
01315 return;
01316
01317 if (!((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable)))
01318 return;
01319
01320 const QTextCursor oldSelection = cursor;
01321 const int oldCursorPos = cursor.position();
01322
01323 mousePressed = true;
01324 #ifndef QT_NO_DRAGANDDROP
01325 mightStartDrag = false;
01326 #endif
01327
01328 if (trippleClickTimer.isActive()
01329 && ((pos - trippleClickPoint).toPoint().manhattanLength() < QApplication::startDragDistance())) {
01330
01331 cursor.movePosition(QTextCursor::StartOfBlock);
01332 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
01333
01334 trippleClickTimer.stop();
01335 } else {
01336 int cursorPos = doc->documentLayout()->hitTest(pos, Qt::FuzzyHit);
01337 if (cursorPos == -1)
01338 return;
01339
01340 #if !defined(QT_NO_IM)
01341 QTextLayout *layout = cursor.block().layout();
01342 if (contextWidget && layout && !layout->preeditAreaText().isEmpty()) {
01343 QInputContext *ctx = contextWidget->inputContext();
01344 if (!ctx && contextWidget->parentWidget())
01345 ctx = contextWidget->parentWidget()->inputContext();
01346 if (ctx) {
01347 QMouseEvent ev(QEvent::MouseButtonPress, contextWidget->mapFromGlobal(globalPos), globalPos,
01348 button, buttons, modifiers);
01349 ctx->mouseHandler(cursorPos - cursor.position(), &ev);
01350 }
01351 if (!layout->preeditAreaText().isEmpty())
01352 return;
01353 }
01354 #endif
01355 if (modifiers == Qt::ShiftModifier) {
01356 if (selectedWordOnDoubleClick.hasSelection())
01357 extendWordwiseSelection(cursorPos, pos.x());
01358 else if (selectedLineOnDoubleClick.hasSelection())
01359 extendLinewiseSelection(cursorPos);
01360 else
01361 setCursorPosition(cursorPos, QTextCursor::KeepAnchor);
01362 } else {
01363
01364 if (cursor.hasSelection()
01365 && cursorPos >= cursor.selectionStart()
01366 && cursorPos <= cursor.selectionEnd()
01367 && doc->documentLayout()->hitTest(pos, Qt::ExactHit) != -1) {
01368 #ifndef QT_NO_DRAGANDDROP
01369 mightStartDrag = true;
01370 dragStartPos = pos.toPoint();
01371 #endif
01372 return;
01373 }
01374
01375 setCursorPosition(cursorPos);
01376 }
01377 }
01378
01379 if (interactionFlags & Qt::TextEditable) {
01380 q->ensureCursorVisible();
01381 if (cursor.position() != oldCursorPos)
01382 emit q->cursorPositionChanged();
01383 _q_updateCurrentCharFormatAndSelection();
01384 } else {
01385 if (cursor.position() != oldCursorPos)
01386 emit q->cursorPositionChanged();
01387 selectionChanged();
01388 }
01389 repaintOldAndNewSelection(oldSelection);
01390 hadSelectionOnMousePress = cursor.hasSelection();
01391 }
01392
01393 void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF &mousePos)
01394 {
01395 Q_Q(QTextControl);
01396
01397 if (interactionFlags & Qt::LinksAccessibleByMouse) {
01398 QString anchor = q->anchorAt(mousePos);
01399 if (anchor != highlightedAnchor) {
01400 highlightedAnchor = anchor;
01401 emit q->linkHovered(anchor);
01402 }
01403 }
01404
01405 if (!(buttons & Qt::LeftButton))
01406 return;
01407
01408 if (!((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable)))
01409 return;
01410
01411 if (!(mousePressed
01412 || selectedWordOnDoubleClick.hasSelection()
01413 || selectedLineOnDoubleClick.hasSelection()))
01414 return;
01415
01416 const QTextCursor oldSelection = cursor;
01417 const int oldCursorPos = cursor.position();
01418
01419 if (mightStartDrag) {
01420 if ((mousePos.toPoint() - dragStartPos).manhattanLength() > QApplication::startDragDistance())
01421 startDrag();
01422 return;
01423 }
01424 const qreal mouseX = qreal(mousePos.x());
01425
01426 #if !defined(QT_NO_IM)
01427 QTextLayout *layout = cursor.block().layout();
01428 if (layout && !layout->preeditAreaText().isEmpty())
01429 return;
01430 #endif
01431
01432 int newCursorPos = doc->documentLayout()->hitTest(mousePos, Qt::FuzzyHit);
01433 if (newCursorPos == -1)
01434 return;
01435
01436 if (selectedWordOnDoubleClick.hasSelection())
01437 extendWordwiseSelection(newCursorPos, mouseX);
01438 else if (selectedLineOnDoubleClick.hasSelection())
01439 extendLinewiseSelection(newCursorPos);
01440 else
01441 setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
01442
01443 if (interactionFlags & Qt::TextEditable) {
01444 q->ensureCursorVisible();
01445 if (cursor.position() != oldCursorPos)
01446 emit q->cursorPositionChanged();
01447 _q_updateCurrentCharFormatAndSelection();
01448 } else {
01449 emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1)));
01450 if (cursor.position() != oldCursorPos)
01451 emit q->cursorPositionChanged();
01452 selectionChanged();
01453 }
01454 repaintOldAndNewSelection(oldSelection);
01455 }
01456
01457 void QTextControlPrivate::mouseReleaseEvent(Qt::MouseButton button, const QPointF &pos)
01458 {
01459 Q_Q(QTextControl);
01460
01461 const QTextCursor oldSelection = cursor;
01462
01463 #ifndef QT_NO_DRAGANDDROP
01464 if (mightStartDrag) {
01465 mousePressed = false;
01466 setCursorPosition(pos);
01467 cursor.clearSelection();
01468 selectionChanged();
01469 }
01470 #endif
01471 if (mousePressed) {
01472 mousePressed = false;
01473 #ifndef QT_NO_CLIPBOARD
01474 if (interactionFlags & Qt::TextSelectableByMouse)
01475 setClipboardSelection();
01476 } else if (button == Qt::MidButton
01477 && (interactionFlags & Qt::TextEditable)
01478 && QApplication::clipboard()->supportsSelection()) {
01479 setCursorPosition(pos);
01480 const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Selection);
01481 if (md)
01482 q->insertFromMimeData(md);
01483 #endif
01484 }
01485
01486 repaintOldAndNewSelection(oldSelection);
01487
01488 if (interactionFlags & Qt::LinksAccessibleByMouse) {
01489 if (!(button & Qt::LeftButton))
01490 return;
01491
01492 const QString anchor = q->anchorAt(pos);
01493
01494 if (anchor.isEmpty())
01495 return;
01496
01497 if (!cursor.hasSelection()
01498 || (anchor == anchorOnMousePress && hadSelectionOnMousePress))
01499 #ifndef QT_NO_DESKTOPSERVICES
01500 if (openExternalLinks)
01501 QDesktopServices::openUrl(anchor);
01502 else
01503 #endif
01504 emit q->linkActivated(anchor);
01505 }
01506 }
01507
01508 void QTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos)
01509 {
01510 Q_Q(QTextControl);
01511 if (button != Qt::LeftButton
01512 || !(interactionFlags & Qt::TextSelectableByMouse)) {
01513 e->ignore();
01514 return;
01515 }
01516 #if !defined(QT_NO_IM)
01517 QTextLayout *layout = cursor.block().layout();
01518 if (layout && !layout->preeditAreaText().isEmpty())
01519 return;
01520 #endif
01521
01522 #ifndef QT_NO_DRAGANDDROP
01523 mightStartDrag = false;
01524 #endif
01525 const QTextCursor oldSelection = cursor;
01526 setCursorPosition(pos);
01527 QTextLine line = currentTextLine(cursor);
01528 if (line.isValid() && line.textLength()) {
01529 cursor.select(QTextCursor::WordUnderCursor);
01530 selectionChanged();
01531 #ifndef QT_NO_CLIPBOARD
01532 setClipboardSelection();
01533 #endif
01534 }
01535 repaintOldAndNewSelection(oldSelection);
01536
01537 selectedWordOnDoubleClick = cursor;
01538
01539 trippleClickPoint = pos;
01540 trippleClickTimer.start(qApp->doubleClickInterval(), q);
01541 }
01542
01543 void QTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
01544 {
01545 #ifdef QT_NO_CONTEXTMENU
01546 Q_UNUSED(screenPos);
01547 Q_UNUSED(docPos);
01548 #else
01549 Q_Q(QTextControl);
01550 if (!hasFocus)
01551 return;
01552 QMenu *menu = q->createStandardContextMenu(docPos, contextWidget);
01553 if (!menu)
01554 return;
01555 menu->exec(screenPos);
01556 delete menu;
01557 #endif
01558 }
01559
01560 bool QTextControlPrivate::dragEnterEvent(QEvent *e, const QMimeData *mimeData)
01561 {
01562 Q_Q(QTextControl);
01563 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
01564 e->ignore();
01565 return false;
01566 }
01567
01568 dndFeedbackCursor = QTextCursor();
01569
01570 return true;
01571 }
01572
01573 void QTextControlPrivate::dragLeaveEvent()
01574 {
01575 Q_Q(QTextControl);
01576
01577 const QRectF crect = q->cursorRect(dndFeedbackCursor);
01578 dndFeedbackCursor = QTextCursor();
01579
01580 if (crect.isValid())
01581 emit q->updateRequest(crect);
01582 }
01583
01584 bool QTextControlPrivate::dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos)
01585 {
01586 Q_Q(QTextControl);
01587 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
01588 e->ignore();
01589 return false;
01590 }
01591
01592 const int cursorPos = doc->documentLayout()->hitTest(pos, Qt::FuzzyHit);
01593 if (cursorPos != -1) {
01594 QRectF crect = q->cursorRect(dndFeedbackCursor);
01595 if (crect.isValid())
01596 emit q->updateRequest(crect);
01597
01598 dndFeedbackCursor = cursor;
01599 dndFeedbackCursor.setPosition(cursorPos);
01600
01601 crect = q->cursorRect(dndFeedbackCursor);
01602 emit q->updateRequest(crect);
01603 }
01604
01605 return true;
01606 }
01607
01608 bool QTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QWidget *source)
01609 {
01610 Q_Q(QTextControl);
01611 dndFeedbackCursor = QTextCursor();
01612
01613 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData))
01614 return false;
01615
01616 repaintSelection();
01617
01618 QTextCursor insertionCursor = q->cursorForPosition(pos);
01619 insertionCursor.beginEditBlock();
01620
01621 if (dropAction == Qt::MoveAction && source == contextWidget)
01622 cursor.removeSelectedText();
01623
01624 cursor = insertionCursor;
01625 q->insertFromMimeData(mimeData);
01626 insertionCursor.endEditBlock();
01627 q->ensureCursorVisible();
01628 return true;
01629 }
01630
01631 void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
01632 {
01633 if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
01634 e->ignore();
01635 return;
01636 }
01637 cursor.beginEditBlock();
01638
01639 cursor.removeSelectedText();
01640
01641
01642 if (!e->commitString().isEmpty() || e->replacementLength()) {
01643 QTextCursor c = cursor;
01644 c.setPosition(c.position() + e->replacementStart());
01645 c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
01646 c.insertText(e->commitString());
01647 }
01648
01649 QTextBlock block = cursor.block();
01650 QTextLayout *layout = block.layout();
01651 layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
01652 QList<QTextLayout::FormatRange> overrides;
01653 preeditCursor = e->preeditString().length();
01654 hideCursor = false;
01655 for (int i = 0; i < e->attributes().size(); ++i) {
01656 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
01657 if (a.type == QInputMethodEvent::Cursor) {
01658 preeditCursor = a.start;
01659 hideCursor = !a.length;
01660 } else if (a.type == QInputMethodEvent::TextFormat) {
01661 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
01662 if (f.isValid()) {
01663 QTextLayout::FormatRange o;
01664 o.start = a.start + cursor.position() - block.position();
01665 o.length = a.length;
01666 o.format = f;
01667 overrides.append(o);
01668 }
01669 }
01670 }
01671 layout->setAdditionalFormats(overrides);
01672 cursor.endEditBlock();
01673 }
01674
01675 QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
01676 {
01677 Q_D(const QTextControl);
01678 QTextBlock block = d->cursor.block();
01679 switch(property) {
01680 case Qt::ImMicroFocus:
01681 return cursorRect();
01682 case Qt::ImFont:
01683 return QVariant(d->cursor.charFormat().font());
01684 case Qt::ImCursorPosition:
01685 return QVariant(d->cursor.position() - block.position());
01686 case Qt::ImSurroundingText:
01687 return QVariant(block.text());
01688 case Qt::ImCurrentSelection:
01689 return QVariant(d->cursor.selectedText());
01690 default:
01691 return QVariant();
01692 }
01693 }
01694
01695 void QTextControl::setFocus(bool focus, Qt::FocusReason reason)
01696 {
01697 QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
01698 reason);
01699 processEvent(&ev);
01700 }
01701
01702 void QTextControlPrivate::focusEvent(QFocusEvent *e)
01703 {
01704 emit q_func()->updateRequest(selectionRect());
01705 if (e->gotFocus()) {
01706 cursorOn = (interactionFlags & Qt::TextSelectableByKeyboard);
01707 if (interactionFlags & Qt::TextEditable) {
01708 setBlinkingCursorEnabled(true);
01709 }
01710 } else {
01711 setBlinkingCursorEnabled(false);
01712
01713 if (interactionFlags & Qt::LinksAccessibleByKeyboard
01714 && e->reason() != Qt::ActiveWindowFocusReason
01715 && e->reason() != Qt::PopupFocusReason
01716 && cursor.hasSelection()) {
01717 cursor.clearSelection();
01718 }
01719 }
01720 hasFocus = e->gotFocus();
01721 }
01722
01723 #ifndef QT_NO_CONTEXTMENU
01724 QMenu *QTextControl::createStandardContextMenu(const QPointF &pos, QWidget *parent)
01725 {
01726 Q_D(QTextControl);
01727
01728 const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
01729
01730 d->linkToCopy = QString();
01731 if (!pos.isNull())
01732 d->linkToCopy = anchorAt(pos);
01733
01734 if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
01735 return 0;
01736
01737 QMenu *menu = new QMenu(parent);
01738 QAction *a;
01739
01740 if (d->interactionFlags & Qt::TextEditable) {
01741 a = menu->addAction(tr("&Undo") + ACCEL_KEY(Z), this, SLOT(undo()));
01742 a->setEnabled(d->doc->isUndoAvailable());
01743 a = menu->addAction(tr("&Redo") + ACCEL_KEY(Y), this, SLOT(redo()));
01744 a->setEnabled(d->doc->isRedoAvailable());
01745 menu->addSeparator();
01746
01747 a = menu->addAction(tr("Cu&t") + ACCEL_KEY(X), this, SLOT(cut()));
01748 a->setEnabled(d->cursor.hasSelection());
01749 }
01750
01751 if (showTextSelectionActions) {
01752 a = menu->addAction(tr("&Copy") + ACCEL_KEY(C), this, SLOT(copy()));
01753 a->setEnabled(d->cursor.hasSelection());
01754 }
01755
01756 if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
01757 || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
01758
01759 a = menu->addAction(tr("Copy &Link Location"), this, SLOT(_q_copyLink()));
01760 a->setEnabled(!d->linkToCopy.isEmpty());
01761 }
01762
01763 if (d->interactionFlags & Qt::TextEditable) {
01764 #if !defined(QT_NO_CLIPBOARD)
01765 a = menu->addAction(tr("&Paste") + ACCEL_KEY(V), this, SLOT(paste()));
01766 a->setEnabled(canPaste());
01767 #endif
01768 a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected()));
01769 a->setEnabled(d->cursor.hasSelection());
01770 }
01771
01772
01773 if (showTextSelectionActions) {
01774 menu->addSeparator();
01775 a = menu->addAction(tr("Select All") + ACCEL_KEY(A), this, SLOT(selectAll()));
01776 a->setEnabled(!d->doc->isEmpty());
01777 }
01778
01779 if (d->interactionFlags & Qt::TextEditable) {
01780 menu->addSeparator();
01781 QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, menu);
01782 menu->addMenu(ctrlCharacterMenu);
01783 }
01784
01785 return menu;
01786 }
01787 #endif // QT_NO_CONTEXTMENU
01788
01789 QTextCursor QTextControl::cursorForPosition(const QPointF &pos) const
01790 {
01791 Q_D(const QTextControl);
01792 int cursorPos = d->doc->documentLayout()->hitTest(pos, Qt::FuzzyHit);
01793 if (cursorPos == -1)
01794 cursorPos = 0;
01795 QTextCursor c(d->doc);
01796 c.setPosition(cursorPos);
01797 return c;
01798 }
01799
01800 QRectF QTextControl::cursorRect(const QTextCursor &cursor) const
01801 {
01802 Q_D(const QTextControl);
01803 if (cursor.isNull())
01804 return QRectF();
01805
01806 return d->rectForPosition(cursor.position());
01807 }
01808
01809 QRectF QTextControl::cursorRect() const
01810 {
01811 Q_D(const QTextControl);
01812 return cursorRect(d->cursor);
01813 }
01814
01815 QString QTextControl::anchorAt(const QPointF &pos) const
01816 {
01817 Q_D(const QTextControl);
01818 return d->doc->documentLayout()->anchorAt(pos);
01819 }
01820
01821 bool QTextControl::overwriteMode() const
01822 {
01823 Q_D(const QTextControl);
01824 return d->overwriteMode;
01825 }
01826
01827 void QTextControl::setOverwriteMode(bool overwrite)
01828 {
01829 Q_D(QTextControl);
01830 d->overwriteMode = overwrite;
01831 }
01832
01833 int QTextControl::tabStopWidth() const
01834 {
01835 #ifndef QT_NO_PROPERTIES
01836 Q_D(const QTextControl);
01837 return qRound(d->doc->documentLayout()->property("tabStopWidth").toDouble());
01838 #else
01839 return 80;
01840 #endif
01841 }
01842
01843 void QTextControl::setTabStopWidth(int width)
01844 {
01845 #ifdef QT_NO_PROPERTIES
01846 Q_UNUSED(width);
01847 #else
01848 Q_D(QTextControl);
01849 d->doc->documentLayout()->setProperty("tabStopWidth", QVariant(double(width)));
01850 #endif
01851 }
01852
01853 int QTextControl::cursorWidth() const
01854 {
01855 #ifndef QT_NO_PROPERTIES
01856 Q_D(const QTextControl);
01857 return d->doc->documentLayout()->property("cursorWidth").toInt();
01858 #else
01859 return 1;
01860 #endif
01861 }
01862
01863 void QTextControl::setCursorWidth(int width)
01864 {
01865 Q_D(QTextControl);
01866 #ifdef QT_NO_PROPERTIES
01867 Q_UNUSED(width);
01868 #else
01869 d->doc->documentLayout()->setProperty("cursorWidth", width);
01870 #endif
01871 d->repaintCursor();
01872 }
01873
01874 bool QTextControl::acceptRichText() const
01875 {
01876 Q_D(const QTextControl);
01877 return d->acceptRichText;
01878 }
01879
01880 void QTextControl::setAcceptRichText(bool accept)
01881 {
01882 Q_D(QTextControl);
01883 d->acceptRichText = accept;
01884 }
01885
01886 #ifndef QT_NO_TEXTEDIT
01887
01888 void QTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
01889 {
01890 Q_D(QTextControl);
01891 if (selections.count() == d->extraSelections.count()) {
01892 bool needUpdate = false;
01893 for (int i = 0; i < selections.count(); ++i)
01894 if (selections.at(i).cursor != d->extraSelections.at(i).cursor
01895 || selections.at(i).format != d->extraSelections.at(i).format) {
01896 needUpdate = true;
01897 break;
01898 }
01899 if (!needUpdate)
01900 return;
01901 }
01902
01903 for (int i = 0; i < d->extraSelections.count(); ++i) {
01904 QRectF r = d->selectionRect(d->extraSelections.at(i).cursor);
01905 if (d->extraSelections.at(i).format.boolProperty(QTextFormat::FullWidthSelection)) {
01906 r.setLeft(0);
01907 r.setWidth(INT_MAX);
01908 }
01909 emit updateRequest(r);
01910 }
01911
01912 d->extraSelections.resize(selections.count());
01913 for (int i = 0; i < selections.count(); ++i) {
01914 d->extraSelections[i].cursor = selections.at(i).cursor;
01915 d->extraSelections[i].format = selections.at(i).format;
01916 }
01917
01918 for (int i = 0; i < d->extraSelections.count(); ++i) {
01919 QRectF r = d->selectionRect(d->extraSelections.at(i).cursor);
01920 if (d->extraSelections.at(i).format.boolProperty(QTextFormat::FullWidthSelection)) {
01921 r.setLeft(0);
01922 r.setWidth(INT_MAX);
01923 }
01924 emit updateRequest(r);
01925 }
01926 }
01927
01928 QList<QTextEdit::ExtraSelection> QTextControl::extraSelections() const
01929 {
01930 Q_D(const QTextControl);
01931 QList<QTextEdit::ExtraSelection> selections;
01932 for (int i = 0; i < d->extraSelections.count(); ++i) {
01933 QTextEdit::ExtraSelection sel;
01934 sel.cursor = d->extraSelections.at(i).cursor;
01935 sel.format = d->extraSelections.at(i).format;
01936 selections.append(sel);
01937 }
01938 return selections;
01939 }
01940
01941 #endif // QT_NO_TEXTEDIT
01942
01943 void QTextControl::setTextWidth(qreal width)
01944 {
01945 Q_D(QTextControl);
01946 d->doc->setTextWidth(width);
01947 }
01948
01949 qreal QTextControl::textWidth() const
01950 {
01951 Q_D(const QTextControl);
01952 return d->doc->textWidth();
01953 }
01954
01955 QSizeF QTextControl::size() const
01956 {
01957 Q_D(const QTextControl);
01958 return d->doc->size();
01959 }
01960
01961 void QTextControl::setOpenExternalLinks(bool open)
01962 {
01963 Q_D(QTextControl);
01964 d->openExternalLinks = open;
01965 }
01966
01967 bool QTextControl::openExternalLinks() const
01968 {
01969 Q_D(const QTextControl);
01970 return d->openExternalLinks;
01971 }
01972
01973 void QTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
01974 {
01975 Q_D(QTextControl);
01976 const QTextCursor oldSelection = d->cursor;
01977 const bool moved = d->cursor.movePosition(op, mode);
01978 d->_q_updateCurrentCharFormatAndSelection();
01979 ensureCursorVisible();
01980 d->repaintOldAndNewSelection(oldSelection);
01981 if (moved)
01982 emit cursorPositionChanged();
01983 }
01984
01985 bool QTextControl::canPaste() const
01986 {
01987 #ifndef QT_NO_CLIPBOARD
01988 Q_D(const QTextControl);
01989 if (d->interactionFlags & Qt::TextEditable) {
01990 const QMimeData *md = QApplication::clipboard()->mimeData();
01991 return md && canInsertFromMimeData(md);
01992 }
01993 #endif
01994 return false;
01995 }
01996
01997 QMimeData *QTextControl::createMimeDataFromSelection() const
01998 {
01999 Q_D(const QTextControl);
02000 const QTextDocumentFragment fragment(d->cursor);
02001 return new QTextEditMimeData(fragment);
02002 }
02003
02004 bool QTextControl::canInsertFromMimeData(const QMimeData *source) const
02005 {
02006 Q_D(const QTextControl);
02007 if (d->acceptRichText)
02008 return (source->hasText() && !source->text().isEmpty())
02009 || source->hasHtml()
02010 || source->hasFormat(QLatin1String("application/x-qrichtext"))
02011 || source->hasFormat(QLatin1String("application/x-qt-richtext"));
02012 else
02013 return source->hasText() && !source->text().isEmpty();
02014 }
02015
02016 void QTextControl::insertFromMimeData(const QMimeData *source)
02017 {
02018 Q_D(QTextControl);
02019 if (!(d->interactionFlags & Qt::TextEditable) || !source)
02020 return;
02021
02022 bool hasData = false;
02023 QTextDocumentFragment fragment;
02024 if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
02025
02026 fragment = QTextDocumentFragment::fromHtml(QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext"))));
02027 hasData = true;
02028 } else if (source->hasHtml() && d->acceptRichText) {
02029 fragment = QTextDocumentFragment::fromHtml(source->html());
02030 hasData = true;
02031 } else {
02032 QString text = source->text();
02033 if (!text.isNull()) {
02034 fragment = QTextDocumentFragment::fromPlainText(text);
02035 hasData = true;
02036 }
02037 }
02038
02039 if (hasData)
02040 d->cursor.insertFragment(fragment);
02041 ensureCursorVisible();
02042 }
02043
02044 bool QTextControlPrivate::findNextPrevAnchor(bool next, int &start, int &end)
02045 {
02046 if (!cursor.hasSelection()) {
02047 cursor = QTextCursor(doc);
02048 if (next)
02049 cursor .movePosition(QTextCursor::Start);
02050 else
02051 cursor.movePosition(QTextCursor::End);
02052 }
02053
02054 Q_ASSERT(!cursor.isNull());
02055
02056 int anchorStart = -1;
02057 QString anchorHref;
02058 int anchorEnd = -1;
02059
02060 if (next) {
02061 const int startPos = cursor.selectionEnd();
02062
02063 QTextBlock block = doc->findBlock(startPos);
02064 QTextBlock::Iterator it = block.begin();
02065
02066 while (!it.atEnd() && it.fragment().position() < startPos)
02067 ++it;
02068
02069 while (block.isValid()) {
02070 anchorStart = -1;
02071
02072
02073 for (; !it.atEnd(); ++it) {
02074 const QTextFragment fragment = it.fragment();
02075 const QTextCharFormat fmt = fragment.charFormat();
02076
02077 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
02078 anchorStart = fragment.position();
02079 anchorHref = fmt.anchorHref();
02080 break;
02081 }
02082 }
02083
02084 if (anchorStart != -1) {
02085 anchorEnd = -1;
02086
02087
02088 for (; !it.atEnd(); ++it) {
02089 const QTextFragment fragment = it.fragment();
02090 const QTextCharFormat fmt = fragment.charFormat();
02091
02092 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
02093 anchorEnd = fragment.position();
02094 break;
02095 }
02096 }
02097
02098 if (anchorEnd == -1)
02099 anchorEnd = block.position() + block.length() - 1;
02100
02101
02102 break;
02103 }
02104
02105 block = block.next();
02106 it = block.begin();
02107 }
02108 } else {
02109 int startPos = cursor.selectionStart();
02110 if (startPos > 0)
02111 --startPos;
02112
02113 QTextBlock block = doc->findBlock(startPos);
02114 QTextBlock::Iterator blockStart = block.begin();
02115 QTextBlock::Iterator it = block.end();
02116
02117 if (startPos == block.position()) {
02118 it = block.begin();
02119 } else {
02120 do {
02121 if (it == blockStart) {
02122 it = QTextBlock::Iterator();
02123 block = QTextBlock();
02124 } else {
02125 --it;
02126 }
02127 } while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
02128 }
02129
02130 while (block.isValid()) {
02131 anchorStart = -1;
02132
02133 if (!it.atEnd()) {
02134 do {
02135 const QTextFragment fragment = it.fragment();
02136 const QTextCharFormat fmt = fragment.charFormat();
02137
02138 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
02139 anchorStart = fragment.position() + fragment.length();
02140 anchorHref = fmt.anchorHref();
02141 break;
02142 }
02143
02144 if (it == blockStart)
02145 it = QTextBlock::Iterator();
02146 else
02147 --it;
02148 } while (!it.atEnd());
02149 }
02150
02151 if (anchorStart != -1 && !it.atEnd()) {
02152 anchorEnd = -1;
02153
02154 do {
02155 const QTextFragment fragment = it.fragment();
02156 const QTextCharFormat fmt = fragment.charFormat();
02157
02158 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
02159 anchorEnd = fragment.position() + fragment.length();
02160 break;
02161 }
02162
02163 if (it == blockStart)
02164 it = QTextBlock::Iterator();
02165 else
02166 --it;
02167 } while (!it.atEnd());
02168
02169 if (anchorEnd == -1)
02170 anchorEnd = qMax(0, block.position());
02171
02172 break;
02173 }
02174
02175 block = block.previous();
02176 it = block.end();
02177 if (it != block.begin())
02178 --it;
02179 blockStart = block.begin();
02180 }
02181
02182 }
02183
02184 if (anchorStart != -1 && anchorEnd != -1) {
02185 start = anchorStart;
02186 end = anchorEnd;
02187 return true;
02188 }
02189
02190 return false;
02191 }
02192
02193 bool QTextControl::setFocusToNextOrPreviousAnchor(bool next)
02194 {
02195 Q_D(QTextControl);
02196
02197 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
02198 return false;
02199
02200 QRectF crect = d->selectionRect(d->cursor);
02201 emit updateRequest(crect);
02202
02203 int anchorStart, anchorEnd;
02204 if (d->findNextPrevAnchor(next, anchorStart, anchorEnd)) {
02205 d->cursor.setPosition(anchorStart);
02206 d->cursor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
02207 d->cursorIsFocusIndicator = true;
02208 } else {
02209 d->cursor.clearSelection();
02210 }
02211
02212 if (d->cursor.hasSelection()) {
02213 crect = d->selectionRect(d->cursor);
02214 emit updateRequest(crect);
02215 emit visibilityRequest(crect);
02216 return true;
02217 } else {
02218 return false;
02219 }
02220 }
02221
02222 void QTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
02223 {
02224 Q_D(QTextControl);
02225 if (flags == d->interactionFlags)
02226 return;
02227 d->interactionFlags = flags;
02228
02229 if (d->hasFocus)
02230 d->setBlinkingCursorEnabled(flags & Qt::TextEditable);
02231 }
02232
02233 Qt::TextInteractionFlags QTextControl::textInteractionFlags() const
02234 {
02235 Q_D(const QTextControl);
02236 return d->interactionFlags;
02237 }
02238
02239 void QTextControl::mergeCurrentCharFormat(const QTextCharFormat &modifier)
02240 {
02241 Q_D(QTextControl);
02242 d->cursor.mergeCharFormat(modifier);
02243 d->lastCharFormat = d->cursor.charFormat();
02244 }
02245
02246 void QTextControl::setCurrentCharFormat(const QTextCharFormat &format)
02247 {
02248 Q_D(QTextControl);
02249 d->cursor.setCharFormat(format);
02250 d->lastCharFormat = format;
02251 }
02252
02253 QTextCharFormat QTextControl::currentCharFormat() const
02254 {
02255 Q_D(const QTextControl);
02256 return d->cursor.charFormat();
02257 }
02258
02259 void QTextControl::insertPlainText(const QString &text)
02260 {
02261 Q_D(QTextControl);
02262 d->cursor.insertText(text);
02263 }
02264
02265 void QTextControl::insertHtml(const QString &text)
02266 {
02267 Q_D(QTextControl);
02268 d->cursor.insertHtml(text);
02269 }
02270
02271 QPointF QTextControl::anchorPosition(const QString &name) const
02272 {
02273 Q_D(const QTextControl);
02274 if (name.isEmpty())
02275 return QPointF();
02276
02277 QRectF r;
02278 for (QTextBlock block = d->doc->begin(); block.isValid(); block = block.next()) {
02279 QTextCharFormat format = block.charFormat();
02280 if (format.isAnchor() && format.anchorName() == name) {
02281 r = d->rectForPosition(block.position());
02282 break;
02283 }
02284
02285 for (QTextBlock::Iterator it = block.begin(); !it.atEnd(); ++it) {
02286 QTextFragment fragment = it.fragment();
02287 format = fragment.charFormat();
02288 if (format.isAnchor() && format.anchorName() == name) {
02289 r = d->rectForPosition(fragment.position());
02290 block = QTextBlock();
02291 break;
02292 }
02293 }
02294 }
02295 if (!r.isValid())
02296 return QPointF();
02297 return QPointF(0, r.top());
02298 }
02299
02300 void QTextControl::adjustSize()
02301 {
02302 Q_D(QTextControl);
02303 d->doc->adjustSize();
02304 }
02305
02306 QTextOption::WrapMode QTextControl::wordWrapMode() const
02307 {
02308 Q_D(const QTextControl);
02309 if (QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(d->doc->documentLayout()))
02310 return layout->wordWrapMode();
02311 return QTextOption::WordWrap;
02312 }
02313
02314 void QTextControl::setWordWrapMode(QTextOption::WrapMode mode)
02315 {
02316 Q_D(QTextControl);
02317 if (QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(d->doc->documentLayout()))
02318 layout->setWordWrapMode(mode);
02319 }
02320
02321 bool QTextControl::find(const QString &exp, QTextDocument::FindFlags options)
02322 {
02323 Q_D(QTextControl);
02324 QTextCursor search = d->doc->find(exp, d->cursor, options);
02325 if (search.isNull())
02326 return false;
02327
02328 setTextCursor(search);
02329 return true;
02330 }
02331
02332 void QTextControl::append(const QString &text)
02333 {
02334 Q_D(QTextControl);
02335 QTextCursor cursor(d->doc);
02336 cursor.beginEditBlock();
02337 cursor.movePosition(QTextCursor::End);
02338
02339 if (!d->doc->isEmpty())
02340 cursor.insertBlock(d->cursor.blockFormat(), d->cursor.charFormat());
02341 else
02342 cursor.setCharFormat(d->cursor.charFormat());
02343
02344
02345 QTextCharFormat oldCharFormat = d->cursor.charFormat();
02346 if (Qt::mightBeRichText(text)) {
02347 cursor.insertHtml(text);
02348 } else {
02349 cursor.insertText(text);
02350 }
02351 if (!d->cursor.hasSelection())
02352 d->cursor.setCharFormat(oldCharFormat);
02353
02354 cursor.endEditBlock();
02355 }
02356
02357 void QTextControl::ensureCursorVisible()
02358 {
02359 Q_D(QTextControl);
02360 QRectF crect = d->rectForPosition(d->cursor.position());
02361 emit visibilityRequest(crect);
02362 emit microFocusChanged();
02363 }
02364
02365 QPalette QTextControl::palette() const
02366 {
02367 Q_D(const QTextControl);
02368 return d->palette;
02369 }
02370
02371 void QTextControl::setPalette(const QPalette &pal)
02372 {
02373 Q_D(QTextControl);
02374 d->palette = pal;
02375 }
02376
02377 void QTextControl::drawContents(QPainter *p, const QRectF &rect)
02378 {
02379 Q_D(QTextControl);
02380 p->save();
02381 QAbstractTextDocumentLayout::PaintContext ctx;
02382 if (rect.isValid())
02383 p->setClipRect(rect);
02384 ctx.clip = rect;
02385 ctx.selections = d->extraSelections;
02386
02387 for (int i = 0; i < ctx.selections.count(); ++i)
02388 if (ctx.selections.at(i).format.boolProperty(QTextFormat::FullWidthSelection)) {
02389 ctx.clip.setLeft(0);
02390 ctx.clip.setWidth(INT_MAX);
02391 }
02392
02393 ctx.palette = d->palette;
02394 if (d->cursorOn && d->isEnabled) {
02395 if (d->hideCursor)
02396 ctx.cursorPosition = -1;
02397 else if (d->preeditCursor != 0)
02398 ctx.cursorPosition = - (d->preeditCursor + 2);
02399 else
02400 ctx.cursorPosition = d->cursor.position();
02401 }
02402
02403 if (!d->dndFeedbackCursor.isNull())
02404 ctx.cursorPosition = d->dndFeedbackCursor.position();
02405 if (d->cursor.hasSelection()) {
02406 QAbstractTextDocumentLayout::Selection selection;
02407 selection.cursor = d->cursor;
02408 if (d->cursorIsFocusIndicator) {
02409 QPen outline(ctx.palette.color(QPalette::Text), 1, Qt::DotLine);
02410 selection.format.setProperty(QTextFormat::OutlinePen, outline);
02411 } else {
02412 QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive;
02413 selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
02414 selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
02415 }
02416 ctx.selections.append(selection);
02417 }
02418
02419 d->doc->documentLayout()->draw(p, ctx);
02420 p->restore();
02421 }
02422
02423 void QTextControlPrivate::_q_copyLink()
02424 {
02425 QMimeData *md = new QMimeData;
02426 md->setText(linkToCopy);
02427 #ifndef QT_NO_CLIPBOARD
02428 QApplication::clipboard()->setMimeData(md);
02429 #endif
02430 }
02431
02432 #include "moc_qtextcontrol_p.cpp"
02433
02434 #endif // QT_NO_TEXTCONTROL