diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20e1a84..02a2535 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,169 +1,170 @@ add_subdirectory(ksendbugmail) if (HAVE_ATTICA) set (XMLGUI_EXTRA_LIBS ${XMLGUI_EXTRA_LIBS} KF5::Attica) endif () if (HAVE_GLOBALACCEL) set (XMLGUI_EXTRA_LIBS ${XMLGUI_EXTRA_LIBS} KF5::GlobalAccel) endif () if(WIN32) set (XMLGUI_EXTRA_LIBS ${XMLGUI_EXTRA_LIBS} secur32) # GetUserNameEx() endif() configure_file(config-xmlgui.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-xmlgui.h ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/kaboutapplicationconfigattica_p.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kaboutapplicationconfigattica_p.h ) set(kxmlgui_SRCS kaboutapplicationdialog.cpp kaboutapplicationpersonlistdelegate_p.cpp kaboutapplicationpersonlistview_p.cpp kaboutapplicationpersonmodel_p.cpp kaboutkdedialog_p.cpp kactioncategory.cpp kactioncollection.cpp kactionconflictdetector.cpp kbugreport.cpp kedittoolbar.cpp kgesture.cpp kgesturemap.cpp khelpmenu.cpp kkeysequencewidget.cpp kmainwindow.cpp kmainwindowiface.cpp kmenumenuhandler_p.cpp kshortcuteditwidget.cpp kshortcutschemeseditor.cpp kshortcutschemeshelper.cpp kshortcutsdialog.cpp kshortcutseditor.cpp kshortcutseditordelegate.cpp kshortcutseditoritem.cpp kshortcutwidget.cpp kswitchlanguagedialog_p.cpp ktoggletoolbaraction.cpp ktoolbar.cpp ktoolbarhandler.cpp + ktoolbarhelper.cpp kxmlguibuilder.cpp kxmlguiclient.cpp kxmlguifactory.cpp kxmlguifactory_p.cpp kxmlguiversionhandler.cpp kxmlguiwindow.cpp kundoactions.cpp kcheckaccelerators.cpp ) # add the resource file qt5_add_resources(kxmlgui_SRCS kxmlgui.qrc) ecm_qt_declare_logging_category(kxmlgui_SRCS HEADER debug.h IDENTIFIER DEBUG_KXMLGUI CATEGORY_NAME kf5.kxmlgui) set(kxmlgui_UI kshortcutsdialog.ui kshortcutwidget.ui ) ki18n_wrap_ui(kxmlgui_SRCS ${kxmlgui_UI} ) add_library(KF5XmlGui ${kxmlgui_SRCS}) generate_export_header(KF5XmlGui BASE_NAME KXmlGui) add_library(KF5::XmlGui ALIAS KF5XmlGui) target_include_directories(KF5XmlGui INTERFACE "$") target_link_libraries(KF5XmlGui PUBLIC Qt5::DBus #QDBus connect to signal in KToolBar Qt5::Xml #To parse the configuration (QDomDocument etc) Qt5::Widgets #QWidget is used everywhere KF5::ConfigCore #Reading config for ToolbarIcons, Shortcut Schemes... KF5::ConfigWidgets #KStandardAction, KToggleAction... PRIVATE Qt5::Network #QNetworkAccessManager in kaboutapplicationpersonmodel_p Qt5::PrintSupport #QPrinter in kshortcutseditor KF5::CoreAddons #KAboutData KF5::WidgetsAddons KF5::ItemViews #KWidgetItemDelegate in KAboutApplicationPersonListDelegate KF5::I18n #i18n and i18nc in many places KF5::IconThemes #KIconLoader and KIconThemes in KToolBar KF5::TextWidgets #KTextEdit in kbugreport KF5::WindowSystem #KKeyServer in kkeysequencewidget ${XMLGUI_EXTRA_LIBS} ) set_target_properties(KF5XmlGui PROPERTIES VERSION ${KXMLGUI_VERSION_STRING} SOVERSION ${KXMLGUI_SOVERSION} EXPORT_NAME XmlGui ) ecm_generate_headers(KXmlGui_HEADERS HEADER_NAMES KAboutApplicationDialog KActionCategory KActionCollection KBugReport KEditToolBar KHelpMenu KKeySequenceWidget KMainWindow KShortcutsDialog KShortcutsEditor KShortcutWidget KToggleToolBarAction KToolBar KXMLGUIBuilder KXMLGUIClient KXMLGUIFactory KXmlGuiWindow KUndoActions REQUIRED_HEADERS KXmlGui_HEADERS ) install(TARGETS KF5XmlGui EXPORT KF5XmlGuiTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES kgesture_p.h kgesturemap_p.h ${CMAKE_CURRENT_BINARY_DIR}/kxmlgui_export.h ${KXmlGui_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KXmlGui COMPONENT Devel ) # install this file to be compatible, it is bundled in the resource file, too install( FILES ui_standards.rc DESTINATION ${KDE_INSTALL_CONFDIR}/ui ) if (BUILD_QCH) ecm_add_qch( KF5XmlGui_QCH NAME KXmlGui BASE_NAME KF5XmlGui VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KXmlGui_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics" LINK_QCHS Qt5Xml_QCH Qt5DBus_QCH Qt5Widgets_QCH KF5Config_QCH KF5ConfigWidgets_QCH BLANK_MACROS KXMLGUI_EXPORT KXMLGUI_DEPRECATED_EXPORT KXMLGUI_DEPRECATED TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KXmlGui LIB_NAME KF5XmlGui DEPS "dbus xml widgets KConfigCore KConfigWidgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KXmlGui) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/kedittoolbar.cpp b/src/kedittoolbar.cpp index ca77a38..90344d0 100644 --- a/src/kedittoolbar.cpp +++ b/src/kedittoolbar.cpp @@ -1,1728 +1,1711 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Kurt Granroth Copyright (C) 2006 Hamish Rodda Copyright 2007 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "kedittoolbar.h" #include "kedittoolbar_p.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 "kactioncollection.h" #include "kxmlguifactory.h" #include "ktoolbar.h" +#include "ktoolbarhelper_p.h" #include "../kxmlgui_version.h" static const char separatorstring[] = I18N_NOOP("--- separator ---"); #define SEPARATORSTRING i18n(separatorstring) //static const char *const s_XmlTypeToString[] = { "Shell", "Part", "Local", "Merged" }; typedef QList ToolBarList; namespace KDEPrivate { /** * Return a list of toolbar elements given a toplevel element */ static ToolBarList findToolBars(const QDomElement &start) { ToolBarList list; for (QDomElement elem = start; !elem.isNull(); elem = elem.nextSiblingElement()) { if (elem.tagName() == QStringLiteral("ToolBar")) { if (elem.attribute(QStringLiteral("noEdit")) != QLatin1String("true")) { list.append(elem); } } else { if (elem.tagName() != QStringLiteral("MenuBar")) { // there are no toolbars inside the menubar :) list += findToolBars(elem.firstChildElement()); // recursive } } } return list; } class XmlData { public: enum XmlType { Shell = 0, Part, Local, Merged }; explicit XmlData(XmlType xmlType, const QString &xmlFile, KActionCollection *collection) : m_isModified(false), m_xmlFile(xmlFile), m_type(xmlType), m_actionCollection(collection) { } void dump() const { #if 0 qDebug(240) << "XmlData" << this << "type" << s_XmlTypeToString[m_type] << "xmlFile:" << m_xmlFile; foreach (const QDomElement &element, m_barList) { qDebug(240) << " ToolBar:" << toolBarText(element); } if (m_actionCollection) { qDebug(240) << " " << m_actionCollection->actions().count() << "actions in the collection."; } else { qDebug(240) << " no action collection."; } #endif } QString xmlFile() const { return m_xmlFile; } XmlType type() const { return m_type; } KActionCollection *actionCollection() const { return m_actionCollection; } void setDomDocument(const QDomDocument &domDoc) { m_document = domDoc.cloneNode().toDocument(); m_barList = findToolBars(m_document.documentElement()); } // Return reference, for e.g. actionPropertiesElement() to modify the document QDomDocument &domDocument() { return m_document; } const QDomDocument &domDocument() const { return m_document; } /** * Return the text (user-visible name) of a given toolbar */ QString toolBarText(const QDomElement &it) const; bool m_isModified; ToolBarList &barList() { return m_barList; } const ToolBarList &barList() const { return m_barList; } private: ToolBarList m_barList; QString m_xmlFile; QDomDocument m_document; XmlType m_type; KActionCollection *m_actionCollection; }; QString XmlData::toolBarText(const QDomElement &it) const { - const QLatin1String attrName("name"); - - QString name; - QByteArray txt(it.namedItem(QStringLiteral("text")).toElement().text().toUtf8()); - if (txt.isEmpty()) { - txt = it.namedItem(QStringLiteral("text")).toElement().text().toUtf8(); - } - if (txt.isEmpty()) { - name = it.attribute(attrName); - } else { - QByteArray domain = it.namedItem(QStringLiteral("text")).toElement().attribute(QStringLiteral("translationDomain")).toUtf8(); - if (domain.isEmpty()) { - domain = it.ownerDocument().documentElement().attribute(QStringLiteral("translationDomain")).toUtf8(); - if (domain.isEmpty()) { - domain = KLocalizedString::applicationDomain(); - } - } - name = i18nd(domain.constData(), txt.constData()); - } + QString name = KToolbarHelper::i18nToolBarName(it); // the name of the toolbar might depend on whether or not // it is in kparts if ((m_type == XmlData::Shell) || (m_type == XmlData::Part)) { - QString doc_name(m_document.documentElement().attribute(attrName)); + QString doc_name(m_document.documentElement().attribute(QStringLiteral("name"))); name += QStringLiteral(" <") + doc_name + QLatin1Char('>'); } return name; } typedef QList XmlDataList; class ToolBarItem : public QListWidgetItem { public: ToolBarItem(QListWidget *parent, const QString &tag = QString(), const QString &name = QString(), const QString &statusText = QString()) : QListWidgetItem(parent), m_internalTag(tag), m_internalName(name), m_statusText(statusText), m_isSeparator(false), m_isTextAlongsideIconHidden(false) { // Drop between items, not onto items setFlags((flags() | Qt::ItemIsDragEnabled) & ~Qt::ItemIsDropEnabled); } void setInternalTag(const QString &tag) { m_internalTag = tag; } void setInternalName(const QString &name) { m_internalName = name; } void setStatusText(const QString &text) { m_statusText = text; } void setSeparator(bool sep) { m_isSeparator = sep; } void setTextAlongsideIconHidden(bool hidden) { m_isTextAlongsideIconHidden = hidden; } QString internalTag() const { return m_internalTag; } QString internalName() const { return m_internalName; } QString statusText() const { return m_statusText; } bool isSeparator() const { return m_isSeparator; } bool isTextAlongsideIconHidden() const { return m_isTextAlongsideIconHidden; } int index() const { return listWidget()->row(const_cast(this)); } private: QString m_internalTag; QString m_internalName; QString m_statusText; bool m_isSeparator; bool m_isTextAlongsideIconHidden; }; static QDataStream &operator<< (QDataStream &s, const ToolBarItem &item) { s << item.internalTag(); s << item.internalName(); s << item.statusText(); s << item.isSeparator(); s << item.isTextAlongsideIconHidden(); return s; } static QDataStream &operator>> (QDataStream &s, ToolBarItem &item) { QString internalTag; s >> internalTag; item.setInternalTag(internalTag); QString internalName; s >> internalName; item.setInternalName(internalName); QString statusText; s >> statusText; item.setStatusText(statusText); bool sep; s >> sep; item.setSeparator(sep); bool hidden; s >> hidden; item.setTextAlongsideIconHidden(hidden); return s; } //// ToolBarListWidget::ToolBarListWidget(QWidget *parent) : QListWidget(parent), m_activeList(true) { setDragDropMode(QAbstractItemView::DragDrop); // no internal moves } QMimeData *ToolBarListWidget::mimeData(const QList items) const { if (items.isEmpty()) { return nullptr; } QMimeData *mimedata = new QMimeData(); QByteArray data; { QDataStream stream(&data, QIODevice::WriteOnly); // we only support single selection ToolBarItem *item = static_cast(items.first()); stream << *item; } mimedata->setData(QStringLiteral("application/x-kde-action-list"), data); mimedata->setData(QStringLiteral("application/x-kde-source-treewidget"), m_activeList ? "active" : "inactive"); return mimedata; } bool ToolBarListWidget::dropMimeData(int index, const QMimeData *mimeData, Qt::DropAction action) { Q_UNUSED(action) const QByteArray data = mimeData->data(QStringLiteral("application/x-kde-action-list")); if (data.isEmpty()) { return false; } QDataStream stream(data); const bool sourceIsActiveList = mimeData->data(QStringLiteral("application/x-kde-source-treewidget")) == "active"; ToolBarItem *item = new ToolBarItem(this); // needs parent, use this temporarily stream >> *item; emit dropped(this, index, item, sourceIsActiveList); return true; } ToolBarItem *ToolBarListWidget::currentItem() const { return static_cast(QListWidget::currentItem()); } IconTextEditDialog::IconTextEditDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("Change Text")); setModal(true); QVBoxLayout *layout = new QVBoxLayout; setLayout(layout); QGridLayout *grid = new QGridLayout; grid->setMargin(0); m_lineEdit = new QLineEdit(this); m_lineEdit->setClearButtonEnabled(true); QLabel *label = new QLabel(i18n("Icon te&xt:"), this); label->setBuddy(m_lineEdit); grid->addWidget(label, 0, 0); grid->addWidget(m_lineEdit, 0, 1); m_cbHidden = new QCheckBox(i18n("&Hide text when toolbar shows text alongside icons"), this); grid->addWidget(m_cbHidden, 1, 1); layout->addLayout(grid); m_buttonBox = new QDialogButtonBox(this); m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); layout->addWidget(m_buttonBox); connect(m_lineEdit, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString))); m_lineEdit->setFocus(); setFixedHeight(sizeHint().height()); } void IconTextEditDialog::setIconText(const QString &text) { m_lineEdit->setText(text); } QString IconTextEditDialog::iconText() const { return m_lineEdit->text().trimmed(); } void IconTextEditDialog::setTextAlongsideIconHidden(bool hidden) { m_cbHidden->setChecked(hidden); } bool IconTextEditDialog::textAlongsideIconHidden() const { return m_cbHidden->isChecked(); } void IconTextEditDialog::slotTextChanged(const QString &text) { // Do not allow empty icon text m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.trimmed().isEmpty()); } class KEditToolBarWidgetPrivate { public: /** * * @param collection In the old-style constructor, this is the collection passed * to the KEditToolBar constructor. * In the xmlguifactory-based constructor, we let KXMLGUIClient create a dummy one, * but it probably isn't used. */ KEditToolBarWidgetPrivate(KEditToolBarWidget *widget, const QString &cName, KActionCollection *collection) : m_collection(collection), m_widget(widget), m_factory(nullptr), m_loadedOnce(false) { m_componentName = cName; m_isPart = false; m_helpArea = nullptr; // We want items with an icon to align with items without icon // So we use an empty QPixmap for that const int iconSize = widget->style()->pixelMetric(QStyle::PM_SmallIconSize); m_emptyIcon = QPixmap(iconSize, iconSize); m_emptyIcon.fill(Qt::transparent); } ~KEditToolBarWidgetPrivate() { } // private slots void slotToolBarSelected(int index); void slotInactiveSelectionChanged(); void slotActiveSelectionChanged(); void slotInsertButton(); void slotRemoveButton(); void slotUpButton(); void slotDownButton(); void selectActiveItem(const QString &); void slotChangeIcon(); void slotChangeIconText(); void slotDropped(ToolBarListWidget *list, int index, ToolBarItem *item, bool sourceIsActiveList); void setupLayout(); void initOldStyle(const QString &file, bool global, const QString &defaultToolbar); void initFromFactory(KXMLGUIFactory *factory, const QString &defaultToolbar); void loadToolBarCombo(const QString &defaultToolbar); void loadActions(const QDomElement &elem); QString xmlFile(const QString &xml_file) const { return xml_file.isEmpty() ? m_componentName + QStringLiteral("ui.rc") : xml_file; } /** * Load in the specified XML file and dump the raw xml */ QString loadXMLFile(const QString &_xml_file) { QString raw_xml; QString xml_file = xmlFile(_xml_file); //qDebug() << "loadXMLFile xml_file=" << xml_file; if (!QDir::isRelativePath(xml_file)) { raw_xml = KXMLGUIFactory::readConfigFile(xml_file); } else { raw_xml = KXMLGUIFactory::readConfigFile(xml_file, m_componentName); } return raw_xml; } /** * Look for a given item in the current toolbar */ QDomElement findElementForToolBarItem(const ToolBarItem *item) const { //qDebug(240) << "looking for name=" << item->internalName() << "and tag=" << item->internalTag(); for (QDomNode n = m_currentToolBarElem.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement elem = n.toElement(); if ((elem.attribute(QStringLiteral("name")) == item->internalName()) && (elem.tagName() == item->internalTag())) { return elem; } } //qDebug(240) << "no item found in the DOM with name=" << item->internalName() << "and tag=" << item->internalTag(); return QDomElement(); } void insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend = false); void removeActive(ToolBarItem *item); void moveActive(ToolBarItem *item, ToolBarItem *before); void updateLocal(QDomElement &elem); #ifndef NDEBUG void dump() const { XmlDataList::const_iterator xit = m_xmlFiles.begin(); for (; xit != m_xmlFiles.end(); ++xit) { (*xit).dump(); } } #endif QComboBox *m_toolbarCombo; QToolButton *m_upAction; QToolButton *m_removeAction; QToolButton *m_insertAction; QToolButton *m_downAction; //QValueList m_actionList; KActionCollection *m_collection; KEditToolBarWidget *m_widget; KXMLGUIFactory *m_factory; QString m_componentName; QPixmap m_emptyIcon; XmlData *m_currentXmlData; QDomElement m_currentToolBarElem; QString m_xmlFile; QString m_globalFile; QString m_rcFile; QDomDocument m_localDoc; ToolBarList m_barList; ToolBarListWidget *m_inactiveList; ToolBarListWidget *m_activeList; XmlDataList m_xmlFiles; QLabel *m_comboLabel; KSeparator *m_comboSeparator; QLabel *m_helpArea; QPushButton *m_changeIcon; QPushButton *m_changeIconText; bool m_isPart : 1; bool m_loadedOnce : 1; }; } using namespace KDEPrivate; class KEditToolBarPrivate { public: KEditToolBarPrivate(KEditToolBar *q): q(q), m_accept(false), m_global(false), m_collection(nullptr), m_factory(nullptr), m_widget(nullptr) {} void init(); void _k_slotButtonClicked(QAbstractButton *button); void _k_acceptOK(bool); void _k_enableApply(bool); void okClicked(); void applyClicked(); void defaultClicked(); KEditToolBar *q; bool m_accept; // Save parameters for recreating widget after resetting toolbar bool m_global; KActionCollection *m_collection; QString m_file; QString m_defaultToolBar; KXMLGUIFactory *m_factory; KEditToolBarWidget *m_widget; QVBoxLayout *m_layout; QDialogButtonBox *m_buttonBox; }; Q_GLOBAL_STATIC(QString, s_defaultToolBarName) KEditToolBar::KEditToolBar(KActionCollection *collection, QWidget *parent) : QDialog(parent), d(new KEditToolBarPrivate(this)) { d->m_widget = new KEditToolBarWidget(collection, this); d->init(); d->m_collection = collection; } KEditToolBar::KEditToolBar(KXMLGUIFactory *factory, QWidget *parent) : QDialog(parent), d(new KEditToolBarPrivate(this)) { d->m_widget = new KEditToolBarWidget(this); d->init(); d->m_factory = factory; } void KEditToolBarPrivate::init() { m_accept = false; m_factory = nullptr; q->setDefaultToolBar(QString()); q->setWindowTitle(i18n("Configure Toolbars")); q->setModal(false); m_layout = new QVBoxLayout; q->setLayout(m_layout); m_layout->addWidget(m_widget); m_buttonBox = new QDialogButtonBox(q); m_buttonBox->setStandardButtons(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); KGuiItem::assign(m_buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); KGuiItem::assign(m_buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::apply()); KGuiItem::assign(m_buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); KGuiItem::assign(m_buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); q->connect(m_buttonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(_k_slotButtonClicked(QAbstractButton*))); q->connect(m_buttonBox, SIGNAL(rejected()), SLOT(reject())); m_layout->addWidget(m_buttonBox); q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool))); q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_enableApply(bool))); _k_enableApply(false); q->setMinimumSize(q->sizeHint()); } void KEditToolBar::setResourceFile(const QString &file, bool global) { d->m_file = file; d->m_global = global; d->m_widget->load(d->m_file, d->m_global, d->m_defaultToolBar); } KEditToolBar::~KEditToolBar() { delete d; s_defaultToolBarName()->clear(); } void KEditToolBar::setDefaultToolBar(const QString &toolBarName) { if (toolBarName.isEmpty()) { d->m_defaultToolBar = *s_defaultToolBarName(); } else { d->m_defaultToolBar = toolBarName; } } void KEditToolBarPrivate::_k_acceptOK(bool b) { m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(b); m_accept = b; } void KEditToolBarPrivate::_k_enableApply(bool b) { m_buttonBox->button(QDialogButtonBox::Apply)->setEnabled(b); } void KEditToolBarPrivate::defaultClicked() { if (KMessageBox::warningContinueCancel(q, i18n("Do you really want to reset all toolbars of this application to their default? The changes will be applied immediately."), i18n("Reset Toolbars"), KGuiItem(i18n("Reset"))) != KMessageBox::Continue) { return; } KEditToolBarWidget *oldWidget = m_widget; m_widget = nullptr; m_accept = false; if (m_factory) { foreach (KXMLGUIClient *client, m_factory->clients()) { const QString file = client->localXMLFile(); if (file.isEmpty()) { continue; } //qDebug(240) << "Deleting local xml file" << file; // << "for client" << client << typeid(*client).name(); if (QFile::exists(file)) if (!QFile::remove(file)) { qWarning() << "Could not delete" << file; } } // Reload the xml files in all clients, now that the local files are gone oldWidget->rebuildKXMLGUIClients(); m_widget = new KEditToolBarWidget(q); m_widget->load(m_factory, m_defaultToolBar); } else { int slash = m_file.lastIndexOf(QLatin1Char('/')) + 1; if (slash) { m_file = m_file.mid(slash); } const QString xml_file = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kxmlgui5/") + QCoreApplication::instance()->applicationName() + QLatin1Char('/') + m_file; if (QFile::exists(xml_file)) if (!QFile::remove(xml_file)) { qWarning() << "Could not delete " << xml_file; } m_widget = new KEditToolBarWidget(m_collection, q); q->setResourceFile(m_file, m_global); } // Copy the geometry to minimize UI flicker m_widget->setGeometry(oldWidget->geometry()); delete oldWidget; m_layout->insertWidget(0, m_widget); q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_acceptOK(bool))); q->connect(m_widget, SIGNAL(enableOk(bool)), SLOT(_k_enableApply(bool))); _k_enableApply(false); emit q->newToolBarConfig(); emit q->newToolbarConfig(); // compat } void KEditToolBarPrivate::_k_slotButtonClicked(QAbstractButton *button) { QDialogButtonBox::StandardButton type = m_buttonBox->standardButton(button); switch (type) { case QDialogButtonBox::Ok: okClicked(); break; case QDialogButtonBox::Apply: applyClicked(); break; case QDialogButtonBox::RestoreDefaults: defaultClicked(); break; default: break; } } void KEditToolBarPrivate::okClicked() { if (!m_accept) { q->reject(); return; } // Do not rebuild GUI and emit the "newToolBarConfig" signal again here if the "Apply" // button was already pressed and no further changes were made. if (m_buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) { m_widget->save(); emit q->newToolBarConfig(); emit q->newToolbarConfig(); // compat } q->accept(); } void KEditToolBarPrivate::applyClicked() { (void)m_widget->save(); _k_enableApply(false); emit q->newToolBarConfig(); emit q->newToolbarConfig(); // compat } void KEditToolBar::setGlobalDefaultToolBar(const char *toolbarName) { *s_defaultToolBarName() = QString::fromLatin1(toolbarName); } KEditToolBarWidget::KEditToolBarWidget(KActionCollection *collection, QWidget *parent) : QWidget(parent), d(new KEditToolBarWidgetPrivate(this, componentName(), collection)) { d->setupLayout(); } KEditToolBarWidget::KEditToolBarWidget(QWidget *parent) : QWidget(parent), d(new KEditToolBarWidgetPrivate(this, componentName(), KXMLGUIClient::actionCollection() /*create new one*/)) { d->setupLayout(); } KEditToolBarWidget::~KEditToolBarWidget() { delete d; } void KEditToolBarWidget::load(const QString &file, bool global, const QString &defaultToolBar) { d->initOldStyle(file, global, defaultToolBar); } void KEditToolBarWidget::load(KXMLGUIFactory *factory, const QString &defaultToolBar) { d->initFromFactory(factory, defaultToolBar); } void KEditToolBarWidgetPrivate::initOldStyle(const QString &resourceFile, bool global, const QString &defaultToolBar) { //TODO: make sure we can call this multiple times? if (m_loadedOnce) { return; } m_loadedOnce = true; //d->m_actionList = collection->actions(); // handle the merging if (global) { m_widget->loadStandardsXmlFile(); // ui_standards.rc } const QString localXML = loadXMLFile(resourceFile); m_widget->setXML(localXML, global ? true /*merge*/ : false); // first, get all of the necessary info for our local xml XmlData local(XmlData::Local, xmlFile(resourceFile), m_collection); QDomDocument domDoc; domDoc.setContent(localXML); local.setDomDocument(domDoc); m_xmlFiles.append(local); // then, the merged one (ui_standards + local xml) XmlData merge(XmlData::Merged, QString(), m_collection); merge.setDomDocument(m_widget->domDocument()); m_xmlFiles.append(merge); #ifndef NDEBUG dump(); #endif // now load in our toolbar combo box loadToolBarCombo(defaultToolBar); m_widget->adjustSize(); m_widget->setMinimumSize(m_widget->sizeHint()); } void KEditToolBarWidgetPrivate::initFromFactory(KXMLGUIFactory *factory, const QString &defaultToolBar) { //TODO: make sure we can call this multiple times? if (m_loadedOnce) { return; } m_loadedOnce = true; m_factory = factory; // add all of the client data bool first = true; foreach (KXMLGUIClient *client, factory->clients()) { if (client->xmlFile().isEmpty()) { continue; } XmlData::XmlType type = XmlData::Part; if (first) { type = XmlData::Shell; first = false; Q_ASSERT(!client->localXMLFile().isEmpty()); // where would we save changes?? } XmlData data(type, client->localXMLFile(), client->actionCollection()); QDomDocument domDoc = client->domDocument(); data.setDomDocument(domDoc); m_xmlFiles.append(data); //d->m_actionList += client->actionCollection()->actions(); } #ifndef NDEBUG //d->dump(); #endif // now load in our toolbar combo box loadToolBarCombo(defaultToolBar); m_widget->adjustSize(); m_widget->setMinimumSize(m_widget->sizeHint()); m_widget->actionCollection()->addAssociatedWidget(m_widget); foreach (QAction *action, m_widget->actionCollection()->actions()) { action->setShortcutContext(Qt::WidgetWithChildrenShortcut); } } void KEditToolBarWidget::save() { //qDebug(240) << "KEditToolBarWidget::save"; XmlDataList::Iterator it = d->m_xmlFiles.begin(); for (; it != d->m_xmlFiles.end(); ++it) { // let's not save non-modified files if (!((*it).m_isModified)) { continue; } // let's also skip (non-existent) merged files if ((*it).type() == XmlData::Merged) { continue; } // Add noMerge="1" to all the menus since we are saving the merged data QDomNodeList menuNodes = (*it).domDocument().elementsByTagName(QStringLiteral("Menu")); for (int i = 0; i < menuNodes.length(); ++i) { QDomNode menuNode = menuNodes.item(i); QDomElement menuElement = menuNode.toElement(); if (menuElement.isNull()) { continue; } menuElement.setAttribute(QStringLiteral("noMerge"), QStringLiteral("1")); } //qDebug() << (*it).domDocument().toString(); //qDebug(240) << "Saving " << (*it).xmlFile(); // if we got this far, we might as well just save it KXMLGUIFactory::saveConfigFile((*it).domDocument(), (*it).xmlFile()); } if (!d->m_factory) { return; } rebuildKXMLGUIClients(); } void KEditToolBarWidget::rebuildKXMLGUIClients() { if (!d->m_factory) { return; } const QList clients = d->m_factory->clients(); //qDebug(240) << "factory: " << clients.count() << " clients"; // remove the elements starting from the last going to the first if (clients.isEmpty()) { return; } QListIterator clientIterator = clients; clientIterator.toBack(); while (clientIterator.hasPrevious()) { KXMLGUIClient *client = clientIterator.previous(); //qDebug(240) << "factory->removeClient " << client; d->m_factory->removeClient(client); } KXMLGUIClient *firstClient = clients.first(); // now, rebuild the gui from the first to the last //qDebug(240) << "rebuilding the gui"; foreach (KXMLGUIClient *client, clients) { //qDebug(240) << "updating client " << client << " " << client->componentName() << " xmlFile=" << client->xmlFile(); QString file(client->xmlFile()); // before setting ui_standards! if (!file.isEmpty()) { // passing an empty stream forces the clients to reread the XML client->setXMLGUIBuildDocument(QDomDocument()); // for the shell, merge in ui_standards.rc if (client == firstClient) { // same assumption as in the ctor: first==shell client->loadStandardsXmlFile(); } // and this forces it to use the *new* XML file client->setXMLFile(file, client == firstClient /* merge if shell */); // [we can't use reloadXML, it doesn't load ui_standards.rc] } } // Now we can add the clients to the factory // We don't do it in the loop above because adding a part automatically // adds its plugins, so we must make sure the plugins were updated first. foreach (KXMLGUIClient *client, clients) { d->m_factory->addClient(client); } } void KEditToolBarWidgetPrivate::setupLayout() { // the toolbar name combo m_comboLabel = new QLabel(i18n("&Toolbar:"), m_widget); m_toolbarCombo = new QComboBox(m_widget); m_comboLabel->setBuddy(m_toolbarCombo); m_comboSeparator = new KSeparator(m_widget); QObject::connect(m_toolbarCombo, SIGNAL(activated(int)), m_widget, SLOT(slotToolBarSelected(int))); // QPushButton *new_toolbar = new QPushButton(i18n("&New"), this); // new_toolbar->setPixmap(BarIcon("document-new", KIconLoader::SizeSmall)); // new_toolbar->setEnabled(false); // disabled until implemented // QPushButton *del_toolbar = new QPushButton(i18n("&Delete"), this); // del_toolbar->setPixmap(BarIcon("edit-delete", KIconLoader::SizeSmall)); // del_toolbar->setEnabled(false); // disabled until implemented // our list of inactive actions QLabel *inactive_label = new QLabel(i18n("A&vailable actions:"), m_widget); m_inactiveList = new ToolBarListWidget(m_widget); m_inactiveList->setDragEnabled(true); m_inactiveList->setActiveList(false); m_inactiveList->setMinimumSize(180, 250); m_inactiveList->setDropIndicatorShown(false); // #165663 inactive_label->setBuddy(m_inactiveList); QObject::connect(m_inactiveList, SIGNAL(itemSelectionChanged()), m_widget, SLOT(slotInactiveSelectionChanged())); QObject::connect(m_inactiveList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), m_widget, SLOT(slotInsertButton())); QObject::connect(m_inactiveList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)), m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool))); KListWidgetSearchLine *inactiveListSearchLine = new KListWidgetSearchLine(m_widget, m_inactiveList); inactiveListSearchLine->setPlaceholderText(i18n("Filter")); // our list of active actions QLabel *active_label = new QLabel(i18n("Curr&ent actions:"), m_widget); m_activeList = new ToolBarListWidget(m_widget); m_activeList->setDragEnabled(true); m_activeList->setActiveList(true); // With Qt-4.1 only setting MiniumWidth results in a 0-width icon column ... m_activeList->setMinimumSize(m_inactiveList->minimumWidth(), 100); active_label->setBuddy(m_activeList); QObject::connect(m_activeList, SIGNAL(itemSelectionChanged()), m_widget, SLOT(slotActiveSelectionChanged())); QObject::connect(m_activeList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), m_widget, SLOT(slotRemoveButton())); QObject::connect(m_activeList, SIGNAL(dropped(ToolBarListWidget*,int,ToolBarItem*,bool)), m_widget, SLOT(slotDropped(ToolBarListWidget*,int,ToolBarItem*,bool))); KListWidgetSearchLine *activeListSearchLine = new KListWidgetSearchLine(m_widget, m_activeList); activeListSearchLine->setPlaceholderText(i18n("Filter")); // "change icon" button m_changeIcon = new QPushButton(i18n("Change &Icon..."), m_widget); m_changeIcon->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-icons"))); m_changeIcon->setEnabled(m_activeList->currentItem()); QObject::connect(m_changeIcon, SIGNAL(clicked()), m_widget, SLOT(slotChangeIcon())); // "change icon text" button m_changeIconText = new QPushButton(i18n("Change Te&xt..."), m_widget); m_changeIconText->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); m_changeIconText->setEnabled(m_activeList->currentItem() != nullptr); QObject::connect(m_changeIconText, SIGNAL(clicked()), m_widget, SLOT(slotChangeIconText())); // The buttons in the middle m_upAction = new QToolButton(m_widget); m_upAction->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); m_upAction->setEnabled(false); m_upAction->setAutoRepeat(true); QObject::connect(m_upAction, SIGNAL(clicked()), m_widget, SLOT(slotUpButton())); m_insertAction = new QToolButton(m_widget); m_insertAction->setIcon(QIcon::fromTheme(QApplication::isRightToLeft() ? QStringLiteral("go-previous") : QStringLiteral("go-next"))); m_insertAction->setEnabled(false); QObject::connect(m_insertAction, SIGNAL(clicked()), m_widget, SLOT(slotInsertButton())); m_removeAction = new QToolButton(m_widget); m_removeAction->setIcon(QIcon::fromTheme(QApplication::isRightToLeft() ? QStringLiteral("go-next") : QStringLiteral("go-previous"))); m_removeAction->setEnabled(false); QObject::connect(m_removeAction, SIGNAL(clicked()), m_widget, SLOT(slotRemoveButton())); m_downAction = new QToolButton(m_widget); m_downAction->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); m_downAction->setEnabled(false); m_downAction->setAutoRepeat(true); QObject::connect(m_downAction, SIGNAL(clicked()), m_widget, SLOT(slotDownButton())); m_helpArea = new QLabel(m_widget); m_helpArea->setWordWrap(true); // now start with our layouts QVBoxLayout *top_layout = new QVBoxLayout(m_widget); top_layout->setMargin(0); QVBoxLayout *name_layout = new QVBoxLayout(); QHBoxLayout *list_layout = new QHBoxLayout(); QVBoxLayout *inactive_layout = new QVBoxLayout(); QVBoxLayout *active_layout = new QVBoxLayout(); QHBoxLayout *changeIcon_layout = new QHBoxLayout(); QGridLayout *button_layout = new QGridLayout(); name_layout->addWidget(m_comboLabel); name_layout->addWidget(m_toolbarCombo); // name_layout->addWidget(new_toolbar); // name_layout->addWidget(del_toolbar); button_layout->setSpacing(0); button_layout->setRowStretch(0, 10); button_layout->addWidget(m_upAction, 1, 1); button_layout->addWidget(m_removeAction, 2, 0); button_layout->addWidget(m_insertAction, 2, 2); button_layout->addWidget(m_downAction, 3, 1); button_layout->setRowStretch(4, 10); inactive_layout->addWidget(inactive_label); inactive_layout->addWidget(inactiveListSearchLine); inactive_layout->addWidget(m_inactiveList, 1); active_layout->addWidget(active_label); active_layout->addWidget(activeListSearchLine); active_layout->addWidget(m_activeList, 1); active_layout->addLayout(changeIcon_layout); changeIcon_layout->addWidget(m_changeIcon); changeIcon_layout->addStretch(1); changeIcon_layout->addWidget(m_changeIconText); list_layout->addLayout(inactive_layout); list_layout->addLayout(button_layout); list_layout->addLayout(active_layout); top_layout->addLayout(name_layout); top_layout->addWidget(m_comboSeparator); top_layout->addLayout(list_layout, 10); top_layout->addWidget(m_helpArea); top_layout->addWidget(new KSeparator(m_widget)); } void KEditToolBarWidgetPrivate::loadToolBarCombo(const QString &defaultToolBar) { const QLatin1String attrName("name"); // just in case, we clear our combo m_toolbarCombo->clear(); int defaultToolBarId = -1; int count = 0; // load in all of the toolbar names into this combo box XmlDataList::const_iterator xit = m_xmlFiles.constBegin(); for (; xit != m_xmlFiles.constEnd(); ++xit) { // skip the merged one in favor of the local one, // so that we can change icons // This also makes the app-defined named for "mainToolBar" appear rather than the ui_standards-defined name. if ((*xit).type() == XmlData::Merged) { continue; } // each xml file may have any number of toolbars ToolBarList::const_iterator it = (*xit).barList().begin(); for (; it != (*xit).barList().constEnd(); ++it) { const QString text = (*xit).toolBarText(*it); m_toolbarCombo->addItem(text); const QString name = (*it).attribute(attrName); if (defaultToolBarId == -1 && name == defaultToolBar) { defaultToolBarId = count; } count++; } } const bool showCombo = (count > 1); m_comboLabel->setVisible(showCombo); m_comboSeparator->setVisible(showCombo); m_toolbarCombo->setVisible(showCombo); if (defaultToolBarId == -1) { defaultToolBarId = 0; } // we want to the specified item selected and its actions loaded m_toolbarCombo->setCurrentIndex(defaultToolBarId); slotToolBarSelected(m_toolbarCombo->currentIndex()); } void KEditToolBarWidgetPrivate::loadActions(const QDomElement &elem) { const QLatin1String tagSeparator("Separator"); const QLatin1String tagMerge("Merge"); const QLatin1String tagActionList("ActionList"); const QLatin1String tagAction("Action"); const QLatin1String attrName("name"); int sep_num = 0; QString sep_name(QStringLiteral("separator_%1")); // clear our lists m_inactiveList->clear(); m_activeList->clear(); m_insertAction->setEnabled(false); m_removeAction->setEnabled(false); m_upAction->setEnabled(false); m_downAction->setEnabled(false); // We'll use this action collection KActionCollection *actionCollection = m_currentXmlData->actionCollection(); // store the names of our active actions QSet active_list; // Filtering message requested by translators (scripting). KLocalizedString nameFilter = ki18nc("@item:intable Action name in toolbar editor", "%1"); // see if our current action is in this toolbar QDomNode n = elem.firstChild(); for (; !n.isNull(); n = n.nextSibling()) { QDomElement it = n.toElement(); if (it.isNull()) { continue; } if (it.tagName() == tagSeparator) { ToolBarItem *act = new ToolBarItem(m_activeList, tagSeparator, sep_name.arg(sep_num++), QString()); act->setSeparator(true); act->setText(SEPARATORSTRING); it.setAttribute(attrName, act->internalName()); continue; } if (it.tagName() == tagMerge) { // Merge can be named or not - use the name if there is one QString name = it.attribute(attrName); ToolBarItem *act = new ToolBarItem(m_activeList, tagMerge, name, i18n("This element will be replaced with all the elements of an embedded component.")); if (name.isEmpty()) { act->setText(i18n("")); } else { act->setText(i18n("", name)); } continue; } if (it.tagName() == tagActionList) { ToolBarItem *act = new ToolBarItem(m_activeList, tagActionList, it.attribute(attrName), i18n("This is a dynamic list of actions. You can move it, but if you remove it you will not be able to re-add it.")); act->setText(i18n("ActionList: %1", it.attribute(attrName))); continue; } // iterate through this client's actions // This used to iterate through _all_ actions, but we don't support // putting any action into any client... foreach (QAction *action, actionCollection->actions()) { // do we have a match? if (it.attribute(attrName) == action->objectName()) { // we have a match! ToolBarItem *act = new ToolBarItem(m_activeList, it.tagName(), action->objectName(), action->toolTip()); act->setText(nameFilter.subs(KLocalizedString::removeAcceleratorMarker(action->iconText())).toString()); act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon); act->setTextAlongsideIconHidden(action->priority() < QAction::NormalPriority); active_list.insert(action->objectName()); break; } } } // go through the rest of the collection foreach (QAction *action, actionCollection->actions()) { // skip our active ones if (active_list.contains(action->objectName())) { continue; } ToolBarItem *act = new ToolBarItem(m_inactiveList, tagAction, action->objectName(), action->toolTip()); act->setText(nameFilter.subs(KLocalizedString::removeAcceleratorMarker(action->text())).toString()); act->setIcon(!action->icon().isNull() ? action->icon() : m_emptyIcon); } m_inactiveList->sortItems(Qt::AscendingOrder); // finally, add default separators to the inactive list ToolBarItem *act = new ToolBarItem(nullptr, tagSeparator, sep_name.arg(sep_num++), QString()); act->setSeparator(true); act->setText(SEPARATORSTRING); m_inactiveList->insertItem(0, act); } KActionCollection *KEditToolBarWidget::actionCollection() const { return d->m_collection; } void KEditToolBarWidgetPrivate::slotToolBarSelected(int index) { const QLatin1String attrName("name"); // We need to find the XmlData and toolbar element for this index // To do that, we do the same iteration as the one which filled in the combobox. int toolbarNumber = 0; XmlDataList::iterator xit = m_xmlFiles.begin(); for (; xit != m_xmlFiles.end(); ++xit) { // skip the merged one in favor of the local one, // so that we can change icons if ((*xit).type() == XmlData::Merged) { continue; } // each xml file may have any number of toolbars ToolBarList::Iterator it = (*xit).barList().begin(); for (; it != (*xit).barList().end(); ++it) { // is this our toolbar? if (toolbarNumber == index) { // save our current settings m_currentXmlData = & (*xit); m_currentToolBarElem = *it; //qDebug() << "found toolbar" << m_currentXmlData->toolBarText(*it) << "m_currentXmlData set to"; m_currentXmlData->dump(); // If this is a Merged xmldata, clicking the "change icon" button would assert... Q_ASSERT(m_currentXmlData->type() != XmlData::Merged); // load in our values loadActions(m_currentToolBarElem); if ((*xit).type() == XmlData::Part || (*xit).type() == XmlData::Shell) { m_widget->setDOMDocument((*xit).domDocument()); } return; } ++toolbarNumber; } } } void KEditToolBarWidgetPrivate::slotInactiveSelectionChanged() { if (!m_inactiveList->selectedItems().isEmpty()) { m_insertAction->setEnabled(true); QString statusText = static_cast(m_inactiveList->selectedItems().first())->statusText(); m_helpArea->setText(i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText)); } else { m_insertAction->setEnabled(false); m_helpArea->setText(QString()); } } void KEditToolBarWidgetPrivate::slotActiveSelectionChanged() { ToolBarItem *toolitem = nullptr; if (!m_activeList->selectedItems().isEmpty()) { toolitem = static_cast(m_activeList->selectedItems().first()); } m_removeAction->setEnabled(toolitem); m_changeIcon->setEnabled(toolitem && toolitem->internalTag() == QStringLiteral("Action")); m_changeIconText->setEnabled(toolitem && toolitem->internalTag() == QStringLiteral("Action")); if (toolitem) { m_upAction->setEnabled(toolitem->index() != 0); m_downAction->setEnabled(toolitem->index() != toolitem->listWidget()->count() - 1); QString statusText = toolitem->statusText(); m_helpArea->setText(i18nc("@label Action tooltip in toolbar editor, below the action list", "%1", statusText)); } else { m_upAction->setEnabled(false); m_downAction->setEnabled(false); m_helpArea->setText(QString()); } } void KEditToolBarWidgetPrivate::slotInsertButton() { QString internalName = static_cast(m_inactiveList->currentItem())->internalName(); insertActive(m_inactiveList->currentItem(), m_activeList->currentItem(), false); // we're modified, so let this change emit m_widget->enableOk(true); slotToolBarSelected(m_toolbarCombo->currentIndex()); selectActiveItem(internalName); } void KEditToolBarWidgetPrivate::selectActiveItem(const QString &internalName) { int activeItemCount = m_activeList->count(); for (int i = 0; i < activeItemCount; i++) { ToolBarItem *item = static_cast(m_activeList->item(i)); if (item->internalName() == internalName) { m_activeList->setCurrentItem(item); break; } } } void KEditToolBarWidgetPrivate::slotRemoveButton() { removeActive(m_activeList->currentItem()); slotToolBarSelected(m_toolbarCombo->currentIndex()); } void KEditToolBarWidgetPrivate::insertActive(ToolBarItem *item, ToolBarItem *before, bool prepend) { if (!item) { return; } QDomElement new_item; // let's handle the separator specially if (item->isSeparator()) { new_item = m_widget->domDocument().createElement(QStringLiteral("Separator")); } else { new_item = m_widget->domDocument().createElement(QStringLiteral("Action")); } new_item.setAttribute(QStringLiteral("name"), item->internalName()); Q_ASSERT(!m_currentToolBarElem.isNull()); if (before) { // we have the item in the active list which is before the new // item.. so let's try our best to add our new item right after it QDomElement elem = findElementForToolBarItem(before); Q_ASSERT(!elem.isNull()); m_currentToolBarElem.insertAfter(new_item, elem); } else { // simply put it at the beginning or the end of the list. if (prepend) { m_currentToolBarElem.insertBefore(new_item, m_currentToolBarElem.firstChild()); } else { m_currentToolBarElem.appendChild(new_item); } } // and set this container as a noMerge m_currentToolBarElem.setAttribute(QStringLiteral("noMerge"), QStringLiteral("1")); // update the local doc updateLocal(m_currentToolBarElem); } void KEditToolBarWidgetPrivate::removeActive(ToolBarItem *item) { if (!item) { return; } // we're modified, so let this change emit m_widget->enableOk(true); // now iterate through to find the child to nuke QDomElement elem = findElementForToolBarItem(item); if (!elem.isNull()) { // nuke myself! m_currentToolBarElem.removeChild(elem); // and set this container as a noMerge m_currentToolBarElem.setAttribute(QStringLiteral("noMerge"), QStringLiteral("1")); // update the local doc updateLocal(m_currentToolBarElem); } } void KEditToolBarWidgetPrivate::slotUpButton() { ToolBarItem *item = m_activeList->currentItem(); if (!item) { Q_ASSERT(false); return; } int row = item->listWidget()->row(item) - 1; // make sure we're not the top item already if (row < 0) { Q_ASSERT(false); return; } // we're modified, so let this change emit m_widget->enableOk(true); moveActive(item, static_cast(item->listWidget()->item(row - 1))); } void KEditToolBarWidgetPrivate::moveActive(ToolBarItem *item, ToolBarItem *before) { QDomElement e = findElementForToolBarItem(item); if (e.isNull()) { return; } // remove item m_activeList->takeItem(m_activeList->row(item)); // put it where it's supposed to go m_activeList->insertItem(m_activeList->row(before) + 1, item); // make it selected again m_activeList->setCurrentItem(item); // and do the real move in the DOM if (!before) { m_currentToolBarElem.insertBefore(e, m_currentToolBarElem.firstChild()); } else { m_currentToolBarElem.insertAfter(e, findElementForToolBarItem(before)); } // and set this container as a noMerge m_currentToolBarElem.setAttribute(QStringLiteral("noMerge"), QStringLiteral("1")); // update the local doc updateLocal(m_currentToolBarElem); } void KEditToolBarWidgetPrivate::slotDownButton() { ToolBarItem *item = m_activeList->currentItem(); if (!item) { Q_ASSERT(false); return; } // make sure we're not the bottom item already int newRow = item->listWidget()->row(item) + 1; if (newRow >= item->listWidget()->count()) { Q_ASSERT(false); return; } // we're modified, so let this change emit m_widget->enableOk(true); moveActive(item, static_cast(item->listWidget()->item(newRow))); } void KEditToolBarWidgetPrivate::updateLocal(QDomElement &elem) { XmlDataList::Iterator xit = m_xmlFiles.begin(); for (; xit != m_xmlFiles.end(); ++xit) { if ((*xit).type() == XmlData::Merged) { continue; } if ((*xit).type() == XmlData::Shell || (*xit).type() == XmlData::Part) { if (m_currentXmlData->xmlFile() == (*xit).xmlFile()) { (*xit).m_isModified = true; return; } continue; } (*xit).m_isModified = true; const QLatin1String attrName("name"); ToolBarList::Iterator it = (*xit).barList().begin(); for (; it != (*xit).barList().end(); ++it) { QString name((*it).attribute(attrName)); QString tag((*it).tagName()); if ((tag != elem.tagName()) || (name != elem.attribute(attrName))) { continue; } QDomElement toolbar = (*xit).domDocument().documentElement().toElement(); toolbar.replaceChild(elem, (*it)); return; } // just append it QDomElement toolbar = (*xit).domDocument().documentElement().toElement(); Q_ASSERT(!toolbar.isNull()); toolbar.appendChild(elem); } } void KEditToolBarWidgetPrivate::slotChangeIcon() { m_currentXmlData->dump(); Q_ASSERT(m_currentXmlData->type() != XmlData::Merged); QString icon = KIconDialog::getIcon(KIconLoader::Toolbar, KIconLoader::Action, false, 0, false, // all defaults m_widget, i18n("Change Icon")); if (icon.isEmpty()) { return; } ToolBarItem *item = m_activeList->currentItem(); //qDebug() << item; if (item) { item->setIcon(QIcon::fromTheme(icon)); m_currentXmlData->m_isModified = true; // Get hold of ActionProperties tag QDomElement elem = KXMLGUIFactory::actionPropertiesElement(m_currentXmlData->domDocument()); // Find or create an element for this action QDomElement act_elem = KXMLGUIFactory::findActionByName(elem, item->internalName(), true /*create*/); Q_ASSERT(!act_elem.isNull()); act_elem.setAttribute(QStringLiteral("icon"), icon); // we're modified, so let this change emit m_widget->enableOk(true); } } void KEditToolBarWidgetPrivate::slotChangeIconText() { m_currentXmlData->dump(); ToolBarItem *item = m_activeList->currentItem(); if (item) { QString iconText = item->text(); bool hidden = item->isTextAlongsideIconHidden(); IconTextEditDialog dialog(m_widget); dialog.setIconText(iconText); dialog.setTextAlongsideIconHidden(hidden); bool ok = dialog.exec() == QDialog::Accepted; iconText = dialog.iconText(); hidden = dialog.textAlongsideIconHidden(); bool hiddenChanged = hidden != item->isTextAlongsideIconHidden(); bool iconTextChanged = iconText != item->text(); if (!ok || (!hiddenChanged && !iconTextChanged)) { return; } item->setText(iconText); item->setTextAlongsideIconHidden(hidden); Q_ASSERT(m_currentXmlData->type() != XmlData::Merged); m_currentXmlData->m_isModified = true; // Get hold of ActionProperties tag QDomElement elem = KXMLGUIFactory::actionPropertiesElement(m_currentXmlData->domDocument()); // Find or create an element for this action QDomElement act_elem = KXMLGUIFactory::findActionByName(elem, item->internalName(), true /*create*/); Q_ASSERT(!act_elem.isNull()); if (iconTextChanged) { act_elem.setAttribute(QStringLiteral("iconText"), iconText); } if (hiddenChanged) { act_elem.setAttribute(QStringLiteral("priority"), hidden ? QAction::LowPriority : QAction::NormalPriority); } // we're modified, so let this change emit m_widget->enableOk(true); } } void KEditToolBarWidgetPrivate::slotDropped(ToolBarListWidget *list, int index, ToolBarItem *item, bool sourceIsActiveList) { //qDebug() << "slotDropped list=" << (list==m_activeList?"activeList":"inactiveList") // << "index=" << index << "sourceIsActiveList=" << sourceIsActiveList; if (list == m_activeList) { ToolBarItem *after = index > 0 ? static_cast(list->item(index - 1)) : nullptr; //qDebug() << "after" << after->text() << after->internalTag(); if (sourceIsActiveList) { // has been dragged within the active list (moved). moveActive(item, after); } else { // dragged from the inactive list to the active list insertActive(item, after, true); } } else if (list == m_inactiveList) { // has been dragged to the inactive list -> remove from the active list. removeActive(item); } delete item; // not needed anymore. must be deleted before slotToolBarSelected clears the lists // we're modified, so let this change emit m_widget->enableOk(true); slotToolBarSelected(m_toolbarCombo->currentIndex()); } void KEditToolBar::showEvent(QShowEvent *event) { if (!event->spontaneous()) { // The dialog has been shown, enable toolbar editing if (d->m_factory) { // call the xmlgui-factory version d->m_widget->load(d->m_factory, d->m_defaultToolBar); } else { // call the action collection version d->m_widget->load(d->m_file, d->m_global, d->m_defaultToolBar); } KToolBar::setToolBarsEditable(true); } QDialog::showEvent(event); } void KEditToolBar::hideEvent(QHideEvent *event) { // The dialog has been hidden, disable toolbar editing KToolBar::setToolBarsEditable(false); QDialog::hideEvent(event); } #include "moc_kedittoolbar.cpp" #include "moc_kedittoolbar_p.cpp" diff --git a/src/ktoolbar.cpp b/src/ktoolbar.cpp index b322728..f86ebc3 100644 --- a/src/ktoolbar.cpp +++ b/src/ktoolbar.cpp @@ -1,1434 +1,1405 @@ /* This file is part of the KDE libraries Copyright (C) 2000 Reginald Stadlbauer (reggie@kde.org) (C) 1997, 1998 Stephan Kulow (coolo@kde.org) (C) 1997, 1998 Mark Donohoe (donohoe@kde.org) (C) 1997, 1998 Sven Radej (radej@kde.org) (C) 1997, 1998 Matthias Ettrich (ettrich@kde.org) (C) 1999 Chris Schlaeger (cs@kde.org) (C) 1999 Kurt Granroth (granroth@kde.org) (C) 2005-2006 Hamish Rodda (rodda@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "ktoolbar.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 "kactioncollection.h" #include "kedittoolbar.h" #include "kxmlguifactory.h" #include "kxmlguiwindow.h" +#include "ktoolbarhelper_p.h" + /* Toolbar settings (e.g. icon size or toolButtonStyle) ===================================================== We have the following stack of settings (in order of priority) : - user-specified settings (loaded/saved in KConfig) - developer-specified settings in the XMLGUI file (if using xmlgui) (cannot change at runtime) - KDE-global default (user-configurable; can change at runtime) and when switching between kparts, they are saved as xml in memory, which, in the unlikely case of no-kmainwindow-autosaving, could be different from the user-specified settings saved in KConfig and would have priority over it. So, in summary, without XML: Global config / User settings (loaded/saved in kconfig) and with XML: Global config / App-XML attributes / User settings (loaded/saved in kconfig) And all those settings (except the KDE-global defaults) have to be stored in memory since we cannot retrieve them at random points in time, not knowing the xml document nor config file that holds these settings. Hence the iconSizeSettings and toolButtonStyleSettings arrays. For instance, if you change the KDE-global default, whether this makes a change on a given toolbar depends on whether there are settings at Level_AppXML or Level_UserSettings. Only if there are no settings at those levels, should the change of KDEDefault make a difference. */ enum SettingLevel { Level_KDEDefault, Level_AppXML, Level_UserSettings, NSettingLevels }; enum { Unset = -1 }; class Q_DECL_HIDDEN KToolBar::Private { public: Private(KToolBar *qq) : q(qq), isMainToolBar(false), #ifndef KXMLGUI_NO_DEPRECATED enableContext(true), #endif unlockedMovable(true), contextOrient(nullptr), contextMode(nullptr), contextSize(nullptr), contextButtonTitle(nullptr), contextShowText(nullptr), contextButtonAction(nullptr), contextTop(nullptr), contextLeft(nullptr), contextRight(nullptr), contextBottom(nullptr), contextIcons(nullptr), contextTextRight(nullptr), contextText(nullptr), contextTextUnder(nullptr), contextLockAction(nullptr), dropIndicatorAction(nullptr), context(nullptr), dragAction(nullptr) { } void slotAppearanceChanged(); void slotContextAboutToShow(); void slotContextAboutToHide(); void slotContextLeft(); void slotContextRight(); void slotContextShowText(); void slotContextTop(); void slotContextBottom(); void slotContextIcons(); void slotContextText(); void slotContextTextRight(); void slotContextTextUnder(); void slotContextIconSize(); void slotLockToolBars(bool lock); void init(bool readConfig = true, bool isMainToolBar = false); QString getPositionAsString() const; QMenu *contextMenu(const QPoint &globalPos); void setLocked(bool locked); void adjustSeparatorVisibility(); void loadKDESettings(); void applyCurrentSettings(); QAction *findAction(const QString &actionName, KXMLGUIClient **client = nullptr) const; static Qt::ToolButtonStyle toolButtonStyleFromString(const QString &style); static QString toolButtonStyleToString(Qt::ToolButtonStyle); static Qt::ToolBarArea positionFromString(const QString &position); static Qt::ToolButtonStyle toolButtonStyleSetting(); KToolBar *q; bool isMainToolBar : 1; #ifndef KXMLGUI_NO_DEPRECATED bool enableContext : 1; #endif bool unlockedMovable : 1; static bool s_editable; static bool s_locked; QSet xmlguiClients; QMenu *contextOrient; QMenu *contextMode; QMenu *contextSize; QAction *contextButtonTitle; QAction *contextShowText; QAction *contextButtonAction; QAction *contextTop; QAction *contextLeft; QAction *contextRight; QAction *contextBottom; QAction *contextIcons; QAction *contextTextRight; QAction *contextText; QAction *contextTextUnder; KToggleAction *contextLockAction; QMap contextIconSizes; class IntSetting { public: IntSetting() { for (int level = 0; level < NSettingLevels; ++level) { values[level] = Unset; } } int currentValue() const { int val = Unset; for (int level = 0; level < NSettingLevels; ++level) { if (values[level] != Unset) { val = values[level]; } } return val; } // Default value as far as the user is concerned is kde-global + app-xml. // If currentValue()==defaultValue() then nothing to write into kconfig. int defaultValue() const { int val = Unset; for (int level = 0; level < Level_UserSettings; ++level) { if (values[level] != Unset) { val = values[level]; } } return val; } QString toString() const { QString str; for (int level = 0; level < NSettingLevels; ++level) { str += QString::number(values[level]) + QLatin1Char(' '); } return str; } int &operator[](int index) { return values[index]; } private: int values[NSettingLevels]; }; IntSetting iconSizeSettings; IntSetting toolButtonStyleSettings; // either Qt::ToolButtonStyle or -1, hence "int". QList actionsBeingDragged; QAction *dropIndicatorAction; QMenu *context; QAction *dragAction; QPoint dragStartPosition; }; bool KToolBar::Private::s_editable = false; bool KToolBar::Private::s_locked = true; void KToolBar::Private::init(bool readConfig, bool _isMainToolBar) { isMainToolBar = _isMainToolBar; loadKDESettings(); // also read in our configurable settings (for non-xmlgui toolbars) if (readConfig) { KConfigGroup cg(KSharedConfig::openConfig(), QString()); q->applySettings(cg); } if (q->mainWindow()) { // Get notified when settings change connect(q, SIGNAL(allowedAreasChanged(Qt::ToolBarAreas)), q->mainWindow(), SLOT(setSettingsDirty())); connect(q, SIGNAL(iconSizeChanged(QSize)), q->mainWindow(), SLOT(setSettingsDirty())); connect(q, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)), q->mainWindow(), SLOT(setSettingsDirty())); connect(q, SIGNAL(movableChanged(bool)), q->mainWindow(), SLOT(setSettingsDirty())); connect(q, SIGNAL(orientationChanged(Qt::Orientation)), q->mainWindow(), SLOT(setSettingsDirty())); } if (!KAuthorized::authorize(QStringLiteral("movable_toolbars"))) { q->setMovable(false); } else { q->setMovable(!KToolBar::toolBarsLocked()); } q->toggleViewAction()->setEnabled(KAuthorized::authorizeAction(QStringLiteral("options_show_toolbar"))); connect(q, SIGNAL(movableChanged(bool)), q, SLOT(slotMovableChanged(bool))); q->setAcceptDrops(true); QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged"), q, SLOT(slotAppearanceChanged())); connect(KIconLoader::global(), SIGNAL(iconLoaderSettingsChanged()), q, SLOT(slotAppearanceChanged())); } QString KToolBar::Private::getPositionAsString() const { // get all of the stuff to save switch (q->mainWindow()->toolBarArea(const_cast(q))) { case Qt::BottomToolBarArea: return QStringLiteral("Bottom"); case Qt::LeftToolBarArea: return QStringLiteral("Left"); case Qt::RightToolBarArea: return QStringLiteral("Right"); case Qt::TopToolBarArea: default: return QStringLiteral("Top"); } } QMenu *KToolBar::Private::contextMenu(const QPoint &globalPos) { if (!context) { context = new QMenu(q); contextButtonTitle = context->addSection(i18nc("@title:menu", "Show Text")); contextShowText = context->addAction(QString(), q, SLOT(slotContextShowText())); context->addSection(i18nc("@title:menu", "Toolbar Settings")); contextOrient = new QMenu(i18nc("Toolbar orientation", "Orientation"), context); contextTop = contextOrient->addAction(i18nc("toolbar position string", "Top"), q, SLOT(slotContextTop())); contextTop->setChecked(true); contextLeft = contextOrient->addAction(i18nc("toolbar position string", "Left"), q, SLOT(slotContextLeft())); contextRight = contextOrient->addAction(i18nc("toolbar position string", "Right"), q, SLOT(slotContextRight())); contextBottom = contextOrient->addAction(i18nc("toolbar position string", "Bottom"), q, SLOT(slotContextBottom())); QActionGroup *positionGroup = new QActionGroup(contextOrient); Q_FOREACH (QAction *action, contextOrient->actions()) { action->setActionGroup(positionGroup); action->setCheckable(true); } contextMode = new QMenu(i18n("Text Position"), context); contextIcons = contextMode->addAction(i18n("Icons Only"), q, SLOT(slotContextIcons())); contextText = contextMode->addAction(i18n("Text Only"), q, SLOT(slotContextText())); contextTextRight = contextMode->addAction(i18n("Text Alongside Icons"), q, SLOT(slotContextTextRight())); contextTextUnder = contextMode->addAction(i18n("Text Under Icons"), q, SLOT(slotContextTextUnder())); QActionGroup *textGroup = new QActionGroup(contextMode); Q_FOREACH (QAction *action, contextMode->actions()) { action->setActionGroup(textGroup); action->setCheckable(true); } contextSize = new QMenu(i18n("Icon Size"), context); contextIconSizes.insert(contextSize->addAction(i18nc("@item:inmenu Icon size", "Default"), q, SLOT(slotContextIconSize())), iconSizeSettings.defaultValue()); // Query the current theme for available sizes KIconTheme *theme = KIconLoader::global()->theme(); QList avSizes; if (theme) { avSizes = theme->querySizes(isMainToolBar ? KIconLoader::MainToolbar : KIconLoader::Toolbar); } qSort(avSizes); if (avSizes.count() < 10) { // Fixed or threshold type icons Q_FOREACH (int it, avSizes) { QString text; if (it < 19) { text = i18n("Small (%1x%2)", it, it); } else if (it < 25) { text = i18n("Medium (%1x%2)", it, it); } else if (it < 35) { text = i18n("Large (%1x%2)", it, it); } else { text = i18n("Huge (%1x%2)", it, it); } // save the size in the contextIconSizes map contextIconSizes.insert(contextSize->addAction(text, q, SLOT(slotContextIconSize())), it); } } else { // Scalable icons. const int progression[] = { 16, 22, 32, 48, 64, 96, 128, 192, 256 }; for (uint i = 0; i < 9; i++) { Q_FOREACH (int it, avSizes) { if (it >= progression[ i ]) { QString text; if (it < 19) { text = i18n("Small (%1x%2)", it, it); } else if (it < 25) { text = i18n("Medium (%1x%2)", it, it); } else if (it < 35) { text = i18n("Large (%1x%2)", it, it); } else { text = i18n("Huge (%1x%2)", it, it); } // save the size in the contextIconSizes map contextIconSizes.insert(contextSize->addAction(text, q, SLOT(slotContextIconSize())), it); break; } } } } QActionGroup *sizeGroup = new QActionGroup(contextSize); Q_FOREACH (QAction *action, contextSize->actions()) { action->setActionGroup(sizeGroup); action->setCheckable(true); } if (!q->toolBarsLocked() && !q->isMovable()) { unlockedMovable = false; } delete contextLockAction; contextLockAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("system-lock-screen")), i18n("Lock Toolbar Positions"), q); contextLockAction->setChecked(q->toolBarsLocked()); connect(contextLockAction, SIGNAL(toggled(bool)), q, SLOT(slotLockToolBars(bool))); // Now add the actions to the menu context->addMenu(contextMode); context->addMenu(contextSize); context->addMenu(contextOrient); context->addSeparator(); connect(context, SIGNAL(aboutToShow()), q, SLOT(slotContextAboutToShow())); } contextButtonAction = q->actionAt(q->mapFromGlobal(globalPos)); if (contextButtonAction) { contextShowText->setText(contextButtonAction->text()); contextShowText->setIcon(contextButtonAction->icon()); contextShowText->setCheckable(true); } contextOrient->menuAction()->setVisible(!q->toolBarsLocked()); // Unplugging a submenu from abouttohide leads to the popupmenu floating around // So better simply call that code from after exec() returns (DF) //connect(context, SIGNAL(aboutToHide()), this, SLOT(slotContextAboutToHide())); return context; } void KToolBar::Private::setLocked(bool locked) { if (unlockedMovable) { q->setMovable(!locked); } } void KToolBar::Private::adjustSeparatorVisibility() { bool visibleNonSeparator = false; int separatorToShow = -1; for (int index = 0; index < q->actions().count(); ++index) { QAction *action = q->actions().at(index); if (action->isSeparator()) { if (visibleNonSeparator) { separatorToShow = index; visibleNonSeparator = false; } else { action->setVisible(false); } } else if (!visibleNonSeparator) { if (action->isVisible()) { visibleNonSeparator = true; if (separatorToShow != -1) { q->actions().at(separatorToShow)->setVisible(true); separatorToShow = -1; } } } } if (separatorToShow != -1) { q->actions().at(separatorToShow)->setVisible(false); } } Qt::ToolButtonStyle KToolBar::Private::toolButtonStyleFromString(const QString &_style) { QString style = _style.toLower(); if (style == QStringLiteral("textbesideicon") || style == QLatin1String("icontextright")) { return Qt::ToolButtonTextBesideIcon; } else if (style == QStringLiteral("textundericon") || style == QLatin1String("icontextbottom")) { return Qt::ToolButtonTextUnderIcon; } else if (style == QStringLiteral("textonly")) { return Qt::ToolButtonTextOnly; } else { return Qt::ToolButtonIconOnly; } } QString KToolBar::Private::toolButtonStyleToString(Qt::ToolButtonStyle style) { switch (style) { case Qt::ToolButtonIconOnly: default: return QStringLiteral("IconOnly"); case Qt::ToolButtonTextBesideIcon: return QStringLiteral("TextBesideIcon"); case Qt::ToolButtonTextOnly: return QStringLiteral("TextOnly"); case Qt::ToolButtonTextUnderIcon: return QStringLiteral("TextUnderIcon"); } } Qt::ToolBarArea KToolBar::Private::positionFromString(const QString &position) { Qt::ToolBarArea newposition = Qt::TopToolBarArea; if (position == QStringLiteral("left")) { newposition = Qt::LeftToolBarArea; } else if (position == QStringLiteral("bottom")) { newposition = Qt::BottomToolBarArea; } else if (position == QStringLiteral("right")) { newposition = Qt::RightToolBarArea; } return newposition; } // Global setting was changed void KToolBar::Private::slotAppearanceChanged() { loadKDESettings(); applyCurrentSettings(); } Qt::ToolButtonStyle KToolBar::Private::toolButtonStyleSetting() { KConfigGroup group(KSharedConfig::openConfig(), "Toolbar style"); const QString fallback = KToolBar::Private::toolButtonStyleToString(Qt::ToolButtonTextBesideIcon); return KToolBar::Private::toolButtonStyleFromString(group.readEntry("ToolButtonStyle", fallback)); } void KToolBar::Private::loadKDESettings() { iconSizeSettings[Level_KDEDefault] = q->iconSizeDefault(); if (isMainToolBar) { toolButtonStyleSettings[Level_KDEDefault] = toolButtonStyleSetting(); } else { const QString fallBack = toolButtonStyleToString(Qt::ToolButtonTextBesideIcon); /** TODO: if we get complaints about text beside icons on small screens, try the following code out on such systems - aseigo. // if we are on a small screen with a non-landscape ratio, then // we revert to text under icons since width is probably not our // friend in such cases QDesktopWidget *desktop = QApplication::desktop(); QRect screenGeom = desktop->screenGeometry(desktop->primaryScreen()); qreal ratio = screenGeom.width() / qreal(screenGeom.height()); if (screenGeom.width() < 1024 && ratio <= 1.4) { fallBack = "TextUnderIcon"; } **/ KConfigGroup group(KSharedConfig::openConfig(), "Toolbar style"); const QString value = group.readEntry("ToolButtonStyleOtherToolbars", fallBack); toolButtonStyleSettings[Level_KDEDefault] = KToolBar::Private::toolButtonStyleFromString(value); } } // Call this after changing something in d->iconSizeSettings or d->toolButtonStyleSettings void KToolBar::Private::applyCurrentSettings() { //qDebug() << q->objectName() << "iconSizeSettings:" << iconSizeSettings.toString() << "->" << iconSizeSettings.currentValue(); const int currentIconSize = iconSizeSettings.currentValue(); q->setIconSize(QSize(currentIconSize, currentIconSize)); //qDebug() << q->objectName() << "toolButtonStyleSettings:" << toolButtonStyleSettings.toString() << "->" << toolButtonStyleSettings.currentValue(); q->setToolButtonStyle(static_cast(toolButtonStyleSettings.currentValue())); // And remember to save the new look later KMainWindow *kmw = q->mainWindow(); if (kmw) { kmw->setSettingsDirty(); } } QAction *KToolBar::Private::findAction(const QString &actionName, KXMLGUIClient **clientOut) const { Q_FOREACH (KXMLGUIClient *client, xmlguiClients) { QAction *action = client->actionCollection()->action(actionName); if (action) { if (clientOut) { *clientOut = client; } return action; } } return nullptr; } void KToolBar::Private::slotContextAboutToShow() { /** * The idea here is to reuse the "static" part of the menu to save time. * But the "Toolbars" action is dynamic (can be a single action or a submenu) * and ToolBarHandler::setupActions() deletes it, so better not keep it around. * So we currently plug/unplug the last two actions of the menu. * Another way would be to keep around the actions and plug them all into a (new each time) popupmenu. */ KXmlGuiWindow *kmw = qobject_cast(q->mainWindow()); // try to find "configure toolbars" action QAction *configureAction = nullptr; const char *actionName = KStandardAction::name(KStandardAction::ConfigureToolbars); configureAction = findAction(QLatin1String(actionName)); if (!configureAction && kmw) { configureAction = kmw->actionCollection()->action(QLatin1String(actionName)); } if (configureAction) { context->addAction(configureAction); } context->addAction(contextLockAction); if (kmw) { kmw->setupToolbarMenuActions(); // Only allow hiding a toolbar if the action is also plugged somewhere else (e.g. menubar) QAction *tbAction = kmw->toolBarMenuAction(); if (!q->toolBarsLocked() && tbAction && tbAction->associatedWidgets().count() > 0) { context->addAction(tbAction); } } KEditToolBar::setGlobalDefaultToolBar(q->QObject::objectName().toLatin1().constData()); // Check the actions that should be checked switch (q->toolButtonStyle()) { case Qt::ToolButtonIconOnly: default: contextIcons->setChecked(true); break; case Qt::ToolButtonTextBesideIcon: contextTextRight->setChecked(true); break; case Qt::ToolButtonTextOnly: contextText->setChecked(true); break; case Qt::ToolButtonTextUnderIcon: contextTextUnder->setChecked(true); break; } QMapIterator< QAction *, int > it = contextIconSizes; while (it.hasNext()) { it.next(); if (it.value() == q->iconSize().width()) { it.key()->setChecked(true); break; } } switch (q->mainWindow()->toolBarArea(q)) { case Qt::BottomToolBarArea: contextBottom->setChecked(true); break; case Qt::LeftToolBarArea: contextLeft->setChecked(true); break; case Qt::RightToolBarArea: contextRight->setChecked(true); break; default: case Qt::TopToolBarArea: contextTop->setChecked(true); break; } const bool showButtonSettings = contextButtonAction && !contextShowText->text().isEmpty() && contextTextRight->isChecked(); contextButtonTitle->setVisible(showButtonSettings); contextShowText->setVisible(showButtonSettings); if (showButtonSettings) { contextShowText->setChecked(contextButtonAction->priority() >= QAction::NormalPriority); } } void KToolBar::Private::slotContextAboutToHide() { // We have to unplug whatever slotContextAboutToShow plugged into the menu. // Unplug the toolbar menu action KXmlGuiWindow *kmw = qobject_cast(q->mainWindow()); if (kmw && kmw->toolBarMenuAction()) { if (kmw->toolBarMenuAction()->associatedWidgets().count() > 1) { context->removeAction(kmw->toolBarMenuAction()); } } // Unplug the configure toolbars action too, since it's afterwards anyway QAction *configureAction = nullptr; const char *actionName = KStandardAction::name(KStandardAction::ConfigureToolbars); configureAction = findAction(QLatin1String(actionName)); if (!configureAction && kmw) { configureAction = kmw->actionCollection()->action(QLatin1String(actionName)); } if (configureAction) { context->removeAction(configureAction); } context->removeAction(contextLockAction); } void KToolBar::Private::slotContextLeft() { q->mainWindow()->addToolBar(Qt::LeftToolBarArea, q); } void KToolBar::Private::slotContextRight() { q->mainWindow()->addToolBar(Qt::RightToolBarArea, q); } void KToolBar::Private::slotContextShowText() { Q_ASSERT(contextButtonAction); const QAction::Priority priority = contextShowText->isChecked() ? QAction::NormalPriority : QAction::LowPriority; contextButtonAction->setPriority(priority); // Find to which xml file and componentData the action belongs to QString componentName; QString filename; KXMLGUIClient *client; if (findAction(contextButtonAction->objectName(), &client)) { componentName = client->componentName(); filename = client->xmlFile(); } if (filename.isEmpty()) { componentName = QCoreApplication::applicationName(); filename = componentName + QStringLiteral("ui.rc"); } // Save the priority state of the action const QString configFile = KXMLGUIFactory::readConfigFile(filename, componentName); QDomDocument document; document.setContent(configFile); QDomElement elem = KXMLGUIFactory::actionPropertiesElement(document); QDomElement actionElem = KXMLGUIFactory::findActionByName(elem, contextButtonAction->objectName(), true); actionElem.setAttribute(QStringLiteral("priority"), priority); KXMLGUIFactory::saveConfigFile(document, filename, componentName); } void KToolBar::Private::slotContextTop() { q->mainWindow()->addToolBar(Qt::TopToolBarArea, q); } void KToolBar::Private::slotContextBottom() { q->mainWindow()->addToolBar(Qt::BottomToolBarArea, q); } void KToolBar::Private::slotContextIcons() { q->setToolButtonStyle(Qt::ToolButtonIconOnly); toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); } void KToolBar::Private::slotContextText() { q->setToolButtonStyle(Qt::ToolButtonTextOnly); toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); } void KToolBar::Private::slotContextTextUnder() { q->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); } void KToolBar::Private::slotContextTextRight() { q->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); toolButtonStyleSettings[Level_UserSettings] = q->toolButtonStyle(); } void KToolBar::Private::slotContextIconSize() { QAction *action = qobject_cast(q->sender()); if (action && contextIconSizes.contains(action)) { const int iconSize = contextIconSizes.value(action); q->setIconDimensions(iconSize); } } void KToolBar::Private::slotLockToolBars(bool lock) { q->setToolBarsLocked(lock); } KToolBar::KToolBar(QWidget *parent, bool isMainToolBar, bool readConfig) : QToolBar(parent), d(new Private(this)) { d->init(readConfig, isMainToolBar); // KToolBar is auto-added to the top area of the main window if parent is a QMainWindow if (QMainWindow *mw = qobject_cast(parent)) { mw->addToolBar(this); } } KToolBar::KToolBar(const QString &objectName, QWidget *parent, bool readConfig) : QToolBar(parent), d(new Private(this)) { setObjectName(objectName); // mainToolBar -> isMainToolBar = true -> buttonStyle is configurable // others -> isMainToolBar = false -> ### hardcoded default for buttonStyle !!! should be configurable? -> hidden key added d->init(readConfig, objectName == QStringLiteral("mainToolBar")); // KToolBar is auto-added to the top area of the main window if parent is a QMainWindow if (QMainWindow *mw = qobject_cast(parent)) { mw->addToolBar(this); } } KToolBar::KToolBar(const QString &objectName, QMainWindow *parent, Qt::ToolBarArea area, bool newLine, bool isMainToolBar, bool readConfig) : QToolBar(parent), d(new Private(this)) { setObjectName(objectName); d->init(readConfig, isMainToolBar); if (newLine) { mainWindow()->addToolBarBreak(area); } mainWindow()->addToolBar(area, this); if (newLine) { mainWindow()->addToolBarBreak(area); } } KToolBar::~KToolBar() { delete d->contextLockAction; delete d; } #ifndef KXMLGUI_NO_DEPRECATED void KToolBar::setContextMenuEnabled(bool enable) { d->enableContext = enable; } #endif #ifndef KXMLGUI_NO_DEPRECATED bool KToolBar::contextMenuEnabled() const { return d->enableContext; } #endif void KToolBar::saveSettings(KConfigGroup &cg) { Q_ASSERT(!cg.name().isEmpty()); const int currentIconSize = iconSize().width(); //qDebug() << objectName() << currentIconSize << d->iconSizeSettings.toString() << "defaultValue=" << d->iconSizeSettings.defaultValue(); if (!cg.hasDefault("IconSize") && currentIconSize == d->iconSizeSettings.defaultValue()) { cg.revertToDefault("IconSize"); d->iconSizeSettings[Level_UserSettings] = Unset; } else { cg.writeEntry("IconSize", currentIconSize); d->iconSizeSettings[Level_UserSettings] = currentIconSize; } const Qt::ToolButtonStyle currentToolButtonStyle = toolButtonStyle(); if (!cg.hasDefault("ToolButtonStyle") && currentToolButtonStyle == d->toolButtonStyleSettings.defaultValue()) { cg.revertToDefault("ToolButtonStyle"); d->toolButtonStyleSettings[Level_UserSettings] = Unset; } else { cg.writeEntry("ToolButtonStyle", d->toolButtonStyleToString(currentToolButtonStyle)); d->toolButtonStyleSettings[Level_UserSettings] = currentToolButtonStyle; } } #ifndef KXMLGUI_NO_DEPRECATED void KToolBar::setXMLGUIClient(KXMLGUIClient *client) { d->xmlguiClients.clear(); d->xmlguiClients << client; } #endif void KToolBar::addXMLGUIClient(KXMLGUIClient *client) { d->xmlguiClients << client; } void KToolBar::removeXMLGUIClient(KXMLGUIClient *client) { d->xmlguiClients.remove(client); } void KToolBar::contextMenuEvent(QContextMenuEvent *event) { #ifndef KXMLGUI_NO_DEPRECATED if (mainWindow() && d->enableContext) { QPointer guard(this); const QPoint globalPos = event->globalPos(); d->contextMenu(globalPos)->exec(globalPos); // "Configure Toolbars" recreates toolbars, so we might not exist anymore. if (guard) { d->slotContextAboutToHide(); } return; } #endif QToolBar::contextMenuEvent(event); } void KToolBar::loadState(const QDomElement &element) { QMainWindow *mw = mainWindow(); if (!mw) { return; } { - QDomNode textNode = element.namedItem(QStringLiteral("text")); - QByteArray domain; - QByteArray text; - QByteArray context; - if (textNode.isElement()) { - QDomElement textElement = textNode.toElement(); - domain = textElement.attribute(QStringLiteral("translationDomain")).toUtf8(); - text = textElement.text().toUtf8(); - context = textElement.attribute(QStringLiteral("context")).toUtf8(); - } else { - textNode = element.namedItem(QStringLiteral("Text")); - if (textNode.isElement()) { - QDomElement textElement = textNode.toElement(); - domain = textElement.attribute(QStringLiteral("translationDomain")).toUtf8(); - text = textElement.text().toUtf8(); - context = textElement.attribute(QStringLiteral("context")).toUtf8(); - } - } - - if (domain.isEmpty()) { - domain = element.ownerDocument().documentElement().attribute(QStringLiteral("translationDomain")).toUtf8(); - if (domain.isEmpty()) { - domain = KLocalizedString::applicationDomain(); - } - } - QString i18nText; - if (!text.isEmpty() && !context.isEmpty()) { - i18nText = i18ndc(domain.constData(), context.constData(), text.constData()); - } else if (!text.isEmpty()) { - i18nText = i18nd(domain.constData(), text.constData()); - } - + const QString& i18nText = KToolbarHelper::i18nToolBarName(element); if (!i18nText.isEmpty()) { setWindowTitle(i18nText); } } /* This method is called in order to load toolbar settings from XML. However this can be used in two rather different cases: - for the initial loading of the app's XML. In that case the settings are only the defaults (Level_AppXML), the user's KConfig settings will override them - for later re-loading when switching between parts in KXMLGUIFactory. In that case the XML contains the final settings, not the defaults. We do need the defaults, and the toolbar might have been completely deleted and recreated meanwhile. So we store the app-default settings into the XML. */ bool loadingAppDefaults = true; if (element.hasAttribute(QStringLiteral("tempXml"))) { // this isn't the first time, so the app-xml defaults have been saved into the (in-memory) XML loadingAppDefaults = false; const QString iconSizeDefault = element.attribute(QStringLiteral("iconSizeDefault")); if (!iconSizeDefault.isEmpty()) { d->iconSizeSettings[Level_AppXML] = iconSizeDefault.toInt(); } const QString toolButtonStyleDefault = element.attribute(QStringLiteral("toolButtonStyleDefault")); if (!toolButtonStyleDefault.isEmpty()) { d->toolButtonStyleSettings[Level_AppXML] = d->toolButtonStyleFromString(toolButtonStyleDefault); } } else { // loading app defaults bool newLine = false; QString attrNewLine = element.attribute(QStringLiteral("newline")).toLower(); if (!attrNewLine.isEmpty()) { newLine = attrNewLine == QStringLiteral("true"); } if (newLine && mw) { mw->insertToolBarBreak(this); } } int newIconSize = -1; if (element.hasAttribute(QStringLiteral("iconSize"))) { bool ok; newIconSize = element.attribute(QStringLiteral("iconSize")).trimmed().toInt(&ok); if (!ok) { newIconSize = -1; } } if (newIconSize != -1) { d->iconSizeSettings[loadingAppDefaults ? Level_AppXML : Level_UserSettings] = newIconSize; } const QString newToolButtonStyle = element.attribute(QStringLiteral("iconText")); if (!newToolButtonStyle.isEmpty()) { d->toolButtonStyleSettings[loadingAppDefaults ? Level_AppXML : Level_UserSettings] = d->toolButtonStyleFromString(newToolButtonStyle); } bool hidden = false; { QString attrHidden = element.attribute(QStringLiteral("hidden")).toLower(); if (!attrHidden.isEmpty()) { hidden = attrHidden == QStringLiteral("true"); } } Qt::ToolBarArea pos = Qt::NoToolBarArea; { QString attrPosition = element.attribute(QStringLiteral("position")).toLower(); if (!attrPosition.isEmpty()) { pos = KToolBar::Private::positionFromString(attrPosition); } } if (pos != Qt::NoToolBarArea) { mw->addToolBar(pos, this); } setVisible(!hidden); d->applyCurrentSettings(); } // Called when switching between xmlgui clients, in order to find any unsaved settings // again when switching back to the current xmlgui client. void KToolBar::saveState(QDomElement ¤t) const { Q_ASSERT(!current.isNull()); current.setAttribute(QStringLiteral("tempXml"), QStringLiteral("true")); current.setAttribute(QStringLiteral("noMerge"), QStringLiteral("1")); current.setAttribute(QStringLiteral("position"), d->getPositionAsString().toLower()); current.setAttribute(QStringLiteral("hidden"), isHidden() ? QStringLiteral("true") : QStringLiteral("false")); const int currentIconSize = iconSize().width(); if (currentIconSize == d->iconSizeSettings.defaultValue()) { current.removeAttribute(QStringLiteral("iconSize")); } else { current.setAttribute(QStringLiteral("iconSize"), iconSize().width()); } if (toolButtonStyle() == d->toolButtonStyleSettings.defaultValue()) { current.removeAttribute(QStringLiteral("iconText")); } else { current.setAttribute(QStringLiteral("iconText"), d->toolButtonStyleToString(toolButtonStyle())); } // Note: if this method is used by more than KXMLGUIBuilder, e.g. to save XML settings to *disk*, // then the stuff below shouldn't always be done. This is not the case currently though. if (d->iconSizeSettings[Level_AppXML] != Unset) { current.setAttribute(QStringLiteral("iconSizeDefault"), d->iconSizeSettings[Level_AppXML]); } if (d->toolButtonStyleSettings[Level_AppXML] != Unset) { const Qt::ToolButtonStyle bs = static_cast(d->toolButtonStyleSettings[Level_AppXML]); current.setAttribute(QStringLiteral("toolButtonStyleDefault"), d->toolButtonStyleToString(bs)); } } // called by KMainWindow::applyMainWindowSettings to read from the user settings void KToolBar::applySettings(const KConfigGroup &cg) { Q_ASSERT(!cg.name().isEmpty()); if (cg.hasKey("IconSize")) { d->iconSizeSettings[Level_UserSettings] = cg.readEntry("IconSize", 0); } if (cg.hasKey("ToolButtonStyle")) { d->toolButtonStyleSettings[Level_UserSettings] = d->toolButtonStyleFromString(cg.readEntry("ToolButtonStyle", QString())); } d->applyCurrentSettings(); } KMainWindow *KToolBar::mainWindow() const { return qobject_cast(const_cast(parent())); } void KToolBar::setIconDimensions(int size) { QToolBar::setIconSize(QSize(size, size)); d->iconSizeSettings[Level_UserSettings] = size; } int KToolBar::iconSizeDefault() const { return KIconLoader::global()->currentSize(d->isMainToolBar ? KIconLoader::MainToolbar : KIconLoader::Toolbar); } void KToolBar::slotMovableChanged(bool movable) { if (movable && !KAuthorized::authorize(QStringLiteral("movable_toolbars"))) { setMovable(false); } } void KToolBar::dragEnterEvent(QDragEnterEvent *event) { if (toolBarsEditable() && event->proposedAction() & (Qt::CopyAction | Qt::MoveAction) && event->mimeData()->hasFormat(QStringLiteral("application/x-kde-action-list"))) { QByteArray data = event->mimeData()->data(QStringLiteral("application/x-kde-action-list")); QDataStream stream(data); QStringList actionNames; stream >> actionNames; Q_FOREACH (const QString &actionName, actionNames) { Q_FOREACH (KActionCollection *ac, KActionCollection::allCollections()) { QAction *newAction = ac->action(actionName); if (newAction) { d->actionsBeingDragged.append(newAction); break; } } } if (!d->actionsBeingDragged.isEmpty()) { QAction *overAction = actionAt(event->pos()); QFrame *dropIndicatorWidget = new QFrame(this); dropIndicatorWidget->resize(8, height() - 4); dropIndicatorWidget->setFrameShape(QFrame::VLine); dropIndicatorWidget->setLineWidth(3); d->dropIndicatorAction = insertWidget(overAction, dropIndicatorWidget); insertAction(overAction, d->dropIndicatorAction); event->acceptProposedAction(); return; } } QToolBar::dragEnterEvent(event); } void KToolBar::dragMoveEvent(QDragMoveEvent *event) { if (toolBarsEditable()) Q_FOREVER { if (d->dropIndicatorAction) { QAction *overAction = nullptr; Q_FOREACH (QAction *action, actions()) { // want to make it feel that half way across an action you're dropping on the other side of it QWidget *widget = widgetForAction(action); if (event->pos().x() < widget->pos().x() + (widget->width() / 2)) { overAction = action; break; } } if (overAction != d->dropIndicatorAction) { // Check to see if the indicator is already in the right spot int dropIndicatorIndex = actions().indexOf(d->dropIndicatorAction); if (dropIndicatorIndex + 1 < actions().count()) { if (actions().at(dropIndicatorIndex + 1) == overAction) { break; } } else if (!overAction) { break; } insertAction(overAction, d->dropIndicatorAction); } event->accept(); return; } break; } QToolBar::dragMoveEvent(event); } void KToolBar::dragLeaveEvent(QDragLeaveEvent *event) { // Want to clear this even if toolBarsEditable was changed mid-drag (unlikey) delete d->dropIndicatorAction; d->dropIndicatorAction = nullptr; d->actionsBeingDragged.clear(); if (toolBarsEditable()) { event->accept(); return; } QToolBar::dragLeaveEvent(event); } void KToolBar::dropEvent(QDropEvent *event) { if (toolBarsEditable()) { Q_FOREACH (QAction *action, d->actionsBeingDragged) { if (actions().contains(action)) { removeAction(action); } insertAction(d->dropIndicatorAction, action); } } // Want to clear this even if toolBarsEditable was changed mid-drag (unlikey) delete d->dropIndicatorAction; d->dropIndicatorAction = nullptr; d->actionsBeingDragged.clear(); if (toolBarsEditable()) { event->accept(); return; } QToolBar::dropEvent(event); } void KToolBar::mousePressEvent(QMouseEvent *event) { if (toolBarsEditable() && event->button() == Qt::LeftButton) { if (QAction *action = actionAt(event->pos())) { d->dragAction = action; d->dragStartPosition = event->pos(); event->accept(); return; } } QToolBar::mousePressEvent(event); } void KToolBar::mouseMoveEvent(QMouseEvent *event) { if (!toolBarsEditable() || !d->dragAction) { return QToolBar::mouseMoveEvent(event); } if ((event->pos() - d->dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { event->accept(); return; } QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; QByteArray data; { QDataStream stream(&data, QIODevice::WriteOnly); QStringList actionNames; actionNames << d->dragAction->objectName(); stream << actionNames; } mimeData->setData(QStringLiteral("application/x-kde-action-list"), data); drag->setMimeData(mimeData); Qt::DropAction dropAction = drag->start(Qt::MoveAction); if (dropAction == Qt::MoveAction) // Only remove from this toolbar if it was moved to another toolbar // Otherwise the receiver moves it. if (drag->target() != this) { removeAction(d->dragAction); } d->dragAction = nullptr; event->accept(); } void KToolBar::mouseReleaseEvent(QMouseEvent *event) { // Want to clear this even if toolBarsEditable was changed mid-drag (unlikey) if (d->dragAction) { d->dragAction = nullptr; event->accept(); return; } QToolBar::mouseReleaseEvent(event); } bool KToolBar::eventFilter(QObject *watched, QEvent *event) { // Generate context menu events for disabled buttons too... if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *me = static_cast(event); if (me->buttons() & Qt::RightButton) if (QWidget *ww = qobject_cast(watched)) if (ww->parent() == this && !ww->isEnabled()) { QCoreApplication::postEvent(this, new QContextMenuEvent(QContextMenuEvent::Mouse, me->pos(), me->globalPos())); } } else if (event->type() == QEvent::ParentChange) { // Make sure we're not leaving stale event filters around, // when a child is reparented somewhere else if (QWidget *ww = qobject_cast(watched)) { if (!this->isAncestorOf(ww)) { // New parent is not a subwidget - remove event filter ww->removeEventFilter(this); Q_FOREACH (QWidget *child, ww->findChildren()) { child->removeEventFilter(this); } } } } // Redirect mouse events to the toolbar when drag + drop editing is enabled if (toolBarsEditable()) { if (QWidget *ww = qobject_cast(watched)) { switch (event->type()) { case QEvent::MouseButtonPress: { QMouseEvent *me = static_cast(event); QMouseEvent newEvent(me->type(), mapFromGlobal(ww->mapToGlobal(me->pos())), me->globalPos(), me->button(), me->buttons(), me->modifiers()); mousePressEvent(&newEvent); return true; } case QEvent::MouseMove: { QMouseEvent *me = static_cast(event); QMouseEvent newEvent(me->type(), mapFromGlobal(ww->mapToGlobal(me->pos())), me->globalPos(), me->button(), me->buttons(), me->modifiers()); mouseMoveEvent(&newEvent); return true; } case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast(event); QMouseEvent newEvent(me->type(), mapFromGlobal(ww->mapToGlobal(me->pos())), me->globalPos(), me->button(), me->buttons(), me->modifiers()); mouseReleaseEvent(&newEvent); return true; } default: break; } } } return QToolBar::eventFilter(watched, event); } void KToolBar::actionEvent(QActionEvent *event) { if (event->type() == QEvent::ActionRemoved) { QWidget *widget = widgetForAction(event->action()); if (widget) { widget->removeEventFilter(this); Q_FOREACH (QWidget *child, widget->findChildren()) { child->removeEventFilter(this); } } } QToolBar::actionEvent(event); if (event->type() == QEvent::ActionAdded) { QWidget *widget = widgetForAction(event->action()); if (widget) { widget->installEventFilter(this); Q_FOREACH (QWidget *child, widget->findChildren()) { child->installEventFilter(this); } // Center widgets that do not have any use for more space. See bug 165274 if (!(widget->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag) // ... but do not center when using text besides icon in vertical toolbar. See bug 243196 && !(orientation() == Qt::Vertical && toolButtonStyle() == Qt::ToolButtonTextBesideIcon)) { const int index = layout()->indexOf(widget); if (index != -1) { layout()->itemAt(index)->setAlignment(Qt::AlignJustify); } } } } d->adjustSeparatorVisibility(); } bool KToolBar::toolBarsEditable() { return KToolBar::Private::s_editable; } void KToolBar::setToolBarsEditable(bool editable) { if (KToolBar::Private::s_editable != editable) { KToolBar::Private::s_editable = editable; } } void KToolBar::setToolBarsLocked(bool locked) { if (KToolBar::Private::s_locked != locked) { KToolBar::Private::s_locked = locked; Q_FOREACH (KMainWindow *mw, KMainWindow::memberList()) { Q_FOREACH (KToolBar *toolbar, mw->findChildren()) { toolbar->d->setLocked(locked); } } } } bool KToolBar::toolBarsLocked() { return KToolBar::Private::s_locked; } void KToolBar::emitToolbarStyleChanged() { QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KToolBar"), QStringLiteral("org.kde.KToolBar"), QStringLiteral("styleChanged")); QDBusConnection::sessionBus().send(message); } #include "moc_ktoolbar.cpp" diff --git a/src/ktoolbarhelper.cpp b/src/ktoolbarhelper.cpp new file mode 100644 index 0000000..ca31b0e --- /dev/null +++ b/src/ktoolbarhelper.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017 Alexander Potashev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ktoolbarhelper_p.h" + +#include + +#include + +namespace KToolbarHelper { + +QString i18nToolBarName(const QDomElement &element) +{ + QDomElement textElement; + bool textElementFound = false; + const QVector textKeys = {QStringLiteral("text"), QStringLiteral("Text")}; + for (const QString &key : textKeys) { + QDomNode textNode = element.namedItem(key); + if (textNode.isElement()) { + textElement = textNode.toElement(); + textElementFound = true; + break; + } + } + + if (!textElementFound) { + return element.attribute(QStringLiteral("name")); + } + + QByteArray domain = textElement.attribute(QStringLiteral("translationDomain")).toUtf8(); + QByteArray text = textElement.text().toUtf8(); + QByteArray context = textElement.attribute(QStringLiteral("context")).toUtf8(); + + if (domain.isEmpty()) { + domain = element.ownerDocument().documentElement().attribute(QStringLiteral("translationDomain")).toUtf8(); + if (domain.isEmpty()) { + domain = KLocalizedString::applicationDomain(); + } + } + QString i18nText; + if (!text.isEmpty() && !context.isEmpty()) { + i18nText = i18ndc(domain.constData(), context.constData(), text.constData()); + } else if (!text.isEmpty()) { + i18nText = i18nd(domain.constData(), text.constData()); + } + return i18nText; +} + +} // namespace KToolbarHelper diff --git a/src/ktoolbarhelper_p.h b/src/ktoolbarhelper_p.h new file mode 100644 index 0000000..f33b2fe --- /dev/null +++ b/src/ktoolbarhelper_p.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 Alexander Potashev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef KTOOLBARHELPER_P_H +#define KTOOLBARHELPER_P_H + +#include + +namespace KToolbarHelper +{ + +QString i18nToolBarName(const QDomElement &element); + +} + +#endif // KTOOLBARHELPER_P_H