Krita Source Code Documentation
Loading...
Searching...
No Matches
KisOpenPane.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2005 Peter Simonsson <psn@linux.se>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "KisOpenPane.h"
8
9#include <QLayout>
10#include <QImage>
11#include <QPainter>
12#include <QPen>
13#include <QPixmap>
14#include <QSize>
15#include <QString>
16#include <QTreeWidget>
17#include <QTreeWidgetItem>
18#include <QStyledItemDelegate>
19#include <QLinearGradient>
20#include <QStandardPaths>
21#include <QDragEnterEvent>
22#include <QDropEvent>
23#include <QMimeData>
24
25#include <klocalizedstring.h>
26#include <ksharedconfig.h>
27#include <kis_debug.h>
28#include <QUrl>
29
30
31#include <KisKineticScroller.h>
32#include <KoFileDialog.h>
33#include <KoIcon.h>
34#include "KisTemplateTree.h"
35#include "KisTemplateGroup.h"
36#include "KisTemplate.h"
37#include "KisDetailsPane.h"
38#include "KisTemplatesPane.h"
39#include "ui_KisOpenPaneBase.h"
40
41#include <limits.h>
42#include <kconfiggroup.h>
43
44#include <kis_icon.h>
45
46class KoSectionListItem : public QTreeWidgetItem
47{
48public:
49 KoSectionListItem(QTreeWidget* treeWidget, const QString& name, QString untranslatedName, int sortWeight, int widgetIndex = -1)
50 : QTreeWidgetItem(treeWidget, QStringList() << name)
54 {
55 Qt::ItemFlags newFlags = Qt::NoItemFlags;
56
57 if(m_widgetIndex >= 0)
58 newFlags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
59
60 setFlags(newFlags);
61 }
62
63 bool operator<(const QTreeWidgetItem & other) const override {
64 const KoSectionListItem* item = dynamic_cast<const KoSectionListItem*>(&other);
65
66 if (!item)
67 return 0;
68
69 return ((item->sortWeight() - sortWeight()) < 0);
70 }
71
72 int sortWeight() const {
73 return m_sortWeight;
74 }
75
76 int widgetIndex() const {
77 return m_widgetIndex;
78 }
79
80 QString untranslatedName() const {
81 return m_untranslatedName;
82 }
83
84private:
85 int m_sortWeight {0};
86 int m_widgetIndex {-1};
88};
89
90class KisOpenPanePrivate : public Ui_KisOpenPaneBase
91{
92public:
94 Ui_KisOpenPaneBase()
95 { }
96
99
100
101};
102
103KisOpenPane::KisOpenPane(QWidget *parent, const QStringList& mimeFilter, const QString& templatesResourcePath)
104 : QDialog(parent)
105 , d(new KisOpenPanePrivate)
106{
107 d->setupUi(this);
108
109 m_mimeFilter = mimeFilter;
110
111 QStyledItemDelegate* delegate = new QStyledItemDelegate(d->m_sectionList);
112 d->m_sectionList->setItemDelegate(delegate);
113 QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(d->m_sectionList);
114 if (scroller) {
115 connect(scroller, &QScroller::stateChanged, this, [&](QScroller::State state) {
117 });
118 }
119
120 connect(d->m_sectionList, SIGNAL(itemSelectionChanged()),
121 this, SLOT(updateSelectedWidget()));
122 connect(d->m_sectionList, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
123 this, SLOT(itemClicked(QTreeWidgetItem*)));
124 connect(d->m_sectionList, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
125 this, SLOT(itemClicked(QTreeWidgetItem*)));
126
127 initTemplates(templatesResourcePath);
128
130
131 if (!d->m_sectionList->selectedItems().isEmpty())
132 {
133 KoSectionListItem* selectedItem = static_cast<KoSectionListItem*>(d->m_sectionList->selectedItems().first());
134
135 if (selectedItem) {
136 d->m_widgetStack->widget(selectedItem->widgetIndex())->setFocus();
137 }
138 }
139
140 QList<int> sizes;
141
142 // Set the sizes of the details pane splitters
143 KConfigGroup cfgGrp( KSharedConfig::openConfig(), "TemplateChooserDialog"); sizes = cfgGrp.readEntry("DetailsPaneSplitterSizes", sizes);
144
145 if (!sizes.isEmpty())
146 Q_EMIT splitterResized(0, sizes);
147
150
151 setAcceptDrops(true);
152}
153
155{
156 if (!d->m_sectionList->selectedItems().isEmpty()) {
157 KoSectionListItem* item = dynamic_cast<KoSectionListItem*>(d->m_sectionList->selectedItems().first());
158
159 if (item) {
160 if (!qobject_cast<KisDetailsPane*>(d->m_widgetStack->widget(item->widgetIndex()))) {
161 KConfigGroup cfgGrp( KSharedConfig::openConfig(), "TemplateChooserDialog");
162 cfgGrp.writeEntry("LastReturnType", item->untranslatedName());
163 }
164 }
165 }
166
167 delete d;
168}
169
170
171
173{
174
175 KoFileDialog dialog(this, KoFileDialog::OpenFiles, "OpenDocument");
176 dialog.setCaption(i18n("Open Existing Document"));
177 dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
178 dialog.setMimeTypeFilters(m_mimeFilter);
179 Q_FOREACH (const QString &filename, dialog.filenames()) {
180 Q_EMIT openExistingFile(QUrl::fromUserInput(filename));
181 }
182}
183
184void KisOpenPane::slotOpenTemplate(const QUrl &url)
185{
186 Q_EMIT openTemplate(url);
187 accept();
188}
189
190void KisOpenPane::initTemplates(const QString& templatesResourcePath)
191{
192 QTreeWidgetItem* selectItem = 0;
193 QTreeWidgetItem* firstItem = 0;
194 const int templateOffset = 1000;
195
196 if (!templatesResourcePath.isEmpty()) {
197 KisTemplateTree templateTree(templatesResourcePath, true);
198
199 Q_FOREACH (KisTemplateGroup *group, templateTree.groups()) {
200 if (group->isHidden()) {
201 continue;
202 }
203
204 if (!d->m_templatesSeparator) {
205 d->m_templatesSeparator = new KoSectionListItem(d->m_sectionList, "", "", 999);
206 }
207
208 KisTemplatesPane* pane = new KisTemplatesPane(this, group->name(),
209 group, templateTree.defaultTemplate());
210 connect(pane, SIGNAL(openUrl(QUrl)), this, SLOT(slotOpenTemplate(QUrl)));
211 connect(pane, SIGNAL(alwaysUseChanged(KisTemplatesPane*,QString)),
212 this, SIGNAL(alwaysUseChanged(KisTemplatesPane*,QString)));
213 connect(this, SIGNAL(alwaysUseChanged(KisTemplatesPane*,QString)),
214 pane, SLOT(changeAlwaysUseTemplate(KisTemplatesPane*,QString)));
218 pane, SLOT(resizeSplitter(KisDetailsPane*,QList<int>)));
219 QTreeWidgetItem* item = addPane(group->name(), "Template", group->templates().first()->loadPicture(),
220 pane, group->sortingWeight() + templateOffset);
221
222
223
224 if (!firstItem) {
225 firstItem = item;
226 }
227
228 if (group == templateTree.defaultGroup()) {
229 firstItem = item;
230 }
231
232 if (pane->isSelected()) {
233 selectItem = item;
234 }
235 }
236 } else {
237 firstItem = d->m_sectionList->topLevelItem(0);
238 }
239
240 KConfigGroup cfgGrp( KSharedConfig::openConfig(), "TemplateChooserDialog");
241
242 if (selectItem && (cfgGrp.readEntry("LastReturnType") == "Template")) {
243 d->m_sectionList->setCurrentItem(selectItem, 0, QItemSelectionModel::ClearAndSelect);
244 }
245 else if (d->m_sectionList->selectedItems().isEmpty() && firstItem) {
246 d->m_sectionList->setCurrentItem(firstItem, 0, QItemSelectionModel::ClearAndSelect);
247 }
248}
249
250void KisOpenPane::dragEnterEvent(QDragEnterEvent *event)
251{
252 if (event->mimeData()->hasUrls()) {
253 event->accept();
254 }
255}
256
257void KisOpenPane::dropEvent(QDropEvent *event)
258{
259 if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) {
260 // XXX: when the MVC refactoring is done, this can open a bunch of
261 // urls, but since the part/document combination is still 1:1
262 // that won't work for now.
263 Q_EMIT openExistingFile(event->mimeData()->urls().first());
264
265 }
266}
267
268void KisOpenPane::addCustomDocumentWidget(QWidget *widget, const QString& title, const QString &untranslatedName, const QString& icon)
269{
270 Q_ASSERT(widget);
271
272 QTreeWidgetItem* item = addPane(title, untranslatedName, icon, widget, d->m_freeCustomWidgetIndex);
274 KConfigGroup cfgGrp( KSharedConfig::openConfig(), "TemplateChooserDialog");
275
276 QString lastActiveItem = cfgGrp.readEntry("LastReturnType");
277 bool showCustomItemByDefault = cfgGrp.readEntry("ShowCustomDocumentWidgetByDefault", false);
278 if (lastActiveItem == untranslatedName || (lastActiveItem.isEmpty() && showCustomItemByDefault)) {
279 d->m_sectionList->setCurrentItem(item, 0, QItemSelectionModel::ClearAndSelect);
280 KoSectionListItem* selectedItem = static_cast<KoSectionListItem*>(item);
281 d->m_widgetStack->widget(selectedItem->widgetIndex())->setFocus();
282 }
283}
284
285
286QTreeWidgetItem* KisOpenPane::addPane(const QString &title, const QString &untranslatedName, const QString &iconName, QWidget *widget, int sortWeight)
287{
288 if (!widget) {
289 return 0;
290 }
291
292 int id = d->m_widgetStack->addWidget(widget);
293 KoSectionListItem* listItem = new KoSectionListItem(d->m_sectionList, title, untranslatedName, sortWeight, id);
294
295 // resizes icons so they are a bit smaller
296 QIcon icon = KisIconUtils::loadIcon(iconName);
297 QPixmap iconPixmap = icon.pixmap(32, 32);
298
299 QIcon finalIcon(iconPixmap);
300 listItem->setIcon(0, finalIcon);
301
302 return listItem;
303}
304
305QTreeWidgetItem* KisOpenPane::addPane(const QString &title, const QString &untranslatedName, const QPixmap& icon, QWidget* widget, int sortWeight)
306{
307 if (!widget) {
308 return 0;
309 }
310
311 int id = d->m_widgetStack->addWidget(widget);
312
313 int iconSize = 32;
314
315 KoSectionListItem* listItem = new KoSectionListItem(d->m_sectionList, title, untranslatedName, sortWeight, id);
316
317 if (!icon.isNull()) {
318 QImage image = icon.toImage();
319
320 if (!image.isNull() && ((image.width() > iconSize) || (image.height() > iconSize))) {
321 image = image.scaled(iconSize, iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
322 }
323
324 image.convertTo(QImage::Format_ARGB32);
325 image = image.copy((image.width() - iconSize) / 2, (image.height() - iconSize) / 2, iconSize, iconSize);
326 listItem->setIcon(0, QIcon(QPixmap::fromImage(image)));
327 }
328
329 return listItem;
330}
331
333{
334 if(!d->m_sectionList->selectedItems().isEmpty())
335 {
336 KoSectionListItem* section = dynamic_cast<KoSectionListItem*>(d->m_sectionList->selectedItems().first());
337
338 if (!section)
339 return;
340
341 d->m_widgetStack->setCurrentIndex(section->widgetIndex());
342 }
343}
344
346{
347 Q_UNUSED(sender);
348 KConfigGroup cfgGrp( KSharedConfig::openConfig(), "TemplateChooserDialog");
349 cfgGrp.writeEntry("DetailsPaneSplitterSizes", sizes);
350}
351
352void KisOpenPane::itemClicked(QTreeWidgetItem* item)
353{
354 KoSectionListItem* selectedItem = static_cast<KoSectionListItem*>(item);
355
356 if (selectedItem && selectedItem->widgetIndex() >= 0) {
357 d->m_widgetStack->widget(selectedItem->widgetIndex())->setFocus();
358 }
359}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
int iconSize(qreal width, qreal height)
KoSectionListItem * m_templatesSeparator
void dropEvent(QDropEvent *event) override
void splitterResized(KisDetailsPane *sender, const QList< int > &sizes)
Emitted when one of the detail panes have changed it's splitter.
~KisOpenPane() override
void initTemplates(const QString &templatesResourcePath)
void openFileDialog()
when clicked "Open Existing Document" button
void saveSplitterSizes(KisDetailsPane *sender, const QList< int > &sizes)
Saves the splitter sizes for KisDetailsPaneBase based panes.
QStringList m_mimeFilter
Definition KisOpenPane.h:92
void openTemplate(const QUrl &)
void updateSelectedWidget()
void addCustomDocumentWidget(QWidget *widget, const QString &title, const QString &untranslatedName, const QString &icon=QString())
KisOpenPane(QWidget *parent, const QStringList &mimeFilter, const QString &templatesResourcePath=QString())
void slotOpenTemplate(const QUrl &url)
QTreeWidgetItem * addPane(const QString &title, const QString &untranslatedName, const QString &iconName, QWidget *widget, int sortWeight)
KisOpenPanePrivate *const d
Definition KisOpenPane.h:94
void openExistingFile(const QUrl &)
void itemClicked(QTreeWidgetItem *item)
void alwaysUseChanged(KisTemplatesPane *sender, const QString &alwaysUse)
Emitted when the always use template has changed.
void dragEnterEvent(QDragEnterEvent *event) override
QString name() const
int sortingWeight() const
QList< KisTemplate * > templates() const
bool isHidden() const
If all children are hidden, we are hidden too.
KisTemplateGroup * defaultGroup() const
QList< KisTemplateGroup * > groups() const
KisTemplate * defaultTemplate() const
bool isSelected()
Returns true if a template in this group was the last one selected.
int widgetIndex() const
int sortWeight() const
QString m_untranslatedName
bool operator<(const QTreeWidgetItem &other) const override
QString untranslatedName() const
KoSectionListItem(QTreeWidget *treeWidget, const QString &name, QString untranslatedName, int sortWeight, int widgetIndex=-1)
QIcon loadIcon(const QString &name)
KRITAWIDGETUTILS_EXPORT void updateCursor(QWidget *source, QScroller::State state)
KRITAWIDGETUTILS_EXPORT QScroller * createPreconfiguredScroller(QAbstractScrollArea *target)