File indexing completed on 2024-04-21 05:38:18

0001 /*
0002 ** Copyright (C) 2013 Jiří Procházka (Hobrasoft)
0003 ** Contact: http://www.hobrasoft.cz/
0004 **
0005 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
0006 ** Contact: http://www.qt-project.org/legal
0007 **
0008 ** $QT_BEGIN_LICENSE:LGPL$
0009 ** GNU Lesser General Public License Usage
0010 ** This file is under the terms of the GNU Lesser General Public License
0011 ** version 2.1 as published by the Free Software Foundation and appearing
0012 ** in the file LICENSE.LGPL included in the packaging of this file.
0013 ** Please review the following information to ensure the
0014 ** GNU Lesser General Public License version 2.1 requirements
0015 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
0016 **
0017 ** In addition, as a special exception, Digia gives you certain additional
0018 ** rights.  These rights are described in the Digia Qt LGPL Exception
0019 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
0020 **
0021 ** $QT_END_LICENSE$
0022 */
0023 
0024 #include "mrichtextedit.h"
0025 #include <QApplication>
0026 #include <QBuffer>
0027 #include <QClipboard>
0028 #include <QColorDialog>
0029 #include <QDialog>
0030 #include <QFileDialog>
0031 #include <QFontDatabase>
0032 #include <QImageReader>
0033 #include <QInputDialog>
0034 #include <QMenu>
0035 #include <QMimeData>
0036 #include <QPlainTextEdit>
0037 #include <QRegularExpression>
0038 #include <QSettings>
0039 #include <QTextList>
0040 #include <QUrl>
0041 #include <QtDebug>
0042 
0043 #include "ui_mrichtextedit.h"
0044 
0045 MRichTextEdit::MRichTextEdit(QWidget* parent) : QWidget(parent), m_ui(new Ui::MRichTextEdit)
0046 {
0047     m_ui->setupUi(this);
0048     m_lastBlockList= nullptr;
0049     m_ui->f_textedit->setTabStopDistance(40);
0050 
0051     connect(m_ui->f_textedit, SIGNAL(currentCharFormatChanged(QTextCharFormat)), this,
0052             SLOT(slotCurrentCharFormatChanged(QTextCharFormat)));
0053     connect(m_ui->f_textedit, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorPositionChanged()));
0054 
0055     m_fontsize_h1= 18;
0056     m_fontsize_h2= 16;
0057     m_fontsize_h3= 14;
0058     m_fontsize_h4= 12;
0059 
0060     fontChanged(m_ui->f_textedit->font());
0061     bgColorChanged(m_ui->f_textedit->textColor());
0062 
0063     // paragraph formatting
0064 
0065     m_paragraphItems << tr("Standard") << tr("Heading 1") << tr("Heading 2") << tr("Heading 3") << tr("Heading 4")
0066                      << tr("Monospace");
0067     m_ui->f_paragraph->addItems(m_paragraphItems);
0068 
0069     connect(m_ui->f_paragraph, SIGNAL(activated(int)), this, SLOT(textStyle(int)));
0070 
0071     // undo & redo
0072 
0073     m_ui->f_undo->setShortcut(QKeySequence::Undo);
0074     m_ui->f_redo->setShortcut(QKeySequence::Redo);
0075 
0076     connect(m_ui->f_textedit->document(), SIGNAL(undoAvailable(bool)), m_ui->f_undo, SLOT(setEnabled(bool)));
0077     connect(m_ui->f_textedit->document(), SIGNAL(redoAvailable(bool)), m_ui->f_redo, SLOT(setEnabled(bool)));
0078 
0079     m_ui->f_undo->setEnabled(m_ui->f_textedit->document()->isUndoAvailable());
0080     m_ui->f_redo->setEnabled(m_ui->f_textedit->document()->isRedoAvailable());
0081 
0082     connect(m_ui->f_undo, SIGNAL(clicked()), m_ui->f_textedit, SLOT(undo()));
0083     connect(m_ui->f_redo, SIGNAL(clicked()), m_ui->f_textedit, SLOT(redo()));
0084 
0085     // cut, copy & paste
0086 
0087     m_ui->f_cut->setShortcut(QKeySequence::Cut);
0088     m_ui->f_copy->setShortcut(QKeySequence::Copy);
0089     m_ui->f_paste->setShortcut(QKeySequence::Paste);
0090 
0091     m_ui->f_cut->setEnabled(false);
0092     m_ui->f_copy->setEnabled(false);
0093 
0094     connect(m_ui->f_cut, SIGNAL(clicked()), m_ui->f_textedit, SLOT(cut()));
0095     connect(m_ui->f_copy, SIGNAL(clicked()), m_ui->f_textedit, SLOT(copy()));
0096     connect(m_ui->f_paste, SIGNAL(clicked()), m_ui->f_textedit, SLOT(paste()));
0097 
0098     connect(m_ui->f_textedit, SIGNAL(copyAvailable(bool)), m_ui->f_cut, SLOT(setEnabled(bool)));
0099     connect(m_ui->f_textedit, SIGNAL(copyAvailable(bool)), m_ui->f_copy, SLOT(setEnabled(bool)));
0100 
0101 #ifndef QT_NO_CLIPBOARD
0102     connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged()));
0103 #endif
0104 
0105     // link
0106 
0107     m_ui->f_link->setShortcut(Qt::CTRL + Qt::Key_L);
0108 
0109     connect(m_ui->f_link, SIGNAL(clicked(bool)), this, SLOT(textLink(bool)));
0110 
0111     // bold, italic & underline
0112 
0113     m_ui->f_bold->setShortcut(Qt::CTRL + Qt::Key_B);
0114     m_ui->f_italic->setShortcut(Qt::CTRL + Qt::Key_I);
0115     m_ui->f_underline->setShortcut(Qt::CTRL + Qt::Key_U);
0116 
0117     connect(m_ui->f_bold, SIGNAL(clicked()), this, SLOT(textBold()));
0118     connect(m_ui->f_italic, SIGNAL(clicked()), this, SLOT(textItalic()));
0119     connect(m_ui->f_underline, SIGNAL(clicked()), this, SLOT(textUnderline()));
0120     connect(m_ui->f_strikeout, SIGNAL(clicked()), this, SLOT(textStrikeout()));
0121 
0122     QAction* removeFormat= new QAction(tr("Remove character formatting"), this);
0123     removeFormat->setShortcut(QKeySequence("CTRL+M"));
0124     connect(removeFormat, SIGNAL(triggered()), this, SLOT(textRemoveFormat()));
0125     m_ui->f_textedit->addAction(removeFormat);
0126 
0127     QAction* removeAllFormat= new QAction(tr("Remove all formatting"), this);
0128     connect(removeAllFormat, SIGNAL(triggered()), this, SLOT(textRemoveAllFormat()));
0129     m_ui->f_textedit->addAction(removeAllFormat);
0130 
0131     QAction* textsource= new QAction(tr("Edit document source"), this);
0132     textsource->setShortcut(QKeySequence("CTRL+O"));
0133     connect(textsource, SIGNAL(triggered()), this, SLOT(textSource()));
0134     m_ui->f_textedit->addAction(textsource);
0135 
0136     QMenu* menu= new QMenu(this);
0137     menu->addAction(removeAllFormat);
0138     menu->addAction(removeFormat);
0139     menu->addAction(textsource);
0140     m_ui->f_menu->setMenu(menu);
0141     m_ui->f_menu->setPopupMode(QToolButton::InstantPopup);
0142 
0143     // lists
0144 
0145     m_ui->f_list_bullet->setShortcut(Qt::CTRL + Qt::Key_Minus);
0146     m_ui->f_list_ordered->setShortcut(Qt::CTRL + Qt::Key_Equal);
0147 
0148     connect(m_ui->f_list_bullet, SIGNAL(clicked(bool)), this, SLOT(listBullet(bool)));
0149     connect(m_ui->f_list_ordered, SIGNAL(clicked(bool)), this, SLOT(listOrdered(bool)));
0150 
0151     // indentation
0152 
0153     m_ui->f_indent_dec->setShortcut(Qt::CTRL + Qt::Key_Comma);
0154     m_ui->f_indent_inc->setShortcut(Qt::CTRL + Qt::Key_Period);
0155 
0156     connect(m_ui->f_indent_inc, SIGNAL(clicked()), this, SLOT(increaseIndentation()));
0157     connect(m_ui->f_indent_dec, SIGNAL(clicked()), this, SLOT(decreaseIndentation()));
0158 
0159     // font size
0160 
0161     QFontDatabase db;
0162     for(int& size : db.standardSizes())
0163         m_ui->f_fontsize->addItem(QString::number(size));
0164 
0165     connect(m_ui->f_fontsize, SIGNAL(activated(QString)), this, SLOT(textSize(QString)));
0166     m_ui->f_fontsize->setCurrentIndex(m_ui->f_fontsize->findText(QString::number(QApplication::font().pointSize())));
0167 
0168     // text foreground color
0169 
0170     QPixmap pix(16, 16);
0171     pix.fill(QApplication::palette().windowText().color());
0172     m_ui->f_fgcolor->setIcon(pix);
0173 
0174     connect(m_ui->f_fgcolor, SIGNAL(clicked()), this, SLOT(textFgColor()));
0175 
0176     // text background color
0177 
0178     pix.fill(QApplication::palette().window().color());
0179     m_ui->f_bgcolor->setIcon(pix);
0180 
0181     connect(m_ui->f_bgcolor, SIGNAL(clicked()), this, SLOT(textBgColor()));
0182 
0183     // images
0184     connect(m_ui->f_image, SIGNAL(clicked()), this, SLOT(insertImage()));
0185 }
0186 
0187 MRichTextEdit::~MRichTextEdit() = default;
0188 
0189 QString MRichTextEdit::toPlainText() const { return m_ui->f_textedit->toPlainText(); }
0190 
0191 void MRichTextEdit::textSource()
0192 {
0193     QDialog* dialog= new QDialog(this);
0194     QPlainTextEdit* pte= new QPlainTextEdit(dialog);
0195     pte->setPlainText(m_ui->f_textedit->toHtml());
0196     QGridLayout* gl= new QGridLayout(dialog);
0197     gl->addWidget(pte, 0, 0, 1, 1);
0198     dialog->setWindowTitle(tr("Document source"));
0199     dialog->setMinimumWidth(400);
0200     dialog->setMinimumHeight(600);
0201     dialog->exec();
0202 
0203     m_ui->f_textedit->setHtml(pte->toPlainText());
0204 
0205     delete dialog;
0206 }
0207 
0208 void MRichTextEdit::textRemoveFormat()
0209 {
0210     QTextCharFormat fmt;
0211     fmt.setFontWeight(QFont::Normal);
0212     fmt.setFontUnderline(false);
0213     fmt.setFontStrikeOut(false);
0214     fmt.setFontItalic(false);
0215     fmt.setFontPointSize(9);
0216     //  fmt.setFontFamily     ("Helvetica");
0217     //  fmt.setFontStyleHint  (QFont::SansSerif);
0218     //  fmt.setFontFixedPitch (true);
0219 
0220     m_ui->f_bold->setChecked(false);
0221     m_ui->f_underline->setChecked(false);
0222     m_ui->f_italic->setChecked(false);
0223     m_ui->f_strikeout->setChecked(false);
0224     m_ui->f_fontsize->setCurrentIndex(m_ui->f_fontsize->findText("9"));
0225 
0226     //  QTextBlockFormat bfmt = cursor.blockFormat();
0227     //  bfmt->setIndent(0);
0228 
0229     fmt.clearBackground();
0230 
0231     mergeFormatOnWordOrSelection(fmt);
0232 }
0233 
0234 void MRichTextEdit::textRemoveAllFormat()
0235 {
0236     m_ui->f_bold->setChecked(false);
0237     m_ui->f_underline->setChecked(false);
0238     m_ui->f_italic->setChecked(false);
0239     m_ui->f_strikeout->setChecked(false);
0240     m_ui->f_fontsize->setCurrentIndex(m_ui->f_fontsize->findText("9"));
0241     QString text= m_ui->f_textedit->toPlainText();
0242     m_ui->f_textedit->setPlainText(text);
0243 }
0244 
0245 void MRichTextEdit::textBold()
0246 {
0247     QTextCharFormat fmt;
0248     fmt.setFontWeight(m_ui->f_bold->isChecked() ? QFont::Bold : QFont::Normal);
0249     mergeFormatOnWordOrSelection(fmt);
0250 }
0251 
0252 void MRichTextEdit::focusInEvent(QFocusEvent*)
0253 {
0254     m_ui->f_textedit->setFocus(Qt::TabFocusReason);
0255 }
0256 
0257 void MRichTextEdit::textUnderline()
0258 {
0259     QTextCharFormat fmt;
0260     fmt.setFontUnderline(m_ui->f_underline->isChecked());
0261     mergeFormatOnWordOrSelection(fmt);
0262 }
0263 
0264 void MRichTextEdit::textItalic()
0265 {
0266     QTextCharFormat fmt;
0267     fmt.setFontItalic(m_ui->f_italic->isChecked());
0268     mergeFormatOnWordOrSelection(fmt);
0269 }
0270 
0271 void MRichTextEdit::textStrikeout()
0272 {
0273     QTextCharFormat fmt;
0274     fmt.setFontStrikeOut(m_ui->f_strikeout->isChecked());
0275     mergeFormatOnWordOrSelection(fmt);
0276 }
0277 
0278 void MRichTextEdit::textSize(const QString& p)
0279 {
0280     qreal pointSize= p.toFloat();
0281     if(p.toFloat() > 0)
0282     {
0283         QTextCharFormat fmt;
0284         fmt.setFontPointSize(pointSize);
0285         mergeFormatOnWordOrSelection(fmt);
0286     }
0287 }
0288 
0289 void MRichTextEdit::textLink(bool checked)
0290 {
0291     bool unlink= false;
0292     QTextCharFormat fmt;
0293     if(checked)
0294     {
0295         QString url= m_ui->f_textedit->currentCharFormat().anchorHref();
0296         bool ok;
0297         QString newUrl= QInputDialog::getText(this, tr("Create a link"), tr("Link URL:"), QLineEdit::Normal, url, &ok);
0298         if(ok)
0299         {
0300             fmt.setAnchor(true);
0301             fmt.setAnchorHref(newUrl);
0302             fmt.setForeground(QApplication::palette().color(QPalette::Link));
0303             fmt.setFontUnderline(true);
0304         }
0305         else
0306         {
0307             unlink= true;
0308         }
0309     }
0310     else
0311     {
0312         unlink= true;
0313     }
0314     if(unlink)
0315     {
0316         fmt.setAnchor(false);
0317         fmt.setForeground(QApplication::palette().color(QPalette::Text));
0318         fmt.setFontUnderline(false);
0319     }
0320     mergeFormatOnWordOrSelection(fmt);
0321 }
0322 
0323 void MRichTextEdit::textStyle(int index)
0324 {
0325     QTextCursor cursor= m_ui->f_textedit->textCursor();
0326     cursor.beginEditBlock();
0327 
0328     // standard
0329     if(!cursor.hasSelection())
0330     {
0331         cursor.select(QTextCursor::BlockUnderCursor);
0332     }
0333     QTextCharFormat fmt;
0334     cursor.setCharFormat(fmt);
0335     m_ui->f_textedit->setCurrentCharFormat(fmt);
0336 
0337     if(index == ParagraphHeading1 || index == ParagraphHeading2 || index == ParagraphHeading3
0338        || index == ParagraphHeading4)
0339     {
0340         if(index == ParagraphHeading1)
0341         {
0342             fmt.setFontPointSize(m_fontsize_h1);
0343         }
0344         if(index == ParagraphHeading2)
0345         {
0346             fmt.setFontPointSize(m_fontsize_h2);
0347         }
0348         if(index == ParagraphHeading3)
0349         {
0350             fmt.setFontPointSize(m_fontsize_h3);
0351         }
0352         if(index == ParagraphHeading4)
0353         {
0354             fmt.setFontPointSize(m_fontsize_h4);
0355         }
0356         if(index == ParagraphHeading2 || index == ParagraphHeading4)
0357         {
0358             fmt.setFontItalic(true);
0359         }
0360 
0361         fmt.setFontWeight(QFont::Bold);
0362     }
0363     if(index == ParagraphMonospace)
0364     {
0365         fmt= cursor.charFormat();
0366         fmt.setFontFamily("Monospace");
0367         fmt.setFontStyleHint(QFont::Monospace);
0368         fmt.setFontFixedPitch(true);
0369     }
0370     cursor.setCharFormat(fmt);
0371     m_ui->f_textedit->setCurrentCharFormat(fmt);
0372 
0373     cursor.endEditBlock();
0374 }
0375 
0376 void MRichTextEdit::textFgColor()
0377 {
0378     QColor col= QColorDialog::getColor(m_ui->f_textedit->textColor(), this);
0379     QTextCursor cursor= m_ui->f_textedit->textCursor();
0380     if(!cursor.hasSelection())
0381     {
0382         cursor.select(QTextCursor::WordUnderCursor);
0383     }
0384     QTextCharFormat fmt= cursor.charFormat();
0385     if(col.isValid())
0386     {
0387         fmt.setForeground(col);
0388     }
0389     else
0390     {
0391         fmt.clearForeground();
0392     }
0393     cursor.setCharFormat(fmt);
0394     m_ui->f_textedit->setCurrentCharFormat(fmt);
0395     fgColorChanged(col);
0396 }
0397 
0398 void MRichTextEdit::textBgColor()
0399 {
0400     QColor col= QColorDialog::getColor(m_ui->f_textedit->textBackgroundColor(), this);
0401     QTextCursor cursor= m_ui->f_textedit->textCursor();
0402     if(!cursor.hasSelection())
0403     {
0404         cursor.select(QTextCursor::WordUnderCursor);
0405     }
0406     QTextCharFormat fmt= cursor.charFormat();
0407     if(col.isValid())
0408     {
0409         fmt.setBackground(col);
0410     }
0411     else
0412     {
0413         fmt.clearBackground();
0414     }
0415     cursor.setCharFormat(fmt);
0416     m_ui->f_textedit->setCurrentCharFormat(fmt);
0417     bgColorChanged(col);
0418 }
0419 
0420 void MRichTextEdit::listBullet(bool checked)
0421 {
0422     if(checked)
0423     {
0424         m_ui->f_list_ordered->setChecked(false);
0425     }
0426     list(checked, QTextListFormat::ListDisc);
0427 }
0428 
0429 void MRichTextEdit::listOrdered(bool checked)
0430 {
0431     if(checked)
0432     {
0433         m_ui->f_list_bullet->setChecked(false);
0434     }
0435     list(checked, QTextListFormat::ListDecimal);
0436 }
0437 
0438 void MRichTextEdit::list(bool checked, QTextListFormat::Style style)
0439 {
0440     QTextCursor cursor= m_ui->f_textedit->textCursor();
0441     cursor.beginEditBlock();
0442     if(!checked)
0443     {
0444         QTextBlockFormat obfmt= cursor.blockFormat();
0445         QTextBlockFormat bfmt;
0446         bfmt.setIndent(obfmt.indent());
0447         cursor.setBlockFormat(bfmt);
0448     }
0449     else
0450     {
0451         QTextListFormat listFmt;
0452         if(cursor.currentList())
0453         {
0454             listFmt= cursor.currentList()->format();
0455         }
0456         listFmt.setStyle(style);
0457         cursor.createList(listFmt);
0458     }
0459     cursor.endEditBlock();
0460 }
0461 
0462 void MRichTextEdit::mergeFormatOnWordOrSelection(const QTextCharFormat& format)
0463 {
0464     QTextCursor cursor= m_ui->f_textedit->textCursor();
0465     if(!cursor.hasSelection())
0466     {
0467         cursor.select(QTextCursor::WordUnderCursor);
0468     }
0469     cursor.mergeCharFormat(format);
0470     m_ui->f_textedit->mergeCurrentCharFormat(format);
0471     m_ui->f_textedit->setFocus(Qt::TabFocusReason);
0472 }
0473 
0474 void MRichTextEdit::slotCursorPositionChanged()
0475 {
0476     QTextList* l= m_ui->f_textedit->textCursor().currentList();
0477     if(m_lastBlockList
0478        && (l == m_lastBlockList
0479            || (l != nullptr && m_lastBlockList != nullptr && l->format().style() == m_lastBlockList->format().style())))
0480     {
0481         return;
0482     }
0483     m_lastBlockList= l;
0484     if(l)
0485     {
0486         QTextListFormat lfmt= l->format();
0487         if(lfmt.style() == QTextListFormat::ListDisc)
0488         {
0489             m_ui->f_list_bullet->setChecked(true);
0490             m_ui->f_list_ordered->setChecked(false);
0491         }
0492         else if(lfmt.style() == QTextListFormat::ListDecimal)
0493         {
0494             m_ui->f_list_bullet->setChecked(false);
0495             m_ui->f_list_ordered->setChecked(true);
0496         }
0497         else
0498         {
0499             m_ui->f_list_bullet->setChecked(false);
0500             m_ui->f_list_ordered->setChecked(false);
0501         }
0502     }
0503     else
0504     {
0505         m_ui->f_list_bullet->setChecked(false);
0506         m_ui->f_list_ordered->setChecked(false);
0507     }
0508 }
0509 
0510 void MRichTextEdit::fontChanged(const QFont& f)
0511 {
0512     m_ui->f_fontsize->setCurrentIndex(m_ui->f_fontsize->findText(QString::number(f.pointSize())));
0513     m_ui->f_bold->setChecked(f.bold());
0514     m_ui->f_italic->setChecked(f.italic());
0515     m_ui->f_underline->setChecked(f.underline());
0516     m_ui->f_strikeout->setChecked(f.strikeOut());
0517     if(f.pointSize() == m_fontsize_h1)
0518     {
0519         m_ui->f_paragraph->setCurrentIndex(ParagraphHeading1);
0520     }
0521     else if(f.pointSize() == m_fontsize_h2)
0522     {
0523         m_ui->f_paragraph->setCurrentIndex(ParagraphHeading2);
0524     }
0525     else if(f.pointSize() == m_fontsize_h3)
0526     {
0527         m_ui->f_paragraph->setCurrentIndex(ParagraphHeading3);
0528     }
0529     else if(f.pointSize() == m_fontsize_h4)
0530     {
0531         m_ui->f_paragraph->setCurrentIndex(ParagraphHeading4);
0532     }
0533     else
0534     {
0535         if(f.fixedPitch() && f.family() == "Monospace")
0536         {
0537             m_ui->f_paragraph->setCurrentIndex(ParagraphMonospace);
0538         }
0539         else
0540         {
0541             m_ui->f_paragraph->setCurrentIndex(ParagraphStandard);
0542         }
0543     }
0544     if(m_ui->f_textedit->textCursor().currentList())
0545     {
0546         QTextListFormat lfmt= m_ui->f_textedit->textCursor().currentList()->format();
0547         if(lfmt.style() == QTextListFormat::ListDisc)
0548         {
0549             m_ui->f_list_bullet->setChecked(true);
0550             m_ui->f_list_ordered->setChecked(false);
0551         }
0552         else if(lfmt.style() == QTextListFormat::ListDecimal)
0553         {
0554             m_ui->f_list_bullet->setChecked(false);
0555             m_ui->f_list_ordered->setChecked(true);
0556         }
0557         else
0558         {
0559             m_ui->f_list_bullet->setChecked(false);
0560             m_ui->f_list_ordered->setChecked(false);
0561         }
0562     }
0563     else
0564     {
0565         m_ui->f_list_bullet->setChecked(false);
0566         m_ui->f_list_ordered->setChecked(false);
0567     }
0568 }
0569 
0570 void MRichTextEdit::fgColorChanged(const QColor& c)
0571 {
0572     QPixmap pix(16, 16);
0573     if(c.isValid())
0574     {
0575         pix.fill(c);
0576     }
0577     else
0578     {
0579         pix.fill(QApplication::palette().windowText().color());
0580     }
0581     m_ui->f_fgcolor->setIcon(pix);
0582 }
0583 
0584 void MRichTextEdit::bgColorChanged(const QColor& c)
0585 {
0586     QPixmap pix(16, 16);
0587     if(c.isValid())
0588     {
0589         pix.fill(c);
0590     }
0591     else
0592     {
0593         pix.fill(QApplication::palette().window().color());
0594     }
0595     m_ui->f_bgcolor->setIcon(pix);
0596 }
0597 
0598 void MRichTextEdit::slotCurrentCharFormatChanged(const QTextCharFormat& format)
0599 {
0600     fontChanged(format.font());
0601     bgColorChanged((format.background().isOpaque()) ? format.background().color() : QColor());
0602     fgColorChanged((format.foreground().isOpaque()) ? format.foreground().color() : QColor());
0603     m_ui->f_link->setChecked(format.isAnchor());
0604 }
0605 
0606 void MRichTextEdit::slotClipboardDataChanged()
0607 {
0608 #ifndef QT_NO_CLIPBOARD
0609     if(const QMimeData* md= QApplication::clipboard()->mimeData())
0610         m_ui->f_paste->setEnabled(md->hasText());
0611 #endif
0612 }
0613 
0614 QString MRichTextEdit::toHtml() const
0615 {
0616     QString s= m_ui->f_textedit->toHtml();
0617     // convert emails to links
0618     s= s.replace(QRegularExpression("(<[^a][^>]+>(?:<span[^>]+>)?|\\s)([a-zA-Z\\d]+@[a-zA-Z\\d]+\\.[a-zA-Z]+)"),
0619                  "\\1<a href=\"mailto:\\2\">\\2</a>");
0620     // convert links
0621     s= s.replace(QRegularExpression("(<[^a][^>]+>(?:<span[^>]+>)?|\\s)((?:https?|ftp|file)://[^\\s'\"<>]+)"),
0622                  "\\1<a href=\"\\2\">\\2</a>");
0623     // see also: Utils::linkify()
0624     return s;
0625 }
0626 
0627 QTextDocument *MRichTextEdit::document() { return m_ui->f_textedit->document(); }
0628 
0629 QTextCursor MRichTextEdit::textCursor() const { return m_ui->f_textedit->textCursor(); }
0630 
0631 void MRichTextEdit::setTextCursor(const QTextCursor &cursor) { m_ui->f_textedit->setTextCursor(cursor); }
0632 
0633 void MRichTextEdit::increaseIndentation()
0634 {
0635     indent(+1);
0636 }
0637 
0638 void MRichTextEdit::decreaseIndentation()
0639 {
0640     indent(-1);
0641 }
0642 
0643 void MRichTextEdit::indent(int delta)
0644 {
0645     QTextCursor cursor= m_ui->f_textedit->textCursor();
0646     cursor.beginEditBlock();
0647     QTextBlockFormat bfmt= cursor.blockFormat();
0648     int ind= bfmt.indent();
0649     if(ind + delta >= 0)
0650     {
0651         bfmt.setIndent(ind + delta);
0652     }
0653     cursor.setBlockFormat(bfmt);
0654     cursor.endEditBlock();
0655 }
0656 
0657 void MRichTextEdit::setText(const QString& text)
0658 {
0659     if(text.isEmpty())
0660     {
0661         setPlainText(text);
0662         return;
0663     }
0664     if(text[0] == '<')
0665     {
0666         setHtml(text);
0667     }
0668     else
0669     {
0670         setPlainText(text);
0671     }
0672 }
0673 
0674 void MRichTextEdit::setPlainText(const QString &text) { m_ui->f_textedit->setPlainText(text); }
0675 
0676 void MRichTextEdit::setHtml(const QString &text) { m_ui->f_textedit->setHtml(text); }
0677 
0678 void MRichTextEdit::insertImage()
0679 {
0680     QSettings s;
0681     QString attdir= s.value("general/filedialog-path").toString();
0682     QString file= QFileDialog::getOpenFileName(this, tr("Select an image"), attdir,
0683                                                tr("JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)"));
0684     QImage image= QImageReader(file).read();
0685 
0686     m_ui->f_textedit->dropImage(image, QFileInfo(file).suffix().toUpper().toLocal8Bit().data());
0687 }