1 /*
2  *   SPDX-FileCopyrightText: 2008 Aaron Seigo <aseigo@kde.org>
3  *
4  *   SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 #include "serviceviewer.h"
8 
9 #include <KLocalizedString>
10 #include <KMessageBox>
11 #include <KStringHandler>
12 #include <QDebug>
13 #include <QDialogButtonBox>
14 
15 #include <Plasma/DataEngine>
16 #include <Plasma/Service>
17 #include <Plasma/ServiceJob>
18 
19 #include "engineexplorer.h"
20 
ServiceViewer(Plasma::DataEngine * engine,const QString & source,QWidget * parent)21 ServiceViewer::ServiceViewer(Plasma::DataEngine *engine, const QString &source, QWidget *parent)
22     : QDialog(parent)
23     , m_engine(engine)
24     , m_service(nullptr)
25     , m_source(source)
26     , m_operationCount(0)
27     , m_operationButton(new QPushButton(i18n("Start Operation"), this))
28 {
29     setAttribute(Qt::WA_DeleteOnClose);
30     QWidget *mainWidget = new QWidget(this);
31     QVBoxLayout *layout = new QVBoxLayout();
32 
33     QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
34     buttonBox->addButton(m_operationButton, QDialogButtonBox::ActionRole);
35     buttonBox->addButton(QDialogButtonBox::Close);
36 
37     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
38 
39     layout->addWidget(mainWidget);
40     layout->addWidget(buttonBox);
41     setLayout(layout);
42 
43     setupUi(mainWidget);
44     m_operationStatus->hide();
45 
46     connect(m_operationButton, &QAbstractButton::clicked, this, &ServiceViewer::startOperation);
47     m_operationButton->setEnabled(false);
48 
49     connect(m_operations, SIGNAL(currentIndexChanged(QString)), this, SLOT(operationSelected(QString)));
50 
51     QString engineName = i18nc("Plasma engine with unknown name", "Unknown");
52     QString serviceName = i18nc("Plasma service with unknown name", "Unknown");
53 
54     if (m_engine) {
55         if (m_engine->pluginInfo().isValid()) {
56             engineName = KStringHandler::capwords(m_engine->pluginInfo().name());
57         }
58         qDebug() << "########### CALLING SERVICE FOR SOURCE: " << m_source;
59         m_service = m_engine->serviceForSource(m_source);
60 
61         if (m_service != nullptr) {
62             serviceName = m_service->name();
63             updateOperations();
64             connect(m_service, SIGNAL(operationsChanged()), this, SLOT(updateOperations()));
65             connect(m_engine, &QObject::destroyed, this, &ServiceViewer::engineDestroyed);
66         } else {
67             KMessageBox::sorry(this, i18n("No valid service was returned. Verify that a service is available for this source."));
68             close();
69         }
70     }
71 
72     setWindowTitle(i18nc("%1 is a Plasma service name", "%1 Service Explorer", serviceName));
73 
74     QString title = i18nc("Source: name of the data, Service: writes data instead of fetching",
75                           "DataEngine: <b>%1</b>; Source: <b>%2</b>; Service: <b>%3</b>",
76                           engineName,
77                           m_source,
78                           serviceName);
79     m_title->setText(title);
80     m_operations->setFocus();
81 }
82 
~ServiceViewer()83 ServiceViewer::~ServiceViewer()
84 {
85     delete m_service;
86     m_engine = nullptr;
87 }
88 
updateOperations()89 void ServiceViewer::updateOperations()
90 {
91     if (!m_engine) {
92         return;
93     }
94 
95     bool enable = false;
96 
97     m_operations->clear();
98     m_operationDescription->clear();
99 
100     if (m_service) {
101         const QStringList operations = m_service->operationNames();
102 
103         if (!operations.isEmpty()) {
104             enable = true;
105 
106             foreach (const QString &operation, operations) {
107                 m_operations->addItem(operation);
108             }
109         }
110     }
111 
112     m_operations->setEnabled(enable);
113     m_operationsLabel->setEnabled(enable);
114     m_operationDescription->setEnabled(enable);
115 }
116 
startOperation()117 void ServiceViewer::startOperation()
118 {
119     if (!m_service) {
120         return;
121     }
122 
123     QString operation = m_operations->currentText();
124     QVariantMap desc = m_service->operationDescription(operation);
125     for (int i = 0; i < m_operationDescription->rowCount(); ++i) {
126         QTableWidgetItem *item = m_operationDescription->item(i, 1);
127         QString value = item->text();
128 
129         if (value.isEmpty()) {
130             continue;
131         }
132 
133         item = m_operationDescription->item(i, 0);
134         QString key = item->text();
135         desc[key] = value;
136     }
137 
138     updateJobCount(1);
139     Plasma::ServiceJob *job = m_service->startOperationCall(desc);
140     connect(job, &KJob::finished, this, &ServiceViewer::operationResult);
141 }
142 
operationSelected(const QString & operation)143 void ServiceViewer::operationSelected(const QString &operation)
144 {
145     if (!m_service) {
146         return;
147     }
148 
149     m_operationButton->setEnabled(true);
150     QStringList headers;
151     headers << i18n("Key") << i18n("Value");
152     m_operationDescription->setHorizontalHeaderLabels(headers);
153 
154     QVariantMap desc = m_service->operationDescription(operation);
155     int i = 0;
156     const QStringList keys = desc.keys();
157     m_operationDescription->setRowCount(keys.count());
158     foreach (const QString &key, keys) {
159         QTableWidgetItem *item = new QTableWidgetItem(key);
160         item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
161         m_operationDescription->setItem(i, 0, item);
162 
163         item = new QTableWidgetItem(desc[key].toString());
164         m_operationDescription->setItem(i, 1, item);
165 
166         ++i;
167     }
168 }
169 
operationResult(KJob * j)170 void ServiceViewer::operationResult(KJob *j)
171 {
172     if (!m_service) {
173         return;
174     }
175 
176     Plasma::ServiceJob *job = qobject_cast<Plasma::ServiceJob *>(j);
177     if (!job) {
178         return;
179     }
180 
181     updateJobCount(-1);
182 
183     if (job->error()) {
184         KMessageBox::information(this,
185                                  i18n("<b>'%1'</b> operation with destination <b>'%2'</b> failed. "
186                                       "<p>The error was: <b>'%3: %4'</b></p>",
187                                       job->operationName(),
188                                       job->destination(),
189                                       job->error(),
190                                       job->errorString()),
191                                  i18n("Operation Result"));
192     } else {
193         QString result = EngineExplorer::convertToString(job->result());
194         if (result.isEmpty()) {
195             result = i18n("No response from job.");
196         }
197 
198         KMessageBox::information(this,
199                                  i18n("<b>'%1'</b> operation with destination <b>'%2'</b> returned successfully. "
200                                       "<p>The result was: <b>'%3'</b></p>",
201                                       job->operationName(),
202                                       job->destination(),
203                                       result),
204                                  i18n("Operation Result"));
205     }
206 
207     qDebug() << "operation results are in!";
208 }
209 
engineDestroyed()210 void ServiceViewer::engineDestroyed()
211 {
212     m_service = nullptr;
213     m_engine = nullptr;
214     hide();
215     deleteLater();
216 }
217 
updateJobCount(int numberOfJobs)218 void ServiceViewer::updateJobCount(int numberOfJobs)
219 {
220     m_operationCount += numberOfJobs;
221 
222     if (m_operationCount < 1) {
223         m_operationCount = 0;
224         m_operationStatus->hide();
225     } else {
226         m_operationStatus->setText(i18np("One active operation…", "%1 operations active…", m_operationCount));
227         m_operationStatus->show();
228     }
229 }
230