File indexing completed on 2024-05-12 04:06:25

0001 /*
0002     SPDX-FileCopyrightText: 2010 Stefan Majewsky <majewsky@gmx.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "trigger.h"
0008 
0009 #include <QMap>
0010 #include <KLocalizedString>
0011 
0012 namespace
0013 {
0014     class ByteArrayList : public QList<QByteArray>
0015     {
0016         public:
0017             QByteArray join(const QChar& separator) const
0018             {
0019                 char sep = separator.toLatin1();
0020                 if (isEmpty())
0021                     return QByteArray();
0022                 int size = -1;
0023                 for (int i = 0; i < count(); ++i)
0024                     size += 1 + at(i).size();
0025                 QByteArray result;
0026                 result.reserve(size);
0027                 for (int i = 0; i < count(); ++i)
0028                 {
0029                     if (i != 0)
0030                         result.append(sep);
0031                     result.append(at(i));
0032                 }
0033                 return result;
0034             }
0035     };
0036 
0037     template<typename T, typename ListType> struct TriggerData
0038     {
0039         QMap<Qt::KeyboardModifier, T> m_modifierStrings;
0040         QMap<Qt::MouseButton, T> m_buttonStrings;
0041         QMap<Qt::Orientation, T> m_orientationStrings;
0042 
0043         T modifierString(Qt::KeyboardModifiers modifiers, const QChar& separator) const
0044         {
0045             typename QMap<Qt::KeyboardModifier, T>::const_iterator it1 = m_modifierStrings.begin(), it2 = m_modifierStrings.end();
0046             ListType modifierStrings;
0047             for (; it1 != it2; ++it1)
0048                 if (modifiers & it1.key())
0049                     modifierStrings << it1.value();
0050             return modifierStrings.join(separator);
0051         }
0052 
0053         T actionString(Qt::Orientation wheelDirection, Qt::MouseButton button) const
0054         {
0055             if (m_orientationStrings.contains(wheelDirection))
0056                 return m_orientationStrings.value(wheelDirection);
0057             else
0058                 return m_buttonStrings.value(button);
0059         }
0060     };
0061 
0062     struct TriggerParserData : public TriggerData<QByteArray, ByteArrayList>
0063     {
0064         TriggerParserData()
0065         {
0066             m_modifierStrings[Qt::ShiftModifier] = "ShiftModifier";
0067             m_modifierStrings[Qt::ControlModifier] = "ControlModifier";
0068             m_modifierStrings[Qt::AltModifier] = "AltModifier";
0069             m_modifierStrings[Qt::MetaModifier] = "MetaModifier";
0070             m_modifierStrings[Qt::GroupSwitchModifier] = "GroupSwitchModifier";
0071             m_buttonStrings[Qt::NoButton] = "NoButton";
0072             m_buttonStrings[Qt::LeftButton] = "LeftButton";
0073             m_buttonStrings[Qt::RightButton] = "RightButton";
0074             m_buttonStrings[Qt::MiddleButton] = "MidButton";
0075             m_buttonStrings[Qt::XButton1] = "XButton1";
0076             m_buttonStrings[Qt::XButton2] = "XButton2";
0077             m_orientationStrings[Qt::Horizontal] = "wheel:Horizontal";
0078             m_orientationStrings[Qt::Vertical] = "wheel:Vertical";
0079         }
0080     };
0081 
0082     struct TriggerPrinterData : public TriggerData<QString, QStringList>
0083     {
0084         TriggerPrinterData()
0085         {
0086             //FIXME: These are probably wrong for Macs.
0087             m_modifierStrings[Qt::ShiftModifier] = i18nc("a keyboard modifier", "Shift");
0088             m_modifierStrings[Qt::ControlModifier] = i18nc("a keyboard modifier", "Ctrl");
0089             m_modifierStrings[Qt::AltModifier] = i18nc("a keyboard modifier", "Alt");
0090             m_modifierStrings[Qt::MetaModifier] = i18nc("a keyboard modifier", "Meta");
0091             m_modifierStrings[Qt::GroupSwitchModifier] = i18nc("a special keyboard modifier", "GroupSwitch");
0092             m_buttonStrings[Qt::NoButton] = i18nc("refers to no mouse buttons being pressed", "No-Button");
0093             //FIXME: Left/right may be wrong if mouse buttons are swapped.
0094             m_buttonStrings[(Qt::MouseButton) -1] = QStringLiteral("%1"); //allow external users to insert their custom strings into here
0095             m_buttonStrings[Qt::LeftButton] = i18nc("a mouse button", "Left-Button");
0096             m_buttonStrings[Qt::RightButton] = i18nc("a mouse button", "Right-Button");
0097             m_buttonStrings[Qt::MiddleButton] = i18nc("a mouse button", "Middle-Button");
0098             m_buttonStrings[Qt::XButton1] = i18nc("a special mouse button", "XButton1");
0099             m_buttonStrings[Qt::XButton2] = i18nc("a special mouse button", "XButton2");
0100             m_orientationStrings[Qt::Horizontal] = i18n("Horizontal-Scroll");
0101             m_orientationStrings[Qt::Vertical] = i18n("Vertical-Scroll");
0102         }
0103     };
0104 }
0105 
0106 Q_GLOBAL_STATIC(TriggerParserData, tParserData)
0107 Q_GLOBAL_STATIC(TriggerPrinterData, tPrinterData)
0108 
0109 Palapeli::Trigger::Trigger()
0110     : m_modifiers(Qt::NoModifier)
0111     , m_button((Qt::MouseButton) -1)
0112     , m_wheelDirection((Qt::Orientation) 0)
0113 {
0114 }
0115 
0116 Palapeli::Trigger::Trigger(const QByteArray& serialization)
0117     : m_modifiers(Qt::NoModifier)
0118     , m_button((Qt::MouseButton) -1)
0119     , m_wheelDirection((Qt::Orientation) 0)
0120 {
0121     //expect format "BUTTON_OR_WHEEL;MODIFIERLIST", i.e. two sections separated by semicolon
0122     const QList<QByteArray> sections = serialization.split(';');
0123     if (sections.size() != 2)
0124         return;
0125     //parse modifier list (separated by vertical pipes) -> We do this first because this one can fail.
0126     Qt::KeyboardModifiers modifiers = Qt::NoModifier;
0127     if (sections[1] != "NoModifier")
0128     {
0129         const QList<QByteArray> modifierStrings = sections[1].split('|');
0130         for (const QByteArray& modifierString : modifierStrings)
0131         {
0132             Qt::KeyboardModifier modifier = tParserData->m_modifierStrings.key(modifierString, Qt::NoModifier);
0133             if (modifier == Qt::NoModifier)
0134                 return; //parsing failed
0135             modifiers |= modifier;
0136         }
0137     }
0138     m_modifiers = modifiers;
0139     //parse first section (button or wheel direction) -> default to NoButton + NoOrientation if parsing fails
0140     m_button = tParserData->m_buttonStrings.key(sections[0], Qt::NoButton);
0141     m_wheelDirection = tParserData->m_orientationStrings.key(sections[0], (Qt::Orientation) 0);
0142 }
0143 
0144 bool Palapeli::Trigger::isValid() const
0145 {
0146     if (m_wheelDirection > 0 && m_button > 0)
0147         return false; //do not allow wheel and mouse triggers at the same time
0148     else
0149         return m_button != ((Qt::MouseButton) -1); //do not allow 'negative' m_button values
0150 }
0151 
0152 QByteArray Palapeli::Trigger::serialized() const
0153 {
0154     if (!isValid())
0155         return QByteArray();
0156     const QByteArray actionString = tParserData->actionString(m_wheelDirection, m_button);
0157     QByteArray modifierString = tParserData->modifierString(m_modifiers, QLatin1Char('|'));
0158     if (modifierString.isEmpty())
0159         modifierString = "NoModifier";
0160     return actionString + QByteArray(1, ';') + modifierString;
0161 }
0162 
0163 QString Palapeli::Trigger::toString() const
0164 {
0165     const QString actionString = tPrinterData->actionString(m_wheelDirection, m_button);
0166     const QString modifierString = tPrinterData->modifierString(m_modifiers, QLatin1Char('+'));
0167     if (modifierString.isEmpty())
0168         return actionString;
0169     else
0170         return modifierString + QLatin1Char('+') + actionString;
0171 }
0172 
0173 Qt::KeyboardModifiers Palapeli::Trigger::modifiers() const
0174 {
0175     return m_modifiers;
0176 }
0177 
0178 void Palapeli::Trigger::setModifiers(Qt::KeyboardModifiers modifiers)
0179 {
0180     m_modifiers = modifiers;
0181 }
0182 
0183 Qt::MouseButton Palapeli::Trigger::button() const
0184 {
0185     return m_button;
0186 }
0187 
0188 void Palapeli::Trigger::setButton(Qt::MouseButton button)
0189 {
0190     m_button = button;
0191     if (m_button != Qt::NoButton)
0192         m_wheelDirection = (Qt::Orientation) 0;
0193 }
0194 
0195 Qt::Orientation Palapeli::Trigger::wheelDirection() const
0196 {
0197     return m_wheelDirection;
0198 }
0199 
0200 void Palapeli::Trigger::setWheelDirection(Qt::Orientation orientation)
0201 {
0202     m_wheelDirection = orientation;
0203     if (m_wheelDirection != (Qt::Orientation) 0)
0204         m_button = Qt::NoButton;
0205 }
0206 
0207 bool Palapeli::Trigger::operator==(const Palapeli::Trigger& other) const
0208 {
0209     return m_modifiers == other.m_modifiers
0210         && m_button == other.m_button
0211         && m_wheelDirection == other.m_wheelDirection;
0212 }