diff --git a/libs/widgetutils/kis_action_registry.cpp b/libs/widgetutils/kis_action_registry.cpp index 6f2c49f929..15d880ca79 100644 --- a/libs/widgetutils/kis_action_registry.cpp +++ b/libs/widgetutils/kis_action_registry.cpp @@ -1,412 +1,412 @@ /* * Copyright (c) 2015 Michael Abrahams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "kis_debug.h" #include "KoResourcePaths.h" #include "kis_icon_utils.h" #include "kis_action_registry.h" #include "kshortcutschemeshelper_p.h" namespace { /** * We associate several pieces of information with each shortcut. The first * piece of information is a QDomElement, containing the raw data from the * .action XML file. The second and third are QKeySequences, the first of * which is the default shortcut, the last of which is any custom shortcut. * The last two are the KActionCollection and KActionCategory used to * organize the shortcut editor. */ struct ActionInfoItem { QDomElement xmlData; QString collectionName; QString categoryName; inline QList defaultShortcuts() const { return m_defaultShortcuts; } inline void setDefaultShortcuts(const QList &value) { m_defaultShortcuts = value; } inline QList customShortcuts() const { return m_customShortcuts; } inline void setCustomShortcuts(const QList &value, bool explicitlyReset) { m_customShortcuts = value; m_explicitlyReset = explicitlyReset; } inline QList effectiveShortcuts() const { return m_customShortcuts.isEmpty() && !m_explicitlyReset ? m_defaultShortcuts : m_customShortcuts; } private: QList m_defaultShortcuts; QList m_customShortcuts; bool m_explicitlyReset = false; }; // Convenience macros to extract text of a child node. QString getChildContent(QDomElement xml, QString node) { return xml.firstChildElement(node).text(); } // Use Krita debug logging categories instead of KDE's default qDebug() for // harmless empty strings and translations QString quietlyTranslate(const QString &s) { if (s.isEmpty()) { return s; } QString translatedString = i18nc("action", s.toUtf8()); if (translatedString == s) { translatedString = i18n(s.toUtf8()); } if (translatedString.isEmpty()) { dbgAction << "No translation found for" << s; return s; } return translatedString; } } class Q_DECL_HIDDEN KisActionRegistry::Private { public: Private(KisActionRegistry *_q) : q(_q) {} // This is the main place containing ActionInfoItems. QMap actionInfoList; void loadActionFiles(); void loadCustomShortcuts(QString filename = QStringLiteral("kritashortcutsrc")); // XXX: this adds a default item for the given name to the list of actioninfo objects! ActionInfoItem &actionInfo(const QString &name) { if (!actionInfoList.contains(name)) { dbgAction << "Tried to look up info for unknown action" << name; } return actionInfoList[name]; } KisActionRegistry *q; QSet sanityPropertizedShortcuts; }; Q_GLOBAL_STATIC(KisActionRegistry, s_instance) KisActionRegistry *KisActionRegistry::instance() { return s_instance; } bool KisActionRegistry::hasAction(const QString &name) const { return d->actionInfoList.contains(name); } KisActionRegistry::KisActionRegistry() : d(new KisActionRegistry::Private(this)) { KConfigGroup cg = KSharedConfig::openConfig()->group("Shortcut Schemes"); QString schemeName = cg.readEntry("Current Scheme", "Default"); loadShortcutScheme(schemeName); loadCustomShortcuts(); } KisActionRegistry::ActionCategory KisActionRegistry::fetchActionCategory(const QString &name) const { if (!d->actionInfoList.contains(name)) return ActionCategory(); const ActionInfoItem info = d->actionInfoList.value(name); return ActionCategory(info.collectionName, info.categoryName); } void KisActionRegistry::notifySettingsUpdated() { d->loadCustomShortcuts(); } void KisActionRegistry::loadCustomShortcuts() { d->loadCustomShortcuts(); } void KisActionRegistry::loadShortcutScheme(const QString &schemeName) { // Load scheme file if (schemeName != QStringLiteral("Default")) { QString schemeFileName = KShortcutSchemesHelper::schemeFileLocations().value(schemeName); if (schemeFileName.isEmpty()) { return; } KConfig schemeConfig(schemeFileName, KConfig::SimpleConfig); applyShortcutScheme(&schemeConfig); } else { // Apply default scheme, updating KisActionRegistry data applyShortcutScheme(); } } QAction * KisActionRegistry::makeQAction(const QString &name, QObject *parent) { QAction * a = new QAction(parent); if (!d->actionInfoList.contains(name)) { dbgAction << "Warning: requested data for unknown action" << name; return a; } propertizeAction(name, a); return a; } void KisActionRegistry::settingsPageSaved() { // For now, custom shortcuts are dealt with by writing to file and reloading. loadCustomShortcuts(); // Announce UI should reload current shortcuts. emit shortcutsUpdated(); } void KisActionRegistry::applyShortcutScheme(const KConfigBase *config) { // First, update the things in KisActionRegistry if (config == 0) { // Use default shortcut scheme. Simplest just to reload everything. d->actionInfoList.clear(); d->loadActionFiles(); loadCustomShortcuts(); } else { const auto schemeEntries = config->group(QStringLiteral("Shortcuts")).entryMap(); // Load info item for each shortcut, reset custom shortcuts auto it = schemeEntries.constBegin(); while (it != schemeEntries.end()) { ActionInfoItem &info = d->actionInfo(it.key()); info.setDefaultShortcuts(QKeySequence::listFromString(it.value())); it++; } } } void KisActionRegistry::updateShortcut(const QString &name, QAction *action) { const ActionInfoItem &info = d->actionInfo(name); action->setShortcuts(info.effectiveShortcuts()); action->setProperty("defaultShortcuts", qVariantFromValue(info.defaultShortcuts())); d->sanityPropertizedShortcuts.insert(name); } bool KisActionRegistry::sanityCheckPropertized(const QString &name) { return d->sanityPropertizedShortcuts.contains(name); } QList KisActionRegistry::registeredShortcutIds() const { return d->actionInfoList.keys(); } bool KisActionRegistry::propertizeAction(const QString &name, QAction * a) { if (!d->actionInfoList.contains(name)) { - qDebug() << "No XML data found for action" << name; + qWarning() << "No XML data found for action" << name; return false; } const ActionInfoItem info = d->actionInfo(name); QDomElement actionXml = info.xmlData; if (!actionXml.text().isEmpty()) { // i18n requires converting format from QString. auto getChildContent_i18n = [=](QString node){return quietlyTranslate(getChildContent(actionXml, node));}; // Note: the fields in the .action documents marked for translation are determined by extractrc. QString icon = getChildContent(actionXml, "icon"); QString text = getChildContent_i18n("text"); QString whatsthis = getChildContent_i18n("whatsThis"); QString toolTip = getChildContent_i18n("toolTip"); QString statusTip = getChildContent_i18n("statusTip"); QString iconText = getChildContent_i18n("iconText"); bool isCheckable = getChildContent(actionXml, "isCheckable") == QString("true"); a->setObjectName(name); // This is helpful, should be added more places in Krita a->setIcon(KisIconUtils::loadIcon(icon.toLatin1())); a->setText(text); a->setObjectName(name); a->setWhatsThis(whatsthis); a->setToolTip(toolTip); a->setStatusTip(statusTip); a->setIconText(iconText); a->setCheckable(isCheckable); } updateShortcut(name, a); return true; } QString KisActionRegistry::getActionProperty(const QString &name, const QString &property) { ActionInfoItem info = d->actionInfo(name); QDomElement actionXml = info.xmlData; if (actionXml.text().isEmpty()) { dbgAction << "No XML data found for action" << name; return QString(); } return getChildContent(actionXml, property); } void KisActionRegistry::Private::loadActionFiles() { QStringList actionDefinitions = KoResourcePaths::findAllResources("kis_actions", "*.action", KoResourcePaths::Recursive); // Extract actions all XML .action files. Q_FOREACH (const QString &actionDefinition, actionDefinitions) { QDomDocument doc; QFile f(actionDefinition); f.open(QFile::ReadOnly); doc.setContent(f.readAll()); QDomElement base = doc.documentElement(); // "ActionCollection" outer group QString collectionName = base.attribute("name"); QString version = base.attribute("version"); if (version != "2") { errAction << ".action XML file" << actionDefinition << "has incorrect version; skipping."; continue; } // Loop over nodes. Each of these corresponds to a // KActionCategory, producing a group of actions in the shortcut dialog. QDomElement actions = base.firstChild().toElement(); while (!actions.isNull()) { // field QDomElement categoryTextNode = actions.firstChild().toElement(); QString categoryName = quietlyTranslate(categoryTextNode.text()); // tags QDomElement actionXml = categoryTextNode.nextSiblingElement(); // Loop over individual actions while (!actionXml.isNull()) { if (actionXml.tagName() == "Action") { // Read name from format QString name = actionXml.attribute("name"); // Bad things if (name.isEmpty()) { errAction << "Unnamed action in definitions file " << actionDefinition; } else if (actionInfoList.contains(name)) { errAction << "NOT COOL: Duplicated action name from xml data: " << name; } else { ActionInfoItem info; info.xmlData = actionXml; // Use empty list to signify no shortcut QString shortcutText = getChildContent(actionXml, "shortcut"); if (!shortcutText.isEmpty()) { info.setDefaultShortcuts(QKeySequence::listFromString(shortcutText)); } info.categoryName = categoryName; info.collectionName = collectionName; actionInfoList.insert(name,info); } } actionXml = actionXml.nextSiblingElement(); } actions = actions.nextSiblingElement(); } } } void KisActionRegistry::Private::loadCustomShortcuts(QString filename) { const KConfigGroup localShortcuts(KSharedConfig::openConfig(filename), QStringLiteral("Shortcuts")); if (!localShortcuts.exists()) { return; } // Distinguish between two "null" states for custom shortcuts. for (auto i = actionInfoList.begin(); i != actionInfoList.end(); ++i) { if (localShortcuts.hasKey(i.key())) { QString entry = localShortcuts.readEntry(i.key(), QString()); if (entry == QStringLiteral("none")) { i.value().setCustomShortcuts(QList(), true); } else { i.value().setCustomShortcuts(QKeySequence::listFromString(entry), false); } } else { i.value().setCustomShortcuts(QList(), false); } } } KisActionRegistry::ActionCategory::ActionCategory() { } KisActionRegistry::ActionCategory::ActionCategory(const QString &_componentName, const QString &_categoryName) : componentName(_componentName), categoryName(_categoryName), m_isValid(true) { } bool KisActionRegistry::ActionCategory::isValid() const { return m_isValid && !categoryName.isEmpty() && !componentName.isEmpty(); } diff --git a/plugins/tools/svgtexttool/CMakeLists.txt b/plugins/tools/svgtexttool/CMakeLists.txt index c23c51363a..6ef650e92a 100644 --- a/plugins/tools/svgtexttool/CMakeLists.txt +++ b/plugins/tools/svgtexttool/CMakeLists.txt @@ -1,25 +1,31 @@ project(SvgTextTool) set(CMAKE_AUTORCC ON) set (SvgTextTool_SRCS BasicXMLSyntaxHighlighter.cpp Plugin.cpp SvgTextChangeCommand.cpp SvgTextEditor.cpp SvgTextTool.cpp SvgTextToolFactory.cpp svgtexttool.qrc kis_font_family_combo_box.cpp ) ki18n_wrap_ui(SvgTextTool_SRCS WdgSvgTextEditor.ui ) +install( FILES + SvgTextTool.action + DESTINATION ${DATA_INSTALL_DIR}/krita/actions +) + + add_library(krita_tool_svgtext MODULE ${SvgTextTool_SRCS}) target_link_libraries(krita_tool_svgtext kritaui KF5::I18n) install(TARGETS krita_tool_svgtext DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) add_executable(svgtexttool ${SvgTextTool_SRCS} main.cpp) target_link_libraries(svgtexttool kritaui KF5::I18n) diff --git a/plugins/tools/svgtexttool/SvgTextEditor.cpp b/plugins/tools/svgtexttool/SvgTextEditor.cpp index 2665da6adf..1516e0fa20 100644 --- a/plugins/tools/svgtexttool/SvgTextEditor.cpp +++ b/plugins/tools/svgtexttool/SvgTextEditor.cpp @@ -1,893 +1,903 @@ /* This file is part of the KDE project * * Copyright 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SvgTextEditor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include "kis_font_family_combo_box.h" SvgTextEditor::SvgTextEditor(QWidget *parent, Qt::WindowFlags flags) : KXmlGuiWindow(parent, flags) , m_page(new QWidget(this)) , m_charSelectDialog(new KoDialog(this)) { m_textEditorWidget.setupUi(m_page); setCentralWidget(m_page); KCharSelect *charSelector = new KCharSelect(m_charSelectDialog, 0, KCharSelect::AllGuiElements); m_charSelectDialog->setMainWidget(charSelector); connect(charSelector, SIGNAL(currentCharChanged(QChar)), SLOT(insertCharacter(QChar))); m_charSelectDialog->hide(); m_charSelectDialog->setButtons(KoDialog::Close); connect(m_textEditorWidget.buttons, SIGNAL(accepted()), this, SLOT(save())); connect(m_textEditorWidget.buttons, SIGNAL(rejected()), this, SLOT(close())); connect(m_textEditorWidget.buttons, SIGNAL(clicked(QAbstractButton*)), this, SLOT(dialogButtonClicked(QAbstractButton*))); KConfigGroup cg(KSharedConfig::openConfig(), "SvgTextTool"); actionCollection()->setConfigGroup("SvgTextTool"); actionCollection()->setComponentName("svgtexttool"); actionCollection()->setComponentDisplayName(i18n("Text Tool")); QByteArray state; if (cg.hasKey("WindowState")) { state = cg.readEntry("State", state); state = QByteArray::fromBase64(state); // One day will need to load the version number, but for now, assume 0 restoreState(state); } setAcceptDrops(true); setStandardToolBarMenuEnabled(true); #ifdef Q_OS_OSX setUnifiedTitleAndToolBarOnMac(true); #endif setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); BasicXMLSyntaxHighlighter *hl = new BasicXMLSyntaxHighlighter(m_textEditorWidget.svgTextEdit); Q_UNUSED(hl); createActions(); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "svgtexttool.xmlgui")); setXMLFile(":/kxmlgui5/svgtexttool.xmlgui"); guiFactory()->addClient(this); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); if (toolBar) { KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); act->setChecked(!toolBar->isHidden()); toolbarList.append(act); } } plugActionList("toolbarlist", toolbarList); connect(m_textEditorWidget.textTab, SIGNAL(currentChanged(int)), this, SLOT(switchTextEditorTab())); switchTextEditorTab(); m_textEditorWidget.richTextEdit->document()->setDefaultStyleSheet("p {margin:0px;}"); } SvgTextEditor::~SvgTextEditor() { KConfigGroup g(KSharedConfig::openConfig(), "SvgTextTool"); QByteArray ba = saveState(); g.writeEntry("windowState", ba.toBase64()); } void SvgTextEditor::setShape(KoSvgTextShape *shape) { m_shape = shape; if (m_shape) { KoSvgTextShapeMarkupConverter converter(m_shape); QString svg; QString styles; QString html; if (converter.convertToHtml(&html)) { qDebug() << "html:" << html; m_textEditorWidget.richTextEdit->document()->clear(); m_textEditorWidget.richTextEdit->document()->setHtml(html); m_textEditorWidget.richTextEdit->document()->setModified(false); } if (converter.convertToSvg(&svg, &styles)) { m_textEditorWidget.svgTextEdit->setPlainText(svg); m_textEditorWidget.svgStylesEdit->setPlainText(styles); m_textEditorWidget.svgTextEdit->document()->setModified(false); } else { QMessageBox::warning(this, i18n("Conversion failed"), "Could not get svg text from the shape:\n" + converter.errors().join('\n') + "\n" + converter.warnings().join('\n')); } } } void SvgTextEditor::save() { if (m_shape) { if (m_textEditorWidget.textTab->currentIndex() == Richtext) { QString svg; QString styles; KoSvgTextShapeMarkupConverter converter(m_shape); if (!converter.convertFromHtml(m_textEditorWidget.richTextEdit->document()->toHtml(), &svg, &styles)) { qWarning() << "Eeeek"; } m_textEditorWidget.richTextEdit->document()->setModified(false); emit textUpdated(svg, styles); } else { emit textUpdated(m_textEditorWidget.svgTextEdit->document()->toPlainText(), m_textEditorWidget.svgStylesEdit->document()->toPlainText()); m_textEditorWidget.svgTextEdit->document()->setModified(false); } } } void SvgTextEditor::switchTextEditorTab() { KoSvgTextShape shape; KoSvgTextShapeMarkupConverter converter(&shape); if (m_currentEditor) { disconnect(m_currentEditor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setModified(bool))); } if (m_textEditorWidget.textTab->currentIndex() == Richtext) { //first, make buttons checkable enableRichTextActions(true); //then connect the cursor change to the checkformat(); connect(m_textEditorWidget.richTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(checkFormat())); if (m_shape) { // Convert the svg text to html XXX: Fix resolution! Also, the rect should be the image rect, not the shape rect. if (!converter.convertFromSvg(m_textEditorWidget.svgTextEdit->document()->toPlainText(), m_textEditorWidget.svgStylesEdit->document()->toPlainText(), m_shape->boundingRect(), 72.0)) { qDebug() << "Eeek 3"; } QString html; if (!converter.convertToHtml(&html)) { qDebug() << "Eeek 4"; } m_textEditorWidget.richTextEdit->document()->setHtml(html); } m_currentEditor = m_textEditorWidget.richTextEdit; } else { //first, make buttons uncheckable enableRichTextActions(false); disconnect(m_textEditorWidget.richTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(checkFormat())); // Convert the rich text to svg and styles strings if (m_shape) { QString svg; QString styles; if (!converter.convertFromHtml(m_textEditorWidget.richTextEdit->document()->toHtml(), &svg, &styles)) { qWarning() << "Eeeek"; } //if (!converter.convertToSvg(&svg, &styles)) { // qDebug() << "Eeeek 2"; //} m_textEditorWidget.svgTextEdit->setPlainText(svg); m_textEditorWidget.svgStylesEdit->setPlainText(styles); } m_currentEditor = m_textEditorWidget.svgTextEdit; } connect(m_currentEditor->document(), SIGNAL(modificationChanged(bool)), SLOT(setModified(bool))); } void SvgTextEditor::checkFormat() { QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat(); QTextBlockFormat blockFormat = m_textEditorWidget.richTextEdit->textCursor().blockFormat(); if (format.fontWeight() > QFont::Normal) { actionCollection()->action("weight_bold")->setChecked(true); } else { actionCollection()->action("weight_bold")->setChecked(false); } - actionCollection()->action("italic")->setChecked(format.fontItalic()); - actionCollection()->action("underline")->setChecked(format.fontUnderline()); - actionCollection()->action("strike_through")->setChecked(format.fontStrikeOut()); + actionCollection()->action("format_italic")->setChecked(format.fontItalic()); + actionCollection()->action("format_underline")->setChecked(format.fontUnderline()); + actionCollection()->action("format_strike_through")->setChecked(format.fontStrikeOut()); - qobject_cast(qobject_cast(actionCollection()->action("font"))->defaultWidget())->setCurrentFont(format.font()); - - QComboBox *fontSizeCombo = qobject_cast(qobject_cast(actionCollection()->action("font_size"))->defaultWidget()); + qobject_cast(qobject_cast(actionCollection()->action("svg_font"))->defaultWidget())->setCurrentFont(format.font()); + QComboBox *fontSizeCombo = qobject_cast(qobject_cast(actionCollection()->action("svg_font_size"))->defaultWidget()); fontSizeCombo->setCurrentIndex(QFontDatabase::standardSizes().indexOf(format.font().pointSize())); KoColor fg(format.foreground().color(), KoColorSpaceRegistry::instance()->rgb8()); - qobject_cast(actionCollection()->action("font_color"))->setCurrentColor(fg); + qobject_cast(actionCollection()->action("svg_format_textcolor"))->setCurrentColor(fg); KoColor bg(format.foreground().color(), KoColorSpaceRegistry::instance()->rgb8()); - qobject_cast(actionCollection()->action("background_color"))->setCurrentColor(bg); + qobject_cast(actionCollection()->action("svg_background_color"))->setCurrentColor(bg); QDoubleSpinBox *spnLineHeight = qobject_cast(qobject_cast(actionCollection()->action("line_height"))->defaultWidget()); if (blockFormat.lineHeightType()==QTextBlockFormat::SingleHeight) { spnLineHeight->setValue(1.0); } else if(blockFormat.lineHeightType()==QTextBlockFormat::ProportionalHeight) { spnLineHeight->setValue(double(blockFormat.lineHeight()/100.0)); } } void SvgTextEditor::undo() { m_currentEditor->undo(); } void SvgTextEditor::redo() { m_currentEditor->redo(); } void SvgTextEditor::cut() { m_currentEditor->cut(); } void SvgTextEditor::copy() { m_currentEditor->copy(); } void SvgTextEditor::paste() { m_currentEditor->paste(); } void SvgTextEditor::selectAll() { m_currentEditor->selectAll(); } void SvgTextEditor::deselect() { m_currentEditor->textCursor().clearSelection(); } void SvgTextEditor::find() { } void SvgTextEditor::findNext() { } void SvgTextEditor::findPrev() { } void SvgTextEditor::replace() { } void SvgTextEditor::zoomOut() { m_currentEditor->zoomOut(); } void SvgTextEditor::zoomIn() { m_currentEditor->zoomIn(); } void SvgTextEditor::showInsertSpecialCharacterDialog() { m_charSelectDialog->setVisible(!m_charSelectDialog->isVisible()); } void SvgTextEditor::insertCharacter(const QChar &c) { m_currentEditor->textCursor().insertText(QString(c)); } void SvgTextEditor::setTextBold(QFont::Weight weight) { if (m_textEditorWidget.textTab->currentIndex() == Richtext) { QTextCharFormat format; if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight() > QFont::Normal && weight==QFont::Bold) { format.setFontWeight(QFont::Normal); } else { format.setFontWeight(weight); } m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } else { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } } void SvgTextEditor::setTextWeightLight() { if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight() < QFont::Normal) { setTextBold(QFont::Normal); } else { setTextBold(QFont::Light); } } void SvgTextEditor::setTextWeightNormal() { setTextBold(QFont::Normal); } void SvgTextEditor::setTextWeightDemi() { if (m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight()>QFont::Normal && m_textEditorWidget.richTextEdit->textCursor().charFormat().fontWeight()textCursor().charFormat().fontWeight()>QFont::Normal) { setTextBold(QFont::Normal); } else { setTextBold(QFont::Black); } } void SvgTextEditor::setTextItalic(QFont::Style style) { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); QString fontStyle = "inherit"; if (style == QFont::StyleItalic) { fontStyle = "italic"; } else if(style == QFont::StyleOblique) { fontStyle = "oblique"; } if (m_textEditorWidget.textTab->currentIndex() == Richtext) { QTextCharFormat format; format.setFontItalic(!m_textEditorWidget.richTextEdit->textCursor().charFormat().fontItalic()); m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } else { if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } } void SvgTextEditor::setTextDecoration(KoSvgText::TextDecoration decor) { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); QTextCharFormat currentFormat = m_textEditorWidget.richTextEdit->textCursor().charFormat(); QTextCharFormat format; QString textDecoration = "inherit"; if (decor == KoSvgText::DecorationUnderline) { textDecoration = "underline"; if (currentFormat.fontUnderline()) { format.setFontUnderline(false); } else { format.setFontUnderline(true); } format.setFontOverline(false); format.setFontStrikeOut(false); } else if (decor == KoSvgText::DecorationLineThrough) { textDecoration = "line-through"; format.setFontUnderline(false); format.setFontOverline(false); if (currentFormat.fontStrikeOut()) { format.setFontStrikeOut(false); } else { format.setFontStrikeOut(true); } } else if (decor == KoSvgText::DecorationOverline) { textDecoration = "overline"; format.setFontUnderline(false); if (currentFormat.fontOverline()) { format.setFontOverline(false); } else { format.setFontOverline(true); } format.setFontStrikeOut(false); } if (m_textEditorWidget.textTab->currentIndex() == Richtext) { m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } else { if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } } void SvgTextEditor::setTextUnderline() { setTextDecoration(KoSvgText::DecorationUnderline); } void SvgTextEditor::setTextOverline() { setTextDecoration(KoSvgText::DecorationOverline); } void SvgTextEditor::setTextStrikethrough() { setTextDecoration(KoSvgText::DecorationLineThrough); } void SvgTextEditor::setTextSubscript() { QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat(); if (format.verticalAlignment()==QTextCharFormat::AlignSubScript) { format.setVerticalAlignment(QTextCharFormat::AlignNormal); } else { format.setVerticalAlignment(QTextCharFormat::AlignSubScript); } m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } void SvgTextEditor::setTextSuperScript() { QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat(); if (format.verticalAlignment()==QTextCharFormat::AlignSuperScript) { format.setVerticalAlignment(QTextCharFormat::AlignNormal); } else { format.setVerticalAlignment(QTextCharFormat::AlignSuperScript); } m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } void SvgTextEditor::increaseTextSize() { QTextCharFormat format; int pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pointSize(); if (pointSize<0) { pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pixelSize(); } qDebug()<mergeCurrentCharFormat(format); } void SvgTextEditor::decreaseTextSize() { QTextCharFormat format; int pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pointSize(); if (pointSize<1) { pointSize = m_textEditorWidget.richTextEdit->textCursor().charFormat().font().pixelSize(); } format.setFontPointSize(qMax(pointSize-1.0, 1.0)); m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } void SvgTextEditor::setLineHeight(double lineHeightEm) { QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat(); format.setLineHeight(lineHeightEm*100, QTextBlockFormat::ProportionalHeight); m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format); } void SvgTextEditor::alignLeft() { QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat(); format.setAlignment(Qt::AlignLeft); m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format); } void SvgTextEditor::alignRight() { QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat(); format.setAlignment(Qt::AlignRight); m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format); } void SvgTextEditor::alignCenter() { QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat(); format.setAlignment(Qt::AlignCenter); m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format); } void SvgTextEditor::alignJustified() { QTextBlockFormat format = m_textEditorWidget.richTextEdit->textCursor().blockFormat(); format.setAlignment(Qt::AlignJustify); m_textEditorWidget.richTextEdit->textCursor().mergeBlockFormat(format); } void SvgTextEditor::setShapeProperties() { } void SvgTextEditor::slotConfigureToolbars() { } void SvgTextEditor::slotToolbarToggled(bool) { } void SvgTextEditor::setFontColor(const KoColor &c) { QColor color = c.toQColor(); if (m_textEditorWidget.textTab->currentIndex() == Richtext) { QTextCharFormat format; format.setForeground(QBrush(color)); m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } else { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } } void SvgTextEditor::setBackgroundColor(const KoColor &c) { QColor color = c.toQColor(); QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } void SvgTextEditor::setModified(bool modified) { if (modified) { m_textEditorWidget.buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Discard); } else { m_textEditorWidget.buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close); } } void SvgTextEditor::dialogButtonClicked(QAbstractButton *button) { if (m_textEditorWidget.buttons->standardButton(button) == QDialogButtonBox::Discard) { if (QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("You have modified the text. Discard changes?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { close(); } } } void SvgTextEditor::setFont(const QString &fontName) { QFont font; font.fromString(fontName); QTextCharFormat format = m_textEditorWidget.richTextEdit->textCursor().charFormat(); font.setPointSize(format.font().pointSize()); format.setFont(font); if (m_textEditorWidget.textTab->currentIndex() == Richtext) { m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } else { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } } void SvgTextEditor::setFontSize(const QString &fontSize) { if (m_textEditorWidget.textTab->currentIndex() == Richtext) { QTextCharFormat format; format.setFontPointSize((qreal)fontSize.toInt()); m_textEditorWidget.richTextEdit->mergeCurrentCharFormat(format); } else { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } } void SvgTextEditor::setBaseline(KoSvgText::BaselineShiftMode) { QTextCursor cursor = m_textEditorWidget.svgTextEdit->textCursor(); if (cursor.hasSelection()) { QString selectionModified = "" + cursor.selectedText() + ""; cursor.removeSelectedText(); cursor.insertText(selectionModified); } } void SvgTextEditor::wheelEvent(QWheelEvent *event) { if (event->modifiers() & Qt::ControlModifier) { int numDegrees = event->delta() / 8; int numSteps = numDegrees / 7; m_textEditorWidget.svgTextEdit->zoomOut(numSteps); event->accept(); } } -QAction *SvgTextEditor::createAction(const QString &name, const QString &text, const QString &icon, const char *member, const QKeySequence &shortcut) +QAction *SvgTextEditor::createAction(const QString &name, const QString &text, const QString &icon, const char *member) { QAction *action = new QAction(KisIconUtils::loadIcon(icon), text, this); - actionCollection()->setDefaultShortcut(action, shortcut); + KisActionRegistry *actionRegistry = KisActionRegistry::instance(); + actionRegistry->propertizeAction(name, action); + actionCollection()->addAction(name, action); QObject::connect(action, SIGNAL(triggered(bool)), this, member); return action; } - void SvgTextEditor::createActions() { + KisActionRegistry *actionRegistry = KisActionRegistry::instance(); + + // File: new, open, save, save as, close KStandardAction::openNew(this, SLOT(openNew()), actionCollection()); KStandardAction::open(this, SLOT(open()), actionCollection()); KStandardAction::save(this, SLOT(save()), actionCollection()); KStandardAction::saveAs(this, SLOT(saveAs()), actionCollection()); KStandardAction::close(this, SLOT(close()), actionCollection()); // Edit KStandardAction::undo(this, SLOT(undo()), actionCollection()); KStandardAction::redo(this, SLOT(redo()), actionCollection()); KStandardAction::cut(this, SLOT(cut()), actionCollection()); KStandardAction::copy(this, SLOT(copy()), actionCollection()); KStandardAction::paste(this, SLOT(paste()), actionCollection()); KStandardAction::selectAll(this, SLOT(selectAll()), actionCollection()); KStandardAction::deselect(this, SLOT(deselect()), actionCollection()); KStandardAction::find(this, SLOT(find()), actionCollection()); KStandardAction::findNext(this, SLOT(findNext()), actionCollection()); KStandardAction::findPrev(this, SLOT(findPrev()), actionCollection()); KStandardAction::replace(this, SLOT(replace()), actionCollection()); // View KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection()); KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection()); // Insert: QAction * insertAction = createAction("insert_special_character", i18n("Insert Special Character"), "insert-special-character", SLOT(showInsertSpecialCharacterDialog())); insertAction->setCheckable(true); insertAction->setChecked(false); // Format: m_richTextActions << createAction("weight_bold", i18n("Bold"), "format-text-bold", SLOT(setTextBold())); - m_richTextActions << createAction("italic", + m_richTextActions << createAction("format_italic", i18n("Italic"), "format-text-italic", SLOT(setTextItalic())); - m_richTextActions << createAction("underline", + m_richTextActions << createAction("format_underline", i18n("Underline"), "format-text-underline", SLOT(setTextUnderline())); - m_richTextActions << createAction("strike_through", + m_richTextActions << createAction("format_strike_through", i18n("Strike-through"), "format-text-strike-through", SLOT(setTextStrikethrough())); - m_richTextActions << createAction("superscript", + m_richTextActions << createAction("format_superscript", i18n("Superscript"), "format-text-superscript", SLOT(setTextSuperScript())); - m_richTextActions << createAction("subscript", + m_richTextActions << createAction("format_subscript", i18n("Subscript"), "format-text-subscript", SLOT(setTextSubscript())); m_richTextActions << createAction("weight_light", i18n("Light"), "format-text-light", SLOT(setTextWeightLight())); m_richTextActions << createAction("weight_normal", i18n("Normal"), "format-text-normal", SLOT(setTextWeightNormal())); - m_richTextActions << createAction("weight_Demi", + m_richTextActions << createAction("weight_demi", i18n("Demi"), "format-text-demi", SLOT(setTextWeightDemi())); m_richTextActions << createAction("weight_black", i18n("Black"), "format-text-black", SLOT(setTextWeightBlack())); - m_richTextActions << createAction("increase_text_size", + m_richTextActions << createAction("increase_font_size", i18n("Larger"), "increase-font-size", SLOT(increaseTextSize())); - m_richTextActions << createAction("decrease_text_size", + m_richTextActions << createAction("decrease_font_size", i18n("Smaller"), "decrease-font-size", SLOT(decreaseTextSize())); m_richTextActions << createAction("align_left", i18n("Align Left"), "align-left", SLOT(alignLeft())); m_richTextActions << createAction("align_right", i18n("Alight Right"), "align-right", SLOT(alignRight())); m_richTextActions << createAction("align_center", i18n("Align Center"), "align-center", SLOT(alignCenter())); - m_richTextActions << createAction("align_justified", - i18n("Alight Justified"), - "align-justified", - SLOT(alignJustified())); +// m_richTextActions << createAction("align_justified", +// i18n("Alight Justified"), +// "align-justified", +// SLOT(alignJustified())); // Settings: configure toolbars m_richTextActions << createAction("options_shape_properties", i18n("Properties"), - "settings", + "svg_settings", SLOT(setShapeProperties())); KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbars()), actionCollection()); QWidgetAction *fontComboAction = new QWidgetAction(this); fontComboAction->setToolTip(i18n("Font")); KisFontComboBoxes *fontCombo = new KisFontComboBoxes(); connect(fontCombo, SIGNAL(fontChanged(QString)), SLOT(setFont(QString))); fontComboAction->setDefaultWidget(fontCombo); - actionCollection()->addAction("font", fontComboAction); + actionCollection()->addAction("svg_font", fontComboAction); m_richTextActions << fontComboAction; + actionRegistry->propertizeAction("svg_font", fontComboAction); QWidgetAction *fontSizeAction = new QWidgetAction(this); fontSizeAction->setToolTip(i18n("Size")); QComboBox *fontSizeCombo = new QComboBox(); Q_FOREACH (int size, QFontDatabase::standardSizes()) { fontSizeCombo->addItem(QString::number(size)); } fontSizeCombo->setCurrentIndex(QFontDatabase::standardSizes().indexOf(QApplication::font().pointSize())); connect(fontSizeCombo, SIGNAL(activated(QString)), SLOT(setFontSize(QString))); fontSizeAction->setDefaultWidget(fontSizeCombo); - actionCollection()->addAction("font_size", fontSizeAction); + actionCollection()->addAction("svg_font_size", fontSizeAction); m_richTextActions << fontSizeAction; + actionRegistry->propertizeAction("svg_font_size", fontSizeAction); + KoColorPopupAction *fgColor = new KoColorPopupAction(this); fgColor->setCurrentColor(QColor(Qt::black)); fgColor->setToolTip(i18n("Text Color")); connect(fgColor, SIGNAL(colorChanged(KoColor)), SLOT(setFontColor(KoColor))); - actionCollection()->addAction("font_color", fgColor); + actionCollection()->addAction("svg_format_textcolor", fgColor); m_richTextActions << fgColor; + actionRegistry->propertizeAction("svg_format_textcolor", fgColor); KoColorPopupAction *bgColor = new KoColorPopupAction(this); bgColor->setCurrentColor(QColor(Qt::white)); bgColor->setToolTip(i18n("Background Color")); connect(bgColor, SIGNAL(colorChanged(KoColor)), SLOT(setBackgroundColor(KoColor))); - actionCollection()->addAction("background_color", bgColor); + actionCollection()->addAction("svg_background_color", bgColor); + actionRegistry->propertizeAction("svg_background_color", bgColor); m_richTextActions << bgColor; QWidgetAction *lineHeight = new QWidgetAction(this); lineHeight->setToolTip(i18n("Line height")); QDoubleSpinBox *spnLineHeight = new QDoubleSpinBox(); spnLineHeight->setRange(0.0, 99.0); spnLineHeight->setSingleStep(0.1); spnLineHeight->setSuffix(i18n(" em"));//Does this need to be translated? connect(spnLineHeight, SIGNAL(valueChanged(double)), SLOT(setLineHeight(double))); lineHeight->setDefaultWidget(spnLineHeight); actionCollection()->addAction("line_height", lineHeight); m_richTextActions << lineHeight; + actionRegistry->propertizeAction("line_height", lineHeight); } void SvgTextEditor::enableRichTextActions(bool enable) { Q_FOREACH(QAction *action, m_richTextActions) { action->setEnabled(enable); } } diff --git a/plugins/tools/svgtexttool/SvgTextEditor.h b/plugins/tools/svgtexttool/SvgTextEditor.h index b4688c2851..9374503a51 100644 --- a/plugins/tools/svgtexttool/SvgTextEditor.h +++ b/plugins/tools/svgtexttool/SvgTextEditor.h @@ -1,145 +1,144 @@ /* This file is part of the KDE project * * Copyright 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef TEXTNGSHAPECONFIGWIDGET_H #define TEXTNGSHAPECONFIGWIDGET_H #include #include #include #include #include //for the enums #include "ui_WdgSvgTextEditor.h" class KoSvgTextShape; class KisFileNameRequester; class KoDialog; class SvgTextEditor : public KXmlGuiWindow { Q_OBJECT public: SvgTextEditor(QWidget *parent = 0, Qt::WindowFlags flags = 0); ~SvgTextEditor(); //tiny enum to keep track of the tab on which editor something happens while keeping the code readable. enum Editor { Richtext, // 0 SVGsource // 1 }; void setShape(KoSvgTextShape *shape); private Q_SLOTS: /** * switch the text editor tab. */ void switchTextEditorTab(); /** * in rich text, check the current format, and toggle the given buttons. */ void checkFormat(); void save(); void undo(); void redo(); void cut(); void copy(); void paste(); void selectAll(); void deselect(); void find(); void findNext(); void findPrev(); void replace(); void zoomOut(); void zoomIn(); void showInsertSpecialCharacterDialog(); void insertCharacter(const QChar &c); void setTextBold(QFont::Weight weight = QFont::Bold); void setTextWeightLight(); void setTextWeightNormal(); void setTextWeightDemi(); void setTextWeightBlack(); void setTextItalic(QFont::Style style = QFont::StyleOblique); void setTextDecoration(KoSvgText::TextDecoration decor); void setTextUnderline(); void setTextOverline(); void setTextStrikethrough(); void setTextSubscript(); void setTextSuperScript(); void increaseTextSize(); void decreaseTextSize(); void setLineHeight(double lineHeightEm); void alignLeft(); void alignRight(); void alignCenter(); void alignJustified(); void setFont(const QString &fontName); void setFontSize(const QString &size); void setBaseline(KoSvgText::BaselineShiftMode baseline); void setShapeProperties(); void slotConfigureToolbars(); void slotToolbarToggled(bool); void setFontColor(const KoColor &c); void setBackgroundColor(const KoColor &c); void setModified(bool modified); void dialogButtonClicked(QAbstractButton *button); Q_SIGNALS: void textUpdated(const QString &svg, const QString &defs); protected: void wheelEvent(QWheelEvent *event) override; private: QAction *createAction(const QString &name, const QString &text, const QString &icon, - const char *member, - const QKeySequence &shortcut = QKeySequence()); + const char *member); void createActions(); void enableRichTextActions(bool enable); Ui_WdgSvgTextEditor m_textEditorWidget; QTextEdit *m_currentEditor {0}; QWidget *m_page {0}; QList m_richTextActions; KoSvgTextShape *m_shape {0}; KoDialog *m_charSelectDialog {0}; }; #endif //TEXTNGSHAPECONFIGWIDGET_H diff --git a/plugins/tools/svgtexttool/SvgTextTool.action b/plugins/tools/svgtexttool/SvgTextTool.action new file mode 100644 index 0000000000..369ed511c4 --- /dev/null +++ b/plugins/tools/svgtexttool/SvgTextTool.action @@ -0,0 +1,216 @@ + + + + SVG Text Tool + + Text Color + + Text Color... + format-text-color + + + false + Text Color + + + Background + + Background Color... + format-fill-color + + + false + Background + + + Font Size + + Font Size + + + + false + Font Size + + + Font + Ctrl+Alt+F + Change character size, font, boldface, italics etc. + + Change the attributes of the currently selected characters. + + false + Font... + + + Special Character + Alt+Shift+C + Insert one or more symbols or characters not found on the keyboard + character-set + Insert one or more symbols or characters not found on the keyboard. + + false + Special Character... + + + Align Right + Ctrl+Alt+R + Align Right + format-justify-right + + + false + Align Right + + + Align Left + + Align Left + format-justify-left + + + false + Align Left + + + Align Block + Ctrl+Alt+R + Align Block + format-justify-fill + + + false + Align Block + + + Align Center + Ctrl+Alt+C + Align Center + format-justify-center + + + false + Align Center + + + Decrease Font Size + Ctrl+< + Decrease Font Size + + + + false + Decrease Font Size + + + Increase Font Size + Ctrl+> + Increase Font Size + + + + false + Increase Font Size + + + Subscript + Ctrl+Shift+B + Subscript + format-text-subscript + + + false + Subscript + + + Superscript + Ctrl+Shift+P + Superscript + format-text-superscript + + + false + Superscript + + + Underline + Ctrl+U + Underline + format-text-underline + + + false + Underline + + + Strikethrough + + Strikethrough + format-text-strikethrough + + + false + Strikethrough + + + Italic + Ctrl+I + Italic + format-text-italic + + + false + Italic + + + Bold + Ctrl+B + Bold + format-text-bold + + + false + Bold + + + Normal + Ctrl+N + Normal + format-text-normal + + + false + Normal + + + Demi + + Demi + format-text-demi + + + false + Demi + + + Black + + Black + format-text-black + + + false + Black + + + Light + Ctrl+L + Light + format-text-light + + + false + Light + + + diff --git a/plugins/tools/svgtexttool/svgtexttool.xmlgui b/plugins/tools/svgtexttool/svgtexttool.xmlgui index cd822504ba..58aacf9720 100644 --- a/plugins/tools/svgtexttool/svgtexttool.xmlgui +++ b/plugins/tools/svgtexttool/svgtexttool.xmlgui @@ -1,89 +1,89 @@ &File &Edit &View &Insert &Format - - - - - + + + + + &Weight - + Setti&ngs File Formatting - - + + - - + + - - + +