39#include <QApplication>
41#include <QFontDatabase>
42#include <QInputDialog>
46#include <QImageReader>
60 QVBoxLayout *sourceLayout =
new QVBoxLayout();
61 sourceLayout->setContentsMargins( 0, 0, 0, 0 );
64 sourceLayout->addWidget( codeEditorWidget );
65 mPageSourceEdit->setLayout( sourceLayout );
69 connect( mTextEdit, &QTextEdit::currentCharFormatChanged,
this, &QgsRichTextEditor::slotCurrentCharFormatChanged );
70 connect( mTextEdit, &QTextEdit::cursorPositionChanged,
this, &QgsRichTextEditor::slotCursorPositionChanged );
73 mActionUndo->setShortcut( QKeySequence::Undo );
74 mActionRedo->setShortcut( QKeySequence::Redo );
76 connect( mTextEdit->document(), &QTextDocument::undoAvailable, mActionUndo, &QAction::setEnabled );
77 connect( mTextEdit->document(), &QTextDocument::redoAvailable, mActionRedo, &QAction::setEnabled );
79 mActionUndo->setEnabled( mTextEdit->document()->isUndoAvailable() );
80 mActionRedo->setEnabled( mTextEdit->document()->isRedoAvailable() );
82 connect( mActionUndo, &QAction::triggered, mTextEdit, &QTextEdit::undo );
83 connect( mActionRedo, &QAction::triggered, mTextEdit, &QTextEdit::redo );
86 mActionCut->setShortcut( QKeySequence::Cut );
87 mActionCopy->setShortcut( QKeySequence::Copy );
88 mActionPaste->setShortcut( QKeySequence::Paste );
90 mActionCut->setEnabled(
false );
91 mActionCopy->setEnabled(
false );
93 connect( mActionCut, &QAction::triggered, mTextEdit, &QTextEdit::cut );
94 connect( mActionCopy, &QAction::triggered, mTextEdit, &QTextEdit::copy );
95 connect( mActionPaste, &QAction::triggered, mTextEdit, &QTextEdit::paste );
97 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCut, &QAction::setEnabled );
98 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCopy, &QAction::setEnabled );
100#ifndef QT_NO_CLIPBOARD
101 connect( QApplication::clipboard(), &QClipboard::dataChanged,
this, &QgsRichTextEditor::slotClipboardDataChanged );
105 mActionInsertLink->setShortcut( QKeySequence( QStringLiteral(
"CTRL+L" ) ) );
106 connect( mActionInsertLink, &QAction::triggered,
this, &QgsRichTextEditor::textLink );
109 mActionBold->setShortcut( QKeySequence( QStringLiteral(
"CTRL+B" ) ) );
110 mActionItalic->setShortcut( QKeySequence( QStringLiteral(
"CTRL+I" ) ) );
111 mActionUnderline->setShortcut( QKeySequence( QStringLiteral(
"CTRL+U" ) ) );
113 connect( mActionBold, &QAction::triggered,
this, &QgsRichTextEditor::textBold );
114 connect( mActionItalic, &QAction::triggered,
this, &QgsRichTextEditor::textItalic );
115 connect( mActionUnderline, &QAction::triggered,
this, &QgsRichTextEditor::textUnderline );
116 connect( mActionStrikeOut, &QAction::triggered,
this, &QgsRichTextEditor::textStrikeout );
119 mActionBulletList->setShortcut( QKeySequence( QStringLiteral(
"CTRL+-" ) ) );
120 mActionOrderedList->setShortcut( QKeySequence( QStringLiteral(
"CTRL+=" ) ) );
121 connect( mActionBulletList, &QAction::triggered,
this, &QgsRichTextEditor::listBullet );
122 connect( mActionOrderedList, &QAction::triggered,
this, &QgsRichTextEditor::listOrdered );
125 mActionDecreaseIndent->setShortcut( QKeySequence( QStringLiteral(
"CTRL+," ) ) );
126 mActionIncreaseIndent->setShortcut( QKeySequence( QStringLiteral(
"CTRL+." ) ) );
127 connect( mActionIncreaseIndent, &QAction::triggered,
this, &QgsRichTextEditor::increaseIndentation );
128 connect( mActionDecreaseIndent, &QAction::triggered,
this, &QgsRichTextEditor::decreaseIndentation );
130 connect( mActionEditSource, &QAction::toggled,
this, &QgsRichTextEditor::editSource );
133 connect( mActionInsertImage, &QAction::triggered,
this, &QgsRichTextEditor::insertImage );
137 fontChanged( mTextEdit->font() );
147 delete mFontSizeCombo;
148 mFontSizeCombo =
nullptr;
149 delete mParagraphStyleCombo;
150 mParagraphStyleCombo =
nullptr;
151 delete mForeColorButton;
152 mForeColorButton =
nullptr;
153 delete mBackColorButton;
154 mBackColorButton =
nullptr;
159 mParagraphStyleCombo =
new QComboBox();
160 mParagraphStyleCombo->addItem( tr(
"Standard" ), ParagraphStandard );
161 mParagraphStyleCombo->addItem( tr(
"Heading 1" ), ParagraphHeading1 );
162 mParagraphStyleCombo->addItem( tr(
"Heading 2" ), ParagraphHeading2 );
163 mParagraphStyleCombo->addItem( tr(
"Heading 3" ), ParagraphHeading3 );
164 mParagraphStyleCombo->addItem( tr(
"Heading 4" ), ParagraphHeading4 );
165 mParagraphStyleCombo->addItem( tr(
"Monospace" ), ParagraphMonospace );
167 connect( mParagraphStyleCombo, qOverload< int >( &QComboBox::activated ),
this, &QgsRichTextEditor::textStyle );
170 mToolBar->addWidget( mParagraphStyleCombo );
173 mToolBar->addAction( mActionUndo );
174 mToolBar->addAction( mActionRedo );
175 mToolBar->addAction( mActionCut );
176 mToolBar->addAction( mActionCopy );
177 mToolBar->addAction( mActionPaste );
180 mFontSizeCombo =
new QComboBox();
181 mFontSizeCombo->setEditable(
true );
183 const QList< int > sizes = QFontDatabase::standardSizes();
184 for (
const int size : sizes )
185 mFontSizeCombo->addItem( QString::number( size ), size );
187 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( QApplication::font().pointSize() ) );
188 connect( mFontSizeCombo, &QComboBox::textActivated,
this, &QgsRichTextEditor::textSize );
192 mToolBar->addSeparator();
193 mToolBar->addWidget( mFontSizeCombo );
194 mToolBar->addAction( mActionBold );
195 mToolBar->addAction( mActionItalic );
196 mToolBar->addAction( mActionUnderline );
197 mToolBar->addAction( mActionStrikeOut );
199 mToolBar->addSeparator();
206 mForeColorButton->
setColor( palette().windowText().color() );
208 mForeColorButton->setToolTip( tr(
"Foreground color" ) );
209 mForeColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
210 mForeColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
216 mToolBar->addWidget( mForeColorButton );
223 mBackColorButton->setToolTip( tr(
"Background color" ) );
224 mBackColorButton->
setShowNull(
true, tr(
"No Background Color" ) );
226 mBackColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
227 mBackColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
232 mToolBar->addWidget( mBackColorButton );
233 mToolBar->addAction( mActionBulletList );
234 mToolBar->addAction( mActionOrderedList );
235 mToolBar->addAction( mActionDecreaseIndent );
236 mToolBar->addAction( mActionIncreaseIndent );
237 mToolBar->addSeparator();
238 mToolBar->addAction( mActionInsertLink );
239 mToolBar->addAction( mActionInsertImage );
243 mToolBar->addAction( mActionEditSource );
246 QMenu *menu =
new QMenu(
this );
249 QAction *removeFormat =
new QAction( tr(
"Remove Character Formatting" ), menu );
250 removeFormat->setShortcut( QKeySequence( QStringLiteral(
"CTRL+M" ) ) );
251 connect( removeFormat, &QAction::triggered,
this, &QgsRichTextEditor::textRemoveFormat );
252 mTextEdit->addAction( removeFormat );
254 QAction *removeAllFormat =
new QAction( tr(
"Remove all Formatting" ), menu );
255 connect( removeAllFormat, &QAction::triggered,
this, &QgsRichTextEditor::textRemoveAllFormat );
256 mTextEdit->addAction( removeAllFormat );
257 menu->addAction( removeAllFormat );
258 menu->addAction( removeFormat );
261 QAction *clearText =
new QAction( tr(
"Clear all Content" ), menu );
263 mTextEdit->addAction( clearText );
265 menu->addAction( clearText );
267 QToolButton *menuButton =
new QToolButton( mToolBar );
268 menuButton->setMenu( menu );
269 menuButton->setPopupMode( QToolButton::InstantPopup );
270 menuButton->setToolTip( tr(
"Advanced Options" ) );
271 menuButton->setText( QStringLiteral(
"…" ) );
273 QWidget *spacer =
new QWidget();
274 spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
275 mToolBar->addWidget( spacer );
276 mToolBar->addWidget( menuButton );
286 switch ( mStackedWidget->currentIndex() )
289 return mTextEdit->toPlainText();
293 mTextEdit->setText( mSourceEdit->text() );
294 return mTextEdit->toPlainText();
304 switch ( mStackedWidget->currentIndex() )
307 return mTextEdit->toHtml();
310 return mSourceEdit->text();
318void QgsRichTextEditor::editSource(
bool enabled )
322 mSourceEdit->setText( mTextEdit->toHtml() );
323 mStackedWidget->setCurrentIndex( 1 );
327 mTextEdit->setHtml( mSourceEdit->text() );
328 mStackedWidget->setCurrentIndex( 0 );
329 mSourceEdit->clear();
333 mFontSizeCombo->setEnabled( !enabled );
334 mParagraphStyleCombo->setEnabled( !enabled );
335 mForeColorButton->setEnabled( !enabled );
336 mBackColorButton->setEnabled( !enabled );
337 mActionUndo->setEnabled( !enabled );
338 mActionRedo->setEnabled( !enabled );
339 mActionCut->setEnabled( !enabled );
340 mActionCopy->setEnabled( !enabled );
341 mActionPaste->setEnabled( !enabled );
342 mActionInsertLink->setEnabled( !enabled );
343 mActionBold->setEnabled( !enabled );
344 mActionItalic->setEnabled( !enabled );
345 mActionUnderline->setEnabled( !enabled );
346 mActionStrikeOut->setEnabled( !enabled );
347 mActionBulletList->setEnabled( !enabled );
348 mActionOrderedList->setEnabled( !enabled );
349 mActionDecreaseIndent->setEnabled( !enabled );
350 mActionIncreaseIndent->setEnabled( !enabled );
351 mActionInsertImage->setEnabled( !enabled );
359void QgsRichTextEditor::textRemoveFormat()
361 QTextCharFormat format;
362 format.setFontWeight( QFont::Normal );
363 format.setFontUnderline(
false );
364 format.setFontStrikeOut(
false );
365 format.setFontItalic(
false );
366 format.setFontPointSize( 9 );
368 mActionBold->setChecked(
false );
369 mActionUnderline->setChecked(
false );
370 mActionItalic->setChecked(
false );
371 mActionStrikeOut->setChecked(
false );
372 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
374 format.clearBackground();
376 mergeFormatOnWordOrSelection( format );
379void QgsRichTextEditor::textRemoveAllFormat()
381 mActionBold->setChecked(
false );
382 mActionUnderline->setChecked(
false );
383 mActionItalic->setChecked(
false );
384 mActionStrikeOut->setChecked(
false );
385 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
386 const QString text = mTextEdit->toPlainText();
387 mTextEdit->setPlainText( text );
390void QgsRichTextEditor::textBold()
392 QTextCharFormat format;
393 format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
394 mergeFormatOnWordOrSelection( format );
399 mTextEdit->setFocus( Qt::TabFocusReason );
402void QgsRichTextEditor::textUnderline()
404 QTextCharFormat format;
405 format.setFontUnderline( mActionUnderline->isChecked() );
406 mergeFormatOnWordOrSelection( format );
409void QgsRichTextEditor::textItalic()
411 QTextCharFormat format;
412 format.setFontItalic( mActionItalic->isChecked() );
413 mergeFormatOnWordOrSelection( format );
416void QgsRichTextEditor::textStrikeout()
418 QTextCharFormat format;
419 format.setFontStrikeOut( mActionStrikeOut->isChecked() );
420 mergeFormatOnWordOrSelection( format );
423void QgsRichTextEditor::textSize(
const QString &p )
425 const qreal pointSize = p.toDouble();
426 if ( p.toFloat() > 0 )
428 QTextCharFormat format;
429 format.setFontPointSize( pointSize );
430 mergeFormatOnWordOrSelection( format );
434void QgsRichTextEditor::textLink(
bool checked )
437 QTextCharFormat format;
440 const QString url = mTextEdit->currentCharFormat().anchorHref();
442 const QString newUrl = QInputDialog::getText(
this, tr(
"Create a Link" ),
443 tr(
"Link URL:" ), QLineEdit::Normal,
448 format.setAnchor(
true );
449 format.setAnchorHref( newUrl );
450 format.setForeground( palette().color( QPalette::Link ) );
451 format.setFontUnderline(
true );
464 format.setAnchor(
false );
465 format.setForeground( palette().color( QPalette::Text ) );
466 format.setFontUnderline(
false );
468 mergeFormatOnWordOrSelection( format );
471void QgsRichTextEditor::textStyle(
int )
473 QTextCursor cursor = mTextEdit->textCursor();
474 cursor.beginEditBlock();
477 if ( !cursor.hasSelection() )
479 cursor.select( QTextCursor::BlockUnderCursor );
481 QTextCharFormat format;
482 cursor.setCharFormat( format );
483 mTextEdit->setCurrentCharFormat( format );
485 const ParagraphItems style =
static_cast< ParagraphItems
>( mParagraphStyleCombo->currentData().toInt() );
489 case QgsRichTextEditor::ParagraphStandard:
492 case QgsRichTextEditor::ParagraphHeading1:
493 format.setFontPointSize( mFontSizeH1 );
494 format.setFontWeight( QFont::Bold );
497 case QgsRichTextEditor::ParagraphHeading2:
498 format.setFontPointSize( mFontSizeH2 );
499 format.setFontWeight( QFont::Bold );
500 format.setFontItalic(
true );
503 case QgsRichTextEditor::ParagraphHeading3:
504 format.setFontPointSize( mFontSizeH3 );
505 format.setFontWeight( QFont::Bold );
508 case QgsRichTextEditor::ParagraphHeading4:
509 format.setFontPointSize( mFontSizeH4 );
510 format.setFontWeight( QFont::Bold );
511 format.setFontItalic(
true );
514 case QgsRichTextEditor::ParagraphMonospace:
516 format = cursor.charFormat();
517 format.setFontFamily( mMonospaceFontFamily );
518 format.setFontStyleHint( QFont::Monospace );
519 format.setFontFixedPitch(
true );
524 cursor.setCharFormat( format );
525 mTextEdit->setCurrentCharFormat( format );
527 cursor.endEditBlock();
530void QgsRichTextEditor::textFgColor()
532 QTextCharFormat format;
533 format.setForeground( mForeColorButton->
color() );
534 mergeFormatOnWordOrSelection( format );
537void QgsRichTextEditor::textBgColor()
539 QTextCharFormat format;
540 const QColor col = mBackColorButton->
color();
543 format.setBackground( col );
547 format.clearBackground();
549 mergeFormatOnWordOrSelection( format );
552void QgsRichTextEditor::listBullet(
bool checked )
556 mActionOrderedList->setChecked(
false );
558 list( checked, QTextListFormat::ListDisc );
561void QgsRichTextEditor::listOrdered(
bool checked )
565 mActionBulletList->setChecked(
false );
567 list( checked, QTextListFormat::ListDecimal );
570void QgsRichTextEditor::list(
bool checked, QTextListFormat::Style style )
572 QTextCursor cursor = mTextEdit->textCursor();
573 cursor.beginEditBlock();
576 const QTextBlockFormat originalFormat = cursor.blockFormat();
577 QTextBlockFormat format;
578 format.setIndent( originalFormat.indent() );
579 cursor.setBlockFormat( format );
583 QTextListFormat listFormat;
584 if ( cursor.currentList() )
586 listFormat = cursor.currentList()->format();
588 listFormat.setStyle( style );
589 cursor.createList( listFormat );
591 cursor.endEditBlock();
594void QgsRichTextEditor::mergeFormatOnWordOrSelection(
const QTextCharFormat &format )
596 QTextCursor cursor = mTextEdit->textCursor();
597 if ( !cursor.hasSelection() )
599 cursor.select( QTextCursor::WordUnderCursor );
601 cursor.mergeCharFormat( format );
602 mTextEdit->mergeCurrentCharFormat( format );
603 mTextEdit->setFocus( Qt::TabFocusReason );
606void QgsRichTextEditor::slotCursorPositionChanged()
608 QTextList *l = mTextEdit->textCursor().currentList();
609 if ( mLastBlockList && ( l == mLastBlockList || ( l && mLastBlockList
610 && l->format().style() == mLastBlockList->format().style() ) ) )
617 const QTextListFormat listFormat = l->format();
618 if ( listFormat.style() == QTextListFormat::ListDisc )
620 mActionBulletList->setChecked(
true );
621 mActionOrderedList->setChecked(
false );
623 else if ( listFormat.style() == QTextListFormat::ListDecimal )
625 mActionBulletList->setChecked(
false );
626 mActionOrderedList->setChecked(
true );
630 mActionBulletList->setChecked(
false );
631 mActionOrderedList->setChecked(
false );
636 mActionBulletList->setChecked(
false );
637 mActionOrderedList->setChecked(
false );
641void QgsRichTextEditor::fontChanged(
const QFont &f )
643 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
644 mActionBold->setChecked( f.bold() );
645 mActionItalic->setChecked( f.italic() );
646 mActionUnderline->setChecked( f.underline() );
647 mActionStrikeOut->setChecked( f.strikeOut() );
648 if ( f.pointSize() == mFontSizeH1 )
650 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
652 else if ( f.pointSize() == mFontSizeH2 )
654 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
656 else if ( f.pointSize() == mFontSizeH3 )
658 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
660 else if ( f.pointSize() == mFontSizeH4 )
662 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
666 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
668 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
672 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
675 if ( mTextEdit->textCursor().currentList() )
677 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
678 if ( listFormat.style() == QTextListFormat::ListDisc )
680 mActionBulletList->setChecked(
true );
681 mActionOrderedList->setChecked(
false );
683 else if ( listFormat.style() == QTextListFormat::ListDecimal )
685 mActionBulletList->setChecked(
false );
686 mActionOrderedList->setChecked(
true );
690 mActionBulletList->setChecked(
false );
691 mActionOrderedList->setChecked(
false );
696 mActionBulletList->setChecked(
false );
697 mActionOrderedList->setChecked(
false );
701void QgsRichTextEditor::fgColorChanged(
const QColor &
c )
706void QgsRichTextEditor::bgColorChanged(
const QColor &
c )
714void QgsRichTextEditor::slotCurrentCharFormatChanged(
const QTextCharFormat &format )
716 fontChanged( format.font() );
717 bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
718 fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
719 mActionInsertLink->setChecked( format.isAnchor() );
722void QgsRichTextEditor::slotClipboardDataChanged()
724#ifndef QT_NO_CLIPBOARD
725 if (
const QMimeData *md = QApplication::clipboard()->mimeData() )
726 mActionPaste->setEnabled( md->hasText() );
730void QgsRichTextEditor::increaseIndentation()
735void QgsRichTextEditor::decreaseIndentation()
740void QgsRichTextEditor::indent(
int delta )
742 QTextCursor cursor = mTextEdit->textCursor();
743 cursor.beginEditBlock();
744 QTextBlockFormat format = cursor.blockFormat();
745 const int indent = format.indent();
746 if ( indent + delta >= 0 )
748 format.setIndent( indent + delta );
750 cursor.setBlockFormat( format );
751 cursor.endEditBlock();
756 if ( text.isEmpty() )
758 setPlainText( text );
761 if ( text[0] ==
'<' )
767 setPlainText( text );
771void QgsRichTextEditor::insertImage()
774 const QString attdir = s.value( QStringLiteral(
"general/filedialog-path" ) ).toString();
775 const QString file = QFileDialog::getOpenFileName(
this,
776 tr(
"Select an image" ),
778 tr(
"JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
779 if ( file.isEmpty() )
782 const QImage image = QImageReader( file ).read();
784 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.
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.