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" ),
444 tr(
"Link URL:" ), QLineEdit::Normal,
449 format.setAnchor(
true );
450 format.setAnchorHref( newUrl );
451 format.setForeground( palette().color( QPalette::Link ) );
452 format.setFontUnderline(
true );
465 format.setAnchor(
false );
466 format.setForeground( palette().color( QPalette::Text ) );
467 format.setFontUnderline(
false );
469 mergeFormatOnWordOrSelection( format );
472void QgsRichTextEditor::textStyle(
int )
474 QTextCursor cursor = mTextEdit->textCursor();
475 cursor.beginEditBlock();
478 if ( !cursor.hasSelection() )
480 cursor.select( QTextCursor::BlockUnderCursor );
482 QTextCharFormat format;
483 cursor.setCharFormat( format );
484 mTextEdit->setCurrentCharFormat( format );
486 const ParagraphItems style =
static_cast< ParagraphItems
>( mParagraphStyleCombo->currentData().toInt() );
490 case QgsRichTextEditor::ParagraphStandard:
493 case QgsRichTextEditor::ParagraphHeading1:
494 format.setFontPointSize( mFontSizeH1 );
495 format.setFontWeight( QFont::Bold );
498 case QgsRichTextEditor::ParagraphHeading2:
499 format.setFontPointSize( mFontSizeH2 );
500 format.setFontWeight( QFont::Bold );
501 format.setFontItalic(
true );
504 case QgsRichTextEditor::ParagraphHeading3:
505 format.setFontPointSize( mFontSizeH3 );
506 format.setFontWeight( QFont::Bold );
509 case QgsRichTextEditor::ParagraphHeading4:
510 format.setFontPointSize( mFontSizeH4 );
511 format.setFontWeight( QFont::Bold );
512 format.setFontItalic(
true );
515 case QgsRichTextEditor::ParagraphMonospace:
517 format = cursor.charFormat();
518 format.setFontFamily( mMonospaceFontFamily );
519 format.setFontStyleHint( QFont::Monospace );
520 format.setFontFixedPitch(
true );
525 cursor.setCharFormat( format );
526 mTextEdit->setCurrentCharFormat( format );
528 cursor.endEditBlock();
531void QgsRichTextEditor::textFgColor()
533 QTextCharFormat format;
534 format.setForeground( mForeColorButton->
color() );
535 mergeFormatOnWordOrSelection( format );
538void QgsRichTextEditor::textBgColor()
540 QTextCharFormat format;
541 const QColor col = mBackColorButton->
color();
544 format.setBackground( col );
548 format.clearBackground();
550 mergeFormatOnWordOrSelection( format );
553void QgsRichTextEditor::listBullet(
bool checked )
557 mActionOrderedList->setChecked(
false );
559 list( checked, QTextListFormat::ListDisc );
562void QgsRichTextEditor::listOrdered(
bool checked )
566 mActionBulletList->setChecked(
false );
568 list( checked, QTextListFormat::ListDecimal );
571void QgsRichTextEditor::list(
bool checked, QTextListFormat::Style style )
573 QTextCursor cursor = mTextEdit->textCursor();
574 cursor.beginEditBlock();
577 const QTextBlockFormat originalFormat = cursor.blockFormat();
578 QTextBlockFormat format;
579 format.setIndent( originalFormat.indent() );
580 cursor.setBlockFormat( format );
584 QTextListFormat listFormat;
585 if ( cursor.currentList() )
587 listFormat = cursor.currentList()->format();
589 listFormat.setStyle( style );
590 cursor.createList( listFormat );
592 cursor.endEditBlock();
595void QgsRichTextEditor::mergeFormatOnWordOrSelection(
const QTextCharFormat &format )
597 QTextCursor cursor = mTextEdit->textCursor();
598 if ( !cursor.hasSelection() )
600 cursor.select( QTextCursor::WordUnderCursor );
602 cursor.mergeCharFormat( format );
603 mTextEdit->mergeCurrentCharFormat( format );
604 mTextEdit->setFocus( Qt::TabFocusReason );
607void QgsRichTextEditor::slotCursorPositionChanged()
609 QTextList *l = mTextEdit->textCursor().currentList();
610 if ( mLastBlockList && ( l == mLastBlockList || ( l && mLastBlockList
611 && l->format().style() == mLastBlockList->format().style() ) ) )
618 const QTextListFormat listFormat = l->format();
619 if ( listFormat.style() == QTextListFormat::ListDisc )
621 mActionBulletList->setChecked(
true );
622 mActionOrderedList->setChecked(
false );
624 else if ( listFormat.style() == QTextListFormat::ListDecimal )
626 mActionBulletList->setChecked(
false );
627 mActionOrderedList->setChecked(
true );
631 mActionBulletList->setChecked(
false );
632 mActionOrderedList->setChecked(
false );
637 mActionBulletList->setChecked(
false );
638 mActionOrderedList->setChecked(
false );
642void QgsRichTextEditor::fontChanged(
const QFont &f )
644 mFontSizeCombo->setCurrentIndex( mFontSizeCombo->findData( f.pointSize() ) );
645 mActionBold->setChecked( f.bold() );
646 mActionItalic->setChecked( f.italic() );
647 mActionUnderline->setChecked( f.underline() );
648 mActionStrikeOut->setChecked( f.strikeOut() );
649 if ( f.pointSize() == mFontSizeH1 )
651 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading1 );
653 else if ( f.pointSize() == mFontSizeH2 )
655 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading2 );
657 else if ( f.pointSize() == mFontSizeH3 )
659 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading3 );
661 else if ( f.pointSize() == mFontSizeH4 )
663 mParagraphStyleCombo->setCurrentIndex( ParagraphHeading4 );
667 if ( f.fixedPitch() && f.family() == mMonospaceFontFamily )
669 mParagraphStyleCombo->setCurrentIndex( ParagraphMonospace );
673 mParagraphStyleCombo->setCurrentIndex( ParagraphStandard );
676 if ( mTextEdit->textCursor().currentList() )
678 const QTextListFormat listFormat = mTextEdit->textCursor().currentList()->format();
679 if ( listFormat.style() == QTextListFormat::ListDisc )
681 mActionBulletList->setChecked(
true );
682 mActionOrderedList->setChecked(
false );
684 else if ( listFormat.style() == QTextListFormat::ListDecimal )
686 mActionBulletList->setChecked(
false );
687 mActionOrderedList->setChecked(
true );
691 mActionBulletList->setChecked(
false );
692 mActionOrderedList->setChecked(
false );
697 mActionBulletList->setChecked(
false );
698 mActionOrderedList->setChecked(
false );
702void QgsRichTextEditor::fgColorChanged(
const QColor &
c )
707void QgsRichTextEditor::bgColorChanged(
const QColor &
c )
715void QgsRichTextEditor::slotCurrentCharFormatChanged(
const QTextCharFormat &format )
717 fontChanged( format.font() );
718 bgColorChanged( ( format.background().isOpaque() ) ? format.background().color() : QColor() );
719 fgColorChanged( ( format.foreground().isOpaque() ) ? format.foreground().color() : palette().windowText().color() );
720 mActionInsertLink->setChecked( format.isAnchor() );
723void QgsRichTextEditor::slotClipboardDataChanged()
725#ifndef QT_NO_CLIPBOARD
726 if (
const QMimeData *md = QApplication::clipboard()->mimeData() )
727 mActionPaste->setEnabled( md->hasText() );
731void QgsRichTextEditor::increaseIndentation()
736void QgsRichTextEditor::decreaseIndentation()
741void QgsRichTextEditor::indent(
int delta )
743 QTextCursor cursor = mTextEdit->textCursor();
744 cursor.beginEditBlock();
745 QTextBlockFormat format = cursor.blockFormat();
746 const int indent = format.indent();
747 if ( indent + delta >= 0 )
749 format.setIndent( indent + delta );
751 cursor.setBlockFormat( format );
752 cursor.endEditBlock();
757 if ( text.isEmpty() )
759 setPlainText( text );
762 if ( text[0] ==
'<' )
768 setPlainText( text );
772void QgsRichTextEditor::insertImage()
775 const QString attdir = s.value( QStringLiteral(
"general/filedialog-path" ) ).toString();
776 const QString file = QFileDialog::getOpenFileName(
this,
777 tr(
"Select an image" ),
779 tr(
"JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)" ) );
780 if ( file.isEmpty() )
783 const QImage image = QImageReader( file ).read();
785 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.