• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.1 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 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 
27 #include <kmime/kmime_codecs.h>
28 
29 #include <KDE/KAction>
30 #include <KDE/KActionCollection>
31 #include <KDE/KCursor>
32 #include <KDE/KFileDialog>
33 #include <KDE/KLocalizedString>
34 #include <KDE/KMessageBox>
35 #include <KDE/KPushButton>
36 #include <KDE/KUrl>
37 #include <KDE/KImageIO>
38 
39 #include <QtCore/QBuffer>
40 #include <QtCore/QDateTime>
41 #include <QtCore/QMimeData>
42 #include <QtCore/QFileInfo>
43 #include <QtCore/QPointer>
44 #include <QtGui/QKeyEvent>
45 #include <QtGui/QTextLayout>
46 
47 #include "textutils.h"
48 #include <QPlainTextEdit>
49 
50 namespace KPIMTextEdit {
51 
52 class TextEditPrivate
53 {
54  public:
55 
56  TextEditPrivate( TextEdit *parent )
57  : actionAddImage( 0 ),
58  actionDeleteLine( 0 ),
59  q( parent ),
60  imageSupportEnabled( false ),
61  emoticonSupportEnabled( false )
62  {
63  }
64 
73  void addImageHelper( const QString &imageName, const QImage &image );
74 
78  QList<QTextImageFormat> embeddedImageFormats() const;
79 
84  void fixupTextEditString( QString &text ) const;
85 
89  void init();
90 
95  void _k_slotAddImage();
96 
97  void _k_slotDeleteLine();
98 
99  void _k_slotAddEmoticon(const QString&);
101  KAction *actionAddImage;
102 
104  KAction *actionDeleteLine;
105 
106  EmoticonTextEditAction *actionAddEmoticon;
108  TextEdit *q;
109 
111  bool imageSupportEnabled;
112 
113  bool emoticonSupportEnabled;
119  QStringList mImageNames;
120 
132  bool spellCheckingEnabled;
133 
134  QString configFile;
135 };
136 
137 } // namespace
138 
139 using namespace KPIMTextEdit;
140 
141 void TextEditPrivate::fixupTextEditString( QString &text ) const
142 {
143  // Remove line separators. Normal \n chars are still there, so no linebreaks get lost here
144  text.remove( QChar::LineSeparator );
145 
146  // Get rid of embedded images, see QTextImageFormat documentation:
147  // "Inline images are represented by an object replacement character (0xFFFC in Unicode) "
148  text.remove( 0xFFFC );
149 
150  // In plaintext mode, each space is non-breaking.
151  text.replace( QChar::Nbsp, QChar::fromAscii( ' ' ) );
152 }
153 
154 TextEdit::TextEdit( const QString &text, QWidget *parent )
155  : KRichTextWidget( text, parent ),
156  d( new TextEditPrivate( this ) )
157 {
158  d->init();
159 }
160 
161 TextEdit::TextEdit( QWidget *parent )
162  : KRichTextWidget( parent ),
163  d( new TextEditPrivate( this ) )
164 {
165  d->init();
166 }
167 
168 TextEdit::TextEdit( QWidget *parent, const QString &configFile )
169  : KRichTextWidget( parent ),
170  d( new TextEditPrivate( this ) )
171 {
172  d->init();
173  d->configFile = configFile;
174 }
175 
176 TextEdit::~TextEdit()
177 {
178 }
179 
180 bool TextEdit::eventFilter( QObject *o, QEvent *e )
181 {
182 #ifndef QT_NO_CURSOR
183  if ( o == this ) {
184  KCursor::autoHideEventFilter( o, e );
185  }
186 #endif
187  return KRichTextWidget::eventFilter( o, e );
188 }
189 
190 void TextEditPrivate::init()
191 {
192  q->setSpellInterface( q );
193  // We tell the KRichTextWidget to enable spell checking, because only then it will
194  // call createHighlighter() which will create our own highlighter which also
195  // does quote highlighting.
196  // However, *our* spellchecking is still disabled. Our own highlighter only
197  // cares about our spellcheck status, it will not highlight missspelled words
198  // if our spellchecking is disabled.
199  // See also KEMailQuotingHighlighter::highlightBlock().
200  spellCheckingEnabled = false;
201  q->setCheckSpellingEnabledInternal( true );
202 
203 #ifndef QT_NO_CURSOR
204  KCursor::setAutoHideCursor( q, true, true );
205 #endif
206  q->installEventFilter( q );
207 }
208 
209 QString TextEdit::configFile() const
210 {
211  return d->configFile;
212 }
213 
214 void TextEdit::keyPressEvent ( QKeyEvent * e )
215 {
216  if ( e->key() == Qt::Key_Return ) {
217  QTextCursor cursor = textCursor();
218  int oldPos = cursor.position();
219  int blockPos = cursor.block().position();
220 
221  //selection all the line.
222  cursor.movePosition( QTextCursor::StartOfBlock );
223  cursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
224  QString lineText = cursor.selectedText();
225  if ( ( ( oldPos - blockPos ) > 0 ) &&
226  ( ( oldPos - blockPos ) < int( lineText.length() ) ) ) {
227  bool isQuotedLine = false;
228  int bot = 0; // bot = begin of text after quote indicators
229  while ( bot < lineText.length() ) {
230  if( ( lineText[bot] == QChar::fromAscii( '>' ) ) ||
231  ( lineText[bot] == QChar::fromAscii( '|' ) ) ) {
232  isQuotedLine = true;
233  ++bot;
234  } else if ( lineText[bot].isSpace() ) {
235  ++bot;
236  } else {
237  break;
238  }
239  }
240  KRichTextWidget::keyPressEvent( e );
241  // duplicate quote indicators of the previous line before the new
242  // line if the line actually contained text (apart from the quote
243  // indicators) and the cursor is behind the quote indicators
244  if ( isQuotedLine &&
245  ( bot != lineText.length() ) &&
246  ( ( oldPos - blockPos ) >= int( bot ) ) ) {
247  // The cursor position might have changed unpredictably if there was selected
248  // text which got replaced by a new line, so we query it again:
249  cursor.movePosition( QTextCursor::StartOfBlock );
250  cursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
251  QString newLine = cursor.selectedText();
252 
253  // remove leading white space from the new line and instead
254  // add the quote indicators of the previous line
255  int leadingWhiteSpaceCount = 0;
256  while ( ( leadingWhiteSpaceCount < newLine.length() ) &&
257  newLine[leadingWhiteSpaceCount].isSpace() ) {
258  ++leadingWhiteSpaceCount;
259  }
260  newLine = newLine.replace( 0, leadingWhiteSpaceCount, lineText.left( bot ) );
261  cursor.insertText( newLine );
262  //cursor.setPosition( cursor.position() + 2 );
263  cursor.movePosition( QTextCursor::StartOfBlock );
264  setTextCursor( cursor );
265  }
266  } else {
267  KRichTextWidget::keyPressEvent( e );
268  }
269  } else {
270  KRichTextWidget::keyPressEvent( e );
271  }
272 }
273 
274 bool TextEdit::isSpellCheckingEnabled() const
275 {
276  return d->spellCheckingEnabled;
277 }
278 
279 void TextEdit::setSpellCheckingEnabled( bool enable )
280 {
281  EMailQuoteHighlighter *hlighter = dynamic_cast<EMailQuoteHighlighter*>( highlighter() );
282  if ( hlighter ) {
283  hlighter->toggleSpellHighlighting( enable );
284  }
285 
286  d->spellCheckingEnabled = enable;
287  emit checkSpellingChanged( enable );
288 }
289 
290 bool TextEdit::shouldBlockBeSpellChecked( const QString &block ) const
291 {
292  return !isLineQuoted( block );
293 }
294 
295 bool KPIMTextEdit::TextEdit::isLineQuoted( const QString &line ) const
296 {
297  return quoteLength( line ) > 0;
298 }
299 
300 int KPIMTextEdit::TextEdit::quoteLength( const QString &line ) const
301 {
302  bool quoteFound = false;
303  int startOfText = -1;
304  const int lineLength(line.length());
305  for ( int i = 0; i < lineLength; ++i ) {
306  if ( line[i] == QLatin1Char( '>' ) || line[i] == QLatin1Char( '|' ) ) {
307  quoteFound = true;
308  } else if ( line[i] != QLatin1Char( ' ' ) ) {
309  startOfText = i;
310  break;
311  }
312  }
313  if ( quoteFound ) {
314  if ( startOfText == -1 ) {
315  startOfText = line.length() - 1;
316  }
317  return startOfText;
318  } else {
319  return 0;
320  }
321 }
322 
323 const QString KPIMTextEdit::TextEdit::defaultQuoteSign() const
324 {
325  return QLatin1String( "> " );
326 }
327 
328 void TextEdit::createHighlighter()
329 {
330  EMailQuoteHighlighter *emailHighLighter = new EMailQuoteHighlighter( this );
331 
332  setHighlighterColors( emailHighLighter );
333 
334  //TODO change config
335  KRichTextWidget::setHighlighter( emailHighLighter );
336 
337  if ( !spellCheckingLanguage().isEmpty() ) {
338  setSpellCheckingLanguage( spellCheckingLanguage() );
339  }
340  setSpellCheckingEnabled( isSpellCheckingEnabled() );
341 }
342 
343 void TextEdit::setHighlighterColors( EMailQuoteHighlighter *highlighter )
344 {
345  Q_UNUSED( highlighter );
346 }
347 
348 QString TextEdit::toWrappedPlainText() const
349 {
350  QString temp;
351  QTextDocument *doc = document();
352  QTextBlock block = doc->begin();
353  while ( block.isValid() ) {
354  QTextLayout *layout = block.layout();
355  const int numberOfLine( layout->lineCount() );
356  for ( int i = 0; i < numberOfLine; ++i ) {
357  QTextLine line = layout->lineAt( i );
358  temp += block.text().mid( line.textStart(), line.textLength() ) + QLatin1Char( '\n' );
359  }
360  block = block.next();
361  }
362 
363  // Remove the last superfluous newline added above
364  if ( temp.endsWith( QLatin1Char( '\n' ) ) ) {
365  temp.chop( 1 );
366  }
367 
368  d->fixupTextEditString( temp );
369  return temp;
370 }
371 
372 QString TextEdit::toCleanPlainText() const
373 {
374  QString temp = toPlainText();
375  d->fixupTextEditString( temp );
376  return temp;
377 }
378 
379 void TextEdit::createActions( KActionCollection *actionCollection )
380 {
381  KRichTextWidget::createActions( actionCollection );
382 
383  if ( d->imageSupportEnabled ) {
384  d->actionAddImage = new KAction( KIcon( QLatin1String( "insert-image" ) ),
385  i18n( "Add Image" ), this );
386  actionCollection->addAction( QLatin1String( "add_image" ), d->actionAddImage );
387  connect( d->actionAddImage, SIGNAL(triggered(bool)), SLOT(_k_slotAddImage()) );
388  }
389  if ( d->emoticonSupportEnabled ) {
390  d->actionAddEmoticon = new EmoticonTextEditAction( this );
391  actionCollection->addAction( QLatin1String( "add_emoticon" ), d->actionAddEmoticon );
392  connect( d->actionAddEmoticon, SIGNAL(emoticonActivated(QString)), SLOT(_k_slotAddEmoticon(QString)) );
393  }
394 
395  d->actionDeleteLine = new KAction( i18n( "Delete Line" ), this );
396  d->actionDeleteLine->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_K ) );
397  actionCollection->addAction( QLatin1String( "delete_line" ), d->actionDeleteLine );
398  connect( d->actionDeleteLine, SIGNAL(triggered(bool)), SLOT(_k_slotDeleteLine()) );
399 }
400 
401 void TextEdit::addImage( const KUrl &url )
402 {
403  QImage image;
404  if ( !image.load( url.path() ) ) {
405  KMessageBox::error( this,
406  i18nc( "@info",
407  "Unable to load image <filename>%1</filename>.",
408  url.path() ) );
409  return;
410  }
411  QFileInfo fi( url.path() );
412  QString imageName = fi.baseName().isEmpty() ? QLatin1String( "image.png" )
413  : QString( fi.baseName() + QLatin1String( ".png" ) );
414  d->addImageHelper( imageName, image );
415 }
416 
417 void TextEdit::loadImage ( const QImage &image, const QString &matchName,
418  const QString &resourceName )
419 {
420  QSet<int> cursorPositionsToSkip;
421  QTextBlock currentBlock = document()->begin();
422  QTextBlock::iterator it;
423  while ( currentBlock.isValid() ) {
424  for ( it = currentBlock.begin(); !it.atEnd(); ++it ) {
425  QTextFragment fragment = it.fragment();
426  if ( fragment.isValid() ) {
427  QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
428  if ( imageFormat.isValid() && imageFormat.name() == matchName ) {
429  int pos = fragment.position();
430  if ( !cursorPositionsToSkip.contains( pos ) ) {
431  QTextCursor cursor( document() );
432  cursor.setPosition( pos );
433  cursor.setPosition( pos + 1, QTextCursor::KeepAnchor );
434  cursor.removeSelectedText();
435  document()->addResource( QTextDocument::ImageResource,
436  QUrl( resourceName ), QVariant( image ) );
437  cursor.insertImage( resourceName );
438 
439  // The textfragment iterator is now invalid, restart from the beginning
440  // Take care not to replace the same fragment again, or we would be in
441  // an infinite loop.
442  cursorPositionsToSkip.insert( pos );
443  it = currentBlock.begin();
444  }
445  }
446  }
447  }
448  currentBlock = currentBlock.next();
449  }
450 }
451 
452 void TextEditPrivate::addImageHelper( const QString &imageName, const QImage &image )
453 {
454  QString imageNameToAdd = imageName;
455  QTextDocument *document = q->document();
456 
457  // determine the imageNameToAdd
458  int imageNumber = 1;
459  while ( mImageNames.contains( imageNameToAdd ) ) {
460  QVariant qv = document->resource( QTextDocument::ImageResource, QUrl( imageNameToAdd ) );
461  if ( qv == image ) {
462  // use the same name
463  break;
464  }
465  int firstDot = imageName.indexOf( QLatin1Char( '.' ) );
466  if ( firstDot == -1 ) {
467  imageNameToAdd = imageName + QString::number( imageNumber++ );
468  } else {
469  imageNameToAdd = imageName.left( firstDot ) + QString::number( imageNumber++ ) +
470  imageName.mid( firstDot );
471  }
472  }
473 
474  if ( !mImageNames.contains( imageNameToAdd ) ) {
475  document->addResource( QTextDocument::ImageResource, QUrl( imageNameToAdd ), image );
476  mImageNames << imageNameToAdd;
477  }
478  q->textCursor().insertImage( imageNameToAdd );
479  q->enableRichTextMode();
480 }
481 
482 ImageWithNameList TextEdit::imagesWithName() const
483 {
484  ImageWithNameList retImages;
485  QStringList seenImageNames;
486  QList<QTextImageFormat> imageFormats = d->embeddedImageFormats();
487  foreach ( const QTextImageFormat &imageFormat, imageFormats ) {
488  if ( !seenImageNames.contains( imageFormat.name() ) ) {
489  QVariant resourceData = document()->resource( QTextDocument::ImageResource,
490  QUrl( imageFormat.name() ) );
491  QImage image = qvariant_cast<QImage>( resourceData );
492  QString name = imageFormat.name();
493  ImageWithNamePtr newImage( new ImageWithName );
494  newImage->image = image;
495  newImage->name = name;
496  retImages.append( newImage );
497  seenImageNames.append( imageFormat.name() );
498  }
499  }
500  return retImages;
501 }
502 
503 QList< QSharedPointer<EmbeddedImage> > TextEdit::embeddedImages() const
504 {
505  ImageWithNameList normalImages = imagesWithName();
506  QList< QSharedPointer<EmbeddedImage> > retImages;
507  foreach ( const ImageWithNamePtr &normalImage, normalImages ) {
508  QBuffer buffer;
509  buffer.open( QIODevice::WriteOnly );
510  normalImage->image.save( &buffer, "PNG" );
511 
512  qsrand( QDateTime::currentDateTime().toTime_t() + qHash( normalImage->name ) );
513  QSharedPointer<EmbeddedImage> embeddedImage( new EmbeddedImage() );
514  retImages.append( embeddedImage );
515  embeddedImage->image = KMime::Codec::codecForName( "base64" )->encode( buffer.buffer() );
516  embeddedImage->imageName = normalImage->name;
517  embeddedImage->contentID = QString( QLatin1String( "%1@KDE" ) ).arg( qrand() );
518  }
519  return retImages;
520 }
521 
522 QList<QTextImageFormat> TextEditPrivate::embeddedImageFormats() const
523 {
524  QTextDocument *doc = q->document();
525  QList<QTextImageFormat> retList;
526 
527  QTextBlock currentBlock = doc->begin();
528  while ( currentBlock.isValid() ) {
529  QTextBlock::iterator it;
530  for ( it = currentBlock.begin(); !it.atEnd(); ++it ) {
531  QTextFragment fragment = it.fragment();
532  if ( fragment.isValid() ) {
533  QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
534  if ( imageFormat.isValid() ) {
535  //TODO: Replace with a way to see if an image is an embedded image or a remote
536  QUrl url(imageFormat.name());
537  if( !url.isValid() || !url.scheme().startsWith( QLatin1String( "http" ) ) ) {
538  retList.append( imageFormat );
539  }
540  }
541  }
542  }
543  currentBlock = currentBlock.next();
544  }
545  return retList;
546 }
547 
548 void TextEditPrivate::_k_slotAddEmoticon( const QString& text)
549 {
550  QTextCursor cursor = q->textCursor();
551  cursor.insertText( text );
552 }
553 
554 void TextEditPrivate::_k_slotAddImage()
555 {
556  QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading );
557  QPointer<KFileDialog> fdlg = new KFileDialog( QString(), mimetypes.join(QLatin1String(" ")), q );
558  fdlg->setOperationMode( KFileDialog::Other );
559  fdlg->setCaption( i18n( "Add Image" ) );
560  fdlg->okButton()->setGuiItem( KGuiItem( i18n( "&Add" ), QLatin1String( "document-open" ) ) );
561  fdlg->setMode( KFile::Files );
562  if ( fdlg->exec() == KDialog::Accepted && fdlg ) {
563  const KUrl::List files = fdlg->selectedUrls();
564  foreach ( const KUrl &url, files ) {
565  q->addImage( url );
566  }
567  }
568  delete fdlg;
569 }
570 
571 void KPIMTextEdit::TextEdit::enableImageActions()
572 {
573  d->imageSupportEnabled = true;
574 }
575 
576 bool KPIMTextEdit::TextEdit::isEnableImageActions() const
577 {
578  return d->imageSupportEnabled;
579 }
580 
581 void KPIMTextEdit::TextEdit::enableEmoticonActions()
582 {
583  d->emoticonSupportEnabled = true;
584 }
585 
586 bool KPIMTextEdit::TextEdit::isEnableEmoticonActions() const
587 {
588  return d->emoticonSupportEnabled;
589 }
590 
591 
592 QByteArray KPIMTextEdit::TextEdit::imageNamesToContentIds(
593  const QByteArray &htmlBody, const KPIMTextEdit::ImageList &imageList )
594 {
595  QByteArray result = htmlBody;
596  if ( !imageList.isEmpty() ) {
597  foreach ( const QSharedPointer<EmbeddedImage> &image, imageList ) {
598  const QString newImageName = QLatin1String( "cid:" ) + image->contentID;
599  QByteArray quote( "\"" );
600  result.replace( QByteArray( quote + image->imageName.toLocal8Bit() + quote ),
601  QByteArray( quote + newImageName.toLocal8Bit() + quote ) );
602  }
603  }
604  return result;
605 }
606 
607 void TextEdit::insertImage( const QImage &image, const QFileInfo &fileInfo )
608 {
609  QString imageName = fileInfo.baseName().isEmpty() ?
610  i18nc( "Start of the filename for an image", "image" ) :
611  fileInfo.baseName();
612  d->addImageHelper( imageName, image );
613 }
614 
615 void TextEdit::insertFromMimeData( const QMimeData *source )
616 {
617  // Add an image if that is on the clipboard
618  if ( textMode() == KRichTextEdit::Rich && source->hasImage() && d->imageSupportEnabled ) {
619  QImage image = qvariant_cast<QImage>( source->imageData() );
620  QFileInfo fi( source->text() );
621  insertImage( image, fi );
622  return;
623  }
624 
625  // Attempt to paste HTML contents into the text edit in plain text mode,
626  // prevent this and prevent plain text instead.
627  if ( textMode() == KRichTextEdit::Plain && source->hasHtml() ) {
628  if ( source->hasText() ) {
629  insertPlainText( source->text() );
630  return;
631  }
632  }
633 
634  KRichTextWidget::insertFromMimeData( source );
635 }
636 
637 bool KPIMTextEdit::TextEdit::canInsertFromMimeData( const QMimeData *source ) const
638 {
639  if ( source->hasHtml() && textMode() == KRichTextEdit::Rich ) {
640  return true;
641  }
642 
643  if ( source->hasText() ) {
644  return true;
645  }
646 
647  if ( textMode() == KRichTextEdit::Rich && source->hasImage() && d->imageSupportEnabled ) {
648  return true;
649  }
650 
651  return KRichTextWidget::canInsertFromMimeData( source );
652 }
653 
654 bool TextEdit::isFormattingUsed() const
655 {
656  if ( textMode() == Plain ) {
657  return false;
658  }
659 
660  return TextUtils::containsFormatting( document() );
661 }
662 
663 void TextEditPrivate::_k_slotDeleteLine()
664 {
665  if ( q->hasFocus() ) {
666  q->deleteCurrentLine();
667  }
668 }
669 
670 void TextEdit::deleteCurrentLine()
671 {
672  QTextCursor cursor = textCursor();
673  QTextBlock block = cursor.block();
674  const QTextLayout *layout = block.layout();
675 
676  // The current text block can have several lines due to word wrapping.
677  // Search the line the cursor is in, and then delete it.
678  for ( int lineNumber = 0; lineNumber < layout->lineCount(); lineNumber++ ) {
679  QTextLine line = layout->lineAt( lineNumber );
680  const bool lastLineInBlock = ( line.textStart() + line.textLength() == block.length() - 1 );
681  const bool oneLineBlock = ( layout->lineCount() == 1 );
682  const int startOfLine = block.position() + line.textStart();
683  int endOfLine = block.position() + line.textStart() + line.textLength();
684  if ( !lastLineInBlock ) {
685  endOfLine -= 1;
686  }
687 
688  // Found the line where the cursor is in
689  if ( cursor.position() >= startOfLine && cursor.position() <= endOfLine ) {
690  int deleteStart = startOfLine;
691  int deleteLength = line.textLength();
692  if ( oneLineBlock ) {
693  deleteLength++; // The trailing newline
694  }
695 
696  // When deleting the last line in the document,
697  // remove the newline of the line before the last line instead
698  if ( deleteStart + deleteLength >= document()->characterCount() &&
699  deleteStart > 0 ) {
700  deleteStart--;
701  }
702 
703  cursor.beginEditBlock();
704  cursor.setPosition( deleteStart );
705  cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor, deleteLength );
706  cursor.removeSelectedText();
707  cursor.endEditBlock();
708  return;
709  }
710  }
711 
712 }
713 
714 #include "textedit.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Sep 24 2012 09:03:50 by doxygen 1.8.1.1 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.9.1 API Reference

Skip menu "kdepimlibs-4.9.1 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • 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