File indexing completed on 2024-04-14 03:57:10

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 
0011     SPDX-License-Identifier: LGPL-2.0-or-later
0012 */
0013 
0014 #include "config-xmlgui.h"
0015 #include "kshortcutsdialog_p.h"
0016 
0017 #include <QAction>
0018 #include <QGridLayout>
0019 #include <QLabel>
0020 #include <QPainter>
0021 #include <QPen>
0022 #include <QRadioButton>
0023 
0024 #include <KLocalizedString>
0025 #if HAVE_GLOBALACCEL
0026 #include <KGlobalAccel>
0027 #endif
0028 
0029 #include "kkeysequencewidget.h"
0030 
0031 void TabConnectedWidget::paintEvent(QPaintEvent *e)
0032 {
0033     QWidget::paintEvent(e);
0034     QPainter p(this);
0035     QPen pen(QPalette().highlight().color());
0036     pen.setWidth(6);
0037     p.setPen(pen);
0038     p.drawLine(0, 0, width(), 0);
0039     if (qApp->isLeftToRight()) {
0040         p.drawLine(0, 0, 0, height());
0041     } else {
0042         p.drawLine(width(), 0, width(), height());
0043     }
0044 }
0045 
0046 ShortcutEditWidget::ShortcutEditWidget(QWidget *viewport, const QKeySequence &defaultSeq, const QKeySequence &activeSeq, bool allowLetterShortcuts)
0047     : TabConnectedWidget(viewport)
0048     , m_defaultKeySequence(defaultSeq)
0049     , m_isUpdating(false)
0050     , m_action(nullptr)
0051     , m_noneText(i18nc("No shortcut defined", "None"))
0052 {
0053     QGridLayout *layout = new QGridLayout(this);
0054 
0055     m_defaultRadio = new QRadioButton(i18nc("@option:radio", "Default:"), this);
0056     m_defaultLabel = new QLabel(m_noneText, this);
0057     const QString defaultText = defaultSeq.toString(QKeySequence::NativeText);
0058     if (!defaultText.isEmpty()) {
0059         m_defaultLabel->setText(defaultText);
0060     }
0061 
0062     m_customRadio = new QRadioButton(i18nc("@option:radio", "Custom:"), this);
0063     m_customEditor = new KKeySequenceWidget(this);
0064     m_customEditor->setModifierlessAllowed(allowLetterShortcuts);
0065 
0066     layout->addWidget(m_defaultRadio, 0, 0);
0067     layout->addWidget(m_defaultLabel, 0, 1);
0068     layout->addWidget(m_customRadio, 1, 0);
0069     layout->addWidget(m_customEditor, 1, 1);
0070     layout->setColumnStretch(2, 1);
0071 
0072     setKeySequence(activeSeq);
0073 
0074     connect(m_defaultRadio, &QRadioButton::toggled, this, &ShortcutEditWidget::defaultToggled);
0075     connect(m_customEditor, &KKeySequenceWidget::keySequenceChanged, this, &ShortcutEditWidget::setCustom);
0076     connect(m_customEditor, &KKeySequenceWidget::stealShortcut, this, &ShortcutEditWidget::stealShortcut);
0077 #if HAVE_GLOBALACCEL
0078     connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, [this](QAction *action, const QKeySequence &seq) {
0079         if (action != m_action) {
0080             return;
0081         }
0082         setKeySequence(seq);
0083     });
0084 #endif
0085 }
0086 
0087 KKeySequenceWidget::ShortcutTypes ShortcutEditWidget::checkForConflictsAgainst() const
0088 {
0089     return m_customEditor->checkForConflictsAgainst();
0090 }
0091 
0092 // slot
0093 void ShortcutEditWidget::defaultToggled(bool checked)
0094 {
0095     if (m_isUpdating) {
0096         return;
0097     }
0098 
0099     m_isUpdating = true;
0100     if (checked) {
0101         // The default key sequence should be activated. We check first if this is
0102         // possible.
0103         if (m_customEditor->isKeySequenceAvailable(m_defaultKeySequence)) {
0104             // Clear the customs widget
0105             m_customEditor->clearKeySequence();
0106             Q_EMIT keySequenceChanged(m_defaultKeySequence);
0107         } else {
0108             // We tried to switch to the default key sequence and failed. Go
0109             // back.
0110             m_customRadio->setChecked(true);
0111         }
0112     } else {
0113         // The empty key sequence is always valid
0114         Q_EMIT keySequenceChanged(QKeySequence());
0115     }
0116     m_isUpdating = false;
0117 }
0118 
0119 void ShortcutEditWidget::setCheckActionCollections(const QList<KActionCollection *> &checkActionCollections)
0120 {
0121     // We just forward them to out KKeySequenceWidget.
0122     m_customEditor->setCheckActionCollections(checkActionCollections);
0123 }
0124 
0125 void ShortcutEditWidget::setCheckForConflictsAgainst(KKeySequenceWidget::ShortcutTypes types)
0126 {
0127     m_customEditor->setCheckForConflictsAgainst(types);
0128 }
0129 
0130 void ShortcutEditWidget::setComponentName(const QString &componentName)
0131 {
0132     m_customEditor->setComponentName(componentName);
0133 }
0134 
0135 void ShortcutEditWidget::setMultiKeyShortcutsAllowed(bool allowed)
0136 {
0137     // We just forward them to out KKeySequenceWidget.
0138     m_customEditor->setMultiKeyShortcutsAllowed(allowed);
0139 }
0140 
0141 bool ShortcutEditWidget::multiKeyShortcutsAllowed() const
0142 {
0143     return m_customEditor->multiKeyShortcutsAllowed();
0144 }
0145 
0146 void ShortcutEditWidget::setAction(QObject *action)
0147 {
0148     m_action = action;
0149 }
0150 
0151 // slot
0152 void ShortcutEditWidget::setCustom(const QKeySequence &seq)
0153 {
0154     if (m_isUpdating) {
0155         return;
0156     }
0157 
0158     // seq is a const reference to a private variable of KKeySequenceWidget.
0159     // Somewhere below we possible change that one. But we want to emit seq
0160     // whatever happens. So we make a copy.
0161     QKeySequence original = seq;
0162 
0163     m_isUpdating = true;
0164 
0165     // Check if the user typed in the default sequence into the custom field.
0166     // We do this by calling setKeySequence which will do the right thing.
0167     setKeySequence(original);
0168 
0169     Q_EMIT keySequenceChanged(original);
0170     m_isUpdating = false;
0171 }
0172 
0173 void ShortcutEditWidget::setKeySequence(const QKeySequence &activeSeq)
0174 {
0175     const QString seqString = activeSeq.isEmpty() ? m_noneText : activeSeq.toString(QKeySequence::NativeText);
0176     if (seqString == m_defaultLabel->text()) {
0177         m_defaultRadio->setChecked(true);
0178         m_customEditor->clearKeySequence();
0179     } else {
0180         m_customRadio->setChecked(true);
0181         // m_customEditor->setKeySequence does some stuff we only want to
0182         // execute when the sequence really changes.
0183         if (activeSeq != m_customEditor->keySequence()) {
0184             m_customEditor->setKeySequence(activeSeq);
0185         }
0186     }
0187 }