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 QList< int > sizes = QFontDatabase::standardSizes();
174 for (
const int size : sizes )
175 mFontSizeCombo->addItem( QString::number( size ), size );
177 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( QApplication::font().pointSize() ) );
183 mForeColorButton->
setColor( palette().windowText().color() );
185 mForeColorButton->setToolTip( tr(
"Foreground color" ) );
186 mForeColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
187 mForeColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
189 QAction *listSeparator = mToolBar->insertSeparator( mActionBulletList );
192 mToolBar->insertWidget( listSeparator, mForeColorButton );
198 mBackColorButton->setToolTip( tr(
"Background color" ) );
199 mBackColorButton->
setShowNull(
true, tr(
"No Background Color" ) );
201 mBackColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
202 mBackColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
204 mToolBar->insertWidget( listSeparator, mBackColorButton );
206 connect( mActionEditSource, &QAction::toggled,
this, &QgsRichTextEditor::editSource );
209 connect( mActionInsertImage, &QAction::triggered,
this, &QgsRichTextEditor::insertImage );
210 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
211 connect( mFontSizeCombo, qOverload< const QString &>( &QComboBox::activated ),
this, &QgsRichTextEditor::textSize );
213 connect( mFontSizeCombo, &QComboBox::textActivated,
this, &QgsRichTextEditor::textSize );
216 fontChanged( mTextEdit->font() );
221 switch ( mStackedWidget->currentIndex() )
224 return mTextEdit->toPlainText();
228 mTextEdit->setText( mSourceEdit->text() );
229 return mTextEdit->toPlainText();
236 switch ( mStackedWidget->currentIndex() )
239 return mTextEdit->toHtml();
242 return mSourceEdit->text();
247 void QgsRichTextEditor::editSource(
bool enabled )
251 mSourceEdit->setText( mTextEdit->toHtml() );
252 mStackedWidget->setCurrentIndex( 1 );
256 mTextEdit->setHtml( mSourceEdit->text() );
257 mStackedWidget->setCurrentIndex( 0 );
258 mSourceEdit->clear();
262 mFontSizeCombo->setEnabled( !enabled );
263 mParagraphStyleCombo->setEnabled( !enabled );
264 mForeColorButton->setEnabled( !enabled );
265 mBackColorButton->setEnabled( !enabled );
266 mActionUndo->setEnabled( !enabled );
267 mActionRedo->setEnabled( !enabled );
268 mActionCut->setEnabled( !enabled );
269 mActionCopy->setEnabled( !enabled );
270 mActionPaste->setEnabled( !enabled );
271 mActionInsertLink->setEnabled( !enabled );
272 mActionBold->setEnabled( !enabled );
273 mActionItalic->setEnabled( !enabled );
274 mActionUnderline->setEnabled( !enabled );
275 mActionStrikeOut->setEnabled( !enabled );
276 mActionBulletList->setEnabled( !enabled );
277 mActionOrderedList->setEnabled( !enabled );
278 mActionDecreaseIndent->setEnabled( !enabled );
279 mActionIncreaseIndent->setEnabled( !enabled );
280 mActionInsertImage->setEnabled( !enabled );
288 void QgsRichTextEditor::textRemoveFormat()
290 QTextCharFormat format;
291 format.setFontWeight( QFont::Normal );
292 format.setFontUnderline(
false );
293 format.setFontStrikeOut(
false );
294 format.setFontItalic(
false );
295 format.setFontPointSize( 9 );
297 mActionBold->setChecked(
false );
298 mActionUnderline->setChecked(
false );
299 mActionItalic->setChecked(
false );
300 mActionStrikeOut->setChecked(
false );
301 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
303 format.clearBackground();
305 mergeFormatOnWordOrSelection( format );
308 void QgsRichTextEditor::textRemoveAllFormat()
310 mActionBold->setChecked(
false );
311 mActionUnderline->setChecked(
false );
312 mActionItalic->setChecked(
false );
313 mActionStrikeOut->setChecked(
false );
314 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
315 const QString text = mTextEdit->toPlainText();
316 mTextEdit->setPlainText( text );
319 void QgsRichTextEditor::textBold()
321 QTextCharFormat format;
322 format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
323 mergeFormatOnWordOrSelection( format );
328 mTextEdit->setFocus( Qt::TabFocusReason );
331 void QgsRichTextEditor::textUnderline()
333 QTextCharFormat format;
334 format.setFontUnderline( mActionUnderline->isChecked() );
335 mergeFormatOnWordOrSelection( format );
338 void QgsRichTextEditor::textItalic()
340 QTextCharFormat format;
341 format.setFontItalic( mActionItalic->isChecked() );
342 mergeFormatOnWordOrSelection( format );
345 void QgsRichTextEditor::textStrikeout()
347 QTextCharFormat format;
348 format.setFontStrikeOut( mActionStrikeOut->isChecked() );
349 mergeFormatOnWordOrSelection( format );
352 void QgsRichTextEditor::textSize(
const QString &p )
354 const qreal pointSize = p.toDouble();
355 if ( p.toFloat() > 0 )
357 QTextCharFormat format;
358 format.setFontPointSize( pointSize );
359 mergeFormatOnWordOrSelection( format );
363 void QgsRichTextEditor::textLink(
bool checked )
366 QTextCharFormat format;
369 const QString url = mTextEdit->currentCharFormat().anchorHref();
371 const QString newUrl = QInputDialog::getText(
this, tr(
"Create a Link" ),
372 tr(
"Link URL:" ), QLineEdit::Normal,
377 format.setAnchor(
true );
378 format.setAnchorHref( newUrl );
379 format.setForeground( palette().color( QPalette::Link ) );
380 format.setFontUnderline(
true );
393 format.setAnchor(
false );
394 format.setForeground( palette().color( QPalette::Text ) );
395 format.setFontUnderline(
false );
397 mergeFormatOnWordOrSelection( format );
400 void QgsRichTextEditor::textStyle(
int )
402 QTextCursor cursor = mTextEdit->textCursor();
403 cursor.beginEditBlock();
406 if ( !cursor.hasSelection() )
408 cursor.select( QTextCursor::BlockUnderCursor );
410 QTextCharFormat format;
411 cursor.setCharFormat( format );
412 mTextEdit->setCurrentCharFormat( format );
414 const ParagraphItems style =
static_cast< ParagraphItems
>( mParagraphStyleCombo->currentData().toInt() );
418 case QgsRichTextEditor::ParagraphStandard:
421 case QgsRichTextEditor::ParagraphHeading1:
422 format.setFontPointSize( mFontSizeH1 );
423 format.setFontWeight( QFont::Bold );
426 case QgsRichTextEditor::ParagraphHeading2:
427 format.setFontPointSize( mFontSizeH2 );
428 format.setFontWeight( QFont::Bold );
429 format.setFontItalic(
true );
432 case QgsRichTextEditor::ParagraphHeading3:
433 format.setFontPointSize( mFontSizeH3 );
434 format.setFontWeight( QFont::Bold );
437 case QgsRichTextEditor::ParagraphHeading4:
438 format.setFontPointSize( mFontSizeH4 );
439 format.setFontWeight( QFont::Bold );
440 format.setFontItalic(
true );
443 case QgsRichTextEditor::ParagraphMonospace:
445 format = cursor.charFormat();
446 format.setFontFamily( mMonospaceFontFamily );
447 format.setFontStyleHint( QFont::Monospace );
448 format.setFontFixedPitch(
true );
453 cursor.setCharFormat( format );
454 mTextEdit->setCurrentCharFormat( format );
456 cursor.endEditBlock();
459 void QgsRichTextEditor::textFgColor()
461 QTextCharFormat format;
462 format.setForeground( mForeColorButton->
color() );
463 mergeFormatOnWordOrSelection( format );
466 void QgsRichTextEditor::textBgColor()
468 QTextCharFormat format;
469 const QColor col = mBackColorButton->
color();
472 format.setBackground( col );
476 format.clearBackground();
478 mergeFormatOnWordOrSelection( format );
481 void QgsRichTextEditor::listBullet(
bool checked )
485 mActionOrderedList->setChecked(
false );
487 list( checked, QTextListFormat::ListDisc );
490 void QgsRichTextEditor::listOrdered(
bool checked )
494 mActionBulletList->setChecked(
false );
496 list( checked, QTextListFormat::ListDecimal );
499 void QgsRichTextEditor::list(
bool checked, QTextListFormat::Style style )
501 QTextCursor cursor = mTextEdit->textCursor();
502 cursor.beginEditBlock();
505 const QTextBlockFormat originalFormat = cursor.blockFormat();
506 QTextBlockFormat format;
507 format.setIndent( originalFormat.indent() );
508 cursor.setBlockFormat( format );
512 QTextListFormat listFormat;
513 if ( cursor.currentList() )
515 listFormat = cursor.currentList()->format();
517 listFormat.setStyle( style );
518 cursor.createList( listFormat );
520 cursor.endEditBlock();
523 void QgsRichTextEditor::mergeFormatOnWordOrSelection(
const QTextCharFormat &format )
525 QTextCursor cursor = mTextEdit->textCursor();
526 if ( !cursor.hasSelection() )
528 cursor.select( QTextCursor::WordUnderCursor );
530 cursor.mergeCharFormat( format );
531 mTextEdit->mergeCurrentCharFormat( format );
532 mTextEdit->setFocus( Qt::TabFocusReason );
535 void QgsRichTextEditor::slotCursorPositionChanged()
537 QTextList *l = mTextEdit->textCursor().currentList();
538 if ( mLastBlockList && ( l == mLastBlockList || ( l !=
nullptr && mLastBlockList !=
nullptr
539 && l->format().style() == mLastBlockList->format().style() ) ) )
546 const QTextListFormat listFormat = l->format();
547 if ( listFormat.style() == QTextListFormat::ListDisc )
549 mActionBulletList->setChecked(
true );
550 mActionOrderedList->setChecked(
false );
552 else if ( listFormat.style() == QTextListFormat::ListDecimal )
554 mActionBulletList->setChecked(
false );
555 mActionOrderedList->setChecked(
true );
559 mActionBulletList->setChecked(
false );
560 mActionOrderedList->setChecked(
false );
565 mActionBulletList->setChecked(
false );
566 mActionOrderedList->setChecked(
false );
570 void QgsRichTextEditor::fontChanged(
const QFont &f )
572 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
573 mActionBold->setChecked( f.bold() );
574 mActionItalic->setChecked( f.italic() );
575 mActionUnderline->setChecked( f.underline() );
576 mActionStrikeOut->setChecked( f.strikeOut() );
577 if ( f.pointSize() == mFontSizeH1 )
579 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
581 else if ( f.pointSize() == mFontSizeH2 )
583 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
585 else if ( f.pointSize() == mFontSizeH3 )
587 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
589 else if ( f.pointSize() == mFontSizeH4 )
591 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
595 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
597 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
601 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
604 if ( mTextEdit->textCursor().currentList() )
606 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
607 if ( listFormat.style() == QTextListFormat::ListDisc )
609 mActionBulletList->setChecked(
true );
610 mActionOrderedList->setChecked(
false );
612 else if ( listFormat.style() == QTextListFormat::ListDecimal )
614 mActionBulletList->setChecked(
false );
615 mActionOrderedList->setChecked(
true );
619 mActionBulletList->setChecked(
false );
620 mActionOrderedList->setChecked(
false );
625 mActionBulletList->setChecked(
false );
626 mActionOrderedList->setChecked(
false );
630 void QgsRichTextEditor::fgColorChanged(
const QColor &
c )
635 void QgsRichTextEditor::bgColorChanged(
const QColor &
c )
643 void QgsRichTextEditor::slotCurrentCharFormatChanged(
const QTextCharFormat &format )
645 fontChanged( format.font() );
646 bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
647 fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
648 mActionInsertLink->setChecked( format.isAnchor() );
651 void QgsRichTextEditor::slotClipboardDataChanged()
653 #ifndef QT_NO_CLIPBOARD
654 if (
const QMimeData *md = QApplication::clipboard()->mimeData() )
655 mActionPaste->setEnabled( md->hasText() );
659 void QgsRichTextEditor::increaseIndentation()
664 void QgsRichTextEditor::decreaseIndentation()
669 void QgsRichTextEditor::indent(
int delta )
671 QTextCursor cursor = mTextEdit->textCursor();
672 cursor.beginEditBlock();
673 QTextBlockFormat format = cursor.blockFormat();
674 const int indent = format.indent();
675 if ( indent + delta >= 0 )
677 format.setIndent( indent + delta );
679 cursor.setBlockFormat( format );
680 cursor.endEditBlock();
685 if ( text.isEmpty() )
687 setPlainText( text );
690 if ( text[0] ==
'<' )
696 setPlainText( text );
700 void QgsRichTextEditor::insertImage()
703 const QString attdir = s.value( QStringLiteral(
"general/filedialog-path" ) ).toString();
704 const QString file = QFileDialog::getOpenFileName(
this,
705 tr(
"Select an image" ),
707 tr(
"JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
708 if ( file.isEmpty() )
711 const QImage image = QImageReader( file ).read();
713 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.