File indexing completed on 2024-05-12 16:35:10

0001 /* This file is part of the KDE project
0002    Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
0003    Copyright 2005,2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 // Local
0022 #include "AbstractRegionCommand.h"
0023 
0024 #include <QApplication>
0025 
0026 #include <KLocalizedString>
0027 #include <kpassivepopup.h>
0028 
0029 #include <KoCanvasBase.h>
0030 
0031 #include "Cell.h"
0032 #include "CellStorage.h"
0033 #include "Damages.h"
0034 #include "Map.h"
0035 #include "Sheet.h"
0036 
0037 using namespace Calligra::Sheets;
0038 
0039 //BEGIN NOTE Stefan: some words on operations
0040 //
0041 // 1. SubTotal
0042 // a) Makes no sense to extend to non-contiguous selections (NCS) as
0043 //    it refers to a change in one column.
0044 // b) No special undo command available yet.
0045 //
0046 // 2. AutoSum
0047 // a) should insert cell at the end of the selection, if the last
0048 //    is not empty
0049 // b) opens an editor, if the user's intention is fuzzy -> hard to
0050 //    convert to NCS
0051 //END
0052 
0053 /***************************************************************************
0054   class AbstractRegionCommand
0055 ****************************************************************************/
0056 
0057 AbstractRegionCommand::AbstractRegionCommand(KUndo2Command* parent)
0058         : Region(),
0059         KUndo2Command(parent),
0060         m_sheet(0),
0061         m_reverse(false),
0062         m_firstrun(true),
0063         m_register(true),
0064         m_success(true),
0065         m_checkLock(false)
0066 {
0067 }
0068 
0069 AbstractRegionCommand::~AbstractRegionCommand()
0070 {
0071 }
0072 
0073 bool AbstractRegionCommand::execute(KoCanvasBase* canvas)
0074 {
0075     if (!m_firstrun)
0076         return false;
0077     if (!isApproved())
0078         return false;
0079     // registering in undo history?
0080     if (m_register)
0081         canvas ? canvas->addCommand(this) : m_sheet->map()->addCommand(this);
0082     else
0083         redo();
0084     return m_success;
0085 }
0086 
0087 void AbstractRegionCommand::redo()
0088 {
0089     //sebsauer; following conditions and warning makes no sense cause we would crash
0090     //later on cause m_sheet is direct accessed without NULL-check. So, let's add
0091     //some asserts to check for the m_sheet=NULL case to be able to fix it if we
0092     //can reproduce the situation.
0093 #if 0
0094     if (!m_sheet) {
0095         warnSheets << "AbstractRegionCommand::redo(): No explicit m_sheet is set. "
0096         << "Manipulating all sheets of the region." << endl;
0097     }
0098 #else
0099     Q_ASSERT(m_sheet);
0100     if (!m_sheet) { m_success = false; return; }
0101 #endif
0102 
0103     m_success = true;
0104     bool successfully = true;
0105     successfully = preProcessing();
0106     if (!successfully) {
0107         m_success = false;
0108         return;   // do nothing if pre-processing fails
0109     }
0110 
0111     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0112     // FIXME Stefan: Does every derived command damage the visual cache? No!
0113     m_sheet->map()->addDamage(new CellDamage(m_sheet, *this, CellDamage::Appearance));
0114 
0115     successfully = mainProcessing();
0116     if (!successfully) {
0117         m_success = false;
0118         warnSheets << "AbstractRegionCommand::redo(): processing was not successful!";
0119     }
0120 
0121     successfully = true;
0122     successfully = postProcessing();
0123     if (!successfully) {
0124         m_success = false;
0125         warnSheets << "AbstractRegionCommand::redo(): postprocessing was not successful!";
0126     }
0127 
0128     QApplication::restoreOverrideCursor();
0129 
0130     m_firstrun = false;
0131 }
0132 
0133 void AbstractRegionCommand::undo()
0134 {
0135     m_reverse = !m_reverse;
0136     redo();
0137     m_reverse = !m_reverse;
0138 }
0139 
0140 bool AbstractRegionCommand::isApproved() const
0141 {
0142     //sebsauer; same as in AbstractRegionCommand::redo
0143     Q_ASSERT(m_sheet);
0144     if (!m_sheet) return false;
0145 
0146     const QList<Element *> elements = cells();
0147     const int begin = m_reverse ? elements.count() - 1 : 0;
0148     const int end = m_reverse ? -1 : elements.count();
0149     if (m_checkLock && m_sheet->cellStorage()->hasLockedCells(*this)) {
0150         KPassivePopup::message(i18n("Processing is not possible, because some "
0151                                     "cells are locked as elements of a matrix."),
0152                                QApplication::activeWindow());
0153         return false;
0154     }
0155     if (m_sheet->isProtected()) {
0156         for (int i = begin; i != end; m_reverse ? --i : ++i) {
0157             const QRect range = elements[i]->rect();
0158 
0159             for (int col = range.left(); col <= range.right(); ++col) {
0160                 for (int row = range.top(); row <= range.bottom(); ++row) {
0161                     Cell cell(m_sheet, col, row);
0162                     if (!cell.style().notProtected()) {
0163                         KPassivePopup::message(i18n("Processing is not possible, "
0164                                                     "because some cells are protected."),
0165                                                QApplication::activeWindow());
0166                         return false;
0167                     }
0168                 }
0169             }
0170         }
0171     }
0172     return true;
0173 }
0174 
0175 bool AbstractRegionCommand::mainProcessing()
0176 {
0177     //sebsauer; same as in AbstractRegionCommand::redo
0178     Q_ASSERT(m_sheet);
0179     if (!m_sheet) return false;
0180 
0181     bool successfully = true;
0182     const QList<Element *> elements = cells();
0183     const int begin = m_reverse ? elements.count() - 1 : 0;
0184     const int end = m_reverse ? -1 : elements.count();
0185     for (int i = begin; i != end; m_reverse ? --i : ++i) {
0186         successfully = successfully && process(elements[i]);
0187     }
0188     return successfully;
0189 }