Skip to content
Permalink
Browse files
Nicer edit source mode, using QgsCodeEditorHTML for formatted HTML code
editing
  • Loading branch information
nyalldawson committed Apr 22, 2021
1 parent fee5a29 commit 5895ab9706b1383b13da1ec3ed437f66de72fd3d
Showing with 119 additions and 47 deletions.
  1. +69 −32 src/gui/qgsrichtexteditor.cpp
  2. +4 −2 src/gui/qgsrichtexteditor.h
  3. +46 −13 src/ui/qgsrichtexteditorbase.ui
@@ -32,23 +32,20 @@
#include "qgsguiutils.h"
#include "qgscolorbutton.h"
#include "qgscodeeditor.h"
#include "qgscodeeditorhtml.h"

#include <QMimeData>
#include <QApplication>
#include <QClipboard>
#include <QFontDatabase>
#include <QInputDialog>
#include <QColorDialog>
#include <QTextList>
#include <QtDebug>
#include <QFileDialog>
#include <QImageReader>
#include <QSettings>
#include <QBuffer>
#include <QUrl>
#include <QPlainTextEdit>
#include <QMenu>
#include <QDialog>
#include <QComboBox>
#include <QToolButton>

@@ -59,6 +56,12 @@ QgsRichTextEditor::QgsRichTextEditor( QWidget *parent )

mMonospaceFontFamily = QgsCodeEditor::getMonospaceFont().family();

QVBoxLayout *sourceLayout = new QVBoxLayout();
sourceLayout->setContentsMargins( 0, 0, 0, 0 );
mSourceEdit = new QgsCodeEditorHTML();
sourceLayout->addWidget( mSourceEdit );
mPageSourceEdit->setLayout( sourceLayout );

mToolBar->setIconSize( QgsGuiUtils::iconSize( false ) );

connect( mTextEdit, &QTextEdit::currentCharFormatChanged, this, &QgsRichTextEditor::slotCurrentCharFormatChanged );
@@ -135,19 +138,13 @@ QgsRichTextEditor::QgsRichTextEditor( QWidget *parent )
connect( removeAllFormat, &QAction::triggered, this, &QgsRichTextEditor::textRemoveAllFormat );
mTextEdit->addAction( removeAllFormat );

QAction *textsource = new QAction( tr( "Edit Document Source" ), this );
textsource->setShortcut( QKeySequence( QStringLiteral( "CTRL+O" ) ) );
connect( textsource, &QAction::triggered, this, &QgsRichTextEditor::textSource );
mTextEdit->addAction( textsource );

QAction *clearText = new QAction( tr( "Clear all Content" ), this );
connect( clearText, &QAction::triggered, this, &QgsRichTextEditor::clearSource );
mTextEdit->addAction( clearText );

QMenu *menu = new QMenu( this );
menu->addAction( removeAllFormat );
menu->addAction( removeFormat );
menu->addAction( textsource );
menu->addAction( clearText );

QToolButton *menuButton = new QToolButton();
@@ -207,6 +204,8 @@ QgsRichTextEditor::QgsRichTextEditor( QWidget *parent )
connect( mBackColorButton, &QgsColorButton::colorChanged, this, &QgsRichTextEditor::textBgColor );
mToolBar->insertWidget( listSeparator, mBackColorButton );

connect( mActionEditSource, &QAction::toggled, this, &QgsRichTextEditor::editSource );

// images
connect( mActionInsertImage, &QAction::triggered, this, &QgsRichTextEditor::insertImage );
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
@@ -218,19 +217,68 @@ QgsRichTextEditor::QgsRichTextEditor( QWidget *parent )
fontChanged( mTextEdit->font() );
}

void QgsRichTextEditor::textSource()
QString QgsRichTextEditor::toPlainText() const
{
QDialog dialog( this );
QPlainTextEdit *pte = new QPlainTextEdit( &dialog );
pte->setPlainText( mTextEdit->toHtml() );
QGridLayout *gl = new QGridLayout( &dialog );
gl->addWidget( pte, 0, 0, 1, 1 );
dialog.setWindowTitle( tr( "Document Source" ) );
dialog.setMinimumWidth( 400 );
dialog.setMinimumHeight( 600 );
dialog.exec();
switch ( mStackedWidget->currentIndex() )
{
case 0:
return mTextEdit->toPlainText();

mTextEdit->setHtml( pte->toPlainText() );
case 1:
// go via text edit to remove html from text...
mTextEdit->setText( mSourceEdit->text() );
return mTextEdit->toPlainText();
}
return QString();
}

QString QgsRichTextEditor::toHtml() const
{
switch ( mStackedWidget->currentIndex() )
{
case 0:
return mTextEdit->toPlainText();

case 1:
return mSourceEdit->text();
}
return QString();
}

