1 /***************************************************************************
2 * KoScriptManager.cpp
3 * This file is part of the KDE project
4 * copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
5 * copyright (C) 2006-2007 Sebastian Sauer <mail@dipe.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 ***************************************************************************/
22
23 #include "KoScriptManager.h"
24
25 #include "KoScriptManagerAdd.h"
26 #include "KoKrossDebug.h"
27
28 #include <kross/core/manager.h>
29 #include <kross/core/actioncollection.h>
30 #include <kross/ui/model.h>
31 #include <kross/ui/view.h>
32
33 #include <KoIcon.h>
34
35 #include <klocalizedstring.h>
36
37 #include <QStandardPaths>
38 #include <QBoxLayout>
39
40 /******************************************************************************
41 * KoScriptManagerCollection
42 */
43
44 /*
45 /// \internal class that inherits \a KNewStuffSecure to implement the GHNS-functionality.
46 class KoScriptManagerNewStuff : public KNewStuffSecure
47 {
48 public:
49 KoScriptManagerNewStuff(KoScriptManagerCollection *collection, const QString& type, QWidget *parentWidget = 0)
50 : KNewStuffSecure(type, parentWidget)
51 , m_collection(collection) {}
52 virtual ~KoScriptManagerNewStuff() {}
53 private:
54 KoScriptManagerCollection *m_collection;
55 virtual void installResource() { m_collection->module()->installPackage(m_tarName); }
56 };
57 */
58
59 class KoScriptManagerView : public Kross::ActionCollectionView
60 {
61 public:
KoScriptManagerView(KoScriptManagerCollection * collection)62 KoScriptManagerView(KoScriptManagerCollection *collection) : Kross::ActionCollectionView(collection)
63 {
64 setDragEnabled(true);
65 setAcceptDrops(true);
66
67 Kross::ActionCollectionModel::Mode modelmode = Kross::ActionCollectionModel::Mode(Kross::ActionCollectionModel::Icons | Kross::ActionCollectionModel::ToolTips | Kross::ActionCollectionModel::UserCheckable);
68 Kross::ActionCollectionModel *model = new Kross::ActionCollectionModel(this, Kross::Manager::self().actionCollection(), modelmode);
69 setModel(model);
70 //selectionModel();
71 }
72
~KoScriptManagerView()73 ~KoScriptManagerView() override {}
74
model() const75 Kross::ActionCollectionModel *model() const
76 {
77 return static_cast<Kross::ActionCollectionModel*>(Kross::ActionCollectionView::model());
78 }
79
slotAdd()80 void slotAdd() override
81 {
82 Kross::ActionCollection *collection = model()->rootCollection();
83 if (itemSelection().count() == 1) {
84 collection = Kross::ActionCollectionModel::collection(itemSelection().indexes().first());
85 }
86 KoScriptManagerAddWizard wizard(this, collection);
87 int result = wizard.exec();
88 Q_UNUSED(result);
89 }
slotRemove()90 void slotRemove() override
91 {
92 if (itemSelection().isEmpty()) {
93 return;
94 }
95 // get the actions/collections, indexes will change when things are removed
96 QList<Kross::Action*> actions;
97 QList<Kross::ActionCollection*> collections;
98 foreach (const QModelIndex &idx, itemSelection().indexes()) {
99 Kross::Action *a = model()->action(idx);
100 if (a) {
101 actions << a;
102 } else {
103 Kross::ActionCollection *c = model()->collection(idx);
104 if (c) {
105 collections << c;
106 }
107 }
108 }
109 foreach (Kross::Action *action, actions) {
110 QModelIndex idx = model()->indexForAction(action);
111 if (idx.isValid()) {
112 //debugKoKross<<"action:"<<action->name();
113 delete action;
114 }
115 }
116 foreach (Kross::ActionCollection *collection, collections) {
117 QModelIndex idx = model()->indexForCollection(collection);
118 if (idx.isValid()) {
119 //debugKoKross<<"collection:"<<collection->name();
120 delete collection;
121 }
122 }
123 }
124 };
125
KoScriptManagerCollection(QWidget * parent)126 KoScriptManagerCollection::KoScriptManagerCollection(QWidget *parent)
127 : QWidget(parent),
128 m_modified(false)
129 {
130 QHBoxLayout *mainlayout = new QHBoxLayout();
131 mainlayout->setMargin(0);
132 setLayout(mainlayout);
133
134 m_view = new KoScriptManagerView(this);
135 mainlayout->addWidget(m_view);
136
137 QWidget *btnwidget = new QWidget(this);
138 QVBoxLayout *btnlayout = new QVBoxLayout();
139 btnlayout->setMargin(0);
140 btnwidget->setLayout(btnlayout);
141 mainlayout->addWidget(btnwidget);
142
143 //KActionCollection *collection = m_view->actionCollection();
144
145 m_view->createButton(btnwidget, "run");
146 m_view->createButton(btnwidget, "stop");
147
148 QFrame *hr1 = new QFrame(btnwidget);
149 hr1->setFrameStyle(QFrame::HLine | QFrame::Sunken);
150 btnlayout->addWidget(hr1, 0);
151
152 m_view->createButton(btnwidget, "edit");
153 m_view->createButton(btnwidget, "add");
154 m_view->createButton(btnwidget, "remove");
155
156 btnlayout->addStretch(1);
157 m_view->expandAll();
158 }
159
~KoScriptManagerCollection()160 KoScriptManagerCollection::~KoScriptManagerCollection()
161 {
162 }
163
164 /*
165 bool KoScriptManagerCollection::isModified() const
166 {
167 return d->modified;
168 }
169 */
170
171 #if 0
172 bool KoScriptManagerCollection::slotInstall() {
173 KFileDialog* filedialog = new KFileDialog(
174 QUrl("kfiledialog:///KrossInstallPackage"), // startdir
175 "*.tar.gz *.tgz *.bz2", // filter
176 0, // custom widget
177 0 // parent
178 );
179 filedialog->setCaption(i18n("Install Script Package"));
180 return filedialog->exec() ? module()->installPackage(filedialog->selectedUrl().path()) : false;
181 }
182 void KoScriptManagerView::slotUninstall() {
183 foreach(QModelIndex index, d->selectionmodel->selectedIndexes())
184 if(index.isValid())
185 if(! uninstallPackage( static_cast< Action* >(index.internalPointer()) ))
186 break;
187 }
188 void KoScriptManagerView::slotNewScripts() {
189 const QString appname = KApplication::kApplication()->objectName();
190 const QString type = QString("%1/script").arg(appname);
191 krossdebug( QString("ScriptManagerView::slotNewScripts %1").arg(type) );
192 if(! d->newstuff) {
193 d->newstuff = new KoScriptManagerNewStuff(this, type);
194 connect(d->newstuff, SIGNAL(installFinished()), this, SLOT(slotNewScriptsInstallFinished()));
195 }
196 KNS::Engine *engine = new KNS::Engine(d->newstuff, type, this);
197 KNS::DownloadDialog *d = new KNS::DownloadDialog(engine, this);
198 d->setCategory(type);
199 KNS::ProviderLoader *p = new KNS::ProviderLoader(this);
200 QObject::connect(p, SIGNAL(providersLoaded(Provider::List*)), d, SLOT(slotProviders(Provider::List*)));
201 p->load(type, QString("http://download.kde.org/khotnewstuff/%1scripts-providers.xml").arg(appname));
202 d->exec();
203 }
204 void KoScriptManagerView::slotNewScriptsInstallFinished() {
205 // Delete KNewStuff's configuration entries. These entries reflect what has
206 // already been installed. As we cannot yet keep them in sync after uninstalling
207 // scripts, we deactivate the check marks entirely.
208 KGlobal::config()->deleteGroup("KNewStuffStatus");
209 }
210 #endif
211
212 #if 0
213 bool KoScriptManagerModule::installPackage(const QString& scriptpackagefile)
214 {
215 KTar archive( scriptpackagefile );
216 if(! archive.open(QIODevice::ReadOnly)) {
217 KMessageBox::sorry(0, i18n("Could not read the package \"%1\".", scriptpackagefile));
218 return false;
219 }
220
221 const KArchiveDirectory* archivedir = archive.directory();
222 const KArchiveEntry* entry = archivedir->entry("install.rc");
223 if(! entry || ! entry->isFile()) {
224 KMessageBox::sorry(0, i18n("The package \"%1\" does not contain a valid install.rc file.", scriptpackagefile));
225 return false;
226 }
227
228 QString xml = static_cast< const KArchiveFile* >(entry)->data();
229 QDomDocument domdoc;
230 if(! domdoc.setContent(xml)) {
231 KMessageBox::sorry(0, i18n("Failed to parse the install.rc file at package \"%1\".", scriptpackagefile));
232 return false;
233 }
234
235 QString destination = KGlobal::dirs()->saveLocation("appdata", "scripts/", true);
236 if(destination.isNull()) {
237 KMessageBox::sorry(0, i18n("Failed to determinate location where the package \"%1\" should be installed to.", scriptpackagefile));
238 return false;
239 }
240
241 QString packagename = QFileInfo(scriptpackagefile).baseName();
242 destination += packagename; // add the packagename to the name of the destination-directory.
243
244 QDir packagepath(destination);
245 if( packagepath.exists() ) {
246 if( KMessageBox::warningContinueCancel(0,
247 i18n("A script package with the name \"%1\" already exists. Replace this package?", packagename),
248 i18n("Replace")) != KMessageBox::Continue )
249 return false;
250 if(! KIO::NetAccess::del(destination, 0) ) {
251 KMessageBox::sorry(0, i18n("Could not uninstall this script package. You may not have sufficient permissions to delete the folder \"%1\".", destination));
252 return false;
253 }
254 }
255
256 krossdebug( QString("Copy script-package to destination directory: %1").arg(destination) );
257 archivedir->copyTo(destination, true);
258
259 QDomNodeList nodelist = domdoc.elementsByTagName("ScriptAction");
260 int nodelistcount = nodelist.count();
261 for(int i = 0; i < nodelistcount; ++i) {
262 QDomElement element = nodelist.item(i).toElement();
263 const QString name = element.attribute("name");
264 Action* action = new Action(Manager::self().actionCollection(), name, packagepath);
265 action->fromDomElement(element);
266 //connect(action, SIGNAL(failed(QString,QString)), this, SLOT(executionFailed(QString,QString)));
267 //connect(action, SIGNAL(success()), this, SLOT(executionSuccessful()));
268 //connect(action, SIGNAL(activated(Kross::Action*)), SIGNAL(executionStarted(Kross::Action*)));
269 }
270
271 //d->modified = true;
272 return true;
273 }
274
275 bool KoScriptManagerModule::uninstallPackage(Action* action)
276 {
277 const QString name = action->objectName();
278 QString file = action->file();
279 QFileInfo fi(file);
280 if(file.isNull() || ! fi.exists()) {
281 KMessageBox::sorry(0, i18n("Could not uninstall the script package \"%1\" since the script is not installed.",action->objectName()));
282 return false;
283 }
284 const QString scriptpackagepath = fi.absolutePath();
285 krossdebug( QString("Uninstall script-package with destination directory: %1").arg(scriptpackagepath) );
286 if(! KIO::NetAccess::del(scriptpackagepath, 0) ) {
287 KMessageBox::sorry(0, i18n("Could not uninstall the script package \"%1\". You may not have sufficient permissions to delete the folder \"%1\".",action->objectName()).arg(scriptpackagepath));
288 return false;
289 }
290 delete action; action = 0; // removes the action from d->actions as well
291 d->modified = true;
292 return true;
293 }
294 #endif
295
KoScriptManagerDialog()296 KoScriptManagerDialog::KoScriptManagerDialog()
297 : KoDialog()
298 {
299 setCaption(i18n("Script Manager"));
300 setButtons(KoDialog::Ok | KoDialog::Cancel);
301 setButtonText(KoDialog::Ok, i18n("Save"));
302 setButtonIcon(KoDialog::Ok, koIcon("document-save"));
303 m_collection = new KoScriptManagerCollection(mainWidget());
304 setMainWidget(m_collection);
305 resize(QSize(520, 380).expandedTo(minimumSizeHint()));
306 connect(this, SIGNAL(accepted()), this, SLOT(slotAccepted()));
307 }
308
~KoScriptManagerDialog()309 KoScriptManagerDialog::~KoScriptManagerDialog()
310 {
311 }
312
slotAccepted()313 void KoScriptManagerDialog::slotAccepted()
314 {
315 const QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
316 if (! dir.isEmpty()) {
317 const QString scriptsDir = dir + QStringLiteral("/scripts/");
318 QDir().mkpath(scriptsDir);
319
320 const QString file = QFileInfo(scriptsDir, "scripts.rc").absoluteFilePath();
321 QFile f(file);
322 if (f.open(QIODevice::WriteOnly))
323 if (Kross::Manager::self().actionCollection()->writeXml(&f))
324 debugKoKross<<"Successfully saved file:"<<file;
325 f.close();
326 }
327 }
328