diff --git a/src/kconfigdialog.cpp b/src/kconfigdialog.cpp index 7404cfa..3fd429f 100644 --- a/src/kconfigdialog.cpp +++ b/src/kconfigdialog.cpp @@ -1,380 +1,385 @@ /* * This file is part of the KDE libraries * Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net) * Copyright (C) 2003 Waldo Bastian * Copyright (C) 2004 Michael Brade * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kconfigdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KConfigDialog::KConfigDialogPrivate { public: KConfigDialogPrivate(KConfigDialog *q, const QString &name, KCoreConfigSkeleton *config) : q(q), shown(false), manager(nullptr) { q->setObjectName(name); q->setWindowTitle(i18nc("@title:window", "Configure")); q->setFaceType(List); if (!name.isEmpty()) { openDialogs.insert(name, q); } else { QString genericName; genericName.sprintf("SettingsDialog-%p", static_cast(q)); openDialogs.insert(genericName, q); q->setObjectName(genericName); } QDialogButtonBox *buttonBox = q->buttonBox(); buttonBox->setStandardButtons(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Help); connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, q, &KConfigDialog::updateSettings); connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, &KConfigDialog::updateSettings); connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, [this]() { _k_updateButtons(); }); connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, q, &KConfigDialog::updateWidgets); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, q, &KConfigDialog::updateWidgetsDefault); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, q, [this]() { _k_updateButtons(); }); connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &KConfigDialog::showHelp); - connect(q, SIGNAL(pageRemoved(KPageWidgetItem*)), q, SLOT(onPageRemoved(KPageWidgetItem*))); + connect(q, &KPageDialog::pageRemoved, + q, &KConfigDialog::onPageRemoved); manager = new KConfigDialogManager(q, config); setupManagerConnections(manager); setApplyButtonEnabled(false); } KPageWidgetItem *addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header); void setupManagerConnections(KConfigDialogManager *manager); void setApplyButtonEnabled(bool enabled); void setRestoreDefaultsButtonEnabled(bool enabled); void _k_updateButtons(); void _k_settingsChangedSlot(); KConfigDialog *q; QString mAnchor; QString mHelpApp; bool shown; KConfigDialogManager *manager; QMap managerForPage; /** * The list of existing dialogs. */ static QHash openDialogs; }; QHash KConfigDialog::KConfigDialogPrivate::openDialogs; KConfigDialog::KConfigDialog(QWidget *parent, const QString &name, KCoreConfigSkeleton *config) : KPageDialog(parent), d(new KConfigDialogPrivate(this, name, config)) { } KConfigDialog::~KConfigDialog() { KConfigDialogPrivate::openDialogs.remove(objectName()); delete d; } KPageWidgetItem *KConfigDialog::addPage(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header, bool manage) { Q_ASSERT(page); if (!page) { return nullptr; } KPageWidgetItem *item = d->addPageInternal(page, itemName, pixmapName, header); if (manage) { d->manager->addWidget(page); } if (d->shown && manage) { // update the default button if the dialog is shown QPushButton *defaultButton = buttonBox()->button(QDialogButtonBox::RestoreDefaults); if (defaultButton) { bool is_default = defaultButton->isEnabled() && d->manager->isDefault(); defaultButton->setEnabled(!is_default); } } return item; } KPageWidgetItem *KConfigDialog::addPage(QWidget *page, KCoreConfigSkeleton *config, const QString &itemName, const QString &pixmapName, const QString &header) { Q_ASSERT(page); if (!page) { return nullptr; } KPageWidgetItem *item = d->addPageInternal(page, itemName, pixmapName, header); d->managerForPage[page] = new KConfigDialogManager(page, config); d->setupManagerConnections(d->managerForPage[page]); if (d->shown) { // update the default button if the dialog is shown QPushButton *defaultButton = buttonBox()->button(QDialogButtonBox::RestoreDefaults); if (defaultButton) { bool is_default = defaultButton->isEnabled() && d->managerForPage[page]->isDefault(); defaultButton->setEnabled(!is_default); } } return item; } KPageWidgetItem *KConfigDialog::KConfigDialogPrivate::addPageInternal(QWidget *page, const QString &itemName, const QString &pixmapName, const QString &header) { QWidget *frame = new QWidget(q); QVBoxLayout *boxLayout = new QVBoxLayout(frame); boxLayout->setMargin(0); boxLayout->setMargin(0); QScrollArea *scroll = new QScrollArea(q); scroll->setFrameShape(QFrame::NoFrame); scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); scroll->setWidget(page); scroll->setWidgetResizable(true); scroll->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding ); boxLayout->addWidget(scroll); KPageWidgetItem *item = new KPageWidgetItem(frame, itemName); item->setHeader(header); if (!pixmapName.isEmpty()) { item->setIcon(QIcon::fromTheme(pixmapName)); } q->KPageDialog::addPage(item); return item; } void KConfigDialog::KConfigDialogPrivate::setupManagerConnections(KConfigDialogManager *manager) { q->connect(manager, SIGNAL(settingsChanged()), q, SLOT(_k_settingsChangedSlot())); q->connect(manager, SIGNAL(widgetModified()), q, SLOT(_k_updateButtons())); QDialogButtonBox *buttonBox = q->buttonBox(); - q->connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), manager, SLOT(updateSettings())); - q->connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), manager, SLOT(updateSettings())); - q->connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), manager, SLOT(updateWidgets())); - q->connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), manager, SLOT(updateWidgetsDefault())); + q->connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, + manager, &KConfigDialogManager::updateSettings); + q->connect(buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, + manager, &KConfigDialogManager::updateSettings); + q->connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, + manager, &KConfigDialogManager::updateWidgets); + q->connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, + manager, &KConfigDialogManager::updateWidgetsDefault); } void KConfigDialog::KConfigDialogPrivate::setApplyButtonEnabled(bool enabled) { QPushButton *applyButton = q->buttonBox()->button(QDialogButtonBox::Apply); if (applyButton) { applyButton->setEnabled(enabled); } } void KConfigDialog::KConfigDialogPrivate::setRestoreDefaultsButtonEnabled(bool enabled) { QPushButton *restoreDefaultsButton = q->buttonBox()->button(QDialogButtonBox::RestoreDefaults); if (restoreDefaultsButton) { restoreDefaultsButton->setEnabled(enabled); } } void KConfigDialog::onPageRemoved(KPageWidgetItem *item) { QMap::iterator j = d->managerForPage.begin(); while (j != d->managerForPage.end()) { // there is a manager for this page, so remove it if (item->widget()->isAncestorOf(j.key())) { KConfigDialogManager *manager = j.value(); d->managerForPage.erase(j); delete manager; d->_k_updateButtons(); break; } ++j; } } KConfigDialog *KConfigDialog::exists(const QString &name) { QHash::const_iterator it = KConfigDialogPrivate::openDialogs.constFind(name); if (it != KConfigDialogPrivate::openDialogs.constEnd()) { return *it; } return nullptr; } bool KConfigDialog::showDialog(const QString &name) { KConfigDialog *dialog = exists(name); if (dialog) { dialog->show(); } return (dialog != nullptr); } void KConfigDialog::KConfigDialogPrivate::_k_updateButtons() { static bool only_once = false; if (only_once) { return; } only_once = true; QMap::iterator it; bool has_changed = manager->hasChanged() || q->hasChanged(); for (it = managerForPage.begin(); it != managerForPage.end() && !has_changed; ++it) { has_changed |= (*it)->hasChanged(); } setApplyButtonEnabled(has_changed); bool is_default = manager->isDefault() && q->isDefault(); for (it = managerForPage.begin(); it != managerForPage.end() && is_default; ++it) { is_default &= (*it)->isDefault(); } setRestoreDefaultsButtonEnabled(!is_default); emit q->widgetModified(); only_once = false; } void KConfigDialog::KConfigDialogPrivate::_k_settingsChangedSlot() { // Update the buttons _k_updateButtons(); emit q->settingsChanged(q->objectName()); } void KConfigDialog::showEvent(QShowEvent *e) { if (!d->shown) { QMap::iterator it; updateWidgets(); d->manager->updateWidgets(); for (it = d->managerForPage.begin(); it != d->managerForPage.end(); ++it) { (*it)->updateWidgets(); } bool has_changed = d->manager->hasChanged() || hasChanged(); for (it = d->managerForPage.begin(); it != d->managerForPage.end() && !has_changed; ++it) { has_changed |= (*it)->hasChanged(); } d->setApplyButtonEnabled(has_changed); bool is_default = d->manager->isDefault() && isDefault(); for (it = d->managerForPage.begin(); it != d->managerForPage.end() && is_default; ++it) { is_default &= (*it)->isDefault(); } d->setRestoreDefaultsButtonEnabled(!is_default); d->shown = true; } KPageDialog::showEvent(e); } void KConfigDialog::updateSettings() { } void KConfigDialog::updateWidgets() { } void KConfigDialog::updateWidgetsDefault() { } bool KConfigDialog::hasChanged() { return false; } bool KConfigDialog::isDefault() { return true; } void KConfigDialog::updateButtons() { d->_k_updateButtons(); } void KConfigDialog::settingsChangedSlot() { d->_k_settingsChangedSlot(); } void KConfigDialog::setHelp(const QString &anchor, const QString &appname) { d->mAnchor = anchor; d->mHelpApp = appname; } void KConfigDialog::showHelp() { KHelpClient::invokeHelp(d->mAnchor, d->mHelpApp); } #include "moc_kconfigdialog.cpp" diff --git a/src/kconfigdialogmanager.cpp b/src/kconfigdialogmanager.cpp index 27d1a92..f5f9849 100644 --- a/src/kconfigdialogmanager.cpp +++ b/src/kconfigdialogmanager.cpp @@ -1,600 +1,601 @@ /* * This file is part of the KDE libraries * Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net) * Copyright (C) 2003 Waldo Bastian * Copyright (C) 2017 Friedrich W. H. Kossebau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kconfigdialogmanager.h" #include "kconfigwidgets_debug.h" #include #include #include #include #include #include #include #include #include #include typedef QHash MyHash; Q_GLOBAL_STATIC(MyHash, s_propertyMap) Q_GLOBAL_STATIC(MyHash, s_changedMap) class KConfigDialogManagerPrivate { public: KConfigDialogManagerPrivate(KConfigDialogManager *q) : q(q), insideGroupBox(false) { } public: KConfigDialogManager *q; /** * KConfigSkeleton object used to store settings */ KCoreConfigSkeleton *m_conf = nullptr; /** * Dialog being managed */ QWidget *m_dialog = nullptr; QHash knownWidget; QHash buddyWidget; QSet allExclusiveGroupBoxes; bool insideGroupBox : 1; bool trackChanges : 1; }; KConfigDialogManager::KConfigDialogManager(QWidget *parent, KCoreConfigSkeleton *conf) : QObject(parent), d(new KConfigDialogManagerPrivate(this)) { d->m_conf = conf; d->m_dialog = parent; init(true); } KConfigDialogManager::KConfigDialogManager(QWidget *parent, KConfigSkeleton *conf) : QObject(parent), d(new KConfigDialogManagerPrivate(this)) { d->m_conf = conf; d->m_dialog = parent; init(true); } KConfigDialogManager::~KConfigDialogManager() { delete d; } // KF6: Drop this and get signals only from metaObject and/or widget's dynamic properties kcfg_property/kcfg_propertyNotify void KConfigDialogManager::initMaps() { if (s_propertyMap()->isEmpty()) { s_propertyMap()->insert(QStringLiteral("KButtonGroup"), "current"); s_propertyMap()->insert(QStringLiteral("KColorButton"), "color"); s_propertyMap()->insert(QStringLiteral("KColorCombo"), "color"); } if (s_changedMap()->isEmpty()) { // QT s_changedMap()->insert(QStringLiteral("QCheckBox"), SIGNAL(stateChanged(int))); s_changedMap()->insert(QStringLiteral("QPushButton"), SIGNAL(clicked(bool))); s_changedMap()->insert(QStringLiteral("QRadioButton"), SIGNAL(toggled(bool))); s_changedMap()->insert(QStringLiteral("QGroupBox"), SIGNAL(toggled(bool))); s_changedMap()->insert(QStringLiteral("QComboBox"), SIGNAL(activated(int))); s_changedMap()->insert(QStringLiteral("QDateEdit"), SIGNAL(dateChanged(QDate))); s_changedMap()->insert(QStringLiteral("QTimeEdit"), SIGNAL(timeChanged(QTime))); s_changedMap()->insert(QStringLiteral("QDateTimeEdit"), SIGNAL(dateTimeChanged(QDateTime))); s_changedMap()->insert(QStringLiteral("QDial"), SIGNAL(valueChanged(int))); s_changedMap()->insert(QStringLiteral("QDoubleSpinBox"), SIGNAL(valueChanged(double))); s_changedMap()->insert(QStringLiteral("QLineEdit"), SIGNAL(textChanged(QString))); s_changedMap()->insert(QStringLiteral("QSlider"), SIGNAL(valueChanged(int))); s_changedMap()->insert(QStringLiteral("QSpinBox"), SIGNAL(valueChanged(int))); s_changedMap()->insert(QStringLiteral("QTextEdit"), SIGNAL(textChanged())); s_changedMap()->insert(QStringLiteral("QTextBrowser"), SIGNAL(sourceChanged(QString))); s_changedMap()->insert(QStringLiteral("QPlainTextEdit"), SIGNAL(textChanged())); s_changedMap()->insert(QStringLiteral("QTabWidget"), SIGNAL(currentChanged(int))); // KDE s_changedMap()->insert(QStringLiteral("KComboBox"), SIGNAL(activated(int))); s_changedMap()->insert(QStringLiteral("KFontComboBox"), SIGNAL(activated(int))); s_changedMap()->insert(QStringLiteral("KFontRequester"), SIGNAL(fontSelected(QFont))); s_changedMap()->insert(QStringLiteral("KFontChooser"), SIGNAL(fontSelected(QFont))); s_changedMap()->insert(QStringLiteral("KColorCombo"), SIGNAL(activated(QColor))); s_changedMap()->insert(QStringLiteral("KColorButton"), SIGNAL(changed(QColor))); s_changedMap()->insert(QStringLiteral("KDatePicker"), SIGNAL(dateSelected(QDate))); s_changedMap()->insert(QStringLiteral("KDateWidget"), SIGNAL(changed(QDate))); s_changedMap()->insert(QStringLiteral("KDateTimeWidget"), SIGNAL(valueChanged(QDateTime))); s_changedMap()->insert(QStringLiteral("KEditListWidget"), SIGNAL(changed())); s_changedMap()->insert(QStringLiteral("KListWidget"), SIGNAL(itemSelectionChanged())); s_changedMap()->insert(QStringLiteral("KLineEdit"), SIGNAL(textChanged(QString))); s_changedMap()->insert(QStringLiteral("KRestrictedLine"), SIGNAL(textChanged(QString))); s_changedMap()->insert(QStringLiteral("KTextEdit"), SIGNAL(textChanged())); s_changedMap()->insert(QStringLiteral("KUrlRequester"), SIGNAL(textChanged(QString))); s_changedMap()->insert(QStringLiteral("KUrlComboRequester"), SIGNAL(textChanged(QString))); s_changedMap()->insert(QStringLiteral("KUrlComboBox"), SIGNAL(urlActivated(QUrl))); s_changedMap()->insert(QStringLiteral("KButtonGroup"), SIGNAL(changed(int))); } } QHash *KConfigDialogManager::propertyMap() { initMaps(); return s_propertyMap(); } QHash *KConfigDialogManager::changedMap() { initMaps(); return s_changedMap(); } void KConfigDialogManager::init(bool trackChanges) { initMaps(); d->trackChanges = trackChanges; // Go through all of the children of the widgets and find all known widgets (void) parseChildren(d->m_dialog, trackChanges); } void KConfigDialogManager::addWidget(QWidget *widget) { (void) parseChildren(widget, true); } void KConfigDialogManager::setupWidget(QWidget *widget, KConfigSkeletonItem *item) { QVariant minValue = item->minValue(); if (minValue.isValid()) { // Only q3datetimeedit is using this property we can remove it if we stop supporting Qt3Support if (widget->metaObject()->indexOfProperty("minValue") != -1) { widget->setProperty("minValue", minValue); } if (widget->metaObject()->indexOfProperty("minimum") != -1) { widget->setProperty("minimum", minValue); } } QVariant maxValue = item->maxValue(); if (maxValue.isValid()) { // Only q3datetimeedit is using that property we can remove it if we stop supporting Qt3Support if (widget->metaObject()->indexOfProperty("maxValue") != -1) { widget->setProperty("maxValue", maxValue); } if (widget->metaObject()->indexOfProperty("maximum") != -1) { widget->setProperty("maximum", maxValue); } } if (widget->whatsThis().isEmpty()) { QString whatsThis = item->whatsThis(); if (!whatsThis.isEmpty()) { widget->setWhatsThis(whatsThis); } } if (widget->toolTip().isEmpty()) { QString toolTip = item->toolTip(); if (!toolTip.isEmpty()) { widget->setToolTip(toolTip); } } // If it is a QGroupBox with only autoExclusive buttons // and has no custom property and the config item type // is an integer, assume we want to save the index like we did with // KButtonGroup instead of if it is checked or not QGroupBox *gb = qobject_cast(widget); if (gb && getCustomProperty(gb).isEmpty()) { const KConfigSkeletonItem *item = d->m_conf->findItem(widget->objectName().mid(5)); if (item->property().type() == QVariant::Int) { QObjectList children = gb->children(); children.removeAll(gb->layout()); const QList buttons = gb->findChildren(); bool allAutoExclusiveDirectChildren = true; foreach(QAbstractButton *button, buttons) { allAutoExclusiveDirectChildren = allAutoExclusiveDirectChildren && button->autoExclusive() && button->parent() == gb; } if (allAutoExclusiveDirectChildren) { d->allExclusiveGroupBoxes << widget; } } } if (!item->isEqual(property(widget))) { setProperty(widget, item->property()); } } bool KConfigDialogManager::parseChildren(const QWidget *widget, bool trackChanges) { bool valueChanged = false; const QList listOfChildren = widget->children(); if (listOfChildren.count() == 0) { //?? XXX return valueChanged; } const QMetaMethod widgetModifiedSignal = metaObject()->method(metaObject()->indexOfSignal("widgetModified()")); Q_ASSERT(widgetModifiedSignal.isValid() && metaObject()->indexOfSignal("widgetModified()")>=0); foreach (QObject *object, listOfChildren) { if (!object->isWidgetType()) { continue; // Skip non-widgets } QWidget *childWidget = static_cast(object); QString widgetName = childWidget->objectName(); bool bParseChildren = true; bool bSaveInsideGroupBox = d->insideGroupBox; if (widgetName.startsWith(QLatin1String("kcfg_"))) { // This is one of our widgets! QString configId = widgetName.mid(5); KConfigSkeletonItem *item = d->m_conf->findItem(configId); if (item) { d->knownWidget.insert(configId, childWidget); setupWidget(childWidget, item); if (trackChanges) { bool changeSignalFound = false; if (d->allExclusiveGroupBoxes.contains(childWidget)) { const QList buttons = childWidget->findChildren(); foreach(QAbstractButton *button, buttons) { - connect(button, SIGNAL(toggled(bool)), this, SIGNAL(widgetModified())); + connect(button, &QAbstractButton::toggled, + this, &KConfigDialogManager::widgetModified); } } QByteArray propertyChangeSignal = getCustomPropertyChangedSignal(childWidget); if (propertyChangeSignal.isEmpty()) { propertyChangeSignal = getUserPropertyChangedSignal(childWidget); } if (propertyChangeSignal.isEmpty()) { // get the change signal from the meta object const QMetaObject *metaObject = childWidget->metaObject(); QByteArray userproperty = getCustomProperty(childWidget); if (userproperty.isEmpty()) { userproperty = getUserProperty(childWidget); } if (!userproperty.isEmpty()) { const int indexOfProperty = metaObject->indexOfProperty(userproperty); if (indexOfProperty != -1) { const QMetaProperty property = metaObject->property(indexOfProperty); const QMetaMethod notifySignal = property.notifySignal(); if (notifySignal.isValid()) { connect(childWidget, notifySignal, this, widgetModifiedSignal); changeSignalFound = true; } } } else { qCWarning(KCONFIG_WIDGETS_LOG) << "Don't know how to monitor widget '" << childWidget->metaObject()->className() << "' for changes!"; } } else { connect(childWidget, propertyChangeSignal, this, SIGNAL(widgetModified())); changeSignalFound = true; } if (changeSignalFound) { QComboBox *cb = qobject_cast(childWidget); if (cb && cb->isEditable()) - connect(cb, SIGNAL(editTextChanged(QString)), - this, SIGNAL(widgetModified())); + connect(cb, &QComboBox::editTextChanged, + this, &KConfigDialogManager::widgetModified); } } QGroupBox *gb = qobject_cast(childWidget); if (!gb) { bParseChildren = false; } else { d->insideGroupBox = true; } } else { qCWarning(KCONFIG_WIDGETS_LOG) << "A widget named '" << widgetName << "' was found but there is no setting named '" << configId << "'"; } } else if (QLabel *label = qobject_cast(childWidget)) { QWidget *buddy = label->buddy(); if (!buddy) { continue; } QString buddyName = buddy->objectName(); if (buddyName.startsWith(QLatin1String("kcfg_"))) { // This is one of our widgets! QString configId = buddyName.mid(5); d->buddyWidget.insert(configId, childWidget); } } //kf5: commented out to reduce debug output // #ifndef NDEBUG // else if (!widgetName.isEmpty() && trackChanges) // { // QHash::const_iterator changedIt = s_changedMap()->constFind(childWidget->metaObject()->className()); // if (changedIt != s_changedMap()->constEnd()) // { // if ((!d->insideGroupBox || !qobject_cast(childWidget)) && // !qobject_cast(childWidget) &&!qobject_cast(childWidget) ) // qCDebug(KCONFIG_WIDGETS_LOG) << "Widget '" << widgetName << "' (" << childWidget->metaObject()->className() << ") remains unmanaged."; // } // } // #endif if (bParseChildren) { // this widget is not known as something we can store. // Maybe we can store one of its children. valueChanged |= parseChildren(childWidget, trackChanges); } d->insideGroupBox = bSaveInsideGroupBox; } return valueChanged; } void KConfigDialogManager::updateWidgets() { bool changed = false; bool bSignalsBlocked = signalsBlocked(); blockSignals(true); QWidget *widget; QHashIterator it(d->knownWidget); while (it.hasNext()) { it.next(); widget = it.value(); KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); if (!item) { qCWarning(KCONFIG_WIDGETS_LOG) << "The setting '" << it.key() << "' has disappeared!"; continue; } if (!item->isEqual(property(widget))) { setProperty(widget, item->property()); // qCDebug(KCONFIG_WIDGETS_LOG) << "The setting '" << it.key() << "' [" << widget->className() << "] has changed"; changed = true; } if (item->isImmutable()) { widget->setEnabled(false); QWidget *buddy = d->buddyWidget.value(it.key(), nullptr); if (buddy) { buddy->setEnabled(false); } } } blockSignals(bSignalsBlocked); if (changed) { - QTimer::singleShot(0, this, SIGNAL(widgetModified())); + QTimer::singleShot(0, this, &KConfigDialogManager::widgetModified); } } void KConfigDialogManager::updateWidgetsDefault() { bool bUseDefaults = d->m_conf->useDefaults(true); updateWidgets(); d->m_conf->useDefaults(bUseDefaults); } void KConfigDialogManager::updateSettings() { bool changed = false; QWidget *widget; QHashIterator it(d->knownWidget); while (it.hasNext()) { it.next(); widget = it.value(); KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); if (!item) { qCWarning(KCONFIG_WIDGETS_LOG) << "The setting '" << it.key() << "' has disappeared!"; continue; } QVariant fromWidget = property(widget); if (!item->isEqual(fromWidget)) { item->setProperty(fromWidget); changed = true; } } if (changed) { d->m_conf->save(); emit settingsChanged(); } } QByteArray KConfigDialogManager::getUserProperty(const QWidget *widget) const { if (!s_propertyMap()->contains(widget->metaObject()->className())) { const QMetaObject *metaObject = widget->metaObject(); const QMetaProperty user = metaObject->userProperty(); if (user.isValid()) { s_propertyMap()->insert(widget->metaObject()->className(), user.name()); //qCDebug(KCONFIG_WIDGETS_LOG) << "class name: '" << widget->metaObject()->className() //<< " 's USER property: " << metaProperty.name() << endl; } else { return QByteArray(); //no USER property } } const QComboBox *cb = qobject_cast(widget); if (cb) { const char *qcomboUserPropertyName = cb->QComboBox::metaObject()->userProperty().name(); const int qcomboUserPropertyIndex = qcomboUserPropertyName ? cb->QComboBox::metaObject()->indexOfProperty(qcomboUserPropertyName) : -1; const char *widgetUserPropertyName = widget->metaObject()->userProperty().name(); const int widgetUserPropertyIndex = widgetUserPropertyName ? cb->metaObject()->indexOfProperty(widgetUserPropertyName) : -1; // no custom user property set on subclass of QComboBox? if (qcomboUserPropertyIndex == widgetUserPropertyIndex) { return QByteArray(); // use the q/kcombobox special code } } return s_propertyMap()->value(widget->metaObject()->className()); } QByteArray KConfigDialogManager::getCustomProperty(const QWidget *widget) const { QVariant prop(widget->property("kcfg_property")); if (prop.isValid()) { if (!prop.canConvert(QVariant::ByteArray)) { qCWarning(KCONFIG_WIDGETS_LOG) << "kcfg_property on" << widget->metaObject()->className() << "is not of type ByteArray"; } else { return prop.toByteArray(); } } return QByteArray(); } QByteArray KConfigDialogManager::getUserPropertyChangedSignal(const QWidget *widget) const { QHash::const_iterator changedIt = s_changedMap()->constFind(widget->metaObject()->className()); if (changedIt == s_changedMap()->constEnd()) { // If the class name of the widget wasn't in the monitored widgets map, then look for // it again using the super class name. This fixes a problem with using QtRuby/Korundum // widgets with KConfigXT where 'Qt::Widget' wasn't being seen a the real deal, even // though it was a 'QWidget'. if (widget->metaObject()->superClass()) { changedIt = s_changedMap()->constFind(widget->metaObject()->superClass()->className()); } } return (changedIt == s_changedMap()->constEnd()) ? QByteArray() : *changedIt; } QByteArray KConfigDialogManager::getCustomPropertyChangedSignal(const QWidget *widget) const { QVariant prop(widget->property("kcfg_propertyNotify")); if (prop.isValid()) { if (!prop.canConvert(QVariant::ByteArray)) { qCWarning(KCONFIG_WIDGETS_LOG) << "kcfg_propertyNotify on" << widget->metaObject()->className() << "is not of type ByteArray"; } else { return prop.toByteArray(); } } return QByteArray(); } void KConfigDialogManager::setProperty(QWidget *w, const QVariant &v) { if (d->allExclusiveGroupBoxes.contains(w)) { const QList buttons = w->findChildren(); if (v.toInt() < buttons.count()) { buttons[v.toInt()]->setChecked(true); } return; } QByteArray userproperty = getCustomProperty(w); if (userproperty.isEmpty()) { userproperty = getUserProperty(w); } if (userproperty.isEmpty()) { QComboBox *cb = qobject_cast(w); if (cb) { if (cb->isEditable()) { int i = cb->findText(v.toString()); if (i != -1) { cb->setCurrentIndex(i); } else { cb->setEditText(v.toString()); } } else { cb->setCurrentIndex(v.toInt()); } return; } } if (userproperty.isEmpty()) { qCWarning(KCONFIG_WIDGETS_LOG) << w->metaObject()->className() << " widget not handled!"; return; } w->setProperty(userproperty, v); } QVariant KConfigDialogManager::property(QWidget *w) const { if (d->allExclusiveGroupBoxes.contains(w)) { const QList buttons = w->findChildren(); for (int i = 0; i < buttons.count(); ++i) { if (buttons[i]->isChecked()) return i; } return -1; } QByteArray userproperty = getCustomProperty(w); if (userproperty.isEmpty()) { userproperty = getUserProperty(w); } if (userproperty.isEmpty()) { QComboBox *cb = qobject_cast(w); if (cb) { if (cb->isEditable()) { return QVariant(cb->currentText()); } else { return QVariant(cb->currentIndex()); } } } if (userproperty.isEmpty()) { qCWarning(KCONFIG_WIDGETS_LOG) << w->metaObject()->className() << " widget not handled!"; return QVariant(); } return w->property(userproperty); } bool KConfigDialogManager::hasChanged() const { QWidget *widget; QHashIterator it(d->knownWidget); while (it.hasNext()) { it.next(); widget = it.value(); KConfigSkeletonItem *item = d->m_conf->findItem(it.key()); if (!item) { qCWarning(KCONFIG_WIDGETS_LOG) << "The setting '" << it.key() << "' has disappeared!"; continue; } if (!item->isEqual(property(widget))) { // qCDebug(KCONFIG_WIDGETS_LOG) << "Widget for '" << it.key() << "' has changed."; return true; } } return false; } bool KConfigDialogManager::isDefault() const { bool bUseDefaults = d->m_conf->useDefaults(true); bool result = !hasChanged(); d->m_conf->useDefaults(bUseDefaults); return result; } diff --git a/src/klanguagebutton.cpp b/src/klanguagebutton.cpp index f530651..9d69770 100644 --- a/src/klanguagebutton.cpp +++ b/src/klanguagebutton.cpp @@ -1,302 +1,302 @@ /* * Copyright (c) 1999-2003 Hans Petter Bieker * (c) 2007 David Jarvie * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "klanguagebutton.h" #include "kconfigwidgets_debug.h" #include #include #include #include #include #include #include #include static void checkInsertPos(QMenu *popup, const QString &str, int &index) { if (index != -1) { return; } int a = 0; const QList actions = popup->actions(); int b = actions.count(); while (a < b) { int w = (a + b) / 2; QAction *ac = actions[ w ]; int j = str.localeAwareCompare(ac->text()); if (j > 0) { a = w + 1; } else { b = w; } } index = a; // it doesn't really matter ... a == b here. Q_ASSERT(a == b); } class KLanguageButtonPrivate { public: explicit KLanguageButtonPrivate(KLanguageButton *parent); ~KLanguageButtonPrivate() { delete button; delete popup; } void setCurrentItem(QAction *); void clear(); QAction *findAction(const QString &data) const; QPushButton *button = nullptr; QStringList ids; QMenu *popup = nullptr; QString current; QString locale; bool staticText : 1; bool showCodes : 1; }; KLanguageButton::KLanguageButton(QWidget *parent) : QWidget(parent), d(new KLanguageButtonPrivate(this)) { } KLanguageButton::KLanguageButton(const QString &text, QWidget *parent) : QWidget(parent), d(new KLanguageButtonPrivate(this)) { setText(text); } KLanguageButtonPrivate::KLanguageButtonPrivate(KLanguageButton *parent) : button(new QPushButton(parent)), popup(new QMenu(parent)), locale(QLocale::system().name()), staticText(false), showCodes(false) { QHBoxLayout *layout = new QHBoxLayout(parent); layout->setMargin(0); layout->addWidget(button); parent->setFocusProxy(button); parent->setFocusPolicy(button->focusPolicy()); button->setMenu(popup); - QObject::connect(popup, SIGNAL(triggered(QAction*)), parent, SLOT(slotTriggered(QAction*))); - QObject::connect(popup, SIGNAL(hovered(QAction*)), parent, SLOT(slotHovered(QAction*))); + QObject::connect(popup, &QMenu::triggered, parent, &KLanguageButton::slotTriggered); + QObject::connect(popup, &QMenu::hovered, parent, &KLanguageButton::slotHovered); } KLanguageButton::~KLanguageButton() { delete d; } void KLanguageButton::setText(const QString &text) { d->staticText = true; d->button->setText(text); } void KLanguageButton::setLocale(const QString &locale) { d->locale = locale; } void KLanguageButton::showLanguageCodes(bool show) { d->showCodes = show; } static QString nameFromEntryFile(const QString &entryFile) { const KConfig entry(entryFile, KConfig::SimpleConfig); const KConfigGroup group(&entry, "KCM Locale"); return group.readEntry("Name", QString()); } void KLanguageButton::insertLanguage(const QString &languageCode, const QString &name, int index) { QString text; bool showCodes = d->showCodes; if (name.isEmpty()) { const QString entryFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("locale/") + languageCode + QStringLiteral("/kf5_entry.desktop")); if (QFile::exists(entryFile)) { text = nameFromEntryFile(entryFile); } if (text.isEmpty()) { text = languageCode; QLocale locale(languageCode); if (locale != QLocale::c()) { text = locale.nativeLanguageName(); // For some languages the native name might be empty. // In this case use the non native language name as fallback. // See: QTBUG-51323 text = text.isEmpty() ? QLocale::languageToString(locale.language()) : text; } else { showCodes = false; } } } else { text = name; } if (showCodes) { text += QLatin1String(" (") + languageCode + QLatin1Char(')'); } checkInsertPos(d->popup, text, index); QAction *a = new QAction(QIcon(), text, this); a->setData(languageCode); if (index >= 0 && index < d->popup->actions().count() - 1) { d->popup->insertAction(d->popup->actions()[index], a); } else { d->popup->addAction(a); } d->ids.append(languageCode); } void KLanguageButton::insertSeparator(int index) { if (index >= 0 && index < d->popup->actions().count() - 1) { d->popup->insertSeparator(d->popup->actions()[index]); } else { d->popup->addSeparator(); } } void KLanguageButton::loadAllLanguages() { QStringList langlist; const QStringList localeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("locale"), QStandardPaths::LocateDirectory); for (const QString &localeDir : localeDirs) { const QStringList entries = QDir(localeDir).entryList(QDir::Dirs); for (const QString &d : entries) { const QString entryFile = localeDir + QLatin1Char('/') + d + QStringLiteral("/kf5_entry.desktop"); if (QFile::exists(entryFile)) { langlist.append(entryFile); } } } langlist.sort(); for (int i = 0, count = langlist.count(); i < count; ++i) { QString fpath = langlist[i].left(langlist[i].length() - 14); QString code = fpath.mid(fpath.lastIndexOf(QLatin1Char('/')) + 1); insertLanguage(code); } setCurrentItem(d->locale); } void KLanguageButton::slotTriggered(QAction *a) { //qCDebug(KCONFIG_WIDGETS_LOG) << "slotTriggered" << index; if (!a) { return; } d->setCurrentItem(a); // Forward event from popup menu as if it was emitted from this widget: emit activated(d->current); } void KLanguageButton::slotHovered(QAction *a) { //qCDebug(KCONFIG_WIDGETS_LOG) << "slotHovered" << index; emit highlighted(a->data().toString()); } int KLanguageButton::count() const { return d->ids.count(); } void KLanguageButton::clear() { d->clear(); } void KLanguageButtonPrivate::clear() { ids.clear(); popup->clear(); if (!staticText) { button->setText(QString()); } } bool KLanguageButton::contains(const QString &languageCode) const { return d->ids.contains(languageCode); } QString KLanguageButton::current() const { return d->current.isEmpty() ? QStringLiteral("en") : d->current; } QAction *KLanguageButtonPrivate::findAction(const QString &data) const { Q_FOREACH (QAction *a, popup->actions()) { if (!a->data().toString().compare(data)) { return a; } } return nullptr; } void KLanguageButton::setCurrentItem(const QString &languageCode) { if (!d->ids.count()) { return; } QAction *a; if (d->ids.indexOf(languageCode) < 0) { a = d->findAction(d->ids[0]); } else { a = d->findAction(languageCode); } if (a) { d->setCurrentItem(a); } } void KLanguageButtonPrivate::setCurrentItem(QAction *a) { if (!a->data().isValid()) { return; } current = a->data().toString(); if (!staticText) { button->setText(a->text()); } } diff --git a/src/klanguagebutton.h b/src/klanguagebutton.h index c5f2408..d16e1f3 100644 --- a/src/klanguagebutton.h +++ b/src/klanguagebutton.h @@ -1,177 +1,178 @@ /* * klangbutton.h - Button with language selection drop down menu. * Derived from the KLangCombo class by Hans Petter Bieker. * * Copyright (c) 1999-2003 Hans Petter Bieker * (c) 2001 Martijn Klingens * (c) 2007 David Jarvie * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KLANGUAGEBUTTON_H #define KLANGUAGEBUTTON_H #include "kconfigwidgets_export.h" #include class QAction; class KLanguageButtonPrivate; /** * @class KLanguageButton klanguagebutton.h KLanguageButton * * KLanguageButton is a pushbutton which allows a language to be selected from * a popup list. * * Languages are identified by their ISO 639-1 codes, e.g. en, pt_BR. * * \image html klanguagebutton.png "KDE Language Selection Widget" * * @author Hans Petter Bieker , Martijn Klingens , * David Jarvie */ class KCONFIGWIDGETS_EXPORT KLanguageButton : public QWidget { Q_OBJECT public: /** * Constructs a button whose text is determined by the current language * in the popup list. * * @param parent the parent of the button */ explicit KLanguageButton(QWidget *parent = nullptr); /** * Constructs a button with static text. * * @param text the text of the button * @param parent the parent of the button */ explicit KLanguageButton(const QString &text, QWidget *parent = nullptr); /** * Deconstructor */ virtual ~KLanguageButton(); /** * Sets the locale to display language names. By default, QLocale::system().name() is used. * * @param locale locale to use */ void setLocale(const QString &locale); /** * Sets a static button text. * * @param text button text */ void setText(const QString &text); /** * Specifies whether language codes should be shown alongside language names * in the popup. Calling this method does not affect any previously * inserted language texts, so it should normally be called before * populating the list. * * @param show true to show codes, false to hide codes */ void showLanguageCodes(bool show); /** * Load all known languages into the popup list. * The current language in the list is set to the default language for the * current locale (as modified by setLocale()). */ void loadAllLanguages(); /** * Inserts a language into the combo box. * Normally the display name of the language is obtained automatically, but * if either the language code does not exist, or there are special display * requirements, the name of the language can be specified in @p name. * * @param languageCode the code for the language * @param name language name. If empty, the name is obtained automatically. * @param index the insertion position, or -1 to insert in alphabetical order */ void insertLanguage(const QString &languageCode, const QString &name = QString(), int index = -1); /** * Inserts a separator item into the combo box. A negative index will append the item. * * @param index the insertion position */ void insertSeparator(int index = -1); /** * Returns the number of items in the combo box. */ int count() const; /** * Removes all combobox items. */ void clear(); /** * Returns the language code of the combobox's current item. * * @return the current item's language code */ QString current() const; /** * Checks whether the specified language is in the popup list. * * @param languageCode the language's code * @return true if in the list */ bool contains(const QString &languageCode) const; /** * Sets a given language to be the current item. * * @param languageCode the language's code */ void setCurrentItem(const QString &languageCode); Q_SIGNALS: /** * This signal is emitted when a new item is activated. * * @param languageCode code of the activated language */ void activated(const QString &languageCode); /** * This signal is emitted when a new item is highlighted. * * @param languageCode code of the highlighted language */ void highlighted(const QString &languageCode); private Q_SLOTS: void slotTriggered(QAction *); void slotHovered(QAction *); private: + friend class KLanguageButtonPrivate; KLanguageButtonPrivate *const d; }; #endif diff --git a/src/krecentfilesaction.cpp b/src/krecentfilesaction.cpp index 4c4c2f6..ec87406 100644 --- a/src/krecentfilesaction.cpp +++ b/src/krecentfilesaction.cpp @@ -1,345 +1,345 @@ /* This file is part of the KDE libraries Copyright (C) 1999 Reginald Stadlbauer (C) 1999 Simon Hausmann (C) 2000 Nicolas Hadacek (C) 2000 Kurt Granroth (C) 2000 Michael Koch (C) 2001 Holger Freyther (C) 2002 Ellis Whitehead (C) 2002 Joseph Wenninger (C) 2003 Andras Mantia (C) 2005-2006 Hamish Rodda 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 "krecentfilesaction.h" #include "krecentfilesaction_p.h" #include #include #include #include #include #include #include #include KRecentFilesAction::KRecentFilesAction(QObject *parent) : KSelectAction(parent), d_ptr(new KRecentFilesActionPrivate(this)) { Q_D(KRecentFilesAction); d->init(); } KRecentFilesAction::KRecentFilesAction(const QString &text, QObject *parent) : KSelectAction(parent), d_ptr(new KRecentFilesActionPrivate(this)) { Q_D(KRecentFilesAction); d->init(); // Want to keep the ampersands setText(text); } KRecentFilesAction::KRecentFilesAction(const QIcon &icon, const QString &text, QObject *parent) : KSelectAction(parent), d_ptr(new KRecentFilesActionPrivate(this)) { Q_D(KRecentFilesAction); d->init(); setIcon(icon); // Want to keep the ampersands setText(text); } void KRecentFilesActionPrivate::init() { Q_Q(KRecentFilesAction); delete q->menu(); q->setMenu(new QMenu()); q->setToolBarMode(KSelectAction::MenuMode); m_noEntriesAction = q->menu()->addAction(i18n("No Entries")); m_noEntriesAction->setObjectName(QStringLiteral("no_entries")); m_noEntriesAction->setEnabled(false); clearSeparator = q->menu()->addSeparator(); clearSeparator->setVisible(false); clearSeparator->setObjectName(QStringLiteral("separator")); - clearAction = q->menu()->addAction(i18n("Clear List"), q, SLOT(clear())); + clearAction = q->menu()->addAction(i18n("Clear List"), q, &KRecentFilesAction::clear); clearAction->setObjectName(QStringLiteral("clear_action")); clearAction->setVisible(false); q->setEnabled(false); q->connect(q, SIGNAL(triggered(QAction*)), SLOT(_k_urlSelected(QAction*))); } KRecentFilesAction::~KRecentFilesAction() { delete d_ptr; } void KRecentFilesActionPrivate::_k_urlSelected(QAction *action) { Q_Q(KRecentFilesAction); emit q->urlSelected(m_urls[action]); } int KRecentFilesAction::maxItems() const { Q_D(const KRecentFilesAction); return d->m_maxItems; } void KRecentFilesAction::setMaxItems(int maxItems) { Q_D(KRecentFilesAction); // set new maxItems d->m_maxItems = maxItems; // remove all excess items while (selectableActionGroup()->actions().count() > maxItems) { delete removeAction(selectableActionGroup()->actions().last()); } } static QString titleWithSensibleWidth(const QString &nameValue, const QString &value) { // Calculate 3/4 of screen geometry, we do not want // action titles to be bigger than that // Since we do not know in which screen we are going to show // we choose the min of all the screens const QDesktopWidget desktopWidget; int maxWidthForTitles = INT_MAX; for (int i = 0; i < desktopWidget.screenCount(); ++i) { maxWidthForTitles = qMin(maxWidthForTitles, desktopWidget.availableGeometry(i).width() * 3 / 4); } const QFontMetrics fontMetrics = QFontMetrics(QFont()); QString title = nameValue + QStringLiteral(" [") + value + QLatin1Char(']'); if (fontMetrics.width(title) > maxWidthForTitles) { // If it does not fit, try to cut only the whole path, though if the // name is too long (more than 3/4 of the whole text) we cut it a bit too const int nameValueMaxWidth = maxWidthForTitles * 3 / 4; const int nameWidth = fontMetrics.width(nameValue); QString cutNameValue, cutValue; if (nameWidth > nameValueMaxWidth) { cutNameValue = fontMetrics.elidedText(nameValue, Qt::ElideMiddle, nameValueMaxWidth); cutValue = fontMetrics.elidedText(value, Qt::ElideMiddle, maxWidthForTitles - nameValueMaxWidth); } else { cutNameValue = nameValue; cutValue = fontMetrics.elidedText(value, Qt::ElideMiddle, maxWidthForTitles - nameWidth); } title = cutNameValue + QStringLiteral(" [") + cutValue + QLatin1Char(']'); } return title; } void KRecentFilesAction::addUrl(const QUrl &_url, const QString &name) { Q_D(KRecentFilesAction); /** * Create a deep copy here, because if _url is the parameter from * urlSelected() signal, we will delete it in the removeAction() call below. * but access it again in the addAction call... => crash */ const QUrl url(_url); if (url.isLocalFile() && url.toLocalFile().startsWith(QDir::tempPath())) { return; } const QString tmpName = name.isEmpty() ? url.fileName() : name; const QString pathOrUrl(url.toDisplayString(QUrl::PreferLocalFile)); #ifdef Q_OS_WIN const QString file = url.isLocalFile() ? QDir::toNativeSeparators(pathOrUrl) : pathOrUrl; #else const QString file = pathOrUrl; #endif // remove file if already in list foreach (QAction *action, selectableActionGroup()->actions()) { const QString urlStr = d->m_urls[action].toDisplayString(QUrl::PreferLocalFile); #ifdef Q_OS_WIN const QString tmpFileName = url.isLocalFile() ? QDir::toNativeSeparators(urlStr) : urlStr; if (tmpFileName.endsWith(file, Qt::CaseInsensitive)) #else if (urlStr.endsWith(file)) #endif { removeAction(action)->deleteLater(); break; } } // remove oldest item if already maxitems in list if (d->m_maxItems && selectableActionGroup()->actions().count() == d->m_maxItems) { // remove oldest added item delete removeAction(selectableActionGroup()->actions().first()); } d->m_noEntriesAction->setVisible(false); d->clearSeparator->setVisible(true); d->clearAction->setVisible(true); setEnabled(true); // add file to list const QString title = titleWithSensibleWidth(tmpName, file); QAction *action = new QAction(title, selectableActionGroup()); addAction(action, url, tmpName); } void KRecentFilesAction::addAction(QAction *action, const QUrl &url, const QString &name) { Q_D(KRecentFilesAction); menu()->insertAction(menu()->actions().value(0), action); d->m_shortNames.insert(action, name); d->m_urls.insert(action, url); } QAction *KRecentFilesAction::removeAction(QAction *action) { Q_D(KRecentFilesAction); KSelectAction::removeAction(action); d->m_shortNames.remove(action); d->m_urls.remove(action); return action; } void KRecentFilesAction::removeUrl(const QUrl &url) { Q_D(KRecentFilesAction); for (QMap::ConstIterator it = d->m_urls.constBegin(); it != d->m_urls.constEnd(); ++it) if (it.value() == url) { delete removeAction(it.key()); return; } } QList KRecentFilesAction::urls() const { Q_D(const KRecentFilesAction); return d->m_urls.values(); } void KRecentFilesAction::clear() { clearEntries(); emit recentListCleared(); } void KRecentFilesAction::clearEntries() { Q_D(KRecentFilesAction); KSelectAction::clear(); d->m_shortNames.clear(); d->m_urls.clear(); d->m_noEntriesAction->setVisible(true); d->clearSeparator->setVisible(false); d->clearAction->setVisible(false); setEnabled(false); } void KRecentFilesAction::loadEntries(const KConfigGroup &_config) { Q_D(KRecentFilesAction); clearEntries(); QString key; QString value; QString nameKey; QString nameValue; QString title; QUrl url; KConfigGroup cg = _config; if (cg.name().isEmpty()) { cg = KConfigGroup(cg.config(), "RecentFiles"); } bool thereAreEntries = false; // read file list for (int i = 1; i <= d->m_maxItems; i++) { key = QStringLiteral("File%1").arg(i); value = cg.readPathEntry(key, QString()); if (value.isEmpty()) { continue; } url = QUrl::fromUserInput(value); // Don't restore if file doesn't exist anymore if (url.isLocalFile() && !QFile::exists(url.toLocalFile())) { continue; } // Don't restore where the url is already known (eg. broken config) if (d->m_urls.values().contains(url)) { continue; } #ifdef Q_OS_WIN // convert to backslashes if (url.isLocalFile()) { value = QDir::toNativeSeparators(value); } #endif nameKey = QStringLiteral("Name%1").arg(i); nameValue = cg.readPathEntry(nameKey, url.fileName()); title = titleWithSensibleWidth(nameValue, value); if (!value.isNull()) { thereAreEntries = true; addAction(new QAction(title, selectableActionGroup()), url, nameValue); } } if (thereAreEntries) { d->m_noEntriesAction->setVisible(false); d->clearSeparator->setVisible(true); d->clearAction->setVisible(true); setEnabled(true); } } void KRecentFilesAction::saveEntries(const KConfigGroup &_cg) { Q_D(KRecentFilesAction); QString key; QString value; QStringList lst = items(); KConfigGroup cg = _cg; if (cg.name().isEmpty()) { cg = KConfigGroup(cg.config(), "RecentFiles"); } cg.deleteGroup(); // write file list for (int i = 1; i <= selectableActionGroup()->actions().count(); i++) { key = QStringLiteral("File%1").arg(i); // i - 1 because we started from 1 value = d->m_urls[ selectableActionGroup()->actions()[ i - 1 ] ].toDisplayString(QUrl::PreferLocalFile); cg.writePathEntry(key, value); key = QStringLiteral("Name%1").arg(i); value = d->m_shortNames[ selectableActionGroup()->actions()[ i - 1 ] ]; cg.writePathEntry(key, value); } } #include "moc_krecentfilesaction.cpp"