1 /* This file is part of the KDE project
2  * Copyright (C) 2007,2009,2011 Jan Hambrecht <jaham@gmx.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "KarbonPatternTool.h"
21 #include "KarbonPatternEditStrategy.h"
22 #include <KarbonPatternOptionsWidget.h>
23 
24 #include <KoCanvasBase.h>
25 #include <KoShapeManager.h>
26 #include <KoSelection.h>
27 #include <KoShape.h>
28 #include <KoDocumentResourceManager.h>
29 #include <KoShapeBackgroundCommand.h>
30 #include <KoPointerEvent.h>
31 #include <KoPattern.h>
32 #include <KoPatternBackground.h>
33 #include <KoImageCollection.h>
34 #include <KoShapeController.h>
35 #include <KoResource.h>
36 #include <KoResourceServerProvider.h>
37 #include <KoResourceItemChooser.h>
38 #include <KoResourceServerAdapter.h>
39 
40 #include <klocalizedstring.h>
41 
42 #include <QPainter>
43 #include <QWidget>
44 #include <kundo2command.h>
45 
KarbonPatternTool(KoCanvasBase * canvas)46 KarbonPatternTool::KarbonPatternTool(KoCanvasBase *canvas)
47         : KoToolBase(canvas), m_currentStrategy(0), m_optionsWidget(0)
48 {
49 }
50 
~KarbonPatternTool()51 KarbonPatternTool::~KarbonPatternTool()
52 {
53 }
54 
paint(QPainter & painter,const KoViewConverter & converter)55 void KarbonPatternTool::paint(QPainter &painter, const KoViewConverter &converter)
56 {
57     painter.setBrush(Qt::green);   //TODO make configurable
58     painter.setPen(QPen(Qt::blue, 0));   //TODO make configurable
59 
60     // paint all the strategies
61     foreach(KarbonPatternEditStrategyBase *strategy, m_strategies) {
62         if (strategy == m_currentStrategy)
63             continue;
64 
65         painter.save();
66         strategy->paint(painter, converter);
67         painter.restore();
68     }
69 
70     // paint selected strategy with another color
71     if (m_currentStrategy) {
72         painter.setBrush(Qt::red);   //TODO make configurable
73         m_currentStrategy->paint(painter, converter);
74     }
75 }
76 
repaintDecorations()77 void KarbonPatternTool::repaintDecorations()
78 {
79     foreach(KarbonPatternEditStrategyBase *strategy, m_strategies)
80     canvas()->updateCanvas(strategy->boundingRect());
81 }
82 
mousePressEvent(KoPointerEvent * event)83 void KarbonPatternTool::mousePressEvent(KoPointerEvent *event)
84 {
85     //m_currentStrategy = 0;
86 
87     foreach(KarbonPatternEditStrategyBase *strategy, m_strategies) {
88         if (strategy->selectHandle(event->point, *canvas()->viewConverter())) {
89             m_currentStrategy = strategy;
90             m_currentStrategy->repaint();
91             useCursor(Qt::SizeAllCursor);
92             break;
93         }
94     }
95     if (m_currentStrategy) {
96         m_currentStrategy->setEditing(true);
97         updateOptionsWidget();
98     }
99 }
100 
mouseMoveEvent(KoPointerEvent * event)101 void KarbonPatternTool::mouseMoveEvent(KoPointerEvent *event)
102 {
103     if (m_currentStrategy) {
104         m_currentStrategy->repaint();
105         if (m_currentStrategy->isEditing()) {
106             m_currentStrategy->handleMouseMove(event->point, event->modifiers());
107             m_currentStrategy->repaint();
108             return;
109         }
110     }
111     foreach(KarbonPatternEditStrategyBase *strategy, m_strategies) {
112         if (strategy->selectHandle(event->point, *canvas()->viewConverter())) {
113             useCursor(Qt::SizeAllCursor);
114             return;
115         }
116     }
117     useCursor(Qt::ArrowCursor);
118 }
119 
mouseReleaseEvent(KoPointerEvent * event)120 void KarbonPatternTool::mouseReleaseEvent(KoPointerEvent *event)
121 {
122     Q_UNUSED(event)
123     // if we are editing, get out of edit mode and add a command to the stack
124     if (m_currentStrategy && m_currentStrategy->isEditing()) {
125         m_currentStrategy->setEditing(false);
126         KUndo2Command * cmd = m_currentStrategy->createCommand();
127         if (cmd)
128             canvas()->addCommand(cmd);
129 
130         updateOptionsWidget();
131     }
132 }
133 
keyPressEvent(QKeyEvent * event)134 void KarbonPatternTool::keyPressEvent(QKeyEvent *event)
135 {
136     switch (event->key()) {
137     case Qt::Key_I: {
138         KoDocumentResourceManager *rm = canvas()->shapeController()->resourceManager();
139         uint handleRadius = rm->handleRadius();
140         if (event->modifiers() & Qt::ControlModifier)
141             handleRadius--;
142         else
143             handleRadius++;
144         rm->setHandleRadius(handleRadius);
145     }
146     break;
147     default:
148         event->ignore();
149         return;
150     }
151     event->accept();
152 }
153 
initialize()154 void KarbonPatternTool::initialize()
155 {
156     if (m_currentStrategy && m_currentStrategy->isEditing())
157         return;
158 
159     QList<KoShape*> selectedShapes = canvas()->shapeManager()->selection()->selectedShapes();
160 
161     // remove all pattern strategies no longer applicable
162     foreach(KarbonPatternEditStrategyBase * strategy, m_strategies) {
163         // is this gradient shape still selected ?
164         if (! selectedShapes.contains(strategy->shape()) || ! strategy->shape()->isEditable()) {
165             m_strategies.remove(strategy->shape());
166             if (m_currentStrategy == strategy)
167                 m_currentStrategy = 0;
168             delete strategy;
169             continue;
170         }
171 
172         // does the shape has no fill pattern anymore ?
173         QSharedPointer<KoPatternBackground>  fill = qSharedPointerDynamicCast<KoPatternBackground>(strategy->shape()->background());
174         if (! fill) {
175             // delete the gradient
176             m_strategies.remove(strategy->shape());
177             if (m_currentStrategy == strategy)
178                 m_currentStrategy = 0;
179             delete strategy;
180             continue;
181         }
182 
183         strategy->updateHandles();
184         strategy->repaint();
185     }
186 
187     KoImageCollection *imageCollection = canvas()->shapeController()->resourceManager()->imageCollection();
188 
189     // now create new strategies if needed
190     foreach(KoShape *shape, selectedShapes) {
191         if (! shape->isEditable())
192             continue;
193 
194         // do we already have a strategy for that shape?
195         if (m_strategies.contains(shape))
196             continue;
197 
198         if (qSharedPointerDynamicCast<KoPatternBackground>(shape->background())) {
199             KarbonPatternEditStrategyBase * s = new KarbonOdfPatternEditStrategy(shape, imageCollection);
200             m_strategies.insert(shape, s);
201             s->repaint();
202         }
203     }
204     // automatically select strategy when editing single shape
205     if (m_strategies.count() == 1 && ! m_currentStrategy) {
206         m_currentStrategy = m_strategies.begin().value();
207         updateOptionsWidget();
208     }
209 
210     if (m_currentStrategy)
211         m_currentStrategy->repaint();
212 }
213 
activate(ToolActivation toolActivation,const QSet<KoShape * > & shapes)214 void KarbonPatternTool::activate(ToolActivation toolActivation, const QSet<KoShape*> &shapes)
215 {
216     Q_UNUSED(toolActivation);
217     if (shapes.isEmpty()) {
218         emit done();
219         return;
220     }
221 
222     initialize();
223 
224     KarbonPatternEditStrategyBase::setHandleRadius(handleRadius());
225     KarbonPatternEditStrategyBase::setGrabSensitivity(grabSensitivity());
226 
227     useCursor(Qt::ArrowCursor);
228 
229     connect(canvas()->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(initialize()));
230 }
231 
deactivate()232 void KarbonPatternTool::deactivate()
233 {
234     // we are not interested in selection content changes when not active
235     disconnect(canvas()->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(initialize()));
236 
237     foreach(KarbonPatternEditStrategyBase * strategy, m_strategies) {
238         strategy->repaint();
239     }
240 
241     qDeleteAll(m_strategies);
242     m_strategies.clear();
243 
244     foreach(KoShape *shape, canvas()->shapeManager()->selection()->selectedShapes())
245     shape->update();
246 
247     m_currentStrategy = 0;
248 }
249 
documentResourceChanged(int key,const QVariant & res)250 void KarbonPatternTool::documentResourceChanged(int key, const QVariant & res)
251 {
252     switch (key) {
253     case KoDocumentResourceManager::HandleRadius:
254         foreach(KarbonPatternEditStrategyBase *strategy, m_strategies)
255             strategy->repaint();
256 
257         KarbonPatternEditStrategyBase::setHandleRadius(res.toUInt());
258 
259         foreach(KarbonPatternEditStrategyBase *strategy, m_strategies)
260             strategy->repaint();
261         break;
262     case KoDocumentResourceManager::GrabSensitivity:
263         KarbonPatternEditStrategyBase::setGrabSensitivity(res.toUInt());
264         break;
265     default:
266         return;
267     }
268 }
269 
createOptionWidgets()270 QList<QPointer<QWidget> > KarbonPatternTool::createOptionWidgets()
271 {
272     QList<QPointer<QWidget> > widgets;
273 
274     m_optionsWidget = new KarbonPatternOptionsWidget();
275     connect(m_optionsWidget, SIGNAL(patternChanged()),
276             this, SLOT(patternChanged()));
277 
278     KoResourceServer<KoPattern> * rserver = KoResourceServerProvider::instance()->patternServer();
279     QSharedPointer<KoAbstractResourceServerAdapter> adapter(new KoResourceServerAdapter<KoPattern>(rserver));
280     KoResourceItemChooser * chooser = new KoResourceItemChooser(adapter, m_optionsWidget);
281     chooser->setObjectName("KarbonPatternChooser");
282 
283     connect(chooser, SIGNAL(resourceSelected(KoResource*)),
284             this, SLOT(patternSelected(KoResource*)));
285 
286     m_optionsWidget->setWindowTitle(i18n("Pattern Options"));
287     widgets.append(m_optionsWidget);
288     chooser->setWindowTitle(i18n("Patterns"));
289     widgets.append(chooser);
290     updateOptionsWidget();
291     return widgets;
292 }
293 
patternSelected(KoResource * resource)294 void KarbonPatternTool::patternSelected(KoResource * resource)
295 {
296     KoPattern * currentPattern = dynamic_cast<KoPattern*>(resource);
297     if (! currentPattern || ! currentPattern->valid())
298         return;
299 
300     KoImageCollection *imageCollection = canvas()->shapeController()->resourceManager()->imageCollection();
301     if (imageCollection) {
302         QList<KoShape*> selectedShapes = canvas()->shapeManager()->selection()->selectedShapes();
303         QSharedPointer<KoPatternBackground> newFill(new KoPatternBackground(imageCollection));
304         newFill->setPattern(currentPattern->pattern());
305         canvas()->addCommand(new KoShapeBackgroundCommand(selectedShapes, newFill));
306         initialize();
307     }
308 }
309 
updateOptionsWidget()310 void KarbonPatternTool::updateOptionsWidget()
311 {
312     if (m_optionsWidget && m_currentStrategy) {
313         QSharedPointer<KoPatternBackground>  fill = qSharedPointerDynamicCast<KoPatternBackground>(m_currentStrategy->shape()->background());
314         if (fill) {
315             m_optionsWidget->setRepeat(fill->repeat());
316             m_optionsWidget->setReferencePoint(fill->referencePoint());
317             m_optionsWidget->setReferencePointOffset(fill->referencePointOffset());
318             m_optionsWidget->setTileRepeatOffset(fill->tileRepeatOffset());
319             m_optionsWidget->setPatternSize(fill->patternDisplaySize().toSize());
320         }
321     }
322 }
323 
patternChanged()324 void KarbonPatternTool::patternChanged()
325 {
326     if (m_currentStrategy) {
327         KoShape * shape = m_currentStrategy->shape();
328         QSharedPointer<KoPatternBackground>  oldFill = qSharedPointerDynamicCast<KoPatternBackground>(shape->background());
329         if (! oldFill)
330             return;
331         KoImageCollection *imageCollection = canvas()->shapeController()->resourceManager()->imageCollection();
332         if (! imageCollection)
333             return;
334         QSharedPointer<KoPatternBackground> newFill(new KoPatternBackground(imageCollection));
335         if (! newFill)
336             return;
337         newFill->setTransform(oldFill->transform());
338         newFill->setPattern(oldFill->pattern());
339 
340         newFill->setRepeat(m_optionsWidget->repeat());
341         newFill->setReferencePoint(m_optionsWidget->referencePoint());
342         newFill->setReferencePointOffset(m_optionsWidget->referencePointOffset());
343         newFill->setTileRepeatOffset(m_optionsWidget->tileRepeatOffset());
344         newFill->setPatternDisplaySize(m_optionsWidget->patternSize());
345         canvas()->addCommand(new KoShapeBackgroundCommand(shape, newFill));
346     }
347 }
348 
349