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

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