File indexing completed on 2024-04-21 05:43:43
0001 /*************************************************************************** 0002 * Copyright (C) 2006 by David Saxton - david@bluehaze.org * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 ***************************************************************************/ 0009 0010 #include "richtexteditor.h" 0011 0012 #include <KToggleAction> 0013 #include <KToolBarPopupAction> 0014 0015 #include <KLocalizedString> 0016 // #include <k3popupmenu.h> 0017 #include <KActionCollection> 0018 #include <KTextEdit> 0019 #include <KToolBar> 0020 0021 #include <QFont> 0022 #include <QIcon> 0023 #include <QTextEdit> 0024 //#include <qmime.h> 0025 #include <QColorDialog> 0026 #include <QDialogButtonBox> 0027 #include <QDir> 0028 #include <QMenu> 0029 #include <QPushButton> 0030 #include <QRegExp> 0031 #include <QTextList> 0032 #include <QTextListFormat> 0033 #include <QVBoxLayout> 0034 0035 #include <ktechlab_debug.h> 0036 0037 // #include <q3vbox.h> 0038 // #include <q3textedit.h> 0039 // #include <q3stylesheet.h> 0040 0041 // BEGIN class RichTextEditor 0042 RichTextEditor::RichTextEditor(QWidget *parent) 0043 : QWidget(parent) 0044 { 0045 QVBoxLayout *layout = new QVBoxLayout(this /*, 0, 6 */); 0046 layout->setMargin(0); 0047 layout->setSpacing(6); 0048 m_pEditor = new QTextEdit(this); //, "RichTextEdit" ); 0049 m_pEditor->setObjectName("RichTextEdit"); 0050 layout->addWidget(m_pEditor); 0051 0052 // m_pEditor->setTextFormat( Qt::RichText ); // 2018.12.07 - just use toHtml() and html() 0053 0054 connect(m_pEditor, &QTextEdit::textChanged, this, &RichTextEditor::textChanged); 0055 connect(m_pEditor, &QTextEdit::currentCharFormatChanged, this, &RichTextEditor::slotCurrentCharFormatChanged); 0056 // connect( m_pEditor, SIGNAL( currentFontChanged( const QFont & ) ), this, SLOT( fontChanged( const QFont & ) ) ); // 2018.01.03 - use slotCurrentCharFormatChanged 0057 // connect( m_pEditor, SIGNAL( currentColorChanged( const QColor & ) ), this, SLOT( colorChanged( const QColor & ) ) ); // 2018.01.03 - use slotCurrentCharFormatChanged 0058 // connect( m_pEditor, SIGNAL( currentAlignmentChanged( int ) ), this, SLOT( alignmentChanged( int ) ) ); // 2018.01.03 - use slotCurrentCharFormatChanged 0059 // connect( m_pEditor, SIGNAL( currentVerticalAlignmentChanged( Q3TextEdit::VerticalAlignment ) ), this, SLOT(verticalAlignmentChanged()) ); // 2018.01.03 - use slotCurrentCharFormatChanged 0060 0061 KToolBar *tools = new KToolBar(QStringLiteral("RichTextEditorToops"), this); 0062 layout->addWidget(tools); 0063 KActionCollection *ac = new KActionCollection(m_pEditor); 0064 0065 // m_pTextBold = new KToggleAction( i18n("Bold"), "format-text-bold", Qt::CTRL + Qt::Key_B, 0, 0, ac, "format_bold" ); 0066 m_pTextBold = new KToggleAction(i18n("Bold"), ac); 0067 m_pTextBold->setObjectName("text_bold"); 0068 m_pTextBold->setShortcut(Qt::CTRL + Qt::Key_B); 0069 m_pTextBold->setIcon(QIcon::fromTheme("format-text-bold")); 0070 connect(m_pTextBold, &KToggleAction::toggled, this, &RichTextEditor::slotSetBold); 0071 // m_pTextBold->plug( tools ); 0072 tools->addAction(m_pTextBold); 0073 0074 // m_pTextItalic = new KToggleAction( i18n("Italic"), "format-text-italic", Qt::CTRL + Qt::Key_I, 0, 0, ac, "format_italic" ); 0075 m_pTextItalic = new KToggleAction(i18n("Italic"), ac); 0076 m_pTextItalic->setObjectName("text_italic"); 0077 m_pTextItalic->setShortcut(Qt::CTRL + Qt::Key_I); 0078 m_pTextItalic->setIcon(QIcon::fromTheme("format-text-italic")); 0079 connect(m_pTextItalic, &KToggleAction::toggled, this, &RichTextEditor::slotSetItalic); 0080 // m_pTextItalic->plug( tools ); 0081 tools->addAction(m_pTextItalic); 0082 0083 // m_pTextUnderline = new KToggleAction( i18n("Underline"), "format-text-underline", Qt::CTRL + Qt::Key_U, 0, 0, ac, "format_underline" ); 0084 m_pTextUnderline = new KToggleAction(i18n("Underline"), ac); 0085 m_pTextUnderline->setObjectName("text_under"); 0086 m_pTextUnderline->setShortcut(Qt::CTRL + Qt::Key_U); 0087 m_pTextItalic->setIcon(QIcon::fromTheme("format-text-underline")); 0088 connect(m_pTextUnderline, &KToggleAction::toggled, this, &RichTextEditor::slotSetUnderline); 0089 // m_pTextUnderline->plug( tools ); 0090 tools->addAction(m_pTextUnderline); 0091 0092 // m_pTextList = new KToggleAction( i18n("List"), "unsorted_list", Qt::CTRL + Qt::Key_L, 0, 0, ac, "format_list" ); 0093 m_pTextList = new KToggleAction(i18n("List"), ac); 0094 m_pTextList->setObjectName("unsorted_list"); 0095 m_pTextList->setShortcut(Qt::CTRL + Qt::Key_L); 0096 m_pTextItalic->setIcon(QIcon::fromTheme("format-list-unordered")); 0097 connect(m_pTextList, &KToggleAction::toggled, this, &RichTextEditor::slotSetList); 0098 // m_pTextList->plug( tools ); 0099 tools->addAction(m_pTextList); 0100 0101 // BEGIN Text horizontal-alignment actions 0102 // m_pTextAlignment = new KToolBarPopupAction( i18n("Text Alignment"), "format-justify-left", 0, 0, 0, ac, "text_alignment" ); 0103 m_pTextAlignment = new KToolBarPopupAction(QIcon::fromTheme("format-justify-left"), i18n("Text Alignment"), ac); 0104 m_pTextAlignment->setObjectName("text_left"); 0105 // m_pTextAlignment->plug( tools ); 0106 tools->addAction(m_pTextAlignment); 0107 m_pTextAlignment->setDelayed(false); 0108 0109 // K3PopupMenu * m = m_pTextAlignment->menu(); 0110 QMenu *m = m_pTextAlignment->menu(); 0111 // m->insertTitle( i18n("Text Alignment") ); 0112 m->setTitle(i18n("Text Alignment")); 0113 // m->setCheckable( true ); // 2018.12.07 0114 0115 // m->insertItem( QIcon::fromTheme( "format-justify-left" ), i18n("Align Left"), Qt::AlignLeft ); 0116 m->addAction(QIcon::fromTheme("format-justify-left"), i18n("Align Left"))->setData(Qt::AlignLeft); 0117 // m->insertItem( QIcon::fromTheme( "format-justify-center"), i18n("Align Center"), Qt::AlignHCenter ); 0118 m->addAction(QIcon::fromTheme("format-justify-center"), i18n("Align Center"))->setData(Qt::AlignHCenter); 0119 // m->insertItem( QIcon::fromTheme( "format-justify-right" ), i18n("Align Right"), Qt::AlignRight ); 0120 m->addAction(QIcon::fromTheme("format-justify-right"), i18n("Align Right"))->setData(Qt::AlignRight); 0121 // m->insertItem( QIcon::fromTheme( "format-justify-fill" ), i18n("Align Block"), Qt::AlignJustify ); 0122 m->addAction(QIcon::fromTheme("format-justify-fill"), i18n("Align Block"))->setData(Qt::AlignJustify); 0123 connect(m, &QMenu::triggered, this, &RichTextEditor::slotSetAlignment); 0124 // END Text horizontal-alignment actions 0125 0126 // BEGIN Text vertical-alignment actions 0127 // m_pTextVerticalAlignment = new KToolBarPopupAction( i18n("Text Vertical Alignment"), "text", 0, 0, 0, ac, "text_vertical_alignment" ); 0128 m_pTextVerticalAlignment = new KToolBarPopupAction(QIcon::fromTheme(QString("text_vertical_alignment")), i18n("Text Vertical Alignment"), ac); 0129 m_pTextVerticalAlignment->setObjectName("text"); 0130 // m_pTextVerticalAlignment->plug( tools ); 0131 tools->addAction(m_pTextVerticalAlignment); 0132 m_pTextVerticalAlignment->setDelayed(false); 0133 0134 m = m_pTextVerticalAlignment->menu(); 0135 // m->insertTitle( i18n("Text Vertical Alignment") ); 0136 m->setTitle(i18n("Text Vertical Alignment")); 0137 // m->setCheckable( true ); // 2018.12.07 0138 0139 m->addAction(QIcon::fromTheme("format-text-superscript"), i18n("Superscript"))->setData(QTextCharFormat::AlignSuperScript); 0140 // m->insertItem( QIcon::fromTheme( "format-text-superscript" ), i18n("Superscript"), QTextCharFormat::AlignSuperScript ); 0141 m->addAction(i18n("Normal"))->setData(QTextCharFormat::AlignNormal); 0142 // m->insertItem( i18n("Normal"), QTextCharFormat::AlignNormal ); 0143 m->addAction(QIcon::fromTheme("format-text-subscript"), i18n("Subscript"))->setData(QTextCharFormat::AlignSubScript); 0144 // m->insertItem( QIcon::fromTheme( "format-text-subscript" ), i18n("Subscript"), QTextCharFormat::AlignSubScript ); 0145 connect(m, &QMenu::triggered, this, &RichTextEditor::slotSetVerticalAlignment); 0146 // END Text vertical-alignment actions 0147 0148 QPixmap pm(16, 16); 0149 pm.fill(Qt::black); 0150 // m_pTextColor = new KAction( i18n("Text Color..."), pm, 0, this, SLOT(textColor()), ac, "format_color" ); 0151 m_pTextColor = new QAction(i18n("Text Color..."), this); 0152 m_pTextColor->setIcon(pm); 0153 m_pTextColor->setObjectName("format_color"); 0154 connect(m_pTextColor, &QAction::triggered, this, &RichTextEditor::textColor); 0155 // m_pTextColor->plug( tools ); 0156 ac->addAction("format_color", m_pTextColor); 0157 tools->addAction(m_pTextColor); 0158 } 0159 0160 RichTextEditor::~RichTextEditor() 0161 { 0162 } 0163 0164 void RichTextEditor::makeUseStandardFont(QString *html) 0165 { 0166 if (!html) 0167 return; 0168 0169 QFont f; 0170 QString bodyString = QString("<body style=\"font-size:%1pt;font-family:%2\">").arg(f.pointSize()).arg(f.family()); 0171 0172 if (html->contains("<body>")) { 0173 // Set the correct font size 0174 QFont f; 0175 html->replace("<body>", bodyString); 0176 } 0177 0178 else if (!html->startsWith("<html>")) { 0179 html->prepend("<html>" + bodyString); 0180 html->append("</body></html>"); 0181 } 0182 } 0183 0184 QWidget *RichTextEditor::editorViewport() const 0185 { 0186 return m_pEditor->viewport(); 0187 } 0188 0189 void RichTextEditor::setText(QString text) 0190 { 0191 if (!Qt::mightBeRichText(text)) { 0192 // Format the text to be HTML 0193 text.replace('\n', "<br>"); 0194 } 0195 0196 m_pEditor->setText(text); 0197 } 0198 0199 QString RichTextEditor::text() const 0200 { 0201 QString text = m_pEditor->toHtml().trimmed(); 0202 0203 // Remove the style info (e.g. style="font-size:8pt;font-family:DejaVu Sans") inserted into the body tag. 0204 text.replace(QRegExp("<body style=\"[^\"]*\">"), "<body>"); 0205 0206 // Replace all non-latin1 characters with HTML codes to represent them 0207 QString nonAsciiChars; 0208 for (int i = 0; i < text.length(); ++i) { 0209 QChar current = text[i]; 0210 if ((current.toLatin1() == 0) && (current.unicode() != 0)) { 0211 // A non-latin1 character 0212 if (!nonAsciiChars.contains(current)) 0213 nonAsciiChars.append(current); 0214 } 0215 } 0216 for (int i = 0; i < nonAsciiChars.length(); ++i) { 0217 text.replace(nonAsciiChars[i], QString("&#%1;").arg(nonAsciiChars[i].unicode())); 0218 } 0219 0220 return text; 0221 } 0222 0223 void RichTextEditor::insertURL(const QString &url, const QString &text) 0224 { 0225 insertHTML(QString("<a href=\"%1\">%2</a>").arg(url).arg(text)); 0226 } 0227 0228 void RichTextEditor::insertHTML(const QString &html) 0229 { 0230 // 2018.12.07 0231 // // Save cursor position 0232 // //int cursorPara, cursorIndex; 0233 // //m_pEditor->getCursorPosition( & cursorPara, & cursorIndex ); 0234 // QPoint cursorPos; 0235 // cursorPos = m_pEditor->cursor().pos(); 0236 // 0237 // // replaceString is used so that the inserted text is at the cursor position. 0238 // // it's just a random set of characters, so that the chance of them actually being 0239 // // used is about zero. 0240 // QString replaceString = "SXbCk2CtqJ83"; 0241 // 0242 // m_pEditor->insert( replaceString ); 0243 // QString editorText = m_pEditor->text(); 0244 // //editorText.replace( replaceString, html, (uint)0 ); // 2018.12.07 0245 // editorText.replace( replaceString, html, Qt::CaseInsensitive ); 0246 // m_pEditor->setText( editorText ); 0247 // 0248 // // Restore cursor position 0249 // //m_pEditor->setCursorPosition( cursorPara, cursorIndex ); 0250 // m_pEditor->cursor().setPos(cursorPos); 0251 0252 m_pEditor->insertHtml(html); 0253 } 0254 0255 void RichTextEditor::slotSetBold(bool isBold) 0256 { 0257 QTextCharFormat format; 0258 if (isBold) { 0259 format.setFontWeight(QFont::Bold); 0260 } else { 0261 format.setFontWeight(QFont::Normal); 0262 } 0263 m_pEditor->textCursor().mergeCharFormat(format); 0264 } 0265 void RichTextEditor::slotSetItalic(bool isItalic) 0266 { 0267 QTextCharFormat format; 0268 format.setFontItalic(isItalic); 0269 m_pEditor->textCursor().mergeCharFormat(format); 0270 } 0271 void RichTextEditor::slotSetUnderline(bool isUnderline) 0272 { 0273 QTextCharFormat format; 0274 format.setFontUnderline(isUnderline); 0275 m_pEditor->textCursor().mergeCharFormat(format); 0276 } 0277 void RichTextEditor::slotSetAlignment(QAction *act) 0278 { 0279 int alignment = act->data().toInt(); 0280 QTextBlockFormat format = m_pEditor->textCursor().blockFormat(); 0281 format.setAlignment(static_cast<Qt::AlignmentFlag>(alignment)); 0282 m_pEditor->textCursor().mergeBlockFormat(format); 0283 } 0284 0285 void RichTextEditor::slotSetVerticalAlignment(QAction *action) 0286 { 0287 int a = action->data().toInt(); 0288 // m_pEditor->setVerticalAlignment( (Q3TextEdit::VerticalAlignment)a ); 0289 // m_pEditor->setAlignment(a); 0290 QTextCharFormat format; 0291 format.setVerticalAlignment(static_cast<QTextCharFormat::VerticalAlignment>(a)); 0292 m_pEditor->mergeCurrentCharFormat(format); 0293 } 0294 0295 void RichTextEditor::slotSetList(bool set) 0296 { 0297 // m_pEditor->setParagType( set ? Q3StyleSheetItem::DisplayListItem : Q3StyleSheetItem::DisplayBlock, Q3StyleSheetItem::ListDisc ); 0298 if (set) { 0299 m_pEditor->textCursor().createList(QTextListFormat::ListDisc); 0300 } else { 0301 QTextCursor cursor = m_pEditor->textCursor(); 0302 QTextList *list = cursor.currentList(); 0303 if (list) { 0304 QTextListFormat::Style style = QTextListFormat::ListStyleUndefined; 0305 QTextListFormat listFormat; 0306 listFormat.setIndent(0); 0307 listFormat.setStyle(style); 0308 list->setFormat(listFormat); 0309 0310 for (int i = list->count() - 1; i >= 0; --i) 0311 list->removeItem(i); 0312 } 0313 } 0314 } 0315 0316 void RichTextEditor::slotCurrentCharFormatChanged(const QTextCharFormat &f) 0317 { 0318 fontChanged(f.font()); 0319 // colorChanged( m_pEditor->foregroundColor() ); // 2018.12.07 0320 colorChanged(m_pEditor->palette().color(m_pEditor->foregroundRole())); 0321 alignmentChanged(m_pEditor->alignment()); 0322 verticalAlignmentChanged(); // note: consider removing this method 0323 } 0324 0325 void RichTextEditor::fontChanged(const QFont &f) 0326 { 0327 m_pTextBold->setChecked(f.bold()); 0328 m_pTextItalic->setChecked(f.italic()); 0329 m_pTextUnderline->setChecked(f.underline()); 0330 } 0331 0332 void RichTextEditor::textColor() 0333 { 0334 const QColor c = QColorDialog::getColor(m_pEditor->textColor(), this); 0335 if (c.isValid()) { 0336 m_pEditor->setTextColor(c); 0337 } 0338 } 0339 0340 void RichTextEditor::colorChanged(const QColor &c) 0341 { 0342 QPixmap pix(16, 16); 0343 pix.fill(c); 0344 m_pTextColor->setIcon(pix); 0345 } 0346 0347 void RichTextEditor::alignmentChanged(int a) 0348 { 0349 if (/*( a == Qt::AlignAuto ) || */ (a & Qt::AlignLeft)) 0350 m_pTextAlignment->setIcon(QIcon::fromTheme("format-justify-left")); 0351 else if ((a & Qt::AlignHCenter)) 0352 m_pTextAlignment->setIcon(QIcon::fromTheme("format-justify-center")); 0353 else if ((a & Qt::AlignRight)) 0354 m_pTextAlignment->setIcon(QIcon::fromTheme("format-justify-right")); 0355 else if ((a & Qt::AlignJustify)) 0356 m_pTextAlignment->setIcon(QIcon::fromTheme("format-justify-fill")); 0357 } 0358 0359 void RichTextEditor::verticalAlignmentChanged() 0360 { 0361 // QTextEdit::VerticalAlignment a = 0362 // if ( a == KTextEdit::AlignNormal ) 0363 // m_pTextVerticalAlignment->setIcon( "text" ); 0364 // else if ( a == KTextEdit::AlignSuperScript ) 0365 // m_pTextVerticalAlignment->setIcon( "format-text-superscript" ); 0366 // else if ( a == KTextEdit::AlignSubScript ) 0367 // m_pTextVerticalAlignment->setIcon( "format-text-subscript" ); 0368 } 0369 0370 void RichTextEditor::setResourcePaths(const QStringList &paths) 0371 { 0372 // m_pEditor->mimeSourceFactory()->setFilePath( paths ); 0373 0374 for (QStringList::const_iterator itStr = paths.begin(); itStr != paths.end(); ++itStr) { 0375 QString dirName = *itStr; 0376 QDir dir(dirName); 0377 dir.setFilter(QDir::Files); 0378 QStringList l; 0379 l << "*.png"; 0380 dir.setNameFilters(l); 0381 QFileInfoList fileInfoList = dir.entryInfoList(); 0382 qCDebug(KTL_LOG) << " list size " << fileInfoList.size(); 0383 for (QFileInfoList::iterator itFile = fileInfoList.begin(); itFile != fileInfoList.end(); ++itFile) { 0384 QFileInfo &fi = *itFile; 0385 0386 QString fullPath = fi.path() + "/" + fi.fileName(); 0387 QPixmap img(fullPath); 0388 if (img.isNull()) { 0389 qCWarning(KTL_LOG) << " img is null " << fullPath; 0390 } 0391 0392 m_pEditor->document()->addResource(QTextDocument::ImageResource, QUrl(fi.fileName()), QVariant(img)); 0393 qCDebug(KTL_LOG) << " added resource: " << fi.fileName() << " to " << fullPath; 0394 } 0395 } 0396 } 0397 // END class RichTextEditor 0398 0399 // BEGIN class RichTextEditorDlg 0400 RichTextEditorDlg::RichTextEditorDlg(QWidget *parent, const QString &caption) 0401 : QDialog(parent) 0402 { 0403 setObjectName("RichTextEditorDlg"); 0404 setModal(true); 0405 setWindowTitle(caption); 0406 0407 QVBoxLayout *mainLayout = new QVBoxLayout; 0408 setLayout(mainLayout); 0409 0410 m_pEditor = new RichTextEditor(this); 0411 mainLayout->addWidget(m_pEditor); 0412 0413 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0414 mainLayout->addWidget(buttonBox); 0415 0416 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); 0417 okButton->setDefault(true); 0418 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0419 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0420 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0421 } 0422 // END class RichTextEditorDlg 0423 0424 #include "moc_richtexteditor.cpp"