File indexing completed on 2024-12-22 05:17:22

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 "dialog.h"
0021 #include "ui_dialog.h"
0022 
0023 #include "hwbuttondialog.h"
0024 #include "tabletdatabase.h"
0025 
0026 #include <KConfigGroup>
0027 #include <KSharedConfig>
0028 
0029 #include <QAbstractButton>
0030 #include <QMap>
0031 #include <QMapIterator>
0032 #include <QProcess>
0033 
0034 using namespace Wacom;
0035 
0036 Dialog::Dialog(QWidget *parent)
0037     : QDialog(parent)
0038     , m_ui(new Ui::Dialog)
0039     , m_hwbDialog(0)
0040 {
0041     m_ui->setupUi(this);
0042 
0043     connect(m_ui->refreshButton, SIGNAL(clicked()), SLOT(refreshTabletList()));
0044     connect(m_ui->listTablets, SIGNAL(currentIndexChanged(int)), SLOT(changeTabletSelection(int)));
0045 
0046     connect(m_ui->hasStatusLEDsLeft, SIGNAL(toggled(bool)), SLOT(onHasStatusLEDsLeftChanged(bool)));
0047     connect(m_ui->hasStatusLEDsRight, SIGNAL(toggled(bool)), SLOT(onhasStatusLEDsRightChanged(bool)));
0048     connect(m_ui->hasTouchRing, SIGNAL(toggled(bool)), SLOT(onhasTouchRingChanged(bool)));
0049     connect(m_ui->hasTouchStripLeft, SIGNAL(toggled(bool)), SLOT(onhasTouchStripLeftChanged(bool)));
0050     connect(m_ui->hasTouchStripRight, SIGNAL(toggled(bool)), SLOT(onhasTouchStripRightChanged(bool)));
0051     connect(m_ui->hasWheel, SIGNAL(toggled(bool)), SLOT(onhasWheelChanged(bool)));
0052 
0053     connect(m_ui->expressKeyNumbers, SIGNAL(valueChanged(int)), SLOT(onExpressKeyNumbersChanged(int)));
0054 
0055     connect(m_ui->buttonBox, SIGNAL(clicked(QAbstractButton *)), SLOT(buttonBoxClicked(QAbstractButton *)));
0056 
0057     connect(m_ui->mapButtons, SIGNAL(clicked()), SLOT(onMapButtons()));
0058 
0059     connect(m_ui->comboTouchSensor, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &Dialog::onPairedIdChanged);
0060     connect(m_ui->radioNormalTablet, &QRadioButton::toggled, this, &Dialog::onNormalTabletSet);
0061     connect(m_ui->radioParentTablet, &QRadioButton::toggled, this, &Dialog::onParentTabletSet);
0062     connect(m_ui->radioTouchSensor, &QRadioButton::toggled, this, &Dialog::onTouchSensorSet);
0063 
0064     m_ui->mapButtons->setEnabled(false);
0065 
0066     refreshTabletList();
0067 }
0068 
0069 Dialog::~Dialog()
0070 {
0071     delete m_ui;
0072 }
0073 
0074 void Dialog::refreshTabletList()
0075 {
0076     m_ui->listTablets->blockSignals(true);
0077     m_ui->comboTouchSensor->blockSignals(true);
0078 
0079     m_ui->listTablets->clear();
0080     m_ui->comboTouchSensor->clear();
0081 
0082     m_tabletList.clear();
0083 
0084     // fetch all connected tablets
0085     QLatin1String program("xsetwacom");
0086     QStringList arguments;
0087     arguments << QLatin1String("--list") << QLatin1String("devices");
0088 
0089     QProcess listDevices;
0090     listDevices.start(program, arguments);
0091     listDevices.waitForFinished();
0092 
0093     QString listDevicesString = QString::fromLatin1(listDevices.readAll());
0094     QStringList listDevicesStringList = listDevicesString.split(QLatin1String("\n"));
0095 
0096     // for each tablet device fetch the device id
0097     QMap<QString, QStringList> tabletList;
0098     foreach (const QString &s, listDevicesStringList) {
0099         QString device = s.split(QLatin1String("\t")).first();
0100         device = device.trimmed();
0101 
0102         if (device.isEmpty()) {
0103             continue;
0104         }
0105 
0106         QProcess checkTabletID;
0107         arguments.clear();
0108         arguments << QLatin1String("--get") << device << QLatin1String("TabletID");
0109         checkTabletID.start(program, arguments);
0110         checkTabletID.waitForFinished();
0111 
0112         QString checkTabletIDString = QString::fromLatin1(checkTabletID.readAll());
0113         checkTabletIDString.remove(QLatin1String("\n"));
0114         QString tabletID = checkTabletIDString.trimmed();
0115 
0116         QStringList tl = tabletList.value(tabletID);
0117         tl << device;
0118         tabletList.insert(tabletID, tl);
0119     }
0120 
0121     // for each device id figure out the common base name
0122     // for most this is the name without "pad", "stylus", "touch" etc
0123     // for some like the Wacom Pen and Touch we remove "Finger" as well
0124     QMapIterator<QString, QStringList> i(tabletList);
0125     while (i.hasNext()) {
0126         i.next();
0127 
0128         QString name;
0129         QStringList deviceList = i.value();
0130         QString firstDevice = deviceList.takeFirst();
0131         bool end = false;
0132 
0133         for (int j = 0; j < firstDevice.length(); j++) {
0134             QChar c = firstDevice.at(j);
0135 
0136             foreach (const QString &s, deviceList) {
0137                 if (s.at(j) != c) {
0138                     end = true;
0139                     break;
0140                 }
0141             }
0142 
0143             if (end) {
0144                 break;
0145             }
0146 
0147             name.append(c);
0148         }
0149 
0150         // create the Tablet entry
0151         Tablet t;
0152         t.serialID = i.key().toInt();
0153         t.company = QLatin1String("Wacom");
0154         t.name = name.trimmed();
0155         t.devices = i.value();
0156 
0157         QString hexNumber = QString::number(t.serialID, 16);
0158         while (hexNumber.length() < 4) {
0159             hexNumber.prepend(QLatin1String("0"));
0160         }
0161 
0162         TabletInformation ti;
0163         if (TabletDatabase::instance().lookupTablet(hexNumber.toUpper(), ti)) {
0164             t.buttonNumber = ti.getInt(TabletInfo::NumPadButtons);
0165             int leds = ti.getInt(TabletInfo::StatusLEDs);
0166             t.hasStatusLEDsLeft = leds > 4;
0167             t.hasStatusLEDsRight = leds > 0;
0168             t.hasTouchRing = ti.getBool(TabletInfo::HasTouchRing);
0169             t.hasTouchStripLeft = ti.getBool(TabletInfo::HasLeftTouchStrip);
0170             t.hasTouchStripRight = ti.getBool(TabletInfo::HasRightTouchStrip);
0171             t.hasWheel = ti.getBool(TabletInfo::HasWheel);
0172 
0173             t.company = ti.get(TabletInfo::CompanyName);
0174             t.name = ti.get(TabletInfo::TabletName);
0175 
0176             t.model = ti.get(TabletInfo::TabletModel);
0177             t.layout = ti.get(TabletInfo::ButtonLayout);
0178 
0179             // set default button map
0180             for (int i = 1; i <= t.buttonNumber; i++) {
0181                 t.hwMapping << i;
0182             }
0183 
0184             const auto buttonMap = ti.getButtonMap();
0185             for (const auto &key : buttonMap.keys()) {
0186                 const auto keyIndex = key.toInt() - 1;
0187                 if (keyIndex < t.buttonNumber) {
0188                     t.hwMapping[keyIndex] = buttonMap.value(key).toInt();
0189                 }
0190             }
0191 
0192             auto pairedID = ti.get(TabletInfo::TouchSensorId);
0193             if (pairedID.isEmpty()) {
0194                 t.hasPairedID = false;
0195             } else {
0196                 t.hasPairedID = true;
0197                 t.pairedID = pairedID;
0198             }
0199             t.isTouchSensor = ti.getBool(TabletInfo::IsTouchSensor);
0200         }
0201 
0202         m_tabletList.append(t);
0203 
0204         m_ui->listTablets->addItem(t.name);
0205         m_ui->comboTouchSensor->addItem(t.name);
0206     }
0207 
0208     m_ui->listTablets->setCurrentIndex(0);
0209     m_ui->listTablets->blockSignals(false);
0210     m_ui->comboTouchSensor->setCurrentIndex(0);
0211     m_ui->comboTouchSensor->blockSignals(false);
0212 
0213     changeTabletSelection(0);
0214 }
0215 
0216 bool Dialog::validIndex()
0217 {
0218     return !m_tabletList.isEmpty() && m_tabletList.size() > m_ui->listTablets->currentIndex();
0219 }
0220 
0221 void Dialog::changeTabletSelection(int index)
0222 {
0223     if (!validIndex()) {
0224         return;
0225     }
0226 
0227     Tablet t = m_tabletList.at(index);
0228 
0229     QString hexNumber = QString::number(t.serialID, 16);
0230 
0231     while (hexNumber.length() < 4) {
0232         hexNumber.prepend(QLatin1String("0"));
0233     }
0234 
0235     m_ui->listSerialId->setText(QString::fromLatin1("%1 [%2]").arg(t.serialID).arg(hexNumber.toUpper()));
0236 
0237     m_ui->listDevices->setText(t.devices.join(QLatin1String("\n")));
0238     m_ui->hasStatusLEDsLeft->setChecked(t.hasStatusLEDsLeft);
0239     m_ui->hasStatusLEDsRight->setChecked(t.hasStatusLEDsRight);
0240     m_ui->hasTouchRing->setChecked(t.hasTouchRing);
0241     m_ui->hasTouchStripLeft->setChecked(t.hasTouchStripLeft);
0242     m_ui->hasTouchStripRight->setChecked(t.hasTouchStripRight);
0243     m_ui->hasWheel->setChecked(t.hasWheel);
0244     m_ui->expressKeyNumbers->setValue(t.buttonNumber);
0245     m_ui->radioNormalTablet->setChecked(!t.isTouchSensor && !t.hasPairedID);
0246     m_ui->radioTouchSensor->setChecked(t.isTouchSensor);
0247     m_ui->radioParentTablet->setChecked(t.hasPairedID);
0248     m_ui->comboTouchSensor->setEnabled(t.hasPairedID);
0249 
0250     int tabletIndex = 0;
0251     for (const auto &tablet : m_tabletList) {
0252         if (QString::fromLatin1("%1").arg(tablet.serialID, 4, 16, QChar::fromLatin1('0')) == t.pairedID) {
0253             m_ui->comboTouchSensor->setCurrentIndex(tabletIndex);
0254             break;
0255         }
0256         ++tabletIndex;
0257     }
0258 
0259     showHWButtonMap();
0260 }
0261 
0262 void Dialog::onHasStatusLEDsLeftChanged(bool toggled)
0263 {
0264     if (!validIndex()) {
0265         return;
0266     }
0267 
0268     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0269     t.hasStatusLEDsLeft = toggled;
0270     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0271 }
0272 
0273 void Dialog::onhasStatusLEDsRightChanged(bool toggled)
0274 {
0275     if (!validIndex()) {
0276         return;
0277     }
0278 
0279     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0280     t.hasStatusLEDsRight = toggled;
0281     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0282 }
0283 
0284 void Dialog::onhasTouchRingChanged(bool toggled)
0285 {
0286     if (!validIndex()) {
0287         return;
0288     }
0289 
0290     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0291     t.hasTouchRing = toggled;
0292     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0293 }
0294 
0295 void Dialog::onhasTouchStripLeftChanged(bool toggled)
0296 {
0297     if (!validIndex()) {
0298         return;
0299     }
0300 
0301     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0302     t.hasTouchStripLeft = toggled;
0303     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0304 }
0305 
0306 void Dialog::onhasTouchStripRightChanged(bool toggled)
0307 {
0308     if (!validIndex()) {
0309         return;
0310     }
0311 
0312     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0313     t.hasTouchStripRight = toggled;
0314     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0315 }
0316 
0317 void Dialog::onhasWheelChanged(bool toggled)
0318 {
0319     if (!validIndex()) {
0320         return;
0321     }
0322 
0323     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0324     t.hasWheel = toggled;
0325     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0326 }
0327 
0328 void Dialog::onExpressKeyNumbersChanged(int buttons)
0329 {
0330     if (!validIndex()) {
0331         return;
0332     }
0333 
0334     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0335     t.buttonNumber = buttons;
0336     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0337 
0338     m_ui->mapButtons->setEnabled(m_ui->expressKeyNumbers->value() > 0);
0339 
0340     showHWButtonMap();
0341 }
0342 
0343 void Dialog::buttonBoxClicked(QAbstractButton *button)
0344 {
0345     QDialogButtonBox::StandardButton stdButton = m_ui->buttonBox->standardButton(button);
0346     switch (stdButton) {
0347     case QDialogButtonBox::Close:
0348         qApp->quit();
0349         break;
0350 
0351     case QDialogButtonBox::Save: {
0352         if (!validIndex()) {
0353             return;
0354         }
0355 
0356         Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0357         saveTabletInfo(t);
0358         break;
0359     }
0360     case QDialogButtonBox::SaveAll: {
0361         foreach (const Tablet &t, m_tabletList) {
0362             saveTabletInfo(t);
0363         }
0364         break;
0365     }
0366     default:
0367         return;
0368     }
0369 }
0370 
0371 void Dialog::onPairedIdChanged(int index)
0372 {
0373     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0374     t.pairedID = QString::fromLatin1("%1").arg(m_tabletList.at(index).serialID, 4, 16, QChar::fromLatin1('0'));
0375     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0376 }
0377 
0378 void Dialog::onNormalTabletSet(bool enabled)
0379 {
0380     if (enabled) {
0381         const int index = m_ui->listTablets->currentIndex();
0382         if (index != -1) {
0383             Tablet t = m_tabletList.at(index);
0384             t.isTouchSensor = false;
0385             t.hasPairedID = false;
0386             m_tabletList.replace(index, t);
0387             m_ui->comboTouchSensor->setEnabled(false);
0388         }
0389     }
0390 }
0391 
0392 void Dialog::onParentTabletSet(bool enabled)
0393 {
0394     const int index = m_ui->listTablets->currentIndex();
0395     if (enabled && index != -1) {
0396         Tablet t = m_tabletList.at(index);
0397         t.isTouchSensor = false;
0398         t.hasPairedID = true;
0399         m_tabletList.replace(index, t);
0400         m_ui->comboTouchSensor->setEnabled(true);
0401     } else {
0402         m_ui->comboTouchSensor->setEnabled(false);
0403     }
0404 }
0405 
0406 void Dialog::onTouchSensorSet(bool enabled)
0407 {
0408     const int index = m_ui->listTablets->currentIndex();
0409     if (enabled && index != -1) {
0410         Tablet t = m_tabletList.at(index);
0411         t.isTouchSensor = true;
0412         t.hasPairedID = false;
0413         m_tabletList.replace(index, t);
0414         m_ui->comboTouchSensor->setEnabled(false);
0415     }
0416 }
0417 
0418 void Dialog::onMapButtons()
0419 {
0420     m_hwbDialog = new HWButtonDialog(m_ui->expressKeyNumbers->value(), this);
0421 
0422     int ret = m_hwbDialog->exec();
0423 
0424     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0425     if (ret == QDialog::Accepted) {
0426         t.hwMapping = m_hwbDialog->buttonMap();
0427     } else {
0428         t.hwMapping.clear();
0429     }
0430 
0431     m_tabletList.replace(m_ui->listTablets->currentIndex(), t);
0432     showHWButtonMap();
0433 }
0434 
0435 void Dialog::showHWButtonMap()
0436 {
0437     Tablet t = m_tabletList.at(m_ui->listTablets->currentIndex());
0438 
0439     QString text;
0440     for (int i = 0; i < t.hwMapping.size(); ++i) {
0441         text.append(i18n("Button %1 maps to Button %2", (i + 1), t.hwMapping.at(i)));
0442         text.append(QLatin1String("\n"));
0443     }
0444 
0445     m_ui->buttonMappingLabel->setText(text);
0446 }
0447 
0448 void Dialog::saveTabletInfo(const Tablet &t)
0449 {
0450     KConfig config(QLatin1String("tabletdblocalrc"));
0451 
0452     QString hexNumber = QString::number(t.serialID, 16);
0453 
0454     while (hexNumber.length() < 4) {
0455         hexNumber.prepend(QLatin1String("0"));
0456     }
0457     KConfigGroup tabletGroup(&config, hexNumber.toUpper());
0458     tabletGroup.deleteGroup();
0459     tabletGroup.config()->sync();
0460 
0461     tabletGroup.writeEntry("model", t.model);
0462     tabletGroup.writeEntry("layout", t.layout);
0463     tabletGroup.writeEntry("name", t.name);
0464 
0465     int leds = 0;
0466     if (t.hasStatusLEDsLeft && t.hasStatusLEDsRight) {
0467         leds = 8;
0468     } else if (t.hasStatusLEDsLeft || t.hasStatusLEDsRight) {
0469         leds = 4;
0470     }
0471 
0472     tabletGroup.writeEntry("statusleds", leds);
0473     tabletGroup.writeEntry("wheel", t.hasWheel);
0474     tabletGroup.writeEntry("touchring", t.hasTouchRing);
0475     tabletGroup.writeEntry("touchstripl", t.hasTouchStripLeft);
0476     tabletGroup.writeEntry("touchstripr", t.hasTouchStripRight);
0477 
0478     tabletGroup.writeEntry("padbuttons", t.buttonNumber);
0479     for (int i = 0; i < t.hwMapping.size(); i++) {
0480         tabletGroup.writeEntry(QString::fromLatin1("hwbutton%1").arg(i + 1), t.hwMapping.at(i));
0481     }
0482 
0483     if (t.isTouchSensor) {
0484         tabletGroup.writeEntry("istouchsensor", t.isTouchSensor);
0485     }
0486     if (t.hasPairedID) {
0487         tabletGroup.writeEntry("touchsensorid", t.pairedID);
0488     }
0489 
0490     tabletGroup.config()->sync();
0491 }
0492 
0493 #include "moc_dialog.cpp"