• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.4 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  QTextImageFormat format;
438  format.setName( resourceName );
439  if ( (imageFormat.width()!=0) && (imageFormat.height()!=0) ) {
440  format.setWidth( imageFormat.width() );
441  format.setHeight( imageFormat.height() );
442  }
443  cursor.insertImage( format );
444 
445 
446  // The textfragment iterator is now invalid, restart from the beginning
447  // Take care not to replace the same fragment again, or we would be in
448  // an infinite loop.
449  cursorPositionsToSkip.insert( pos );
450  it = currentBlock.begin();
451  }
452  }
453  }
454  }
455  currentBlock = currentBlock.next();
456  }
457 }
458 
459 void TextEditPrivate::addImageHelper( const QString &imageName, const QImage &image )
460 {
461  QString imageNameToAdd = imageName;
462  QTextDocument *document = q->document();
463 
464  // determine the imageNameToAdd
465  int imageNumber = 1;
466  while ( mImageNames.contains( imageNameToAdd ) ) {
467  QVariant qv = document->resource( QTextDocument::ImageResource, QUrl( imageNameToAdd ) );
468  if ( qv == image ) {
469  // use the same name
470  break;
471  }
472  int firstDot = imageName.indexOf( QLatin1Char( '.' ) );
473  if ( firstDot == -1 ) {
474  imageNameToAdd = imageName + QString::number( imageNumber++ );
475  } else {
476  imageNameToAdd = imageName.left( firstDot ) + QString::number( imageNumber++ ) +
477  imageName.mid( firstDot );
478  }
479  }
480 
481  if ( !mImageNames.contains( imageNameToAdd ) ) {
482  document->addResource( QTextDocument::ImageResource, QUrl( imageNameToAdd ), image );
483  mImageNames << imageNameToAdd;
484  }
485  q->textCursor().insertImage( imageNameToAdd );
486  q->enableRichTextMode();
487 }
488 
489 ImageWithNameList TextEdit::imagesWithName() const
490 {
491  ImageWithNameList retImages;
492  QStringList seenImageNames;
493  QList<QTextImageFormat> imageFormats = d->embeddedImageFormats();
494  foreach ( const QTextImageFormat &imageFormat, imageFormats ) {
495  if ( !seenImageNames.contains( imageFormat.name() ) ) {
496  QVariant resourceData = document()->resource( QTextDocument::ImageResource,
497  QUrl( imageFormat.name() ) );
498  QImage image = qvariant_cast<QImage>( resourceData );
499  QString name = imageFormat.name();
500  ImageWithNamePtr newImage( new ImageWithName );
501  newImage->image = image;
502  newImage->name = name;
503  retImages.append( newImage );
504  seenImageNames.append( imageFormat.name() );
505  }
506  }
507  return retImages;
508 }
509 
510 QList< QSharedPointer<EmbeddedImage> > TextEdit::embeddedImages() const
511 {
512  ImageWithNameList normalImages = imagesWithName();
513  QList< QSharedPointer<EmbeddedImage> > retImages;
514  foreach ( const ImageWithNamePtr &normalImage, normalImages ) {
515  QBuffer buffer;
516  buffer.open( QIODevice::WriteOnly );
517  normalImage->image.save( &buffer, "PNG" );
518 
519  qsrand( QDateTime::currentDateTime().toTime_t() + qHash( normalImage->name ) );
520  QSharedPointer<EmbeddedImage> embeddedImage( new EmbeddedImage() );
521  retImages.append( embeddedImage );
522  embeddedImage->image = KMime::Codec::codecForName( "base64" )->encode( buffer.buffer() );
523  embeddedImage->imageName = normalImage->name;
524  embeddedImage->contentID = QString( QLatin1String( "%1@KDE" ) ).arg( qrand() );
525  }
526  return retImages;
527 }
528 
529 QList<QTextImageFormat> TextEditPrivate::embeddedImageFormats() const
530 {
531  QTextDocument *doc = q->document();
532  QList<QTextImageFormat> retList;
533 
534  QTextBlock currentBlock = doc->begin();
535  while ( currentBlock.isValid() ) {
536  QTextBlock::iterator it;
537  for ( it = currentBlock.begin(); !it.atEnd(); ++it ) {
538  QTextFragment fragment = it.fragment();
539  if ( fragment.isValid() ) {
540  QTextImageFormat imageFormat = fragment.charFormat().toImageFormat();
541  if ( imageFormat.isValid() ) {
542  //TODO: Replace with a way to see if an image is an embedded image or a remote
543  QUrl url(imageFormat.name());
544  if( !url.isValid() || !url.scheme().startsWith( QLatin1String( "http" ) ) ) {
545  retList.append( imageFormat );
546  }
547  }
548  }
549  }
550  currentBlock = currentBlock.next();
551  }
552  return retList;
553 }
554 
555 void TextEditPrivate::_k_slotAddEmoticon( const QString& text)
556 {
557  QTextCursor cursor = q->textCursor();
558  cursor.insertText( text );
559 }
560 
561 void TextEditPrivate::_k_slotAddImage()
562 {
563  QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading );
564  QPointer<KFileDialog> fdlg = new KFileDialog( QString(), mimetypes.join(QLatin1String(" ")), q );
565  fdlg->setOperationMode( KFileDialog::Other );
566  fdlg->setCaption( i18n( "Add Image" ) );
567  fdlg->okButton()->setGuiItem( KGuiItem( i18n( "&Add" ), QLatin1String( "document-open" ) ) );
568  fdlg->setMode( KFile::Files );
569  if ( fdlg->exec() == KDialog::Accepted && fdlg ) {
570  const KUrl::List files = fdlg->selectedUrls();
571  foreach ( const KUrl &url, files ) {
572  q->addImage( url );
573  }
574  }
575  delete fdlg;
576 }
577 
578 void KPIMTextEdit::TextEdit::enableImageActions()
579 {
580  d->imageSupportEnabled = true;
581 }
582 
583 bool KPIMTextEdit::TextEdit::isEnableImageActions() const
584 {
585  return d->imageSupportEnabled;
586 }
587 
588 void KPIMTextEdit::TextEdit::enableEmoticonActions()
589 {
590  d->emoticonSupportEnabled = true;
591 }
592 
593 bool KPIMTextEdit::TextEdit::isEnableEmoticonActions() const
594 {
595  return d->emoticonSupportEnabled;
596 }
597 
598 
599 QByteArray KPIMTextEdit::TextEdit::imageNamesToContentIds(
600  const QByteArray &htmlBody, const KPIMTextEdit::ImageList &imageList )
601 {
602  QByteArray result = htmlBody;
603  if ( !imageList.isEmpty() ) {
604  foreach ( const QSharedPointer<EmbeddedImage> &image, imageList ) {
605  const QString newImageName = QLatin1String( "cid:" ) + image->contentID;
606  QByteArray quote( "\"" );
607  result.replace( QByteArray( quote + image->imageName.toLocal8Bit() + quote ),
608  QByteArray( quote + newImageName.toLocal8Bit() + quote ) );
609  }
610  }
611  return result;
612 }
613 
614 void TextEdit::insertImage( const QImage &image, const QFileInfo &fileInfo )
615 {
616  QString imageName = fileInfo.baseName().isEmpty() ?
617  i18nc( "Start of the filename for an image", "image" ) :
618  fileInfo.baseName();
619  d->addImageHelper( imageName, image );
620 }
621 
622 void TextEdit::insertFromMimeData( const QMimeData *source )
623 {
624  // Add an image if that is on the clipboard
625  if ( textMode() == KRichTextEdit::Rich && source->hasImage() && d->imageSupportEnabled ) {
626  QImage image = qvariant_cast<QImage>( source->imageData() );
627  QFileInfo fi( source->text() );
628  insertImage( image, fi );
629  return;
630  }
631 
632  // Attempt to paste HTML contents into the text edit in plain text mode,
633  // prevent this and prevent plain text instead.
634  if ( textMode() == KRichTextEdit::Plain && source->hasHtml() ) {
635  if ( source->hasText() ) {
636  insertPlainText( source->text() );
637  return;
638  }
639  }
640 
641  KRichTextWidget::insertFromMimeData( source );
642 }
643 
644 bool KPIMTextEdit::TextEdit::canInsertFromMimeData( const QMimeData *source ) const
645 {
646  if ( source->hasHtml() && textMode() == KRichTextEdit::Rich ) {
647  return true;
648  }
649 
650  if ( source->hasText() ) {
651  return true;
652  }
653 
654  if ( textMode() == KRichTextEdit::Rich && source->hasImage() && d->imageSupportEnabled ) {
655  return true;
656  }
657 
658  return KRichTextWidget::canInsertFromMimeData( source );
659 }
660 
661 bool TextEdit::isFormattingUsed() const
662 {
663  if ( textMode() == Plain ) {
664  return false;
665  }
666 
667  return TextUtils::containsFormatting( document() );
668 }
669 
670 void TextEditPrivate::_k_slotDeleteLine()
671 {
672  if ( q->hasFocus() ) {
673  q->deleteCurrentLine();
674  }
675 }
676 
677 void TextEdit::deleteCurrentLine()
678 {
679  QTextCursor cursor = textCursor();
680  QTextBlock block = cursor.block();
681  const QTextLayout *layout = block.layout();
682 
683  // The current text block can have several lines due to word wrapping.
684  // Search the line the cursor is in, and then delete it.
685  for ( int lineNumber = 0; lineNumber < layout->lineCount(); lineNumber++ ) {
686  QTextLine line = layout->lineAt( lineNumber );
687  const bool lastLineInBlock = ( line.textStart() + line.textLength() == block.length() - 1 );
688  const bool oneLineBlock = ( layout->lineCount() == 1 );
689  const int startOfLine = block.position() + line.textStart();
690  int endOfLine = block.position() + line.textStart() + line.textLength();
691  if ( !lastLineInBlock ) {
692  endOfLine -= 1;
693  }
694 
695  // Found the line where the cursor is in
696  if ( cursor.position() >= startOfLine && cursor.position() <= endOfLine ) {
697  int deleteStart = startOfLine;
698  int deleteLength = line.textLength();
699  if ( oneLineBlock ) {
700  deleteLength++; // The trailing newline
701  }
702 
703  // When deleting the last line in the document,
704  // remove the newline of the line before the last line instead
705  if ( deleteStart + deleteLength >= document()->characterCount() &&
706  deleteStart > 0 ) {
707  deleteStart--;
708  }
709 
710  cursor.beginEditBlock();
711  cursor.setPosition( deleteStart );
712  cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor, deleteLength );
713  cursor.removeSelectedText();
714  cursor.endEditBlock();
715  return;
716  }
717  }
718 
719 }
720 
721 #include "textedit.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue Dec 11 2012 12:13:22 by doxygen 1.8.1.2 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.4 API Reference

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