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