KDEUI
krichtextedit.cpp
Go to the documentation of this file.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 "krichtextedit.h"
00025
00026
00027 #include "nestedlisthelper.h"
00028 #include "klinkdialog.h"
00029
00030
00031 #include <kcursor.h>
00032
00033
00034 #include <QtGui/QTextDocumentFragment>
00035 #include <QtGui/QMouseEvent>
00036
00041
00042 class KRichTextEditPrivate : public QObject
00043 {
00044 public:
00045 KRichTextEditPrivate(KRichTextEdit *parent)
00046 : q(parent),
00047 mMode(KRichTextEdit::Plain) {
00048 nestedListHelper = new NestedListHelper(q);
00049 }
00050
00051 ~KRichTextEditPrivate() {
00052 delete nestedListHelper;
00053 }
00054
00055
00056
00057
00058
00059
00060
00061
00062 void selectLinkText() const;
00063
00064 void init();
00065
00066
00067
00068 void activateRichText();
00069
00070
00071 void mergeFormatOnWordOrSelection(const QTextCharFormat &format);
00072
00073 void setTextCursor(QTextCursor &cursor);
00074
00075
00076
00077
00078 KRichTextEdit *q;
00079 KRichTextEdit::Mode mMode;
00080
00081 NestedListHelper *nestedListHelper;
00082
00083 };
00084
00085 void KRichTextEditPrivate::activateRichText()
00086 {
00087 if (mMode == KRichTextEdit::Plain) {
00088 q->setAcceptRichText(true);
00089 mMode = KRichTextEdit::Rich;
00090 emit q->textModeChanged(mMode);
00091 }
00092 }
00093
00094 void KRichTextEditPrivate::setTextCursor(QTextCursor &cursor)
00095 {
00096 q->setTextCursor(cursor);
00097 }
00098
00099 void KRichTextEditPrivate::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
00100 {
00101 QTextCursor cursor = q->textCursor();
00102 cursor.beginEditBlock();
00103 if (!cursor.hasSelection())
00104 cursor.select(QTextCursor::WordUnderCursor);
00105 cursor.mergeCharFormat(format);
00106 q->mergeCurrentCharFormat(format);
00107 cursor.endEditBlock();
00108 }
00109
00110
00111 KRichTextEdit::KRichTextEdit(const QString& text, QWidget *parent)
00112 : KTextEdit(text, parent), d(new KRichTextEditPrivate(this))
00113 {
00114 d->init();
00115 }
00116
00117 KRichTextEdit::KRichTextEdit(QWidget *parent)
00118 : KTextEdit(parent), d(new KRichTextEditPrivate(this))
00119 {
00120 d->init();
00121 }
00122
00123 KRichTextEdit::~KRichTextEdit()
00124 {
00125 delete d;
00126 }
00127
00128
00129 void KRichTextEditPrivate::init()
00130 {
00131 KCursor::setAutoHideCursor(q, true, true);
00132 }
00133
00134
00135 void KRichTextEdit::setListStyle(int _styleIndex)
00136 {
00137 d->nestedListHelper->handleOnBulletType(-_styleIndex);
00138 setFocus();
00139 d->activateRichText();
00140 }
00141
00142 void KRichTextEdit::indentListMore()
00143 {
00144 d->nestedListHelper->handleOnIndentMore();
00145 d->activateRichText();
00146 }
00147
00148 void KRichTextEdit::indentListLess()
00149 {
00150 d->nestedListHelper->handleOnIndentLess();
00151 }
00152
00153 void KRichTextEdit::insertHorizontalRule()
00154 {
00155 QTextCursor cursor = textCursor();
00156 QTextBlockFormat bf = cursor.blockFormat();
00157 QTextCharFormat cf = cursor.charFormat();
00158
00159 cursor.beginEditBlock();
00160 cursor.insertHtml("<hr>");
00161 cursor.insertBlock(bf, cf);
00162 setTextCursor(cursor);
00163 d->activateRichText();
00164 cursor.endEditBlock();
00165 }
00166
00167 void KRichTextEdit::alignLeft()
00168 {
00169 setAlignment(Qt::AlignLeft);
00170 setFocus();
00171 d->activateRichText();
00172 }
00173
00174 void KRichTextEdit::alignCenter()
00175 {
00176 setAlignment(Qt::AlignHCenter);
00177 setFocus();
00178 d->activateRichText();
00179 }
00180
00181 void KRichTextEdit::alignRight()
00182 {
00183 setAlignment(Qt::AlignRight);
00184 setFocus();
00185 d->activateRichText();
00186 }
00187
00188 void KRichTextEdit::alignJustify()
00189 {
00190 setAlignment(Qt::AlignJustify);
00191 setFocus();
00192 d->activateRichText();
00193 }
00194
00195 void KRichTextEdit::setTextBold(bool bold)
00196 {
00197 QTextCharFormat fmt;
00198 fmt.setFontWeight(bold ? QFont::Bold : QFont::Normal);
00199 d->mergeFormatOnWordOrSelection(fmt);
00200 setFocus();
00201 d->activateRichText();
00202 }
00203
00204 void KRichTextEdit::setTextItalic(bool italic)
00205 {
00206 QTextCharFormat fmt;
00207 fmt.setFontItalic(italic);
00208 d->mergeFormatOnWordOrSelection(fmt);
00209 setFocus();
00210 d->activateRichText();
00211 }
00212
00213 void KRichTextEdit::setTextUnderline(bool underline)
00214 {
00215 QTextCharFormat fmt;
00216 fmt.setFontUnderline(underline);
00217 d->mergeFormatOnWordOrSelection(fmt);
00218 setFocus();
00219 d->activateRichText();
00220 }
00221
00222 void KRichTextEdit::setTextStrikeOut(bool strikeOut)
00223 {
00224 QTextCharFormat fmt;
00225 fmt.setFontStrikeOut(strikeOut);
00226 d->mergeFormatOnWordOrSelection(fmt);
00227 setFocus();
00228 d->activateRichText();
00229 }
00230
00231 void KRichTextEdit::setTextForegroundColor(const QColor &color)
00232 {
00233 QTextCharFormat fmt;
00234 fmt.setForeground(color);
00235 d->mergeFormatOnWordOrSelection(fmt);
00236 setFocus();
00237 d->activateRichText();
00238 }
00239
00240 void KRichTextEdit::setTextBackgroundColor(const QColor &color)
00241 {
00242 QTextCharFormat fmt;
00243 fmt.setBackground(color);
00244 d->mergeFormatOnWordOrSelection(fmt);
00245 setFocus();
00246 d->activateRichText();
00247 }
00248
00249 void KRichTextEdit::setFontFamily(const QString &fontFamily)
00250 {
00251 QTextCharFormat fmt;
00252 fmt.setFontFamily(fontFamily);
00253 d->mergeFormatOnWordOrSelection(fmt);
00254 setFocus();
00255 d->activateRichText();
00256 }
00257
00258 void KRichTextEdit::setFontSize(int size)
00259 {
00260 QTextCharFormat fmt;
00261 fmt.setFontPointSize(size);
00262 d->mergeFormatOnWordOrSelection(fmt);
00263 setFocus();
00264 d->activateRichText();
00265 }
00266
00267 void KRichTextEdit::setFont(const QFont &font)
00268 {
00269 QTextCharFormat fmt;
00270 fmt.setFont(font);
00271 d->mergeFormatOnWordOrSelection(fmt);
00272 setFocus();
00273 d->activateRichText();
00274 }
00275
00276 void KRichTextEdit::switchToPlainText()
00277 {
00278 if (d->mMode == Rich) {
00279 d->mMode = Plain;
00280
00281 document()->setPlainText(document()->toPlainText());
00282 setAcceptRichText(false);
00283 emit textModeChanged(d->mMode);
00284 }
00285 }
00286
00287 void KRichTextEdit::setTextSuperScript(bool superscript)
00288 {
00289 QTextCharFormat fmt;
00290 fmt.setVerticalAlignment(superscript ? QTextCharFormat::AlignSuperScript : QTextCharFormat::AlignNormal);
00291 d->mergeFormatOnWordOrSelection(fmt);
00292 setFocus();
00293 d->activateRichText();
00294 }
00295
00296 void KRichTextEdit::setTextSubScript(bool subscript)
00297 {
00298 QTextCharFormat fmt;
00299 fmt.setVerticalAlignment(subscript ? QTextCharFormat::AlignSubScript : QTextCharFormat::AlignNormal);
00300 d->mergeFormatOnWordOrSelection(fmt);
00301 setFocus();
00302 d->activateRichText();
00303 }
00304
00305 void KRichTextEdit::enableRichTextMode()
00306 {
00307 d->activateRichText();
00308 }
00309
00310 KRichTextEdit::Mode KRichTextEdit::textMode() const
00311 {
00312 return d->mMode;
00313 }
00314
00315 QString KRichTextEdit::textOrHtml() const
00316 {
00317 if (textMode() == Rich)
00318 return toCleanHtml();
00319 else
00320 return toPlainText();
00321 }
00322
00323 void KRichTextEdit::setTextOrHtml(const QString &text)
00324 {
00325
00326 if (Qt::mightBeRichText(text)) {
00327 if (d->mMode == KRichTextEdit::Plain) {
00328 d->activateRichText();
00329 }
00330 setHtml(text);
00331 } else {
00332 setPlainText(text);
00333 }
00334 }
00335
00336 QString KRichTextEdit::currentLinkText() const
00337 {
00338 QTextCursor cursor = textCursor();
00339 selectLinkText(&cursor);
00340 return cursor.selectedText();
00341 }
00342
00343 void KRichTextEdit::selectLinkText() const
00344 {
00345 QTextCursor cursor = textCursor();
00346 selectLinkText(&cursor);
00347 d->setTextCursor(cursor);
00348 }
00349
00350 void KRichTextEdit::selectLinkText(QTextCursor *cursor) const
00351 {
00352
00353 if (cursor->charFormat().isAnchor()) {
00354 QString aHref = cursor->charFormat().anchorHref();
00355
00356
00357 while (cursor->charFormat().anchorHref() == aHref) {
00358 if (cursor->atStart())
00359 break;
00360 cursor->setPosition(cursor->position() - 1);
00361 }
00362 if (cursor->charFormat().anchorHref() != aHref)
00363 cursor->setPosition(cursor->position() + 1, QTextCursor::KeepAnchor);
00364
00365
00366 while (cursor->charFormat().anchorHref() == aHref) {
00367 if (cursor->atEnd())
00368 break;
00369 cursor->setPosition(cursor->position() + 1, QTextCursor::KeepAnchor);
00370 }
00371 if (cursor->charFormat().anchorHref() != aHref)
00372 cursor->setPosition(cursor->position() - 1, QTextCursor::KeepAnchor);
00373 } else if (cursor->hasSelection()) {
00374
00375 } else {
00376
00377
00378 cursor->movePosition(QTextCursor::StartOfWord);
00379 cursor->movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
00380 }
00381 }
00382
00383 QString KRichTextEdit::currentLinkUrl() const
00384 {
00385 return textCursor().charFormat().anchorHref();
00386 }
00387
00388 void KRichTextEdit::updateLink(const QString &linkUrl, const QString &linkText)
00389 {
00390 QTextCursor cursor = textCursor();
00391 cursor.beginEditBlock();
00392 QTextCharFormat format = cursor.charFormat();
00393
00394 selectLinkText();
00395 if (!cursor.hasSelection()) {
00396 cursor.select(QTextCursor::WordUnderCursor);
00397 }
00398
00399 if (!linkUrl.isEmpty()) {
00400 format.setAnchor(true);
00401 format.setAnchorHref(linkUrl);
00402 } else {
00403 format = cursor.block().charFormat();
00404 format.setAnchor(false);
00405 format.setAnchorHref(QString());
00406 }
00407
00408 QString _linkText;
00409
00410 int lowPos = qMin(cursor.selectionStart(), cursor.selectionEnd());
00411 if (!linkText.isEmpty()) {
00412 _linkText = linkText;
00413 } else {
00414 _linkText = linkUrl;
00415 }
00416
00417
00418
00419
00420 cursor.insertText(_linkText, format);
00421
00422
00423
00424
00425
00426
00427 if (!linkUrl.isEmpty()) {
00428 cursor.setPosition(lowPos);
00429 cursor.setPosition(lowPos + _linkText.length(), QTextCursor::KeepAnchor);
00430
00431 if (!cursor.currentList()) {
00432 cursor.insertHtml(cursor.selection().toHtml());
00433 } else {
00434
00435
00436
00437
00438
00439
00440 QString selectionHtml = cursor.selection().toHtml();
00441 QString style = selectionHtml.split("<li style=\"").takeAt(1).split('\"').first();
00442 QString linkTag = "<a" + selectionHtml.split("<a").takeAt(1).split('>').first() + '>'
00443 + "<span style=\"" + style + "\">" + _linkText + "</span></a>";
00444 cursor.insertHtml(linkTag);
00445 }
00446
00447
00448
00449 if (cursor.position() == cursor.block().position() + cursor.block().length() - 1) {
00450 cursor.setCharFormat(cursor.block().charFormat());
00451 cursor.insertText(QString(' '));
00452 }
00453
00454 d->activateRichText();
00455 } else {
00456
00457
00458 QTextCharFormat charFormat;
00459 cursor.setCharFormat(charFormat);
00460 }
00461
00462 cursor.endEditBlock();
00463 }
00464
00465 void KRichTextEdit::keyPressEvent(QKeyEvent *event)
00466 {
00467 bool handled = false;
00468 if (textCursor().currentList()) {
00469
00470
00471 handled = d->nestedListHelper->handleBeforeKeyPressEvent(event);
00472 }
00473
00474 if (!handled) {
00475 KTextEdit::keyPressEvent(event);
00476 }
00477
00478 if (textCursor().currentList()) {
00479 d->nestedListHelper->handleAfterKeyPressEvent(event);
00480 }
00481 emit cursorPositionChanged();
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 bool KRichTextEdit::canIndentList() const
00499 {
00500 return d->nestedListHelper->canIndent();
00501 }
00502
00503 bool KRichTextEdit::canDedentList() const
00504 {
00505 return d->nestedListHelper->canDedent();
00506 }
00507
00508 QString KRichTextEdit::toCleanHtml() const
00509 {
00510 static QString evilline = "<p style=\" margin-top:0px; margin-bottom:0px; "
00511 "margin-left:0px; margin-right:0px; -qt-block-indent:0; "
00512 "text-indent:0px; -qt-user-state:0;\">";
00513
00514 QString result;
00515 const QStringList lines = toHtml().split('\n');
00516 Q_FOREACH (const QString &tempLine, lines) {
00517 if (tempLine.startsWith(evilline)) {
00518 QString tempLineCopy = tempLine;
00519 tempLineCopy.remove(evilline);
00520 if (tempLineCopy.endsWith("</p>")) {
00521 tempLineCopy.remove(QRegExp("</p>$"));
00522 tempLineCopy.append("<br>\n");
00523 }
00524 result += tempLineCopy;
00525 } else {
00526 result += tempLine;
00527 }
00528 }
00529
00530
00531 int offset = 0;
00532 QRegExp paragraphFinder("<p.*>(.*)</p>");
00533 QRegExp paragraphEnd("</p>");
00534 paragraphFinder.setMinimal(true);
00535
00536 while (offset != -1) {
00537
00538
00539 offset = paragraphFinder.indexIn(result, offset);
00540
00541 if (offset != -1) {
00542
00543
00544 if (paragraphFinder.capturedTexts().size() == 2 &&
00545 paragraphFinder.capturedTexts()[1].isEmpty()) {
00546 int end = paragraphEnd.indexIn(result, offset);
00547 Q_ASSERT(end != -1 && end > offset);
00548 result.replace(end, paragraphEnd.pattern().length(), "<br></p>");
00549 }
00550
00551
00552 offset++;
00553 }
00554 }
00555
00556 return result;
00557 }
00558
00559 #include "krichtextedit.moc"