File indexing completed on 2024-05-12 16:35:42
0001 /* This file is part of the KDE project 0002 Copyright 2009 Thomas Zander <zander@kde.org> 0003 Copyright 2006-2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0004 Copyright 2006 Robert Knight <robertknight@gmail.com> 0005 Copyright 2006 Inge Wallin <inge@lysator.liu.se> 0006 Copyright 1999-2002,2004 Laurent Montel <montel@kde.org> 0007 Copyright 2002-2005 Ariya Hidayat <ariya@kde.org> 0008 Copyright 1999-2004 David Faure <faure@kde.org> 0009 Copyright 2004-2005 Meni Livne <livne@kde.org> 0010 Copyright 2001-2003 Philipp Mueller <philipp.mueller@gmx.de> 0011 Copyright 2002-2003 Norbert Andres <nandres@web.de> 0012 Copyright 2003 Hamish Rodda <rodda@kde.org> 0013 Copyright 2003 Joseph Wenninger <jowenn@kde.org> 0014 Copyright 2003 Lukas Tinkl <lukas@kde.org> 0015 Copyright 2000-2002 Werner Trobin <trobin@kde.org> 0016 Copyright 2002 Harri Porten <porten@kde.org> 0017 Copyright 2002 John Dailey <dailey@vt.edu> 0018 Copyright 2002 Daniel Naber <daniel.naber@t-online.de> 0019 Copyright 1999-2000 Torben Weis <weis@kde.org> 0020 Copyright 1999-2000 Stephan Kulow <coolo@kde.org> 0021 Copyright 2000 Bernd Wuebben <wuebben@kde.org> 0022 Copyright 2000 Wilco Greven <greven@kde.org> 0023 Copyright 2000 Simon Hausmann <hausmann@kde.org 0024 Copyright 1999 Michael Reiher <michael.reiher@gmx.de> 0025 Copyright 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at> 0026 Copyright 1999 Reginald Stadlbauer <reggie@kde.org> 0027 0028 This library is free software; you can redistribute it and/or 0029 modify it under the terms of the GNU Library General Public 0030 License as published by the Free Software Foundation; either 0031 version 2 of the License, or (at your option) any later version. 0032 0033 This library is distributed in the hope that it will be useful, 0034 but WITHOUT ANY WARRANTY; without even the implied warranty of 0035 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0036 Library General Public License for more details. 0037 0038 You should have received a copy of the GNU Library General Public License 0039 along with this library; see the file COPYING.LIB. If not, write to 0040 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0041 Boston, MA 02110-1301, USA. 0042 */ 0043 0044 // Local 0045 #include "Canvas.h" 0046 #include "CanvasBase_p.h" 0047 0048 // std 0049 #include <assert.h> 0050 #include <float.h> 0051 #include <stdlib.h> 0052 0053 // Qt 0054 #include <QApplication> 0055 #include <QBuffer> 0056 #include <QByteArray> 0057 #include <QClipboard> 0058 #include <QDragLeaveEvent> 0059 #include <QDragMoveEvent> 0060 #include <QDropEvent> 0061 #include <QEvent> 0062 #include <QFocusEvent> 0063 #include <QKeyEvent> 0064 #include <QLabel> 0065 #include <QList> 0066 #include <QMenu> 0067 #include <QMouseEvent> 0068 #include <QPainter> 0069 #include <QPaintEvent> 0070 #include <QPixmap> 0071 #include <QPoint> 0072 #include <QScrollBar> 0073 #include <QTextStream> 0074 #include <QToolTip> 0075 #include <QWidget> 0076 0077 // KF5 0078 #include <kxmlguifactory.h> 0079 0080 // Calligra 0081 #include <KoCanvasController.h> 0082 #include <KoShapeManager.h> 0083 #include <KoToolManager.h> 0084 #include <KoToolProxy.h> 0085 #include <KoZoomHandler.h> 0086 #include <KoPointerEvent.h> 0087 0088 // Sheets 0089 #include "SheetsDebug.h" 0090 #include "CellStorage.h" 0091 #include "Doc.h" 0092 #include "Global.h" 0093 #include "HeaderWidgets.h" 0094 #include "Localization.h" 0095 #include "Map.h" 0096 #include "RowColumnFormat.h" 0097 #include "Sheet.h" 0098 #include "Util.h" 0099 #include "Validity.h" 0100 #include "View.h" 0101 0102 // commands 0103 #include "commands/CopyCommand.h" 0104 #include "commands/DeleteCommand.h" 0105 #include "commands/PasteCommand.h" 0106 #include "commands/StyleCommand.h" 0107 0108 // ui 0109 #include "ui/CellView.h" 0110 #include "ui/Selection.h" 0111 #include "ui/SheetView.h" 0112 0113 #define MIN_SIZE 10 0114 0115 using namespace Calligra::Sheets; 0116 0117 class Q_DECL_HIDDEN Canvas::Private 0118 { 0119 public: 0120 View *view; 0121 }; 0122 0123 /**************************************************************** 0124 * 0125 * Canvas 0126 * 0127 ****************************************************************/ 0128 0129 Canvas::Canvas(View *view) 0130 : QWidget(view) 0131 , CanvasBase(view ? view->doc() : 0) 0132 , cd(new Private) 0133 { 0134 cd->view = view; 0135 0136 setAttribute(Qt::WA_OpaquePaintEvent); 0137 setAttribute(Qt::WA_StaticContents); 0138 setBackgroundRole(QPalette::Base); 0139 QWidget::setFocusPolicy(Qt::StrongFocus); 0140 setMouseTracking(true); 0141 0142 installEventFilter(this); // for TAB key processing, otherwise focus change 0143 setAcceptDrops(true); 0144 setAttribute(Qt::WA_InputMethodEnabled, true); // ensure using the InputMethod 0145 } 0146 0147 Canvas::~Canvas() 0148 { 0149 foreach (QAction* action, actions()) { 0150 removeAction(action); 0151 } 0152 0153 delete cd; 0154 } 0155 0156 View* Canvas::view() const 0157 { 0158 return cd->view; 0159 } 0160 0161 void Canvas::mousePressEvent(QMouseEvent* event) 0162 { 0163 //KoPointerEvent pev(event, QPointF()); 0164 //mousePressed(&pev); 0165 0166 QMouseEvent *const origEvent = event; 0167 QPointF documentPosition; 0168 if (layoutDirection() == Qt::LeftToRight) { 0169 documentPosition = viewConverter()->viewToDocument(event->pos()) + offset(); 0170 } else { 0171 const QPoint position(QWidget::width() - event->x(), event->y()); 0172 const QPointF offset(this->offset().x(), this->offset().y()); 0173 documentPosition = viewConverter()->viewToDocument(position) + offset; 0174 debugSheets << "----------------------------"; 0175 debugSheets << "event->pos():" << event->pos(); 0176 debugSheets << "event->globalPos():" << event->globalPos(); 0177 debugSheets << "position:" << position; 0178 debugSheets << "offset:" << offset; 0179 debugSheets << "documentPosition:" << documentPosition; 0180 event = new QMouseEvent(QEvent::MouseButtonPress, position, mapToGlobal(position), event->button(), event->buttons(), event->modifiers()); 0181 debugSheets << "newEvent->pos():" << event->pos(); 0182 debugSheets << "newEvent->globalPos():" << event->globalPos(); 0183 } 0184 0185 #if 0 // This is disabled for now as per irc, as it blocks resize. 0186 // If the celltool is not active and we initiate a click on something that is not a flake element, we need 0187 // to reactivate the cell tool. THis is a temporary solution, pending the flake updates. 0188 if (KoToolManager::instance()->activeToolId() != "KSpreadCellToolId") 0189 if (!shapeManager()->shapeAt (documentPosition, KoFlake::ShapeOnTop)) 0190 KoToolManager::instance()->switchToolRequested("KSpreadCellToolId"); 0191 #endif 0192 0193 // flake 0194 if(d->toolProxy) { 0195 d->toolProxy->mousePressEvent(event, documentPosition); 0196 0197 if (!event->isAccepted() && event->button() == Qt::RightButton) { 0198 showContextMenu(origEvent->globalPos()); 0199 origEvent->setAccepted(true); 0200 } 0201 } 0202 if (layoutDirection() == Qt::RightToLeft) { 0203 delete event; 0204 } 0205 } 0206 0207 void Canvas::showContextMenu(const QPoint& globalPos) 0208 { 0209 view()->unplugActionList("toolproxy_action_list"); 0210 view()->plugActionList("toolproxy_action_list", toolProxy()->popupActionList()); 0211 if (KXMLGUIFactory *factory = view()->factory()) { 0212 QMenu* menu = dynamic_cast<QMenu*>(factory->container("default_canvas_popup", view())); 0213 // Only show the menu, if there are items. The plugged action list counts as one action. 0214 if (menu && menu->actions().count() > 1) { 0215 menu->exec(globalPos); 0216 } 0217 } 0218 } 0219 0220 void Canvas::mouseReleaseEvent(QMouseEvent* event) 0221 { 0222 // KoPointerEvent pev(event, QPointF()); 0223 // mouseReleased(&pev); 0224 0225 QPointF documentPosition; 0226 if (layoutDirection() == Qt::LeftToRight) { 0227 documentPosition = viewConverter()->viewToDocument(event->pos()) + offset(); 0228 } else { 0229 const QPoint position(QWidget::width() - event->x(), event->y()); 0230 const QPointF offset(this->offset().x(), this->offset().y()); 0231 documentPosition = viewConverter()->viewToDocument(position) + offset; 0232 event = new QMouseEvent(QEvent::MouseButtonRelease, position, mapToGlobal(position), event->button(), event->buttons(), event->modifiers()); 0233 } 0234 0235 // flake 0236 if(d->toolProxy) 0237 d->toolProxy->mouseReleaseEvent(event, documentPosition); 0238 0239 if (layoutDirection() == Qt::RightToLeft) { 0240 delete event; 0241 } 0242 } 0243 0244 void Canvas::mouseMoveEvent(QMouseEvent* event) 0245 { 0246 // KoPointerEvent pev(event, QPointF()); 0247 // mouseMoved(&pev); 0248 0249 QPointF documentPosition; 0250 if (layoutDirection() == Qt::LeftToRight) { 0251 documentPosition = viewConverter()->viewToDocument(event->pos()) + offset(); 0252 } else { 0253 const QPoint position(QWidget::width() - event->x(), event->y()); 0254 const QPointF offset(this->offset().x(), this->offset().y()); 0255 documentPosition = viewConverter()->viewToDocument(position) + offset; 0256 event = new QMouseEvent(QEvent::MouseMove, position, mapToGlobal(position), event->button(), event->buttons(), event->modifiers()); 0257 } 0258 0259 // flake 0260 if(d->toolProxy) 0261 d->toolProxy->mouseMoveEvent(event, documentPosition); 0262 0263 if (layoutDirection() == Qt::RightToLeft) { 0264 delete event; 0265 } 0266 } 0267 0268 void Canvas::mouseDoubleClickEvent(QMouseEvent* event) 0269 { 0270 // KoPointerEvent pev(event, QPointF()); 0271 // mouseDoubleClicked(&pev); 0272 0273 QPointF documentPosition; 0274 if (layoutDirection() == Qt::LeftToRight) { 0275 documentPosition = viewConverter()->viewToDocument(event->pos()) + offset(); 0276 } else { 0277 const QPoint position(QWidget::width() - event->x(), event->y()); 0278 const QPointF offset(this->offset().x(), this->offset().y()); 0279 documentPosition = viewConverter()->viewToDocument(position) + offset; 0280 event = new QMouseEvent(QEvent::MouseButtonDblClick, position, mapToGlobal(position), event->button(), event->buttons(), event->modifiers()); 0281 } 0282 0283 // flake 0284 if (d->toolProxy) { 0285 // If the celltool is not active and the double click is on something that is not a flake element, we need 0286 // to reactivate the cell tool. Normally flake would handle this, but the main app is not a shape, so we have to. 0287 // TODO: figure out a way to make the flake's functionality work. It'd likely require turning the main app 0288 // widget into a KoShape or something along those lines. 0289 if (KoToolManager::instance()->activeToolId() != "KSpreadCellToolId") { 0290 if (!shapeManager()->shapeAt (documentPosition, KoFlake::ShapeOnTop)) { 0291 KoToolManager::instance()->switchToolRequested("KSpreadCellToolId"); 0292 return; 0293 } 0294 } 0295 0296 d->toolProxy->mouseDoubleClickEvent(event, documentPosition); 0297 } 0298 0299 if (layoutDirection() == Qt::RightToLeft) { 0300 // delete event; 0301 } 0302 0303 } 0304 0305 bool Canvas::event(QEvent *e) 0306 { 0307 if(toolProxy()) { 0308 toolProxy()->processEvent(e); 0309 } 0310 return QWidget::event(e); 0311 } 0312 0313 void Canvas::paintEvent(QPaintEvent* event) 0314 { 0315 QPainter painter(this); 0316 paint(&painter, event->rect()); 0317 event->accept(); 0318 } 0319 0320 void Canvas::dragEnterEvent(QDragEnterEvent* event) 0321 { 0322 if (CanvasBase::dragEnter(event->mimeData())) { 0323 event->acceptProposedAction(); 0324 } 0325 } 0326 0327 void Canvas::dragMoveEvent(QDragMoveEvent* event) 0328 { 0329 if (CanvasBase::dragMove(event->mimeData(), event->pos(), event->source())) { 0330 event->acceptProposedAction(); 0331 } else { 0332 event->ignore(); 0333 } 0334 } 0335 0336 void Canvas::dragLeaveEvent(QDragLeaveEvent*) 0337 { 0338 CanvasBase::dragLeave(); 0339 } 0340 0341 void Canvas::dropEvent(QDropEvent *event) 0342 { 0343 if (CanvasBase::drop(event->mimeData(), event->pos(), event->source())) { 0344 event->setAccepted(true); 0345 } else { 0346 event->ignore(); 0347 } 0348 } 0349 0350 void Canvas::setVertScrollBarPos(qreal pos) 0351 { 0352 if (pos < 0) pos = view()->vertScrollBar()->maximum() - pos; 0353 view()->vertScrollBar()->setValue((int)pos); 0354 } 0355 0356 void Canvas::setHorizScrollBarPos(qreal pos) 0357 { 0358 if (pos < 0) pos = view()->horzScrollBar()->maximum() - pos; 0359 view()->horzScrollBar()->setValue((int)pos); 0360 } 0361 0362 KoZoomHandler* Canvas::zoomHandler() const 0363 { 0364 return view()->zoomHandler(); 0365 } 0366 0367 Sheet* Canvas::activeSheet() const 0368 { 0369 return view()->activeSheet(); 0370 } 0371 0372 bool Canvas::isViewLoading() const 0373 { 0374 return view()->isLoading(); 0375 } 0376 0377 SheetView* Canvas::sheetView(const Sheet* sheet) const 0378 { 0379 return view()->sheetView(sheet); 0380 } 0381 0382 Calligra::Sheets::Selection* Canvas::selection() const 0383 { 0384 return view()->selection(); 0385 } 0386 0387 ColumnHeader* Canvas::columnHeader() const 0388 { 0389 return view()->columnHeader(); 0390 } 0391 0392 RowHeader* Canvas::rowHeader() const 0393 { 0394 return view()->rowHeader(); 0395 } 0396 0397 void Canvas::enableAutoScroll() 0398 { 0399 view()->enableAutoScroll(); 0400 } 0401 0402 void Canvas::disableAutoScroll() 0403 { 0404 view()->disableAutoScroll(); 0405 } 0406 0407 void Canvas::setCursor(const QCursor &cursor) 0408 { 0409 QWidget::setCursor(cursor); 0410 }