Krita Source Code Documentation
Loading...
Searching...
No Matches
KisUndoModel.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2010 Matus Talcik <matus.talcik@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6/****************************************************************************
7**
8** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
9** All rights reserved.
10** Contact: Nokia Corporation (qt-info@nokia.com)
11**
12** This file is part of the QtGui module of the Qt Toolkit.
13**
14** $QT_BEGIN_LICENSE:LGPL$
15** No Commercial Usage
16** This file contains pre-release code and may not be distributed.
17** You may use this file in accordance with the terms and conditions
18** contained in the Technology Preview License Agreement accompanying
19** this package.
20**
21** GNU Lesser General Public License Usage
22** Alternatively, this file may be used under the terms of the GNU Lesser
23** General Public License version 2.1 as published by the Free Software
24** Foundation and appearing in the file LICENSE.LGPL included in the
25** packaging of this file. Please review the following information to
26** ensure the GNU Lesser General Public License version 2.1 requirements
27** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
28**
29** In addition, as a special exception, Nokia gives you certain additional
30** rights. These rights are described in the Nokia Qt LGPL Exception
31** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
32**
33** If you have questions regarding the use of this file, please contact
34** Nokia at qt-info@nokia.com.
35**
36**
37**
38**
39**
40**
41**
42**
43** $QT_END_LICENSE$
44**
45****************************************************************************/
46#include "KisUndoModel.h"
47#include <klocalizedstring.h>
48
50 : QAbstractItemModel(parent)
51{
53 m_stack = 0;
54 m_canvas = 0;
55 m_sel_model = new QItemSelectionModel(this, this);
56 connect(m_sel_model, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(setStackCurrentIndex(QModelIndex)));
57 m_empty_label = i18n("<empty>");
58}
59
60QItemSelectionModel *KisUndoModel::selectionModel() const
61{
62 return m_sel_model;
63}
64
66{
67 return m_stack;
68}
69
71{
72 if (m_stack == stack)
73 return;
74
75 if (m_stack != 0) {
76 disconnect(m_stack, SIGNAL(canRedoChanged(bool)), this, SLOT(stackChanged()));
77 disconnect(m_stack, SIGNAL(cleanChanged(bool)), this, SLOT(stackChanged()));
78 disconnect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(stackChanged()));
79 disconnect(m_stack, SIGNAL(destroyed(QObject*)), this, SLOT(stackDestroyed(QObject*)));
80 disconnect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(addImage(int)));
81 }
82
83 m_stack = stack;
84
85 if (m_stack != 0) {
86 connect(m_stack, SIGNAL(canRedoChanged(bool)), this, SLOT(stackChanged()));
87 connect(m_stack, SIGNAL(cleanChanged(bool)), this, SLOT(stackChanged()));
88 connect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(stackChanged()));
89 connect(m_stack, SIGNAL(destroyed(QObject*)), this, SLOT(stackDestroyed(QObject*)));
90 connect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(addImage(int)));
91 }
92
94}
95
97{
98 if (obj != m_stack)
99 return;
100 m_stack = 0;
101
102 stackChanged();
103}
104
106{
107 beginResetModel();
108 endResetModel();
109
111 m_sel_model->setCurrentIndex(selectedIndex(), QItemSelectionModel::ClearAndSelect);
113}
114
115void KisUndoModel::setStackCurrentIndex(const QModelIndex &index)
116{
118 return;
119
120 if (m_stack == 0)
121 return;
122
123 if (index == selectedIndex())
124 return;
125
126 if (index.column() != 0)
127 return;
128
129 m_stack->setIndex(index.row());
130}
131
133{
134 return m_stack == 0 ? QModelIndex() : createIndex(m_stack->index(), 0);
135}
136
137QModelIndex KisUndoModel::index(int row, int column, const QModelIndex &parent) const
138{
139 if (m_stack == 0)
140 return QModelIndex();
141
142 if (parent.isValid())
143 return QModelIndex();
144
145 if (column != 0)
146 return QModelIndex();
147
148 if (row < 0 || row > m_stack->count())
149 return QModelIndex();
150
151 return createIndex(row, column);
152}
153
154QModelIndex KisUndoModel::parent(const QModelIndex&) const
155{
156 return QModelIndex();
157}
158
159int KisUndoModel::rowCount(const QModelIndex &parent) const
160{
161 if (m_stack == 0)
162 return 0;
163
164 if (parent.isValid())
165 return 0;
166
167 return m_stack->count() + 1;
168}
169
170int KisUndoModel::columnCount(const QModelIndex&) const
171{
172 return 1;
173}
174
175namespace {
176
177int calcNumMergedCommands(KUndo2Command *cmd) {
178 int numCommands = 1;
179 Q_FOREACH (KUndo2Command *child, cmd->mergeCommandsVector()) {
180 numCommands += calcNumMergedCommands(child);
181 }
182 return numCommands;
183};
184
185} // namespace
186
187QVariant KisUndoModel::data(const QModelIndex &index, int role) const
188{
189 if (m_stack == 0){
190 return QVariant();
191 }
192
193 if (index.column() != 0){
194 return QVariant();
195 }
196
197 if (index.row() < 0 || index.row() > m_stack->count()){
198 return QVariant();
199 }
200
201 if (role == Qt::DisplayRole) {
202 if (index.row() == 0){
203 return m_empty_label;
204 }
205 KUndo2Command* currentCommand = const_cast<KUndo2Command*>(m_stack->command(index.row() - 1));
206
207 return currentCommand->isMerged() ?
208 QString("%1 (Merged %2)").arg(currentCommand->text().toString()).arg(calcNumMergedCommands(currentCommand)) :
209 currentCommand->text().toString();
210 }
211 else if (role == Qt::DecorationRole) {
212 if (index.row() > 0) {
213 const KUndo2Command* currentCommand = m_stack->command(index.row() - 1);
214 if (m_imageMap.contains(currentCommand)) {
215 return m_imageMap[currentCommand];
216 }
217 }
218 }
219 return QVariant();
220}
221
223{
224 return m_empty_label;
225}
226
227void KisUndoModel::setEmptyLabel(const QString &label)
228{
229 m_empty_label = label;
230 stackChanged();
231}
232
233void KisUndoModel::setCleanIcon(const QIcon &icon)
234{
235 m_clean_icon = icon;
236 stackChanged();
237}
238
240{
241 return m_clean_icon;
242}
243
245{
246 m_canvas = canvas;
247}
248
250{
251
252 if (m_stack == 0 || m_stack->count() == 0) {
253 return;
254 }
255
256 const KUndo2Command* currentCommand = m_stack->command(idx-1);
257 if (m_stack->count() == idx && !m_imageMap.contains(currentCommand)) {
258 KisImageWSP historyImage = m_canvas->image();
259 KisPaintDeviceSP paintDevice = historyImage->projection();
260 QSize size = QSize(32, 32)*m_devicePixelRatioF;
261 QImage image = paintDevice->createThumbnail(size.width(), size.height(), 1,
264 image.setDevicePixelRatio(m_devicePixelRatioF);
265 m_imageMap[currentCommand] = image;
266 }
267
269
270 for (int i = 0; i < m_stack->count(); ++i) {
271 list << m_stack->command(i);
272 }
273
274 for (QMap<const KUndo2Command*, QImage>:: iterator it = m_imageMap.begin(); it != m_imageMap.end();) {
275 if (!list.contains(it.key())) {
276 it = m_imageMap.erase(it);
277 }
278 else {
279 ++it;
280 }
281 }
282}
284{
285 Q_UNUSED(index);
286 return false;
287}
288
289void KisUndoModel::setDevicePixelRatio(qreal devicePixelRatio)
290{
291 m_devicePixelRatioF = devicePixelRatio;
292}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KUndo2MagicString text() const
virtual QVector< KUndo2Command * > mergeCommandsVector() const
virtual bool isMerged() const
QString toString() const
The KUndo2QStack class is a stack of KUndo2Command objects.
virtual void setIndex(int idx)
int index() const
int count() const
const KUndo2Command * command(int index) const
KisPaintDeviceSP projection() const
QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample=1, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags())
bool m_blockOutgoingHistoryChange
KUndo2QStack * stack() const
QIcon cleanIcon() const
QPointer< KisCanvas2 > m_canvas
qreal m_devicePixelRatioF
void setDevicePixelRatio(qreal devicePixelRatio)
void setStackCurrentIndex(const QModelIndex &index)
QString m_empty_label
QModelIndex parent(const QModelIndex &child) const override
QMap< const KUndo2Command *, QImage > m_imageMap
KisUndoModel(QObject *parent=0)
KUndo2QStack * m_stack
void addImage(int idx)
QItemSelectionModel * selectionModel() const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void stackDestroyed(QObject *obj)
void setCleanIcon(const QIcon &icon)
void setEmptyLabel(const QString &label)
QString emptyLabel() const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void setCanvas(KisCanvas2 *canvas)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool checkMergedCommand(int index)
QModelIndex selectedIndex() const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setStack(KUndo2QStack *stack)
QItemSelectionModel * m_sel_model