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::enableRichTextMode()
00288 {
00289 d->activateRichText();
00290 }
00291
00292 KRichTextEdit::Mode KRichTextEdit::textMode() const
00293 {
00294 return d->mMode;
00295 }
00296
00297 QString KRichTextEdit::textOrHtml() const
00298 {
00299 if (textMode() == Rich)
00300 return toCleanHtml();
00301 else
00302 return toPlainText();
00303 }
00304
00305 void KRichTextEdit::setTextOrHtml(const QString &text)
00306 {
00307
00308 if (Qt::mightBeRichText(text)) {
00309 if (d->mMode == KRichTextEdit::Plain) {
00310 d->activateRichText();
00311 }
00312 setHtml(text);
00313 } else {
00314 setPlainText(text);
00315 }
00316 }
00317
00318 QString KRichTextEdit::currentLinkText() const
00319 {
00320 QTextCursor cursor = textCursor();
00321 selectLinkText(&cursor);
00322 return cursor.selectedText();
00323 }
00324
00325 void KRichTextEdit::selectLinkText() const
00326 {
00327 QTextCursor cursor = textCursor();
00328 selectLinkText(&cursor);
00329 d->setTextCursor(cursor);
00330 }
00331
00332 void KRichTextEdit::selectLinkText(QTextCursor *cursor) const
00333 {
00334
00335 if (cursor->charFormat().isAnchor()) {
00336 QString aHref = cursor->charFormat().anchorHref();
00337
00338
00339 while (cursor->charFormat().anchorHref() == aHref) {
00340 if (cursor->atStart())
00341 break;
00342 cursor->setPosition(cursor->position() - 1);
00343 }
00344 if (cursor->charFormat().anchorHref() != aHref)
00345 cursor->setPosition(cursor->position() + 1, QTextCursor::KeepAnchor);
00346
00347
00348 while (cursor->charFormat().anchorHref() == aHref) {
00349 if (cursor->atEnd())
00350 break;
00351 cursor->setPosition(cursor->position() + 1, QTextCursor::KeepAnchor);
00352 }
00353 if (cursor->charFormat().anchorHref() != aHref)
00354 cursor->setPosition(cursor->position() - 1, QTextCursor::KeepAnchor);
00355 } else if (cursor->hasSelection()) {
00356
00357 } else {
00358
00359
00360 cursor->movePosition(QTextCursor::StartOfWord);
00361 cursor->movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
00362 }
00363 }
00364
00365 QString KRichTextEdit::currentLinkUrl() const
00366 {
00367 return textCursor().charFormat().anchorHref();
00368 }
00369
00370 void KRichTextEdit::updateLink(const QString &linkUrl, const QString &linkText)
00371 {
00372 QTextCursor cursor = textCursor();
00373 cursor.beginEditBlock();
00374 QTextCharFormat format = cursor.charFormat();
00375
00376 selectLinkText();
00377 if (!cursor.hasSelection()) {
00378 cursor.select(QTextCursor::WordUnderCursor);
00379 }
00380
00381 if (!linkUrl.isEmpty()) {
00382 format.setAnchor(true);
00383 format.setAnchorHref(linkUrl);
00384 } else {
00385 format = cursor.block().charFormat();
00386 format.setAnchor(false);
00387 format.setAnchorHref(QString());
00388 }
00389
00390 QString _linkText;
00391
00392 int lowPos = qMin(cursor.selectionStart(), cursor.selectionEnd());
00393 if (!linkText.isEmpty()) {
00394 _linkText = linkText;
00395 } else {
00396 _linkText = linkUrl;
00397 }
00398
00399
00400
00401
00402 cursor.insertText(_linkText, format);
00403
00404
00405
00406
00407
00408
00409 if (!linkUrl.isEmpty()) {
00410 cursor.setPosition(lowPos);
00411 cursor.setPosition(lowPos + _linkText.length(), QTextCursor::KeepAnchor);
00412
00413 if (!cursor.currentList()) {
00414 cursor.insertHtml(cursor.selection().toHtml());
00415 } else {
00416
00417
00418
00419
00420
00421
00422 QString selectionHtml = cursor.selection().toHtml();
00423 QString style = selectionHtml.split("<li style=\"").takeAt(1).split("\"").first();
00424 QString linkTag = "<a" + selectionHtml.split("<a").takeAt(1).split('>').first() + '>'
00425 + "<span style=\"" + style + "\">" + _linkText + "</span></a>";
00426 cursor.insertHtml(linkTag);
00427 }
00428
00429
00430
00431 if (cursor.position() == cursor.block().position() + cursor.block().length() - 1) {
00432 cursor.setCharFormat(cursor.block().charFormat());
00433 cursor.insertText(QString(' '));
00434 }
00435
00436 d->activateRichText();
00437 } else {
00438
00439
00440 QTextCharFormat charFormat;
00441 cursor.setCharFormat(charFormat);
00442 }
00443
00444 cursor.endEditBlock();
00445 }
00446
00447 void KRichTextEdit::keyPressEvent(QKeyEvent *event)
00448 {
00449 bool handled = false;
00450 if (textCursor().currentList()) {
00451
00452
00453 handled = d->nestedListHelper->handleBeforeKeyPressEvent(event);
00454 }
00455
00456 if (!handled) {
00457 KTextEdit::keyPressEvent(event);
00458 }
00459
00460 if (textCursor().currentList()) {
00461 d->nestedListHelper->handleAfterKeyPressEvent(event);
00462 }
00463 emit cursorPositionChanged();
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 bool KRichTextEdit::canIndentList() const
00481 {
00482 return d->nestedListHelper->canIndent();
00483 }
00484
00485 bool KRichTextEdit::canDedentList() const
00486 {
00487 return d->nestedListHelper->canDedent();
00488 }
00489
00490 QString KRichTextEdit::toCleanHtml() const
00491 {
00492 static QString evilline = "<p style=\" margin-top:0px; margin-bottom:0px; "
00493 "margin-left:0px; margin-right:0px; -qt-block-indent:0; "
00494 "text-indent:0px; -qt-user-state:0;\">";
00495
00496 QString result;
00497 QStringList lines = toHtml().split("\n");
00498 foreach(QString tempLine, lines ) {
00499 if (tempLine.startsWith(evilline)) {
00500 tempLine.remove(evilline);
00501 if (tempLine.endsWith("</p>")) {
00502 tempLine.remove(QRegExp("</p>$"));
00503 tempLine.append("<br>\n");
00504 }
00505 result += tempLine;
00506 } else {
00507 result += tempLine;
00508 }
00509 }
00510 return result;
00511 }
00512
00513 #include "krichtextedit.moc"