• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

krichtextedit.cpp

Go to the documentation of this file.
00001 /*
00002  * krichtextedit
00003  *
00004  * Copyright 2007 Laurent Montel <montel@kde.org>
00005  * Copyright 2008 Thomas McGuire <thomas.mcguire@gmx.net>
00006  * Copyright 2008 Stephen Kelly  <steveire@gmail.com>
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00021  * 02110-1301  USA
00022  */
00023 
00024 #include "krichtextedit.h"
00025 
00026 // Own includes
00027 #include "nestedlisthelper.h"
00028 #include "klinkdialog.h"
00029 
00030 // kdelibs includes
00031 #include <kcursor.h>
00032 
00033 // Qt includes
00034 #include <QtGui/QTextDocumentFragment>
00035 #include <QtGui/QMouseEvent>
00036 
00041 //@cond PRIVATE
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     // Normal functions
00057     //
00058 
00059     // If the text under the cursor is a link, the cursor's selection is set to
00060     // the complete link text. Otherwise selects the current word if there is no
00061     // selection.
00062     void selectLinkText() const;
00063 
00064     void init();
00065 
00066     // Switches to rich text mode and emits the mode changed signal if the
00067     // mode really changed.
00068     void activateRichText();
00069 
00070     // Applies formatting to the current word if there is no selection.
00071     void mergeFormatOnWordOrSelection(const QTextCharFormat &format);
00072 
00073     void setTextCursor(QTextCursor &cursor);
00074 
00075 
00076     // Data members
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     QTextCursor wordStart(cursor);
00103     QTextCursor wordEnd(cursor);
00104 
00105     wordStart.movePosition(QTextCursor::StartOfWord);
00106     wordEnd.movePosition(QTextCursor::EndOfWord);
00107 
00108     cursor.beginEditBlock();
00109     if (!cursor.hasSelection() && cursor.position() != wordStart.position() && cursor.position() != wordEnd.position())
00110         cursor.select(QTextCursor::WordUnderCursor);
00111     cursor.mergeCharFormat(format);
00112     q->mergeCurrentCharFormat(format);
00113     cursor.endEditBlock();
00114 }
00115 //@endcond
00116 
00117 KRichTextEdit::KRichTextEdit(const QString& text, QWidget *parent)
00118         : KTextEdit(text, parent), d(new KRichTextEditPrivate(this))
00119 {
00120     d->init();
00121 }
00122 
00123 KRichTextEdit::KRichTextEdit(QWidget *parent)
00124         : KTextEdit(parent), d(new KRichTextEditPrivate(this))
00125 {
00126     d->init();
00127 }
00128 
00129 KRichTextEdit::~KRichTextEdit()
00130 {
00131     delete d;
00132 }
00133 
00134 //@cond PRIVATE
00135 void KRichTextEditPrivate::init()
00136 {
00137     q->setAcceptRichText(false);
00138     KCursor::setAutoHideCursor(q, true, true);
00139 }
00140 //@endcond
00141 
00142 void KRichTextEdit::setListStyle(int _styleIndex)
00143 {
00144     d->nestedListHelper->handleOnBulletType(-_styleIndex);
00145     setFocus();
00146     d->activateRichText();
00147 }
00148 
00149 void KRichTextEdit::indentListMore()
00150 {
00151     d->nestedListHelper->handleOnIndentMore();
00152     d->activateRichText();
00153 }
00154 
00155 void KRichTextEdit::indentListLess()
00156 {
00157     d->nestedListHelper->handleOnIndentLess();
00158 }
00159 
00160 void KRichTextEdit::insertHorizontalRule()
00161 {
00162     QTextCursor cursor = textCursor();
00163     QTextBlockFormat bf = cursor.blockFormat();
00164     QTextCharFormat cf = cursor.charFormat();
00165 
00166     cursor.beginEditBlock();
00167     cursor.insertHtml("<hr>");
00168     cursor.insertBlock(bf, cf);
00169     setTextCursor(cursor);
00170     d->activateRichText();
00171     cursor.endEditBlock();
00172 }
00173 
00174 void KRichTextEdit::alignLeft()
00175 {
00176     setAlignment(Qt::AlignLeft);
00177     setFocus();
00178     d->activateRichText();
00179 }
00180 
00181 void KRichTextEdit::alignCenter()
00182 {
00183     setAlignment(Qt::AlignHCenter);
00184     setFocus();
00185     d->activateRichText();
00186 }
00187 
00188 void KRichTextEdit::alignRight()
00189 {
00190     setAlignment(Qt::AlignRight);
00191     setFocus();
00192     d->activateRichText();
00193 }
00194 
00195 void KRichTextEdit::alignJustify()
00196 {
00197     setAlignment(Qt::AlignJustify);
00198     setFocus();
00199     d->activateRichText();
00200 }
00201 
00202 void KRichTextEdit::setTextBold(bool bold)
00203 {
00204     QTextCharFormat fmt;
00205     fmt.setFontWeight(bold ? QFont::Bold : QFont::Normal);
00206     d->mergeFormatOnWordOrSelection(fmt);
00207     setFocus();
00208     d->activateRichText();
00209 }
00210 
00211 void KRichTextEdit::setTextItalic(bool italic)
00212 {
00213     QTextCharFormat fmt;
00214     fmt.setFontItalic(italic);
00215     d->mergeFormatOnWordOrSelection(fmt);
00216     setFocus();
00217     d->activateRichText();
00218 }
00219 
00220 void KRichTextEdit::setTextUnderline(bool underline)
00221 {
00222     QTextCharFormat fmt;
00223     fmt.setFontUnderline(underline);
00224     d->mergeFormatOnWordOrSelection(fmt);
00225     setFocus();
00226     d->activateRichText();
00227 }
00228 
00229 void KRichTextEdit::setTextStrikeOut(bool strikeOut)
00230 {
00231     QTextCharFormat fmt;
00232     fmt.setFontStrikeOut(strikeOut);
00233     d->mergeFormatOnWordOrSelection(fmt);
00234     setFocus();
00235     d->activateRichText();
00236 }
00237 
00238 void KRichTextEdit::setTextForegroundColor(const QColor &color)
00239 {
00240     QTextCharFormat fmt;
00241     fmt.setForeground(color);
00242     d->mergeFormatOnWordOrSelection(fmt);
00243     setFocus();
00244     d->activateRichText();
00245 }
00246 
00247 void KRichTextEdit::setTextBackgroundColor(const QColor &color)
00248 {
00249     QTextCharFormat fmt;
00250     fmt.setBackground(color);
00251     d->mergeFormatOnWordOrSelection(fmt);
00252     setFocus();
00253     d->activateRichText();
00254 }
00255 
00256 void KRichTextEdit::setFontFamily(const QString &fontFamily)
00257 {
00258     QTextCharFormat fmt;
00259     fmt.setFontFamily(fontFamily);
00260     d->mergeFormatOnWordOrSelection(fmt);
00261     setFocus();
00262     d->activateRichText();
00263 }
00264 
00265 void KRichTextEdit::setFontSize(int size)
00266 {
00267     QTextCharFormat fmt;
00268     fmt.setFontPointSize(size);
00269     d->mergeFormatOnWordOrSelection(fmt);
00270     setFocus();
00271     d->activateRichText();
00272 }
00273 
00274 void KRichTextEdit::setFont(const QFont &font)
00275 {
00276     QTextCharFormat fmt;
00277     fmt.setFont(font);
00278     d->mergeFormatOnWordOrSelection(fmt);
00279     setFocus();
00280     d->activateRichText();
00281 }
00282 
00283 void KRichTextEdit::switchToPlainText()
00284 {
00285     if (d->mMode == Rich) {
00286         d->mMode = Plain;
00287         // TODO: Warn the user about this?
00288         document()->setPlainText(document()->toPlainText());
00289         setAcceptRichText(false);
00290         emit textModeChanged(d->mMode);
00291     }
00292 }
00293 
00294 void KRichTextEdit::setTextSuperScript(bool superscript)
00295 {
00296     QTextCharFormat fmt;
00297     fmt.setVerticalAlignment(superscript ? QTextCharFormat::AlignSuperScript : QTextCharFormat::AlignNormal);
00298     d->mergeFormatOnWordOrSelection(fmt);
00299     setFocus();
00300     d->activateRichText();
00301 }
00302 
00303 void KRichTextEdit::setTextSubScript(bool subscript)
00304 {
00305     QTextCharFormat fmt;
00306     fmt.setVerticalAlignment(subscript ? QTextCharFormat::AlignSubScript : QTextCharFormat::AlignNormal);
00307     d->mergeFormatOnWordOrSelection(fmt);
00308     setFocus();
00309     d->activateRichText();
00310 }
00311 
00312 void KRichTextEdit::enableRichTextMode()
00313 {
00314     d->activateRichText();
00315 }
00316 
00317 KRichTextEdit::Mode KRichTextEdit::textMode() const
00318 {
00319     return d->mMode;
00320 }
00321 
00322 QString KRichTextEdit::textOrHtml() const
00323 {
00324     if (textMode() == Rich)
00325         return toCleanHtml();
00326     else
00327         return toPlainText();
00328 }
00329 
00330 void KRichTextEdit::setTextOrHtml(const QString &text)
00331 {
00332     // might be rich text
00333     if (Qt::mightBeRichText(text)) {
00334         if (d->mMode == KRichTextEdit::Plain) {
00335             d->activateRichText();
00336         }
00337         setHtml(text);
00338     } else {
00339         setPlainText(text);
00340     }
00341 }
00342 
00343 QString KRichTextEdit::currentLinkText() const
00344 {
00345     QTextCursor cursor = textCursor();
00346     selectLinkText(&cursor);
00347     return cursor.selectedText();
00348 }
00349 
00350 void KRichTextEdit::selectLinkText() const
00351 {
00352     QTextCursor cursor = textCursor();
00353     selectLinkText(&cursor);
00354     d->setTextCursor(cursor);
00355 }
00356 
00357 void KRichTextEdit::selectLinkText(QTextCursor *cursor) const
00358 {
00359     // If the cursor is on a link, select the text of the link.
00360     if (cursor->charFormat().isAnchor()) {
00361         QString aHref = cursor->charFormat().anchorHref();
00362 
00363         // Move cursor to start of link
00364         while (cursor->charFormat().anchorHref() == aHref) {
00365             if (cursor->atStart())
00366                 break;
00367             cursor->setPosition(cursor->position() - 1);
00368         }
00369         if (cursor->charFormat().anchorHref() != aHref)
00370             cursor->setPosition(cursor->position() + 1, QTextCursor::KeepAnchor);
00371 
00372         // Move selection to the end of the link
00373         while (cursor->charFormat().anchorHref() == aHref) {
00374             if (cursor->atEnd())
00375                 break;
00376             cursor->setPosition(cursor->position() + 1, QTextCursor::KeepAnchor);
00377         }
00378         if (cursor->charFormat().anchorHref() != aHref)
00379             cursor->setPosition(cursor->position() - 1, QTextCursor::KeepAnchor);
00380     } else if (cursor->hasSelection()) {
00381         // Nothing to to. Using the currently selected text as the link text.
00382     } else {
00383 
00384         // Select current word
00385         cursor->movePosition(QTextCursor::StartOfWord);
00386         cursor->movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
00387     }
00388 }
00389 
00390 QString KRichTextEdit::currentLinkUrl() const
00391 {
00392     return textCursor().charFormat().anchorHref();
00393 }
00394 
00395 void KRichTextEdit::updateLink(const QString &linkUrl, const QString &linkText)
00396 {
00397     selectLinkText();
00398 
00399     QTextCursor cursor = textCursor();
00400     cursor.beginEditBlock();
00401     if (!cursor.hasSelection()) {
00402         cursor.select(QTextCursor::WordUnderCursor);
00403     }
00404 
00405     QTextCharFormat format = cursor.charFormat();
00406     if (!linkUrl.isEmpty()) {
00407         format.setAnchor(true);
00408         format.setAnchorHref(linkUrl);
00409     } else {
00410         format = cursor.block().charFormat();
00411         format.setAnchor(false);
00412         format.setAnchorHref(QString());
00413     }
00414 
00415     QString _linkText;
00416 
00417     int lowPos = qMin(cursor.selectionStart(), cursor.selectionEnd());
00418     if (!linkText.isEmpty()) {
00419         _linkText = linkText;
00420     } else {
00421         _linkText = linkUrl;
00422     }
00423     // Can't simply insertHtml("<a href=\"%1\">%2</a>").arg(linkUrl).arg(_linkText);
00424     // That would remove all existing text formatting on the selection (bold etc).
00425     // The href information is stored in the QTextCharFormat, but qt bugs must
00426     // still be worked around below.
00427     cursor.insertText(_linkText, format);
00428 
00429 
00430     // Workaround for qt bug 203510:
00431     // Link formatting does not get applied immediately. Removing and reinserting
00432     // the marked up html does format the text correctly.
00433     // -- Stephen Kelly, 15th March 2008
00434     if (!linkUrl.isEmpty()) {
00435         cursor.setPosition(lowPos);
00436         cursor.setPosition(lowPos + _linkText.length(), QTextCursor::KeepAnchor);
00437 
00438         if (!cursor.currentList()) {
00439             cursor.insertHtml(cursor.selection().toHtml());
00440         } else {
00441             // Workaround for qt bug 215576:
00442             // If the cursor is currently on a list, inserting html will create a new block.
00443             // This seems to be because toHtml() does not create a <!-- StartFragment --> tag in
00444             // this case and text style information is stored in the list item rather than a span tag.
00445             // -- Stephen Kelly, 8th June 2008
00446 
00447             QString selectionHtml = cursor.selection().toHtml();
00448             QString style = selectionHtml.split("<li style=\"").takeAt(1).split('\"').first();
00449             QString linkTag = "<a" + selectionHtml.split("<a").takeAt(1).split('>').first() + '>'
00450                 + "<span style=\"" + style + "\">" + _linkText + "</span></a>";
00451             cursor.insertHtml(linkTag);
00452         }
00453 
00454         // Insert a space after the link if at the end of the block so that
00455         // typing some text after the link does not carry link formatting
00456         if (cursor.position() == cursor.block().position() + cursor.block().length() - 1) {
00457             cursor.setCharFormat(cursor.block().charFormat());
00458             cursor.insertText(QString(' '));
00459         }
00460 
00461         d->activateRichText();
00462     } else {
00463         // Remove link formatting. This is a workaround for the same qt bug (203510).
00464         // Just remove all formatting from the link text.
00465         QTextCharFormat charFormat;
00466         cursor.setCharFormat(charFormat);
00467     }
00468 
00469     cursor.endEditBlock();
00470 }
00471 
00472 void KRichTextEdit::keyPressEvent(QKeyEvent *event)
00473 {
00474     bool handled = false;
00475     if (textCursor().currentList()) {
00476         // handled is False if the key press event was not handled or not completely
00477         // handled by the Helper class.
00478         handled = d->nestedListHelper->handleBeforeKeyPressEvent(event);
00479     }
00480 
00481     if (!handled) {
00482         KTextEdit::keyPressEvent(event);
00483     }
00484 
00485     if (textCursor().currentList()) {
00486         d->nestedListHelper->handleAfterKeyPressEvent(event);
00487     }
00488     emit cursorPositionChanged();
00489 }
00490 
00491 // void KRichTextEdit::dropEvent(QDropEvent *event)
00492 // {
00493 //     int dropSize = event->mimeData()->text().size();
00494 //
00495 //     dropEvent( event );
00496 //     QTextCursor cursor = textCursor();
00497 //     int cursorPosition = cursor.position();
00498 //     cursor.setPosition( cursorPosition - dropSize );
00499 //     cursor.setPosition( cursorPosition, QTextCursor::KeepAnchor );
00500 //     setTextCursor( cursor );
00501 //     d->nestedListHelper->handleAfterDropEvent( event );
00502 // }
00503 
00504 
00505 bool KRichTextEdit::canIndentList() const
00506 {
00507     return d->nestedListHelper->canIndent();
00508 }
00509 
00510 bool KRichTextEdit::canDedentList() const
00511 {
00512     return d->nestedListHelper->canDedent();
00513 }
00514 
00515 QString KRichTextEdit::toCleanHtml() const
00516 {
00517     // Does nothing anymore, as Qt seems to be fixed now.
00518     // See the unit test which confirms this.
00519     return toHtml();
00520 }
00521 
00522 #include "krichtextedit.moc"

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal