1 /*
2 * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (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 GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19 #include "dlg_bundle_manager.h"
20 #include "ui_wdgdlgbundlemanager.h"
21
22 #include "resourcemanager.h"
23 #include "dlg_create_bundle.h"
24
25 #include <QListWidget>
26 #include <QTreeWidget>
27 #include <QListWidgetItem>
28 #include <QPainter>
29 #include <QPixmap>
30 #include <QMessageBox>
31
32 #include <kis_icon.h>
33 #include "kis_action.h"
34 #include <KisResourceServerProvider.h>
35 #include <kconfiggroup.h>
36 #include <ksharedconfig.h>
37
38 #define ICON_SIZE 48
39
DlgBundleManager(ResourceManager * resourceManager,KisActionManager * actionMgr,QWidget * parent)40 DlgBundleManager::DlgBundleManager(ResourceManager *resourceManager, KisActionManager* actionMgr, QWidget *parent)
41 : KoDialog(parent)
42 , m_page(new QWidget())
43 , m_ui(new Ui::WdgDlgBundleManager)
44 , m_currentBundle(0)
45 , m_resourceManager(resourceManager)
46 {
47 setCaption(i18n("Manage Resource Bundles"));
48 m_ui->setupUi(m_page);
49 setMainWidget(m_page);
50 resize(m_page->sizeHint());
51 setButtons(Ok | Cancel);
52 setDefaultButton(Ok);
53
54 m_ui->listActive->setIconSize(QSize(ICON_SIZE, ICON_SIZE));
55 m_ui->listActive->setSelectionMode(QAbstractItemView::SingleSelection);
56 connect(m_ui->listActive, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*,QListWidgetItem*)));
57 connect(m_ui->listActive, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*)));
58
59 m_ui->listInactive->setIconSize(QSize(ICON_SIZE, ICON_SIZE));
60 m_ui->listInactive->setSelectionMode(QAbstractItemView::SingleSelection);
61 connect(m_ui->listInactive, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*,QListWidgetItem*)));
62 connect(m_ui->listInactive, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*)));
63
64 m_ui->bnAdd->setIcon(KisIconUtils::loadIcon("arrow-right"));
65 connect(m_ui->bnAdd, SIGNAL(clicked()), SLOT(addSelected()));
66
67 m_ui->bnRemove->setIcon(KisIconUtils::loadIcon("arrow-left"));
68 connect(m_ui->bnRemove, SIGNAL(clicked()), SLOT(removeSelected()));
69
70 m_ui->listBundleContents->setHeaderLabel(i18n("Resource"));
71 m_ui->listBundleContents->setSelectionMode(QAbstractItemView::NoSelection);
72
73 m_actionManager = actionMgr;
74
75 refreshListData();
76
77 connect(m_ui->bnEditBundle, SIGNAL(clicked()), SLOT(editBundle()));
78
79 connect(m_ui->bnImportBrushes, SIGNAL(clicked()), SLOT(slotImportResource()));
80 connect(m_ui->bnImportGradients, SIGNAL(clicked()), SLOT(slotImportResource()));
81 connect(m_ui->bnImportPalettes, SIGNAL(clicked()), SLOT(slotImportResource()));
82 connect(m_ui->bnImportPatterns, SIGNAL(clicked()), SLOT(slotImportResource()));
83 connect(m_ui->bnImportPresets, SIGNAL(clicked()), SLOT(slotImportResource()));
84 connect(m_ui->bnImportWorkspaces, SIGNAL(clicked()), SLOT(slotImportResource()));
85 connect(m_ui->bnImportBundles, SIGNAL(clicked()), SLOT(slotImportResource()));
86
87
88 connect(m_ui->createBundleButton, SIGNAL(clicked()), SLOT(slotCreateBundle()));
89 connect(m_ui->deleteBackupFilesButton, SIGNAL(clicked()), SLOT(slotDeleteBackupFiles()));
90 connect(m_ui->openResourceFolderButton, SIGNAL(clicked()), SLOT(slotOpenResourceFolder()));
91
92 }
93
94
refreshListData()95 void DlgBundleManager::refreshListData()
96 {
97 KoResourceServer<KisResourceBundle> *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer();
98
99 m_ui->listInactive->clear();
100 m_ui->listActive->clear();
101
102 Q_FOREACH (const QString &f, bundleServer->blackListedFiles()) {
103 KisResourceBundle *bundle = new KisResourceBundle(f);
104 bundle->load();
105 if (bundle->valid()) {
106 bundle->setInstalled(false);
107 m_blacklistedBundles[f] = bundle;
108 }
109 }
110 fillListWidget(m_blacklistedBundles.values(), m_ui->listInactive);
111
112 Q_FOREACH (KisResourceBundle *bundle, bundleServer->resources()) {
113 if (bundle->valid()) {
114 m_activeBundles[bundle->filename()] = bundle;
115 }
116 }
117 fillListWidget(m_activeBundles.values(), m_ui->listActive);
118 }
119
accept()120 void DlgBundleManager::accept()
121 {
122 KoResourceServer<KisResourceBundle> *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer();
123
124 for (int i = 0; i < m_ui->listActive->count(); ++i) {
125 QListWidgetItem *item = m_ui->listActive->item(i);
126 QByteArray ba = item->data(Qt::UserRole).toByteArray();
127 QString name = item->text();
128 KisResourceBundle *bundle = bundleServer->resourceByMD5(ba);
129 QMessageBox bundleFeedback;
130 bundleFeedback.setIcon(QMessageBox::Warning);
131 QString feedback = "bundlefeedback";
132
133 if (!bundle) {
134 // Get it from the blacklisted bundles
135 Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) {
136 if (b2->md5() == ba) {
137 bundle = b2;
138 break;
139 }
140 }
141 }
142
143 if (bundle) {
144 bool isKrita3Bundle = false;
145 if (bundle->filename().endsWith("Krita_3_Default_Resources.bundle")) {
146 isKrita3Bundle = true;
147 KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack");
148 group.writeEntry("HideKrita3Bundle", false);
149 }
150 else {
151 if (!bundle->isInstalled()) {
152 bundle->install();
153 //this removes the bundle from the blacklist and add it to the server without saving or putting it in front//
154 if (!bundleServer->addResource(bundle, false, false)){
155
156 feedback = i18n("Couldn't add bundle \"%1\" to resource server", name);
157 bundleFeedback.setText(feedback);
158 bundleFeedback.exec();
159 }
160 if (!isKrita3Bundle) {
161 if (!bundleServer->removeFromBlacklist(bundle)) {
162 feedback = i18n("Couldn't remove bundle \"%1\" from blacklist", name);
163 bundleFeedback.setText(feedback);
164 bundleFeedback.exec();
165 }
166 }
167 }
168 else {
169 if (!isKrita3Bundle) {
170 bundleServer->removeFromBlacklist(bundle);
171 }
172 //let's assume that bundles that exist and are installed have to be removed from the blacklist, and if they were already this returns false, so that's not a problem.
173 }
174 }
175 }
176 else{
177 QString feedback = i18n("Bundle \"%1\" doesn't exist!", name);
178 bundleFeedback.setText(feedback);
179 bundleFeedback.exec();
180
181 }
182 }
183
184 for (int i = 0; i < m_ui->listInactive->count(); ++i) {
185 QListWidgetItem *item = m_ui->listInactive->item(i);
186 QByteArray ba = item->data(Qt::UserRole).toByteArray();
187 KisResourceBundle *bundle = bundleServer->resourceByMD5(ba);
188 bool isKrits3Bundle = false;
189 if (bundle) {
190 if (bundle->filename().contains("Krita_3_Default_Resources.bundle")) {
191 isKrits3Bundle = true;
192 KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack");
193 group.writeEntry("HideKrita3Bundle", true);
194 }
195 if (bundle->isInstalled()) {
196 bundle->uninstall();
197 if (!isKrits3Bundle) {
198 bundleServer->removeResourceAndBlacklist(bundle);
199 }
200 }
201 }
202 }
203
204
205 KoDialog::accept();
206 }
207
addSelected()208 void DlgBundleManager::addSelected()
209 {
210 Q_FOREACH (QListWidgetItem *item, m_ui->listActive->selectedItems()) {
211 m_ui->listInactive->addItem(m_ui->listActive->takeItem(m_ui->listActive->row(item)));
212 }
213
214 }
215
removeSelected()216 void DlgBundleManager::removeSelected()
217 {
218 Q_FOREACH (QListWidgetItem *item, m_ui->listInactive->selectedItems()) {
219 m_ui->listActive->addItem(m_ui->listInactive->takeItem(m_ui->listInactive->row(item)));
220 }
221 }
222
itemSelected(QListWidgetItem * current,QListWidgetItem *)223 void DlgBundleManager::itemSelected(QListWidgetItem *current, QListWidgetItem *)
224 {
225 if (!current) {
226 m_ui->lblName->clear();
227 m_ui->lblAuthor->clear();
228 m_ui->lblEmail->clear();
229 m_ui->lblLicense->clear();
230 m_ui->lblWebsite->clear();
231 m_ui->lblDescription->clear();
232 m_ui->lblCreated->clear();
233 m_ui->lblUpdated->clear();
234 m_ui->lblPreview->setPixmap(QPixmap::fromImage(QImage()));
235 m_ui->listBundleContents->clear();
236 m_ui->bnEditBundle->setEnabled(false);
237 m_currentBundle = 0;
238 }
239 else {
240
241 QByteArray ba = current->data(Qt::UserRole).toByteArray();
242 KoResourceServer<KisResourceBundle> *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer();
243 KisResourceBundle *bundle = bundleServer->resourceByMD5(ba);
244
245 if (!bundle) {
246 // Get it from the blacklisted bundles
247 Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) {
248 if (b2->md5() == ba) {
249 bundle = b2;
250 break;
251 }
252 }
253 }
254
255
256 if (bundle) {
257 QFontMetrics metrics(this->font());
258
259 m_currentBundle = bundle;
260 m_ui->bnEditBundle->setEnabled(true);
261
262 m_ui->lblName->setText(bundle->name());
263 m_ui->lblAuthor->setText(metrics.elidedText(bundle->getMeta("author"), Qt::ElideRight, m_ui->lblAuthor->width()));
264 m_ui->lblAuthor->setToolTip(bundle->getMeta("author"));
265 m_ui->lblEmail->setText(metrics.elidedText(bundle->getMeta("email"), Qt::ElideRight, m_ui->lblEmail->width()));
266 m_ui->lblEmail->setToolTip(bundle->getMeta("email"));
267 m_ui->lblLicense->setText(metrics.elidedText(bundle->getMeta("license"), Qt::ElideRight, m_ui->lblLicense->width()));
268 m_ui->lblLicense->setToolTip(bundle->getMeta("license"));
269 m_ui->lblWebsite->setText(metrics.elidedText(bundle->getMeta("website"), Qt::ElideRight, m_ui->lblWebsite->width()));
270 m_ui->lblWebsite->setToolTip(bundle->getMeta("website"));
271 m_ui->lblDescription->setPlainText(bundle->getMeta("description"));
272 if (QDateTime::fromString(bundle->getMeta("created"), Qt::ISODate).isValid()) {
273 m_ui->lblCreated->setText(QDateTime::fromString(bundle->getMeta("created"), Qt::ISODate).toLocalTime().toString(Qt::DefaultLocaleShortDate));
274 } else {
275 m_ui->lblCreated->setText(QDate::fromString(bundle->getMeta("created"), "dd/MM/yyyy").toString(Qt::DefaultLocaleShortDate));
276 }
277 if (QDateTime::fromString(bundle->getMeta("updated"), Qt::ISODate).isValid()) {
278 m_ui->lblUpdated->setText(QDateTime::fromString(bundle->getMeta("updated"), Qt::ISODate).toLocalTime().toString(Qt::DefaultLocaleShortDate));
279 } else {
280 m_ui->lblUpdated->setText(QDate::fromString(bundle->getMeta("updated"), "dd/MM/yyyy").toString(Qt::DefaultLocaleShortDate));
281 }
282 QSize iconSize = QSize(128, 128);
283 QImage icon = bundle->image().scaled(iconSize*devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
284 icon.setDevicePixelRatio(devicePixelRatioF());
285 m_ui->lblPreview->setPixmap(QPixmap::fromImage(icon));
286 m_ui->listBundleContents->clear();
287
288 Q_FOREACH (const QString & resType, bundle->resourceTypes()) {
289
290 QTreeWidgetItem *toplevel = new QTreeWidgetItem();
291 if (resType == "gradients") {
292 toplevel->setText(0, i18n("Gradients"));
293 }
294 else if (resType == "patterns") {
295 toplevel->setText(0, i18n("Patterns"));
296 }
297 else if (resType == "brushes") {
298 toplevel->setText(0, i18n("Brushes"));
299 }
300 else if (resType == "palettes") {
301 toplevel->setText(0, i18n("Palettes"));
302 }
303 else if (resType == "workspaces") {
304 toplevel->setText(0, i18n("Workspaces"));
305 }
306 else if (resType == "paintoppresets") {
307 toplevel->setText(0, i18n("Brush Presets"));
308 }
309 else if (resType == "gamutmasks") {
310 toplevel->setText(0, i18n("Gamut Masks"));
311 }
312 #if defined HAVE_SEEXPR
313 else if (resType == "seexpr_scripts") {
314 toplevel->setText(0, i18n("SeExpr Scripts"));
315 }
316 #endif
317
318
319 m_ui->listBundleContents->addTopLevelItem(toplevel);
320
321 Q_FOREACH (const KoResource *res, bundle->resources(resType)) {
322 if (res) {
323 QTreeWidgetItem *i = new QTreeWidgetItem();
324 i->setIcon(0, QIcon(QPixmap::fromImage(res->image())));
325 i->setText(0, res->name());
326 toplevel->addChild(i);
327 }
328 }
329 }
330 }
331 else {
332 m_currentBundle = 0;
333 }
334 }
335 }
336
itemSelected(QListWidgetItem * current)337 void DlgBundleManager::itemSelected(QListWidgetItem *current)
338 {
339 itemSelected(current, 0);
340 }
341
editBundle()342 void DlgBundleManager::editBundle()
343 {
344 if (m_currentBundle) {
345 DlgCreateBundle dlg(m_currentBundle);
346 m_activeBundles.remove(m_currentBundle->filename());
347 m_currentBundle = 0;
348 if (dlg.exec() != QDialog::Accepted) {
349 return;
350 }
351 m_currentBundle = m_resourceManager->saveBundle(dlg);
352 refreshListData();
353 }
354 }
355
fillListWidget(QList<KisResourceBundle * > bundles,QListWidget * w)356 void DlgBundleManager::fillListWidget(QList<KisResourceBundle *> bundles, QListWidget *w)
357 {
358 QSize iconSize = QSize(ICON_SIZE, ICON_SIZE);
359 w->setIconSize(iconSize);
360 w->setSelectionMode(QAbstractItemView::MultiSelection);
361
362 Q_FOREACH (KisResourceBundle *bundle, bundles) {
363 QPixmap pixmap(iconSize*devicePixelRatioF());
364 pixmap.setDevicePixelRatio(devicePixelRatioF());
365 pixmap.fill(Qt::gray);
366 if (!bundle->image().isNull()) {
367 QImage scaled = bundle->image().scaled(iconSize*devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
368 scaled.setDevicePixelRatio(devicePixelRatioF());
369 int x = (ICON_SIZE - scaled.width()/devicePixelRatioF()) / 2;
370 int y = (ICON_SIZE - scaled.height()/devicePixelRatioF()) / 2;
371 QPainter gc(&pixmap);
372 gc.drawImage(x, y, scaled);
373 gc.end();
374 }
375
376 QListWidgetItem *item = new QListWidgetItem(pixmap, bundle->name());
377 item->setData(Qt::UserRole, bundle->md5());
378 w->addItem(item);
379 }
380 }
381
382
slotImportResource()383 void DlgBundleManager::slotImportResource()
384 {
385 if (m_actionManager) {
386 QObject *button = sender();
387 QString buttonName = button->objectName();
388 KisAction *action = 0;
389 if (buttonName == "bnImportBundles") {
390 action = m_actionManager->actionByName("import_bundles");
391 }
392 else if (buttonName == "bnImportBrushes") {
393 action = m_actionManager->actionByName("import_brushes");
394 }
395 else if (buttonName == "bnImportGradients") {
396 action = m_actionManager->actionByName("import_gradients");
397 }
398 else if (buttonName == "bnImportPalettes") {
399 action = m_actionManager->actionByName("import_palettes");
400 }
401 else if (buttonName == "bnImportPatterns") {
402 action = m_actionManager->actionByName("import_patterns");
403 }
404 else if (buttonName == "bnImportPresets") {
405 action = m_actionManager->actionByName("import_presets");
406 }
407 else if (buttonName == "bnImportWorkspaces") {
408 action = m_actionManager->actionByName("import_workspaces");
409 }
410 else {
411 warnUI << "Unhandled bundle manager import button " << buttonName;
412 return;
413 }
414
415 action->trigger();
416 refreshListData();
417 }
418 }
419
slotCreateBundle()420 void DlgBundleManager::slotCreateBundle() {
421
422 if (m_actionManager) {
423 KisAction *action = m_actionManager->actionByName("create_bundle");
424 action->trigger();
425 refreshListData();
426 }
427 }
428
slotDeleteBackupFiles()429 void DlgBundleManager::slotDeleteBackupFiles() {
430
431 if (m_actionManager) {
432 KisAction *action = m_actionManager->actionByName("edit_blacklist_cleanup");
433 action->trigger();
434 }
435 }
436
slotOpenResourceFolder()437 void DlgBundleManager::slotOpenResourceFolder() {
438
439 if (m_actionManager) {
440 KisAction *action = m_actionManager->actionByName("open_resources_directory");
441 action->trigger();
442 }
443 }
444
445