File indexing completed on 2024-03-24 04:02:26

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org>
0004     SPDX-FileCopyrightText: 1997 Nicolas Hadacek <hadacek@kde.org>
0005     SPDX-FileCopyrightText: 1998 Matthias Ettrich <ettrich@kde.org>
0006     SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
0007     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0008     SPDX-FileCopyrightText: 2007 Roberto Raggi <roberto@kdevelop.org>
0009     SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
0010     SPDX-FileCopyrightText: 2008 Michael Jansen <kde@michael-jansen.biz>
0011     SPDX-FileCopyrightText: 2008 Alexander Dymo <adymo@kdevelop.org>
0012     SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org>
0013 
0014     SPDX-License-Identifier: LGPL-2.0-or-later
0015 */
0016 
0017 #include "kshortcutsdialog.h"
0018 #include "kshortcutschemeshelper_p.h"
0019 #include "kshortcutsdialog_p.h"
0020 
0021 #include <QApplication>
0022 #include <QDialogButtonBox>
0023 #include <QDomDocument>
0024 
0025 #include <KConfigGroup>
0026 #include <KLocalizedString>
0027 #include <KMessageBox>
0028 #include <KSharedConfig>
0029 
0030 #include "kactioncollection.h"
0031 #include "kxmlguiclient.h"
0032 #include "kxmlguifactory.h"
0033 
0034 /************************************************************************/
0035 /* KShortcutsDialog                                                     */
0036 /*                                                                      */
0037 /* Originally by Nicolas Hadacek <hadacek@via.ecp.fr>                   */
0038 /*                                                                      */
0039 /* Substantially revised by Mark Donohoe <donohoe@kde.org>              */
0040 /*                                                                      */
0041 /* And by Espen Sand <espen@kde.org> 1999-10-19                         */
0042 /* (by using KDialog there is almost no code left ;)                    */
0043 /*                                                                      */
0044 /************************************************************************/
0045 
0046 QKeySequence primarySequence(const QList<QKeySequence> &sequences)
0047 {
0048     return sequences.isEmpty() ? QKeySequence() : sequences.at(0);
0049 }
0050 
0051 QKeySequence alternateSequence(const QList<QKeySequence> &sequences)
0052 {
0053     return sequences.size() <= 1 ? QKeySequence() : sequences.at(1);
0054 }
0055 
0056 class KShortcutsDialogPrivate
0057 {
0058 public:
0059     KShortcutsDialogPrivate(KShortcutsDialog *qq)
0060         : q(qq)
0061     {
0062     }
0063 
0064     QList<KActionCollection *> m_collections;
0065 
0066     void changeShortcutScheme(const QString &scheme)
0067     {
0068         if (m_keyChooser->isModified()
0069             && KMessageBox::questionTwoActions(q,
0070                                                i18n("The current shortcut scheme is modified. Save before switching to the new one?"),
0071                                                QString(),
0072                                                KStandardGuiItem::save(),
0073                                                KStandardGuiItem::discard())
0074                 == KMessageBox::PrimaryAction) {
0075             m_keyChooser->save();
0076         } else {
0077             m_keyChooser->undo();
0078         }
0079 
0080         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0081         m_keyChooser->clearCollections();
0082 
0083         for (KActionCollection *collection : std::as_const(m_collections)) {
0084             // passing an empty stream forces the clients to reread the XML
0085             KXMLGUIClient *client = const_cast<KXMLGUIClient *>(collection->parentGUIClient());
0086             if (client) {
0087                 client->setXMLGUIBuildDocument(QDomDocument());
0088             }
0089         }
0090 
0091         // get xmlguifactory
0092         if (!m_collections.isEmpty()) {
0093             const KXMLGUIClient *client = m_collections.first()->parentGUIClient();
0094             if (client) {
0095                 KXMLGUIFactory *factory = client->factory();
0096                 if (factory) {
0097                     factory->changeShortcutScheme(scheme);
0098                 }
0099             }
0100         }
0101 
0102         for (KActionCollection *collection : std::as_const(m_collections)) {
0103             m_keyChooser->addCollection(collection);
0104         }
0105 
0106         QApplication::restoreOverrideCursor();
0107     }
0108 
0109     void undo()
0110     {
0111         m_keyChooser->undo();
0112     }
0113 
0114     void toggleDetails()
0115     {
0116         const bool isVisible = m_schemeEditor->isVisible();
0117 
0118         m_schemeEditor->setVisible(!isVisible);
0119         m_detailsButton->setText(detailsButtonText() + (isVisible ? QStringLiteral(" >>") : QStringLiteral(" <<")));
0120     }
0121 
0122     static QString detailsButtonText()
0123     {
0124         return i18n("Manage &Schemes");
0125     }
0126 
0127     void save()
0128     {
0129         m_keyChooser->save();
0130         Q_EMIT q->saved();
0131     }
0132 
0133     KShortcutsDialog *const q;
0134     KShortcutsEditor *m_keyChooser = nullptr; // ### move
0135     KShortcutSchemesEditor *m_schemeEditor = nullptr;
0136     QPushButton *m_detailsButton = nullptr;
0137     bool m_saveSettings = false;
0138 };
0139 
0140 KShortcutsDialog::KShortcutsDialog(QWidget *parent)
0141     : KShortcutsDialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, parent)
0142 {
0143 }
0144 
0145 KShortcutsDialog::KShortcutsDialog(KShortcutsEditor::ActionTypes types, KShortcutsEditor::LetterShortcuts allowLetterShortcuts, QWidget *parent)
0146     : QDialog(parent)
0147     , d(new KShortcutsDialogPrivate(this))
0148 {
0149     setWindowTitle(i18nc("@title:window", "Configure Keyboard Shortcuts"));
0150     setModal(true);
0151 
0152     QVBoxLayout *layout = new QVBoxLayout(this);
0153 
0154     d->m_keyChooser = new KShortcutsEditor(this, types, allowLetterShortcuts);
0155     layout->addWidget(d->m_keyChooser);
0156 
0157     d->m_schemeEditor = new KShortcutSchemesEditor(this);
0158     connect(d->m_schemeEditor, &KShortcutSchemesEditor::shortcutsSchemeChanged, this, [this](const QString &scheme) {
0159         d->changeShortcutScheme(scheme);
0160     });
0161     d->m_schemeEditor->hide();
0162     layout->addWidget(d->m_schemeEditor);
0163 
0164     d->m_detailsButton = new QPushButton;
0165     d->m_detailsButton->setText(KShortcutsDialogPrivate::detailsButtonText() + QLatin1String(" >>"));
0166 
0167     QPushButton *printButton = new QPushButton;
0168     KGuiItem::assign(printButton, KStandardGuiItem::print());
0169 
0170     QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
0171     buttonBox->addButton(d->m_detailsButton, QDialogButtonBox::ActionRole);
0172     buttonBox->addButton(printButton, QDialogButtonBox::ActionRole);
0173     buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults);
0174     KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok());
0175     KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
0176     KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults());
0177     layout->addWidget(buttonBox);
0178 
0179     connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, d->m_keyChooser, &KShortcutsEditor::allDefault);
0180     connect(d->m_detailsButton, &QPushButton::clicked, this, [this]() {
0181         d->toggleDetails();
0182     });
0183     connect(printButton, &QPushButton::clicked, d->m_keyChooser, &KShortcutsEditor::printShortcuts);
0184     connect(buttonBox, &QDialogButtonBox::rejected, this, [this]() {
0185         d->undo();
0186     });
0187 
0188     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0189     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0190 
0191     KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("KShortcutsDialog Settings"));
0192     resize(group.readEntry("Dialog Size", sizeHint()));
0193 }
0194 
0195 KShortcutsDialog::~KShortcutsDialog()
0196 {
0197     KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("KShortcutsDialog Settings"));
0198     group.writeEntry("Dialog Size", size(), KConfigGroup::Persistent | KConfigGroup::Global);
0199 }
0200 
0201 void KShortcutsDialog::addCollection(KActionCollection *collection, const QString &title)
0202 {
0203     d->m_keyChooser->addCollection(collection, title);
0204     d->m_collections << collection;
0205 }
0206 
0207 QList<KActionCollection *> KShortcutsDialog::actionCollections() const
0208 {
0209     return d->m_collections;
0210 }
0211 
0212 // TODO KF6: remove this method, always save settings, and open the
0213 // dialog with show() not exec()
0214 bool KShortcutsDialog::configure(bool saveSettings)
0215 {
0216     d->m_saveSettings = saveSettings;
0217     if (isModal()) {
0218         int retcode = exec();
0219         return retcode;
0220     } else {
0221         show();
0222         return false;
0223     }
0224 }
0225 
0226 void KShortcutsDialog::accept()
0227 {
0228     if (d->m_saveSettings) {
0229         d->save();
0230     }
0231     QDialog::accept();
0232 }
0233 
0234 QSize KShortcutsDialog::sizeHint() const
0235 {
0236     return QSize(600, 480);
0237 }
0238 
0239 // static
0240 void KShortcutsDialog::showDialog(KActionCollection *collection, KShortcutsEditor::LetterShortcuts allowLetterShortcuts, QWidget *parent)
0241 {
0242     auto *dlg = new KShortcutsDialog(KShortcutsEditor::AllActions, allowLetterShortcuts, parent);
0243     dlg->setAttribute(Qt::WA_DeleteOnClose);
0244 
0245     dlg->d->m_saveSettings = true; // Always save settings if the dialog is accepted
0246 
0247     dlg->addCollection(collection);
0248     dlg->show();
0249 }
0250 
0251 void KShortcutsDialog::importConfiguration(const QString &path)
0252 {
0253     KConfig config(path);
0254     d->m_keyChooser->importConfiguration(static_cast<KConfigBase *>(&config));
0255 }
0256 
0257 void KShortcutsDialog::exportConfiguration(const QString &path) const
0258 {
0259     KConfig config(path);
0260     d->m_keyChooser->exportConfiguration(static_cast<KConfigBase *>(&config));
0261 }
0262 
0263 void KShortcutsDialog::refreshSchemes()
0264 {
0265     d->m_schemeEditor->refreshSchemes();
0266 }
0267 
0268 void KShortcutsDialog::addActionToSchemesMoreButton(QAction *action)
0269 {
0270     d->m_schemeEditor->addMoreMenuAction(action);
0271 }
0272 
0273 #include "moc_kshortcutsdialog.cpp"
0274 #include "moc_kshortcutsdialog_p.cpp"