1 /* This file is part of the KDE project
2 Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3 Copyright 2005,2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library 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 GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21 // Local
22 #include "AbstractRegionCommand.h"
23
24 #include <QApplication>
25
26 #include <KLocalizedString>
27 #include <kpassivepopup.h>
28
29 #include <KoCanvasBase.h>
30
31 #include "Cell.h"
32 #include "CellStorage.h"
33 #include "Damages.h"
34 #include "Map.h"
35 #include "Sheet.h"
36
37 using namespace Calligra::Sheets;
38
39 //BEGIN NOTE Stefan: some words on operations
40 //
41 // 1. SubTotal
42 // a) Makes no sense to extend to non-contiguous selections (NCS) as
43 // it refers to a change in one column.
44 // b) No special undo command available yet.
45 //
46 // 2. AutoSum
47 // a) should insert cell at the end of the selection, if the last
48 // is not empty
49 // b) opens an editor, if the user's intention is fuzzy -> hard to
50 // convert to NCS
51 //END
52
53 /***************************************************************************
54 class AbstractRegionCommand
55 ****************************************************************************/
56
AbstractRegionCommand(KUndo2Command * parent)57 AbstractRegionCommand::AbstractRegionCommand(KUndo2Command* parent)
58 : Region(),
59 KUndo2Command(parent),
60 m_sheet(0),
61 m_reverse(false),
62 m_firstrun(true),
63 m_register(true),
64 m_success(true),
65 m_checkLock(false)
66 {
67 }
68
~AbstractRegionCommand()69 AbstractRegionCommand::~AbstractRegionCommand()
70 {
71 }
72
execute(KoCanvasBase * canvas)73 bool AbstractRegionCommand::execute(KoCanvasBase* canvas)
74 {
75 if (!m_firstrun)
76 return false;
77 if (!isApproved())
78 return false;
79 // registering in undo history?
80 if (m_register)
81 canvas ? canvas->addCommand(this) : m_sheet->map()->addCommand(this);
82 else
83 redo();
84 return m_success;
85 }
86
redo()87 void AbstractRegionCommand::redo()
88 {
89 //sebsauer; following conditions and warning makes no sense cause we would crash
90 //later on cause m_sheet is direct accessed without NULL-check. So, let's add
91 //some asserts to check for the m_sheet=NULL case to be able to fix it if we
92 //can reproduce the situation.
93 #if 0
94 if (!m_sheet) {
95 warnSheets << "AbstractRegionCommand::redo(): No explicit m_sheet is set. "
96 << "Manipulating all sheets of the region." << endl;
97 }
98 #else
99 Q_ASSERT(m_sheet);
100 if (!m_sheet) { m_success = false; return; }
101 #endif
102
103 m_success = true;
104 bool successfully = true;
105 successfully = preProcessing();
106 if (!successfully) {
107 m_success = false;
108 return; // do nothing if pre-processing fails
109 }
110
111 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
112 // FIXME Stefan: Does every derived command damage the visual cache? No!
113 m_sheet->map()->addDamage(new CellDamage(m_sheet, *this, CellDamage::Appearance));
114
115 successfully = mainProcessing();
116 if (!successfully) {
117 m_success = false;
118 warnSheets << "AbstractRegionCommand::redo(): processing was not successful!";
119 }
120
121 successfully = true;
122 successfully = postProcessing();
123 if (!successfully) {
124 m_success = false;
125 warnSheets << "AbstractRegionCommand::redo(): postprocessing was not successful!";
126 }
127
128 QApplication::restoreOverrideCursor();
129
130 m_firstrun = false;
131 }
132
undo()133 void AbstractRegionCommand::undo()
134 {
135 m_reverse = !m_reverse;
136 redo();
137 m_reverse = !m_reverse;
138 }
139
isApproved() const140 bool AbstractRegionCommand::isApproved() const
141 {
142 //sebsauer; same as in AbstractRegionCommand::redo
143 Q_ASSERT(m_sheet);
144 if (!m_sheet) return false;
145
146 const QList<Element *> elements = cells();
147 const int begin = m_reverse ? elements.count() - 1 : 0;
148 const int end = m_reverse ? -1 : elements.count();
149 if (m_checkLock && m_sheet->cellStorage()->hasLockedCells(*this)) {
150 KPassivePopup::message(i18n("Processing is not possible, because some "
151 "cells are locked as elements of a matrix."),
152 QApplication::activeWindow());
153 return false;
154 }
155 if (m_sheet->isProtected()) {
156 for (int i = begin; i != end; m_reverse ? --i : ++i) {
157 const QRect range = elements[i]->rect();
158
159 for (int col = range.left(); col <= range.right(); ++col) {
160 for (int row = range.top(); row <= range.bottom(); ++row) {
161 Cell cell(m_sheet, col, row);
162 if (!cell.style().notProtected()) {
163 KPassivePopup::message(i18n("Processing is not possible, "
164 "because some cells are protected."),
165 QApplication::activeWindow());
166 return false;
167 }
168 }
169 }
170 }
171 }
172 return true;
173 }
174
mainProcessing()175 bool AbstractRegionCommand::mainProcessing()
176 {
177 //sebsauer; same as in AbstractRegionCommand::redo
178 Q_ASSERT(m_sheet);
179 if (!m_sheet) return false;
180
181 bool successfully = true;
182 const QList<Element *> elements = cells();
183 const int begin = m_reverse ? elements.count() - 1 : 0;
184 const int end = m_reverse ? -1 : elements.count();
185 for (int i = begin; i != end; m_reverse ? --i : ++i) {
186 successfully = successfully && process(elements[i]);
187 }
188 return successfully;
189 }
190