38 #include <QApplication>
40 #include <QFontDatabase>
41 #include <QInputDialog>
44 #include <QFileDialog>
45 #include <QImageReader>
50 #include <QToolButton>
59 QVBoxLayout *sourceLayout =
new QVBoxLayout();
60 sourceLayout->setContentsMargins( 0, 0, 0, 0 );
62 sourceLayout->addWidget( mSourceEdit );
63 mPageSourceEdit->setLayout( sourceLayout );
67 connect( mTextEdit, &QTextEdit::currentCharFormatChanged,
this, &QgsRichTextEditor::slotCurrentCharFormatChanged );
68 connect( mTextEdit, &QTextEdit::cursorPositionChanged,
this, &QgsRichTextEditor::slotCursorPositionChanged );
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 );
79 connect( mParagraphStyleCombo, qOverload< int >( &QComboBox::activated ),
this, &QgsRichTextEditor::textStyle );
80 mToolBar->insertWidget( mToolBar->actions().at( 0 ), mParagraphStyleCombo );
82 mFontSizeCombo =
new QComboBox();
83 mFontSizeCombo->setEditable(
true );
84 mToolBar->insertWidget( mActionBold, mFontSizeCombo );
87 mActionUndo->setShortcut( QKeySequence::Undo );
88 mActionRedo->setShortcut( QKeySequence::Redo );
90 connect( mTextEdit->document(), &QTextDocument::undoAvailable, mActionUndo, &QAction::setEnabled );
91 connect( mTextEdit->document(), &QTextDocument::redoAvailable, mActionRedo, &QAction::setEnabled );
93 mActionUndo->setEnabled( mTextEdit->document()->isUndoAvailable() );
94 mActionRedo->setEnabled( mTextEdit->document()->isRedoAvailable() );
96 connect( mActionUndo, &QAction::triggered, mTextEdit, &QTextEdit::undo );
97 connect( mActionRedo, &QAction::triggered, mTextEdit, &QTextEdit::redo );
100 mActionCut->setShortcut( QKeySequence::Cut );
101 mActionCopy->setShortcut( QKeySequence::Copy );
102 mActionPaste->setShortcut( QKeySequence::Paste );
104 mActionCut->setEnabled(
false );
105 mActionCopy->setEnabled(
false );
107 connect( mActionCut, &QAction::triggered, mTextEdit, &QTextEdit::cut );
108 connect( mActionCopy, &QAction::triggered, mTextEdit, &QTextEdit::copy );
109 connect( mActionPaste, &QAction::triggered, mTextEdit, &QTextEdit::paste );
111 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCut, &QAction::setEnabled );
112 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCopy, &QAction::setEnabled );
114 #ifndef QT_NO_CLIPBOARD
115 connect( QApplication::clipboard(), &QClipboard::dataChanged,
this, &QgsRichTextEditor::slotClipboardDataChanged );
119 mActionInsertLink->setShortcut( QKeySequence( QStringLiteral(
"CTRL+L" ) ) );
120 connect( mActionInsertLink, &QAction::triggered,
this, &QgsRichTextEditor::textLink );
123 mActionBold->setShortcut( QKeySequence( QStringLiteral(
"CTRL+B" ) ) );
124 mActionItalic->setShortcut( QKeySequence( QStringLiteral(
"CTRL+I" ) ) );
125 mActionUnderline->setShortcut( QKeySequence( QStringLiteral(
"CTRL+U" ) ) );
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 );
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 );
137 QAction *removeAllFormat =
new QAction( tr(
"Remove all Formatting" ),
this );
138 connect( removeAllFormat, &QAction::triggered,
this, &QgsRichTextEditor::textRemoveAllFormat );
139 mTextEdit->addAction( removeAllFormat );
141 QAction *clearText =
new QAction( tr(
"Clear all Content" ),
this );
143 mTextEdit->addAction( clearText );
145 QMenu *menu =
new QMenu(
this );
146 menu->addAction( removeAllFormat );
147 menu->addAction( removeFormat );
148 menu->addAction( clearText );
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 );
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 );
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 );
173 const QFontDatabase db;
174 const QList< int > sizes = db.standardSizes();
175 for (
const int size : sizes )
176 mFontSizeCombo->addItem( QString::number( size ), size );
178 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( QApplication::font().pointSize() ) );
184 mForeColorButton->
setColor( palette().windowText().color() );
186 mForeColorButton->setToolTip( tr(
"Foreground color" ) );
187 mForeColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
188 mForeColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
190 QAction *listSeparator = mToolBar->insertSeparator( mActionBulletList );
193 mToolBar->insertWidget( listSeparator, mForeColorButton );
199 mBackColorButton->setToolTip( tr(
"Background color" ) );
200 mBackColorButton->
setShowNull(
true, tr(
"No Background Color" ) );
202 mBackColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
203 mBackColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
205 mToolBar->insertWidget( listSeparator, mBackColorButton );
207 connect( mActionEditSource, &QAction::toggled,
this, &QgsRichTextEditor::editSource );
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 );
214 connect( mFontSizeCombo, &QComboBox::textActivated,
this, &QgsRichTextEditor::textSize );
217 fontChanged( mTextEdit->font() );
222 switch ( mStackedWidget->currentIndex() )
225 return mTextEdit->toPlainText();
229 mTextEdit->setText( mSourceEdit->text() );
230 return mTextEdit->toPlainText();
237 switch ( mStackedWidget->currentIndex() )
240 return mTextEdit->toHtml();
243 return mSourceEdit->text();
248 void QgsRichTextEditor::editSource(
bool enabled )
252 mSourceEdit->setText( mTextEdit->toHtml() );
253 mStackedWidget->setCurrentIndex( 1 );
257 mTextEdit->setHtml( mSourceEdit->text() );
258 mStackedWidget->setCurrentIndex( 0 );
259 mSourceEdit->clear();
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 );
289 void QgsRichTextEditor::textRemoveFormat()
291 QTextCharFormat format;
292 format.setFontWeight( QFont::Normal );
293 format.setFontUnderline(
false );
294 format.setFontStrikeOut(
false );
295 format.setFontItalic(
false );
296 format.setFontPointSize( 9 );
298 mActionBold->setChecked(
false );
299 mActionUnderline->setChecked(
false );
300 mActionItalic->setChecked(
false );
301 mActionStrikeOut->setChecked(
false );
302 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
304 format.clearBackground();
306 mergeFormatOnWordOrSelection( format );
309 void QgsRichTextEditor::textRemoveAllFormat()
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 );
320 void QgsRichTextEditor::textBold()
322 QTextCharFormat format;
323 format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
324 mergeFormatOnWordOrSelection( format );
329 mTextEdit->setFocus( Qt::TabFocusReason );
332 void QgsRichTextEditor::textUnderline()
334 QTextCharFormat format;
335 format.setFontUnderline( mActionUnderline->isChecked() );
336 mergeFormatOnWordOrSelection( format );
339 void QgsRichTextEditor::textItalic()
341 QTextCharFormat format;
342 format.setFontItalic( mActionItalic->isChecked() );
343 mergeFormatOnWordOrSelection( format );
346 void QgsRichTextEditor::textStrikeout()
348 QTextCharFormat format;
349 format.setFontStrikeOut( mActionStrikeOut->isChecked() );
350 mergeFormatOnWordOrSelection( format );
353 void QgsRichTextEditor::textSize(
const QString &p )
355 const qreal pointSize = p.toDouble();
356 if ( p.toFloat() > 0 )
358 QTextCharFormat format;
359 format.setFontPointSize( pointSize );
360 mergeFormatOnWordOrSelection( format );
364 void QgsRichTextEditor::textLink(
bool checked )
367 QTextCharFormat format;
370 const QString url = mTextEdit->currentCharFormat().anchorHref();
372 const QString newUrl = QInputDialog::getText(
this, tr(
"Create a Link" ),
373 tr(
"Link URL:" ), QLineEdit::Normal,
378 format.setAnchor(
true );
379 format.setAnchorHref( newUrl );
380 format.setForeground( palette().color( QPalette::Link ) );
381 format.setFontUnderline(
true );
394 format.setAnchor(
false );
395 format.setForeground( palette().color( QPalette::Text ) );
396 format.setFontUnderline(
false );
398 mergeFormatOnWordOrSelection( format );
401 void QgsRichTextEditor::textStyle(
int )
403 QTextCursor cursor = mTextEdit->textCursor();
404 cursor.beginEditBlock();
407 if ( !cursor.hasSelection() )
409 cursor.select( QTextCursor::BlockUnderCursor );
411 QTextCharFormat format;
412 cursor.setCharFormat( format );
413 mTextEdit->setCurrentCharFormat( format );
415 const ParagraphItems style =
static_cast< ParagraphItems
>( mParagraphStyleCombo->currentData().toInt() );
419 case QgsRichTextEditor::ParagraphStandard:
422 case QgsRichTextEditor::ParagraphHeading1:
423 format.setFontPointSize( mFontSizeH1 );
424 format.setFontWeight( QFont::Bold );
427 case QgsRichTextEditor::ParagraphHeading2:
428 format.setFontPointSize( mFontSizeH2 );
429 format.setFontWeight( QFont::Bold );
430 format.setFontItalic(
true );
433 case QgsRichTextEditor::ParagraphHeading3:
434 format.setFontPointSize( mFontSizeH3 );
435 format.setFontWeight( QFont::Bold );
438 case QgsRichTextEditor::ParagraphHeading4:
439 format.setFontPointSize( mFontSizeH4 );
440 format.setFontWeight( QFont::Bold );
441 format.setFontItalic(
true );
444 case QgsRichTextEditor::ParagraphMonospace:
446 format = cursor.charFormat();
447 format.setFontFamily( mMonospaceFontFamily );
448 format.setFontStyleHint( QFont::Monospace );
449 format.setFontFixedPitch(
true );
454 cursor.setCharFormat( format );
455 mTextEdit->setCurrentCharFormat( format );
457 cursor.endEditBlock();
460 void QgsRichTextEditor::textFgColor()
462 QTextCharFormat format;
463 format.setForeground( mForeColorButton->
color() );
464 mergeFormatOnWordOrSelection( format );
467 void QgsRichTextEditor::textBgColor()
469 QTextCharFormat format;
470 const QColor col = mBackColorButton->
color();
473 format.setBackground( col );
477 format.clearBackground();
479 mergeFormatOnWordOrSelection( format );
482 void QgsRichTextEditor::listBullet(
bool checked )
486 mActionOrderedList->setChecked(
false );
488 list( checked, QTextListFormat::ListDisc );
491 void QgsRichTextEditor::listOrdered(
bool checked )
495 mActionBulletList->setChecked(
false );
497 list( checked, QTextListFormat::ListDecimal );
500 void QgsRichTextEditor::list(
bool checked, QTextListFormat::Style style )
502 QTextCursor cursor = mTextEdit->textCursor();
503 cursor.beginEditBlock();
506 const QTextBlockFormat originalFormat = cursor.blockFormat();
507 QTextBlockFormat format;
508 format.setIndent( originalFormat.indent() );
509 cursor.setBlockFormat( format );
513 QTextListFormat listFormat;
514 if ( cursor.currentList() )
516 listFormat = cursor.currentList()->format();
518 listFormat.setStyle( style );
519 cursor.createList( listFormat );
521 cursor.endEditBlock();
524 void QgsRichTextEditor::mergeFormatOnWordOrSelection(
const QTextCharFormat &format )
526 QTextCursor cursor = mTextEdit->textCursor();
527 if ( !cursor.hasSelection() )
529 cursor.select( QTextCursor::WordUnderCursor );
531 cursor.mergeCharFormat( format );
532 mTextEdit->mergeCurrentCharFormat( format );
533 mTextEdit->setFocus( Qt::TabFocusReason );
536 void QgsRichTextEditor::slotCursorPositionChanged()
538 QTextList *l = mTextEdit->textCursor().currentList();
539 if ( mLastBlockList && ( l == mLastBlockList || ( l !=
nullptr && mLastBlockList !=
nullptr
540 && l->format().style() == mLastBlockList->format().style() ) ) )
547 const QTextListFormat listFormat = l->format();
548 if ( listFormat.style() == QTextListFormat::ListDisc )
550 mActionBulletList->setChecked(
true );
551 mActionOrderedList->setChecked(
false );
553 else if ( listFormat.style() == QTextListFormat::ListDecimal )
555 mActionBulletList->setChecked(
false );
556 mActionOrderedList->setChecked(
true );
560 mActionBulletList->setChecked(
false );
561 mActionOrderedList->setChecked(
false );
566 mActionBulletList->setChecked(
false );
567 mActionOrderedList->setChecked(
false );
571 void QgsRichTextEditor::fontChanged(
const QFont &f )
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 )
580 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
582 else if ( f.pointSize() == mFontSizeH2 )
584 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
586 else if ( f.pointSize() == mFontSizeH3 )
588 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
590 else if ( f.pointSize() == mFontSizeH4 )
592 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
596 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
598 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
602 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
605 if ( mTextEdit->textCursor().currentList() )
607 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
608 if ( listFormat.style() == QTextListFormat::ListDisc )
610 mActionBulletList->setChecked(
true );
611 mActionOrderedList->setChecked(
false );
613 else if ( listFormat.style() == QTextListFormat::ListDecimal )
615 mActionBulletList->setChecked(
false );
616 mActionOrderedList->setChecked(
true );
620 mActionBulletList->setChecked(
false );
621 mActionOrderedList->setChecked(
false );
626 mActionBulletList->setChecked(
false );
627 mActionOrderedList->setChecked(
false );
631 void QgsRichTextEditor::fgColorChanged(
const QColor &
c )
636 void QgsRichTextEditor::bgColorChanged(
const QColor &
c )
644 void QgsRichTextEditor::slotCurrentCharFormatChanged(
const QTextCharFormat &format )
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() );
652 void QgsRichTextEditor::slotClipboardDataChanged()
654 #ifndef QT_NO_CLIPBOARD
655 if (
const QMimeData *md = QApplication::clipboard()->mimeData() )
656 mActionPaste->setEnabled( md->hasText() );
660 void QgsRichTextEditor::increaseIndentation()
665 void QgsRichTextEditor::decreaseIndentation()
670 void QgsRichTextEditor::indent(
int delta )
672 QTextCursor cursor = mTextEdit->textCursor();
673 cursor.beginEditBlock();
674 QTextBlockFormat format = cursor.blockFormat();
675 const int indent = format.indent();
676 if ( indent + delta >= 0 )
678 format.setIndent( indent + delta );
680 cursor.setBlockFormat( format );
681 cursor.endEditBlock();
686 if ( text.isEmpty() )
688 setPlainText( text );
691 if ( text[0] ==
'<' )
697 setPlainText( text );
701 void QgsRichTextEditor::insertImage()
704 const QString attdir = s.value( QStringLiteral(
"general/filedialog-path" ) ).toString();
705 const QString file = QFileDialog::getOpenFileName(
this,
706 tr(
"Select an image" ),
708 tr(
"JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
709 if ( file.isEmpty() )
712 const QImage image = QImageReader( file ).read();
714 mTextEdit->dropImage( image, QFileInfo( file ).suffix().toUpper().toLocal8Bit().data() );
A HTML editor based on QScintilla2.
static QFont getMonospaceFont()
Returns the monospaced font to use for code editors.
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.