38#include <QApplication>
40#include <QFontDatabase>
41#include <QInputDialog>
45#include <QImageReader>
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 connect( mFontSizeCombo, &QComboBox::textActivated,
this, &QgsRichTextEditor::textSize );
212 fontChanged( mTextEdit->font() );
220 switch ( mStackedWidget->currentIndex() )
223 return mTextEdit->toPlainText();
227 mTextEdit->setText( mSourceEdit->text() );
228 return mTextEdit->toPlainText();
235 switch ( mStackedWidget->currentIndex() )
238 return mTextEdit->toHtml();
241 return mSourceEdit->text();
246void QgsRichTextEditor::editSource(
bool enabled )
250 mSourceEdit->setText( mTextEdit->toHtml() );
251 mStackedWidget->setCurrentIndex( 1 );
255 mTextEdit->setHtml( mSourceEdit->text() );
256 mStackedWidget->setCurrentIndex( 0 );
257 mSourceEdit->clear();
261 mFontSizeCombo->setEnabled( !enabled );
262 mParagraphStyleCombo->setEnabled( !enabled );
263 mForeColorButton->setEnabled( !enabled );
264 mBackColorButton->setEnabled( !enabled );
265 mActionUndo->setEnabled( !enabled );
266 mActionRedo->setEnabled( !enabled );
267 mActionCut->setEnabled( !enabled );
268 mActionCopy->setEnabled( !enabled );
269 mActionPaste->setEnabled( !enabled );
270 mActionInsertLink->setEnabled( !enabled );
271 mActionBold->setEnabled( !enabled );
272 mActionItalic->setEnabled( !enabled );
273 mActionUnderline->setEnabled( !enabled );
274 mActionStrikeOut->setEnabled( !enabled );
275 mActionBulletList->setEnabled( !enabled );
276 mActionOrderedList->setEnabled( !enabled );
277 mActionDecreaseIndent->setEnabled( !enabled );
278 mActionIncreaseIndent->setEnabled( !enabled );
279 mActionInsertImage->setEnabled( !enabled );
287void QgsRichTextEditor::textRemoveFormat()
289 QTextCharFormat format;
290 format.setFontWeight( QFont::Normal );
291 format.setFontUnderline(
false );
292 format.setFontStrikeOut(
false );
293 format.setFontItalic(
false );
294 format.setFontPointSize( 9 );
296 mActionBold->setChecked(
false );
297 mActionUnderline->setChecked(
false );
298 mActionItalic->setChecked(
false );
299 mActionStrikeOut->setChecked(
false );
300 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
302 format.clearBackground();
304 mergeFormatOnWordOrSelection( format );
307void QgsRichTextEditor::textRemoveAllFormat()
309 mActionBold->setChecked(
false );
310 mActionUnderline->setChecked(
false );
311 mActionItalic->setChecked(
false );
312 mActionStrikeOut->setChecked(
false );
313 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
314 const QString text = mTextEdit->toPlainText();
315 mTextEdit->setPlainText( text );
318void QgsRichTextEditor::textBold()
320 QTextCharFormat format;
321 format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
322 mergeFormatOnWordOrSelection( format );
327 mTextEdit->setFocus( Qt::TabFocusReason );
330void QgsRichTextEditor::textUnderline()
332 QTextCharFormat format;
333 format.setFontUnderline( mActionUnderline->isChecked() );
334 mergeFormatOnWordOrSelection( format );
337void QgsRichTextEditor::textItalic()
339 QTextCharFormat format;
340 format.setFontItalic( mActionItalic->isChecked() );
341 mergeFormatOnWordOrSelection( format );
344void QgsRichTextEditor::textStrikeout()
346 QTextCharFormat format;
347 format.setFontStrikeOut( mActionStrikeOut->isChecked() );
348 mergeFormatOnWordOrSelection( format );
351void QgsRichTextEditor::textSize(
const QString &p )
353 const qreal pointSize = p.toDouble();
354 if ( p.toFloat() > 0 )
356 QTextCharFormat format;
357 format.setFontPointSize( pointSize );
358 mergeFormatOnWordOrSelection( format );
362void QgsRichTextEditor::textLink(
bool checked )
365 QTextCharFormat format;
368 const QString url = mTextEdit->currentCharFormat().anchorHref();
370 const QString newUrl = QInputDialog::getText(
this, tr(
"Create a Link" ),
371 tr(
"Link URL:" ), QLineEdit::Normal,
376 format.setAnchor(
true );
377 format.setAnchorHref( newUrl );
378 format.setForeground( palette().color( QPalette::Link ) );
379 format.setFontUnderline(
true );
392 format.setAnchor(
false );
393 format.setForeground( palette().color( QPalette::Text ) );
394 format.setFontUnderline(
false );
396 mergeFormatOnWordOrSelection( format );
399void QgsRichTextEditor::textStyle(
int )
401 QTextCursor cursor = mTextEdit->textCursor();
402 cursor.beginEditBlock();
405 if ( !cursor.hasSelection() )
407 cursor.select( QTextCursor::BlockUnderCursor );
409 QTextCharFormat format;
410 cursor.setCharFormat( format );
411 mTextEdit->setCurrentCharFormat( format );
413 const ParagraphItems style =
static_cast< ParagraphItems
>( mParagraphStyleCombo->currentData().toInt() );
417 case QgsRichTextEditor::ParagraphStandard:
420 case QgsRichTextEditor::ParagraphHeading1:
421 format.setFontPointSize( mFontSizeH1 );
422 format.setFontWeight( QFont::Bold );
425 case QgsRichTextEditor::ParagraphHeading2:
426 format.setFontPointSize( mFontSizeH2 );
427 format.setFontWeight( QFont::Bold );
428 format.setFontItalic(
true );
431 case QgsRichTextEditor::ParagraphHeading3:
432 format.setFontPointSize( mFontSizeH3 );
433 format.setFontWeight( QFont::Bold );
436 case QgsRichTextEditor::ParagraphHeading4:
437 format.setFontPointSize( mFontSizeH4 );
438 format.setFontWeight( QFont::Bold );
439 format.setFontItalic(
true );
442 case QgsRichTextEditor::ParagraphMonospace:
444 format = cursor.charFormat();
445 format.setFontFamily( mMonospaceFontFamily );
446 format.setFontStyleHint( QFont::Monospace );
447 format.setFontFixedPitch(
true );
452 cursor.setCharFormat( format );
453 mTextEdit->setCurrentCharFormat( format );
455 cursor.endEditBlock();
458void QgsRichTextEditor::textFgColor()
460 QTextCharFormat format;
461 format.setForeground( mForeColorButton->
color() );
462 mergeFormatOnWordOrSelection( format );
465void QgsRichTextEditor::textBgColor()
467 QTextCharFormat format;
468 const QColor col = mBackColorButton->
color();
471 format.setBackground( col );
475 format.clearBackground();
477 mergeFormatOnWordOrSelection( format );
480void QgsRichTextEditor::listBullet(
bool checked )
484 mActionOrderedList->setChecked(
false );
486 list( checked, QTextListFormat::ListDisc );
489void QgsRichTextEditor::listOrdered(
bool checked )
493 mActionBulletList->setChecked(
false );
495 list( checked, QTextListFormat::ListDecimal );
498void QgsRichTextEditor::list(
bool checked, QTextListFormat::Style style )
500 QTextCursor cursor = mTextEdit->textCursor();
501 cursor.beginEditBlock();
504 const QTextBlockFormat originalFormat = cursor.blockFormat();
505 QTextBlockFormat format;
506 format.setIndent( originalFormat.indent() );
507 cursor.setBlockFormat( format );
511 QTextListFormat listFormat;
512 if ( cursor.currentList() )
514 listFormat = cursor.currentList()->format();
516 listFormat.setStyle( style );
517 cursor.createList( listFormat );
519 cursor.endEditBlock();
522void QgsRichTextEditor::mergeFormatOnWordOrSelection(
const QTextCharFormat &format )
524 QTextCursor cursor = mTextEdit->textCursor();
525 if ( !cursor.hasSelection() )
527 cursor.select( QTextCursor::WordUnderCursor );
529 cursor.mergeCharFormat( format );
530 mTextEdit->mergeCurrentCharFormat( format );
531 mTextEdit->setFocus( Qt::TabFocusReason );
534void QgsRichTextEditor::slotCursorPositionChanged()
536 QTextList *l = mTextEdit->textCursor().currentList();
537 if ( mLastBlockList && ( l == mLastBlockList || ( l !=
nullptr && mLastBlockList !=
nullptr
538 && l->format().style() == mLastBlockList->format().style() ) ) )
545 const QTextListFormat listFormat = l->format();
546 if ( listFormat.style() == QTextListFormat::ListDisc )
548 mActionBulletList->setChecked(
true );
549 mActionOrderedList->setChecked(
false );
551 else if ( listFormat.style() == QTextListFormat::ListDecimal )
553 mActionBulletList->setChecked(
false );
554 mActionOrderedList->setChecked(
true );
558 mActionBulletList->setChecked(
false );
559 mActionOrderedList->setChecked(
false );
564 mActionBulletList->setChecked(
false );
565 mActionOrderedList->setChecked(
false );
569void QgsRichTextEditor::fontChanged(
const QFont &f )
571 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
572 mActionBold->setChecked( f.bold() );
573 mActionItalic->setChecked( f.italic() );
574 mActionUnderline->setChecked( f.underline() );
575 mActionStrikeOut->setChecked( f.strikeOut() );
576 if ( f.pointSize() == mFontSizeH1 )
578 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
580 else if ( f.pointSize() == mFontSizeH2 )
582 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
584 else if ( f.pointSize() == mFontSizeH3 )
586 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
588 else if ( f.pointSize() == mFontSizeH4 )
590 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
594 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
596 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
600 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
603 if ( mTextEdit->textCursor().currentList() )
605 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
606 if ( listFormat.style() == QTextListFormat::ListDisc )
608 mActionBulletList->setChecked(
true );
609 mActionOrderedList->setChecked(
false );
611 else if ( listFormat.style() == QTextListFormat::ListDecimal )
613 mActionBulletList->setChecked(
false );
614 mActionOrderedList->setChecked(
true );
618 mActionBulletList->setChecked(
false );
619 mActionOrderedList->setChecked(
false );
624 mActionBulletList->setChecked(
false );
625 mActionOrderedList->setChecked(
false );
629void QgsRichTextEditor::fgColorChanged(
const QColor &
c )
634void QgsRichTextEditor::bgColorChanged(
const QColor &
c )
642void QgsRichTextEditor::slotCurrentCharFormatChanged(
const QTextCharFormat &format )
644 fontChanged( format.font() );
645 bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
646 fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
647 mActionInsertLink->setChecked( format.isAnchor() );
650void QgsRichTextEditor::slotClipboardDataChanged()
652#ifndef QT_NO_CLIPBOARD
653 if (
const QMimeData *md = QApplication::clipboard()->mimeData() )
654 mActionPaste->setEnabled( md->hasText() );
658void QgsRichTextEditor::increaseIndentation()
663void QgsRichTextEditor::decreaseIndentation()
668void QgsRichTextEditor::indent(
int delta )
670 QTextCursor cursor = mTextEdit->textCursor();
671 cursor.beginEditBlock();
672 QTextBlockFormat format = cursor.blockFormat();
673 const int indent = format.indent();
674 if ( indent + delta >= 0 )
676 format.setIndent( indent + delta );
678 cursor.setBlockFormat( format );
679 cursor.endEditBlock();
684 if ( text.isEmpty() )
686 setPlainText( text );
689 if ( text[0] ==
'<' )
695 setPlainText( text );
699void QgsRichTextEditor::insertImage()
702 const QString attdir = s.value( QStringLiteral(
"general/filedialog-path" ) ).toString();
703 const QString file = QFileDialog::getOpenFileName(
this,
704 tr(
"Select an image" ),
706 tr(
"JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
707 if ( file.isEmpty() )
710 const QImage image = QImageReader( file ).read();
712 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 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.