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 }