File indexing completed on 2024-03-24 15:37:27

0001 /***************************************************************************
0002  * actioncollectionview.cpp
0003  * This file is part of the KDE project
0004  * copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
0005  * copyright (C) 2006-2007 Sebastian Sauer <mail@dipe.org>
0006  *
0007  * This program is free software; you can redistribute it and/or
0008  * modify it under the terms of the GNU Library General Public
0009  * License as published by the Free Software Foundation; either
0010  * version 2 of the License, or (at your option) any later version.
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 GNU
0014  * Library General Public License for more details.
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this program; see the file COPYING.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  ***************************************************************************/
0020 
0021 #include "actioncollectionview.h"
0022 #include "actioncollectionmodel.h"
0023 
0024 #include <kross/core/manager.h>
0025 #include <kross/core/action.h>
0026 #include <kross/core/actioncollection.h>
0027 #include <kross/core/interpreter.h>
0028 
0029 #include <QAction>
0030 #include <QBoxLayout>
0031 #include <QDir>
0032 #include <QFileInfo>
0033 #include <QHeaderView>
0034 #include <QLabel>
0035 #include <QLineEdit>
0036 #include <QPushButton>
0037 
0038 #include <kmessagebox.h>
0039 #include <kpagedialog.h>
0040 #include <kactioncollection.h>
0041 #include <kcombobox.h>
0042 #include <kiconbutton.h>
0043 #include <klocalizedstring.h>
0044 #include <kurlrequester.h>
0045 
0046 //#include <ktar.h>
0047 //#include <kio/netaccess.h>
0048 
0049 using namespace Kross;
0050 
0051 /*********************************************************************************
0052  * ActionCollectionEditor
0053  */
0054 
0055 namespace Kross
0056 {
0057 
0058 /// \internal d-pointer class.
0059 class ActionCollectionEditor::Private
0060 {
0061 public:
0062     enum Type { ActionType, CollectionType };
0063     const Type type;
0064     union {
0065         Action *action;
0066         ActionCollection *collection;
0067     };
0068 
0069     QString name() const
0070     {
0071         return type == ActionType ? action->name() : collection->name();
0072     }
0073     QString text() const
0074     {
0075         return type == ActionType ? action->text() : collection->text();
0076     }
0077     QString description() const
0078     {
0079         return type == ActionType ? action->description() : collection->description();
0080     }
0081     QString iconName() const
0082     {
0083         return type == ActionType ? action->iconName() : collection->iconName();
0084     }
0085     bool isEnabled() const
0086     {
0087         return type == ActionType ? action->isEnabled() : collection->isEnabled();
0088     }
0089 
0090     QLineEdit *nameedit;
0091     QLineEdit *textedit;
0092     QLineEdit *commentedit;
0093     QLineEdit *iconedit;
0094     KComboBox *interpreteredit;
0095     KUrlRequester *fileedit;
0096     //QCheckBox* enabledcheckbox;
0097 
0098     explicit Private(Action *a) : type(ActionType), action(a)
0099     {
0100         Q_ASSERT(a);
0101     }
0102     explicit Private(ActionCollection *c) : type(CollectionType), collection(c)
0103     {
0104         Q_ASSERT(c);
0105     }
0106 };
0107 
0108 }
0109 
0110 ActionCollectionEditor::ActionCollectionEditor(Action *action, QWidget *parent)
0111     : QWidget(parent), d(new Private(action))
0112 {
0113     initGui();
0114 }
0115 
0116 ActionCollectionEditor::ActionCollectionEditor(ActionCollection *collection, QWidget *parent)
0117     : QWidget(parent), d(new Private(collection))
0118 {
0119     initGui();
0120 }
0121 
0122 ActionCollectionEditor::~ActionCollectionEditor()
0123 {
0124     delete d;
0125 }
0126 
0127 Action *ActionCollectionEditor::action() const
0128 {
0129     return d->type == Private::ActionType ? d->action : nullptr;
0130 }
0131 
0132 ActionCollection *ActionCollectionEditor::collection() const
0133 {
0134     return d->type == Private::CollectionType ? d->collection : nullptr;
0135 }
0136 
0137 QLineEdit *ActionCollectionEditor::nameEdit() const
0138 {
0139     return d->nameedit;
0140 }
0141 QLineEdit *ActionCollectionEditor::textEdit() const
0142 {
0143     return d->textedit;
0144 }
0145 QLineEdit *ActionCollectionEditor::commentEdit() const
0146 {
0147     return d->commentedit;
0148 }
0149 QLineEdit *ActionCollectionEditor::iconEdit() const
0150 {
0151     return d->iconedit;
0152 }
0153 QComboBox *ActionCollectionEditor::interpreterEdit() const
0154 {
0155     return d->interpreteredit;
0156 }
0157 KUrlRequester *ActionCollectionEditor::fileEdit() const
0158 {
0159     return d->fileedit;
0160 }
0161 
0162 void ActionCollectionEditor::initGui()
0163 {
0164     QVBoxLayout *mainlayout = new QVBoxLayout();
0165     setLayout(mainlayout);
0166 
0167     QWidget *w = new QWidget(this);
0168     mainlayout->addWidget(w);
0169     QGridLayout *gridlayout = new QGridLayout();
0170     gridlayout->setContentsMargins(0, 0, 0, 0);
0171     //gridlayout->setSpacing(0);
0172     w->setLayout(gridlayout);
0173 
0174     QLabel *namelabel = new QLabel(i18n("Name:"), w);
0175     gridlayout->addWidget(namelabel, 0, 0);
0176     d->nameedit = new QLineEdit(w);
0177     namelabel->setBuddy(d->nameedit);
0178     d->nameedit->setText(d->name());
0179     d->nameedit->setEnabled(false);
0180     gridlayout->addWidget(d->nameedit, 0, 1);
0181 
0182     QLabel *textlabel = new QLabel(i18n("Text:"), w);
0183     gridlayout->addWidget(textlabel, 1, 0);
0184     d->textedit = new QLineEdit(w);
0185     textlabel->setBuddy(d->textedit);
0186     d->textedit->setText(d->text());
0187     gridlayout->addWidget(d->textedit, 1, 1);
0188 
0189     QLabel *commentlabel = new QLabel(i18n("Comment:"), w);
0190     gridlayout->addWidget(commentlabel, 2, 0);
0191     d->commentedit = new QLineEdit(w);
0192     commentlabel->setBuddy(d->commentedit);
0193     d->commentedit->setText(d->description());
0194     gridlayout->addWidget(d->commentedit, 2, 1);
0195 
0196     QLabel *iconlabel = new QLabel(i18n("Icon:"), w);
0197     gridlayout->addWidget(iconlabel, 3, 0);
0198     QWidget *iconbox = new QWidget(w);
0199     QHBoxLayout *iconlayout = new QHBoxLayout();
0200     iconlayout->setContentsMargins(0, 0, 0, 0);
0201     iconbox->setLayout(iconlayout);
0202     d->iconedit = new QLineEdit(iconbox);
0203     iconlabel->setBuddy(d->iconedit);
0204     d->iconedit->setText(d->iconName());
0205     iconlayout->addWidget(d->iconedit, 1);
0206     KIconButton *iconbutton = new KIconButton(iconbox);
0207     iconbutton->setIcon(d->iconName());
0208     connect(iconbutton, SIGNAL(iconChanged(QString)), d->iconedit, SLOT(setText(QString)));
0209     iconlayout->addWidget(iconbutton);
0210     gridlayout->addWidget(iconbox, 3, 1);
0211 
0212     //QFrame* hr1 = new QFrame(w);
0213     //hr1->setFrameStyle(QFrame::HLine | QFrame::Sunken);
0214     //gridlayout->addWidget(hr1, 4, 0, -1, -1, Qt::AlignVCenter);
0215 
0216     if (d->type == Private::ActionType) {
0217         QLabel *interpreterlabel = new QLabel(i18n("Interpreter:"), w);
0218         gridlayout->addWidget(interpreterlabel, 4, 0);
0219         d->interpreteredit = new KComboBox(w);
0220         interpreterlabel->setBuddy(d->interpreteredit);
0221         d->interpreteredit->setMaxVisibleItems(10);
0222         d->interpreteredit->insertItems(0, Manager::self().interpreters());
0223         d->interpreteredit->setEditable(true);
0224         //c->lineEdit()->setText( d->action->interpreter() );
0225         int idx = Manager::self().interpreters().indexOf(d->action->interpreter());
0226         if (idx >= 0) {
0227             d->interpreteredit->setCurrentIndex(idx);
0228         } else {
0229             d->interpreteredit->setEditText(d->action->interpreter());
0230         }
0231         gridlayout->addWidget(d->interpreteredit, 4, 1);
0232 
0233         QLabel *filelabel = new QLabel(i18n("File:"), w);
0234         gridlayout->addWidget(filelabel, 5, 0);
0235         d->fileedit = new KUrlRequester(w);
0236         filelabel->setBuddy(d->fileedit);
0237         QStringList mimetypes;
0238         foreach (const QString &interpretername, Manager::self().interpreters()) {
0239             InterpreterInfo *info = Manager::self().interpreterInfo(interpretername);
0240             Q_ASSERT(info);
0241             mimetypes.append(info->mimeTypes().join(" ").trimmed());
0242         }
0243         //InterpreterInfo* info = Manager::self().interpreterInfo( Manager::self().interpreternameForFile( d->action->file() ) );
0244         //const QString defaultmime = info ? info->mimeTypes().join(" ").trimmed() : QString();
0245 
0246         d->fileedit->setMimeTypeFilters(mimetypes);
0247         d->fileedit->setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly);
0248         d->fileedit->setUrl(QUrl::fromLocalFile(d->action->file()));
0249         gridlayout->addWidget(d->fileedit, 5, 1);
0250     } else {
0251         d->interpreteredit = nullptr;
0252         d->fileedit = nullptr;
0253     }
0254 
0255     //d->enabledcheckbox = new QCheckBox(this);
0256     //d->enabledcheckbox->setText( i18n("Enabled") );
0257     //d->enabledcheckbox->setChecked( d->isEnabled() );
0258     //mainlayout->addWidget(d->enabledcheckbox);
0259 
0260     mainlayout->addStretch(1);
0261 }
0262 
0263 bool ActionCollectionEditor::isValid()
0264 {
0265     //TODO check also if such a name already exist.
0266     return ! d->nameedit->text().isEmpty();
0267 }
0268 
0269 void ActionCollectionEditor::commit()
0270 {
0271     switch (d->type) {
0272     case Private::ActionType: {
0273         d->action->setText(d->textedit->text());
0274         d->action->setDescription(d->commentedit->text());
0275         d->action->setIconName(d->iconedit->text());
0276         d->action->setInterpreter(d->interpreteredit->currentText());
0277         d->action->setFile(d->fileedit->url().path());
0278         //d->action->setEnabled( d->enabledcheckbox->isChecked() );
0279     } break;
0280     case Private::CollectionType: {
0281         d->collection->setText(d->textedit->text());
0282         d->collection->setDescription(d->commentedit->text());
0283         d->collection->setIconName(d->iconedit->text());
0284         //d->collection->setEnabled( d->enabledcheckbox->isChecked() );
0285     } break;
0286     default: break;
0287     }
0288 }
0289 
0290 /*********************************************************************************
0291  * ActionCollectionView
0292  */
0293 
0294 namespace Kross
0295 {
0296 
0297 /// \internal d-pointer class.
0298 class ActionCollectionView::Private
0299 {
0300 public:
0301     bool modified;
0302     KActionCollection *collection;
0303     QMap< QString, QPushButton * > buttons;
0304     explicit Private() : modified(false) {}
0305 };
0306 
0307 }
0308 
0309 ActionCollectionView::ActionCollectionView(QWidget *parent)
0310     : QTreeView(parent)
0311     , d(new Private())
0312 {
0313     header()->hide();
0314     setSelectionMode(QAbstractItemView::SingleSelection);
0315     setAlternatingRowColors(true);
0316     setRootIsDecorated(true);
0317     setSortingEnabled(false);
0318     setItemsExpandable(true);
0319     //setDragEnabled(true);
0320     //setAcceptDrops(true);
0321     setDropIndicatorShown(true);
0322     setDragDropMode(QAbstractItemView::InternalMove);
0323 
0324     d->collection = new KActionCollection(this);
0325 
0326     QAction *runaction = new QAction(QIcon::fromTheme("system-run"), i18n("Run"), this);
0327     runaction->setObjectName("run");
0328     runaction->setToolTip(i18n("Execute the selected script."));
0329     runaction->setEnabled(false);
0330     d->collection->addAction("run", runaction);
0331     connect(runaction, SIGNAL(triggered()), this, SLOT(slotRun()));
0332 
0333     QAction *stopaction = new QAction(QIcon::fromTheme("process-stop"), i18n("Stop"), this);
0334     stopaction->setObjectName("stop");
0335     stopaction->setToolTip(i18n("Stop execution of the selected script."));
0336     stopaction->setEnabled(false);
0337     d->collection->addAction("stop", stopaction);
0338     connect(stopaction, SIGNAL(triggered()), this, SLOT(slotStop()));
0339 
0340     QAction *editaction = new QAction(QIcon::fromTheme("document-properties"), i18n("Edit..."), this);
0341     editaction->setObjectName("edit");
0342     editaction->setToolTip(i18n("Edit selected script."));
0343     editaction->setEnabled(false);
0344     d->collection->addAction("edit", editaction);
0345     connect(editaction, SIGNAL(triggered()), this, SLOT(slotEdit()));
0346 
0347     QAction *addaction = new QAction(QIcon::fromTheme("list-add"), i18n("Add..."), this);
0348     addaction->setObjectName("add");
0349     addaction->setToolTip(i18n("Add a new script."));
0350     //addaction->setEnabled(false);
0351     d->collection->addAction("add", addaction);
0352     connect(addaction, SIGNAL(triggered()), this, SLOT(slotAdd()));
0353 
0354     QAction *removeaction = new QAction(QIcon::fromTheme("list-remove"), i18n("Remove"), this);
0355     removeaction->setObjectName("remove");
0356     removeaction->setToolTip(i18n("Remove selected script."));
0357     removeaction->setEnabled(false);
0358     d->collection->addAction("remove", removeaction);
0359     connect(removeaction, SIGNAL(triggered()), this, SLOT(slotRemove()));
0360 
0361     connect(this, SIGNAL(enabledChanged(QString)), this, SLOT(slotEnabledChanged(QString)));
0362     //expandAll();
0363 }
0364 
0365 ActionCollectionView::~ActionCollectionView()
0366 {
0367     delete d;
0368 }
0369 
0370 void ActionCollectionView::setModel(QAbstractItemModel *m)
0371 {
0372     QTreeView::setModel(m);
0373     d->modified = false;
0374 
0375     QItemSelectionModel *selectionmodel = new QItemSelectionModel(m, this);
0376     setSelectionModel(selectionmodel);
0377 
0378     connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
0379             this, SLOT(slotSelectionChanged()));
0380     connect(m, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0381             this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
0382 }
0383 
0384 bool ActionCollectionView::isModified() const
0385 {
0386     return d->modified;
0387 }
0388 
0389 void ActionCollectionView::setModified(bool modified)
0390 {
0391     d->modified = modified;
0392 }
0393 
0394 KActionCollection *ActionCollectionView::actionCollection() const
0395 {
0396     return d->collection;
0397 }
0398 
0399 QPushButton *ActionCollectionView::button(const QString &actionname) const
0400 {
0401     return d->buttons.contains(actionname) ? d->buttons[actionname] : nullptr;
0402 }
0403 
0404 QItemSelection ActionCollectionView::itemSelection() const
0405 {
0406     QAbstractProxyModel *proxymodel = dynamic_cast< QAbstractProxyModel * >(model());
0407     QItemSelection selection = selectionModel()->selection();
0408     return proxymodel ? proxymodel->mapSelectionToSource(selection) : selection;
0409 }
0410 
0411 QPushButton *ActionCollectionView::createButton(QWidget *parentWidget, const QString &actionname)
0412 {
0413     QAction *action = d->collection->action(actionname);
0414     if (! action) {
0415         return nullptr;
0416     }
0417     //if( d->buttons.contains(actionname) ) delete d->buttons[];
0418     QPushButton *btn = new QPushButton(parentWidget);
0419     btn->setText(action->text());
0420     btn->setToolTip(action->toolTip());
0421     btn->setIcon(action->icon());
0422     btn->setEnabled(action->isEnabled());
0423     if (parentWidget && parentWidget->layout()) {
0424         parentWidget->layout()->addWidget(btn);
0425     }
0426     QObject::connect(btn, SIGNAL(clicked()), action, SLOT(trigger()));
0427     d->buttons.insert(actionname, btn);
0428     return btn;
0429 }
0430 
0431 void ActionCollectionView::slotEnabledChanged(const QString &actionname)
0432 {
0433     if (d->buttons.contains(actionname)) {
0434         QAction *action = d->collection->action(actionname);
0435         d->buttons[ actionname ]->setEnabled(action ? action->isEnabled() : false);
0436     }
0437 }
0438 
0439 void ActionCollectionView::slotSelectionChanged()
0440 {
0441     bool startenabled = selectionModel()->hasSelection();
0442     bool stopenabled = false;
0443     bool hasselection = selectionModel()->selectedIndexes().count() > 0;
0444     foreach (const QModelIndex &index, itemSelection().indexes()) {
0445         Action *action = ActionCollectionModel::action(index);
0446         if (startenabled && ! action) {
0447             startenabled = false;
0448         }
0449         if (! stopenabled) {
0450             stopenabled = (action && ! action->isFinalized());
0451         }
0452     }
0453     QAction *runaction = d->collection->action("run");
0454     if (runaction) {
0455         runaction->setEnabled(startenabled);
0456         emit enabledChanged("run");
0457     }
0458     QAction *stopaction = d->collection->action("stop");
0459     if (stopaction) {
0460         stopaction->setEnabled(stopenabled);
0461         emit enabledChanged("stop");
0462     }
0463     QAction *editaction = d->collection->action("edit");
0464     if (editaction) {
0465         editaction->setEnabled(hasselection);
0466         emit enabledChanged("edit");
0467     }
0468     QAction *removeaction = d->collection->action("remove");
0469     if (removeaction) {
0470         removeaction->setEnabled(hasselection);
0471         emit enabledChanged("remove");
0472     }
0473 }
0474 
0475 void ActionCollectionView::slotDataChanged(const QModelIndex &, const QModelIndex &)
0476 {
0477     d->modified = true;
0478 }
0479 
0480 void ActionCollectionView::slotRun()
0481 {
0482     if (! selectionModel()) {
0483         return;
0484     }
0485     QAction *stopaction = d->collection->action("stop");
0486 
0487     foreach (const QModelIndex &index, itemSelection().indexes()) {
0488         if (! index.isValid()) {
0489             continue;
0490         }
0491         if (stopaction) {
0492             stopaction->setEnabled(true);
0493             emit enabledChanged("stop");
0494         }
0495         Action *action = ActionCollectionModel::action(index);
0496         if (! action) {
0497             continue;
0498         }
0499         connect(action, SIGNAL(finished(Kross::Action*)), SLOT(slotSelectionChanged()));
0500         action->trigger();
0501     }
0502     slotSelectionChanged();
0503 }
0504 
0505 void ActionCollectionView::slotStop()
0506 {
0507     if (! selectionModel()) {
0508         return;
0509     }
0510     foreach (const QModelIndex &index, itemSelection().indexes()) {
0511         if (! index.isValid()) {
0512             continue;
0513         }
0514         Action *action = ActionCollectionModel::action(index);
0515         if (! action) {
0516             continue;
0517         }
0518         //connect(action, SIGNAL(started(Kross::Action*)), SLOT(slotSelectionChanged()));
0519         //connect(action, SIGNAL(finished(Kross::Action*)), SLOT(slotSelectionChanged()));
0520         action->finalize();
0521     }
0522     slotSelectionChanged();
0523 }
0524 
0525 void ActionCollectionView::slotEdit()
0526 {
0527     if (! selectionModel()) {
0528         return;
0529     }
0530     Action *action = nullptr;
0531     ActionCollection *collection = nullptr;
0532     foreach (const QModelIndex &index, itemSelection().indexes()) {
0533         if (! index.isValid()) {
0534             continue;
0535         }
0536         if (Action *a = ActionCollectionModel::action(index)) {
0537             action = a;
0538         } else if (ActionCollection *c = ActionCollectionModel::collection(index)) {
0539             collection = c;
0540         } else {
0541             continue;
0542         }
0543         break;
0544     }
0545     if ((! action) && (! collection)) {
0546         return;
0547     }
0548     KPageDialog *dialog = new KPageDialog(this);
0549     dialog->setWindowTitle(i18n("Edit"));
0550     dialog->setFaceType(KPageDialog::Plain);   //Auto Plain List Tree Tabbed
0551     ActionCollectionEditor *editor =
0552         action ? new ActionCollectionEditor(action, dialog)
0553         : new ActionCollectionEditor(collection, dialog);
0554     dialog->addPage(editor, i18nc("@title:group Script properties", "General"));
0555     //dialog->addPage(new QWidget(this), i18n("Security"));
0556     dialog->resize(QSize(580, 200).expandedTo(dialog->minimumSizeHint()));
0557     int result = dialog->exec();
0558     if (result == QDialog::Accepted /*&& dialog->result() == KDialog::Ok*/) {
0559         editor->commit();
0560     }
0561     dialog->deleteLater();
0562 }
0563 
0564 void ActionCollectionView::slotAdd()
0565 {
0566 
0567 //TODO
0568     KMessageBox::error(nullptr, "TODO");
0569 
0570 //ScriptManagerAddWizard wizard(this, collection);
0571 //int result = wizard.exec();
0572 
0573 #if 0
0574     if (! selectionModel()) {
0575         return;
0576     }
0577     ActionCollection *collection = 0;
0578     foreach (QModelIndex index, itemSelection().indexes()) {
0579         if (! index.isValid()) {
0580             continue;
0581         }
0582         if (ActionCollectionModel::action(index)) {
0583             //TODO probably add the item right after the current selected one?
0584             QModelIndex parent = index;
0585             while (parent.isValid() && ! collection) {
0586                 parent = d->view->model()->parent(parent);
0587                 collection = ActionCollectionModel::collection(parent);
0588             }
0589             if (collection) {
0590                 break;    // job done
0591             }
0592         } else if (ActionCollection *c = ActionCollectionModel::collection(index)) {
0593             collection = c;
0594             break; // job done
0595         }
0596     }
0597     ScriptManagerAddWizard wizard(this, collection);
0598     int result = wizard.exec();
0599     Q_UNUSED(result);
0600 #endif
0601 }
0602 
0603 void ActionCollectionView::slotRemove()
0604 {
0605     if (! selectionModel()) {
0606         return;
0607     }
0608     KMessageBox::error(nullptr, "TODO");
0609 }
0610 
0611 #include "moc_actioncollectionview.cpp"