File indexing completed on 2024-05-12 16:35:12
0001 /* This file is part of the KDE project 0002 Copyright 2005,2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 // Local 0021 #include "MergeCommand.h" 0022 0023 #include <KLocalizedString> 0024 #include <kmessagebox.h> 0025 0026 #include "Cell.h" 0027 #include "Damages.h" 0028 #include "Map.h" 0029 #include "ui/Selection.h" // FIXME detach from ui 0030 #include "Sheet.h" 0031 0032 using namespace Calligra::Sheets; 0033 0034 MergeCommand::MergeCommand(KUndo2Command* parent) 0035 : AbstractRegionCommand(parent), 0036 m_merge(true), 0037 m_mergeHorizontal(false), 0038 m_mergeVertical(false), 0039 m_unmerger(0), 0040 m_selection(0) 0041 { 0042 m_checkLock = true; 0043 } 0044 0045 MergeCommand::~MergeCommand() 0046 { 0047 delete m_unmerger; 0048 } 0049 0050 bool MergeCommand::process(Element* element) 0051 { 0052 if (element->type() != Element::Range || element->isRow() || element->isColumn()) { 0053 // TODO Stefan: remove these elements?! 0054 return true; 0055 } 0056 0057 // sanity check 0058 if (m_sheet->isProtected() || m_sheet->map()->isProtected()) { 0059 return false; 0060 } 0061 0062 QRect range = element->rect(); 0063 int left = range.left(); 0064 int right = range.right(); 0065 int top = range.top(); 0066 int bottom = range.bottom(); 0067 int height = range.height(); 0068 int width = range.width(); 0069 0070 bool doMerge = m_reverse ? (!m_merge) : m_merge; 0071 0072 if (doMerge) { 0073 if (m_mergeHorizontal) { 0074 for (int row = top; row <= bottom; ++row) { 0075 int rows = 0; 0076 for (int col = left; col <= right; ++col) { 0077 Cell cell = Cell(m_sheet, col, row); 0078 if (cell.doesMergeCells()) { 0079 rows = qMax(rows, cell.mergedYCells()); 0080 cell.mergeCells(col, row, 0, 0); 0081 } 0082 } 0083 Cell cell = Cell(m_sheet, left, row); 0084 if (!cell.isPartOfMerged()) { 0085 cell.mergeCells(left, row, width - 1, rows); 0086 } 0087 } 0088 } else if (m_mergeVertical) { 0089 for (int col = left; col <= right; ++col) { 0090 int cols = 0; 0091 for (int row = top; row <= bottom; ++row) { 0092 Cell cell = Cell(m_sheet, col, row); 0093 if (cell.doesMergeCells()) { 0094 cols = qMax(cols, cell.mergedXCells()); 0095 cell.mergeCells(col, row, 0, 0); 0096 } 0097 } 0098 Cell cell = Cell(m_sheet, col, top); 0099 if (!cell.isPartOfMerged()) { 0100 cell.mergeCells(col, top, cols, height - 1); 0101 } 0102 } 0103 } else { 0104 Cell cell = Cell(m_sheet, left, top); 0105 cell.mergeCells(left, top, width - 1, height - 1); 0106 } 0107 } else { // dissociate 0108 for (int col = left; col <= right; ++col) { 0109 for (int row = top; row <= bottom; ++row) { 0110 Cell cell = Cell(m_sheet, col, row); 0111 if (!cell.doesMergeCells()) { 0112 continue; 0113 } 0114 cell.mergeCells(col, row, 0, 0); 0115 } 0116 } 0117 } 0118 0119 // adjust selection 0120 if (m_selection) 0121 m_selection->isEmpty() ? m_selection->initialize(range, m_sheet) : m_selection->extend(range, m_sheet); 0122 0123 return true; 0124 } 0125 0126 KUndo2MagicString MergeCommand::name() const 0127 { 0128 if (m_merge) { // MergeCommand 0129 if (m_mergeHorizontal) { 0130 return kundo2_i18n("Merge Cells Horizontally"); 0131 } else if (m_mergeVertical) { 0132 return kundo2_i18n("Merge Cells Vertically"); 0133 } else { 0134 return kundo2_i18n("Merge Cells"); 0135 } 0136 } 0137 return kundo2_i18n("Dissociate Cells"); 0138 } 0139 0140 bool MergeCommand::preProcessing() 0141 { 0142 if (isColumnOrRowSelected()) { 0143 KMessageBox::information(0, i18n("Merging of columns or rows is not supported.")); 0144 return false; 0145 } 0146 0147 if (m_firstrun) { 0148 setText(name()); 0149 0150 // reduce the region to the region occupied by merged cells 0151 Region mergedCells; 0152 ConstIterator endOfList = constEnd(); 0153 for (ConstIterator it = constBegin(); it != endOfList; ++it) { 0154 Element* element = *it; 0155 QRect range = element->rect(); 0156 int right = range.right(); 0157 int bottom = range.bottom(); 0158 for (int row = range.top(); row <= bottom; ++row) { 0159 for (int col = range.left(); col <= right; ++col) { 0160 Cell cell = Cell(m_sheet, col, row); 0161 if (cell.doesMergeCells()) { 0162 QRect rect(col, row, cell.mergedXCells() + 1, cell.mergedYCells() + 1); 0163 mergedCells.add(rect); 0164 } 0165 } 0166 } 0167 } 0168 0169 if (m_merge) { // MergeCommand 0170 // we're in the manipulator's first execution 0171 // initialize the undo manipulator 0172 m_unmerger = new MergeCommand(); 0173 if (!m_mergeHorizontal && !m_mergeVertical) { 0174 m_unmerger->setReverse(true); 0175 } 0176 m_unmerger->setSheet(m_sheet); 0177 m_unmerger->setRegisterUndo(false); 0178 m_unmerger->add(mergedCells); 0179 } else { // DissociateManipulator 0180 clear(); 0181 add(mergedCells); 0182 } 0183 } 0184 0185 if (m_merge) { // MergeCommand 0186 if (m_reverse) { // dissociate 0187 } else { // merge 0188 // Dissociate cells before merging the whole region. 0189 // For horizontal/vertical merging the cells stay 0190 // as they are. E.g. the region contains a merged cell 0191 // occupying two rows. Then the horizontal merge should 0192 // keep the height of two rows and extend the merging to the 0193 // region's width. In this case the unmerging is done while 0194 // processing each region element. 0195 if (!m_mergeHorizontal && !m_mergeVertical) { 0196 m_unmerger->redo(); 0197 } 0198 } 0199 } 0200 // Clear the associated selection, if any. The merge/dissociate process will restore 0201 // selections. This ensures that the selection isn't broken after merging. 0202 if (m_selection) m_selection->Region::clear(); 0203 0204 return AbstractRegionCommand::preProcessing(); 0205 } 0206 0207 bool MergeCommand::postProcessing() 0208 { 0209 if (m_merge) { // MergeCommand 0210 if (m_reverse) { // dissociate 0211 // restore the old merge status 0212 if (m_mergeHorizontal || m_mergeVertical) { 0213 m_unmerger->redo(); 0214 } else { 0215 m_unmerger->undo(); 0216 } 0217 } 0218 } 0219 m_sheet->map()->addDamage(new CellDamage(m_sheet, *this, CellDamage::Appearance)); 0220 return true; 0221 }