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