File indexing completed on 2024-05-12 16:36:01

0001 /* This file is part of the KDE project
0002    Copyright 2008 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 #include "AbstractSelectionStrategy.h"
0021 
0022 #include "CellToolBase.h"
0023 #include "calligra_sheets_limits.h"
0024 #include "RowColumnFormat.h"
0025 #include "RowFormatStorage.h"
0026 #include "Selection.h"
0027 #include "Sheet.h"
0028 
0029 #include <KoCanvasBase.h>
0030 #include <KoSelection.h>
0031 #include <KoShapeManager.h>
0032 #include <KoViewConverter.h>
0033 
0034 using namespace Calligra::Sheets;
0035 
0036 class AbstractSelectionStrategy::Private
0037 {
0038 public:
0039     CellToolBase *cellTool;
0040     QPointF start;
0041 };
0042 
0043 AbstractSelectionStrategy::AbstractSelectionStrategy(CellToolBase *cellTool,
0044         const QPointF &documentPos, Qt::KeyboardModifiers modifiers)
0045         : KoInteractionStrategy(cellTool)
0046         , d(new Private)
0047 {
0048     Q_UNUSED(modifiers)
0049     d->cellTool = cellTool;
0050     d->start = documentPos;
0051 }
0052 
0053 AbstractSelectionStrategy::~AbstractSelectionStrategy()
0054 {
0055     delete d;
0056 }
0057 
0058 void AbstractSelectionStrategy::handleMouseMove(const QPointF& documentPos, Qt::KeyboardModifiers modifiers)
0059 {
0060     Q_UNUSED(modifiers)
0061     Selection *const selection = d->cellTool->selection();
0062     const QPointF position = documentPos - cellTool()->offset();
0063     // In which cell did the user click?
0064     qreal xpos;
0065     qreal ypos;
0066     int col = selection->activeSheet()->leftColumn(position.x(), xpos);
0067     int row = selection->activeSheet()->topRow(position.y(), ypos);
0068     // Check boundaries.
0069     if (col < 1 || col > KS_colMax || row < 1 || row > KS_rowMax) {
0070         debugSheetsUI << "col or row is out of range:" << "col:" << col << " row:" << row;
0071         return;
0072     }
0073     // Test whether mouse is over the Selection.handle
0074     if (hitTestSelectionSizeGrip(tool()->canvas(), selection, position)) {
0075         // If the cursor is over the handle, than it might be already on the next cell.
0076         // Recalculate the cell position!
0077         col = selection->activeSheet()->leftColumn(position.x() - tool()->canvas()->viewConverter()->viewToDocumentX(2.0), xpos);
0078         row = selection->activeSheet()->topRow(position.y() - tool()->canvas()->viewConverter()->viewToDocumentY(2.0), ypos);
0079     }
0080     // Update the selection.
0081     selection->update(QPoint(col, row));
0082     tool()->repaintDecorations();
0083 }
0084 
0085 KUndo2Command* AbstractSelectionStrategy::createCommand()
0086 {
0087     return 0;
0088 }
0089 
0090 void AbstractSelectionStrategy::finishInteraction(Qt::KeyboardModifiers modifiers)
0091 {
0092     Q_UNUSED(modifiers)
0093     tool()->repaintDecorations();
0094 }
0095 
0096 // static
0097 bool AbstractSelectionStrategy::hitTestSelectionSizeGrip(KoCanvasBase *canvas,
0098         Selection *selection,
0099         const QPointF &position)
0100 {
0101     if (selection->referenceSelectionMode() || !selection->isValid()) {
0102         return false;
0103     }
0104 
0105     // Define the (normal) selection size grip.
0106     const qreal pixelX = canvas->viewConverter()->viewToDocumentX(1);
0107     const qreal pixelY = canvas->viewConverter()->viewToDocumentY(1);
0108     const QRectF gripArea(-2 * pixelX, -2 * pixelY, 5 * pixelX, 5 * pixelY);
0109 
0110     Sheet *const sheet = selection->activeSheet();
0111 
0112     int column, row;
0113     if (selection->isColumnOrRowSelected()) {
0114         // complete rows/columns are selected, use the marker.
0115         const QPoint marker = selection->marker();
0116         column = marker.x();
0117         row = marker.y();
0118     } else {
0119         const QRect range = selection->lastRange();
0120         column = range.right();
0121         row = range.bottom();
0122     }
0123 
0124     const double xpos = sheet->columnPosition(column);
0125     const double ypos = sheet->rowPosition(row);
0126     const double width = sheet->columnFormat(column)->width();
0127     const double height = sheet->rowFormats()->rowHeight(row);
0128     return gripArea.translated(xpos + width, ypos + height).contains(position);
0129 }
0130 
0131 // static
0132 bool AbstractSelectionStrategy::hitTestReferenceSizeGrip(KoCanvasBase *canvas,
0133         Selection *selection,
0134         const QPointF &position)
0135 {
0136     if (!selection->referenceSelectionMode() || !selection->isValid()) {
0137         return false;
0138     }
0139 
0140     // Define the reference selection size grip.
0141     const qreal pixelX = canvas->viewConverter()->viewToDocumentX(1);
0142     const qreal pixelY = canvas->viewConverter()->viewToDocumentY(1);
0143     const QRectF gripArea(-3 * pixelX, -3 * pixelY, 6 * pixelX, 6 * pixelY);
0144 
0145     // Iterate over the referenced ranges.
0146     const Region::ConstIterator end(selection->constEnd());
0147     for (Region::ConstIterator it(selection->constBegin()); it != end; ++it) {
0148         Sheet *const sheet = (*it)->sheet();
0149         // Only check the ranges on the active sheet.
0150         if (sheet != selection->activeSheet()) {
0151             continue;
0152         }
0153         const QRect range = (*it)->rect();
0154         const QRectF area = sheet->cellCoordinatesToDocument(range);
0155         const QPointF corner(area.bottomRight());
0156         if (gripArea.translated(corner).contains(position)) {
0157             return true;
0158         }
0159     }
0160     return false;
0161 }
0162 
0163 CellToolBase *AbstractSelectionStrategy::cellTool() const
0164 {
0165     return d->cellTool;
0166 }
0167 
0168 Selection* AbstractSelectionStrategy::selection() const
0169 {
0170     return d->cellTool->selection();
0171 }
0172 
0173 const QPointF& AbstractSelectionStrategy::startPosition() const
0174 {
0175     return d->start;
0176 }