1 /* This file is part of the KDE project 2 * Copyright (C) 2006 Thomas Zander <zander@kde.org> 3 * Copyright (C) 2011 Jan Hambrecht <jaham@gmx.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 #ifndef KOTOOLBASE_H 21 #define KOTOOLBASE_H 22 23 #include <QObject> 24 #include <QPointer> 25 #include <QSet> 26 #include <QList> 27 #include <QHash> 28 29 #include "flake_export.h" 30 31 class KoShape; 32 class KoCanvasBase; 33 class KoPointerEvent; 34 class KoViewConverter; 35 class KoToolSelection; 36 class KoToolBasePrivate; 37 class KoShapeBasedDocumentBase; 38 39 class QAction; 40 class QAction; 41 class QKeyEvent; 42 class QWidget; 43 class QCursor; 44 class QPainter; 45 class QString; 46 class QStringList; 47 class QRectF; 48 class QPointF; 49 class QInputMethodEvent; 50 class QDragMoveEvent; 51 class QDragLeaveEvent; 52 class QDropEvent; 53 class QTouchEvent; 54 55 /** 56 * Abstract base class for all tools. Tools can create or manipulate 57 * flake shapes, canvas state or any other thing that a user may wish 58 * to do to his document or his view on a document with a pointing 59 * device. 60 * 61 * There exists an instance of every tool for every pointer device. 62 * These instances are managed by the toolmanager.. 63 */ 64 class FLAKE_EXPORT KoToolBase : public QObject 65 { 66 Q_OBJECT 67 public: 68 /// Option for activate() 69 enum ToolActivation { 70 TemporaryActivation, ///< The tool is activated temporarily and works 'in-place' of another one. 71 DefaultActivation ///< The tool is activated normally and emitting 'done' goes to the defaultTool 72 }; 73 74 /** 75 * Constructor, normally only called by the factory (see KoToolFactoryBase) 76 * @param canvas the canvas interface this tool will work for. 77 */ 78 explicit KoToolBase(KoCanvasBase *canvas); 79 ~KoToolBase() override; 80 81 /** 82 * connect the tool to the new shapecontroller. Old connections are removed. 83 * 84 * @param shapeController the new shape controller 85 */ 86 void updateShapeController(KoShapeBasedDocumentBase *shapeController); 87 88 /** 89 * request a repaint of the decorations to be made. This triggers 90 * an update call on the canvas, but does not paint directly. 91 */ 92 virtual void repaintDecorations(); 93 94 /** 95 * Return if dragging (moving with the mouse down) to the edge of a canvas should scroll the 96 * canvas (default is true). 97 * @return if this tool wants mouse events to cause scrolling of canvas. 98 */ 99 virtual bool wantsAutoScroll() const; 100 101 /** 102 * Called by the canvas to paint any decorations that the tool deems needed. 103 * The painter has the top left of the canvas as its origin. 104 * @param painter used for painting the shape 105 * @param converter to convert between internal and view coordinates. 106 */ 107 virtual void paint(QPainter &painter, const KoViewConverter &converter) = 0; 108 109 /** 110 * Return the option widgets for this tool. Create them if they 111 * do not exist yet. If the tool does not have an option widget, 112 * this method return an empty list. (After discussion with Thomas, who prefers 113 * the toolmanager to handle that case.) 114 * 115 * @see m_optionWidgets 116 */ 117 QList<QPointer<QWidget> > optionWidgets(); 118 119 /** 120 * Retrieves the entire collection of actions for the tool. 121 */ 122 QHash<QString, QAction *> actions() const; 123 124 /** 125 * Retrieve an action by name. 126 */ 127 QAction *action(const QString &name) const; 128 129 /** 130 * Called when (one of) the mouse or stylus buttons is pressed. 131 * Implementors should call event->ignore() if they do not actually use the event. 132 * @param event state and reason of this mouse or stylus press 133 */ 134 virtual void mousePressEvent(KoPointerEvent *event) = 0; 135 136 /** 137 * Called when (one of) the mouse or stylus buttons is double clicked. 138 * Implementors should call event->ignore() if they do not actually use the event. 139 * Default implementation ignores this event. 140 * @param event state and reason of this mouse or stylus press 141 */ 142 virtual void mouseDoubleClickEvent(KoPointerEvent *event); 143 144 /** 145 * Called when (one of) the mouse or stylus buttons is triple clicked. 146 * Implementors should call event->ignore() if they do not actually use the event. 147 * Default implementation ignores this event. 148 * @param event state and reason of this mouse or stylus press 149 */ 150 virtual void mouseTripleClickEvent(KoPointerEvent *event); 151 152 /** 153 * Called when the mouse or stylus moved over the canvas. 154 * Implementors should call event->ignore() if they do not actually use the event. 155 * @param event state and reason of this mouse or stylus move 156 */ 157 virtual void mouseMoveEvent(KoPointerEvent *event) = 0; 158 159 /** 160 * Called when (one of) the mouse or stylus buttons is released. 161 * Implementors should call event->ignore() if they do not actually use the event. 162 * @param event state and reason of this mouse or stylus release 163 */ 164 virtual void mouseReleaseEvent(KoPointerEvent *event) = 0; 165 166 /** 167 * Called when a key is pressed, before shortcuts are triggered. 168 * Implementors should call event->accept() if they do want this shortcut to 169 * be handled by keyPressEvent rather than by a more global shortcut. 170 * Default implementation ignores this event. 171 * @param event state and reason of this key press 172 */ 173 virtual void shortcutOverrideEvent(QKeyEvent *event); 174 175 /** 176 * Called when a key is pressed. 177 * Implementors should call event->ignore() if they do not actually use the event. 178 * Default implementation ignores this event. 179 * @param event state and reason of this key press 180 */ 181 virtual void keyPressEvent(QKeyEvent *event); 182 183 /** 184 * Called when a key is released 185 * Implementors should call event->ignore() if they do not actually use the event. 186 * Default implementation ignores this event. 187 * @param event state and reason of this key release 188 */ 189 virtual void keyReleaseEvent(QKeyEvent *event); 190 191 /** 192 * Called when the scrollwheel is used 193 * Implementors should call event->ignore() if they do not actually use the event 194 * @param event state of this wheel event 195 */ 196 virtual void wheelEvent(KoPointerEvent *event); 197 198 virtual void touchEvent(QTouchEvent *event); 199 200 /** 201 * This method is used to query a set of properties of the tool to be 202 * able to support complex input method operations as support for surrounding 203 * text and reconversions. 204 * Default implementation returns simple defaults, for tools that want to provide 205 * a more responsive text entry experience for CJK languages it would be good to reimplemnt. 206 * @param query specifies which property is queried. 207 * @param converter the view converter for the current canvas. 208 */ 209 virtual QVariant inputMethodQuery(Qt::InputMethodQuery query, const KoViewConverter &converter) const; 210 211 /** 212 * Text entry of complex text, like CJK, can be made more interactive if a tool 213 * implements this and the InputMethodQuery() methods. 214 * Reimplementing this only provides the user with a more responsive text experience, since the 215 * default implementation forwards the typed text as key pressed events. 216 * @param event the input method event. 217 */ 218 virtual void inputMethodEvent(QInputMethodEvent *event); 219 220 /** 221 * Called when (one of) a custom device buttons is pressed. 222 * Implementors should call event->ignore() if they do not actually use the event. 223 * @param event state and reason of this custom device press 224 */ 225 virtual void customPressEvent(KoPointerEvent *event); 226 227 /** 228 * Called when (one of) a custom device buttons is released. 229 * Implementors should call event->ignore() if they do not actually use the event. 230 * @param event state and reason of this custom device release 231 */ 232 virtual void customReleaseEvent(KoPointerEvent *event); 233 234 /** 235 * Called when a custom device moved over the canvas. 236 * Implementors should call event->ignore() if they do not actually use the event. 237 * @param event state and reason of this custom device move 238 */ 239 virtual void customMoveEvent(KoPointerEvent *event); 240 241 virtual bool wantsTouch() const; 242 243 /** 244 * Set the identifier code from the KoToolFactoryBase that created this tool. 245 * @param id the identifier code 246 * @see KoToolFactoryBase::id() 247 */ 248 void setToolId(const QString &id); 249 250 /** 251 * get the identifier code from the KoToolFactoryBase that created this tool. 252 * @return the toolId. 253 * @see KoToolFactoryBase::id() 254 */ 255 Q_INVOKABLE QString toolId() const; 256 257 /// return the last emitted cursor 258 QCursor cursor() const; 259 260 /** 261 * Returns the internal selection object of this tool. 262 * Each tool can have a selection which is private to that tool and the specified shape that it comes with. 263 * The default returns 0. 264 */ 265 virtual KoToolSelection *selection(); 266 267 /** 268 * @returns true if the tool has selected data. 269 */ 270 virtual bool hasSelection(); 271 272 /** 273 * copies the tools selection to the clipboard. 274 * The default implementation is empty to aid tools that don't have any selection. 275 * @see selection() 276 */ 277 virtual void copy() const; 278 279 /** 280 * Delete the tools selection. 281 * The default implementation is empty to aid tools that don't have any selection. 282 * @see selection() 283 */ 284 virtual void deleteSelection(); 285 286 /** 287 * Cut the tools selection and copy it to the clipboard. 288 * The default implementation calls copy() and then deleteSelection() 289 * @see copy() 290 * @see deleteSelection() 291 */ 292 virtual void cut(); 293 294 /** 295 * Paste the clipboard selection. 296 * A tool typically has one or more shapes selected and pasting should do something meaningful 297 * for this specific shape and tool combination. Inserting text in a text tool, for example. 298 * If you reimplement this function make sure to also reimplement supportedPasteMimeTypes(). 299 * @return will return true if pasting succeeded. False if nothing happened. 300 */ 301 virtual bool paste(); 302 303 /** 304 * Returns the mimetypes that this tool's paste() function can handle 305 * @return QStringList containing the mimetypes that's supported by paste() 306 */ 307 virtual QStringList supportedPasteMimeTypes() const; 308 309 /** 310 * Handle the dragMoveEvent 311 * A tool typically has one or more shapes selected and dropping into should do 312 * something meaningful for this specific shape and tool combination. For example 313 * dropping text in a text tool. 314 * The tool should Accept the event if it is meaningful; Default implementation does not. 315 */ 316 virtual void dragMoveEvent(QDragMoveEvent *event, const QPointF &point); 317 318 /** 319 * Handle the dragLeaveEvent 320 * Basically just a notification that the drag is no long relevant 321 * The tool should Accept the event if it is meaningful; Default implementation does not. 322 */ 323 virtual void dragLeaveEvent(QDragLeaveEvent *event); 324 325 /** 326 * Handle the dropEvent 327 * A tool typically has one or more shapes selected and dropping into should do 328 * something meaningful for this specific shape and tool combination. For example 329 * dropping text in a text tool. 330 * The tool should Accept the event if it is meaningful; Default implementation does not. 331 */ 332 virtual void dropEvent(QDropEvent *event, const QPointF &point); 333 334 /** 335 * @return A list of actions to be used for a popup. 336 */ 337 QList<QAction*> popupActionList() const; 338 339 /// Returns the canvas the tool is working on 340 KoCanvasBase *canvas() const; 341 342 /** 343 * This method can be reimplemented in a subclass. 344 * @return returns true, if the tool is in text mode. that means, that there is 345 * any kind of textual input and all single key shortcuts should be eaten. 346 */ 347 bool isInTextMode() const; 348 349 public Q_SLOTS: 350 351 /** 352 * This method is called when this tool instance is activated. 353 * For any main window there is only one tool active at a time, which then gets all 354 * user input. Switching between tools will call deactivate on one and activate on the 355 * new tool allowing the tool to flush items (like a selection) 356 * when it is not in use. 357 * 358 * <p>There is one case where two tools are activated at the same. This is the case 359 * where one tool delegates work to another temporarily. For example, while shift is 360 * being held down. The second tool will get activated with temporary=true and 361 * it should emit done() when the state that activated it is ended. 362 * <p>One of the important tasks of activate is to call useCursor() 363 * 364 * @param shapes the set of shapes that are selected or suggested for editing by a 365 * selected shape for the tool to work on. Not all shapes will be meant for this 366 * tool. 367 * @param toolActivation if TemporaryActivation, this tool is only temporarily activated 368 * and should emit done when it is done. 369 * @see deactivate() 370 */ 371 virtual void activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes) = 0; 372 373 /** 374 * This method is called whenever this tool is no longer the 375 * active tool 376 * @see activate() 377 */ 378 virtual void deactivate(); 379 380 /** 381 * This method is called whenever a property in the resource 382 * provider associated with the canvas this tool belongs to 383 * changes. An example is currently selected foreground color. 384 */ 385 virtual void canvasResourceChanged(int key, const QVariant &res); 386 387 /** 388 * This method is called whenever a property in the resource 389 * provider associated with the document this tool belongs to 390 * changes. An example is the handle radius 391 */ 392 virtual void documentResourceChanged(int key, const QVariant &res); 393 394 /** 395 * This method just relays the given text via the tools statusTextChanged signal. 396 * @param statusText the new status text 397 */ 398 void setStatusText(const QString &statusText); 399 400 Q_SIGNALS: 401 402 /** 403 * Emitted when this tool wants itself to be replaced by another tool. 404 * 405 * @param id the identification of the desired tool 406 * @see toolId(), KoToolFactoryBase::id() 407 */ 408 void activateTool(const QString &id); 409 410 /** 411 * Emitted when this tool wants itself to temporarily be replaced by another tool. 412 * For instance, a paint tool could desire to be 413 * temporarily replaced by a pan tool which could be temporarily 414 * replaced by a colorpicker. 415 * @param id the identification of the desired tool 416 */ 417 void activateTemporary(const QString &id); 418 419 /** 420 * Emitted when the tool has been temporarily activated and wants 421 * to notify the world that it's done. 422 */ 423 void done(); 424 425 /** 426 * Emitted by useCursor() when the cursor to display on the canvas is changed. 427 * The KoToolManager should connect to this signal to handle cursors further. 428 */ 429 void cursorChanged(const QCursor &cursor); 430 431 /** 432 * A tool can have a selection that is copy-able, this signal is emitted when that status changes. 433 * @param hasSelection is true when the tool holds selected data. 434 */ 435 void selectionChanged(bool hasSelection); 436 437 /** 438 * Emitted when the tool wants to display a different status text 439 * @param statusText the new status text 440 */ 441 void statusTextChanged(const QString &statusText); 442 443 protected: 444 /** 445 * Classes inheriting from this one can call this method to signify which cursor 446 * the tool wants to display at this time. Logical place to call it is after an 447 * incoming event has been handled. 448 * @param cursor the new cursor. 449 */ 450 void useCursor(const QCursor &cursor); 451 452 /** 453 * Reimplement this if your tool actually has an option widget. 454 * Sets the option widget to 0 by default. 455 */ 456 virtual QWidget *createOptionWidget(); 457 virtual QList<QPointer<QWidget> > createOptionWidgets(); 458 459 /** 460 * Add an action under the given name to the collection. 461 * 462 * Inserting an action under a name that is already used for another action will replace 463 * the other action in the collection. 464 * 465 * @param name The name by which the action be retrieved again from the collection. 466 * @param action The action to add. 467 */ 468 void addAction(const QString &name, QAction *action); 469 470 /** 471 * Set the list of actions to be used as popup menu. 472 * @param list the list of actions. 473 * @see popupActionList 474 */ 475 void setPopupActionList(const QList<QAction*> &list); 476 477 /// Convenience function to get the current handle radius 478 uint handleRadius() const; 479 480 /// Convenience function to get the current grab sensitivity 481 uint grabSensitivity() const; 482 483 /** 484 * Returns a handle grab rect at the given position. 485 * 486 * The position is expected to be in document coordinates. The grab sensitivity 487 * canvas resource is used for the dimension of the rectangle. 488 * 489 * @return the handle rectangle in document coordinates 490 */ 491 QRectF handleGrabRect(const QPointF &position) const; 492 493 /** 494 * Returns a handle paint rect at the given position. 495 * 496 * The position is expected to be in document coordinates. The handle radius 497 * canvas resource is used for the dimension of the rectangle. 498 * 499 * @return the handle rectangle in document coordinates 500 */ 501 QRectF handlePaintRect(const QPointF &position) const; 502 503 /** 504 * You should set the text mode to true in subclasses, if this tool is in text input mode, eg if the users 505 * are able to type. If you don't set it, then single key shortcuts will get the key event and not this tool. 506 */ 507 void setTextMode(bool value); 508 509 protected: 510 KoToolBase(KoToolBasePrivate &dd); 511 512 KoToolBasePrivate *d_ptr; 513 514 515 private: 516 KoToolBase(); 517 KoToolBase(const KoToolBase&); 518 KoToolBase& operator=(const KoToolBase&); 519 520 Q_DECLARE_PRIVATE(KoToolBase) 521 }; 522 523 #endif /* KOTOOL_H */ 524