2015-12-10 05:06:13 +02:00
/****************************************************************************
* *
* * Copyright ( C ) 2015 The Qt Company Ltd .
2019-12-29 23:21:34 +00:00
* * Copyright ( C ) 2016 - 2020 Ivailo Monev
2015-12-10 05:06:13 +02:00
* *
2019-11-29 03:33:51 +00:00
* * This file is part of the Katie Designer of the Katie Toolkit .
2015-12-10 05:06:13 +02:00
* *
* * $ QT_BEGIN_LICENSE : LGPL $
* *
* * GNU Lesser General Public License Usage
2019-12-29 23:21:34 +00:00
* * This file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
2015-12-10 05:06:13 +02:00
* *
* * As a special exception , The Qt Company gives you certain additional
* * rights . These rights are described in The Qt Company LGPL Exception
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 3.0 as published by the Free Software
* * Foundation and appearing in the file LICENSE . GPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU General Public License version 3.0 requirements will be
* * met : http : //www.gnu.org/copyleft/gpl.html.
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "richtexteditor_p.h"
# include "htmlhighlighter_p.h"
# include "iconselector_p.h"
# include "ui_addlinkdialog.h"
# include "abstractsettings_p.h"
# include "iconloader_p.h"
# include <QtDesigner/abstractformeditor.h>
# include <QtCore/QList>
# include <QtCore/QMap>
# include <QtCore/QPointer>
2019-05-07 19:08:52 +00:00
# include <QtXml/qxmlstream.h>
2015-12-10 05:06:13 +02:00
# include <QtGui/QAction>
# include <QtGui/QColorDialog>
# include <QtGui/QComboBox>
# include <QtGui/QFontDatabase>
# include <QtGui/QTextCursor>
# include <QtGui/QPainter>
# include <QtGui/QIcon>
# include <QtGui/QMenu>
# include <QtGui/qevent.h>
# include <QtGui/QTabWidget>
# include <QtGui/QTextDocument>
# include <QtGui/qtextobject.h>
# include <QtGui/QToolBar>
# include <QtGui/QToolButton>
# include <QtGui/QVBoxLayout>
# include <QtGui/QHBoxLayout>
# include <QtGui/QPushButton>
# include <QtGui/QDialogButtonBox>
QT_BEGIN_NAMESPACE
static const char RichTextDialogGroupC [ ] = " RichTextDialog " ;
static const char GeometryKeyC [ ] = " Geometry " ;
static const char TabKeyC [ ] = " Tab " ;
const bool simplifyRichTextDefault = true ;
namespace qdesigner_internal {
// Richtext simplification filter helpers: Elements to be discarded
static inline bool filterElement ( const QStringRef & name )
{
return name ! = QLatin1String ( " meta " ) & & name ! = QLatin1String ( " style " ) ;
}
// Richtext simplification filter helpers: Filter attributes of elements
static inline void filterAttributes ( const QStringRef & name ,
QXmlStreamAttributes * atts ,
bool * paragraphAlignmentFound )
{
typedef QXmlStreamAttributes : : iterator AttributeIt ;
if ( atts - > isEmpty ( ) )
return ;
// No style attributes for <body>
if ( name = = QLatin1String ( " body " ) ) {
atts - > clear ( ) ;
return ;
}
// Clean out everything except 'align' for 'p'
if ( name = = QLatin1String ( " p " ) ) {
for ( AttributeIt it = atts - > begin ( ) ; it ! = atts - > end ( ) ; ) {
if ( it - > name ( ) = = QLatin1String ( " align " ) ) {
+ + it ;
* paragraphAlignmentFound = true ;
} else {
it = atts - > erase ( it ) ;
}
}
return ;
}
}
// Richtext simplification filter helpers: Check for blank QStringRef.
static inline bool isWhiteSpace ( const QStringRef & in )
{
const int count = in . size ( ) ;
for ( int i = 0 ; i < count ; i + + )
if ( ! in . at ( i ) . isSpace ( ) )
return false ;
return true ;
}
// Richtext simplification filter: Remove hard-coded font settings,
// <style> elements, <p> attributes other than 'align' and
// and unnecessary meta-information.
QString simplifyRichTextFilter ( const QString & in , bool * isPlainTextPtr = 0 )
{
unsigned elementCount = 0 ;
bool paragraphAlignmentFound = false ;
QString out ;
QXmlStreamReader reader ( in ) ;
QXmlStreamWriter writer ( & out ) ;
writer . setAutoFormatting ( false ) ;
writer . setAutoFormattingIndent ( 0 ) ;
while ( ! reader . atEnd ( ) ) {
switch ( reader . readNext ( ) ) {
case QXmlStreamReader : : StartElement :
elementCount + + ;
if ( filterElement ( reader . name ( ) ) ) {
const QStringRef name = reader . name ( ) ;
QXmlStreamAttributes attributes = reader . attributes ( ) ;
filterAttributes ( name , & attributes , & paragraphAlignmentFound ) ;
writer . writeStartElement ( name . toString ( ) ) ;
if ( ! attributes . isEmpty ( ) )
writer . writeAttributes ( attributes ) ;
} else {
reader . readElementText ( ) ; // Skip away all nested elements and characters.
}
break ;
case QXmlStreamReader : : Characters :
if ( ! isWhiteSpace ( reader . text ( ) ) )
writer . writeCharacters ( reader . text ( ) . toString ( ) ) ;
break ;
case QXmlStreamReader : : EndElement :
writer . writeEndElement ( ) ;
break ;
default :
break ;
}
}
// Check for plain text (no spans, just <html><head><body><p>)
if ( isPlainTextPtr )
* isPlainTextPtr = ! paragraphAlignmentFound & & elementCount = = 4u ; //
return out ;
}
class RichTextEditor : public QTextEdit
{
Q_OBJECT
public :
2016-11-04 04:13:46 +00:00
explicit RichTextEditor ( QWidget * parent = Q_NULLPTR ) ;
2015-12-10 05:06:13 +02:00
void setDefaultFont ( QFont font ) ;
2016-11-04 04:13:46 +00:00
QToolBar * createToolBar ( QDesignerFormEditorInterface * core , QWidget * parent = Q_NULLPTR ) ;
2015-12-10 05:06:13 +02:00
bool simplifyRichText ( ) const { return m_simplifyRichText ; }
public slots :
void setFontBold ( bool b ) ;
void setFontPointSize ( double ) ;
void setText ( const QString & text ) ;
void setSimplifyRichText ( bool v ) ;
QString text ( Qt : : TextFormat format ) const ;
signals :
void stateChanged ( ) ;
void simplifyRichTextChanged ( bool ) ;
private :
bool m_simplifyRichText ;
} ;
class AddLinkDialog : public QDialog
{
Q_OBJECT
public :
2016-11-04 04:13:46 +00:00
AddLinkDialog ( RichTextEditor * editor , QWidget * parent = Q_NULLPTR ) ;
2015-12-10 05:06:13 +02:00
~ AddLinkDialog ( ) ;
int showDialog ( ) ;
public slots :
void accept ( ) ;
private :
RichTextEditor * m_editor ;
2016-08-26 18:05:03 +00:00
Ui_AddLinkDialog * m_ui ;
2015-12-10 05:06:13 +02:00
} ;
AddLinkDialog : : AddLinkDialog ( RichTextEditor * editor , QWidget * parent ) :
QDialog ( parent ) ,
2016-08-26 18:05:03 +00:00
m_ui ( new Ui_AddLinkDialog )
2015-12-10 05:06:13 +02:00
{
m_ui - > setupUi ( this ) ;
setWindowFlags ( windowFlags ( ) & ~ Qt : : WindowContextHelpButtonHint ) ;
m_editor = editor ;
}
AddLinkDialog : : ~ AddLinkDialog ( )
{
delete m_ui ;
}
int AddLinkDialog : : showDialog ( )
{
// Set initial focus
const QTextCursor cursor = m_editor - > textCursor ( ) ;
if ( cursor . hasSelection ( ) ) {
m_ui - > titleInput - > setText ( cursor . selectedText ( ) ) ;
m_ui - > urlInput - > setFocus ( ) ;
} else {
m_ui - > titleInput - > setFocus ( ) ;
}
return exec ( ) ;
}
void AddLinkDialog : : accept ( )
{
const QString title = m_ui - > titleInput - > text ( ) ;
const QString url = m_ui - > urlInput - > text ( ) ;
if ( ! title . isEmpty ( ) ) {
QString html = QLatin1String ( " <a href= \" " ) ;
html + = url ;
html + = QLatin1String ( " \" > " ) ;
html + = title ;
html + = QLatin1String ( " </a> " ) ;
m_editor - > insertHtml ( html ) ;
}
m_ui - > titleInput - > clear ( ) ;
m_ui - > urlInput - > clear ( ) ;
QDialog : : accept ( ) ;
}
class HtmlTextEdit : public QTextEdit
{
Q_OBJECT
public :
2016-11-04 04:13:46 +00:00
HtmlTextEdit ( QWidget * parent = Q_NULLPTR )
2015-12-10 05:06:13 +02:00
: QTextEdit ( parent )
{ }
void contextMenuEvent ( QContextMenuEvent * event ) ;
private slots :
void actionTriggered ( QAction * action ) ;
} ;
void HtmlTextEdit : : contextMenuEvent ( QContextMenuEvent * event )
{
QMenu * menu = createStandardContextMenu ( ) ;
QMenu * htmlMenu = new QMenu ( tr ( " Insert HTML entity " ) , menu ) ;
typedef struct {
const char * text ;
const char * entity ;
} Entry ;
const Entry entries [ ] = {
{ " && (&&) " , " & " } ,
{ " & " , " " } ,
{ " &< (<) " , " < " } ,
{ " &> (>) " , " > " } ,
{ " &© (Copyright) " , " © " } ,
{ " &® (Trade Mark) " , " ® " } ,
} ;
for ( int i = 0 ; i < 6 ; + + i ) {
QAction * entityAction = new QAction ( QLatin1String ( entries [ i ] . text ) ,
htmlMenu ) ;
entityAction - > setData ( QLatin1String ( entries [ i ] . entity ) ) ;
htmlMenu - > addAction ( entityAction ) ;
}
menu - > addMenu ( htmlMenu ) ;
connect ( htmlMenu , SIGNAL ( triggered ( QAction * ) ) ,
SLOT ( actionTriggered ( QAction * ) ) ) ;
menu - > exec ( event - > globalPos ( ) ) ;
delete menu ;
}
void HtmlTextEdit : : actionTriggered ( QAction * action )
{
insertPlainText ( action - > data ( ) . toString ( ) ) ;
}
class ColorAction : public QAction
{
Q_OBJECT
public :
ColorAction ( QObject * parent ) ;
const QColor & color ( ) const { return m_color ; }
void setColor ( const QColor & color ) ;
signals :
void colorChanged ( const QColor & color ) ;
private slots :
void chooseColor ( ) ;
private :
QColor m_color ;
} ;
ColorAction : : ColorAction ( QObject * parent ) :
QAction ( parent )
{
setText ( tr ( " Text Color " ) ) ;
setColor ( Qt : : black ) ;
connect ( this , SIGNAL ( triggered ( ) ) , this , SLOT ( chooseColor ( ) ) ) ;
}
void ColorAction : : setColor ( const QColor & color )
{
if ( color = = m_color )
return ;
m_color = color ;
QPixmap pix ( 24 , 24 ) ;
QPainter painter ( & pix ) ;
painter . setRenderHint ( QPainter : : Antialiasing , false ) ;
painter . fillRect ( pix . rect ( ) , m_color ) ;
painter . setPen ( m_color . darker ( ) ) ;
painter . drawRect ( pix . rect ( ) . adjusted ( 0 , 0 , - 1 , - 1 ) ) ;
setIcon ( pix ) ;
}
void ColorAction : : chooseColor ( )
{
const QColor col = QColorDialog : : getColor ( m_color , 0 ) ;
if ( col . isValid ( ) & & col ! = m_color ) {
setColor ( col ) ;
emit colorChanged ( m_color ) ;
}
}
class RichTextEditorToolBar : public QToolBar
{
Q_OBJECT
public :
RichTextEditorToolBar ( QDesignerFormEditorInterface * core ,
RichTextEditor * editor ,
2016-11-04 04:13:46 +00:00
QWidget * parent = Q_NULLPTR ) ;
2015-12-10 05:06:13 +02:00
public slots :
void updateActions ( ) ;
private slots :
void alignmentActionTriggered ( QAction * action ) ;
void sizeInputActivated ( const QString & size ) ;
void colorChanged ( const QColor & color ) ;
void setVAlignSuper ( bool super ) ;
void setVAlignSub ( bool sub ) ;
void insertLink ( ) ;
void insertImage ( ) ;
private :
QAction * m_bold_action ;
QAction * m_italic_action ;
QAction * m_underline_action ;
QAction * m_valign_sup_action ;
QAction * m_valign_sub_action ;
QAction * m_align_left_action ;
QAction * m_align_center_action ;
QAction * m_align_right_action ;
QAction * m_align_justify_action ;
QAction * m_link_action ;
QAction * m_image_action ;
QAction * m_simplify_richtext_action ;
ColorAction * m_color_action ;
QComboBox * m_font_size_input ;
QDesignerFormEditorInterface * m_core ;
QPointer < RichTextEditor > m_editor ;
} ;
static QAction * createCheckableAction ( const QIcon & icon , const QString & text ,
QObject * receiver , const char * slot ,
2016-11-04 12:42:19 +00:00
QObject * parent = Q_NULLPTR )
2015-12-10 05:06:13 +02:00
{
QAction * result = new QAction ( parent ) ;
result - > setIcon ( icon ) ;
result - > setText ( text ) ;
result - > setCheckable ( true ) ;
result - > setChecked ( false ) ;
if ( slot )
QObject : : connect ( result , SIGNAL ( triggered ( bool ) ) , receiver , slot ) ;
return result ;
}
RichTextEditorToolBar : : RichTextEditorToolBar ( QDesignerFormEditorInterface * core ,
RichTextEditor * editor ,
QWidget * parent ) :
QToolBar ( parent ) ,
m_link_action ( new QAction ( this ) ) ,
m_image_action ( new QAction ( this ) ) ,
m_color_action ( new ColorAction ( this ) ) ,
m_font_size_input ( new QComboBox ) ,
m_core ( core ) ,
m_editor ( editor )
{
// Font size combo box
m_font_size_input - > setEditable ( false ) ;
const QList < int > font_sizes = QFontDatabase : : standardSizes ( ) ;
foreach ( int font_size , font_sizes )
m_font_size_input - > addItem ( QString : : number ( font_size ) ) ;
connect ( m_font_size_input , SIGNAL ( activated ( QString ) ) ,
this , SLOT ( sizeInputActivated ( QString ) ) ) ;
addWidget ( m_font_size_input ) ;
addSeparator ( ) ;
// Bold, italic and underline buttons
m_bold_action = createCheckableAction (
createIconSet ( QLatin1String ( " textbold.png " ) ) ,
tr ( " Bold " ) , editor , SLOT ( setFontBold ( bool ) ) , this ) ;
m_bold_action - > setShortcut ( tr ( " CTRL+B " ) ) ;
addAction ( m_bold_action ) ;
m_italic_action = createCheckableAction (
createIconSet ( QLatin1String ( " textitalic.png " ) ) ,
tr ( " Italic " ) , editor , SLOT ( setFontItalic ( bool ) ) , this ) ;
m_italic_action - > setShortcut ( tr ( " CTRL+I " ) ) ;
addAction ( m_italic_action ) ;
m_underline_action = createCheckableAction (
createIconSet ( QLatin1String ( " textunder.png " ) ) ,
tr ( " Underline " ) , editor , SLOT ( setFontUnderline ( bool ) ) , this ) ;
m_underline_action - > setShortcut ( tr ( " CTRL+U " ) ) ;
addAction ( m_underline_action ) ;
addSeparator ( ) ;
// Left, center, right and justified alignment buttons
QActionGroup * alignment_group = new QActionGroup ( this ) ;
connect ( alignment_group , SIGNAL ( triggered ( QAction * ) ) ,
SLOT ( alignmentActionTriggered ( QAction * ) ) ) ;
m_align_left_action = createCheckableAction (
createIconSet ( QLatin1String ( " textleft.png " ) ) ,
tr ( " Left Align " ) , editor , 0 , alignment_group ) ;
addAction ( m_align_left_action ) ;
m_align_center_action = createCheckableAction (
createIconSet ( QLatin1String ( " textcenter.png " ) ) ,
tr ( " Center " ) , editor , 0 , alignment_group ) ;
addAction ( m_align_center_action ) ;
m_align_right_action = createCheckableAction (
createIconSet ( QLatin1String ( " textright.png " ) ) ,
tr ( " Right Align " ) , editor , 0 , alignment_group ) ;
addAction ( m_align_right_action ) ;
m_align_justify_action = createCheckableAction (
createIconSet ( QLatin1String ( " textjustify.png " ) ) ,
tr ( " Justify " ) , editor , 0 , alignment_group ) ;
addAction ( m_align_justify_action ) ;
addSeparator ( ) ;
// Superscript and subscript buttons
m_valign_sup_action = createCheckableAction (
createIconSet ( QLatin1String ( " textsuperscript.png " ) ) ,
tr ( " Superscript " ) ,
this , SLOT ( setVAlignSuper ( bool ) ) , this ) ;
addAction ( m_valign_sup_action ) ;
m_valign_sub_action = createCheckableAction (
createIconSet ( QLatin1String ( " textsubscript.png " ) ) ,
tr ( " Subscript " ) ,
this , SLOT ( setVAlignSub ( bool ) ) , this ) ;
addAction ( m_valign_sub_action ) ;
addSeparator ( ) ;
// Insert hyperlink and image buttons
m_link_action - > setIcon ( createIconSet ( QLatin1String ( " textanchor.png " ) ) ) ;
m_link_action - > setText ( tr ( " Insert &Link " ) ) ;
connect ( m_link_action , SIGNAL ( triggered ( ) ) , SLOT ( insertLink ( ) ) ) ;
addAction ( m_link_action ) ;
m_image_action - > setIcon ( createIconSet ( QLatin1String ( " insertimage.png " ) ) ) ;
m_image_action - > setText ( tr ( " Insert &Image " ) ) ;
connect ( m_image_action , SIGNAL ( triggered ( ) ) , SLOT ( insertImage ( ) ) ) ;
addAction ( m_image_action ) ;
addSeparator ( ) ;
// Text color button
connect ( m_color_action , SIGNAL ( colorChanged ( QColor ) ) ,
this , SLOT ( colorChanged ( QColor ) ) ) ;
addAction ( m_color_action ) ;
addSeparator ( ) ;
// Simplify rich text
m_simplify_richtext_action
= createCheckableAction ( createIconSet ( QLatin1String ( " simplifyrichtext.png " ) ) ,
tr ( " Simplify Rich Text " ) , m_editor , SLOT ( setSimplifyRichText ( bool ) ) ) ;
m_simplify_richtext_action - > setChecked ( m_editor - > simplifyRichText ( ) ) ;
connect ( m_editor , SIGNAL ( simplifyRichTextChanged ( bool ) ) ,
m_simplify_richtext_action , SLOT ( setChecked ( bool ) ) ) ;
addAction ( m_simplify_richtext_action ) ;
connect ( editor , SIGNAL ( textChanged ( ) ) , this , SLOT ( updateActions ( ) ) ) ;
connect ( editor , SIGNAL ( stateChanged ( ) ) , this , SLOT ( updateActions ( ) ) ) ;
updateActions ( ) ;
}
void RichTextEditorToolBar : : alignmentActionTriggered ( QAction * action )
{
Qt : : Alignment new_alignment ;
if ( action = = m_align_left_action ) {
new_alignment = Qt : : AlignLeft ;
} else if ( action = = m_align_center_action ) {
new_alignment = Qt : : AlignCenter ;
} else if ( action = = m_align_right_action ) {
new_alignment = Qt : : AlignRight ;
} else {
new_alignment = Qt : : AlignJustify ;
}
m_editor - > setAlignment ( new_alignment ) ;
}
void RichTextEditorToolBar : : colorChanged ( const QColor & color )
{
m_editor - > setTextColor ( color ) ;
m_editor - > setFocus ( ) ;
}
void RichTextEditorToolBar : : sizeInputActivated ( const QString & size )
{
bool ok ;
int i = size . toInt ( & ok ) ;
if ( ! ok )
return ;
m_editor - > setFontPointSize ( i ) ;
m_editor - > setFocus ( ) ;
}
void RichTextEditorToolBar : : setVAlignSuper ( bool super )
{
const QTextCharFormat : : VerticalAlignment align = super ?
QTextCharFormat : : AlignSuperScript : QTextCharFormat : : AlignNormal ;
QTextCharFormat charFormat = m_editor - > currentCharFormat ( ) ;
charFormat . setVerticalAlignment ( align ) ;
m_editor - > setCurrentCharFormat ( charFormat ) ;
m_valign_sub_action - > setChecked ( false ) ;
}
void RichTextEditorToolBar : : setVAlignSub ( bool sub )
{
const QTextCharFormat : : VerticalAlignment align = sub ?
QTextCharFormat : : AlignSubScript : QTextCharFormat : : AlignNormal ;
QTextCharFormat charFormat = m_editor - > currentCharFormat ( ) ;
charFormat . setVerticalAlignment ( align ) ;
m_editor - > setCurrentCharFormat ( charFormat ) ;
m_valign_sup_action - > setChecked ( false ) ;
}
void RichTextEditorToolBar : : insertLink ( )
{
AddLinkDialog linkDialog ( m_editor , this ) ;
linkDialog . showDialog ( ) ;
m_editor - > setFocus ( ) ;
}
void RichTextEditorToolBar : : insertImage ( )
{
const QString path = IconSelector : : choosePixmapResource ( m_core , m_core - > resourceModel ( ) , QString ( ) , this ) ;
if ( ! path . isEmpty ( ) )
m_editor - > insertHtml ( QLatin1String ( " <img src= \" " ) + path + QLatin1String ( " \" /> " ) ) ;
}
void RichTextEditorToolBar : : updateActions ( )
{
if ( m_editor = = 0 ) {
setEnabled ( false ) ;
return ;
}
const Qt : : Alignment alignment = m_editor - > alignment ( ) ;
const QTextCursor cursor = m_editor - > textCursor ( ) ;
const QTextCharFormat charFormat = cursor . charFormat ( ) ;
const QFont font = charFormat . font ( ) ;
const QTextCharFormat : : VerticalAlignment valign =
charFormat . verticalAlignment ( ) ;
const bool superScript = valign = = QTextCharFormat : : AlignSuperScript ;
const bool subScript = valign = = QTextCharFormat : : AlignSubScript ;
if ( alignment & Qt : : AlignLeft ) {
m_align_left_action - > setChecked ( true ) ;
} else if ( alignment & Qt : : AlignRight ) {
m_align_right_action - > setChecked ( true ) ;
} else if ( alignment & Qt : : AlignHCenter ) {
m_align_center_action - > setChecked ( true ) ;
} else {
m_align_justify_action - > setChecked ( true ) ;
}
m_bold_action - > setChecked ( font . bold ( ) ) ;
m_italic_action - > setChecked ( font . italic ( ) ) ;
m_underline_action - > setChecked ( font . underline ( ) ) ;
m_valign_sup_action - > setChecked ( superScript ) ;
m_valign_sub_action - > setChecked ( subScript ) ;
const int size = font . pointSize ( ) ;
const int idx = m_font_size_input - > findText ( QString : : number ( size ) ) ;
if ( idx ! = - 1 )
m_font_size_input - > setCurrentIndex ( idx ) ;
m_color_action - > setColor ( m_editor - > textColor ( ) ) ;
}
RichTextEditor : : RichTextEditor ( QWidget * parent )
: QTextEdit ( parent ) , m_simplifyRichText ( simplifyRichTextDefault )
{
connect ( this , SIGNAL ( currentCharFormatChanged ( QTextCharFormat ) ) ,
this , SIGNAL ( stateChanged ( ) ) ) ;
connect ( this , SIGNAL ( cursorPositionChanged ( ) ) ,
this , SIGNAL ( stateChanged ( ) ) ) ;
}
QToolBar * RichTextEditor : : createToolBar ( QDesignerFormEditorInterface * core , QWidget * parent )
{
return new RichTextEditorToolBar ( core , this , parent ) ;
}
void RichTextEditor : : setFontBold ( bool b )
{
if ( b )
setFontWeight ( QFont : : Bold ) ;
else
setFontWeight ( QFont : : Normal ) ;
}
void RichTextEditor : : setFontPointSize ( double d )
{
QTextEdit : : setFontPointSize ( qreal ( d ) ) ;
}
void RichTextEditor : : setText ( const QString & text )
{
if ( Qt : : mightBeRichText ( text ) )
setHtml ( text ) ;
else
setPlainText ( text ) ;
}
void RichTextEditor : : setSimplifyRichText ( bool v )
{
if ( v ! = m_simplifyRichText ) {
m_simplifyRichText = v ;
emit simplifyRichTextChanged ( v ) ;
}
}
void RichTextEditor : : setDefaultFont ( QFont font )
{
// Some default fonts on Windows have a default size of 7.8,
// which results in complicated rich text generated by toHtml().
// Use an integer value.
const int pointSize = qRound ( font . pointSizeF ( ) ) ;
if ( pointSize > 0 & & ! qFuzzyCompare ( qreal ( pointSize ) , font . pointSizeF ( ) ) ) {
font . setPointSize ( pointSize ) ;
}
document ( ) - > setDefaultFont ( font ) ;
if ( font . pointSize ( ) > 0 )
setFontPointSize ( font . pointSize ( ) ) ;
else
setFontPointSize ( QFontInfo ( font ) . pointSize ( ) ) ;
emit textChanged ( ) ;
}
QString RichTextEditor : : text ( Qt : : TextFormat format ) const
{
switch ( format ) {
case Qt : : PlainText :
return toPlainText ( ) ;
case Qt : : RichText :
return m_simplifyRichText ? simplifyRichTextFilter ( toHtml ( ) ) : toHtml ( ) ;
case Qt : : AutoText :
break ;
}
const QString html = toHtml ( ) ;
bool isPlainText ;
const QString simplifiedHtml = simplifyRichTextFilter ( html , & isPlainText ) ;
if ( isPlainText )
return toPlainText ( ) ;
return m_simplifyRichText ? simplifiedHtml : html ;
}
RichTextEditorDialog : : RichTextEditorDialog ( QDesignerFormEditorInterface * core , QWidget * parent ) :
QDialog ( parent ) ,
m_editor ( new RichTextEditor ( ) ) ,
m_text_edit ( new HtmlTextEdit ) ,
m_tab_widget ( new QTabWidget ) ,
m_state ( Clean ) ,
m_core ( core ) ,
m_initialTab ( RichTextIndex )
{
setWindowTitle ( tr ( " Edit text " ) ) ;
setWindowFlags ( windowFlags ( ) & ~ Qt : : WindowContextHelpButtonHint ) ;
// Read settings
const QDesignerSettingsInterface * settings = core - > settingsManager ( ) ;
const QString rootKey = QLatin1String ( RichTextDialogGroupC ) + QLatin1Char ( ' / ' ) ;
const QByteArray lastGeometry = settings - > value ( rootKey + QLatin1String ( GeometryKeyC ) ) . toByteArray ( ) ;
const int initialTab = settings - > value ( rootKey + QLatin1String ( TabKeyC ) , QVariant ( m_initialTab ) ) . toInt ( ) ;
if ( initialTab = = RichTextIndex | | initialTab = = SourceIndex )
m_initialTab = initialTab ;
m_text_edit - > setAcceptRichText ( false ) ;
new HtmlHighlighter ( m_text_edit ) ;
connect ( m_editor , SIGNAL ( textChanged ( ) ) , this , SLOT ( richTextChanged ( ) ) ) ;
connect ( m_editor , SIGNAL ( simplifyRichTextChanged ( bool ) ) , this , SLOT ( richTextChanged ( ) ) ) ;
connect ( m_text_edit , SIGNAL ( textChanged ( ) ) , this , SLOT ( sourceChanged ( ) ) ) ;
// The toolbar needs to be created after the RichTextEditor
QToolBar * tool_bar = m_editor - > createToolBar ( core ) ;
tool_bar - > setSizePolicy ( QSizePolicy : : Expanding , QSizePolicy : : Minimum ) ;
QWidget * rich_edit = new QWidget ;
QVBoxLayout * rich_edit_layout = new QVBoxLayout ( rich_edit ) ;
rich_edit_layout - > addWidget ( tool_bar ) ;
rich_edit_layout - > addWidget ( m_editor ) ;
QWidget * plain_edit = new QWidget ;
QVBoxLayout * plain_edit_layout = new QVBoxLayout ( plain_edit ) ;
plain_edit_layout - > addWidget ( m_text_edit ) ;
m_tab_widget - > setTabPosition ( QTabWidget : : South ) ;
m_tab_widget - > addTab ( rich_edit , tr ( " Rich Text " ) ) ;
m_tab_widget - > addTab ( plain_edit , tr ( " Source " ) ) ;
connect ( m_tab_widget , SIGNAL ( currentChanged ( int ) ) ,
SLOT ( tabIndexChanged ( int ) ) ) ;
QDialogButtonBox * buttonBox = new QDialogButtonBox ( QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel , Qt : : Horizontal ) ;
QPushButton * ok_button = buttonBox - > button ( QDialogButtonBox : : Ok ) ;
ok_button - > setText ( tr ( " &OK " ) ) ;
ok_button - > setDefault ( true ) ;
buttonBox - > button ( QDialogButtonBox : : Cancel ) - > setText ( tr ( " &Cancel " ) ) ;
connect ( buttonBox , SIGNAL ( accepted ( ) ) , this , SLOT ( accept ( ) ) ) ;
connect ( buttonBox , SIGNAL ( rejected ( ) ) , this , SLOT ( reject ( ) ) ) ;
QVBoxLayout * layout = new QVBoxLayout ( this ) ;
layout - > addWidget ( m_tab_widget ) ;
layout - > addWidget ( buttonBox ) ;
if ( ! lastGeometry . isEmpty ( ) )
restoreGeometry ( lastGeometry ) ;
}
RichTextEditorDialog : : ~ RichTextEditorDialog ( )
{
QDesignerSettingsInterface * settings = m_core - > settingsManager ( ) ;
settings - > beginGroup ( QLatin1String ( RichTextDialogGroupC ) ) ;
settings - > setValue ( QLatin1String ( GeometryKeyC ) , saveGeometry ( ) ) ;
settings - > setValue ( QLatin1String ( TabKeyC ) , m_tab_widget - > currentIndex ( ) ) ;
settings - > endGroup ( ) ;
}
int RichTextEditorDialog : : showDialog ( )
{
m_tab_widget - > setCurrentIndex ( m_initialTab ) ;
switch ( m_initialTab ) {
case RichTextIndex :
m_editor - > selectAll ( ) ;
m_editor - > setFocus ( ) ;
break ;
case SourceIndex :
m_text_edit - > selectAll ( ) ;
m_text_edit - > setFocus ( ) ;
break ;
}
return exec ( ) ;
}
void RichTextEditorDialog : : setDefaultFont ( const QFont & font )
{
m_editor - > setDefaultFont ( font ) ;
}
void RichTextEditorDialog : : setText ( const QString & text )
{
// Generally simplify rich text unless verbose text is found.
2016-06-15 02:32:57 +00:00
const bool isSimplifiedRichText = ! text . startsWith ( QLatin1String ( " <!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML 4.0//EN \" \" http://www.w3.org/TR/REC-html40/strict.dtd \" > " ) ) ;
2015-12-10 05:06:13 +02:00
m_editor - > setSimplifyRichText ( isSimplifiedRichText ) ;
m_editor - > setText ( text ) ;
m_text_edit - > setPlainText ( text ) ;
m_state = Clean ;
}
QString RichTextEditorDialog : : text ( Qt : : TextFormat format ) const
{
// In autotext mode, if the user has changed the source, use that
if ( format = = Qt : : AutoText & & ( m_state = = Clean | | m_state = = SourceChanged ) )
return m_text_edit - > toPlainText ( ) ;
// If the plain text HTML editor is selected, first copy its contents over
// to the rich text editor so that it is converted to Qt-HTML or actual
// plain text.
if ( m_tab_widget - > currentIndex ( ) = = SourceIndex & & m_state = = SourceChanged )
m_editor - > setHtml ( m_text_edit - > toPlainText ( ) ) ;
return m_editor - > text ( format ) ;
}
void RichTextEditorDialog : : tabIndexChanged ( int newIndex )
{
// Anything changed, is there a need for a conversion?
if ( newIndex = = SourceIndex & & m_state ! = RichTextChanged )
return ;
if ( newIndex = = RichTextIndex & & m_state ! = SourceChanged )
return ;
const State oldState = m_state ;
// Remember the cursor position, since it is invalidated by setPlainText
QTextEdit * new_edit = ( newIndex = = SourceIndex ) ? m_text_edit : m_editor ;
const int position = new_edit - > textCursor ( ) . position ( ) ;
if ( newIndex = = SourceIndex )
m_text_edit - > setPlainText ( m_editor - > text ( Qt : : RichText ) ) ;
else
m_editor - > setHtml ( m_text_edit - > toPlainText ( ) ) ;
QTextCursor cursor = new_edit - > textCursor ( ) ;
cursor . movePosition ( QTextCursor : : End ) ;
if ( cursor . position ( ) > position ) {
cursor . setPosition ( position ) ;
}
new_edit - > setTextCursor ( cursor ) ;
m_state = oldState ; // Changed is triggered by setting the text
}
void RichTextEditorDialog : : richTextChanged ( )
{
m_state = RichTextChanged ;
}
void RichTextEditorDialog : : sourceChanged ( )
{
m_state = SourceChanged ;
}
} // namespace qdesigner_internal
QT_END_NAMESPACE
# include "moc_richtexteditor.cpp"
2019-12-31 00:24:20 +00:00
# include "moc_richtexteditor_p.h"