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