32#include "moc_qgsrichtexteditor.cpp"
40#include <QApplication>
42#include <QFontDatabase>
43#include <QInputDialog>
47#include <QImageReader>
61 QVBoxLayout *sourceLayout =
new QVBoxLayout();
62 sourceLayout->setContentsMargins( 0, 0, 0, 0 );
65 sourceLayout->addWidget( codeEditorWidget );
66 mPageSourceEdit->setLayout( sourceLayout );
70 connect( mTextEdit, &QTextEdit::currentCharFormatChanged,
this, &QgsRichTextEditor::slotCurrentCharFormatChanged );
71 connect( mTextEdit, &QTextEdit::cursorPositionChanged,
this, &QgsRichTextEditor::slotCursorPositionChanged );
74 mActionUndo->setShortcut( QKeySequence::Undo );
75 mActionRedo->setShortcut( QKeySequence::Redo );
77 connect( mTextEdit->document(), &QTextDocument::undoAvailable, mActionUndo, &QAction::setEnabled );
78 connect( mTextEdit->document(), &QTextDocument::redoAvailable, mActionRedo, &QAction::setEnabled );
80 mActionUndo->setEnabled( mTextEdit->document()->isUndoAvailable() );
81 mActionRedo->setEnabled( mTextEdit->document()->isRedoAvailable() );
83 connect( mActionUndo, &QAction::triggered, mTextEdit, &QTextEdit::undo );
84 connect( mActionRedo, &QAction::triggered, mTextEdit, &QTextEdit::redo );
87 mActionCut->setShortcut( QKeySequence::Cut );
88 mActionCopy->setShortcut( QKeySequence::Copy );
89 mActionPaste->setShortcut( QKeySequence::Paste );
91 mActionCut->setEnabled(
false );
92 mActionCopy->setEnabled(
false );
94 connect( mActionCut, &QAction::triggered, mTextEdit, &QTextEdit::cut );
95 connect( mActionCopy, &QAction::triggered, mTextEdit, &QTextEdit::copy );
96 connect( mActionPaste, &QAction::triggered, mTextEdit, &QTextEdit::paste );
98 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCut, &QAction::setEnabled );
99 connect( mTextEdit, &QTextEdit::copyAvailable, mActionCopy, &QAction::setEnabled );
101#ifndef QT_NO_CLIPBOARD
102 connect( QApplication::clipboard(), &QClipboard::dataChanged,
this, &QgsRichTextEditor::slotClipboardDataChanged );
106 mActionInsertLink->setShortcut( QKeySequence( QStringLiteral(
"CTRL+L" ) ) );
107 connect( mActionInsertLink, &QAction::triggered,
this, &QgsRichTextEditor::textLink );
110 mActionBold->setShortcut( QKeySequence( QStringLiteral(
"CTRL+B" ) ) );
111 mActionItalic->setShortcut( QKeySequence( QStringLiteral(
"CTRL+I" ) ) );
112 mActionUnderline->setShortcut( QKeySequence( QStringLiteral(
"CTRL+U" ) ) );
114 connect( mActionBold, &QAction::triggered,
this, &QgsRichTextEditor::textBold );
115 connect( mActionItalic, &QAction::triggered,
this, &QgsRichTextEditor::textItalic );
116 connect( mActionUnderline, &QAction::triggered,
this, &QgsRichTextEditor::textUnderline );
117 connect( mActionStrikeOut, &QAction::triggered,
this, &QgsRichTextEditor::textStrikeout );
120 mActionBulletList->setShortcut( QKeySequence( QStringLiteral(
"CTRL+-" ) ) );
121 mActionOrderedList->setShortcut( QKeySequence( QStringLiteral(
"CTRL+=" ) ) );
122 connect( mActionBulletList, &QAction::triggered,
this, &QgsRichTextEditor::listBullet );
123 connect( mActionOrderedList, &QAction::triggered,
this, &QgsRichTextEditor::listOrdered );
126 mActionDecreaseIndent->setShortcut( QKeySequence( QStringLiteral(
"CTRL+," ) ) );
127 mActionIncreaseIndent->setShortcut( QKeySequence( QStringLiteral(
"CTRL+." ) ) );
128 connect( mActionIncreaseIndent, &QAction::triggered,
this, &QgsRichTextEditor::increaseIndentation );
129 connect( mActionDecreaseIndent, &QAction::triggered,
this, &QgsRichTextEditor::decreaseIndentation );
131 connect( mActionEditSource, &QAction::toggled,
this, &QgsRichTextEditor::editSource );
134 connect( mActionInsertImage, &QAction::triggered,
this, &QgsRichTextEditor::insertImage );
138 fontChanged( mTextEdit->font() );
148 delete mFontSizeCombo;
149 mFontSizeCombo =
nullptr;
150 delete mParagraphStyleCombo;
151 mParagraphStyleCombo =
nullptr;
152 delete mForeColorButton;
153 mForeColorButton =
nullptr;
154 delete mBackColorButton;
155 mBackColorButton =
nullptr;
160 mParagraphStyleCombo =
new QComboBox();
161 mParagraphStyleCombo->addItem( tr(
"Standard" ), ParagraphStandard );
162 mParagraphStyleCombo->addItem( tr(
"Heading 1" ), ParagraphHeading1 );
163 mParagraphStyleCombo->addItem( tr(
"Heading 2" ), ParagraphHeading2 );
164 mParagraphStyleCombo->addItem( tr(
"Heading 3" ), ParagraphHeading3 );
165 mParagraphStyleCombo->addItem( tr(
"Heading 4" ), ParagraphHeading4 );
166 mParagraphStyleCombo->addItem( tr(
"Monospace" ), ParagraphMonospace );
168 connect( mParagraphStyleCombo, qOverload<int>( &QComboBox::activated ),
this, &QgsRichTextEditor::textStyle );
171 mToolBar->addWidget( mParagraphStyleCombo );
174 mToolBar->addAction( mActionUndo );
175 mToolBar->addAction( mActionRedo );
176 mToolBar->addAction( mActionCut );
177 mToolBar->addAction( mActionCopy );
178 mToolBar->addAction( mActionPaste );
181 mFontSizeCombo =
new QComboBox();
182 mFontSizeCombo->setEditable(
true );
184 const QList<int> sizes = QFontDatabase::standardSizes();
185 for (
const int size : sizes )
186 mFontSizeCombo->addItem( QString::number( size ), size );
188 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( QApplication::font().pointSize() ) );
189 connect( mFontSizeCombo, &QComboBox::textActivated,
this, &QgsRichTextEditor::textSize );
193 mToolBar->addSeparator();
194 mToolBar->addWidget( mFontSizeCombo );
195 mToolBar->addAction( mActionBold );
196 mToolBar->addAction( mActionItalic );
197 mToolBar->addAction( mActionUnderline );
198 mToolBar->addAction( mActionStrikeOut );
200 mToolBar->addSeparator();
207 mForeColorButton->
setColor( palette().windowText().color() );
209 mForeColorButton->setToolTip( tr(
"Foreground color" ) );
210 mForeColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
211 mForeColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
217 mToolBar->addWidget( mForeColorButton );
224 mBackColorButton->setToolTip( tr(
"Background color" ) );
225 mBackColorButton->
setShowNull(
true, tr(
"No Background Color" ) );
227 mBackColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
228 mBackColorButton->setMinimumWidth( QFontMetrics( font() ).horizontalAdvance( QStringLiteral(
"x" ) ) * 10 );
233 mToolBar->addWidget( mBackColorButton );
234 mToolBar->addAction( mActionBulletList );
235 mToolBar->addAction( mActionOrderedList );
236 mToolBar->addAction( mActionDecreaseIndent );
237 mToolBar->addAction( mActionIncreaseIndent );
238 mToolBar->addSeparator();
239 mToolBar->addAction( mActionInsertLink );
240 mToolBar->addAction( mActionInsertImage );
244 mToolBar->addAction( mActionEditSource );
247 QMenu *menu =
new QMenu(
this );
250 QAction *removeFormat =
new QAction( tr(
"Remove Character Formatting" ), menu );
251 removeFormat->setShortcut( QKeySequence( QStringLiteral(
"CTRL+M" ) ) );
252 connect( removeFormat, &QAction::triggered,
this, &QgsRichTextEditor::textRemoveFormat );
253 mTextEdit->addAction( removeFormat );
255 QAction *removeAllFormat =
new QAction( tr(
"Remove all Formatting" ), menu );
256 connect( removeAllFormat, &QAction::triggered,
this, &QgsRichTextEditor::textRemoveAllFormat );
257 mTextEdit->addAction( removeAllFormat );
258 menu->addAction( removeAllFormat );
259 menu->addAction( removeFormat );
262 QAction *clearText =
new QAction( tr(
"Clear all Content" ), menu );
264 mTextEdit->addAction( clearText );
266 menu->addAction( clearText );
268 QToolButton *menuButton =
new QToolButton( mToolBar );
269 menuButton->setMenu( menu );
270 menuButton->setPopupMode( QToolButton::InstantPopup );
271 menuButton->setToolTip( tr(
"Advanced Options" ) );
272 menuButton->setText( QStringLiteral(
"…" ) );
274 QWidget *spacer =
new QWidget();
275 spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
276 mToolBar->addWidget( spacer );
277 mToolBar->addWidget( menuButton );
287 switch ( mStackedWidget->currentIndex() )
290 return mTextEdit->toPlainText();
294 mTextEdit->setText( mSourceEdit->text() );
295 return mTextEdit->toPlainText();
305 switch ( mStackedWidget->currentIndex() )
308 return mTextEdit->toHtml();
311 return mSourceEdit->text();
319void QgsRichTextEditor::editSource(
bool enabled )
323 mSourceEdit->setText( mTextEdit->toHtml() );
324 mStackedWidget->setCurrentIndex( 1 );
328 mTextEdit->setHtml( mSourceEdit->text() );
329 mStackedWidget->setCurrentIndex( 0 );
330 mSourceEdit->clear();
334 mFontSizeCombo->setEnabled( !enabled );
335 mParagraphStyleCombo->setEnabled( !enabled );
336 mForeColorButton->setEnabled( !enabled );
337 mBackColorButton->setEnabled( !enabled );
338 mActionUndo->setEnabled( !enabled );
339 mActionRedo->setEnabled( !enabled );
340 mActionCut->setEnabled( !enabled );
341 mActionCopy->setEnabled( !enabled );
342 mActionPaste->setEnabled( !enabled );
343 mActionInsertLink->setEnabled( !enabled );
344 mActionBold->setEnabled( !enabled );
345 mActionItalic->setEnabled( !enabled );
346 mActionUnderline->setEnabled( !enabled );
347 mActionStrikeOut->setEnabled( !enabled );
348 mActionBulletList->setEnabled( !enabled );
349 mActionOrderedList->setEnabled( !enabled );
350 mActionDecreaseIndent->setEnabled( !enabled );
351 mActionIncreaseIndent->setEnabled( !enabled );
352 mActionInsertImage->setEnabled( !enabled );
360void QgsRichTextEditor::textRemoveFormat()
362 QTextCharFormat format;
363 format.setFontWeight( QFont::Normal );
364 format.setFontUnderline(
false );
365 format.setFontStrikeOut(
false );
366 format.setFontItalic(
false );
367 format.setFontPointSize( 9 );
369 mActionBold->setChecked(
false );
370 mActionUnderline->setChecked(
false );
371 mActionItalic->setChecked(
false );
372 mActionStrikeOut->setChecked(
false );
373 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
375 format.clearBackground();
377 mergeFormatOnWordOrSelection( format );
380void QgsRichTextEditor::textRemoveAllFormat()
382 mActionBold->setChecked(
false );
383 mActionUnderline->setChecked(
false );
384 mActionItalic->setChecked(
false );
385 mActionStrikeOut->setChecked(
false );
386 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( 9 ) );
387 const QString text = mTextEdit->toPlainText();
388 mTextEdit->setPlainText( text );
391void QgsRichTextEditor::textBold()
393 QTextCharFormat format;
394 format.setFontWeight( mActionBold->isChecked() ? QFont::Bold : QFont::Normal );
395 mergeFormatOnWordOrSelection( format );
400 mTextEdit->setFocus( Qt::TabFocusReason );
403void QgsRichTextEditor::textUnderline()
405 QTextCharFormat format;
406 format.setFontUnderline( mActionUnderline->isChecked() );
407 mergeFormatOnWordOrSelection( format );
410void QgsRichTextEditor::textItalic()
412 QTextCharFormat format;
413 format.setFontItalic( mActionItalic->isChecked() );
414 mergeFormatOnWordOrSelection( format );
417void QgsRichTextEditor::textStrikeout()
419 QTextCharFormat format;
420 format.setFontStrikeOut( mActionStrikeOut->isChecked() );
421 mergeFormatOnWordOrSelection( format );
424void QgsRichTextEditor::textSize(
const QString &p )
426 const qreal pointSize = p.toDouble();
427 if ( p.toFloat() > 0 )
429 QTextCharFormat format;
430 format.setFontPointSize( pointSize );
431 mergeFormatOnWordOrSelection( format );
435void QgsRichTextEditor::textLink(
bool checked )
438 QTextCharFormat format;
441 const QString url = mTextEdit->currentCharFormat().anchorHref();
443 const QString newUrl = QInputDialog::getText(
this, tr(
"Create a Link" ), tr(
"Link URL:" ), QLineEdit::Normal, url, &ok );
446 format.setAnchor(
true );
447 format.setAnchorHref( newUrl );
448 format.setForeground( palette().color( QPalette::Link ) );
449 format.setFontUnderline(
true );
462 format.setAnchor(
false );
463 format.setForeground( palette().color( QPalette::Text ) );
464 format.setFontUnderline(
false );
466 mergeFormatOnWordOrSelection( format );
469void QgsRichTextEditor::textStyle(
int )
471 QTextCursor cursor = mTextEdit->textCursor();
472 cursor.beginEditBlock();
475 if ( !cursor.hasSelection() )
477 cursor.select( QTextCursor::BlockUnderCursor );
479 QTextCharFormat format;
480 cursor.setCharFormat( format );
481 mTextEdit->setCurrentCharFormat( format );
483 const ParagraphItems style =
static_cast<ParagraphItems
>( mParagraphStyleCombo->currentData().toInt() );
487 case QgsRichTextEditor::ParagraphStandard:
490 case QgsRichTextEditor::ParagraphHeading1:
491 format.setFontPointSize( mFontSizeH1 );
492 format.setFontWeight( QFont::Bold );
495 case QgsRichTextEditor::ParagraphHeading2:
496 format.setFontPointSize( mFontSizeH2 );
497 format.setFontWeight( QFont::Bold );
498 format.setFontItalic(
true );
501 case QgsRichTextEditor::ParagraphHeading3:
502 format.setFontPointSize( mFontSizeH3 );
503 format.setFontWeight( QFont::Bold );
506 case QgsRichTextEditor::ParagraphHeading4:
507 format.setFontPointSize( mFontSizeH4 );
508 format.setFontWeight( QFont::Bold );
509 format.setFontItalic(
true );
512 case QgsRichTextEditor::ParagraphMonospace:
514 format = cursor.charFormat();
515 format.setFontFamily( mMonospaceFontFamily );
516 format.setFontStyleHint( QFont::Monospace );
517 format.setFontFixedPitch(
true );
522 cursor.setCharFormat( format );
523 mTextEdit->setCurrentCharFormat( format );
525 cursor.endEditBlock();
528void QgsRichTextEditor::textFgColor()
530 QTextCharFormat format;
531 format.setForeground( mForeColorButton->
color() );
532 mergeFormatOnWordOrSelection( format );
535void QgsRichTextEditor::textBgColor()
537 QTextCharFormat format;
538 const QColor col = mBackColorButton->
color();
541 format.setBackground( col );
545 format.clearBackground();
547 mergeFormatOnWordOrSelection( format );
550void QgsRichTextEditor::listBullet(
bool checked )
554 mActionOrderedList->setChecked(
false );
556 list( checked, QTextListFormat::ListDisc );
559void QgsRichTextEditor::listOrdered(
bool checked )
563 mActionBulletList->setChecked(
false );
565 list( checked, QTextListFormat::ListDecimal );
568void QgsRichTextEditor::list(
bool checked, QTextListFormat::Style style )
570 QTextCursor cursor = mTextEdit->textCursor();
571 cursor.beginEditBlock();
574 const QTextBlockFormat originalFormat = cursor.blockFormat();
575 QTextBlockFormat format;
576 format.setIndent( originalFormat.indent() );
577 cursor.setBlockFormat( format );
581 QTextListFormat listFormat;
582 if ( cursor.currentList() )
584 listFormat = cursor.currentList()->format();
586 listFormat.setStyle( style );
587 cursor.createList( listFormat );
589 cursor.endEditBlock();
592void QgsRichTextEditor::mergeFormatOnWordOrSelection(
const QTextCharFormat &format )
594 QTextCursor cursor = mTextEdit->textCursor();
595 if ( !cursor.hasSelection() )
597 cursor.select( QTextCursor::WordUnderCursor );
599 cursor.mergeCharFormat( format );
600 mTextEdit->mergeCurrentCharFormat( format );
601 mTextEdit->setFocus( Qt::TabFocusReason );
604void QgsRichTextEditor::slotCursorPositionChanged()
606 QTextList *l = mTextEdit->textCursor().currentList();
607 if ( mLastBlockList && ( l == mLastBlockList || ( l && mLastBlockList && l->format().style() == mLastBlockList->format().style() ) ) )
614 const QTextListFormat listFormat = l->format();
615 if ( listFormat.style() == QTextListFormat::ListDisc )
617 mActionBulletList->setChecked(
true );
618 mActionOrderedList->setChecked(
false );
620 else if ( listFormat.style() == QTextListFormat::ListDecimal )
622 mActionBulletList->setChecked(
false );
623 mActionOrderedList->setChecked(
true );
627 mActionBulletList->setChecked(
false );
628 mActionOrderedList->setChecked(
false );
633 mActionBulletList->setChecked(
false );
634 mActionOrderedList->setChecked(
false );
638void QgsRichTextEditor::fontChanged(
const QFont &f )
640 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
641 mActionBold->setChecked( f.bold() );
642 mActionItalic->setChecked( f.italic() );
643 mActionUnderline->setChecked( f.underline() );
644 mActionStrikeOut->setChecked( f.strikeOut() );
645 if ( f.pointSize() == mFontSizeH1 )
647 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
649 else if ( f.pointSize() == mFontSizeH2 )
651 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
653 else if ( f.pointSize() == mFontSizeH3 )
655 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
657 else if ( f.pointSize() == mFontSizeH4 )
659 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
663 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
665 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
669 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
672 if ( mTextEdit->textCursor().currentList() )
674 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
675 if ( listFormat.style() == QTextListFormat::ListDisc )
677 mActionBulletList->setChecked(
true );
678 mActionOrderedList->setChecked(
false );
680 else if ( listFormat.style() == QTextListFormat::ListDecimal )
682 mActionBulletList->setChecked(
false );
683 mActionOrderedList->setChecked(
true );
687 mActionBulletList->setChecked(
false );
688 mActionOrderedList->setChecked(
false );
693 mActionBulletList->setChecked(
false );
694 mActionOrderedList->setChecked(
false );
698void QgsRichTextEditor::fgColorChanged(
const QColor &
c )
703void QgsRichTextEditor::bgColorChanged(
const QColor &
c )
711void QgsRichTextEditor::slotCurrentCharFormatChanged(
const QTextCharFormat &format )
713 fontChanged( format.font() );
714 bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
715 fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
716 mActionInsertLink->setChecked( format.isAnchor() );
719void QgsRichTextEditor::slotClipboardDataChanged()
721#ifndef QT_NO_CLIPBOARD
722 if (
const QMimeData *md = QApplication::clipboard()->mimeData() )
723 mActionPaste->setEnabled( md->hasText() );
727void QgsRichTextEditor::increaseIndentation()
732void QgsRichTextEditor::decreaseIndentation()
737void QgsRichTextEditor::indent(
int delta )
739 QTextCursor cursor = mTextEdit->textCursor();
740 cursor.beginEditBlock();
741 QTextBlockFormat format = cursor.blockFormat();
742 const int indent = format.indent();
743 if ( indent + delta >= 0 )
745 format.setIndent( indent + delta );
747 cursor.setBlockFormat( format );
748 cursor.endEditBlock();
753 if ( text.isEmpty() )
755 setPlainText( text );
758 if ( text[0] ==
'<' )
764 setPlainText( text );
768void QgsRichTextEditor::insertImage()
771 const QString attdir = s.value( QStringLiteral(
"general/filedialog-path" ) ).toString();
772 const QString file = QFileDialog::getOpenFileName(
this, tr(
"Select an image" ), attdir, tr(
"JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
773 if ( file.isEmpty() )
776 const QImage image = QImageReader( file ).read();
778 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.