File indexing completed on 2025-01-26 05:09:30

0001 /*
0002  * This file is part of the KDE wacomtablet project. For copyright
0003  * information and license terms see the AUTHORS and COPYING files
0004  * in the top-level directory of this distribution.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "buttonpagewidget.h"
0021 #include "ui_buttonpagewidget.h"
0022 
0023 #include "buttonactionselectiondialog.h"
0024 #include "buttonactionselectorwidget.h"
0025 #include "profilemanagement.h"
0026 
0027 // common includes
0028 #include "buttonshortcut.h"
0029 #include "dbustabletinterface.h"
0030 #include "deviceprofile.h"
0031 #include "property.h"
0032 #include "stringutils.h"
0033 #include "tabletinfo.h"
0034 
0035 // stdlib
0036 #include <memory>
0037 
0038 // KDE includes
0039 
0040 // Qt includes
0041 #include <QDBusInterface>
0042 #include <QDBusReply>
0043 #include <QDialog>
0044 #include <QFile>
0045 #include <QKeySequence>
0046 #include <QLabel>
0047 #include <QList>
0048 #include <QPixmap>
0049 #include <QPointer>
0050 #include <QStandardPaths>
0051 
0052 using namespace Wacom;
0053 
0054 QString findLayoutFile(const QString &filename)
0055 {
0056     if (filename.isEmpty())
0057         return QString();
0058 
0059     const QString builtinLayout = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString::fromLatin1("wacomtablet/images/%1.png").arg(filename));
0060     if (QFile::exists(builtinLayout)) {
0061         return builtinLayout;
0062     } else if (QFile::exists(filename)) {
0063         return filename;
0064     }
0065 
0066     return QString();
0067 }
0068 
0069 ButtonPageWidget::ButtonPageWidget(QWidget *parent)
0070     : QWidget(parent)
0071     , ui(new Ui::ButtonPageWidget)
0072 {
0073     setupUi();
0074     reloadWidget();
0075 }
0076 
0077 ButtonPageWidget::~ButtonPageWidget()
0078 {
0079     delete ui;
0080 }
0081 
0082 void ButtonPageWidget::setTabletId(const QString &tabletId)
0083 {
0084     _tabletId = tabletId;
0085 }
0086 
0087 void ButtonPageWidget::saveToProfile(ProfileManagementInterface &profileManagement)
0088 {
0089     DeviceProfile padProfile = profileManagement.loadDeviceProfile(DeviceType::Pad);
0090 
0091     // save button shortcuts
0092     ButtonActionSelectorWidget *buttonSelector;
0093 
0094     for (int i = 1; i < 19; ++i) {
0095         buttonSelector = this->findChild<ButtonActionSelectorWidget *>(QString::fromLatin1("button%1ActionSelector").arg(i));
0096 
0097         if (buttonSelector && buttonSelector->isEnabled()) {
0098             padProfile.setButton(i, buttonSelector->getShortcut().toString());
0099         } else {
0100             // Make sure only valid buttons are set.
0101             // If invalid button numbers are set they might overwrite mapped buttons.
0102             // For instance, if button 4 gets mapped to 9, then setting button 9 will
0103             // overwrite the value from button 4 unless the device actually has a
0104             // button 9 which would then in turn have another mapping to another X11
0105             // button number, e.g. 13.
0106             padProfile.setButton(i, QString());
0107         }
0108     }
0109 
0110     // save strip shortcuts - reset invalid ones - same reasons as above
0111     QString stripLUp, stripRUp, stripLDown, stripRDown;
0112 
0113     if (ui->touchStripGroupBox->isEnabled()) {
0114         if (ui->leftStripWidget->isEnabled()) {
0115             stripLUp = ui->leftStripUpSelector->getShortcut().toString();
0116             stripLDown = ui->leftStripDownSelector->getShortcut().toString();
0117         }
0118 
0119         if (ui->rightStripWidget->isEnabled()) {
0120             stripRUp = ui->rightStripUpSelector->getShortcut().toString();
0121             stripRDown = ui->rightStripDownSelector->getShortcut().toString();
0122         }
0123     }
0124 
0125     padProfile.setProperty(Property::StripLeftUp, stripLUp);
0126     padProfile.setProperty(Property::StripLeftDown, stripLDown);
0127     padProfile.setProperty(Property::StripRightUp, stripRUp);
0128     padProfile.setProperty(Property::StripRightDown, stripRDown);
0129 
0130     // save wheel and ring shortcuts - reset invalid values - same reasons as above
0131     QString absWUp, absWDown;
0132 
0133     if (ui->touchRingGroupBox->isEnabled() || ui->wheelGroupBox->isEnabled()) {
0134         // ring and wheel shortcuts are treated the same but only one value may be written,
0135         // as the other one could be empty. Use whichever value we can get our hands on first.
0136         if (ui->ringUpSelector->getShortcut().isSet()) {
0137             absWUp = ui->ringUpSelector->getShortcut().toString();
0138         } else {
0139             absWUp = ui->wheelUpSelector->getShortcut().toString();
0140         }
0141 
0142         if (ui->ringDownSelector->getShortcut().isSet()) {
0143             absWDown = ui->ringDownSelector->getShortcut().toString();
0144         } else {
0145             absWDown = ui->wheelDownSelector->getShortcut().toString();
0146         }
0147     }
0148 
0149     padProfile.setProperty(Property::AbsWheelUp, absWUp);
0150     padProfile.setProperty(Property::AbsWheel2Up, absWUp);
0151     padProfile.setProperty(Property::AbsWheelDown, absWDown);
0152     padProfile.setProperty(Property::AbsWheel2Down, absWDown);
0153 
0154     // save device profile
0155     profileManagement.saveDeviceProfile(padProfile);
0156 }
0157 
0158 void ButtonPageWidget::loadFromProfile(ProfileManagementInterface &profileManagement)
0159 {
0160     DeviceProfile padProfile = profileManagement.loadDeviceProfile(DeviceType::Pad);
0161     QString propertyValue;
0162 
0163     for (int i = 1; i < 19; i++) {
0164         auto buttonSelector = this->findChild<ButtonActionSelectorWidget *>(QString::fromLatin1("button%1ActionSelector").arg(i));
0165         propertyValue = padProfile.getButton(i);
0166 
0167         if (buttonSelector) {
0168             buttonSelector->setShortcut(ButtonShortcut(propertyValue));
0169         }
0170     }
0171 
0172     // set wheel and ring shortcuts
0173     propertyValue = padProfile.getProperty(Property::AbsWheelUp);
0174     ui->wheelUpSelector->setShortcut(ButtonShortcut(propertyValue));
0175     ui->ringUpSelector->setShortcut(ButtonShortcut(propertyValue));
0176 
0177     propertyValue = padProfile.getProperty(Property::AbsWheelDown);
0178     ui->wheelDownSelector->setShortcut(ButtonShortcut(propertyValue));
0179     ui->ringDownSelector->setShortcut(ButtonShortcut(propertyValue));
0180 
0181     // set strip shortcuts
0182     propertyValue = padProfile.getProperty(Property::StripLeftUp);
0183     ui->leftStripUpSelector->setShortcut(ButtonShortcut(propertyValue));
0184 
0185     propertyValue = padProfile.getProperty(Property::StripLeftDown);
0186     ui->leftStripDownSelector->setShortcut(ButtonShortcut(propertyValue));
0187 
0188     propertyValue = padProfile.getProperty(Property::StripRightUp);
0189     ui->rightStripUpSelector->setShortcut(ButtonShortcut(propertyValue));
0190 
0191     propertyValue = padProfile.getProperty(Property::StripRightDown);
0192     ui->rightStripDownSelector->setShortcut(ButtonShortcut(propertyValue));
0193 }
0194 
0195 void ButtonPageWidget::reloadWidget()
0196 {
0197     const int padButtons = DBusTabletInterface::instance().getInformation(_tabletId, TabletInfo::NumPadButtons.key()).value().toInt();
0198 
0199     QLabel *buttonLabel = nullptr;
0200     ButtonActionSelectorWidget *buttonSelector = nullptr;
0201     for (int i = 1; i < 19; i++) {
0202         buttonSelector = this->findChild<ButtonActionSelectorWidget *>(QString::fromLatin1("button%1ActionSelector").arg(i));
0203         buttonLabel = this->findChild<QLabel *>(QString::fromLatin1("button%1Label").arg(i));
0204 
0205         if (!buttonSelector || !buttonLabel) {
0206             continue;
0207         }
0208 
0209         // we have to disable the widgets as well because when writing
0210         // the configuration file we can not reliably determine their state
0211         // based on visibility.
0212         if (i <= padButtons) {
0213             buttonLabel->setVisible(true);
0214             buttonSelector->setEnabled(true);
0215             buttonSelector->setVisible(true);
0216         } else {
0217             buttonLabel->setVisible(false);
0218             buttonSelector->setEnabled(false);
0219             buttonSelector->setVisible(false);
0220         }
0221     }
0222 
0223     const QString padLayoutProperty = DBusTabletInterface::instance().getInformation(_tabletId, TabletInfo::ButtonLayout.key());
0224     const QString layoutFile = findLayoutFile(padLayoutProperty);
0225     if (!layoutFile.isEmpty()) {
0226         // FIXME: libwacom svg's are large in size and have small labels
0227         // This looks ugly for some devices/with some themes, think of a better layout
0228         ui->padImage->setPixmap(QPixmap(layoutFile));
0229     }
0230 
0231     const bool anyButtonsOrLayout = padButtons > 0 || (!layoutFile.isEmpty());
0232     ui->buttonGroupBox->setVisible(anyButtonsOrLayout);
0233 
0234     bool hasLeftTouchStrip = StringUtils::asBool(DBusTabletInterface::instance().getInformation(_tabletId, TabletInfo::HasLeftTouchStrip.key()));
0235     bool hasRightTouchStrip = StringUtils::asBool(DBusTabletInterface::instance().getInformation(_tabletId, TabletInfo::HasRightTouchStrip.key()));
0236 
0237     if (!hasLeftTouchStrip && !hasRightTouchStrip) {
0238         ui->touchStripGroupBox->setEnabled(false);
0239         ui->touchStripGroupBox->setVisible(false);
0240 
0241     } else {
0242         ui->touchStripGroupBox->setEnabled(true);
0243         ui->touchStripGroupBox->setVisible(true);
0244 
0245         // Hide the strip input widgets directly instead of
0246         // their parent widget, to keep the layout stable.
0247         // Hiding the parent widget will mess up the layout!
0248         // Also disable the widgets so we can reliable determine
0249         // which settings to save.
0250         if (!hasLeftTouchStrip) {
0251             ui->leftStripWidget->setEnabled(false);
0252             ui->leftStripUpLabel->setVisible(false);
0253             ui->leftStripUpSelector->setVisible(false);
0254             ui->leftStripDownLabel->setVisible(false);
0255             ui->leftStripDownSelector->setVisible(false);
0256         } else {
0257             ui->leftStripWidget->setEnabled(true);
0258             ui->leftStripUpLabel->setVisible(true);
0259             ui->leftStripUpSelector->setVisible(true);
0260             ui->leftStripDownLabel->setVisible(true);
0261             ui->leftStripDownSelector->setVisible(true);
0262         }
0263 
0264         if (!hasRightTouchStrip) {
0265             ui->rightStripWidget->setEnabled(false);
0266             ui->rightStripUpLabel->setVisible(false);
0267             ui->rightStripUpSelector->setVisible(false);
0268             ui->rightStripDownLabel->setVisible(false);
0269             ui->rightStripDownSelector->setVisible(false);
0270         } else {
0271             ui->rightStripWidget->setEnabled(true);
0272             ui->rightStripUpLabel->setVisible(true);
0273             ui->rightStripUpSelector->setVisible(true);
0274             ui->rightStripDownLabel->setVisible(true);
0275             ui->rightStripDownSelector->setVisible(true);
0276         }
0277     }
0278 
0279     if (!StringUtils::asBool(DBusTabletInterface::instance().getInformation(_tabletId, TabletInfo::HasTouchRing.key()))) {
0280         ui->touchRingGroupBox->setEnabled(false);
0281         ui->touchRingGroupBox->setVisible(false);
0282     } else {
0283         ui->touchRingGroupBox->setEnabled(true);
0284         ui->touchRingGroupBox->setVisible(true);
0285     }
0286 
0287     if (!StringUtils::asBool(DBusTabletInterface::instance().getInformation(_tabletId, TabletInfo::HasWheel.key()))) {
0288         ui->wheelGroupBox->setEnabled(false);
0289         ui->wheelGroupBox->setVisible(false);
0290     } else {
0291         ui->wheelGroupBox->setEnabled(true);
0292         ui->wheelGroupBox->setVisible(true);
0293     }
0294 }
0295 
0296 void ButtonPageWidget::onButtonActionChanged()
0297 {
0298     emit changed();
0299 }
0300 
0301 void ButtonPageWidget::setupUi()
0302 {
0303     ui->setupUi(this);
0304 
0305     connect(ui->button1ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0306     connect(ui->button2ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0307     connect(ui->button3ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0308     connect(ui->button4ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0309     connect(ui->button5ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0310     connect(ui->button6ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0311     connect(ui->button7ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0312     connect(ui->button8ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0313     connect(ui->button9ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0314     connect(ui->button10ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0315     connect(ui->button11ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0316     connect(ui->button12ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0317     connect(ui->button13ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0318     connect(ui->button14ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0319     connect(ui->button15ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0320     connect(ui->button16ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0321     connect(ui->button17ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0322     connect(ui->button18ActionSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0323 
0324     connect(ui->leftStripUpSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0325     connect(ui->leftStripDownSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0326     connect(ui->rightStripUpSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0327     connect(ui->rightStripDownSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0328 
0329     connect(ui->ringUpSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0330     connect(ui->ringDownSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0331 
0332     connect(ui->wheelUpSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0333     connect(ui->wheelDownSelector, SIGNAL(buttonActionChanged(ButtonShortcut)), this, SLOT(onButtonActionChanged()));
0334 }
0335 
0336 #include "moc_buttonpagewidget.cpp"