• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

KPIMTextedit Library

  • kpimtextedit
textedit.cpp
1/*
2 Copyright (c) 2009 Thomas McGuire <mcguire@kde.org>
3
4 Based on KMail and libkdepim code by:
5 Copyright 2007 - 2012 Laurent Montel <montel@kde.org>
6
7 This library is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Library General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
11
12 This library is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21*/
22#include "textedit.h"
23
24#include "emailquotehighlighter.h"
25#include "emoticontexteditaction.h"
26#include "inserthtmldialog.h"
27#include "tableactionmenu.h"
28#include "insertimagedialog.h"
29
30#include <kmime/kmime_codecs.h>
31
32#include <KDE/KAction>
33#include <KDE/KActionCollection>
34#include <KDE/KCursor>
35#include <KDE/KFileDialog>
36#include <KDE/KLocalizedString>
37#include <KDE/KMessageBox>
38#include <KDE/KPushButton>
39#include <KDE/KUrl>
40#include <KDE/KIcon>
41
42#include <QtCore/QBuffer>
43#include <QtCore/QDateTime>
44#include <QtCore/QMimeData>
45#include <QtCore/QFileInfo>
46#include <QtCore/QPointer>
47#include <QKeyEvent>
48#include <QTextLayout>
49
50#include "textutils.h"
51
52namespace KPIMTextEdit {
53
54class TextEditPrivate
55{
56 public:
57
58 TextEditPrivate( TextEdit *parent )
59 : actionAddImage( 0 ),
60 actionDeleteLine( 0 ),
61 actionAddEmoticon( 0 ),
62 actionInsertHtml( 0 ),
63 actionTable( 0 ),
64 actionFormatReset( 0 ),
65 q( parent ),
66 imageSupportEnabled( false ),
67 emoticonSupportEnabled( false ),
68 insertHtmlSupportEnabled( false ),
69 insertTableSupportEnabled( false ),
70 spellCheckingEnabled( false )
71 {
72 }
73
82 void addImageHelper( const QString &imageName, const QImage &image,
83 int width = -1, int height = -1 );
84
88 QList<QTextImageFormat> embeddedImageFormats() const;
89
94 void fixupTextEditString( QString &text ) const;
95
99 void init();
100
105 void _k_slotAddImage();
106
107 void _k_slotDeleteLine();
108
109 void _k_slotAddEmoticon( const QString & );
110
111 void _k_slotInsertHtml();
112
113 void _k_slotFormatReset();
114
115 void _k_slotTextModeChanged( KRichTextEdit::Mode );
116
118 KAction *actionAddImage;
119
121 KAction *actionDeleteLine;
122
123 EmoticonTextEditAction *actionAddEmoticon;
124
125 KAction *actionInsertHtml;
126
127 TableActionMenu *actionTable;
128
129 KAction *actionFormatReset;
130
132 TextEdit *q;
133
139 QStringList mImageNames;
140
141 QString configFile;
142 QFont saveFont;
144 bool imageSupportEnabled;
145
146 bool emoticonSupportEnabled;
147
148 bool insertHtmlSupportEnabled;
149
150 bool insertTableSupportEnabled;
151
163 bool spellCheckingEnabled;
164
165};
166
167} // namespace
168
169using namespace KPIMTextEdit;
170
171void TextEditPrivate::fixupTextEditString( QString &text ) const
172{
173 // Remove line separators. Normal \n chars are still there, so no linebreaks get lost here
174 text.remove( QChar::LineSeparator );
175
176 // Get rid of embedded images, see QTextImageFormat documentation:
177 // "Inline images are represented by an object replacement character (0xFFFC in Unicode) "
178 text.remove( 0xFFFC );
179
180 // In plaintext mode, each space is non-breaking.
181 text.replace( QChar::Nbsp, QChar::fromLatin1( ' ' ) );
182}
183
184TextEdit::TextEdit( const QString &text, QWidget *parent )
185 : KRichTextWidget( text, parent ),
186 d( new TextEditPrivate( this ) )
187{
188 d->init();
189}
190
191TextEdit::TextEdit( QWidget *parent )
192 : KRichTextWidget( parent ),
193 d( new TextEditPrivate( this ) )
194{
195 d->init();
196}
197
198TextEdit::TextEdit( QWidget *parent, const QString &configFile )
199 : KRichTextWidget( parent ),
200 d( new TextEditPrivate( this ) )
201{
202 d->init();
203 d->configFile = configFile;
204}
205
206TextEdit::~TextEdit()
207{
208}
209
210bool TextEdit::eventFilter( QObject *o, QEvent *e )
211{
212#ifndef QT_NO_CURSOR
213 if ( o == this ) {
214 KCursor::autoHideEventFilter( o, e );
215 }
216#endif
217 return KRichTextWidget::eventFilter( o, e );
218}
219
220void TextEditPrivate::init()
221{
222 q->connect( q, SIGNAL(textModeChanged(KRichTextEdit::Mode)),
223 q, SLOT(_k_slotTextModeChanged(KRichTextEdit::Mode)) );
224 q->setSpellInterface( q );
225 // We tell the KRichTextWidget to enable spell checking, because only then it will
226 // call createHighlighter() which will create our own highlighter which also
227 // does quote highlighting.
228 // However, *our* spellchecking is still disabled. Our own highlighter only
229 // cares about our spellcheck status, it will not highlight missspelled words
230 // if our spellchecking is disabled.
231 // See also KEMailQuotingHighlighter::highlightBlock().
232 spellCheckingEnabled = false;
233 q->setCheckSpellingEnabledInternal( true );
234
235#ifndef QT_NO_CURSOR
236 KCursor::setAutoHideCursor( q, true, true );
237#endif
238 q->installEventFilter( q );
239}
240
241QString TextEdit::configFile() const
242{
243 return d->configFile;
244}
245
246void TextEdit::keyPressEvent ( QKeyEvent * e )
247{
248 if ( e->key() == Qt::Key_Return ) {
249 QTextCursor cursor = textCursor();
250 int oldPos = cursor.position();
251 int blockPos = cursor.block().position();
252
253 //selection all the line.
254 cursor.movePosition( QTextCursor::StartOfBlock );
255 cursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
256 QString lineText = cursor.selectedText();
257 if ( ( ( oldPos - blockPos ) > 0 ) &&
258 ( ( oldPos - blockPos ) < int( lineText.length() ) ) ) {
259 bool isQuotedLine = false;
260 int bot = 0; // bot = begin of text after quote indicators
261 while ( bot < lineText.length() ) {
262 if ( ( lineText[bot] == QChar::fromLatin1( '>' ) ) ||
263 ( lineText[bot] == QChar::fromLatin1( '|' ) ) ) {
264 isQuotedLine = true;
265 ++bot;
266 } else if ( lineText[bot].isSpace() ) {
267 ++bot;
268 } else {
269 break;
270 }
271 }
272 KRichTextWidget::keyPressEvent( e );
273 // duplicate quote indicators of the previous line before the new
274 // line if the line actually contained text (apart from the quote
275 // indicators) and the cursor is behind the quote indicators
276 if ( isQuotedLine &&
277 ( bot != lineText.length() ) &&
278 ( ( oldPos - blockPos ) >= int( bot ) ) ) {
279 // The cursor position might have changed unpredictably if there was selected
280 // text which got replaced by a new line, so we query it again:
281 cursor.movePosition( QTextCursor::StartOfBlock );
282 cursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
283 QString newLine = cursor.selectedText();
284
285 // remove leading white space from the new line and instead
286 // add the quote indicators of the previous line
287 int leadingWhiteSpaceCount = 0;
288 while ( ( leadingWhiteSpaceCount < newLine.length() ) &&
289 newLine[leadingWhiteSpaceCount].isSpace() ) {
290 ++leadingWhiteSpaceCount;
291 }
292 newLine = newLine.replace( 0, leadingWhiteSpaceCount, lineText.left( bot ) );
293 cursor.insertText( newLine );
294 //cursor.setPosition( cursor.position() + 2 );
295 cursor.movePosition( QTextCursor::StartOfBlock );
296 setTextCursor( cursor );
297 }
298 } else {
299 KRichTextWidget::keyPressEvent( e );
300 }
301 } else {
302 KRichTextWidget::keyPressEvent( e );
303 }
304}
305
306bool TextEdit::isSpellCheckingEnabled() const
307{
308 return d->spellCheckingEnabled;
309}
310
311void TextEdit::setSpellCheckingEnabled( bool enable )
312{
313 EMailQuoteHighlighter *hlighter = dynamic_cast<EMailQuoteHighlighter*>( highlighter() );
314 if ( hlighter ) {
315 hlighter->toggleSpellHighlighting( enable );
316 }
317
318 d->spellCheckingEnabled = enable;
319 emit checkSpellingChanged( enable );
320}
321
322bool TextEdit::shouldBlockBeSpellChecked( const QString &block ) const
323{
324 return !isLineQuoted( block );
325}
326
327bool KPIMTextEdit::TextEdit::isLineQuoted( const QString &line ) const
328{
329 return quoteLength( line ) > 0;
330}
331
332int KPIMTextEdit::TextEdit::quoteLength( const QString &line ) const
333{
334 bool quoteFound = false;
335 int startOfText = -1;
336 const int lineLength( line.length() );
337 for ( int i = 0; i < lineLength; ++i ) {
338 if ( line[i] == QLatin1Char( '>' ) || line[i] == QLatin1Char( '|' ) ) {
339 quoteFound = true;
340 } else if ( line[i] != QLatin1Char( ' ' ) ) {
341 startOfText = i;
342 break;
343 }
344 }
345 if ( quoteFound ) {
346 if ( startOfText == -1 ) {
347 startOfText = line.length() - 1;
348 }
349 return startOfText;
350 } else {
351 return 0;
352 }
353}
354
355const QString KPIMTextEdit::TextEdit::defaultQuoteSign() const
356{
357 return QLatin1String( "> " );
358}
359
360void TextEdit::createHighlighter()
361{
362 EMailQuoteHighlighter *emailHighLighter = new EMailQuoteHighlighter( this );
363
364 setHighlighterColors( emailHighLighter );
365
366 //TODO change config
367 KRichTextWidget::setHighlighter( emailHighLighter );
368
369 if ( !spellCheckingLanguage().isEmpty() ) {
370 setSpellCheckingLanguage( spellCheckingLanguage() );
371 }
372 setSpellCheckingEnabled( isSpellCheckingEnabled() );
373}
374
375void TextEdit::setHighlighterColors( EMailQuoteHighlighter *highlighter )
376{
377 Q_UNUSED( highlighter );
378}
379
380QString TextEdit::toWrappedPlainText() const
381{
382 QTextDocument *doc = document();
383 return toWrappedPlainText( doc );
384}
385
386QString TextEdit::toWrappedPlainText( QTextDocument *doc ) const
387{
388 QString temp;
389 QRegExp rx( QLatin1String( "(http|ftp|ldap)s?\\S+-$" ) );
390 QTextBlock block = doc->begin();
391 while ( block.isValid() ) {
392 QTextLayout *layout = block.layout();
393 const int numberOfLine( layout->lineCount() );
394 bool urlStart = false;
395 for ( int i = 0; i < numberOfLine; ++i ) {
396 QTextLine line = layout->lineAt( i );
397 QString lineText = block.text().mid( line.textStart(), line.textLength() );
398
399 if ( lineText.contains( rx ) ||
400 ( urlStart && !lineText.contains( QLatin1Char( ' ' ) ) &&
401 lineText.endsWith( QLatin1Char( '-' ) ) ) ) {
402 // don't insert line break in URL
403 temp += lineText;
404 urlStart = true;
405 } else {
406 temp += lineText + QLatin1Char( '\n' );
407 }
408 }
409 block = block.next();
410 }
411
412 // Remove the last superfluous newline added above
413 if ( temp.endsWith( QLatin1Char( '\n' ) ) ) {
414 temp.chop( 1 );
415 }
416
417 d->fixupTextEditString( temp );
418 return temp;
419}
420
421QString TextEdit::toCleanPlainText( const QString &plainText ) const
422{
423 QString temp = plainText;
424 d->fixupTextEditString( temp );
425 return temp;
426}
427
428QString TextEdit::toCleanPlainText() const
429{
430 return toCleanPlainText( toPlainText() );
431}
432
433void TextEdit::createActions( KActionCollection *actionCollection )
434{
435 KRichTextWidget::createActions( actionCollection );
436
437 if ( d->imageSupportEnabled ) {
438 d->actionAddImage = new KAction( KIcon( QLatin1String( "insert-image" ) ),
439 i18n( "Add Image" ), this );
440 actionCollection->addAction( QLatin1String( "add_image" ), d->actionAddImage );
441 connect( d->actionAddImage, SIGNAL(triggered(bool)), SLOT(_k_slotAddImage()) );
442 }
443 if ( d->emoticonSupportEnabled ) {
444 d->actionAddEmoticon = new EmoticonTextEditAction( this );
445 actionCollection->addAction( QLatin1String( "add_emoticon" ), d->actionAddEmoticon );
446 connect( d->actionAddEmoticon, SIGNAL(emoticonActivated(QString)),
447 SLOT(_k_slotAddEmoticon(QString)) );
448 }
449
450 if ( d->insertHtmlSupportEnabled ) {
451 d->actionInsertHtml = new KAction( i18n( "Insert HTML" ), this );
452 actionCollection->addAction( QLatin1String( "insert_html" ), d->actionInsertHtml );
453 connect( d->actionInsertHtml, SIGNAL(triggered(bool)), SLOT(_k_slotInsertHtml()) );
454 }
455
456 if ( d->insertTableSupportEnabled ) {
457 d->actionTable = new TableActionMenu( actionCollection, this );
458 d->actionTable->setIcon( KIcon( QLatin1String( "insert-table" ) ) );
459 d->actionTable->setText( i18n( "Table" ) );
460 d->actionTable->setDelayed( false );
461 actionCollection->addAction( QLatin1String( "insert_table" ), d->actionTable );
462 }
463
464 d->actionDeleteLine = new KAction( i18n( "Delete Line" ), this );
465 d->actionDeleteLine->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_K ) );
466 actionCollection->addAction( QLatin1String( "delete_line" ), d->actionDeleteLine );
467 connect( d->actionDeleteLine, SIGNAL(triggered(bool)), SLOT(_k_slotDeleteLine()) );
468
469 d->actionFormatReset =
470 new KAction( KIcon( QLatin1String( "draw-eraser" ) ), i18n( "Reset Font Settings" ), this );
471 d->actionFormatReset->setIconText( i18n( "Reset Font" ) );
472 actionCollection->addAction( QLatin1String( "format_reset" ), d->actionFormatReset );
473 connect( d->actionFormatReset, SIGNAL(triggered(bool)), SLOT(_k_slotFormatReset()) );
474}
475
476void TextEdit::addImage( const KUrl &url, int width, int height )
477{
478 addImageHelper( url, width, height );
479}
480
481void TextEdit::addImage( const KUrl &url )
482{
483 addImageHelper( url );
484}
485
486void TextEdit::addImageHelper( const KUrl &url, int width, int height )
487{
488 QImage image;
489 if ( !image.load( url.path() ) ) {
490 KMessageBox::error(
491 this,
492 i18nc( "@info",
493 "Unable to load image <filename>%1</filename>.",
494 url.path() ) );
495 return;
496 }
497 QFileInfo fi( url.path() );
498 QString imageName =
499 fi.baseName().isEmpty() ?
500 QLatin1String( "image.png" ) :
501 QString( fi.baseName() + QLatin1String( ".png" ) );
502 d->addImageHelper( imageName, image, width, height );
503}
504
505void TextEdit::loadImage ( const QImage &image, const QString &matchName,
506 const QString &resourceName )
507{
508 QSet<int> cursorPositionsToSkip;
509 QTextBlock currentBlock = document()->begin();
510 QTextBlock::iterator it;
511 while ( currentBlock.isValid() ) {
512 for ( it = currentBlock.begin(); !it.atEnd(); ++it ) {
513 QTextFragment fragment = it.fragment();
514 if ( fragment.isValid() ) {
515 QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
516 if ( imageFormat.isValid() && imageFormat.name() == matchName ) {
517 int pos = fragment.position();
518 if ( !cursorPositionsToSkip.contains( pos ) ) {
519 QTextCursor cursor( document() );
520 cursor.setPosition( pos );
521 cursor.setPosition( pos + 1, QTextCursor::KeepAnchor );
522 cursor.removeSelectedText();
523 document()->addResource( QTextDocument::ImageResource,
524 QUrl( resourceName ), QVariant( image ) );
525 QTextImageFormat format;
526 format.setName( resourceName );
527 if ( ( imageFormat.width() != 0 ) && ( imageFormat.height() != 0 ) ) {
528 format.setWidth( imageFormat.width() );
529 format.setHeight( imageFormat.height() );
530 }
531 cursor.insertImage( format );
532
533 // The textfragment iterator is now invalid, restart from the beginning
534 // Take care not to replace the same fragment again, or we would be in
535 // an infinite loop.
536 cursorPositionsToSkip.insert( pos );
537 it = currentBlock.begin();
538 }
539 }
540 }
541 }
542 currentBlock = currentBlock.next();
543 }
544}
545
546void TextEditPrivate::addImageHelper( const QString &imageName, const QImage &image,
547 int width, int height )
548{
549 QString imageNameToAdd = imageName;
550 QTextDocument *document = q->document();
551
552 // determine the imageNameToAdd
553 int imageNumber = 1;
554 while ( mImageNames.contains( imageNameToAdd ) ) {
555 QVariant qv = document->resource( QTextDocument::ImageResource, QUrl( imageNameToAdd ) );
556 if ( qv == image ) {
557 // use the same name
558 break;
559 }
560 int firstDot = imageName.indexOf( QLatin1Char( '.' ) );
561 if ( firstDot == -1 ) {
562 imageNameToAdd = imageName + QString::number( imageNumber++ );
563 } else {
564 imageNameToAdd = imageName.left( firstDot ) + QString::number( imageNumber++ ) +
565 imageName.mid( firstDot );
566 }
567 }
568
569 if ( !mImageNames.contains( imageNameToAdd ) ) {
570 document->addResource( QTextDocument::ImageResource, QUrl( imageNameToAdd ), image );
571 mImageNames << imageNameToAdd;
572 }
573 if ( width != -1 && height != -1 ) {
574 QTextImageFormat format;
575 format.setName( imageNameToAdd );
576 format.setWidth( width );
577 format.setHeight( height );
578 q->textCursor().insertImage( format );
579 } else {
580 q->textCursor().insertImage( imageNameToAdd );
581 }
582 q->enableRichTextMode();
583}
584
585ImageWithNameList TextEdit::imagesWithName() const
586{
587 ImageWithNameList retImages;
588 QStringList seenImageNames;
589 QList<QTextImageFormat> imageFormats = d->embeddedImageFormats();
590 foreach ( const QTextImageFormat &imageFormat, imageFormats ) {
591 if ( !seenImageNames.contains( imageFormat.name() ) ) {
592 QVariant resourceData = document()->resource( QTextDocument::ImageResource,
593 QUrl( imageFormat.name() ) );
594 QImage image = qvariant_cast<QImage>( resourceData );
595 QString name = imageFormat.name();
596 ImageWithNamePtr newImage( new ImageWithName );
597 newImage->image = image;
598 newImage->name = name;
599 retImages.append( newImage );
600 seenImageNames.append( imageFormat.name() );
601 }
602 }
603 return retImages;
604}
605
606QList< QSharedPointer<EmbeddedImage> > TextEdit::embeddedImages() const
607{
608 ImageWithNameList normalImages = imagesWithName();
609 QList< QSharedPointer<EmbeddedImage> > retImages;
610 foreach ( const ImageWithNamePtr &normalImage, normalImages ) {
611 QBuffer buffer;
612 buffer.open( QIODevice::WriteOnly );
613 normalImage->image.save( &buffer, "PNG" );
614
615 qsrand( QDateTime::currentDateTime().toTime_t() + qHash( normalImage->name ) );
616 QSharedPointer<EmbeddedImage> embeddedImage( new EmbeddedImage() );
617 retImages.append( embeddedImage );
618 embeddedImage->image = KMime::Codec::codecForName( "base64" )->encode( buffer.buffer() );
619 embeddedImage->imageName = normalImage->name;
620 embeddedImage->contentID = QString( QLatin1String( "%1@KDE" ) ).arg( qrand() );
621 }
622 return retImages;
623}
624
625QList<QTextImageFormat> TextEditPrivate::embeddedImageFormats() const
626{
627 QTextDocument *doc = q->document();
628 QList<QTextImageFormat> retList;
629
630 QTextBlock currentBlock = doc->begin();
631 while ( currentBlock.isValid() ) {
632 QTextBlock::iterator it;
633 for ( it = currentBlock.begin(); !it.atEnd(); ++it ) {
634 QTextFragment fragment = it.fragment();
635 if ( fragment.isValid() ) {
636 QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
637 if ( imageFormat.isValid() ) {
638 //TODO: Replace with a way to see if an image is an embedded image or a remote
639 QUrl url( imageFormat.name() );
640 if ( !url.isValid() || !url.scheme().startsWith( QLatin1String( "http" ) ) ) {
641 retList.append( imageFormat );
642 }
643 }
644 }
645 }
646 currentBlock = currentBlock.next();
647 }
648 return retList;
649}
650
651void TextEditPrivate::_k_slotAddEmoticon( const QString &text )
652{
653 QTextCursor cursor = q->textCursor();
654 cursor.insertText( text );
655}
656
657void TextEditPrivate::_k_slotInsertHtml()
658{
659 if ( q->textMode() == KRichTextEdit::Rich ) {
660 QPointer<InsertHtmlDialog> dialog = new InsertHtmlDialog( q );
661 if ( dialog->exec() ) {
662 const QString str = dialog->html();
663 if ( !str.isEmpty() ) {
664 QTextCursor cursor = q->textCursor();
665 cursor.insertHtml( str );
666 }
667 }
668 delete dialog;
669 }
670}
671
672void TextEditPrivate::_k_slotAddImage()
673{
674 QPointer<InsertImageDialog> dlg = new InsertImageDialog( q );
675 if ( dlg->exec() == KDialog::Accepted && dlg ) {
676 const KUrl url = dlg->imageUrl();
677 int imageWidth = -1;
678 int imageHeight = -1;
679 if ( !dlg->keepOriginalSize() ) {
680 imageWidth = dlg->imageWidth();
681 imageHeight = dlg->imageHeight();
682 }
683 q->addImage( url, imageWidth, imageHeight );
684 }
685 delete dlg;
686}
687
688void TextEditPrivate::_k_slotTextModeChanged( KRichTextEdit::Mode mode )
689{
690 if ( mode == KRichTextEdit::Rich ) {
691 saveFont = q->currentFont();
692 }
693}
694
695void TextEditPrivate::_k_slotFormatReset()
696{
697 q->setTextBackgroundColor( q->palette().highlightedText().color() );
698 q->setTextForegroundColor( q->palette().text().color() );
699 q->setFont( saveFont );
700
701}
702
703void KPIMTextEdit::TextEdit::enableImageActions()
704{
705 d->imageSupportEnabled = true;
706}
707
708bool KPIMTextEdit::TextEdit::isEnableImageActions() const
709{
710 return d->imageSupportEnabled;
711}
712
713void KPIMTextEdit::TextEdit::enableEmoticonActions()
714{
715 d->emoticonSupportEnabled = true;
716}
717
718bool KPIMTextEdit::TextEdit::isEnableEmoticonActions() const
719{
720 return d->emoticonSupportEnabled;
721}
722
723void KPIMTextEdit::TextEdit::enableInsertHtmlActions()
724{
725 d->insertHtmlSupportEnabled = true;
726}
727
728bool KPIMTextEdit::TextEdit::isEnableInsertHtmlActions() const
729{
730 return d->insertHtmlSupportEnabled;
731}
732
733bool KPIMTextEdit::TextEdit::isEnableInsertTableActions() const
734{
735 return d->insertTableSupportEnabled;
736}
737
738void KPIMTextEdit::TextEdit::enableInsertTableActions()
739{
740 d->insertTableSupportEnabled = true;
741}
742
743QByteArray KPIMTextEdit::TextEdit::imageNamesToContentIds(
744 const QByteArray &htmlBody, const KPIMTextEdit::ImageList &imageList )
745{
746 QByteArray result = htmlBody;
747 if ( !imageList.isEmpty() ) {
748 foreach ( const QSharedPointer<EmbeddedImage> &image, imageList ) {
749 const QString newImageName = QLatin1String( "cid:" ) + image->contentID;
750 QByteArray quote( "\"" );
751 result.replace( QByteArray( quote + image->imageName.toLocal8Bit() + quote ),
752 QByteArray( quote + newImageName.toLocal8Bit() + quote ) );
753 }
754 }
755 return result;
756}
757
758void TextEdit::insertImage( const QImage &image, const QFileInfo &fileInfo )
759{
760 QString imageName = fileInfo.baseName().isEmpty() ?
761 i18nc( "Start of the filename for an image", "image" ) :
762 fileInfo.baseName();
763 d->addImageHelper( imageName, image );
764}
765
766void TextEdit::insertFromMimeData( const QMimeData *source )
767{
768 // Add an image if that is on the clipboard
769 if ( textMode() == KRichTextEdit::Rich && source->hasImage() && d->imageSupportEnabled ) {
770 QImage image = qvariant_cast<QImage>( source->imageData() );
771 QFileInfo fi;
772 insertImage( image, fi );
773 return;
774 }
775
776 // Attempt to paste HTML contents into the text edit in plain text mode,
777 // prevent this and prevent plain text instead.
778 if ( textMode() == KRichTextEdit::Plain && source->hasHtml() ) {
779 if ( source->hasText() ) {
780 insertPlainText( source->text() );
781 return;
782 }
783 }
784
785 KRichTextWidget::insertFromMimeData( source );
786}
787
788bool KPIMTextEdit::TextEdit::canInsertFromMimeData( const QMimeData *source ) const
789{
790 if ( source->hasHtml() && textMode() == KRichTextEdit::Rich ) {
791 return true;
792 }
793
794 if ( source->hasText() ) {
795 return true;
796 }
797
798 if ( textMode() == KRichTextEdit::Rich && source->hasImage() && d->imageSupportEnabled ) {
799 return true;
800 }
801
802 return KRichTextWidget::canInsertFromMimeData( source );
803}
804
805bool TextEdit::isFormattingUsed() const
806{
807 if ( textMode() == Plain ) {
808 return false;
809 }
810
811 return TextUtils::containsFormatting( document() );
812}
813
814void TextEditPrivate::_k_slotDeleteLine()
815{
816 if ( q->hasFocus() ) {
817 q->deleteCurrentLine();
818 }
819}
820
821void TextEdit::deleteCurrentLine()
822{
823 QTextCursor cursor = textCursor();
824 QTextBlock block = cursor.block();
825 const QTextLayout *layout = block.layout();
826
827 // The current text block can have several lines due to word wrapping.
828 // Search the line the cursor is in, and then delete it.
829 for ( int lineNumber = 0; lineNumber < layout->lineCount(); lineNumber++ ) {
830 QTextLine line = layout->lineAt( lineNumber );
831 const bool lastLineInBlock = ( line.textStart() + line.textLength() == block.length() - 1 );
832 const bool oneLineBlock = ( layout->lineCount() == 1 );
833 const int startOfLine = block.position() + line.textStart();
834 int endOfLine = block.position() + line.textStart() + line.textLength();
835 if ( !lastLineInBlock ) {
836 endOfLine -= 1;
837 }
838
839 // Found the line where the cursor is in
840 if ( cursor.position() >= startOfLine && cursor.position() <= endOfLine ) {
841 int deleteStart = startOfLine;
842 int deleteLength = line.textLength();
843 if ( oneLineBlock ) {
844 deleteLength++; // The trailing newline
845 }
846
847 // When deleting the last line in the document,
848 // remove the newline of the line before the last line instead
849 if ( deleteStart + deleteLength >= document()->characterCount() &&
850 deleteStart > 0 ) {
851 deleteStart--;
852 }
853
854 cursor.beginEditBlock();
855 cursor.setPosition( deleteStart );
856 cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor, deleteLength );
857 cursor.removeSelectedText();
858 cursor.endEditBlock();
859 return;
860 }
861 }
862}
863
864#include "moc_textedit.cpp"
KPIMTextEdit::EMailQuoteHighlighter
This highlighter highlights spelling mistakes and also highlightes quotes.
Definition: emailquotehighlighter.h:45
KPIMTextEdit::EMailQuoteHighlighter::toggleSpellHighlighting
void toggleSpellHighlighting(bool on)
Turns spellcheck highlighting on or off.
Definition: emailquotehighlighter.cpp:119
KPIMTextEdit::TextEdit
Special textedit that provides additional features which are useful for PIM applications like mail cl...
Definition: textedit.h:87
KPIMTextEdit::TextEdit::quoteLength
virtual int quoteLength(const QString &line) const
This is called whenever the editor needs to find out the length of the quote, i.e.
Definition: textedit.cpp:332
KPIMTextEdit::TextEdit::isEnableImageActions
bool isEnableImageActions() const
Return true if richtext mode support image.
Definition: textedit.cpp:708
KPIMTextEdit::TextEdit::createActions
virtual void createActions(KActionCollection *actionCollection)
Reimplemented from KMEditor, to support more actions.
Definition: textedit.cpp:433
KPIMTextEdit::TextEdit::setSpellCheckingEnabled
virtual void setSpellCheckingEnabled(bool enable)
Reimplemented from KTextEditSpellInterface.
Definition: textedit.cpp:311
KPIMTextEdit::TextEdit::createHighlighter
virtual void createHighlighter()
Reimplemented to create our own highlighter which does quote and spellcheck highlighting.
Definition: textedit.cpp:360
KPIMTextEdit::TextEdit::shouldBlockBeSpellChecked
virtual bool shouldBlockBeSpellChecked(const QString &block) const
Reimplemented from KTextEditSpellInterface, to avoid spellchecking quoted text.
Definition: textedit.cpp:322
KPIMTextEdit::TextEdit::isEnableInsertHtmlActions
bool isEnableInsertHtmlActions() const
Definition: textedit.cpp:728
KPIMTextEdit::TextEdit::canInsertFromMimeData
virtual bool canInsertFromMimeData(const QMimeData *source) const
Reimplemented for inline image support.
Definition: textedit.cpp:788
KPIMTextEdit::TextEdit::isSpellCheckingEnabled
virtual bool isSpellCheckingEnabled() const
Reimplemented from KTextEditSpellInterface.
Definition: textedit.cpp:306
KPIMTextEdit::TextEdit::insertFromMimeData
virtual void insertFromMimeData(const QMimeData *source)
Reimplemented for inline image support.
Definition: textedit.cpp:766
KPIMTextEdit::TextEdit::isFormattingUsed
bool isFormattingUsed() const
Checks if rich text formatting is used anywhere.
Definition: textedit.cpp:805
KPIMTextEdit::TextEdit::enableEmoticonActions
void enableEmoticonActions()
Calling this allows createActions() to create the add emoticons actions.
Definition: textedit.cpp:713
KPIMTextEdit::TextEdit::isEnableEmoticonActions
bool isEnableEmoticonActions() const
Return true if emoticons actions supported.
Definition: textedit.cpp:718
KPIMTextEdit::TextEdit::loadImage
void loadImage(const QImage &image, const QString &matchName, const QString &resourceName)
Loads an image into the textedit.
Definition: textedit.cpp:505
KPIMTextEdit::TextEdit::TextEdit
TextEdit(const QString &text, QWidget *parent=0)
Constructs a TextEdit object.
Definition: textedit.cpp:184
KPIMTextEdit::TextEdit::configFile
QString configFile() const
Return config file.
Definition: textedit.cpp:241
KPIMTextEdit::TextEdit::~TextEdit
~TextEdit()
Destructor.
Definition: textedit.cpp:206
KPIMTextEdit::TextEdit::addImage
void addImage(const KUrl &url)
Adds an image.
Definition: textedit.cpp:481
KPIMTextEdit::TextEdit::eventFilter
virtual bool eventFilter(QObject *o, QEvent *e)
Reimplemented from KRichTextWidget to hide the mouse cursor when there was no mouse movement for some...
Definition: textedit.cpp:210
KPIMTextEdit::TextEdit::imageNamesToContentIds
static QByteArray imageNamesToContentIds(const QByteArray &htmlBody, const ImageList &imageList)
For all given embedded images, this function replace the image name in the.
Definition: textedit.cpp:743
KPIMTextEdit::TextEdit::isLineQuoted
bool isLineQuoted(const QString &line) const
Convenience method for qouteLength( line ) > 0.
Definition: textedit.cpp:327
KPIMTextEdit::TextEdit::isEnableInsertTableActions
bool isEnableInsertTableActions() const
Definition: textedit.cpp:733
KPIMTextEdit::TextEdit::embeddedImages
ImageList embeddedImages() const
Get a list with all embedded HTML images.
Definition: textedit.cpp:606
KPIMTextEdit::TextEdit::insertImage
void insertImage(const QImage &image, const QFileInfo &info)
Definition: textedit.cpp:758
KPIMTextEdit::TextEdit::deleteCurrentLine
void deleteCurrentLine()
Deletes the line at the current cursor position.
Definition: textedit.cpp:821
KPIMTextEdit::TextEdit::keyPressEvent
virtual void keyPressEvent(QKeyEvent *e)
Reimplemented to add qoute signs when the user presses enter on a quoted line.
Definition: textedit.cpp:246
KPIMTextEdit::TextEdit::defaultQuoteSign
virtual const QString defaultQuoteSign() const
Returns the prefix that is added to a line that is quoted.
Definition: textedit.cpp:355
KPIMTextEdit::TextEdit::enableImageActions
void enableImageActions()
Calling this allows createActions() to create the add image actions.
Definition: textedit.cpp:703
KPIMTextEdit::TextEdit::imagesWithName
ImageWithNameList imagesWithName() const
Same as embeddedImages(), only that this returns a list of general purpose information,...
Definition: textedit.cpp:585
KPIMTextEdit::TextEdit::setHighlighterColors
virtual void setHighlighterColors(EMailQuoteHighlighter *highlighter)
This method is called after the highlighter is created.
Definition: textedit.cpp:375
KPIMTextEdit::TextEdit::toWrappedPlainText
QString toWrappedPlainText() const
Returns the text of the editor as plain text, with linebreaks inserted where word-wrapping occurred.
Definition: textedit.cpp:380
KPIMTextEdit::TextEdit::toCleanPlainText
QString toCleanPlainText() const
Same as toPlainText() from QTextEdit, only that it removes embedded images and converts non-breaking ...
Definition: textedit.cpp:428
KPIMTextEdit::TextUtils::containsFormatting
KPIMTEXTEDIT_EXPORT bool containsFormatting(const QTextDocument *document)
Returns whether the QTextDocument document contains rich text formatting.
Definition: textutils.cpp:69
KPIMTextEdit
Copyright (C) 2006 Laurent Montel montel@kde.org Copyright (C) 2008 Thomas McGuire mcguire@kde....
Definition: emailquotehighlighter.cpp:25
KPIMTextEdit::EmbeddedImage
Holds information about an embedded HTML image that will be useful for mail clients.
Definition: textedit.h:51
KPIMTextEdit::ImageWithName
Holds information about an embedded HTML image that will be generally useful.
Definition: textedit.h:64
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jul 21 2022 00:00:00 by doxygen 1.9.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KPIMTextedit Library

Skip menu "KPIMTextedit Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal