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

Skip menu "kdepimlibs-4.14.7 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