1 /* This file is part of the KDE project
2 
3    Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
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 
21 #include "KoInteractionTool.h"
22 #include "KoInteractionTool_p.h"
23 #include "KoToolBase_p.h"
24 #include "KoPointerEvent.h"
25 #include "KoCanvasBase.h"
26 
27 #include "kis_global.h"
28 #include "kis_assert.h"
29 
30 
KoInteractionTool(KoCanvasBase * canvas)31 KoInteractionTool::KoInteractionTool(KoCanvasBase *canvas)
32     : KoToolBase(*(new KoInteractionToolPrivate(this, canvas)))
33 {
34 }
35 
~KoInteractionTool()36 KoInteractionTool::~KoInteractionTool()
37 {
38 }
39 
paint(QPainter & painter,const KoViewConverter & converter)40 void KoInteractionTool::paint(QPainter &painter, const KoViewConverter &converter)
41 {
42     Q_D(KoInteractionTool);
43 
44     if (d->currentStrategy) {
45         d->currentStrategy->paint(painter, converter);
46     } else {
47         Q_FOREACH (KoInteractionStrategyFactorySP factory, d->interactionFactories) {
48             // skip the rest of rendering if the factory asks for it
49             if (factory->paintOnHover(painter, converter)) break;
50         }
51     }
52 }
53 
mousePressEvent(KoPointerEvent * event)54 void KoInteractionTool::mousePressEvent(KoPointerEvent *event)
55 {
56     Q_D(KoInteractionTool);
57     if (d->currentStrategy) { // possible if the user presses an extra mouse button
58         cancelCurrentStrategy();
59         return;
60     }
61     d->currentStrategy = createStrategyBase(event);
62     if (d->currentStrategy == 0)
63         event->ignore();
64 }
65 
mouseMoveEvent(KoPointerEvent * event)66 void KoInteractionTool::mouseMoveEvent(KoPointerEvent *event)
67 {
68     Q_D(KoInteractionTool);
69     d->lastPoint = event->point;
70 
71     if (d->currentStrategy) {
72         d->currentStrategy->handleMouseMove(d->lastPoint, event->modifiers());
73     } else {
74         Q_FOREACH (KoInteractionStrategyFactorySP factory, d->interactionFactories) {
75             // skip the rest of rendering if the factory asks for it
76             if (factory->hoverEvent(event)) return;
77         }
78 
79         event->ignore();
80     }
81 }
82 
mouseReleaseEvent(KoPointerEvent * event)83 void KoInteractionTool::mouseReleaseEvent(KoPointerEvent *event)
84 {
85     Q_D(KoInteractionTool);
86     if (d->currentStrategy) {
87         d->currentStrategy->finishInteraction(event->modifiers());
88         KUndo2Command *command = d->currentStrategy->createCommand();
89         if (command)
90             d->canvas->addCommand(command);
91         delete d->currentStrategy;
92         d->currentStrategy = 0;
93         repaintDecorations();
94     } else
95         event->ignore();
96 }
97 
keyPressEvent(QKeyEvent * event)98 void KoInteractionTool::keyPressEvent(QKeyEvent *event)
99 {
100     Q_D(KoInteractionTool);
101     event->ignore();
102     if (d->currentStrategy &&
103             (event->key() == Qt::Key_Control ||
104              event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift ||
105              event->key() == Qt::Key_Meta)) {
106         d->currentStrategy->handleMouseMove(d->lastPoint, event->modifiers());
107         event->accept();
108     }
109 }
110 
keyReleaseEvent(QKeyEvent * event)111 void KoInteractionTool::keyReleaseEvent(QKeyEvent *event)
112 {
113     Q_D(KoInteractionTool);
114 
115     if (!d->currentStrategy) {
116         KoToolBase::keyReleaseEvent(event);
117         return;
118     }
119 
120     if (event->key() == Qt::Key_Escape) {
121         cancelCurrentStrategy();
122         event->accept();
123     } else if (event->key() == Qt::Key_Control ||
124                event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift ||
125                event->key() == Qt::Key_Meta) {
126         d->currentStrategy->handleMouseMove(d->lastPoint, event->modifiers());
127     }
128 }
129 
currentStrategy()130 KoInteractionStrategy *KoInteractionTool::currentStrategy()
131 {
132     Q_D(KoInteractionTool);
133     return d->currentStrategy;
134 }
135 
cancelCurrentStrategy()136 void KoInteractionTool::cancelCurrentStrategy()
137 {
138     Q_D(KoInteractionTool);
139     if (d->currentStrategy) {
140         d->currentStrategy->cancelInteraction();
141         delete d->currentStrategy;
142         d->currentStrategy = 0;
143     }
144 }
145 
createStrategyBase(KoPointerEvent * event)146 KoInteractionStrategy *KoInteractionTool::createStrategyBase(KoPointerEvent *event)
147 {
148     Q_D(KoInteractionTool);
149 
150     Q_FOREACH (KoInteractionStrategyFactorySP factory, d->interactionFactories) {
151         KoInteractionStrategy *strategy = factory->createStrategy(event);
152         if (strategy) {
153             return strategy;
154         }
155     }
156 
157     return createStrategy(event);
158 }
159 
addInteractionFactory(KoInteractionStrategyFactory * factory)160 void KoInteractionTool::addInteractionFactory(KoInteractionStrategyFactory *factory)
161 {
162     Q_D(KoInteractionTool);
163 
164     Q_FOREACH (auto f, d->interactionFactories) {
165         KIS_SAFE_ASSERT_RECOVER_RETURN(f->id() != factory->id());
166     }
167 
168     d->interactionFactories.append(toQShared(factory));
169     std::sort(d->interactionFactories.begin(),
170           d->interactionFactories.end(),
171           KoInteractionStrategyFactory::compareLess);
172 }
173 
removeInteractionFactory(const QString & id)174 void KoInteractionTool::removeInteractionFactory(const QString &id)
175 {
176     Q_D(KoInteractionTool);
177     QList<KoInteractionStrategyFactorySP>::iterator it =
178             d->interactionFactories.begin();
179 
180     while (it != d->interactionFactories.end()) {
181         if ((*it)->id() == id) {
182             it = d->interactionFactories.erase(it);
183         } else {
184             ++it;
185         }
186     }
187 }
188 
hasInteractioFactory(const QString & id)189 bool KoInteractionTool::hasInteractioFactory(const QString &id)
190 {
191     Q_D(KoInteractionTool);
192 
193     Q_FOREACH (auto f, d->interactionFactories) {
194         if (f->id() == id) {
195             return true;
196         }
197     }
198 
199     return false;
200 }
201 
tryUseCustomCursor()202 bool KoInteractionTool::tryUseCustomCursor()
203 {
204     Q_D(KoInteractionTool);
205 
206     Q_FOREACH (auto f, d->interactionFactories) {
207         if (f->tryUseCustomCursor()) {
208             return true;
209         }
210     }
211 
212     return false;
213 }
214 
KoInteractionTool(KoInteractionToolPrivate & dd)215 KoInteractionTool::KoInteractionTool(KoInteractionToolPrivate &dd)
216     : KoToolBase(dd)
217 {
218 }
219