File indexing completed on 2024-06-09 04:28:41

0001 /* This file is part of the KDE project
0002  *
0003  * SPDX-FileCopyrightText: 2017 Boudewijn Rempt <boud@valdyas.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "SvgTextEditor.h"
0009 
0010 #include <QAction>
0011 #include <QActionGroup>
0012 #include <QApplication>
0013 #include <QBuffer>
0014 #include <QComboBox>
0015 #include <QDialogButtonBox>
0016 #include <QDoubleSpinBox>
0017 #include <QFontComboBox>
0018 #include <QFontDatabase>
0019 #include <QFormLayout>
0020 #include <QLineEdit>
0021 #include <QListView>
0022 #include <QMenu>
0023 #include <QMessageBox>
0024 #include <QPainter>
0025 #include <QPalette>
0026 #include <QPushButton>
0027 #include <QStandardItem>
0028 #include <QStandardItemModel>
0029 #include <QSvgGenerator>
0030 #include <QTabWidget>
0031 #include <QTextEdit>
0032 #include <QUrl>
0033 #include <QVBoxLayout>
0034 #include <QWidgetAction>
0035 #include <QDesktopWidget>
0036 #include <QScreen>
0037 
0038 #include <kcharselect.h>
0039 #include <klocalizedstring.h>
0040 #include <ksharedconfig.h>
0041 #include <kconfiggroup.h>
0042 #include <kactioncollection.h>
0043 #include <kxmlguifactory.h>
0044 #include <ktoolbar.h>
0045 #include <ktoggleaction.h>
0046 #include <kguiitem.h>
0047 #include <kstandardguiitem.h>
0048 
0049 #include <KoDialog.h>
0050 #include <KoResourcePaths.h>
0051 #include <KoSvgTextShape.h>
0052 #include <KoSvgTextShapeMarkupConverter.h>
0053 #include <KoColorSpaceRegistry.h>
0054 #include <KoColorPopupAction.h>
0055 #include <svg/SvgUtil.h>
0056 
0057 #include <KisSpinBoxI18nHelper.h>
0058 #include <KisScreenColorSampler.h>
0059 #include <kis_icon.h>
0060 #include <kis_config.h>
0061 #include <kis_file_name_requester.h>
0062 #include <kis_action_registry.h>
0063 
0064 #include "kis_font_family_combo_box.h"
0065 #include "FontSizeAction.h"
0066 #include "kis_signals_blocker.h"
0067 
0068 using WrappingMode = KoSvgTextShapeMarkupConverter::WrappingMode;
0069 
0070 
0071 class SvgTextEditor::Private
0072 {
0073 public:
0074 
0075     Private()
0076     {
0077         // some platform plugins may have set a pixelsize which could create a
0078         // conflicting property in QTextCharFormat
0079         font.setPointSize(fontSize);
0080     }
0081 
0082     QActionGroup *textWrappingActionGroup {};
0083 
0084     // collection of last-used properties
0085     QColor fontColor {Qt::black};
0086     //QColor backgroundColor {Qt::transparent};
0087     qreal fontSize {10.0};
0088     QFont font;
0089     bool kerning {true};
0090 
0091     qreal letterSpacing {0.0};
0092 
0093     bool bold {false};
0094     bool italic {false};
0095     bool underline {false};
0096 
0097     bool strikeThrough {false};
0098     bool superscript {false};
0099     bool subscript {false};
0100 
0101     // unsupported properties:
0102     // backgroundColor - because there is no button for that
0103     // horizontal alignment - it seems to work without saving
0104     // line height - it seems to work without saving
0105 
0106     void saveFromWidgets(KisKActionCollection* actions)
0107     {
0108 
0109         FontSizeAction *fontSizeAction = qobject_cast<FontSizeAction*>(actions->action("svg_font_size"));
0110         fontSize = fontSizeAction->fontSize();
0111 
0112         KisFontComboBoxes* fontComboBox2 = qobject_cast<KisFontComboBoxes*>(qobject_cast<QWidgetAction*>(actions->action("svg_font"))->defaultWidget());
0113         font = fontComboBox2->currentFont(fontSize);
0114 
0115         KoColorPopupAction *fontColorAction = qobject_cast<KoColorPopupAction*>(actions->action("svg_format_textcolor"));
0116         fontColor = fontColorAction->currentColor();
0117 
0118         QWidgetAction *letterSpacingAction = qobject_cast<QWidgetAction*>(actions->action("svg_letter_spacing"));
0119         letterSpacing = qobject_cast<QDoubleSpinBox*>(letterSpacingAction->defaultWidget())->value();
0120 
0121         saveBoolActionFromWidget(actions, "svg_weight_bold", bold);
0122         saveBoolActionFromWidget(actions, "svg_format_italic", italic);
0123         saveBoolActionFromWidget(actions, "svg_format_underline", underline);
0124 
0125         saveBoolActionFromWidget(actions, "svg_format_strike_through", strikeThrough);
0126         saveBoolActionFromWidget(actions, "svg_format_superscript", superscript);
0127         saveBoolActionFromWidget(actions, "svg_format_subscript", subscript);
0128 
0129         saveBoolActionFromWidget(actions, "svg_font_kerning", kerning);
0130     }
0131 
0132     void setSavedToWidgets(KisKActionCollection* actions)
0133     {
0134 
0135         FontSizeAction *fontSizeAction = qobject_cast<FontSizeAction*>(actions->action("svg_font_size"));
0136         fontSizeAction->setFontSize(fontSize);
0137 
0138         KisFontComboBoxes* fontComboBox2 = qobject_cast<KisFontComboBoxes*>(qobject_cast<QWidgetAction*>(actions->action("svg_font"))->defaultWidget());
0139         fontComboBox2->setCurrentFont(font);
0140 
0141         KoColorPopupAction *fontColorAction = qobject_cast<KoColorPopupAction*>(actions->action("svg_format_textcolor"));
0142         fontColorAction->setCurrentColor(fontColor);
0143 
0144         QWidgetAction *letterSpacingAction = qobject_cast<QWidgetAction*>(actions->action("svg_letter_spacing"));
0145         qobject_cast<QDoubleSpinBox*>(letterSpacingAction->defaultWidget())->setValue(letterSpacing);
0146 
0147         setBoolActionToWidget(actions, "svg_weight_bold", bold);
0148         setBoolActionToWidget(actions, "svg_format_italic", italic);
0149 
0150         setSavedLineDecorationToWidgets(actions);
0151 
0152         setBoolActionToWidget(actions, "svg_format_superscript", superscript);
0153         setBoolActionToWidget(actions, "svg_format_subscript", subscript);
0154 
0155         setBoolActionToWidget(actions, "svg_font_kerning", kerning);
0156     }
0157 
0158     void setSavedToFormat(QTextCharFormat &format)
0159     {
0160 
0161         format.setFont(font);
0162         format.setFontPointSize(fontSize);
0163         format.setForeground(fontColor);
0164 
0165         format.setFontLetterSpacingType(QFont::AbsoluteSpacing);
0166         format.setFontLetterSpacing(letterSpacing);
0167 
0168         format.setFontUnderline(underline);
0169         format.setFontStrikeOut(strikeThrough);
0170         format.setFontOverline(false);
0171 
0172         if (subscript) {
0173             format.setVerticalAlignment(QTextCharFormat::AlignSubScript);
0174         } else if (superscript) {
0175             format.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
0176         } else {
0177             format.setVerticalAlignment(QTextCharFormat::AlignMiddle);
0178         }
0179 
0180         if (bold) {
0181             format.setFontWeight(QFont::Bold);
0182         }
0183 
0184         format.setFontItalic(italic);
0185         format.setFontKerning(kerning);
0186     }
0187 
0188     void saveFontLineDecoration(KoSvgText::TextDecoration decoration)
0189     {
0190         // Krita for now cannot handle both at the same time; and there is no way to set overline
0191         // FIXME: Krita should support all three at the same time
0192         // (It does support it in SVG)
0193         switch (decoration) {
0194         case KoSvgText::DecorationUnderline:
0195             underline = true;
0196             strikeThrough = false;
0197             break;
0198         case KoSvgText::DecorationLineThrough:
0199             underline = false;
0200             strikeThrough = true;
0201             break;
0202         case KoSvgText::DecorationOverline:
0203             Q_FALLTHROUGH();
0204         case KoSvgText::DecorationNone:
0205             Q_FALLTHROUGH();
0206          default:
0207             underline = false;
0208             strikeThrough = false;
0209             break;
0210         }
0211     }
0212 
0213 
0214     void setSavedLineDecorationToWidgets(KisKActionCollection* actions)
0215     {
0216         setBoolActionToWidget(actions, "svg_format_underline", underline);
0217         setBoolActionToWidget(actions, "svg_format_strike_through", strikeThrough);
0218     }
0219 
0220 private:
0221 
0222     void saveBoolActionFromWidget(KisKActionCollection* actions, QString actionName, bool &variable)
0223     {
0224         QAction *boolAction = actions->action(actionName);
0225         KIS_ASSERT_RECOVER_RETURN(boolAction);
0226         variable = boolAction->isChecked();
0227     }
0228 
0229     void setBoolActionToWidget(KisKActionCollection* actions, QString actionName, bool variable)
0230     {
0231         QAction *boolAction = actions->action(actionName);
0232         KIS_ASSERT_RECOVER_RETURN(boolAction);
0233         boolAction->setChecked(variable);
0234     }
0235 
0236 };
0237 
0238 
0239 SvgTextEditor::SvgTextEditor(QWidget *parent, Qt::WindowFlags flags)
0240     : KXmlGuiWindow(parent, flags)
0241     , m_page(new QWidget(this))
0242 #ifndef Q_OS_WIN
0243     , m_charSelectDialog(new KoDialog(this))
0244 #endif
0245     , d(new Private())
0246 {
0247     m_textEditorWidget.setupUi(m_page);
0248     setCentralWidget(m_page);
0249 
0250 #ifndef Q_OS_WIN
0251     KCharSelect *charSelector = new KCharSelect(m_charSelectDialog, 0, KCharSelect::AllGuiElements);
0252     m_charSelectDialog->setMainWidget(charSelector);
0253     connect(charSelector, SIGNAL(currentCharChanged(QChar)), SLOT(insertCharacter(QChar)));
0254     m_charSelectDialog->hide();
0255     m_charSelectDialog->setButtons(KoDialog::Close);
0256 #endif
0257     KGuiItem::assign(m_textEditorWidget.buttons->button(QDialogButtonBox::Save), KStandardGuiItem::save());
0258     KGuiItem::assign(m_textEditorWidget.buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
0259     connect(m_textEditorWidget.buttons, SIGNAL(accepted()), this, SLOT(save()));
0260     connect(m_textEditorWidget.buttons, SIGNAL(rejected()), this, SLOT(slotCloseEditor()));
0261     connect(m_textEditorWidget.buttons, SIGNAL(clicked(QAbstractButton*)), this, SLOT(dialogButtonClicked(QAbstractButton*)));
0262 
0263     KConfigGroup cg(KSharedConfig::openConfig(), "SvgTextTool");
0264     actionCollection()->setConfigGroup("SvgTextTool");
0265     actionCollection()->setComponentName("svgtexttool");
0266     actionCollection()->setComponentDisplayName(i18n("Text Tool"));
0267 
0268     if (cg.hasKey("WindowState")) {
0269         QByteArray state = cg.readEntry("State", QByteArray());
0270         // One day will need to load the version number, but for now, assume 0
0271         restoreState(QByteArray::fromBase64(state));
0272     }
0273     if (cg.hasKey("Geometry")) {
0274         QByteArray ba = cg.readEntry("Geometry", QByteArray());
0275         restoreGeometry(QByteArray::fromBase64(ba));
0276     }
0277     else {
0278         const int scnum = QApplication::desktop()->screenNumber(QApplication::activeWindow());
0279         QRect desk = QGuiApplication::screens().at(scnum)->availableGeometry();
0280 
0281         quint32 x = desk.x();
0282         quint32 y = desk.y();
0283         quint32 w = 0;
0284         quint32 h = 0;
0285         const int deskWidth = desk.width();
0286         w = (deskWidth / 3) * 2;
0287         h = (desk.height() / 3) * 2;
0288         x += (desk.width() - w) / 2;
0289         y += (desk.height() - h) / 2;
0290 
0291         move(x,y);
0292         setGeometry(geometry().x(), geometry().y(), w, h);
0293 
0294     }
0295 
0296     setAcceptDrops(true);
0297     //setStandardToolBarMenuEnabled(true);
0298 #ifdef Q_OS_MACOS
0299     setUnifiedTitleAndToolBarOnMac(true);
0300 #endif
0301     setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
0302 
0303     m_syntaxHighlighter = new BasicXMLSyntaxHighlighter(m_textEditorWidget.svgTextEdit);
0304     m_textEditorWidget.svgTextEdit->setFont(QFontDatabase().systemFont(QFontDatabase::FixedFont));
0305 
0306     createActions();
0307     // If we have customized the toolbars, load that first
0308     setLocalXMLFile(KoResourcePaths::locateLocal("data", "svgtexttool.xmlgui"));
0309     setXMLFile(":/kxmlgui5/svgtexttool.xmlgui");
0310 
0311     guiFactory()->addClient(this);
0312 
0313     // Create and plug toolbar list for Settings menu
0314     QList<QAction *> toolbarList;
0315     Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) {
0316         KisToolBar * toolBar = ::qobject_cast<KisToolBar *>(it);
0317         if (toolBar) {
0318             toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
0319             KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this);
0320             actionCollection()->addAction(toolBar->objectName().toUtf8(), act);
0321             act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle())));
0322             connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool)));
0323             act->setChecked(!toolBar->isHidden());
0324             toolbarList.append(act);
0325         }
0326     }
0327 
0328     {
0329         // Make the text color and text wrapping actions a simple drop-down
0330         // button and not the split button/drop-down combo.
0331         QAction *const color = actionCollection()->action("svg_format_textcolor");
0332         Q_FOREACH(KisToolBar *const toolBar, toolBars()) {
0333             if (QToolButton *const btn = qobject_cast<QToolButton *>(toolBar->widgetForAction(color))) {
0334                 btn->setPopupMode(QToolButton::InstantPopup);
0335             }
0336             Q_FOREACH(QAction *const action, toolBar->actions()) {
0337                 if (action->objectName() == QLatin1String("svg_text_wrapping")) {
0338                     if (QToolButton *const btn = qobject_cast<QToolButton *>(toolBar->widgetForAction(action))) {
0339                         btn->setPopupMode(QToolButton::InstantPopup);
0340                     }
0341                 }
0342             }
0343         }
0344     }
0345 
0346     plugActionList("toolbarlist", toolbarList);
0347     connect(m_textEditorWidget.textTab, SIGNAL(currentChanged(int)), this, SLOT(switchTextEditorTab()));
0348     switchTextEditorTab();
0349 
0350     m_textEditorWidget.richTextEdit->document()->setDefaultStyleSheet("p {margin:0px;}");
0351     m_textEditorWidget.richTextEdit->installEventFilter(this);
0352 
0353     applySettings();
0354 
0355 }
0356 
0357 SvgTextEditor::~SvgTextEditor()
0358 {
0359     KConfigGroup g(KSharedConfig::openConfig(), "SvgTextTool");
0360     QByteArray ba = saveState();
0361     g.writeEntry("windowState", ba.toBase64());
0362     ba = saveGeometry();
0363     g.writeEntry("Geometry", ba.toBase64());
0364 }
0365 
0366 
0367 void SvgTextEditor::setInitialShape(KoSvgTextShape *shape)
0368 {
0369     m_shape = shape;
0370     if (m_shape) {
0371         KoSvgTextShapeMarkupConverter converter(m_shape);
0372 
0373         QString svg;
0374         QString styles;
0375         QTextDocument *doc = m_textEditorWidget.richTextEdit->document();
0376 
0377         if (converter.convertToSvg(&svg, &styles)) {
0378             m_textEditorWidget.svgTextEdit->setPlainText(svg);
0379             m_textEditorWidget.svgStylesEdit->setPlainText(styles);
0380             m_textEditorWidget.svgTextEdit->document()->setModified(false);
0381 
0382             /// Todo: remove this bool when removing rich text editor.
0383             bool richtextPreferred = false;
0384             if (richtextPreferred &&
0385                 converter.convertSvgToDocument(svg, doc)) {
0386 
0387                 m_textEditorWidget.richTextEdit->setDocument(doc);
0388                 KisSignalsBlocker b(m_textEditorWidget.textTab);
0389                 m_textEditorWidget.textTab->setCurrentIndex(Editor::Richtext);
0390                 doc->clearUndoRedoStacks();
0391                 switchTextEditorTab(false);
0392             } else {
0393                 KisSignalsBlocker b(m_textEditorWidget.textTab);
0394                 m_textEditorWidget.textTab->setCurrentIndex(Editor::SVGsource);
0395                 switchTextEditorTab(false);
0396             }
0397         }
0398         else {
0399             QMessageBox::warning(this, i18n("Conversion failed"), "Could not get svg text from the shape:\n" + converter.errors().join('\n') + "\n" + converter.warnings().join('\n'));
0400         }
0401     }
0402     KisFontComboBoxes* fontComboBox = qobject_cast<KisFontComboBoxes*>(qobject_cast<QWidgetAction*>(actionCollection()->action("svg_font"))->defaultWidget());
0403     fontComboBox->setInitialized();
0404 
0405     KConfigGroup cfg(KSharedConfig::openConfig(), "SvgTextTool");
0406 
0407     d->saveFromWidgets(actionCollection());
0408 
0409     QTextCursor cursor = m_textEditorWidget.richTextEdit->textCursor();
0410     QTextCharFormat format = cursor.blockCharFormat();
0411 
0412     d->setSavedToFormat(format);
0413 
0414     KisSignalsBlocker b(m_textEditorWidget.richTextEdit);
0415     cursor.setBlockCharFormat(format);
0416 
0417     m_textEditorWidget.richTextEdit->document()->setModified(false);
0418     checkDocumentFormat();
0419 }
0420 
0421 void SvgTextEditor::save()
0422 {
0423     if (m_shape) {
0424         if (isRichTextEditorTabActive()) {
0425             QString svg;
0426             QString styles = m_textEditorWidget.svgStylesEdit->document()->toPlainText();
0427             KoSvgTextShapeMarkupConverter converter(m_shape);
0428 
0429             if (!converter.convertDocumentToSvg(m_textEditorWidget.richTextEdit->document(), &svg)) {
0430                     qWarning()<<"new converter doesn't work!";
0431             }
0432             m_textEditorWidget.richTextEdit->document()->setModified(false);
0433             emit textUpdated(m_shape, svg, styles);
0434         } else if (isSvgSourceEditorTabActive()) {
0435             emit textUpdated(m_shape, m_textEditorWidget.svgTextEdit->document()->toPlainText(), m_textEditorWidget.svgStylesEdit->document()->toPlainText());
0436             m_textEditorWidget.svgTextEdit->document()->setModified(false);
0437         }
0438     }
0439 
0440 }
0441 
0442 void SvgTextEditor::switchTextEditorTab(bool convertData)
0443 {
0444     KoSvgTextShape shape;
0445     KoSvgTextShapeMarkupConverter converter(&shape);
0446 
0447     bool wasModified = false;
0448     if (m_currentEditor) {
0449         disconnect(m_currentEditor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setModified(bool)));
0450         wasModified = m_currentEditor->document()->isModified();
0451     }
0452 
0453     // do not switch to the same tab again, otherwise we're losing current changes
0454     if (m_currentEditor != m_textEditorWidget.richTextEdit && isRichTextEditorTabActive()) {
0455         //first, make buttons checkable
0456         enableRichTextActions(true);
0457         enableSvgTextActions(false);
0458 
0459         //then connect the cursor change to the checkformat();
0460         connect(m_textEditorWidget.richTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(checkFormat()));
0461         connect(m_textEditorWidget.richTextEdit, SIGNAL(textChanged()), this, SLOT(slotFixUpEmptyTextBlock()));
0462         connect(m_textEditorWidget.richTextEdit, SIGNAL(textChanged()), this, SLOT(checkDocumentFormat()));
0463         checkFormat();
0464 
0465         if (m_shape && convertData) {
0466             QTextDocument *doc = m_textEditorWidget.richTextEdit->document();
0467             if (!converter.convertSvgToDocument(m_textEditorWidget.svgTextEdit->document()->toPlainText(), doc)) {
0468                 qWarning()<<"new converter svgToDoc doesn't work!";
0469             }
0470             m_textEditorWidget.richTextEdit->setDocument(doc);
0471             doc->clearUndoRedoStacks();
0472         }
0473         m_currentEditor = m_textEditorWidget.richTextEdit;
0474     } else if (m_currentEditor != m_textEditorWidget.svgTextEdit && isSvgSourceEditorTabActive()) {
0475         //first, make buttons uncheckable
0476         enableRichTextActions(false);
0477         enableSvgTextActions(true);
0478         disconnect(m_textEditorWidget.richTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(checkFormat()));
0479 
0480         // Convert the rich text to svg and styles strings
0481         if (m_shape && convertData) {
0482             QString svg;
0483             if (!converter.convertDocumentToSvg(m_textEditorWidget.richTextEdit->document(), &svg)) {
0484                     qWarning()<<"new converter docToSVG doesn't work!";
0485             }
0486             m_textEditorWidget.svgTextEdit->setPlainText(svg);
0487         }
0488         m_currentEditor = m_textEditorWidget.svgTextEdit;
0489     }
0490 
0491     m_currentEditor->document()->setModified(wasModified);
0492     connect(m_currentEditor->document(), SIGNAL(modificationChanged(bool)), SLOT(setModified(bool)));
0493 }
0494 
0495 void SvgTextEditor::checkFormat()
0496 {
0497     QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat();
0498     QTextBlockFormat blockFormat = m_textEditorWidget.richTextEdit->textCursor().blockFormat();
0499 
0500     // checkboxes do not emit signals on manual switching, so we
0501     // can avoid blocking them
0502 
0503     if (format.fontWeight() > QFont::Normal) {
0504         actionCollection()->action("svg_weight_bold")->setChecked(true);
0505     } else {
0506         actionCollection()->action("svg_weight_bold")->setChecked(false);
0507     }
0508     actionCollection()->action("svg_format_italic")->setChecked(format.fontItalic());
0509     actionCollection()->action("svg_format_underline")->setChecked(format.fontUnderline());
0510     actionCollection()->action("svg_format_strike_through")->setChecked(format.fontStrikeOut());
0511     actionCollection()->action("svg_font_kerning")->setChecked(format.fontKerning());
0512 
0513     {
0514         FontSizeAction *fontSizeAction = qobject_cast<FontSizeAction*>(actionCollection()->action("svg_font_size"));
0515         KisSignalsBlocker b(fontSizeAction);
0516         qreal pointSize = format.fontPointSize();
0517         if (pointSize <= 0.0) {
0518             pointSize = format.font().pointSizeF();
0519         }
0520         fontSizeAction->setFontSize(pointSize);
0521     }
0522 
0523 
0524     {
0525         KoColor fg(format.foreground().color(), KoColorSpaceRegistry::instance()->rgb8());
0526         KoColorPopupAction *fgColorPopup = qobject_cast<KoColorPopupAction*>(actionCollection()->action("svg_format_textcolor"));
0527         KisSignalsBlocker b(fgColorPopup);
0528         fgColorPopup->setCurrentColor(fg);
0529     }
0530 
0531     {
0532         KoColor bg(format.foreground().color(), KoColorSpaceRegistry::instance()->rgb8());
0533         KoColorPopupAction *bgColorPopup = qobject_cast<KoColorPopupAction*>(actionCollection()->action("svg_background_color"));
0534         KisSignalsBlocker b(bgColorPopup);
0535         bgColorPopup->setCurrentColor(bg);
0536     }
0537 
0538     {
0539         KisFontComboBoxes* fontComboBox = qobject_cast<KisFontComboBoxes*>(qobject_cast<QWidgetAction*>(actionCollection()->action("svg_font"))->defaultWidget());
0540         KisSignalsBlocker b(fontComboBox);
0541         fontComboBox->setCurrentFont(format.font());
0542     }
0543 
0544     {
0545         QDoubleSpinBox *spnLineHeight = qobject_cast<QWidgetAction*>(actionCollection()->action("svg_line_height"))->defaultWidget()->findChild<QDoubleSpinBox *>();
0546         KisSignalsBlocker b(spnLineHeight);
0547 
0548         if (blockFormat.lineHeightType() == QTextBlockFormat::SingleHeight) {
0549             spnLineHeight->setValue(-1.0);
0550             spnLineHeight->setSingleStep(101.0);
0551         } else if(blockFormat.lineHeightType() == QTextBlockFormat::ProportionalHeight) {
0552             spnLineHeight->setValue(double(blockFormat.lineHeight()));
0553             spnLineHeight->setSingleStep(10.0);
0554         }
0555     }
0556 
0557     {
0558         QDoubleSpinBox* spnLetterSpacing = qobject_cast<QDoubleSpinBox*>(qobject_cast<QWidgetAction*>(actionCollection()->action("svg_letter_spacing"))->defaultWidget());
0559         KisSignalsBlocker b(spnLetterSpacing);
0560         spnLetterSpacing->setValue(format.fontLetterSpacing());
0561     }
0562 }
0563 
0564 void SvgTextEditor::checkDocumentFormat()
0565 {
0566     QTextFrameFormat f = m_textEditorWidget.richTextEdit->document()->rootFrame()->frameFormat();
0567     WrappingMode wrappingMode = KoSvgTextShapeMarkupConverter::getWrappingMode(f);
0568     switch (wrappingMode) {
0569     case WrappingMode::QtLegacy:
0570     default:
0571         if (wrappingMode != WrappingMode::QtLegacy) {
0572             // For sanity
0573             KoSvgTextShapeMarkupConverter::setWrappingMode(&f, WrappingMode::QtLegacy);
0574             m_textEditorWidget.richTextEdit->document()->rootFrame()->setFrameFormat(f);
0575         }
0576         m_textEditorWidget.richTextEdit->setLineWrapMode(QTextEdit::WidgetWidth);
0577         actionCollection()->action("svg_text_wrapping_legacy")->setChecked(true);
0578         break;
0579     case WrappingMode::WhiteSpacePre:
0580         m_textEditorWidget.richTextEdit->setLineWrapMode(QTextEdit::WidgetWidth);
0581         actionCollection()->action("svg_text_wrapping_css_pre")->setChecked(true);
0582         break;
0583     case WrappingMode::WhiteSpacePreWrap:
0584         const double inlineSize = KoSvgTextShapeMarkupConverter::getInlineSize(f).value_or(100.0);
0585         const int wrapWidth = inlineSize * (96.0 / 72.0) + f.leftMargin() + f.rightMargin();
0586         m_textEditorWidget.richTextEdit->setLineWrapColumnOrWidth(wrapWidth);
0587         m_textEditorWidget.richTextEdit->setLineWrapMode(QTextEdit::FixedPixelWidth);
0588         m_textEditorWidget.richTextEdit->setWordWrapMode(QTextOption::WordWrap);
0589         actionCollection()->action("svg_text_wrapping_css_pre_wrap")->setChecked(true);
0590         break;
0591     }
0592 }
0593 
0594 void SvgTextEditor::slotFixUpEmptyTextBlock()
0595 {
0596     if (m_textEditorWidget.richTextEdit->document()->isEmpty()) {
0597         QTextCursor cursor = m_textEditorWidget.richTextEdit->textCursor();
0598         QTextCharFormat format = cursor.blockCharFormat();
0599 
0600 
0601         KisSignalsBlocker b(m_textEditorWidget.richTextEdit);
0602 
0603         d->setSavedToFormat(format);
0604         d->setSavedToWidgets(actionCollection());
0605 
0606         cursor.setBlockCharFormat(format);
0607     }
0608 }
0609 
0610 void SvgTextEditor::undo()
0611 {
0612     m_currentEditor->undo();
0613 }
0614 
0615 void SvgTextEditor::redo()
0616 {
0617     m_currentEditor->redo();
0618 }
0619 
0620 void SvgTextEditor::cut()
0621 {
0622     m_currentEditor->cut();
0623 }
0624 
0625 void SvgTextEditor::copy()
0626 {
0627     m_currentEditor->copy();
0628 }
0629 
0630 void SvgTextEditor::paste()
0631 {
0632     m_currentEditor->paste();
0633 }
0634 
0635 void SvgTextEditor::selectAll()
0636 {
0637     m_currentEditor->selectAll();
0638 }
0639 
0640 void SvgTextEditor::deselect()
0641 {
0642     QTextCursor cursor(m_currentEditor->textCursor());
0643     cursor.clearSelection();
0644     m_currentEditor->setTextCursor(cursor);
0645 }
0646 
0647 void SvgTextEditor::find()
0648 {
0649     QDialog findDialog;
0650     findDialog.setWindowTitle(i18n("Find Text"));
0651     QFormLayout *layout = new QFormLayout(&findDialog);
0652     QLineEdit *lnSearchKey = new QLineEdit();
0653     layout->addRow(i18n("Find:"), lnSearchKey);
0654     QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0655     layout->addWidget(buttons);
0656 
0657     KGuiItem::assign(buttons->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
0658     KGuiItem::assign(buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
0659 
0660     connect(buttons, SIGNAL(accepted()), &findDialog, SLOT(accept()));
0661     connect(buttons, SIGNAL(rejected()), &findDialog, SLOT(reject()));
0662 
0663     if (findDialog.exec() == QDialog::Accepted) {
0664         m_searchKey = lnSearchKey->text();
0665         m_currentEditor->find(m_searchKey);
0666     }
0667 }
0668 
0669 void SvgTextEditor::findNext()
0670 {
0671     if (!m_currentEditor->find(m_searchKey)) {
0672         QTextCursor cursor(m_currentEditor->textCursor());
0673         cursor.movePosition(QTextCursor::Start);
0674         m_currentEditor->setTextCursor(cursor);
0675         m_currentEditor->find(m_searchKey);
0676     }
0677 }
0678 
0679 void SvgTextEditor::findPrev()
0680 {
0681     if (!m_currentEditor->find(m_searchKey,QTextDocument::FindBackward)) {
0682         QTextCursor cursor(m_currentEditor->textCursor());
0683         cursor.movePosition(QTextCursor::End);
0684         m_currentEditor->setTextCursor(cursor);
0685         m_currentEditor->find(m_searchKey,QTextDocument::FindBackward);
0686     }
0687 }
0688 
0689 void SvgTextEditor::replace()
0690 {
0691     QDialog findDialog;
0692     findDialog.setWindowTitle(i18n("Find and Replace all"));
0693     QFormLayout *layout = new QFormLayout(&findDialog);
0694     QLineEdit *lnSearchKey = new QLineEdit();
0695     QLineEdit *lnReplaceKey = new QLineEdit();
0696     layout->addRow(i18n("Find:"), lnSearchKey);
0697     QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0698     layout->addRow(i18n("Replace:"), lnReplaceKey);
0699     layout->addWidget(buttons);
0700 
0701     KGuiItem::assign(buttons->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
0702     KGuiItem::assign(buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
0703 
0704     connect(buttons, SIGNAL(accepted()), &findDialog, SLOT(accept()));
0705     connect(buttons, SIGNAL(rejected()), &findDialog, SLOT(reject()));
0706 
0707     if (findDialog.exec() == QDialog::Accepted) {
0708         QString search = lnSearchKey->text();
0709         QString replace = lnReplaceKey->text();
0710         QTextCursor cursor(m_currentEditor->textCursor());
0711         cursor.movePosition(QTextCursor::Start);
0712         m_currentEditor->setTextCursor(cursor);
0713         while(m_currentEditor->find(search)) {
0714             m_currentEditor->textCursor().removeSelectedText();
0715             m_currentEditor->textCursor().insertText(replace);
0716         }
0717 
0718     }
0719 }
0720 
0721 
0722 void SvgTextEditor::zoomOut()
0723 {
0724     m_currentEditor->zoomOut();
0725 }
0726 
0727 void SvgTextEditor::zoomIn()
0728 {
0729     m_currentEditor->zoomIn();
0730 }
0731 
0732 #ifndef Q_OS_WIN
0733 void SvgTextEditor::showInsertSpecialCharacterDialog()
0734 {
0735     m_charSelectDialog->setVisible(!m_charSelectDialog->isVisible());
0736 }
0737 
0738 void SvgTextEditor::insertCharacter(const QChar &c)
0739 {
0740     m_currentEditor->textCursor().insertText(QString(c));
0741 }
0742 #endif
0743 
0744 void SvgTextEditor::setTextBold(QFont::Weight weight)
0745 {
0746     if (isRichTextEditorTabActive()) {
0747         QTextCharFormat format;
0748         QTextCursor oldCursor = setTextSelection();
0749         if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight() > QFont::Normal && weight==QFont::Bold) {
0750             format.setFontWeight(QFont::Normal);
0751         } else {
0752             format.setFontWeight(weight);
0753         }
0754         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0755         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
0756     } else if (isSvgSourceEditorTabActive()) {
0757         QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
0758         if (cursor.hasSelection()) {
0759             QString selectionModified = "<tspan style=\"font-weight:700;\">" + cursor.selectedText() + "</tspan>";
0760             cursor.removeSelectedText();
0761             cursor.insertText(selectionModified);
0762         }
0763     }
0764     d->bold = weight == QFont::Bold;
0765 
0766     checkFormat();
0767 }
0768 
0769 void SvgTextEditor::setTextWeightLight()
0770 {
0771     if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight() < QFont::Normal) {
0772         setTextBold(QFont::Normal);
0773     } else {
0774         setTextBold(QFont::Light);
0775     }
0776 }
0777 
0778 void SvgTextEditor::setTextWeightNormal()
0779 {
0780     setTextBold(QFont::Normal);
0781 }
0782 
0783 void SvgTextEditor::setTextWeightDemi()
0784 {
0785     if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight() != QFont::Normal) {
0786         setTextBold(QFont::Normal);
0787     } else {
0788         setTextBold(QFont::DemiBold);
0789     }
0790 }
0791 
0792 void SvgTextEditor::setTextWeightBlack()
0793 {
0794     if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight()>QFont::Normal) {
0795         setTextBold(QFont::Normal);
0796     } else {
0797         setTextBold(QFont::Black);
0798     }
0799 }
0800 
0801 void SvgTextEditor::setTextItalic(QFont::Style style)
0802 {
0803     QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
0804     QString fontStyle = "inherit";
0805 
0806     if (style == QFont::StyleItalic) {
0807         fontStyle = "italic";
0808         d->italic = true;
0809     } else if (style == QFont::StyleOblique) {
0810         fontStyle = "oblique";
0811         d->italic = true;
0812     } else {
0813         d->italic = false;
0814     }
0815 
0816 
0817     if (isRichTextEditorTabActive()) {
0818         QTextCharFormat format;
0819         QTextCursor origCursor = setTextSelection();
0820         format.setFontItalic(!m_textEditorWidget.richTextEdit->textCursor().charFormat().fontItalic());
0821         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0822         m_textEditorWidget.richTextEdit->setTextCursor(origCursor);
0823     } else if (isSvgSourceEditorTabActive()) {
0824         if (cursor.hasSelection()) {
0825             QString selectionModified = "<tspan style=\"font-style:"+fontStyle+";\">" + cursor.selectedText() + "</tspan>";
0826             cursor.removeSelectedText();
0827             cursor.insertText(selectionModified);
0828         }
0829     }
0830 
0831     checkFormat();
0832 }
0833 
0834 void SvgTextEditor::setTextDecoration(KoSvgText::TextDecoration decor)
0835 {
0836     QTextCursor cursor = setTextSelection();
0837     QTextCharFormat currentFormat = m_textEditorWidget.richTextEdit->textCursor().charFormat();
0838     QTextCharFormat format;
0839     QString textDecoration = "inherit";
0840 
0841     if (decor == KoSvgText::DecorationUnderline) {
0842         textDecoration = "underline";
0843         if (currentFormat.fontUnderline()) {
0844             format.setFontUnderline(false);
0845         }
0846         else {
0847             format.setFontUnderline(true);
0848         }
0849         format.setFontOverline(false);
0850         format.setFontStrikeOut(false);
0851     }
0852     else if (decor == KoSvgText::DecorationLineThrough) {
0853         textDecoration = "line-through";
0854         format.setFontUnderline(false);
0855         format.setFontOverline(false);
0856         if (currentFormat.fontStrikeOut()) {
0857             format.setFontStrikeOut(false);
0858         }
0859         else {
0860             format.setFontStrikeOut(true);
0861         }
0862     }
0863     else if (decor == KoSvgText::DecorationOverline) {
0864         textDecoration = "overline";
0865         format.setFontUnderline(false);
0866         if (currentFormat.fontOverline()) {
0867             format.setFontOverline(false);
0868         }
0869         else {
0870             format.setFontOverline(true);
0871         }
0872         format.setFontStrikeOut(false);
0873     }
0874 
0875     if (isRichTextEditorTabActive()) {
0876         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0877     } else if (isSvgSourceEditorTabActive()) {
0878         if (cursor.hasSelection()) {
0879             QString selectionModified = "<tspan style=\"text-decoration:" + textDecoration + ";\">" + cursor.selectedText() + "</tspan>";
0880             cursor.removeSelectedText();
0881             cursor.insertText(selectionModified);
0882         }
0883     }
0884     m_textEditorWidget.richTextEdit->setTextCursor(cursor);
0885 
0886     d->saveFontLineDecoration(decor);
0887     d->setSavedLineDecorationToWidgets(actionCollection());
0888 }
0889 
0890 void SvgTextEditor::setTextUnderline()
0891 {
0892     setTextDecoration(KoSvgText::DecorationUnderline);
0893 }
0894 
0895 void SvgTextEditor::setTextOverline()
0896 {
0897     setTextDecoration(KoSvgText::DecorationOverline);
0898 }
0899 
0900 void SvgTextEditor::setTextStrikethrough()
0901 {
0902     setTextDecoration(KoSvgText::DecorationLineThrough);
0903 }
0904 
0905 void SvgTextEditor::setTextSubscript()
0906 {
0907     QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat();
0908     if (format.verticalAlignment()==QTextCharFormat::AlignSubScript) {
0909         format.setVerticalAlignment(QTextCharFormat::AlignNormal);
0910         d->subscript = false;
0911     } else {
0912         format.setVerticalAlignment(QTextCharFormat::AlignSubScript);
0913         d->subscript = true;
0914         d->superscript = false;
0915     }
0916     m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0917 }
0918 
0919 void SvgTextEditor::setTextSuperScript()
0920 {
0921     QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat();
0922     if (format.verticalAlignment()==QTextCharFormat::AlignSuperScript) {
0923         format.setVerticalAlignment(QTextCharFormat::AlignNormal);
0924         d->superscript = false;
0925     } else {
0926         format.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
0927         d->superscript = true;
0928         d->subscript = false;
0929     }
0930     m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0931 }
0932 
0933 void SvgTextEditor::increaseTextSize()
0934 {
0935     QTextCursor oldCursor = setTextSelection();
0936     QTextCharFormat format;
0937     qreal pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().fontPointSize();
0938     if (pointSize <= 0.0) {
0939         pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pointSizeF();
0940     }
0941     if (pointSize <= 0.0) {
0942         pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pixelSize();
0943     }
0944     format.setFontPointSize(pointSize+1.0);
0945     d->fontSize = format.fontPointSize();
0946     m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0947     m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
0948 }
0949 
0950 void SvgTextEditor::decreaseTextSize()
0951 {
0952     QTextCursor oldCursor = setTextSelection();
0953     QTextCharFormat format;
0954     qreal pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().fontPointSize();
0955     if (pointSize <= 0.0) {
0956         pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pointSizeF();
0957     }
0958     if (pointSize <= 0.0) {
0959         pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pixelSize();
0960     }
0961     if (pointSize <= 1.0) {
0962         return;
0963     }
0964     format.setFontPointSize(qMax(pointSize-1.0, 1.0));
0965     d->fontSize = format.fontPointSize();
0966     m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0967     m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
0968 }
0969 
0970 void SvgTextEditor::setLineHeight(double lineHeightPercentage)
0971 {
0972     QDoubleSpinBox *spnLineHeight = qobject_cast<QWidgetAction*>(actionCollection()->action("svg_line_height"))->defaultWidget()->findChild<QDoubleSpinBox *>();
0973     QTextCursor oldCursor = setTextSelection();
0974     QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat();
0975     if (lineHeightPercentage < 0.0) {
0976         format.setLineHeight(1.0, QTextBlockFormat::SingleHeight);
0977         spnLineHeight->setSingleStep(101.0);
0978     } else {
0979         format.setLineHeight(lineHeightPercentage, QTextBlockFormat::ProportionalHeight);
0980         spnLineHeight->setSingleStep(10.0);
0981     }
0982     m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format);
0983     m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
0984 }
0985 
0986 void SvgTextEditor::setLetterSpacing(double letterSpacing)
0987 {
0988     QTextCursor cursor = setTextSelection();
0989     if (isRichTextEditorTabActive()) {
0990         QTextCharFormat format;
0991         format.setFontLetterSpacingType(QFont::AbsoluteSpacing);
0992         format.setFontLetterSpacing(letterSpacing);
0993         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
0994         m_textEditorWidget.richTextEdit->setTextCursor(cursor);
0995     } else if (isSvgSourceEditorTabActive()) {
0996         if (cursor.hasSelection()) {
0997             QString selectionModified = "<tspan style=\"letter-spacing:" + QString::number(letterSpacing) + "\">" + cursor.selectedText() + "</tspan>";
0998             cursor.removeSelectedText();
0999             cursor.insertText(selectionModified);
1000         }
1001     }
1002     d->letterSpacing = letterSpacing;
1003 }
1004 
1005 void SvgTextEditor::alignLeft()
1006 {
1007     QTextBlockFormat format;
1008     format.setAlignment(Qt::AlignLeft);
1009     if (KoSvgTextShapeMarkupConverter::getWrappingMode(
1010             m_textEditorWidget.richTextEdit->document()->rootFrame()->frameFormat())
1011         == WrappingMode::WhiteSpacePreWrap) {
1012         QTextCursor cursor(m_textEditorWidget.richTextEdit->document());
1013         cursor.select(QTextCursor::Document);
1014         cursor.mergeBlockFormat(format);
1015     } else {
1016         QTextCursor oldCursor = setTextSelection();
1017         m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format);
1018         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1019     }
1020 }
1021 
1022 void SvgTextEditor::alignRight()
1023 {
1024     QTextBlockFormat format;
1025     format.setAlignment(Qt::AlignRight);
1026     if (KoSvgTextShapeMarkupConverter::getWrappingMode(
1027             m_textEditorWidget.richTextEdit->document()->rootFrame()->frameFormat())
1028         == WrappingMode::WhiteSpacePreWrap) {
1029         QTextCursor cursor(m_textEditorWidget.richTextEdit->document());
1030         cursor.select(QTextCursor::Document);
1031         cursor.mergeBlockFormat(format);
1032     } else {
1033         QTextCursor oldCursor = setTextSelection();
1034         m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format);
1035         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1036     }
1037 }
1038 
1039 void SvgTextEditor::alignCenter()
1040 {
1041     QTextBlockFormat format;
1042     format.setAlignment(Qt::AlignCenter);
1043     if (KoSvgTextShapeMarkupConverter::getWrappingMode(
1044             m_textEditorWidget.richTextEdit->document()->rootFrame()->frameFormat())
1045         == WrappingMode::WhiteSpacePreWrap) {
1046         QTextCursor cursor(m_textEditorWidget.richTextEdit->document());
1047         cursor.select(QTextCursor::Document);
1048         cursor.mergeBlockFormat(format);
1049     } else {
1050         QTextCursor oldCursor = setTextSelection();
1051         m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format);
1052         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1053     }
1054 }
1055 
1056 void SvgTextEditor::alignJustified()
1057 {
1058     QTextCursor oldCursor = setTextSelection();
1059     QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat();
1060     format.setAlignment(Qt::AlignJustify);
1061     m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format);
1062     m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1063 }
1064 
1065 void SvgTextEditor::setSettings()
1066 {
1067     KoDialog settingsDialog(this);
1068     Ui_WdgSvgTextSettings textSettings;
1069     QWidget *settingsPage = new QWidget(&settingsDialog);
1070     settingsDialog.setMainWidget(settingsPage);
1071     textSettings.setupUi(settingsPage);
1072 
1073     // get the settings and initialize the dialog
1074     KConfigGroup cfg(KSharedConfig::openConfig(), "SvgTextTool");
1075 
1076     QStringList selectedWritingSystems = cfg.readEntry("selectedWritingSystems", "").split(",");
1077 
1078     QList<QFontDatabase::WritingSystem> scripts = QFontDatabase().writingSystems();
1079     QStandardItemModel *writingSystemsModel = new QStandardItemModel(&settingsDialog);
1080     for (int s = 0; s < scripts.size(); s ++) {
1081         QString writingSystem = QFontDatabase().writingSystemName(scripts.at(s));
1082         QStandardItem *script = new QStandardItem(writingSystem);
1083         script->setCheckable(true);
1084         script->setCheckState(selectedWritingSystems.contains(QString::number(scripts.at(s))) ? Qt::Checked : Qt::Unchecked);
1085         script->setData((int)scripts.at(s));
1086         writingSystemsModel->appendRow(script);
1087     }
1088     textSettings.lwScripts->setModel(writingSystemsModel);
1089 
1090     QColor background = cfg.readEntry("colorEditorBackground", qApp->palette().window().color());
1091     textSettings.colorEditorBackground->setColor(background);
1092     textSettings.colorEditorForeground->setColor(cfg.readEntry("colorEditorForeground", qApp->palette().text().color()));
1093 
1094     textSettings.colorKeyword->setColor(cfg.readEntry("colorKeyword", QColor(background.value() < 100 ? Qt::cyan : Qt::blue)));
1095     textSettings.chkBoldKeyword->setChecked(cfg.readEntry("BoldKeyword", true));
1096     textSettings.chkItalicKeyword->setChecked(cfg.readEntry("ItalicKeyword", false));
1097 
1098     textSettings.colorElement->setColor(cfg.readEntry("colorElement", QColor(background.value() < 100 ? Qt::magenta : Qt::darkMagenta)));
1099     textSettings.chkBoldElement->setChecked(cfg.readEntry("BoldElement", true));
1100     textSettings.chkItalicElement->setChecked(cfg.readEntry("ItalicElement", false));
1101 
1102     textSettings.colorAttribute->setColor(cfg.readEntry("colorAttribute", QColor(background.value() < 100 ? Qt::green : Qt::darkGreen)));
1103     textSettings.chkBoldAttribute->setChecked(cfg.readEntry("BoldAttribute", true));
1104     textSettings.chkItalicAttribute->setChecked(cfg.readEntry("ItalicAttribute", true));
1105 
1106     textSettings.colorValue->setColor(cfg.readEntry("colorValue", QColor(background.value() < 100 ? Qt::red: Qt::darkRed)));
1107     textSettings.chkBoldValue->setChecked(cfg.readEntry("BoldValue", true));
1108     textSettings.chkItalicValue->setChecked(cfg.readEntry("ItalicValue", false));
1109 
1110     textSettings.colorComment->setColor(cfg.readEntry("colorComment", QColor(background.value() < 100 ? Qt::lightGray : Qt::gray)));
1111     textSettings.chkBoldComment->setChecked(cfg.readEntry("BoldComment", false));
1112     textSettings.chkItalicComment->setChecked(cfg.readEntry("ItalicComment", false));
1113 
1114     settingsDialog.setButtons(KoDialog::Ok | KoDialog::Cancel);
1115     if (settingsDialog.exec() == QDialog::Accepted) {
1116         // save  and set the settings
1117         QStringList writingSystems;
1118         for (int i = 0; i < writingSystemsModel->rowCount(); i++) {
1119             QStandardItem *item = writingSystemsModel->item(i);
1120             if (item->checkState() == Qt::Checked) {
1121                 writingSystems.append(QString::number(item->data().toInt()));
1122             }
1123         }
1124         cfg.writeEntry("selectedWritingSystems", writingSystems.join(','));
1125 
1126         cfg.writeEntry("colorEditorBackground", textSettings.colorEditorBackground->color());
1127         cfg.writeEntry("colorEditorForeground", textSettings.colorEditorForeground->color());
1128 
1129         cfg.writeEntry("colorKeyword", textSettings.colorKeyword->color());
1130         cfg.writeEntry("BoldKeyword", textSettings.chkBoldKeyword->isChecked());
1131         cfg.writeEntry("ItalicKeyWord", textSettings.chkItalicKeyword->isChecked());
1132 
1133         cfg.writeEntry("colorElement", textSettings.colorElement->color());
1134         cfg.writeEntry("BoldElement", textSettings.chkBoldElement->isChecked());
1135         cfg.writeEntry("ItalicElement", textSettings.chkItalicElement->isChecked());
1136 
1137         cfg.writeEntry("colorAttribute", textSettings.colorAttribute->color());
1138         cfg.writeEntry("BoldAttribute", textSettings.chkBoldAttribute->isChecked());
1139         cfg.writeEntry("ItalicAttribute", textSettings.chkItalicAttribute->isChecked());
1140 
1141         cfg.writeEntry("colorValue", textSettings.colorValue->color());
1142         cfg.writeEntry("BoldValue", textSettings.chkBoldValue->isChecked());
1143         cfg.writeEntry("ItalicValue", textSettings.chkItalicValue->isChecked());
1144 
1145         cfg.writeEntry("colorComment", textSettings.colorComment->color());
1146         cfg.writeEntry("BoldComment", textSettings.chkBoldComment->isChecked());
1147         cfg.writeEntry("ItalicComment", textSettings.chkItalicComment->isChecked());
1148 
1149         applySettings();
1150     }
1151 }
1152 
1153 void SvgTextEditor::slotToolbarToggled(bool)
1154 {
1155 }
1156 
1157 void SvgTextEditor::setFontColor(const KoColor &c)
1158 {
1159     QColor color = c.toQColor();
1160     if (isRichTextEditorTabActive()) {
1161         QTextCursor oldCursor = setTextSelection();
1162         QTextCharFormat format;
1163         format.setForeground(QBrush(color));
1164         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
1165         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1166     } else if (isSvgSourceEditorTabActive()) {
1167         QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
1168         if (cursor.hasSelection()) {
1169             QString selectionModified = "<tspan fill=\""+color.name()+"\">" + cursor.selectedText() + "</tspan>";
1170             cursor.removeSelectedText();
1171             cursor.insertText(selectionModified);
1172         }
1173     }
1174     // save last used color to be used when the editor is cleared
1175     d->fontColor = color;
1176 }
1177 
1178 void SvgTextEditor::setBackgroundColor(const KoColor &c)
1179 {
1180     QColor color = c.toQColor();
1181     QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
1182     if (cursor.hasSelection()) {
1183         QString selectionModified = "<tspan stroke=\""+color.name()+"\">" + cursor.selectedText() + "</tspan>";
1184         cursor.removeSelectedText();
1185         cursor.insertText(selectionModified);
1186     }
1187 }
1188 
1189 void SvgTextEditor::setModified(bool modified)
1190 {
1191     if (modified) {
1192         m_textEditorWidget.buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Discard);
1193         KGuiItem::assign(m_textEditorWidget.buttons->button(QDialogButtonBox::Save), KStandardGuiItem::save());
1194         KGuiItem::assign(m_textEditorWidget.buttons->button(QDialogButtonBox::Discard), KStandardGuiItem::discard());
1195     }
1196     else {
1197         m_textEditorWidget.buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close);
1198         KGuiItem::assign(m_textEditorWidget.buttons->button(QDialogButtonBox::Save), KStandardGuiItem::save());
1199         KGuiItem::assign(m_textEditorWidget.buttons->button(QDialogButtonBox::Close), KStandardGuiItem::close());
1200     }
1201 }
1202 
1203 void SvgTextEditor::dialogButtonClicked(QAbstractButton *button)
1204 {
1205     if (m_textEditorWidget.buttons->standardButton(button) == QDialogButtonBox::Discard) {
1206         if (QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("You have modified the text. Discard changes?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
1207             close();
1208         }
1209     }
1210 }
1211 
1212 void SvgTextEditor::setFont(const QString &fontName)
1213 {
1214     QFont font;
1215     font.fromString(fontName);
1216     QTextCharFormat curFormat = m_textEditorWidget.richTextEdit->textCursor().charFormat();
1217     qreal pointSize = curFormat.fontPointSize();
1218     if (pointSize <= 0.0) {
1219         pointSize = curFormat.font().pointSizeF();
1220     }
1221     font.setPointSize(pointSize);
1222 
1223     QFontDatabase fontDatabase;
1224     const bool italic = fontDatabase.italic(font.family(), font.styleName());
1225     const int fontWeight = fontDatabase.weight(font.family(), font.styleName());
1226     if (isRichTextEditorTabActive()) {
1227         QTextCharFormat format;
1228         format.setFont(font);
1229 
1230         QTextCursor oldCursor = setTextSelection();
1231         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
1232         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1233     } else if (isSvgSourceEditorTabActive()) {
1234         QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
1235         if (cursor.hasSelection()) {
1236             QString selectionModified = "<tspan style=\"font-family:" + font.family() + ";" +
1237                                         "font-weight:" + QString::number(fontWeight) + ";"
1238                                         "font-style:" + (italic ? "italic" : "normal") + ";\">" +
1239                                         cursor.selectedText() + "</tspan>";
1240             cursor.removeSelectedText();
1241             cursor.insertText(selectionModified);
1242         }
1243     }
1244     // save last used font to be used when the editor is cleared
1245     d->font = font;
1246 
1247     checkFormat();
1248 }
1249 
1250 void SvgTextEditor::setFontSize(qreal fontSize)
1251 {
1252     if (isRichTextEditorTabActive()) {
1253         QTextCursor oldCursor = setTextSelection();
1254         QTextCharFormat format;
1255         format.setFontPointSize(fontSize);
1256         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
1257         m_textEditorWidget.richTextEdit->setTextCursor(oldCursor);
1258     } else if (isSvgSourceEditorTabActive()) {
1259         QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
1260         if (cursor.hasSelection()) {
1261             QString selectionModified = "<tspan style=\"font-size:" + QString::number(fontSize) + ";\">" + cursor.selectedText() + "</tspan>";
1262             cursor.removeSelectedText();
1263             cursor.insertText(selectionModified);
1264         }
1265     }
1266     // set last used font size to be used when the editor is cleared
1267     d->fontSize = fontSize;
1268 }
1269 
1270 void SvgTextEditor::setBaseline(KoSvgText::BaselineShiftMode)
1271 {
1272 
1273     QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
1274     if (cursor.hasSelection()) {
1275         QString selectionModified = "<tspan style=\"font-size:50%;baseline-shift:super;\">" + cursor.selectedText() + "</tspan>";
1276         cursor.removeSelectedText();
1277         cursor.insertText(selectionModified);
1278     }
1279 }
1280 
1281 void SvgTextEditor::setKerning(bool enable)
1282 {
1283     d->kerning = enable;
1284 
1285     if (isRichTextEditorTabActive()) {
1286         QTextCharFormat format;
1287         QTextCursor origCursor = setTextSelection();
1288         format.setFontKerning(enable);
1289         m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format);
1290         m_textEditorWidget.richTextEdit->setTextCursor(origCursor);
1291     } else if (isSvgSourceEditorTabActive()) {
1292         QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor();
1293 
1294         if (cursor.hasSelection()) {
1295             QString value;
1296             if (enable) {
1297                 value = "auto";
1298             } else {
1299                 value = "0";
1300             }
1301             
1302             QString selectionModified = "<tspan style=\"kerning:"+value+";\">" + cursor.selectedText() + "</tspan>";
1303             cursor.removeSelectedText();
1304             cursor.insertText(selectionModified);
1305         }
1306     }
1307 }
1308 
1309 void SvgTextEditor::setWrappingLegacy()
1310 {
1311     QTextFrameFormat f = m_textEditorWidget.richTextEdit->document()->rootFrame()->frameFormat();
1312     KoSvgTextShapeMarkupConverter::setWrappingMode(&f, WrappingMode::QtLegacy);
1313     m_textEditorWidget.richTextEdit->document()->rootFrame()->setFrameFormat(f);
1314     checkDocumentFormat();
1315 }
1316 
1317 void SvgTextEditor::setWrappingPre()
1318 {
1319     QTextFrameFormat f = m_textEditorWidget.richTextEdit->document()->rootFrame()->frameFormat();
1320     KoSvgTextShapeMarkupConverter::setWrappingMode(&f, WrappingMode::WhiteSpacePre);
1321     m_textEditorWidget.richTextEdit->document()->rootFrame()->setFrameFormat(f);
1322     checkDocumentFormat();
1323 }
1324 
1325 void SvgTextEditor::setWrappingPreWrap()
1326 {
1327     KisSignalsBlocker b(m_textEditorWidget.richTextEdit);
1328 
1329     QTextDocument *doc = m_textEditorWidget.richTextEdit->document();
1330 
1331     // `inline-size` can only support one block alignment for the whole text
1332     // element, therefore we should make all text blocks use the same alignment.
1333     {
1334         const Qt::Alignment firstBlockAlignment = doc->firstBlock().blockFormat().alignment();
1335         QTextBlockFormat blockFmt;
1336         blockFmt.setAlignment(firstBlockAlignment);
1337         QTextCursor cursor(doc);
1338         cursor.select(QTextCursor::Document);
1339         cursor.mergeBlockFormat(blockFmt);
1340     }
1341 
1342     QTextFrameFormat f = doc->rootFrame()->frameFormat();
1343     const double inlineSize = KoSvgTextShapeMarkupConverter::getInlineSize(f).value_or(100.0);
1344     KoSvgTextShapeMarkupConverter::setWrappingMode(&f, WrappingMode::WhiteSpacePreWrap);
1345     KoSvgTextShapeMarkupConverter::setInlineSize(&f, inlineSize);
1346     doc->rootFrame()->setFrameFormat(f);
1347     checkDocumentFormat();
1348 }
1349 
1350 void SvgTextEditor::wheelEvent(QWheelEvent *event)
1351 {
1352     if (!isSvgSourceEditorTabActive()) {
1353         return;
1354     }
1355 
1356     if (event->modifiers() & Qt::ControlModifier) {
1357         int numDegrees = event->delta() / 8;
1358         int numSteps = numDegrees / 7;
1359         m_textEditorWidget.svgTextEdit->zoomOut(numSteps);
1360         event->accept();
1361     }
1362 }
1363 
1364 QTextCursor SvgTextEditor::setTextSelection()
1365 {
1366     QTextCursor orignalCursor(m_textEditorWidget.richTextEdit->textCursor());
1367     if (!orignalCursor.hasSelection()){
1368         m_textEditorWidget.richTextEdit->selectAll();
1369     }
1370     return orignalCursor;
1371 }
1372 
1373 void SvgTextEditor::applySettings()
1374 {
1375     KConfigGroup cfg(KSharedConfig::openConfig(), "SvgTextTool");
1376 
1377     QWidget *richTab = m_textEditorWidget.richTab;
1378     QWidget *svgTab = m_textEditorWidget.svgTab;
1379 
1380     m_page->setUpdatesEnabled(false);
1381     m_textEditorWidget.textTab->clear();
1382 
1383     m_textEditorWidget.textTab->addTab(richTab, i18n("Rich text"));
1384     m_textEditorWidget.textTab->addTab(svgTab, i18n("SVG Source"));
1385 
1386     m_syntaxHighlighter->setFormats();
1387 
1388     QPalette palette = m_textEditorWidget.svgTextEdit->palette();
1389 
1390     QColor background = cfg.readEntry("colorEditorBackground", qApp->palette().window().color());
1391     palette.setBrush(QPalette::Active, QPalette::Window, QBrush(background));
1392     m_textEditorWidget.richTextEdit->setStyleSheet(QString("background-color:%1").arg(background.name()));
1393     m_textEditorWidget.svgStylesEdit->setStyleSheet(QString("background-color:%1").arg(background.name()));
1394     m_textEditorWidget.svgTextEdit->setStyleSheet(QString("background-color:%1").arg(background.name()));
1395 
1396     QColor foreground = cfg.readEntry("colorEditorForeground", qApp->palette().text().color());
1397     palette.setBrush(QPalette::Active, QPalette::Text, QBrush(foreground));
1398 
1399     QStringList selectedWritingSystems = cfg.readEntry("selectedWritingSystems", "").split(",");
1400 
1401     QVector<QFontDatabase::WritingSystem> writingSystems;
1402     for (int i=0; i<selectedWritingSystems.size(); i++) {
1403         writingSystems.append((QFontDatabase::WritingSystem)QString(selectedWritingSystems.at(i)).toInt());
1404     }
1405 
1406     {
1407         FontSizeAction *fontSizeAction = qobject_cast<FontSizeAction*>(actionCollection()->action("svg_font_size"));
1408         KisFontComboBoxes* fontComboBox = qobject_cast<KisFontComboBoxes*>(qobject_cast<QWidgetAction*>(actionCollection()->action("svg_font"))->defaultWidget());
1409 
1410         const QFont oldFont = fontComboBox->currentFont(fontSizeAction->fontSize());
1411         fontComboBox->refillComboBox(writingSystems);
1412         fontComboBox->setCurrentFont(oldFont);
1413     }
1414 
1415     m_page->setUpdatesEnabled(true);
1416 }
1417 
1418 QAction *SvgTextEditor::createAction(const QString &name, const char *member)
1419 {
1420     QAction *action = new QAction(this);
1421     KisActionRegistry *actionRegistry = KisActionRegistry::instance();
1422     actionRegistry->propertizeAction(name, action);
1423 
1424     actionCollection()->addAction(name, action);
1425     QObject::connect(action, SIGNAL(triggered(bool)), this, member);
1426     return action;
1427 }
1428 
1429 
1430 void SvgTextEditor::createActions()
1431 {
1432     KisActionRegistry *actionRegistry = KisActionRegistry::instance();
1433 
1434 
1435     // File: new, open, save, save as, close
1436     KStandardAction::save(this, SLOT(save()), actionCollection());
1437     KStandardAction::close(this, SLOT(slotCloseEditor()), actionCollection());
1438 
1439     // Edit
1440     KStandardAction::undo(this, SLOT(undo()), actionCollection());
1441     KStandardAction::redo(this, SLOT(redo()), actionCollection());
1442     KStandardAction::cut(this, SLOT(cut()), actionCollection());
1443     KStandardAction::copy(this, SLOT(copy()), actionCollection());
1444     KStandardAction::paste(this, SLOT(paste()), actionCollection());
1445     KStandardAction::selectAll(this, SLOT(selectAll()), actionCollection());
1446     KStandardAction::deselect(this, SLOT(deselect()), actionCollection());
1447     KStandardAction::find(this, SLOT(find()), actionCollection());
1448     KStandardAction::findNext(this, SLOT(findNext()), actionCollection());
1449     KStandardAction::findPrev(this, SLOT(findPrev()), actionCollection());
1450     KStandardAction::replace(this, SLOT(replace()), actionCollection());
1451 
1452     // View
1453     // WISH: we cannot zoom-in/out in rech-text mode
1454     m_svgTextActions << KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection());
1455     m_svgTextActions << KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection());
1456 #ifndef Q_OS_WIN
1457     // Insert:
1458     QAction * insertAction = createAction("svg_insert_special_character",
1459                                           SLOT(showInsertSpecialCharacterDialog()));
1460     insertAction->setCheckable(true);
1461     insertAction->setChecked(false);
1462 #endif
1463     // Format:
1464     m_richTextActions << createAction("svg_weight_bold",
1465                                       SLOT(setTextBold()));
1466 
1467     m_richTextActions << createAction("svg_format_italic",
1468                                       SLOT(setTextItalic()));
1469 
1470     m_richTextActions << createAction("svg_format_underline",
1471                                       SLOT(setTextUnderline()));
1472 
1473     m_richTextActions << createAction("svg_format_strike_through",
1474                                       SLOT(setTextStrikethrough()));
1475 
1476     m_richTextActions << createAction("svg_format_superscript",
1477                                       SLOT(setTextSuperScript()));
1478 
1479     m_richTextActions << createAction("svg_format_subscript",
1480                                       SLOT(setTextSubscript()));
1481 
1482     m_richTextActions << createAction("svg_weight_light",
1483                                       SLOT(setTextWeightLight()));
1484 
1485     m_richTextActions << createAction("svg_weight_normal",
1486                                       SLOT(setTextWeightNormal()));
1487 
1488     m_richTextActions << createAction("svg_weight_demi",
1489                                       SLOT(setTextWeightDemi()));
1490 
1491     m_richTextActions << createAction("svg_weight_black",
1492                                       SLOT(setTextWeightBlack()));
1493 
1494     m_richTextActions << createAction("svg_increase_font_size",
1495                                       SLOT(increaseTextSize()));
1496 
1497     m_richTextActions << createAction("svg_decrease_font_size",
1498                                       SLOT(decreaseTextSize()));
1499 
1500     m_richTextActions << createAction("svg_align_left",
1501                                       SLOT(alignLeft()));
1502 
1503     m_richTextActions << createAction("svg_align_right",
1504                                       SLOT(alignRight()));
1505 
1506     m_richTextActions << createAction("svg_align_center",
1507                                       SLOT(alignCenter()));
1508 
1509 //    m_richTextActions << createAction("svg_align_justified",
1510 //                                      SLOT(alignJustified()));
1511 
1512     m_richTextActions << createAction("svg_font_kerning",
1513                                       SLOT(setKerning(bool)));
1514 
1515     d->textWrappingActionGroup = new QActionGroup(this);
1516     m_richTextActions << d->textWrappingActionGroup->addAction(
1517         createAction("svg_text_wrapping_legacy", SLOT(setWrappingLegacy())));
1518     m_richTextActions << d->textWrappingActionGroup->addAction(
1519         createAction("svg_text_wrapping_css_pre", SLOT(setWrappingPre())));
1520     m_richTextActions << d->textWrappingActionGroup->addAction(
1521         createAction("svg_text_wrapping_css_pre_wrap", SLOT(setWrappingPreWrap())));
1522 
1523     // Settings
1524     // do not add settings action to m_richTextActions list,
1525     // it should always be active, regardless of which editor mode is used.
1526     // otherwise we can lock the user out of being able to change
1527     // editor mode, if user changes to SVG only mode.
1528     createAction("svg_settings", SLOT(setSettings()));
1529 
1530     QWidgetAction *fontComboAction = new QWidgetAction(this);
1531     fontComboAction->setToolTip(i18n("Font"));
1532     KisFontComboBoxes *fontCombo = new KisFontComboBoxes();
1533     connect(fontCombo, SIGNAL(fontChanged(QString)), SLOT(setFont(QString)));
1534     fontComboAction->setDefaultWidget(fontCombo);
1535     actionCollection()->addAction("svg_font", fontComboAction);
1536     m_richTextActions << fontComboAction;
1537     actionRegistry->propertizeAction("svg_font", fontComboAction);
1538 
1539     QWidgetAction *fontSizeAction = new FontSizeAction(this);
1540     fontSizeAction->setToolTip(i18n("Size"));
1541     connect(fontSizeAction, SIGNAL(fontSizeChanged(qreal)), this, SLOT(setFontSize(qreal)));
1542     actionCollection()->addAction("svg_font_size", fontSizeAction);
1543     m_richTextActions << fontSizeAction;
1544     actionRegistry->propertizeAction("svg_font_size", fontSizeAction);
1545 
1546     KoColorPopupAction *fgColor = new KoColorPopupAction(this);
1547     fgColor->setCurrentColor(QColor(Qt::black));
1548     fgColor->setToolTip(i18n("Text Color"));
1549     connect(fgColor, SIGNAL(colorChanged(KoColor)), SLOT(setFontColor(KoColor)));
1550     actionCollection()->addAction("svg_format_textcolor", fgColor);
1551     m_richTextActions << fgColor;
1552     actionRegistry->propertizeAction("svg_format_textcolor", fgColor);
1553 
1554     KoColorPopupAction *bgColor = new KoColorPopupAction(this);
1555     bgColor->setCurrentColor(QColor(Qt::white));
1556     bgColor->setToolTip(i18n("Background Color"));
1557     connect(bgColor, SIGNAL(colorChanged(KoColor)), SLOT(setBackgroundColor(KoColor)));
1558     actionCollection()->addAction("svg_background_color", bgColor);
1559     actionRegistry->propertizeAction("svg_background_color", bgColor);
1560     m_richTextActions << bgColor;
1561 
1562     QWidgetAction *colorSamplerAction = new QWidgetAction(this);
1563     colorSamplerAction->setToolTip(i18n("Sample a Color"));
1564     KisScreenColorSampler *colorSampler = new KisScreenColorSampler(false);
1565     connect(colorSampler, SIGNAL(sigNewColorSampled(KoColor)), fgColor, SLOT(setCurrentColor(KoColor)));
1566     connect(colorSampler, SIGNAL(sigNewColorSampled(KoColor)), SLOT(setFontColor(KoColor)));
1567     colorSamplerAction->setDefaultWidget(colorSampler);
1568     actionCollection()->addAction("svg_sample_color", colorSamplerAction);
1569     m_richTextActions << colorSamplerAction;
1570     actionRegistry->propertizeAction("svg_sample_color", colorSamplerAction);
1571 
1572     QWidgetAction *lineHeight = new QWidgetAction(this);
1573     QWidget *lineHeightWdg = new QWidget();
1574     QHBoxLayout *lineHeightLayout = new QHBoxLayout(lineHeightWdg);
1575     lineHeightLayout->setSpacing(0);
1576     QDoubleSpinBox *spnLineHeight = new QDoubleSpinBox();
1577     spnLineHeight->setToolTip(i18n("Line height"));
1578     spnLineHeight->setRange(-1.0, 1000.0);
1579     spnLineHeight->setSingleStep(10.0);
1580     KisSpinBoxI18nHelper::setText(spnLineHeight, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
1581     spnLineHeight->setSpecialValueText(i18nc("Default line height for text", "Normal"));
1582     connect(spnLineHeight, SIGNAL(valueChanged(double)), SLOT(setLineHeight(double)));
1583     lineHeightLayout->addWidget(spnLineHeight);
1584     {
1585         QToolButton *btn = new QToolButton();
1586         btn->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
1587         btn->setArrowType(Qt::DownArrow);
1588         btn->setPopupMode(QToolButton::InstantPopup);
1589         QMenu *lineHeightMenu = new QMenu(this);
1590         QAction *actionNormal = lineHeightMenu->addAction(i18nc("Default line height for text", "Normal"));
1591         connect(actionNormal, &QAction::triggered, spnLineHeight, [spnLineHeight]() {
1592             spnLineHeight->setValue(-1.0);
1593         });
1594         QAction *action100 = lineHeightMenu->addAction(i18nc("line height for text", "100%"));
1595         connect(action100, &QAction::triggered, spnLineHeight, [spnLineHeight]() {
1596             spnLineHeight->setValue(100.0);
1597         });
1598         btn->setMenu(lineHeightMenu);
1599         lineHeightLayout->addWidget(btn);
1600     }
1601     lineHeight->setDefaultWidget(lineHeightWdg);
1602     actionCollection()->addAction("svg_line_height", lineHeight);
1603     m_richTextActions << lineHeight;
1604     actionRegistry->propertizeAction("svg_line_height", lineHeight);
1605 
1606     QWidgetAction *letterSpacing = new QWidgetAction(this);
1607     QDoubleSpinBox *spnletterSpacing = new QDoubleSpinBox();
1608     spnletterSpacing->setToolTip(i18n("Letter Spacing"));
1609     spnletterSpacing->setRange(-20.0, 20.0);
1610     spnletterSpacing->setSingleStep(0.5);
1611     connect(spnletterSpacing, SIGNAL(valueChanged(double)), SLOT(setLetterSpacing(double)));
1612     letterSpacing->setDefaultWidget(spnletterSpacing);
1613     actionCollection()->addAction("svg_letter_spacing", letterSpacing);
1614     m_richTextActions << letterSpacing;
1615     actionRegistry->propertizeAction("svg_letter_spacing", letterSpacing);
1616 }
1617 
1618 void SvgTextEditor::enableRichTextActions(bool enable)
1619 {
1620     Q_FOREACH(QAction *action, m_richTextActions) {
1621         action->setEnabled(enable);
1622     }
1623 }
1624 
1625 void SvgTextEditor::enableSvgTextActions(bool enable)
1626 {
1627     Q_FOREACH(QAction *action, m_svgTextActions) {
1628         action->setEnabled(enable);
1629     }
1630 }
1631 
1632 bool SvgTextEditor::isRichTextEditorTabActive() {
1633     return m_textEditorWidget.textTab->currentIndex() == Editor::Richtext;
1634 }
1635 
1636 bool SvgTextEditor::isSvgSourceEditorTabActive() {
1637     return m_textEditorWidget.textTab->currentIndex() == Editor::SVGsource;
1638 }
1639 
1640 void SvgTextEditor::slotCloseEditor()
1641 {
1642     close();
1643     emit textEditorClosed();
1644 }
1645 
1646 bool SvgTextEditor::eventFilter(QObject *const watched, QEvent *const event)
1647 {
1648     if (watched == m_textEditorWidget.richTextEdit) {
1649         if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
1650             QKeyEvent *const keyEvent = static_cast<QKeyEvent *>(event);
1651             if ((keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
1652                 && (keyEvent->modifiers() & Qt::ShiftModifier)) {
1653                 // Disable soft line breaks
1654                 return true;
1655             }
1656         }
1657         return false;
1658     }
1659     return KXmlGuiWindow::eventFilter(watched, event);
1660 }