Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAutoSaveRecoveryDialog.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2012 Boudewijn Rempt <boud@valdyas.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
8
9#include <KoStore.h>
10
11#include <kwidgetitemdelegate.h>
12#include <klocalizedstring.h>
13#include <KisKineticScroller.h>
14
15#include <QVBoxLayout>
16#include <QHBoxLayout>
17#include <QListView>
18#include <QAbstractTableModel>
19#include <QLabel>
20#include <QDir>
21#include <QFileInfo>
22#include <QDateTime>
23#include <QImage>
24#include <QPixmap>
25#include <QHeaderView>
26#include <QStandardPaths>
27#include <QPainter>
28#include <QCheckBox>
29#include <kis_debug.h>
30
31
32struct FileItem {
33
34 FileItem() : checked(true) {}
35
36 QImage thumbnail;
37 QString name;
38 QString date;
39 bool checked;
40};
41
42class FileItemDelegate : public KWidgetItemDelegate
43{
44public:
45
46 FileItemDelegate(QAbstractItemView *itemView, KisAutoSaveRecoveryDialog *dlg)
47 : KWidgetItemDelegate(itemView, dlg)
48 , m_parent(dlg)
49 {
50 }
51
52 QList<QWidget*> createItemWidgets(const QModelIndex& index) const override
53 {
54 // a lump of coal and a piece of elastic will get you through the world
55 QWidget *page = new QWidget;
56 QHBoxLayout *layout = new QHBoxLayout(page);
57
58 QCheckBox *checkBox = new QCheckBox;
59 checkBox->setProperty("fileitem", index.data());
60
61 connect(checkBox, SIGNAL(toggled(bool)), m_parent, SLOT(toggleFileItem(bool)));
62 QLabel *thumbnail = new QLabel;
63 QLabel *filename = new QLabel;
64 QLabel *dateModified = new QLabel;
65
66 layout->addWidget(checkBox);
67 layout->addWidget(thumbnail);
68 layout->addWidget(filename);
69 layout->addWidget(dateModified);
70
71 page->setFixedSize(600, 200);
72
73 return QList<QWidget*>() << page;
74 }
75
76#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
77 void updateItemWidgets(const QList<QWidget*> widgets,
78 const QStyleOptionViewItem &option,
79 const QPersistentModelIndex &index) const override
80#else
82 const QStyleOptionViewItem &option,
83 const QPersistentModelIndex &index) const override
84#endif
85
86
87 {
88 FileItem *fileItem = (FileItem*)index.data().value<void*>();
89
90 QWidget* page= widgets[0];
91 QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(page->layout());
92 QCheckBox *checkBox = qobject_cast<QCheckBox*>(layout->itemAt(0)->widget());
93 QLabel *thumbnail = qobject_cast<QLabel*>(layout->itemAt(1)->widget());
94 QLabel *filename = qobject_cast<QLabel*>(layout->itemAt(2)->widget());
95 QLabel *modified = qobject_cast<QLabel*>(layout->itemAt(3)->widget());
96
97 checkBox->setChecked(fileItem->checked);
98 thumbnail->setPixmap(QPixmap::fromImage(fileItem->thumbnail));
99 filename->setText(fileItem->name);
100 modified->setText(fileItem->date);
101
102 // move the page _up_ otherwise it will draw relative to the actual position
103 page->setGeometry(option.rect.translated(0, -option.rect.y()));
104 }
105
106 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const override
107 {
108 //paint background for selected or hovered item
109 QStyleOptionViewItem opt = option;
110 itemView()->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0);
111 }
112
113 QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const override
114 {
115 return QSize(600, 200);
116 }
117
118
120};
121
122class KisAutoSaveRecoveryDialog::FileItemModel : public QAbstractListModel
123{
124public:
125 FileItemModel(QList<FileItem*> fileItems, QObject *parent)
126 : QAbstractListModel(parent)
127 , m_fileItems(fileItems){}
128
129 ~FileItemModel() override
130 {
131 qDeleteAll(m_fileItems);
132 m_fileItems.clear();
133 }
134
135 int rowCount(const QModelIndex &/*parent*/) const override { return m_fileItems.size(); }
136
137 Qt::ItemFlags flags(const QModelIndex& /*index*/) const override
138 {
139 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
140 return flags;
141 }
142
143 QVariant data(const QModelIndex& index, int role) const override
144 {
145 if (index.isValid() && index.row() < m_fileItems.size()) {
146
147 FileItem *item = m_fileItems.at(index.row());
148
149 switch (role) {
150 case Qt::DisplayRole:
151 {
152 return QVariant::fromValue<void*>((void*)item);
153 }
154 case Qt::SizeHintRole:
155 return QSize(600, 200);
156 }
157 }
158 return QVariant();
159 }
160
161 bool setData(const QModelIndex& index, const QVariant& /*value*/, int role) override
162 {
163 if (index.isValid() && index.row() < m_fileItems.size()) {
164 if (role == Qt::CheckStateRole) {
165 m_fileItems.at(index.row())->checked = !m_fileItems.at(index.row())->checked;
166 return true;
167 }
168 }
169 return false;
170 }
172};
173
175 KoDialog(parent)
176{
177 setCaption(i18nc("@title:window", "Recover Files"));
179 setButtonText(KoDialog::User1, i18n("Discard All"));
180 setMinimumSize(650, 500);
181 QWidget *page = new QWidget(this);
182 QVBoxLayout *layout = new QVBoxLayout(page);
183 if (filenames.size() == 1) {
184 layout->addWidget(new QLabel(i18n("The following autosave file can be recovered:")));
185 }
186 else {
187 layout->addWidget(new QLabel(i18n("The following autosave files can be recovered:")));
188 }
189
190 m_listView = new QListView();
191 m_listView->setAcceptDrops(false);
192 KWidgetItemDelegate *delegate = new FileItemDelegate(m_listView, this);
193 m_listView->setItemDelegate(delegate);
194
195 QList<FileItem*> fileItems;
196 Q_FOREACH (const QString &filename, filenames) {
197
198 FileItem *file = new FileItem();
199 file->name = filename;
200
201 QString path = autoSaveLocation() + "/" + filename;
202 // get thumbnail -- almost all Krita-supported formats save a thumbnail
204
205 if (store) {
206 QString thumbnailPath = QLatin1String("Thumbnails/thumbnail.png");
207 QString previewPath = QLatin1String("preview.png");
208 bool thumbnailExists = store->hasFile(thumbnailPath);
209 bool previewExists = store->hasFile(previewPath);
210 QString pathToUse = thumbnailExists ? thumbnailPath : (previewExists ? previewPath : "");
211
212 if (!pathToUse.isEmpty() && store->open(pathToUse)) {
213 // Hooray! No long delay for the user...
214 QByteArray bytes = store->read(store->size());
215 store->close();
216 QImage img;
217 img.loadFromData(bytes);
218 file->thumbnail = img.scaled(QSize(200,200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
219 }
220
221 delete store;
222 }
223
224 // get the date
225 QDateTime date = QFileInfo(path).lastModified();
226 file->date = "(" + QLocale::system().toString(date, QLocale::ShortFormat) + ")";
227
228 fileItems.append(file);
229 }
230
231 m_model = new FileItemModel(fileItems, m_listView);
232 m_listView->setModel(m_model);
234 if (scroller) {
235 connect(scroller, &QScroller::stateChanged, this, [&](QScroller::State state) {
237 });
238 }
239
240 layout->addWidget(m_listView);
241 layout->addWidget(new QLabel(i18n("If you select Cancel, all recoverable files will be kept.\nIf you press OK, selected files will be recovered, the unselected files discarded.")));
242 setMainWidget(page);
243
244 setAttribute(Qt::WA_DeleteOnClose, false);
245 connect( this, SIGNAL(user1Clicked()), this, SLOT(slotDeleteAll()) );
246}
247
249{
250 delete m_listView->itemDelegate();
251 delete m_model;
252 delete m_listView;
253}
254
256{
257 foreach(FileItem* fileItem, m_model->m_fileItems) {
258 fileItem->checked = false;
259 }
260 accept();
261}
262
264{
265 QStringList files;
266 Q_FOREACH (FileItem* fileItem, m_model->m_fileItems) {
267 if (fileItem->checked) {
268 files << fileItem->name;
269 }
270 }
271 return files;
272}
273
275{
276#if defined(Q_OS_WIN)
277 // On Windows, use the temp location (https://bugs.kde.org/show_bug.cgi?id=314921)
278 return QDir::tempPath();
279#elif defined(Q_OS_ANDROID)
280 QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation).append("/krita-backup");
281 if (!QDir(path).exists()) {
282 QDir().mkpath(path);
283 }
284 return path;
285#else
286 // On Linux, use a temp file in $HOME then. Mark it with the pid so two instances don't overwrite each other's
287 // autosave file
288 return QDir::homePath();
289#endif
290}
291
293{
294 // I've made better man from a piece of putty and matchstick!
295 QVariant v = sender()->property("fileitem") ;
296 if (v.isValid()) {
297 FileItem *fileItem = (FileItem*)v.value<void*>();
298 fileItem->checked = toggle;
299 }
300}
qreal v
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void updateItemWidgets(const QList< QWidget * > &widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const override
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &) const override
FileItemDelegate(QAbstractItemView *itemView, KisAutoSaveRecoveryDialog *dlg)
KisAutoSaveRecoveryDialog * m_parent
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override
QList< QWidget * > createItemWidgets(const QModelIndex &index) const override
bool setData(const QModelIndex &index, const QVariant &, int role) override
QVariant data(const QModelIndex &index, int role) const override
int rowCount(const QModelIndex &) const override
FileItemModel(QList< FileItem * > fileItems, QObject *parent)
Qt::ItemFlags flags(const QModelIndex &) const override
KisAutoSaveRecoveryDialog(const QStringList &filenames, QWidget *parent=0)
A dialog base class with standard buttons and predefined layouts.
Definition KoDialog.h:116
void user1Clicked()
void setMainWidget(QWidget *widget)
Definition KoDialog.cpp:354
void setButtonText(ButtonCode id, const QString &text)
Definition KoDialog.cpp:648
virtual void setCaption(const QString &caption)
Definition KoDialog.cpp:498
void setButtons(ButtonCodes buttonMask)
Definition KoDialog.cpp:195
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
Definition KoDialog.h:127
@ User1
Show User defined button 1.
Definition KoDialog.h:136
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
Definition KoDialog.h:130
bool close()
Definition KoStore.cpp:156
@ Read
Definition KoStore.h:29
qint64 size() const
Definition KoStore.cpp:239
static KoStore * createStore(const QString &fileName, Mode mode, const QByteArray &appIdentification=QByteArray(), Backend backend=Auto, bool writeMimetype=true)
Definition KoStore.cpp:39
bool hasFile(const QString &fileName) const
Definition KoStore.cpp:384
bool open(const QString &name)
Definition KoStore.cpp:109
QByteArray read(qint64 max)
Definition KoStore.cpp:181
KRITAWIDGETUTILS_EXPORT void updateCursor(QWidget *source, QScroller::State state)
KRITAWIDGETUTILS_EXPORT QScroller * createPreconfiguredScroller(QAbstractScrollArea *target)