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

KPIMTextedit Library

  • sources
  • kde-4.14
  • kdepimlibs
  • 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 
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 
169 using namespace KPIMTextEdit;
170 
171 void 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 
184 TextEdit::TextEdit( const QString &text, QWidget *parent )
185  : KRichTextWidget( text, parent ),
186  d( new TextEditPrivate( this ) )
187 {
188  d->init();
189 }
190 
191 TextEdit::TextEdit( QWidget *parent )
192  : KRichTextWidget( parent ),
193  d( new TextEditPrivate( this ) )
194 {
195  d->init();
196 }
197 
198 TextEdit::TextEdit( QWidget *parent, const QString &configFile )
199  : KRichTextWidget( parent ),
200  d( new TextEditPrivate( this ) )
201 {
202  d->init();
203  d->configFile = configFile;
204 }
205 
206 TextEdit::~TextEdit()
207 {
208 }
209 
210 bool 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 
220 void 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 
241 QString TextEdit::configFile() const
242 {
243  return d->configFile;
244 }
245 
246 void 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 
306 bool TextEdit::isSpellCheckingEnabled() const
307 {
308  return d->spellCheckingEnabled;
309 }
310 
311 void 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 
322 bool TextEdit::shouldBlockBeSpellChecked( const QString &block ) const
323 {
324  return !isLineQuoted( block );
325 }
326 
327 bool KPIMTextEdit::TextEdit::isLineQuoted( const QString &line ) const
328 {
329  return quoteLength( line ) > 0;
330 }
331 
332 int 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 
355 const QString KPIMTextEdit::TextEdit::defaultQuoteSign() const
356 {
357  return QLatin1String( "> " );
358 }
359 
360 void 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 
375 void TextEdit::setHighlighterColors( EMailQuoteHighlighter *highlighter )
376 {
377  Q_UNUSED( highlighter );
378 }
379 
380 QString TextEdit::toWrappedPlainText() const
381 {
382  QTextDocument *doc = document();
383  return toWrappedPlainText( doc );
384 }
385 
386 QString 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 
421 QString TextEdit::toCleanPlainText( const QString &plainText ) const
422 {
423  QString temp = plainText;
424  d->fixupTextEditString( temp );
425  return temp;
426 }
427 
428 QString TextEdit::toCleanPlainText() const
429 {
430  return toCleanPlainText( toPlainText() );
431 }
432 
433 void 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 
476 void TextEdit::addImage( const KUrl &url, int width, int height )
477 {
478  addImageHelper( url, width, height );
479 }
480 
481 void TextEdit::addImage( const KUrl &url )
482 {
483  addImageHelper( url );
484 }
485 
486 void 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 
505 void 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 
546 void 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 
585 ImageWithNameList 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 
606 QList< 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 
625 QList<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 
651 void TextEditPrivate::_k_slotAddEmoticon( const QString &text )
652 {
653  QTextCursor cursor = q->textCursor();
654  cursor.insertText( text );
655 }
656 
657 void 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 
672 void 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 
688 void TextEditPrivate::_k_slotTextModeChanged( KRichTextEdit::Mode mode )
689 {
690  if ( mode == KRichTextEdit::Rich ) {
691  saveFont = q->currentFont();
692  }
693 }
694 
695 void 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 
703 void KPIMTextEdit::TextEdit::enableImageActions()
704 {
705  d->imageSupportEnabled = true;
706 }
707 
708 bool KPIMTextEdit::TextEdit::isEnableImageActions() const
709 {
710  return d->imageSupportEnabled;
711 }
712 
713 void KPIMTextEdit::TextEdit::enableEmoticonActions()
714 {
715  d->emoticonSupportEnabled = true;
716 }
717 
718 bool KPIMTextEdit::TextEdit::isEnableEmoticonActions() const
719 {
720  return d->emoticonSupportEnabled;
721 }
722 
723 void KPIMTextEdit::TextEdit::enableInsertHtmlActions()
724 {
725  d->insertHtmlSupportEnabled = true;
726 }
727 
728 bool KPIMTextEdit::TextEdit::isEnableInsertHtmlActions() const
729 {
730  return d->insertHtmlSupportEnabled;
731 }
732 
733 bool KPIMTextEdit::TextEdit::isEnableInsertTableActions() const
734 {
735  return d->insertTableSupportEnabled;
736 }
737 
738 void KPIMTextEdit::TextEdit::enableInsertTableActions()
739 {
740  d->insertTableSupportEnabled = true;
741 }
742 
743 QByteArray 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 
758 void 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 
766 void 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 
788 bool 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 
805 bool TextEdit::isFormattingUsed() const
806 {
807  if ( textMode() == Plain ) {
808  return false;
809  }
810 
811  return TextUtils::containsFormatting( document() );
812 }
813 
814 void TextEditPrivate::_k_slotDeleteLine()
815 {
816  if ( q->hasFocus() ) {
817  q->deleteCurrentLine();
818  }
819 }
820 
821 void 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"
QTextCursor::position
int position() const
KPIMTextEdit::TextEdit::setHighlighterColors
virtual void setHighlighterColors(EMailQuoteHighlighter *highlighter)
This method is called after the highlighter is created.
Definition: textedit.cpp:375
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QEvent
QWidget
QTextCursor::removeSelectedText
void removeSelectedText()
QTextFragment::position
int position() const
QImage::load
bool load(QIODevice *device, const char *format)
KPIMTextEdit::EmbeddedImage
Holds information about an embedded HTML image that will be useful for mail clients.
Definition: textedit.h:50
QTextCursor
QTextBlock::begin
iterator begin() const
QTextBlock::position
int position() const
KPIMTextEdit::TextEdit::insertImage
void insertImage(const QImage &image, const QFileInfo &info)
Definition: textedit.cpp:758
KPIMTextEdit::TextEdit::canInsertFromMimeData
virtual bool canInsertFromMimeData(const QMimeData *source) const
Reimplemented for inline image support.
Definition: textedit.cpp:788
QTextBlock::next
QTextBlock next() const
QTextCursor::insertHtml
void insertHtml(const QString &html)
QByteArray
KPIMTextEdit::TextEdit::insertFromMimeData
virtual void insertFromMimeData(const QMimeData *source)
Reimplemented for inline image support.
Definition: textedit.cpp:766
QTextDocument::resource
QVariant resource(int type, const QUrl &name) const
KPIMTextEdit::TextEdit::isLineQuoted
bool isLineQuoted(const QString &line) const
Convenience method for qouteLength( line ) > 0.
Definition: textedit.cpp:327
KPIMTextEdit::TextEdit::isEnableImageActions
bool isEnableImageActions() const
Return true if richtext mode support image.
Definition: textedit.cpp:708
KPIMTextEdit::TextEdit::enableImageActions
void enableImageActions()
Calling this allows createActions() to create the add image actions.
Definition: textedit.cpp:703
QFont
QTextCursor::selectedText
QString selectedText() const
QPointer
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
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
QBuffer
QMimeData::hasText
bool hasText() const
KPIMTextEdit::TextEdit::embeddedImages
ImageList embeddedImages() const
Get a list with all embedded HTML images.
Definition: textedit.cpp:606
QSet::insert
const_iterator insert(const T &value)
QString::remove
QString & remove(int position, int n)
QString::chop
void chop(int n)
QMimeData
QBuffer::buffer
QByteArray & buffer()
QTextCursor::movePosition
bool movePosition(MoveOperation operation, MoveMode mode, int n)
QTextImageFormat::setName
void setName(const QString &name)
QTextDocument::begin
QTextBlock begin() const
KPIMTextEdit::TextEdit::loadImage
void loadImage(const QImage &image, const QString &matchName, const QString &resourceName)
Loads an image into the textedit.
Definition: textedit.cpp:505
QRegExp
QTextFragment::charFormat
QTextCharFormat charFormat() const
KPIMTextEdit::TextEdit::createHighlighter
virtual void createHighlighter()
Reimplemented to create our own highlighter which does quote and spellcheck highlighting.
Definition: textedit.cpp:360
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::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
QString::number
QString number(int n, int base)
KPIMTextEdit::TextEdit::TextEdit
TextEdit(const QString &text, QWidget *parent=0)
Constructs a TextEdit object.
Definition: textedit.cpp:184
KPIMTextEdit::TextEdit::setSpellCheckingEnabled
virtual void setSpellCheckingEnabled(bool enable)
Reimplemented from KTextEditSpellInterface.
Definition: textedit.cpp:311
QTextImageFormat::isValid
bool isValid() const
QList::append
void append(const T &value)
KPIMTextEdit::TextEdit::isEnableInsertHtmlActions
bool isEnableInsertHtmlActions() const
Definition: textedit.cpp:728
KPIMTextEdit::TextEdit::deleteCurrentLine
void deleteCurrentLine()
Deletes the line at the current cursor position.
Definition: textedit.cpp:821
QMimeData::hasHtml
bool hasHtml() const
QTextImageFormat
QMimeData::text
QString text() const
QSharedPointer
QTextDocument::addResource
void addResource(int type, const QUrl &name, const QVariant &resource)
QObject
KPIMTextEdit::TextEdit::createActions
virtual void createActions(KActionCollection *actionCollection)
Reimplemented from KMEditor, to support more actions.
Definition: textedit.cpp:433
QChar::fromLatin1
QChar fromLatin1(char c)
QTextImageFormat::setWidth
void setWidth(qreal width)
QTextFragment::isValid
bool isValid() const
QTextCursor::endEditBlock
void endEditBlock()
QTextCursor::insertText
void insertText(const QString &text)
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
QTextLayout
QByteArray::replace
QByteArray & replace(int pos, int len, const char *after)
QTextBlock::isValid
bool isValid() const
KPIMTextEdit::TextEdit::isFormattingUsed
bool isFormattingUsed() const
Checks if rich text formatting is used anywhere.
Definition: textedit.cpp:805
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
QBuffer::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > flags)
QSet
QString
QList
QTextLine::textStart
int textStart() const
QTextImageFormat::height
qreal height() const
QTextBlock::layout
QTextLayout * layout() const
QStringList
KPIMTextEdit::EMailQuoteHighlighter
This highlighter highlights spelling mistakes and also highlightes quotes.
Definition: emailquotehighlighter.h:44
QFileInfo
QString::toLocal8Bit
QByteArray toLocal8Bit() const
QKeyEvent::key
int key() const
QTextCursor::block
QTextBlock block() const
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QUrl
QLatin1Char
KPIMTextEdit::TextEdit::shouldBlockBeSpellChecked
virtual bool shouldBlockBeSpellChecked(const QString &block) const
Reimplemented from KTextEditSpellInterface, to avoid spellchecking quoted text.
Definition: textedit.cpp:322
QTextCursor::beginEditBlock
void beginEditBlock()
QTextBlock::text
QString text() const
QImage
QSet::contains
bool contains(const T &value) const
KPIMTextEdit::TextEdit::isSpellCheckingEnabled
virtual bool isSpellCheckingEnabled() const
Reimplemented from KTextEditSpellInterface.
Definition: textedit.cpp:306
QString::replace
QString & replace(int position, int n, QChar after)
QKeyEvent
QTextImageFormat::width
qreal width() const
QDateTime::currentDateTime
QDateTime currentDateTime()
QString::mid
QString mid(int position, int n) const
QTextLine
QTextLine::textLength
int textLength() const
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
QLatin1String
QKeySequence
QTextLayout::lineAt
QTextLine lineAt(int i) const
QTextBlock
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
QTextDocument
QMimeData::hasImage
bool hasImage() const
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::TextEdit::~TextEdit
~TextEdit()
Destructor.
Definition: textedit.cpp:206
QMimeData::imageData
QVariant imageData() const
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::isEnableInsertTableActions
bool isEnableInsertTableActions() const
Definition: textedit.cpp:733
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:585
QString::length
int length() const
KPIMTextEdit::TextEdit::addImage
void addImage(const KUrl &url)
Adds an image.
Definition: textedit.cpp:481
QString::left
QString left(int n) const
QTextFormat::toImageFormat
QTextImageFormat toImageFormat() const
QTextCursor::insertImage
void insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
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::configFile
QString configFile() const
Return config file.
Definition: textedit.cpp:241
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
KPIMTextEdit::TextEdit::isEnableEmoticonActions
bool isEnableEmoticonActions() const
Return true if emoticons actions supported.
Definition: textedit.cpp:718
QFileInfo::baseName
QString baseName() const
QTextBlock::iterator
QTextFragment
QTextImageFormat::setHeight
void setHeight(qreal height)
KPIMTextEdit::TextEdit::enableEmoticonActions
void enableEmoticonActions()
Calling this allows createActions() to create the add emoticons actions.
Definition: textedit.cpp:713
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
QVariant
QTextLayout::lineCount
int lineCount() const
QTextBlock::length
int length() const
QTextImageFormat::name
QString name() const
QTextCursor::setPosition
void setPosition(int pos, MoveMode m)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:37:23 by doxygen 1.8.7 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 API Reference

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

Search



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