QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
33#include "qgscodeeditor.h"
34#include "qgscodeeditorhtml.h"
35#include "qgscodeeditorwidget.h"
36#include "qgscolorbutton.h"
37#include "qgsguiutils.h"
38
39#include <QApplication>
40#include <QClipboard>
41#include <QComboBox>
42#include <QFileDialog>
43#include <QFontDatabase>
44#include <QImageReader>
45#include <QInputDialog>
46#include <QMenu>
47#include <QMimeData>
48#include <QSettings>
49#include <QTextList>
50#include <QToolButton>
51#include <QUrl>
52#include <QtDebug>
53
54#include "moc_qgsrichtexteditor.cpp"
55
57 : QWidget( parent )
58{
59 setupUi( this );
60
61 mMonospaceFontFamily = QgsCodeEditor::getMonospaceFont().family();
62
63 QVBoxLayout *sourceLayout = new QVBoxLayout();
64 sourceLayout->setContentsMargins( 0, 0, 0, 0 );
65 mSourceEdit = new QgsCodeEditorHTML();
66 QgsCodeEditorWidget *codeEditorWidget = new QgsCodeEditorWidget( mSourceEdit );
67 sourceLayout->addWidget( codeEditorWidget );
68 mPageSourceEdit->setLayout( sourceLayout );
69
70 mToolBar->setIconSize( QgsGuiUtils::iconSize( false ) );
71
72 connect( mTextEdit, &QTextEdit::currentCharFormatChanged, this, &QgsRichTextEditor::slotCurrentCharFormatChanged );
73 connect( mTextEdit, &QTextEdit::cursorPositionChanged, this, &QgsRichTextEditor::slotCursorPositionChanged );
74
75 // undo & redo
76 mActionUndo->setShortcut( QKeySequence::Undo );
77 mActionRedo->setShortcut( QKeySequence::Redo );
78
79 connect( mTextEdit->document(), &QTextDocument::undoAvailable, mActionUndo, &QAction::setEnabled );
80 connect( mTextEdit->document(), &QTextDocument::redoAvailable, mActionRedo, &QAction::setEnabled );
81
82 mActionUndo->setEnabled( mTextEdit->document()->isUndoAvailable() );
83 mActionRedo->setEnabled( mTextEdit->document()->isRedoAvailable() );
84
85 connect( mActionUndo, &QAction::triggered, mTextEdit, &QTextEdit::undo );
86 connect( mActionRedo, &QAction::triggered, mTextEdit, &QTextEdit::redo );
87
88 // cut, copy & paste
89 mActionCut->setShortcut( QKeySequence::Cut );
90 mActionCopy->setShortcut( QKeySequence::Copy );
91 mActionPaste->setShortcut( QKeySequence::Paste );
92
93 mActionCut->setEnabled( false );
94 mActionCopy->setEnabled( false );
95
96 connect( mActionCut, &QAction::triggered, mTextEdit, &QTextEdit::cut );
97 connect( mActionCopy, &QAction::triggered, mTextEdit, &QTextEdit::copy );
98 connect( mActionPaste, &QAction::triggered, mTextEdit, &QTextEdit::paste );
99
100 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCut, &QAction::setEnabled );
101 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCopy, &QAction::setEnabled );
102
103#ifndef QT_NO_CLIPBOARD
104 connect( QApplication::clipboard(), &QClipboard::dataChanged, this, &QgsRichTextEditor::slotClipboardDataChanged );
105#endif
106
107 // link
108 mActionInsertLink->setShortcut( QKeySequence( QStringLiteral( "CTRL+L" ) ) );
109 connect( mActionInsertLink, &QAction::triggered, this, &QgsRichTextEditor::textLink );
110
111 // bold, italic & underline
112 mActionBold->setShortcut( QKeySequence( QStringLiteral( "CTRL+B" ) ) );
113 mActionItalic->setShortcut( QKeySequence( QStringLiteral( "CTRL+I" ) ) );
114 mActionUnderline->setShortcut( QKeySequence( QStringLiteral( "CTRL+U" ) ) );
115
116 connect( mActionBold, &QAction::triggered, this, &QgsRichTextEditor::textBold );
117 connect( mActionItalic, &QAction::triggered, this, &QgsRichTextEditor::textItalic );
118 connect( mActionUnderline, &QAction::triggered, this, &QgsRichTextEditor::textUnderline );
119 connect( mActionStrikeOut, &QAction::triggered, this, &QgsRichTextEditor::textStrikeout );
120
121 // lists
122 mActionBulletList->setShortcut( QKeySequence( QStringLiteral( "CTRL+-" ) ) );
123 mActionOrderedList->setShortcut( QKeySequence( QStringLiteral( "CTRL+=" ) ) );
124 connect( mActionBulletList, &QAction::triggered, this, &QgsRichTextEditor::listBullet );
125 connect( mActionOrderedList, &QAction::triggered, this, &QgsRichTextEditor::listOrdered );
126
127 // indentation
128 mActionDecreaseIndent->setShortcut( QKeySequence( QStringLiteral( "CTRL+," ) ) );
129 mActionIncreaseIndent->setShortcut( QKeySequence( QStringLiteral( "CTRL+." ) ) );
130 connect( mActionIncreaseIndent, &QAction::triggered, this, &QgsRichTextEditor::increaseIndentation );
131 connect( mActionDecreaseIndent, &QAction::triggered, this, &QgsRichTextEditor::decreaseIndentation );
132
133 connect( mActionEditSource, &QAction::toggled, this, &QgsRichTextEditor::editSource );
134
135 // images
136 connect( mActionInsertImage, &QAction::triggered, this, &QgsRichTextEditor::insertImage );
137
139
140 fontChanged( mTextEdit->font() );
141
142 connect( mTextEdit, &QTextEdit::textChanged, this, &QgsRichTextEditor::textChanged );
143 connect( mSourceEdit, &QgsCodeEditorHTML::textChanged, this, &QgsRichTextEditor::textChanged );
144}
145
147{
148 mMode = mode;
149
150 delete mFontSizeCombo;
151 mFontSizeCombo = nullptr;
152 delete mParagraphStyleCombo;
153 mParagraphStyleCombo = nullptr;
154 delete mForeColorButton;
155 mForeColorButton = nullptr;
156 delete mBackColorButton;
157 mBackColorButton = nullptr;
158
159 mToolBar->clear();
160
161 // paragraph formatting
162 mParagraphStyleCombo = new QComboBox();
163 mParagraphStyleCombo->addItem( tr( "Standard" ), ParagraphStandard );
164 mParagraphStyleCombo->addItem( tr( "Heading 1" ), ParagraphHeading1 );
165 mParagraphStyleCombo->addItem( tr( "Heading 2" ), ParagraphHeading2 );
166 mParagraphStyleCombo->addItem( tr( "Heading 3" ), ParagraphHeading3 );
167 mParagraphStyleCombo->addItem( tr( "Heading 4" ), ParagraphHeading4 );
168 mParagraphStyleCombo->addItem( tr( "Monospace" ), ParagraphMonospace );
169
170 connect( mParagraphStyleCombo, qOverload<int>( &QComboBox::activated ), this, &QgsRichTextEditor::textStyle );
171 if ( mode == Mode::QTextDocument )
172 {
173 mToolBar->addWidget( mParagraphStyleCombo );
174 }
175
176 mToolBar->addAction( mActionUndo );
177 mToolBar->addAction( mActionRedo );
178 mToolBar->addAction( mActionCut );
179 mToolBar->addAction( mActionCopy );
180 mToolBar->addAction( mActionPaste );
181
182 // font size
183 mFontSizeCombo = new QComboBox();
184 mFontSizeCombo->setEditable( true );
185
186 const QList<int> sizes = QFontDatabase::standardSizes();
187 for ( const int size : sizes )
188 mFontSizeCombo->addItem( QString::number( size ), size );
189
190 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( QApplication::font().pointSize() ) );
191 connect( mFontSizeCombo, &QComboBox::textActivated, this, &QgsRichTextEditor::textSize );
192
193 if ( mode != Mode::PlainText )
194 {
195 mToolBar->addSeparator();
196 mToolBar->addWidget( mFontSizeCombo );
197 mToolBar->addAction( mActionBold );
198 mToolBar->addAction( mActionItalic );
199 mToolBar->addAction( mActionUnderline );
200 mToolBar->addAction( mActionStrikeOut );
201
202 mToolBar->addSeparator();
203 }
204
205 // text foreground color
206 mForeColorButton = new QgsColorButton();
207 mForeColorButton->setAllowOpacity( false );
208 mForeColorButton->setColorDialogTitle( tr( "Foreground Color" ) );
209 mForeColorButton->setColor( palette().windowText().color() );
210 mForeColorButton->setShowNoColor( false );
211 mForeColorButton->setToolTip( tr( "Foreground color" ) );
212 mForeColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral( "x" ) ) * 10 );
213 mForeColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
214
215 connect( mForeColorButton, &QgsColorButton::colorChanged, this, &QgsRichTextEditor::textFgColor );
216
217 if ( mode != Mode::PlainText )
218 {
219 mToolBar->addWidget( mForeColorButton );
220 }
221
222 // text background color
223 mBackColorButton = new QgsColorButton();
224 mBackColorButton->setAllowOpacity( false );
225 mBackColorButton->setColorDialogTitle( tr( "Background Color" ) );
226 mBackColorButton->setToolTip( tr( "Background color" ) );
227 mBackColorButton->setShowNull( true, tr( "No Background Color" ) );
228 mBackColorButton->setToNull();
229 mBackColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
230 mBackColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral( "x" ) ) * 10 );
231 connect( mBackColorButton, &QgsColorButton::colorChanged, this, &QgsRichTextEditor::textBgColor );
232
233 if ( mode == Mode::QTextDocument )
234 {
235 mToolBar->addWidget( mBackColorButton );
236 mToolBar->addAction( mActionBulletList );
237 mToolBar->addAction( mActionOrderedList );
238 mToolBar->addAction( mActionDecreaseIndent );
239 mToolBar->addAction( mActionIncreaseIndent );
240 mToolBar->addSeparator();
241 mToolBar->addAction( mActionInsertLink );
242 mToolBar->addAction( mActionInsertImage );
243 }
244 if ( mode != Mode::PlainText )
245 {
246 mToolBar->addAction( mActionEditSource );
247 }
248
249 QMenu *menu = new QMenu( this );
250 if ( mode != Mode::PlainText )
251 {
252 QAction *removeFormat = new QAction( tr( "Remove Character Formatting" ), menu );
253 removeFormat->setShortcut( QKeySequence( QStringLiteral( "CTRL+M" ) ) );
254 connect( removeFormat, &QAction::triggered, this, &QgsRichTextEditor::textRemoveFormat );
255 mTextEdit->addAction( removeFormat );
256
257 QAction *removeAllFormat = new QAction( tr( "Remove all Formatting" ), menu );
258 connect( removeAllFormat, &QAction::triggered, this, &QgsRichTextEditor::textRemoveAllFormat );
259 mTextEdit->addAction( removeAllFormat );
260 menu->addAction( removeAllFormat );
261 menu->addAction( removeFormat );
262 }
263
264 QAction *clearText = new QAction( tr( "Clear all Content" ), menu );
265 connect( clearText, &QAction::triggered, this, &QgsRichTextEditor::clearSource );
266 mTextEdit->addAction( clearText );
267
268 menu->addAction( clearText );
269
270 QToolButton *menuButton = new QToolButton( mToolBar );
271 menuButton->setMenu( menu );
272 menuButton->setPopupMode( QToolButton::InstantPopup );
273 menuButton->setToolTip( tr( "Advanced Options" ) );
274 menuButton->setText( QStringLiteral( "…" ) );
275
276 QWidget *spacer = new QWidget();
277 spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
278 mToolBar->addWidget( spacer );
279 mToolBar->addWidget( menuButton );
280
281 if ( mode == Mode::PlainText )
282 {
283 editSource( false );
284 }
285}
286
288{
289 switch ( mStackedWidget->currentIndex() )
290 {
291 case 0:
292 return mTextEdit->toPlainText();
293
294 case 1:
295 // go via text edit to remove html from text...
296 mTextEdit->setText( mSourceEdit->text() );
297 return mTextEdit->toPlainText();
298
299 default:
300 break;
301 }
302 return QString();
303}
304
306{
307 switch ( mStackedWidget->currentIndex() )
308 {
309 case 0:
310 return mTextEdit->toHtml();
311
312 case 1:
313 return mSourceEdit->text();
314
315 default:
316 break;
317 }
318 return QString();
319}
320
321void QgsRichTextEditor::editSource( bool enabled )
322{
323 if ( enabled && mStackedWidget->currentIndex() == 0 )
324 {
325 mSourceEdit->setText( mTextEdit->toHtml() );
326 mStackedWidget->setCurrentIndex( 1 );
327 }
328 else if ( !enabled && mStackedWidget->currentIndex() == 1 )
329 {
330 mTextEdit->setHtml( mSourceEdit->text() );
331 mStackedWidget->setCurrentIndex( 0 );
332 mSourceEdit->clear();
333 }
334
335 // disable formatting actions when in html edit mode
336 mFontSizeCombo->setEnabled( !enabled );
337 mParagraphStyleCombo->setEnabled( !enabled );
338 mForeColorButton->setEnabled( !enabled );
339 mBackColorButton->setEnabled( !enabled );
340 mActionUndo->setEnabled( !enabled );
341 mActionRedo->setEnabled( !enabled );
342 mActionCut->setEnabled( !enabled );
343 mActionCopy->setEnabled( !enabled );
344 mActionPaste->setEnabled( !enabled );
345 mActionInsertLink->setEnabled( !enabled );
346 mActionBold->setEnabled( !enabled );
347 mActionItalic->setEnabled( !enabled );
348 mActionUnderline->setEnabled( !enabled );
349 mActionStrikeOut->setEnabled( !enabled );
350 mActionBulletList->setEnabled( !enabled );
351 mActionOrderedList->setEnabled( !enabled );
352 mActionDecreaseIndent->setEnabled( !enabled );
353 mActionIncreaseIndent->setEnabled( !enabled );
354 mActionInsertImage->setEnabled( !enabled );
355}
356
358{
359 mTextEdit->clear();
360}
361
362void QgsRichTextEditor::textRemoveFormat()
363{
364 QTextCharFormat format;
365 format.setFontWeight( QFont::Normal );
366 format.setFontUnderline( false );
367 format.setFontStrikeOut( false );
368 format.setFontItalic( false );
369 format.setFontPointSize( 9 );
370
371 mActionBold->setChecked( false );
372 mActionUnderline->setChecked( false );
373 mActionItalic->setChecked( false );
374 mActionStrikeOut->setChecked( false );
375 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
376
377 format.clearBackground();
378
379 mergeFormatOnWordOrSelection( format );
380}
381
382void QgsRichTextEditor::textRemoveAllFormat()
383{
384 mActionBold->setChecked( false );
385 mActionUnderline->setChecked( false );
386 mActionItalic->setChecked( false );
387 mActionStrikeOut->setChecked( false );
388 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
389 const QString text = mTextEdit->toPlainText();
390 mTextEdit->setPlainText( text );
391}
392
393void QgsRichTextEditor::textBold()
394{
395 QTextCharFormat format;
396 format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
397 mergeFormatOnWordOrSelection( format );
398}
399
401{
402 mTextEdit->setFocus( Qt::TabFocusReason );
403}
404
405void QgsRichTextEditor::textUnderline()
406{
407 QTextCharFormat format;
408 format.setFontUnderline( mActionUnderline->isChecked() );
409 mergeFormatOnWordOrSelection( format );
410}
411
412void QgsRichTextEditor::textItalic()
413{
414 QTextCharFormat format;
415 format.setFontItalic( mActionItalic->isChecked() );
416 mergeFormatOnWordOrSelection( format );
417}
418
419void QgsRichTextEditor::textStrikeout()
420{
421 QTextCharFormat format;
422 format.setFontStrikeOut( mActionStrikeOut->isChecked() );
423 mergeFormatOnWordOrSelection( format );
424}
425
426void QgsRichTextEditor::textSize( const QString &p )
427{
428 const qreal pointSize = p.toDouble();
429 if ( p.toFloat() > 0 )
430 {
431 QTextCharFormat format;
432 format.setFontPointSize( pointSize );
433 mergeFormatOnWordOrSelection( format );
434 }
435}
436
437void QgsRichTextEditor::textLink( bool checked )
438{
439 bool unlink = false;
440 QTextCharFormat format;
441 if ( checked )
442 {
443 const QString url = mTextEdit->currentCharFormat().anchorHref();
444 bool ok;
445 const QString newUrl = QInputDialog::getText( this, tr( "Create a Link" ), tr( "Link URL:" ), QLineEdit::Normal, url, &ok );
446 if ( ok )
447 {
448 format.setAnchor( true );
449 format.setAnchorHref( newUrl );
450 format.setForeground( palette().color( QPalette::Link ) );
451 format.setFontUnderline( true );
452 }
453 else
454 {
455 unlink = true;
456 }
457 }
458 else
459 {
460 unlink = true;
461 }
462 if ( unlink )
463 {
464 format.setAnchor( false );
465 format.setForeground( palette().color( QPalette::Text ) );
466 format.setFontUnderline( false );
467 }
468 mergeFormatOnWordOrSelection( format );
469}
470
471void QgsRichTextEditor::textStyle( int index )
472{
473 QTextCursor cursor = mTextEdit->textCursor();
474 cursor.beginEditBlock();
475
476 // standard
477 if ( !cursor.hasSelection() )
478 {
479 cursor.select( QTextCursor::BlockUnderCursor );
480 }
481 QTextCharFormat format;
482 cursor.setCharFormat( format );
483 mTextEdit->setCurrentCharFormat( format );
484
485 const ParagraphItems style = static_cast<ParagraphItems>( mParagraphStyleCombo->itemData( index ).toInt() );
486
487 switch ( style )
488 {
489 case QgsRichTextEditor::ParagraphStandard:
490 break;
491
492 case QgsRichTextEditor::ParagraphHeading1:
493 format.setFontPointSize( mFontSizeH1 );
494 format.setFontWeight( QFont::Bold );
495 break;
496
497 case QgsRichTextEditor::ParagraphHeading2:
498 format.setFontPointSize( mFontSizeH2 );
499 format.setFontWeight( QFont::Bold );
500 format.setFontItalic( true );
501 break;
502
503 case QgsRichTextEditor::ParagraphHeading3:
504 format.setFontPointSize( mFontSizeH3 );
505 format.setFontWeight( QFont::Bold );
506 break;
507
508 case QgsRichTextEditor::ParagraphHeading4:
509 format.setFontPointSize( mFontSizeH4 );
510 format.setFontWeight( QFont::Bold );
511 format.setFontItalic( true );
512 break;
513
514 case QgsRichTextEditor::ParagraphMonospace:
515 {
516 format = cursor.charFormat();
517 format.setFontFamily( mMonospaceFontFamily );
518 format.setFontStyleHint( QFont::Monospace );
519 format.setFontFixedPitch( true );
520 break;
521 }
522 }
523
524 cursor.setCharFormat( format );
525 mTextEdit->setCurrentCharFormat( format );
526
527 cursor.endEditBlock();
528}
529
530void QgsRichTextEditor::textFgColor()
531{
532 QTextCharFormat format;
533 format.setForeground( mForeColorButton->color() );
534 mergeFormatOnWordOrSelection( format );
535}
536
537void QgsRichTextEditor::textBgColor()
538{
539 QTextCharFormat format;
540 const QColor col = mBackColorButton->color();
541 if ( col.isValid() )
542 {
543 format.setBackground( col );
544 }
545 else
546 {
547 format.clearBackground();
548 }
549 mergeFormatOnWordOrSelection( format );
550}
551
552void QgsRichTextEditor::listBullet( bool checked )
553{
554 if ( checked )
555 {
556 mActionOrderedList->setChecked( false );
557 }
558 list( checked, QTextListFormat::ListDisc );
559}
560
561void QgsRichTextEditor::listOrdered( bool checked )
562{
563 if ( checked )
564 {
565 mActionBulletList->setChecked( false );
566 }
567 list( checked, QTextListFormat::ListDecimal );
568}
569
570void QgsRichTextEditor::list( bool checked, QTextListFormat::Style style )
571{
572 QTextCursor cursor = mTextEdit->textCursor();
573 cursor.beginEditBlock();
574 if ( !checked )
575 {
576 const QTextBlockFormat originalFormat = cursor.blockFormat();
577 QTextBlockFormat format;
578 format.setIndent( originalFormat.indent() );
579 cursor.setBlockFormat( format );
580 }
581 else
582 {
583 QTextListFormat listFormat;
584 if ( cursor.currentList() )
585 {
586 listFormat = cursor.currentList()->format();
587 }
588 listFormat.setStyle( style );
589 cursor.createList( listFormat );
590 }
591 cursor.endEditBlock();
592}
593
594void QgsRichTextEditor::mergeFormatOnWordOrSelection( const QTextCharFormat &format )
595{
596 QTextCursor cursor = mTextEdit->textCursor();
597 if ( !cursor.hasSelection() )
598 {
599 cursor.select( QTextCursor::WordUnderCursor );
600 }
601 cursor.mergeCharFormat( format );
602 mTextEdit->mergeCurrentCharFormat( format );
603 mTextEdit->setFocus( Qt::TabFocusReason );
604}
605
606void QgsRichTextEditor::slotCursorPositionChanged()
607{
608 QTextList *l = mTextEdit->textCursor().currentList();
609 if ( mLastBlockList && ( l == mLastBlockList || ( l && mLastBlockList && l->format().style() == mLastBlockList->format().style() ) ) )
610 {
611 return;
612 }
613 mLastBlockList = l;
614 if ( l )
615 {
616 const QTextListFormat listFormat = l->format();
617 if ( listFormat.style() == QTextListFormat::ListDisc )
618 {
619 mActionBulletList->setChecked( true );
620 mActionOrderedList->setChecked( false );
621 }
622 else if ( listFormat.style() == QTextListFormat::ListDecimal )
623 {
624 mActionBulletList->setChecked( false );
625 mActionOrderedList->setChecked( true );
626 }
627 else
628 {
629 mActionBulletList->setChecked( false );
630 mActionOrderedList->setChecked( false );
631 }
632 }
633 else
634 {
635 mActionBulletList->setChecked( false );
636 mActionOrderedList->setChecked( false );
637 }
638}
639
640void QgsRichTextEditor::fontChanged( const QFont &f )
641{
642 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
643 mActionBold->setChecked( f.bold() );
644 mActionItalic->setChecked( f.italic() );
645 mActionUnderline->setChecked( f.underline() );
646 mActionStrikeOut->setChecked( f.strikeOut() );
647 if ( f.bold() && f.pointSize() == mFontSizeH1 )
648 {
649 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
650 }
651 else if ( f.bold() && f.pointSize() == mFontSizeH2 )
652 {
653 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
654 }
655 else if ( f.bold() && f.pointSize() == mFontSizeH3 )
656 {
657 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
658 }
659 else if ( f.bold() && f.pointSize() == mFontSizeH4 )
660 {
661 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
662 }
663 else
664 {
665 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
666 {
667 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
668 }
669 else
670 {
671 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
672 }
673 }
674 if ( mTextEdit->textCursor().currentList() )
675 {
676 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
677 if ( listFormat.style() == QTextListFormat::ListDisc )
678 {
679 mActionBulletList->setChecked( true );
680 mActionOrderedList->setChecked( false );
681 }
682 else if ( listFormat.style() == QTextListFormat::ListDecimal )
683 {
684 mActionBulletList->setChecked( false );
685 mActionOrderedList->setChecked( true );
686 }
687 else
688 {
689 mActionBulletList->setChecked( false );
690 mActionOrderedList->setChecked( false );
691 }
692 }
693 else
694 {
695 mActionBulletList->setChecked( false );
696 mActionOrderedList->setChecked( false );
697 }
698}
699
700void QgsRichTextEditor::fgColorChanged( const QColor &c )
701{
702 whileBlocking( mForeColorButton )->setColor( c );
703}
704
705void QgsRichTextEditor::bgColorChanged( const QColor &c )
706{
707 if ( c.isValid() )
708 whileBlocking( mBackColorButton )->setColor( c );
709 else
710 whileBlocking( mBackColorButton )->setToNull();
711}
712
713void QgsRichTextEditor::slotCurrentCharFormatChanged( const QTextCharFormat &format )
714{
715 fontChanged( format.font() );
716 bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
717 fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
718 mActionInsertLink->setChecked( format.isAnchor() );
719}
720
721void QgsRichTextEditor::slotClipboardDataChanged()
722{
723#ifndef QT_NO_CLIPBOARD
724 if ( const QMimeData *md = QApplication::clipboard()->mimeData() )
725 mActionPaste->setEnabled( md->hasText() );
726#endif
727}
728
729void QgsRichTextEditor::increaseIndentation()
730{
731 indent( +1 );
732}
733
734void QgsRichTextEditor::decreaseIndentation()
735{
736 indent( -1 );
737}
738
739void QgsRichTextEditor::indent( int delta )
740{
741 QTextCursor cursor = mTextEdit->textCursor();
742 cursor.beginEditBlock();
743 QTextBlockFormat format = cursor.blockFormat();
744 const int indent = format.indent();
745 if ( indent + delta >= 0 )
746 {
747 format.setIndent( indent + delta );
748 }
749 cursor.setBlockFormat( format );
750 cursor.endEditBlock();
751}
752
753void QgsRichTextEditor::setText( const QString &text )
754{
755 if ( text.isEmpty() )
756 {
757 mTextEdit->setPlainText( text );
758 mSourceEdit->clear();
759 return;
760 }
761
762 const thread_local QRegularExpression sIsHtmlRx( QStringLiteral( "^\\s*<" ) );
763 if ( sIsHtmlRx.match( text ).hasMatch() )
764 {
765 mTextEdit->setHtml( text );
766 mSourceEdit->setText( text );
767 }
768 else
769 {
770 mTextEdit->setPlainText( text );
771 mSourceEdit->setText( text );
772 }
773}
774
775void QgsRichTextEditor::insertImage()
776{
777 const QSettings s;
778 const QString attdir = s.value( QStringLiteral( "general/filedialog-path" ) ).toString();
779 const QString file = QFileDialog::getOpenFileName( this, tr( "Select an image" ), attdir, tr( "JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
780 if ( file.isEmpty() )
781 return;
782
783 const QImage image = QImageReader( file ).read();
784
785 mTextEdit->dropImage( image, QFileInfo( file ).suffix().toUpper().toLocal8Bit().data() );
786}
A HTML editor based on QScintilla2.
A widget which wraps a QgsCodeEditor in additional functionality.
void setText(const QString &text) override
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.
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.
Mode mode() const
Returns the widget's mode, which defines which formatting options are exposed in the widget.
void setMode(Mode mode)
Sets the widget's mode, which defines which formatting options are exposed in the widget.
@ QTextDocument
Default mode, exposes the Qt supported HTML/CSS subset.
@ PlainText
Plain text mode.
QString toHtml() const
Returns the widget's content as a HTML string.
void textChanged()
Emitted when the text contents are changed.
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:6511