void QgsRichTextEditor::editSource( bool enabled )
{
if ( enabled )
{
mSourceEdit->setText( mTextEdit->toHtml() );
mStackedWidget->setCurrentIndex( 1 );
}
else
{
mTextEdit->setHtml( mSourceEdit->text() );
mStackedWidget->setCurrentIndex( 0 );
mSourceEdit->clear();
}

// disable formatting actions when in html edit mode
mFontSizeCombo->setEnabled( !enabled );
mParagraphStyleCombo->setEnabled( !enabled );
mForeColorButton->setEnabled( !enabled );
mBackColorButton->setEnabled( !enabled );
mActionUndo->setEnabled( !enabled );
mActionRedo->setEnabled( !enabled );
mActionCut->setEnabled( !enabled );
mActionCopy->setEnabled( !enabled );
mActionPaste->setEnabled( !enabled );
mActionInsertLink->setEnabled( !enabled );
mActionBold->setEnabled( !enabled );
mActionItalic->setEnabled( !enabled );
mActionUnderline->setEnabled( !enabled );
mActionStrikeOut->setEnabled( !enabled );
mActionBulletList->setEnabled( !enabled );
mActionOrderedList->setEnabled( !enabled );
mActionDecreaseIndent->setEnabled( !enabled );
mActionIncreaseIndent->setEnabled( !enabled );
mActionInsertImage->setEnabled( !enabled );
}

void QgsRichTextEditor::clearSource()
@@ -609,17 +657,6 @@ void QgsRichTextEditor::slotClipboardDataChanged()
#endif
}

QString QgsRichTextEditor::toHtml() const
{
QString s = mTextEdit->toHtml();
// convert emails to links
s = s.replace( QRegularExpression( QStringLiteral( "(<[^a][^>]+>(?:<span[^>]+>)?|\\s)([a-zA-Z\\d]+@[a-zA-Z\\d]+\\.[a-zA-Z]+)" ) ), QStringLiteral( "\\1<a href=\"mailto:\\2\">\\2</a>" ) );
// convert links
s = s.replace( QRegularExpression( QStringLiteral( "(<[^a][^>]+>(?:<span[^>]+>)?|\\s)((?:https?|ftp|file)://[^\\s'\"<>]+)" ) ), QStringLiteral( "\\1<a href=\"\\2\">\\2</a>" ) );
// see also: Utils::linkify()
return s;
}

void QgsRichTextEditor::increaseIndentation()
{
indent( +1 );
@@ -39,6 +39,7 @@
class QImage;
class QComboBox;
class QgsColorButton;
class QgsCodeEditorHTML;

/*
* Originally ported from https://github.com/Anchakor/MRichTextEditor, courtesy of Hobrasoft.
@@ -69,7 +70,7 @@ class GUI_EXPORT QgsRichTextEditor : public QWidget, protected Ui::QgsRichTextEd
*
* \see toHtml()
*/
QString toPlainText() const { return mTextEdit->toPlainText(); }
QString toPlainText() const;

/**
* Returns the widget's content as a HTML string.
@@ -136,7 +137,7 @@ class GUI_EXPORT QgsRichTextEditor : public QWidget, protected Ui::QgsRichTextEd
void increaseIndentation();
void decreaseIndentation();
void insertImage();
void textSource();
void editSource( bool enabled );

private:
void mergeFormatOnWordOrSelection( const QTextCharFormat &format );
@@ -166,6 +167,7 @@ class GUI_EXPORT QgsRichTextEditor : public QWidget, protected Ui::QgsRichTextEd

QgsColorButton *mForeColorButton = nullptr;
QgsColorButton *mBackColorButton = nullptr;
QgsCodeEditorHTML *mSourceEdit = nullptr;

QPointer<QTextList> mLastBlockList;
QString mMonospaceFontFamily;
@@ -48,16 +48,38 @@
<addaction name="separator"/>
<addaction name="mActionInsertLink"/>
<addaction name="mActionInsertImage"/>
<addaction name="mActionEditSource"/>
</widget>
</item>
<item>
<widget class="QgsImageDropTextEdit" name="mTextEdit">
<property name="autoFormatting">
<set>QTextEdit::AutoNone</set>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<widget class="QStackedWidget" name="mStackedWidget">
<widget class="QWidget" name="mPageRichEdit">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QgsImageDropTextEdit" name="mTextEdit">
<property name="autoFormatting">
<set>QTextEdit::AutoNone</set>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="mPageSourceEdit"/>
</widget>
</item>
</layout>
@@ -126,7 +148,8 @@
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="insert-link"/>
<iconset theme="insert-link">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Insert Link</string>
@@ -140,7 +163,8 @@
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="format-text-bold"/>
<iconset theme="format-text-bold">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Bold</string>
@@ -215,7 +239,8 @@
</action>
<action name="mActionDecreaseIndent">
<property name="icon">
<iconset theme="format-indent-less"/>
<iconset theme="format-indent-less">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Decrease Indentation</string>
@@ -248,6 +273,17 @@
<string>Insert image</string>
</property>
</action>
<action name="mActionEditSource">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Edit HTML Source</string>
</property>
<property name="toolTip">
<string>Edit HTML Source</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
@@ -256,9 +292,6 @@
<header>qgsimagedroptextedit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mTextEdit</tabstop>
</tabstops>
<resources>
<include location="../../images/images.qrc"/>
</resources>

0 comments on commit 5895ab9

Please sign in to comment.