File indexing completed on 2024-05-12 17:07:26

0001 /*
0002     SPDX-FileCopyrightText: 2009 Ben Cooksley <ben@eclipse.endoftheinternet.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "SolidActions.h"
0008 #include "ActionItem.h"
0009 
0010 #include <KAboutData>
0011 #include <KBuildSycocaProgressDialog>
0012 #include <KConfigGroup>
0013 #include <KDesktopFile>
0014 #include <KMessageBox>
0015 #include <KPluginFactory>
0016 #include <KStandardGuiItem>
0017 
0018 #include <KIO/Global>
0019 
0020 #include <QComboBox>
0021 #include <QDebug>
0022 #include <QPushButton>
0023 
0024 #include <Solid/DeviceInterface>
0025 #include <Solid/Predicate>
0026 
0027 K_PLUGIN_CLASS_WITH_JSON(SolidActions, "kcm_solid_actions.json")
0028 
0029 SolidActions::SolidActions(QWidget *parent, const QVariantList &)
0030     : KCModule(parent)
0031 {
0032     KAboutData *about = new KAboutData(QStringLiteral("Device Actions"),
0033                                        i18n("Solid Device Actions Editor"),
0034                                        QStringLiteral("1.2"),
0035                                        i18n("Solid Device Actions Control Panel Module"),
0036                                        KAboutLicense::GPL,
0037                                        i18n("(c) 2009, 2014 Solid Device Actions team"));
0038     about->addAuthor(i18n("Ben Cooksley"), i18n("Maintainer"), QStringLiteral("ben@eclipse.endoftheinternet.org"));
0039     about->addCredit(QStringLiteral("Lukáš Tinkl"), i18n("Port to Plasma 5"), QStringLiteral("ltinkl@redhat.com"));
0040     setAboutData(about);
0041     setButtons(KCModule::Help);
0042 
0043     // Prepare main display dialog
0044     actionModel = new ActionModel(this);
0045     mainUi.setupUi(this);
0046     mainUi.TvActions->setModel(actionModel);
0047     mainUi.TvActions->setHeaderHidden(true);
0048     mainUi.TvActions->setRootIsDecorated(false);
0049     mainUi.TvActions->setSelectionMode(QAbstractItemView::SingleSelection);
0050     KStandardGuiItem::assign(mainUi.PbAddAction, KStandardGuiItem::Add);
0051     mainUi.PbEditAction->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
0052 
0053     connect(mainUi.PbAddAction, &QPushButton::clicked, this, &SolidActions::slotShowAddDialog);
0054     connect(mainUi.PbEditAction, &QPushButton::clicked, this, &SolidActions::editAction);
0055     connect(mainUi.PbDeleteAction, &QPushButton::clicked, this, &SolidActions::deleteAction);
0056     connect(mainUi.TvActions->selectionModel(), &QItemSelectionModel::currentChanged, this, &SolidActions::toggleEditDelete);
0057     connect(mainUi.TvActions, &QTreeView::doubleClicked, this, &SolidActions::editAction);
0058 
0059     // Prepare + connect up with Edit dialog
0060     editUi = new ActionEditor(this);
0061     connect(editUi, &ActionEditor::accepted, this, &SolidActions::acceptActionChanges);
0062 
0063     // Prepare + connect up add action dialog
0064     addDialog = new QDialog(this);
0065     addUi.setupUi(addDialog);
0066     addDialog->resize(QSize(300, 100)); // Set a sensible default size
0067 
0068     slotTextChanged(addUi.LeActionName->text());
0069     connect(addUi.LeActionName, &QLineEdit::textChanged, this, &SolidActions::slotTextChanged);
0070     connect(addUi.buttonBox, &QDialogButtonBox::accepted, this, &SolidActions::addAction);
0071     connect(addUi.buttonBox, &QDialogButtonBox::rejected, addDialog, &QDialog::reject);
0072 }
0073 
0074 SolidActions::~SolidActions()
0075 {
0076     delete editUi;
0077     delete actionModel;
0078 }
0079 
0080 void SolidActions::slotShowAddDialog()
0081 {
0082     addDialog->show();
0083     addUi.LeActionName->setFocus();
0084     addUi.LeActionName->clear();
0085 }
0086 
0087 void SolidActions::slotTextChanged(const QString &text)
0088 {
0089     addUi.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty());
0090 }
0091 
0092 void SolidActions::load()
0093 {
0094     fillActionsList();
0095 }
0096 
0097 void SolidActions::defaults()
0098 {
0099 }
0100 
0101 void SolidActions::save()
0102 {
0103 }
0104 
0105 void SolidActions::addAction()
0106 {
0107     const QString enteredName = addUi.LeActionName->text();
0108     KDesktopFile templateDesktop(QStandardPaths::GenericDataLocation, QStringLiteral("kcmsolidactions/solid-action-template.desktop")); // Lets get the template
0109 
0110     // Lets get a desktop file
0111     QString internalName = enteredName; // copy the name the user entered -> we will be making mods
0112     internalName.replace(QChar(' '), QChar('-'), Qt::CaseSensitive); // replace spaces with dashes
0113     internalName = KIO::encodeFileName(internalName);
0114 
0115     QString filePath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/solid/actions/"; // Get the location on disk for "data"
0116     if (!QDir().exists(filePath)) {
0117         QDir().mkpath(filePath);
0118     }
0119     filePath += internalName + ".desktop";
0120 
0121     // Fill in an initial template
0122     KDesktopFile *newDesktop = templateDesktop.copyTo(filePath);
0123     newDesktop->actionGroup(QStringLiteral("open")).writeEntry("Name", enteredName); // ditto
0124     delete newDesktop; // Force file to be written
0125 
0126     // Prepare to open the editDialog
0127     fillActionsList();
0128     const QList<ActionItem *> actionList = actionModel->actionList();
0129     QModelIndex newAction;
0130     for (ActionItem *newItem : actionList) { // Lets find our new action
0131         if (newItem->desktopMasterPath == filePath) {
0132             const int position = actionList.indexOf(newItem);
0133             newAction = actionModel->index(position, 0); // Grab it
0134             break;
0135         }
0136     }
0137 
0138     mainUi.TvActions->setCurrentIndex(newAction); // Set it as currently active
0139     addDialog->hide();
0140     editAction(); // Open the edit dialog
0141 }
0142 
0143 void SolidActions::editAction()
0144 {
0145     ActionItem *selectedItem = selectedAction();
0146     if (!selectedItem) {
0147         return;
0148     }
0149 
0150     // We should error out here if we have to
0151     if (!selectedItem->predicate().isValid()) {
0152         KMessageBox::error(this, i18n("It appears that the predicate for this action is not valid."), i18n("Error Parsing Device Conditions"));
0153         return;
0154     }
0155 
0156     // Display us!
0157     editUi->setActionToEdit(selectedItem);
0158     editUi->setWindowIcon(windowIcon());
0159     editUi->show();
0160 }
0161 
0162 void SolidActions::deleteAction()
0163 {
0164     ActionItem *action = selectedAction();
0165     if (action->isUserSupplied()) { // Is the action user supplied?
0166         QFile::remove(action->desktopMasterPath); // Remove the main desktop file then
0167     }
0168     QFile::remove(action->desktopWritePath); // Remove the modified desktop file now
0169     fillActionsList(); // Update the list of actions
0170 }
0171 
0172 ActionItem *SolidActions::selectedAction() const
0173 {
0174     QModelIndex action = mainUi.TvActions->currentIndex();
0175     ActionItem *actionItem = actionModel->data(action, Qt::UserRole).value<ActionItem *>();
0176     return actionItem;
0177 }
0178 
0179 void SolidActions::fillActionsList()
0180 {
0181     mainUi.TvActions->clearSelection();
0182     actionModel->buildActionList();
0183     mainUi.TvActions->header()->setSectionResizeMode(0, QHeaderView::Stretch);
0184     mainUi.TvActions->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
0185     toggleEditDelete();
0186 }
0187 
0188 void SolidActions::acceptActionChanges()
0189 {
0190     // Re-read the actions list to ensure changes are reflected
0191     KBuildSycocaProgressDialog::rebuildKSycoca(this);
0192     fillActionsList();
0193 }
0194 
0195 void SolidActions::toggleEditDelete()
0196 {
0197     bool toggle = true;
0198 
0199     if (!mainUi.TvActions->currentIndex().isValid()) { // Is an action selected?
0200         mainUi.PbDeleteAction->setText(i18n("No Action Selected")); // Set a friendly disabled text
0201         mainUi.PbDeleteAction->setIcon(QIcon());
0202         toggle = false;
0203     }
0204 
0205     mainUi.PbEditAction->setEnabled(toggle); // Change them to the new state
0206     mainUi.PbDeleteAction->setEnabled(toggle); // Ditto
0207 
0208     if (!toggle) {
0209         return;
0210     }
0211 
0212     // What functionality do we need to change?
0213     if (selectedAction()->isUserSupplied()) {
0214         // We are able to directly delete it, enable full delete functionality
0215         KStandardGuiItem::assign(mainUi.PbDeleteAction, KStandardGuiItem::Remove);
0216     } else if (QFile::exists(selectedAction()->desktopWritePath)) { // Does the write file exist?
0217         // We are able to revert, lets show it
0218         KStandardGuiItem::assign(mainUi.PbDeleteAction, KStandardGuiItem::Discard);
0219     } else {
0220         // We cannot do anything then, disable delete functionality
0221         mainUi.PbDeleteAction->setText(i18n("Cannot be deleted"));
0222         mainUi.PbDeleteAction->setIcon(QIcon());
0223         mainUi.PbDeleteAction->setEnabled(false);
0224     }
0225 }
0226 
0227 #include "SolidActions.moc"