1     /*
2      *  Copyright (c) 2007-2008 Cyrille Berger <cberger@cberger.net>
3      *  Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org>
4      *
5      *  This program is free software; you can redistribute it and/or modify
6      *  it under the terms of the GNU General Public License as published by
7      *  the Free Software Foundation; either version 2 of the License, or
8      *  (at your option) any later version.
9      *
10      *  This program is distributed in the hope that it will be useful,
11      *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12      *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13      *  GNU General Public License for more details.
14      *
15      *  You should have received a copy of the GNU General Public License
16      *  along with this program; if not, write to the Free Software
17      *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      * Boston, MA 02110-1301, USA.
19      */
20 
21     #include "kis_filter_selector_widget.h"
22 
23     #include <QHeaderView>
24     #include <QTreeView>
25     #include <QLabel>
26     #include <QComboBox>
27     #include <QPushButton>
28     #include <QScrollArea>
29     #include <QLayout>
30     #include <QDialogButtonBox>
31     #include <QPlainTextEdit>
32     #include <QDomDocument>
33     #include <QDomElement>
34 
35     #include "ui_wdgfilterselector.h"
36 
37     #include <kis_layer.h>
38     #include <kis_paint_device.h>
39     #include <filter/kis_filter.h>
40     #include <kis_config_widget.h>
41     #include <filter/kis_filter_configuration.h>
42     #include "kis_default_bounds.h"
43     #include <KisKineticScroller.h>
44 
45     // From krita/ui
46     #include "kis_bookmarked_configurations_editor.h"
47     #include "kis_bookmarked_filter_configurations_model.h"
48     #include "kis_filters_model.h"
49     #include "kis_config.h"
50 
51     class ThumbnailBounds : public KisDefaultBounds {
52     public:
ThumbnailBounds()53         ThumbnailBounds() : KisDefaultBounds() {}
~ThumbnailBounds()54         ~ThumbnailBounds() override {}
55 
bounds() const56         QRect bounds() const override
57         {
58             return QRect(0, 0, 100, 100);
59         }
60     private:
61         Q_DISABLE_COPY(ThumbnailBounds)
62     };
63 
64 
65     struct KisFilterSelectorWidget::Private {
66         QWidget *currentCentralWidget {0};
67         KisConfigWidget *currentFilterConfigurationWidget {0};
68         KisFilterSP currentFilter;
69         KisPaintDeviceSP paintDevice;
70         Ui_FilterSelector uiFilterSelector;
71         KisPaintDeviceSP thumb;
72         KisBookmarkedFilterConfigurationsModel *currentBookmarkedFilterConfigurationsModel {0};
73         KisFiltersModel *filtersModel {};
74         QGridLayout *widgetLayout {};
75         KisViewManager *view{};
76         bool showFilterGallery {true};
77         bool usedForMask {false};
78     };
79 
KisFilterSelectorWidget(QWidget * parent)80     KisFilterSelectorWidget::KisFilterSelectorWidget(QWidget* parent)
81         : d(new Private)
82     {
83         Q_UNUSED(parent);
84         setObjectName("KisFilterSelectorWidget");
85         d->uiFilterSelector.setupUi(this);
86 
87         d->widgetLayout = new QGridLayout(d->uiFilterSelector.centralWidgetHolder);
88         d->widgetLayout->setContentsMargins(0,0,0,0);
89         d->widgetLayout->setHorizontalSpacing(0);
90 
91         showFilterGallery(false);
92 
93         connect(d->uiFilterSelector.filtersSelector, SIGNAL(clicked(QModelIndex)), SLOT(setFilterIndex(QModelIndex)));
94         connect(d->uiFilterSelector.filtersSelector, SIGNAL(activated(QModelIndex)), SLOT(setFilterIndex(QModelIndex)));
95 
96         connect(d->uiFilterSelector.comboBoxPresets, SIGNAL(activated(int)),SLOT(slotBookmarkedFilterConfigurationSelected(int)));
97         connect(d->uiFilterSelector.pushButtonEditPressets, SIGNAL(pressed()), SLOT(editConfigurations()));
98         connect(d->uiFilterSelector.btnXML, SIGNAL(clicked()), this, SLOT(showXMLdialog()));
99 
100         KisConfig cfg(true);
101         d->uiFilterSelector.chkRememberPreset->setChecked(cfg.readEntry<bool>("filterdialog/rememberlastpreset", false));
102 
103     }
104 
~KisFilterSelectorWidget()105     KisFilterSelectorWidget::~KisFilterSelectorWidget()
106     {
107         KisConfig cfg(false);
108         cfg.writeEntry<bool>("filterdialog/rememberlastpreset", d->uiFilterSelector.chkRememberPreset->isChecked());
109         delete d->filtersModel;
110         delete d->currentBookmarkedFilterConfigurationsModel;
111         delete d->currentCentralWidget;
112         delete d->widgetLayout;
113         delete d;
114     }
115 
setView(KisViewManager * view)116     void KisFilterSelectorWidget::setView(KisViewManager *view)
117     {
118         d->view = view;
119     }
120 
setPaintDevice(bool showAll,KisPaintDeviceSP _paintDevice)121     void KisFilterSelectorWidget::setPaintDevice(bool showAll, KisPaintDeviceSP _paintDevice)
122     {
123         if (!_paintDevice) return;
124 
125         if (d->filtersModel) delete d->filtersModel;
126 
127         d->usedForMask = !showAll;
128         d->paintDevice = _paintDevice;
129         d->thumb = d->paintDevice->createThumbnailDevice(100, 100);
130         d->thumb->setDefaultBounds(new ThumbnailBounds());
131         d->filtersModel = new KisFiltersModel(showAll, d->thumb);
132 
133         d->uiFilterSelector.filtersSelector->setFilterModel(d->filtersModel);
134         d->uiFilterSelector.filtersSelector->header()->setVisible(false);
135 
136         KisConfig cfg(true);
137         QModelIndex idx = d->filtersModel->indexForFilter(cfg.readEntry<QString>("FilterSelector/LastUsedFilter", "levels"));
138 
139         if (!idx.isValid()) {
140             idx = d->filtersModel->indexForFilter("levels");
141         }
142 
143         if (d->usedForMask && isFilterGalleryVisible()) {
144             d->uiFilterSelector.filtersSelector->activateFilter(idx);
145         }
146 
147     }
148 
showFilterGallery(bool visible)149     void KisFilterSelectorWidget::showFilterGallery(bool visible)
150     {
151         if (d->showFilterGallery == visible) {
152             return;
153         }
154 
155         d->showFilterGallery = visible;
156         update();
157         emit sigFilterGalleryToggled(visible);
158         emit sigSizeChanged();
159     }
160 
showXMLdialog()161     void KisFilterSelectorWidget::showXMLdialog()
162     {
163         if (currentFilter()->showConfigurationWidget()) {
164             QDialog *xmlDialog = new QDialog(qApp->activeWindow());
165             xmlDialog->setMinimumWidth(500);
166             xmlDialog->setWindowTitle(i18n("Filter configuration XML"));
167             QVBoxLayout *xmllayout = new QVBoxLayout(xmlDialog);
168             QPlainTextEdit *text = new QPlainTextEdit(xmlDialog);
169             KisFilterConfigurationSP config = configuration();
170             text->setPlainText(config->toXML());
171             xmllayout->addWidget(text);
172             QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, xmlDialog);
173             connect(buttons, SIGNAL(accepted()), xmlDialog, SLOT(accept()));
174             connect(buttons, SIGNAL(rejected()), xmlDialog, SLOT(reject()));
175             xmllayout->addWidget(buttons);
176             if (xmlDialog->exec()==QDialog::Accepted) {
177                 QDomDocument doc;
178                 doc.setContent(text->toPlainText());
179                 config->fromXML(doc.documentElement());
180                 if (config) {
181                     d->currentFilterConfigurationWidget->setConfiguration(config);
182                 }
183             }
184         }
185     }
186 
isFilterGalleryVisible() const187     bool KisFilterSelectorWidget::isFilterGalleryVisible() const
188     {
189         return d->showFilterGallery;
190     }
191 
currentFilter() const192     KisFilterSP KisFilterSelectorWidget::currentFilter() const
193     {
194         return d->currentFilter;
195     }
196 
setFilter(KisFilterSP f,KisFilterConfigurationSP overrideDefaultConfig)197     void KisFilterSelectorWidget::setFilter(KisFilterSP f, KisFilterConfigurationSP overrideDefaultConfig)
198     {
199         Q_ASSERT(f);
200         Q_ASSERT(d->filtersModel);
201         setWindowTitle(f->name());
202         dbgKrita << "setFilter: " << f;
203         d->currentFilter = f;
204         delete d->currentCentralWidget;
205 
206         {
207             bool v = d->uiFilterSelector.filtersSelector->blockSignals(true);
208             d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(f->id()));
209             d->uiFilterSelector.filtersSelector->blockSignals(v);
210         }
211 
212         KisConfigWidget* widget =
213                 d->currentFilter->createConfigurationWidget(d->uiFilterSelector.centralWidgetHolder, d->paintDevice, d->usedForMask);
214 
215         if (!widget) { // No widget, so display a label instead
216             d->uiFilterSelector.comboBoxPresets->setEnabled(false);
217             d->uiFilterSelector.pushButtonEditPressets->setEnabled(false);
218             d->uiFilterSelector.btnXML->setEnabled(false);
219 
220             d->currentFilterConfigurationWidget = 0;
221             d->currentCentralWidget = new QLabel(i18n("No configuration options"),
222                                                  d->uiFilterSelector.centralWidgetHolder);
223             d->uiFilterSelector.scrollArea->setMinimumSize(d->currentCentralWidget->sizeHint());
224             qobject_cast<QLabel*>(d->currentCentralWidget)->setAlignment(Qt::AlignCenter);
225         } else {
226             KisFilterConfigurationSP defaultConfiguration =
227                 overrideDefaultConfig ?
228                 overrideDefaultConfig :
229                 d->currentFilter->defaultConfiguration();
230 
231             d->uiFilterSelector.comboBoxPresets->setEnabled(true);
232             d->uiFilterSelector.pushButtonEditPressets->setEnabled(true);
233             d->uiFilterSelector.btnXML->setEnabled(true);
234 
235             d->currentFilterConfigurationWidget = widget;
236             d->currentCentralWidget = widget;
237             widget->layout()->setContentsMargins(0,0,0,0);
238             d->currentFilterConfigurationWidget->setView(d->view);
239             d->currentFilterConfigurationWidget->blockSignals(true);
240             d->currentFilterConfigurationWidget->setConfiguration(defaultConfiguration);
241             d->currentFilterConfigurationWidget->blockSignals(false);
242             d->uiFilterSelector.scrollArea->setContentsMargins(0,0,0,0);
243             d->uiFilterSelector.scrollArea->setMinimumWidth(widget->sizeHint().width() + 18);
244             connect(d->currentFilterConfigurationWidget, SIGNAL(sigConfigurationUpdated()), this, SIGNAL(configurationChanged()));
245         }
246 
247         // Change the list of presets
248         delete d->currentBookmarkedFilterConfigurationsModel;
249         d->currentBookmarkedFilterConfigurationsModel = new KisBookmarkedFilterConfigurationsModel(d->thumb, f);
250         d->uiFilterSelector.comboBoxPresets->setModel(d->currentBookmarkedFilterConfigurationsModel);
251 
252         // Add the widget to the layout
253         d->currentCentralWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
254         d->widgetLayout->addWidget(d->currentCentralWidget, 0 , 0);
255 
256         if (d->uiFilterSelector.chkRememberPreset->isChecked()) {
257             int lastBookmarkedFilterConfiguration = KisConfig(true).readEntry<int>("lastBookmarkedFilterConfiguration/" + f->id(), 0);
258             if (d->uiFilterSelector.comboBoxPresets->count() > lastBookmarkedFilterConfiguration) {
259                 d->uiFilterSelector.comboBoxPresets->setCurrentIndex(lastBookmarkedFilterConfiguration);
260                 slotBookmarkedFilterConfigurationSelected(lastBookmarkedFilterConfiguration);
261             }
262         }
263 
264         update();
265     }
266 
setFilterIndex(const QModelIndex & idx)267     void KisFilterSelectorWidget::setFilterIndex(const QModelIndex& idx)
268     {
269         if (!idx.isValid()) return;
270 
271         Q_ASSERT(d->filtersModel);
272         KisFilter* filter = const_cast<KisFilter*>(d->filtersModel->indexToFilter(idx));
273         if (filter) {
274             setFilter(filter, 0);
275         }
276         else {
277             if (d->currentFilter) {
278                 bool v = d->uiFilterSelector.filtersSelector->blockSignals(true);
279                 QModelIndex idx = d->filtersModel->indexForFilter(d->currentFilter->id());
280                 d->uiFilterSelector.filtersSelector->setCurrentIndex(idx);
281                 d->uiFilterSelector.filtersSelector->scrollTo(idx);
282                 d->uiFilterSelector.filtersSelector->blockSignals(v);
283             }
284         }
285 
286         slotBookMarkCurrentFilter();
287         emit(configurationChanged());
288     }
289 
slotBookMarkCurrentFilter()290     void KisFilterSelectorWidget::slotBookMarkCurrentFilter() {
291         KisConfig cfg(false);
292         cfg.writeEntry<QString>("FilterSelector/LastUsedFilter", d->currentFilter->id());
293     }
294 
slotBookmarkedFilterConfigurationSelected(int index)295     void KisFilterSelectorWidget::slotBookmarkedFilterConfigurationSelected(int index)
296     {
297         if (d->currentFilterConfigurationWidget) {
298             QModelIndex modelIndex = d->currentBookmarkedFilterConfigurationsModel->index(index, 0);
299             KisFilterConfigurationSP config  = d->currentBookmarkedFilterConfigurationsModel->configuration(modelIndex);
300             d->currentFilterConfigurationWidget->setConfiguration(config);
301             if (d->currentFilter && index != KisConfig(true).readEntry<int>("lastBookmarkedFilterConfiguration/" + d->currentFilter->id(), 0)) {
302                 KisConfig(false).writeEntry<int>("lastBookmarkedFilterConfiguration/" + d->currentFilter->id(), index);
303             }
304         }
305     }
306 
editConfigurations()307     void KisFilterSelectorWidget::editConfigurations()
308     {
309         KisSerializableConfigurationSP config =
310                 d->currentFilterConfigurationWidget ? d->currentFilterConfigurationWidget->configuration() : 0;
311         KisBookmarkedConfigurationsEditor editor(this, d->currentBookmarkedFilterConfigurationsModel, config);
312         editor.exec();
313     }
314 
update()315     void KisFilterSelectorWidget::update()
316     {
317         d->uiFilterSelector.filtersSelector->setVisible(d->showFilterGallery);
318         if (d->showFilterGallery) {
319             setMinimumWidth(qMax(sizeHint().width(), 700));
320             d->uiFilterSelector.scrollArea->setMinimumHeight(400);
321             setMinimumHeight(d->uiFilterSelector.verticalLayout->sizeHint().height());
322             if (d->currentFilter) {
323                 bool v = d->uiFilterSelector.filtersSelector->blockSignals(true);
324                 d->uiFilterSelector.filtersSelector->setCurrentIndex(d->filtersModel->indexForFilter(d->currentFilter->id()));
325                 d->uiFilterSelector.filtersSelector->blockSignals(v);
326             }
327         }
328         else {
329             if (d->currentCentralWidget) {
330                 d->uiFilterSelector.scrollArea->setMinimumHeight(qMin(400, d->currentCentralWidget->sizeHint().height()));
331             }
332             setMinimumSize(d->uiFilterSelector.verticalLayout->sizeHint());
333         }
334     }
335 
configuration()336     KisFilterConfigurationSP KisFilterSelectorWidget::configuration()
337     {
338         if (d->currentFilterConfigurationWidget) {
339             KisFilterConfigurationSP config = dynamic_cast<KisFilterConfiguration*>(d->currentFilterConfigurationWidget->configuration().data());
340             if (config) {
341                 return config;
342             }
343         } else if (d->currentFilter) {
344             return d->currentFilter->defaultConfiguration();
345         }
346         return 0;
347 
348     }
349 
setFilterModel(QAbstractItemModel * model)350     void KisFilterTree::setFilterModel(QAbstractItemModel *model)
351     {
352         m_model = model;
353 
354     }
355 
activateFilter(QModelIndex idx)356     void KisFilterTree::activateFilter(QModelIndex idx)
357     {
358         setModel(m_model);
359         selectionModel()->select(idx, QItemSelectionModel::SelectCurrent);
360         expand(idx);
361         scrollTo(idx);
362         emit activated(idx);
363     }
364 
setVisible(bool visible)365     void KisFilterSelectorWidget::setVisible(bool visible)
366     {
367         QWidget::setVisible(visible);
368         if (visible) {
369             update();
370         }
371     }
372 
373