1 /*
2  *  Copyright (c) 2011 Sven Langkamp <sven.langkamp@gmail.com>
3  *
4  *  This library is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU Lesser General Public License as published by
6  *  the Free Software Foundation; version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "tasksetdocker_dock.h"
20 
21 #include <QGridLayout>
22 #include <QListView>
23 #include <QHeaderView>
24 #include <QStyledItemDelegate>
25 #include <QPainter>
26 #include <QInputDialog>
27 #include <QAction>
28 
29 #include <klocalizedstring.h>
30 #include <kactioncollection.h>
31 
32 #include <kis_icon.h>
33 
34 #include <KoCanvasBase.h>
35 #include <KoResourceItemChooser.h>
36 #include <KoResourceServerAdapter.h>
37 #include <KoResourceServerProvider.h>
38 
39 #include <KisResourceServerProvider.h>
40 #include <KisViewManager.h>
41 #include <kis_canvas2.h>
42 #include <KisMainWindow.h>
43 #include "tasksetmodel.h"
44 
45 
46 class KisTasksetDelegate : public QStyledItemDelegate
47 {
48 public:
KisTasksetDelegate(QObject * parent=0)49     KisTasksetDelegate(QObject * parent = 0) : QStyledItemDelegate(parent) {}
~KisTasksetDelegate()50     ~KisTasksetDelegate() override {}
51     /// reimplemented
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const52     QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const override {
53         return QSize(QStyledItemDelegate::sizeHint(option, index).width(),
54                      qMin(QStyledItemDelegate::sizeHint(option, index).width(), 25));
55     }
56 };
57 
58 class KisTasksetResourceDelegate : public QStyledItemDelegate
59 {
60 public:
KisTasksetResourceDelegate(QObject * parent=0)61     KisTasksetResourceDelegate(QObject * parent = 0) : QStyledItemDelegate(parent) {}
~KisTasksetResourceDelegate()62     ~KisTasksetResourceDelegate() override {}
63     /// reimplemented
64     void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
65 };
66 
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const67 void KisTasksetResourceDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
68 {
69     if (! index.isValid())
70         return;
71 
72     TasksetResource* taskset = static_cast<TasksetResource*>(index.internalPointer());
73 
74     if (option.state & QStyle::State_Selected) {
75         painter->setPen(QPen(option.palette.highlight(), 2.0));
76         painter->fillRect(option.rect, option.palette.highlight());
77         painter->setBrush(option.palette.highlightedText());
78     }
79     else {
80         painter->setBrush(option.palette.text());
81     }
82 
83     painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, taskset->name());
84 
85 }
86 
TasksetDockerDock()87 TasksetDockerDock::TasksetDockerDock( ) : QDockWidget(i18n("Task Sets")), m_canvas(0), m_blocked(false)
88 {
89     QWidget* widget = new QWidget(this);
90     setupUi(widget);
91     m_model = new TasksetModel(this);
92     tasksetView->setModel(m_model);
93     tasksetView->setItemDelegate(new KisTasksetDelegate(this));
94     recordButton->setIcon(KisIconUtils::loadIcon("media-record"));
95     recordButton->setCheckable(true);
96     clearButton->setIcon(KisIconUtils::loadIcon("edit-delete"));
97     saveButton->setIcon(KisIconUtils::loadIcon("document-save"));
98     saveButton->setEnabled(false);
99 
100     chooserButton->setIcon(KisIconUtils::loadIcon("edit-copy"));
101 
102     m_rserver = new KoResourceServerSimpleConstruction<TasksetResource>("kis_taskset", "*.kts");
103     if (!QFileInfo(m_rserver->saveLocation()).exists()) {
104         QDir().mkpath(m_rserver->saveLocation());
105     }
106     QSharedPointer<KoAbstractResourceServerAdapter> adapter (new KoResourceServerAdapter<TasksetResource>(m_rserver));
107     m_rserver->loadResources(KoResourceServerProvider::blacklistFileNames(m_rserver->fileNames(), m_rserver->blackListedFiles()));
108     m_rserver->loadTags();
109 
110     KoResourceItemChooser* itemChooser = new KoResourceItemChooser(adapter, this);
111     itemChooser->setItemDelegate(new KisTasksetResourceDelegate(this));
112     itemChooser->setFixedSize(500, 250);
113     itemChooser->setRowHeight(30);
114     itemChooser->setColumnCount(1);
115     itemChooser->showTaggingBar(true);
116     chooserButton->setPopupWidget(itemChooser);
117 
118     connect(itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*)));
119 
120     setWidget(widget);
121 
122     connect( tasksetView, SIGNAL(clicked(QModelIndex)),
123             this, SLOT(activated(QModelIndex)) );
124 
125     connect( recordButton, SIGNAL(toggled(bool)), this, SLOT(recordClicked()));
126     connect( clearButton, SIGNAL(clicked(bool)), this, SLOT(clearClicked()));
127     connect( saveButton, SIGNAL(clicked(bool)), this, SLOT(saveClicked()));
128 }
129 
~TasksetDockerDock()130 TasksetDockerDock::~TasksetDockerDock()
131 {
132     delete m_rserver;
133 }
134 
setCanvas(KoCanvasBase * canvas)135 void TasksetDockerDock::setCanvas(KoCanvasBase * canvas)
136 {
137     if (m_canvas && m_canvas->viewManager()) {
138          m_canvas->viewManager()->actionCollection()->disconnect(this);
139          Q_FOREACH (KXMLGUIClient* client, m_canvas->viewManager()->mainWindow()->childClients()) {
140             client->actionCollection()->disconnect(this);
141         }
142     }
143     m_canvas = dynamic_cast<KisCanvas2*>(canvas);
144 }
145 
unsetCanvas()146 void TasksetDockerDock::unsetCanvas()
147 {
148     m_canvas = 0;
149     m_model->clear();
150 }
151 
actionTriggered(QAction * action)152 void TasksetDockerDock::actionTriggered(QAction* action)
153 {
154     if(action && !action->objectName().isEmpty() &&
155        !m_blocked && recordButton->isChecked()) {
156         m_model->addAction(action);
157         saveButton->setEnabled(true);
158     }
159 }
160 
activated(const QModelIndex & index)161 void TasksetDockerDock::activated(const QModelIndex& index)
162 {
163     QAction* action = m_model->actionFromIndex(index);
164     m_blocked = true;
165     action->trigger();
166     m_blocked = false;
167 }
168 
recordClicked()169 void TasksetDockerDock::recordClicked()
170 {
171     if(m_canvas) {
172         KisViewManager* view = m_canvas->viewManager();
173         connect(view->actionCollection(), SIGNAL(actionTriggered(QAction*)),
174                 this, SLOT(actionTriggered(QAction*)), Qt::UniqueConnection);
175         Q_FOREACH (KXMLGUIClient* client, view->mainWindow()->childClients()) {
176             connect(client->actionCollection(), SIGNAL(actionTriggered(QAction*)),
177                     this, SLOT(actionTriggered(QAction*)), Qt::UniqueConnection);
178         }
179     }
180 }
181 
saveClicked()182 void TasksetDockerDock::saveClicked()
183 {
184     bool ok;
185     QString name = QInputDialog::getText(this, i18n("Taskset Name"),
186                                          i18n("Name:"), QLineEdit::Normal,
187                                          QString(), &ok);
188     if (!ok) {
189         return;
190     }
191 
192     TasksetResource* taskset = new TasksetResource(QString());
193 
194     QStringList actionNames;
195     Q_FOREACH (QAction* action, m_model->actions()) {
196         actionNames.append(action->objectName());
197     }
198     taskset->setActionList(actionNames);
199     taskset->setValid(true);
200     QString saveLocation = m_rserver->saveLocation();
201 
202     bool newName = false;
203     if(name.isEmpty()) {
204         newName = true;
205         name = i18n("Taskset");
206     }
207     QFileInfo fileInfo(saveLocation + name + taskset->defaultFileExtension());
208 
209     int i = 1;
210     while (fileInfo.exists()) {
211         fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + taskset->defaultFileExtension());
212         i++;
213     }
214     taskset->setFilename(fileInfo.filePath());
215     if(newName) {
216         name = i18n("Taskset %1", i);
217     }
218     taskset->setName(name);
219     m_rserver->addResource(taskset);
220 }
221 
clearClicked()222 void TasksetDockerDock::clearClicked()
223 {
224     saveButton->setEnabled(false);
225     m_model->clear();
226 }
227 
resourceSelected(KoResource * resource)228 void TasksetDockerDock::resourceSelected(KoResource* resource)
229 {
230     if(!m_canvas) {
231         return;
232     }
233     m_model->clear();
234     saveButton->setEnabled(true);
235     Q_FOREACH (const QString& actionName, static_cast<TasksetResource*>(resource)->actionList()) {
236         QAction* action = m_canvas->viewManager()->actionCollection()->action(actionName);
237         if(action) {
238             m_model->addAction(action);
239         }
240     }
241 }
242 
243