QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsrichtexteditor.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Jiří Procházka (Hobrasoft)
4 ** Contact: http://www.hobrasoft.cz/
5 **
6 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
7 ** Contact: http://www.qt-project.org/legal
8 **
9 ** This library is free software; you can redistribute it and/or
10 ** modify it under the terms of the GNU Lesser General Public
11 ** License as published by the Free Software Foundation; either
12 ** version 2.1 of the License, or (at your option) any later version.
13 **
14 ** $QT_BEGIN_LICENSE:LGPL$
15 ** GNU Lesser General Public License Usage
16 ** This file is under the terms of the GNU Lesser General Public License
17 ** version 2.1 as published by the Free Software Foundation and appearing
18 ** in the file LICENSE.LGPL included in the packaging of this file.
19 ** Please review the following information to ensure the
20 ** GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22 **
23 ** In addition, as a special exception, Digia gives you certain additional
24 ** rights. These rights are described in the Digia Qt LGPL Exception
25 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30 
31 #include "qgsrichtexteditor.h"
32 #include "qgsguiutils.h"
33 #include "qgscolorbutton.h"
34 #include "qgscodeeditor.h"
35 #include "qgscodeeditorhtml.h"
36 
37 #include <QMimeData>
38 #include <QApplication>
39 #include <QClipboard>
40 #include <QFontDatabase>
41 #include <QInputDialog>
42 #include <QTextList>
43 #include <QtDebug>
44 #include <QFileDialog>
45 #include <QImageReader>
46 #include <QSettings>
47 #include <QUrl>
48 #include <QMenu>
49 #include <QComboBox>
50 #include <QToolButton>
51 
53  : QWidget( parent )
54 {
55  setupUi( this );
56 
57  mMonospaceFontFamily = QgsCodeEditor::getMonospaceFont().family();
58 
59  QVBoxLayout *sourceLayout = new QVBoxLayout();
60  sourceLayout->setContentsMargins( 0, 0, 0, 0 );
61  mSourceEdit = new QgsCodeEditorHTML();
62  sourceLayout->addWidget( mSourceEdit );
63  mPageSourceEdit->setLayout( sourceLayout );
64 
65  mToolBar->setIconSize( QgsGuiUtils::iconSize( false ) );
66 
67  connect( mTextEdit, &QTextEdit::currentCharFormatChanged, this, &QgsRichTextEditor::slotCurrentCharFormatChanged );
68  connect( mTextEdit, &QTextEdit::cursorPositionChanged, this, &QgsRichTextEditor::slotCursorPositionChanged );
69 
70  // paragraph formatting
71  mParagraphStyleCombo = new QComboBox();
72  mParagraphStyleCombo->addItem( tr( "Standard" ), ParagraphStandard );
73  mParagraphStyleCombo->addItem( tr( "Heading 1" ), ParagraphHeading1 );
74  mParagraphStyleCombo->addItem( tr( "Heading 2" ), ParagraphHeading2 );
75  mParagraphStyleCombo->addItem( tr( "Heading 3" ), ParagraphHeading3 );
76  mParagraphStyleCombo->addItem( tr( "Heading 4" ), ParagraphHeading4 );
77  mParagraphStyleCombo->addItem( tr( "Monospace" ), ParagraphMonospace );
78 
79  connect( mParagraphStyleCombo, qOverload< int >( &QComboBox::activated ), this, &QgsRichTextEditor::textStyle );
80  mToolBar->insertWidget( mToolBar->actions().at( 0 ), mParagraphStyleCombo );
81 
82  mFontSizeCombo = new QComboBox();
83  mFontSizeCombo->setEditable( true );
84  mToolBar->insertWidget( mActionBold, mFontSizeCombo );
85 
86  // undo & redo
87  mActionUndo->setShortcut( QKeySequence::Undo );
88  mActionRedo->setShortcut( QKeySequence::Redo );
89 
90  connect( mTextEdit->document(), &QTextDocument::undoAvailable, mActionUndo, &QAction::setEnabled );
91  connect( mTextEdit->document(), &QTextDocument::redoAvailable, mActionRedo, &QAction::setEnabled );
92 
93  mActionUndo->setEnabled( mTextEdit->document()->isUndoAvailable() );
94  mActionRedo->setEnabled( mTextEdit->document()->isRedoAvailable() );
95 
96  connect( mActionUndo, &QAction::triggered, mTextEdit, &QTextEdit::undo );
97  connect( mActionRedo, &QAction::triggered, mTextEdit, &QTextEdit::redo );
98 
99  // cut, copy & paste
100  mActionCut->setShortcut( QKeySequence::Cut );
101  mActionCopy->setShortcut( QKeySequence::Copy );
102  mActionPaste->setShortcut( QKeySequence::Paste );
103 
104  mActionCut->setEnabled( false );
105  mActionCopy->setEnabled( false );
106 
107  connect( mActionCut, &QAction::triggered, mTextEdit, &QTextEdit::cut );
108  connect( mActionCopy, &QAction::triggered, mTextEdit, &QTextEdit::copy );
109  connect( mActionPaste, &QAction::triggered, mTextEdit, &QTextEdit::paste );
110 
111  connect( mTextEdit, &QTextEdit::copyAvailable, mActionCut, &QAction::setEnabled );
112  connect( mTextEdit, &QTextEdit::copyAvailable, mActionCopy, &QAction::setEnabled );
113 
114 #ifndef QT_NO_CLIPBOARD
115  connect( QApplication::clipboard(), &QClipboard::dataChanged, this, &QgsRichTextEditor::slotClipboardDataChanged );
116 #endif
117 
118  // link
119  mActionInsertLink->setShortcut( QKeySequence( QStringLiteral( "CTRL+L" ) ) );
120  connect( mActionInsertLink, &QAction::triggered, this, &QgsRichTextEditor::textLink );
121 
122  // bold, italic & underline
123  mActionBold->setShortcut( QKeySequence( QStringLiteral( "CTRL+B" ) ) );
124  mActionItalic->setShortcut( QKeySequence( QStringLiteral( "CTRL+I" ) ) );
125  mActionUnderline->setShortcut( QKeySequence( QStringLiteral( "CTRL+U" ) ) );
126 
127  connect( mActionBold, &QAction::triggered, this, &QgsRichTextEditor::textBold );
128  connect( mActionItalic, &QAction::triggered, this, &QgsRichTextEditor::textItalic );
129  connect( mActionUnderline, &QAction::triggered, this, &QgsRichTextEditor::textUnderline );
130  connect( mActionStrikeOut, &QAction::triggered, this, &QgsRichTextEditor::textStrikeout );
131 
132  QAction *removeFormat = new QAction( tr( "Remove Character Formatting" ), this );
133  removeFormat->setShortcut( QKeySequence( QStringLiteral( "CTRL+M" ) ) );
134  connect( removeFormat, &QAction::triggered, this, &QgsRichTextEditor::textRemoveFormat );
135  mTextEdit->addAction( removeFormat );
136 
137  QAction *removeAllFormat = new QAction( tr( "Remove all Formatting" ), this );
138  connect( removeAllFormat, &QAction::triggered, this, &QgsRichTextEditor::textRemoveAllFormat );
139  mTextEdit->addAction( removeAllFormat );
140 
141  QAction *clearText = new QAction( tr( "Clear all Content" ), this );
142  connect( clearText, &QAction::triggered, this, &QgsRichTextEditor::clearSource );
143  mTextEdit->addAction( clearText );
144 
145  QMenu *menu = new QMenu( this );
146  menu->addAction( removeAllFormat );
147  menu->addAction( removeFormat );
148  menu->addAction( clearText );
149 
150  QToolButton *menuButton = new QToolButton();
151  menuButton->setMenu( menu );
152  menuButton->setPopupMode( QToolButton::InstantPopup );
153  menuButton->setToolTip( tr( "Advanced Options" ) );
154  menuButton->setText( QStringLiteral( "…" ) );
155  QWidget *spacer = new QWidget();
156  spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
157  mToolBar->addWidget( spacer );
158  mToolBar->addWidget( menuButton );
159 
160  // lists
161  mActionBulletList->setShortcut( QKeySequence( QStringLiteral( "CTRL+-" ) ) );
162  mActionOrderedList->setShortcut( QKeySequence( QStringLiteral( "CTRL+=" ) ) );
163  connect( mActionBulletList, &QAction::triggered, this, &QgsRichTextEditor::listBullet );
164  connect( mActionOrderedList, &QAction::triggered, this, &QgsRichTextEditor::listOrdered );
165 
166  // indentation
167  mActionDecreaseIndent->setShortcut( QKeySequence( QStringLiteral( "CTRL+," ) ) );
168  mActionIncreaseIndent->setShortcut( QKeySequence( QStringLiteral( "CTRL+." ) ) );
169  connect( mActionIncreaseIndent, &QAction::triggered, this, &QgsRichTextEditor::increaseIndentation );
170  connect( mActionDecreaseIndent, &QAction::triggered, this, &QgsRichTextEditor::decreaseIndentation );
171 
172  // font size
173  const QFontDatabase db;
174  const QList< int > sizes = db.standardSizes();
175  for ( const int size : sizes )
176  mFontSizeCombo->addItem( QString::number( size ), size );
177 
178  mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( QApplication::font().pointSize() ) );
179 
180  // text foreground color
181  mForeColorButton = new QgsColorButton();
182  mForeColorButton->setAllowOpacity( false );
183  mForeColorButton->setColorDialogTitle( tr( "Foreground Color" ) );
184  mForeColorButton->setColor( palette().windowText().color() );
185  mForeColorButton->setShowNoColor( false );
186  mForeColorButton->setToolTip( tr( "Foreground color" ) );
187  mForeColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral( "x" ) ) * 10 );
188  mForeColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
189 
190  QAction *listSeparator = mToolBar->insertSeparator( mActionBulletList );
191 
192  connect( mForeColorButton, &QgsColorButton::colorChanged, this, &QgsRichTextEditor::textFgColor );
193  mToolBar->insertWidget( listSeparator, mForeColorButton );
194 
195  // text background color
196  mBackColorButton = new QgsColorButton();
197  mBackColorButton->setAllowOpacity( false );
198  mBackColorButton->setColorDialogTitle( tr( "Background Color" ) );
199  mBackColorButton->setToolTip( tr( "Background color" ) );
200  mBackColorButton->setShowNull( true, tr( "No Background Color" ) );
201  mBackColorButton->setToNull();
202  mBackColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
203  mBackColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral( "x" ) ) * 10 );
204  connect( mBackColorButton, &QgsColorButton::colorChanged, this, &QgsRichTextEditor::textBgColor );
205  mToolBar->insertWidget( listSeparator, mBackColorButton );
206 
207  connect( mActionEditSource, &QAction::toggled, this, &QgsRichTextEditor::editSource );
208 
209  // images
210  connect( mActionInsertImage, &QAction::triggered, this, &QgsRichTextEditor::insertImage );
211 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
212  connect( mFontSizeCombo, qOverload< const QString &>( &QComboBox::activated ), this, &QgsRichTextEditor::textSize );
213 #else
214  connect( mFontSizeCombo, &QComboBox::textActivated, this, &QgsRichTextEditor::textSize );
215 #endif
216 
217  fontChanged( mTextEdit->font() );
218 }
219 
221 {
222  switch ( mStackedWidget->currentIndex() )
223  {
224  case 0:
225  return mTextEdit->toPlainText();
226 
227  case 1:
228  // go via text edit to remove html from text...
229  mTextEdit->setText( mSourceEdit->text() );
230  return mTextEdit->toPlainText();
231  }
232  return QString();
233 }
234 
236 {
237  switch ( mStackedWidget->currentIndex() )
238  {
239  case 0:
240  return mTextEdit->toHtml();
241 
242  case 1:
243  return mSourceEdit->text();
244  }
245  return QString();
246 }
247 
248 void QgsRichTextEditor::editSource( bool enabled )
249 {
250  if ( enabled )
251  {
252  mSourceEdit->setText( mTextEdit->toHtml() );
253  mStackedWidget->setCurrentIndex( 1 );
254  }
255  else
256  {
257  mTextEdit->setHtml( mSourceEdit->text() );
258  mStackedWidget->setCurrentIndex( 0 );
259  mSourceEdit->clear();
260  }
261 
262  // disable formatting actions when in html edit mode
263  mFontSizeCombo->setEnabled( !enabled );
264  mParagraphStyleCombo->setEnabled( !enabled );
265  mForeColorButton->setEnabled( !enabled );
266  mBackColorButton->setEnabled( !enabled );
267  mActionUndo->setEnabled( !enabled );
268  mActionRedo->setEnabled( !enabled );
269  mActionCut->setEnabled( !enabled );
270  mActionCopy->setEnabled( !enabled );
271  mActionPaste->setEnabled( !enabled );
272  mActionInsertLink->setEnabled( !enabled );
273  mActionBold->setEnabled( !enabled );
274  mActionItalic->setEnabled( !enabled );
275  mActionUnderline->setEnabled( !enabled );
276  mActionStrikeOut->setEnabled( !enabled );
277  mActionBulletList->setEnabled( !enabled );
278  mActionOrderedList->setEnabled( !enabled );
279  mActionDecreaseIndent->setEnabled( !enabled );
280  mActionIncreaseIndent->setEnabled( !enabled );
281  mActionInsertImage->setEnabled( !enabled );
282 }
283 
285 {
286  mTextEdit->clear();
287 }
288 
289 void QgsRichTextEditor::textRemoveFormat()
290 {
291  QTextCharFormat format;
292  format.setFontWeight( QFont::Normal );
293  format.setFontUnderline( false );
294  format.setFontStrikeOut( false );
295  format.setFontItalic( false );
296  format.setFontPointSize( 9 );
297 
298  mActionBold->setChecked( false );
299  mActionUnderline->setChecked( false );
300  mActionItalic->setChecked( false );
301  mActionStrikeOut->setChecked( false );
302  mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
303 
304  format.clearBackground();
305 
306  mergeFormatOnWordOrSelection( format );
307 }
308 
309 void QgsRichTextEditor::textRemoveAllFormat()
310 {
311  mActionBold->setChecked( false );
312  mActionUnderline->setChecked( false );
313  mActionItalic->setChecked( false );
314  mActionStrikeOut->setChecked( false );
315  mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
316  const QString text = mTextEdit->toPlainText();
317  mTextEdit->setPlainText( text );
318 }
319 
320 void QgsRichTextEditor::textBold()
321 {
322  QTextCharFormat format;
323  format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
324  mergeFormatOnWordOrSelection( format );
325 }
326 
327 void QgsRichTextEditor::focusInEvent( QFocusEvent * )
328 {
329  mTextEdit->setFocus( Qt::TabFocusReason );
330 }
331 
332 void QgsRichTextEditor::textUnderline()
333 {
334  QTextCharFormat format;
335  format.setFontUnderline( mActionUnderline->isChecked() );
336  mergeFormatOnWordOrSelection( format );
337 }
338 
339 void QgsRichTextEditor::textItalic()
340 {
341  QTextCharFormat format;
342  format.setFontItalic( mActionItalic->isChecked() );
343  mergeFormatOnWordOrSelection( format );
344 }
345 
346 void QgsRichTextEditor::textStrikeout()
347 {
348  QTextCharFormat format;
349  format.setFontStrikeOut( mActionStrikeOut->isChecked() );
350  mergeFormatOnWordOrSelection( format );
351 }
352 
353 void QgsRichTextEditor::textSize( const QString &p )
354 {
355  const qreal pointSize = p.toDouble();
356  if ( p.toFloat() > 0 )
357  {
358  QTextCharFormat format;
359  format.setFontPointSize( pointSize );
360  mergeFormatOnWordOrSelection( format );
361  }
362 }
363 
364 void QgsRichTextEditor::textLink( bool checked )
365 {
366  bool unlink = false;
367  QTextCharFormat format;
368  if ( checked )
369  {
370  const QString url = mTextEdit->currentCharFormat().anchorHref();
371  bool ok;
372  const QString newUrl = QInputDialog::getText( this, tr( "Create a Link" ),
373  tr( "Link URL:" ), QLineEdit::Normal,
374  url,
375  &ok );
376  if ( ok )
377  {
378  format.setAnchor( true );
379  format.setAnchorHref( newUrl );
380  format.setForeground( palette().color( QPalette::Link ) );
381  format.setFontUnderline( true );
382  }
383  else
384  {
385  unlink = true;
386  }
387  }
388  else
389  {
390  unlink = true;
391  }
392  if ( unlink )
393  {
394  format.setAnchor( false );
395  format.setForeground( palette().color( QPalette::Text ) );
396  format.setFontUnderline( false );
397  }
398  mergeFormatOnWordOrSelection( format );
399 }
400 
401 void QgsRichTextEditor::textStyle( int )
402 {
403  QTextCursor cursor = mTextEdit->textCursor();
404  cursor.beginEditBlock();
405 
406  // standard
407  if ( !cursor.hasSelection() )
408  {
409  cursor.select( QTextCursor::BlockUnderCursor );
410  }
411  QTextCharFormat format;
412  cursor.setCharFormat( format );
413  mTextEdit->setCurrentCharFormat( format );
414 
415  const ParagraphItems style = static_cast< ParagraphItems >( mParagraphStyleCombo->currentData().toInt() );
416 
417  switch ( style )
418  {
419  case QgsRichTextEditor::ParagraphStandard:
420  break;
421 
422  case QgsRichTextEditor::ParagraphHeading1:
423  format.setFontPointSize( mFontSizeH1 );
424  format.setFontWeight( QFont::Bold );
425  break;
426 
427  case QgsRichTextEditor::ParagraphHeading2:
428  format.setFontPointSize( mFontSizeH2 );
429  format.setFontWeight( QFont::Bold );
430  format.setFontItalic( true );
431  break;
432 
433  case QgsRichTextEditor::ParagraphHeading3:
434  format.setFontPointSize( mFontSizeH3 );
435  format.setFontWeight( QFont::Bold );
436  break;
437 
438  case QgsRichTextEditor::ParagraphHeading4:
439  format.setFontPointSize( mFontSizeH4 );
440  format.setFontWeight( QFont::Bold );
441  format.setFontItalic( true );
442  break;
443 
444  case QgsRichTextEditor::ParagraphMonospace:
445  {
446  format = cursor.charFormat();
447  format.setFontFamily( mMonospaceFontFamily );
448  format.setFontStyleHint( QFont::Monospace );
449  format.setFontFixedPitch( true );
450  break;
451  }
452  }
453 
454  cursor.setCharFormat( format );
455  mTextEdit->setCurrentCharFormat( format );
456 
457  cursor.endEditBlock();
458 }
459 
460 void QgsRichTextEditor::textFgColor()
461 {
462  QTextCharFormat format;
463  format.setForeground( mForeColorButton->color() );
464  mergeFormatOnWordOrSelection( format );
465 }
466 
467 void QgsRichTextEditor::textBgColor()
468 {
469  QTextCharFormat format;
470  const QColor col = mBackColorButton->color();
471  if ( col.isValid() )
472  {
473  format.setBackground( col );
474  }
475  else
476  {
477  format.clearBackground();
478  }
479  mergeFormatOnWordOrSelection( format );
480 }
481 
482 void QgsRichTextEditor::listBullet( bool checked )
483 {
484  if ( checked )
485  {
486  mActionOrderedList->setChecked( false );
487  }
488  list( checked, QTextListFormat::ListDisc );
489 }
490 
491 void QgsRichTextEditor::listOrdered( bool checked )
492 {
493  if ( checked )
494  {
495  mActionBulletList->setChecked( false );
496  }
497  list( checked, QTextListFormat::ListDecimal );
498 }
499 
500 void QgsRichTextEditor::list( bool checked, QTextListFormat::Style style )
501 {
502  QTextCursor cursor = mTextEdit->textCursor();
503  cursor.beginEditBlock();
504  if ( !checked )
505  {
506  const QTextBlockFormat originalFormat = cursor.blockFormat();
507  QTextBlockFormat format;
508  format.setIndent( originalFormat.indent() );
509  cursor.setBlockFormat( format );
510  }
511  else
512  {
513  QTextListFormat listFormat;
514  if ( cursor.currentList() )
515  {
516  listFormat = cursor.currentList()->format();
517  }
518  listFormat.setStyle( style );
519  cursor.createList( listFormat );
520  }
521  cursor.endEditBlock();
522 }
523 
524 void QgsRichTextEditor::mergeFormatOnWordOrSelection( const QTextCharFormat &format )
525 {
526  QTextCursor cursor = mTextEdit->textCursor();
527  if ( !cursor.hasSelection() )
528  {
529  cursor.select( QTextCursor::WordUnderCursor );
530  }
531  cursor.mergeCharFormat( format );
532  mTextEdit->mergeCurrentCharFormat( format );
533  mTextEdit->setFocus( Qt::TabFocusReason );
534 }
535 
536 void QgsRichTextEditor::slotCursorPositionChanged()
537 {
538  QTextList *l = mTextEdit->textCursor().currentList();
539  if ( mLastBlockList && ( l == mLastBlockList || ( l != nullptr && mLastBlockList != nullptr
540  && l->format().style() == mLastBlockList->format().style() ) ) )
541  {
542  return;
543  }
544  mLastBlockList = l;
545  if ( l )
546  {
547  const QTextListFormat listFormat = l->format();
548  if ( listFormat.style() == QTextListFormat::ListDisc )
549  {
550  mActionBulletList->setChecked( true );
551  mActionOrderedList->setChecked( false );
552  }
553  else if ( listFormat.style() == QTextListFormat::ListDecimal )
554  {
555  mActionBulletList->setChecked( false );
556  mActionOrderedList->setChecked( true );
557  }
558  else
559  {
560  mActionBulletList->setChecked( false );
561  mActionOrderedList->setChecked( false );
562  }
563  }
564  else
565  {
566  mActionBulletList->setChecked( false );
567  mActionOrderedList->setChecked( false );
568  }
569 }
570 
571 void QgsRichTextEditor::fontChanged( const QFont &f )
572 {
573  mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
574  mActionBold->setChecked( f.bold() );
575  mActionItalic->setChecked( f.italic() );
576  mActionUnderline->setChecked( f.underline() );
577  mActionStrikeOut->setChecked( f.strikeOut() );
578  if ( f.pointSize() == mFontSizeH1 )
579  {
580  mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
581  }
582  else if ( f.pointSize() == mFontSizeH2 )
583  {
584  mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
585  }
586  else if ( f.pointSize() == mFontSizeH3 )
587  {
588  mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
589  }
590  else if ( f.pointSize() == mFontSizeH4 )
591  {
592  mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
593  }
594  else
595  {
596  if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
597  {
598  mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
599  }
600  else
601  {
602  mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
603  }
604  }
605  if ( mTextEdit->textCursor().currentList() )
606  {
607  const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
608  if ( listFormat.style() == QTextListFormat::ListDisc )
609  {
610  mActionBulletList->setChecked( true );
611  mActionOrderedList->setChecked( false );
612  }
613  else if ( listFormat.style() == QTextListFormat::ListDecimal )
614  {
615  mActionBulletList->setChecked( false );
616  mActionOrderedList->setChecked( true );
617  }
618  else
619  {
620  mActionBulletList->setChecked( false );
621  mActionOrderedList->setChecked( false );
622  }
623  }
624  else
625  {
626  mActionBulletList->setChecked( false );
627  mActionOrderedList->setChecked( false );
628  }
629 }
630 
631 void QgsRichTextEditor::fgColorChanged( const QColor &c )
632 {
633  whileBlocking( mForeColorButton )->setColor( c );
634 }
635 
636 void QgsRichTextEditor::bgColorChanged( const QColor &c )
637 {
638  if ( c.isValid() )
639  whileBlocking( mBackColorButton )->setColor( c );
640  else
641  whileBlocking( mBackColorButton )->setToNull();
642 }
643 
644 void QgsRichTextEditor::slotCurrentCharFormatChanged( const QTextCharFormat &format )
645 {
646  fontChanged( format.font() );
647  bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
648  fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
649  mActionInsertLink->setChecked( format.isAnchor() );
650 }
651 
652 void QgsRichTextEditor::slotClipboardDataChanged()
653 {
654 #ifndef QT_NO_CLIPBOARD
655  if ( const QMimeData *md = QApplication::clipboard()->mimeData() )
656  mActionPaste->setEnabled( md->hasText() );
657 #endif
658 }
659 
660 void QgsRichTextEditor::increaseIndentation()
661 {
662  indent( +1 );
663 }
664 
665 void QgsRichTextEditor::decreaseIndentation()
666 {
667  indent( -1 );
668 }
669 
670 void QgsRichTextEditor::indent( int delta )
671 {
672  QTextCursor cursor = mTextEdit->textCursor();
673  cursor.beginEditBlock();
674  QTextBlockFormat format = cursor.blockFormat();
675  const int indent = format.indent();
676  if ( indent + delta >= 0 )
677  {
678  format.setIndent( indent + delta );
679  }
680  cursor.setBlockFormat( format );
681  cursor.endEditBlock();
682 }
683 
684 void QgsRichTextEditor::setText( const QString &text )
685 {
686  if ( text.isEmpty() )
687  {
688  setPlainText( text );
689  return;
690  }
691  if ( text[0] == '<' )
692  {
693  setHtml( text );
694  }
695  else
696  {
697  setPlainText( text );
698  }
699 }
700 
701 void QgsRichTextEditor::insertImage()
702 {
703  const QSettings s;
704  const QString attdir = s.value( QStringLiteral( "general/filedialog-path" ) ).toString();
705  const QString file = QFileDialog::getOpenFileName( this,
706  tr( "Select an image" ),
707  attdir,
708  tr( "JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
709  if ( file.isEmpty() )
710  return;
711 
712  const QImage image = QImageReader( file ).read();
713 
714  mTextEdit->dropImage( image, QFileInfo( file ).suffix().toUpper().toLocal8Bit().data() );
715 }
A HTML editor based on QScintilla2.
static QFont getMonospaceFont()
Returns the monospaced font to use for code editors.
A cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
void setColorDialogTitle(const QString &title)
Set the title for the color chooser dialog window.
void setShowNull(bool showNull, const QString &nullString=QString())
Sets whether a set to null (clear) option is shown in the button's drop-down menu.
void setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color.
void setShowNoColor(const bool showNoColorOption)
Sets whether the "no color" option should be shown in the button's drop-down menu.
void setToNull()
Sets color to null.
void setColor(const QColor &color)
Sets the current color for the button.
QgsRichTextEditor(QWidget *parent=nullptr)
Constructor for QgsRichTextEditor, with the specified parent widget.
QString toPlainText() const
Returns the widget's content as a plain text string.
QString toHtml() const
Returns the widget's content as a HTML string.
void clearSource()
Clears the current text from the widget.
void focusInEvent(QFocusEvent *event) override
void setText(const QString &text)
Sets the text to show in the widget.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:1185