1 /* This file is part of the KDE project
2 * Copyright (C) 2001-2002 Lennart Kudling <kudling@kde.org>
3 * Copyright (C) 2001-2005,2007 Rob Buis <buis@kde.org>
4 * Copyright (C) 2002-2003,2005 Tomislav Lukman <tomislav.lukman@ck.t-com.hr>
5 * Copyright (C) 2002-2003,2006 Laurent Montel <montel@kde.org>
6 * Copyright (C) 2002-2006 Stephan Binner <binner@kde.org>
7 * Copyright (C) 2002,2005 David Faure <faure@kde.org>
8 * Copyright (C) 2002 Benoit Vautrin <benoit.vautrin@free.fr>
9 * Copyright (C) 2002,2005-2007 Thomas Zander <zander@kde.org>
10 * Copyright (C) 2003 Dirk Mueller <mueller@kde.org>
11 * Copyright (C) 2003,2006 Stephan Kulow <coolo@kde.org>
12 * Copyright (C) 2004 Brad Hards <bradh@frogmouth.net>
13 * Copyright (C) 2005-2006 Tim Beaulen <tbscope@gmail.com>
14 * Copyright (C) 2005 Yann Bodson <yann.bodson@online.fr>
15 * Copyright (C) 2005-2010 Boudewijn Rempt <boud@valdyas.org>
16 * Copyright (C) 2005-2009,2011 Jan Hambrecht <jaham@gmx.net>
17 * Copyright (C) 2005-2006 Peter Simonsson <psn@linux.se>
18 * Copyright (C) 2005-2006 Sven Langkamp <sven.langkamp@gmail.com>
19 * Copyright (C) 2005-2006 Inge Wallin <inge@lysator.liu.se>
20 * Copyright (C) 2005-2006 C. Boemann <cbo@boemann.dk>
21 * Copyright (C) 2006 Martin Ellis <martin.ellis@kdemail.net>
22 * Copyright (C) 2006 Adriaan de Groot <groot@kde.org>
23 * Copyright (C) 2006 Sebastian Sauer <mail@dipe.org>
24 * Copyright (C) 2006-2007 Thorsten Zachmann <t.zachmann@zagge.de>
25 * Copyright (C) 2006 Andreas Hartmetz <ahartmetz@gmail.com>
26 * Copyright (C) 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
27 * Copyright (C) 2006-2007 Aaron J. Seigo <aseigo@kde.org>
28 * Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
29 *
30 * This library is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Library General Public
32 * License as published by the Free Software Foundation; either
33 * version 2 of the License, or (at your option) any later version.
34 *
35 * This library is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 * Library General Public License for more details.
39 *
40 * You should have received a copy of the GNU Library General Public License
41 * along with this library; see the file COPYING.LIB. If not, write to
42 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
43 * Boston, MA 02110-1301, USA.
44 */
45
46 #include "KarbonView.h"
47
48 // Dialogs.
49 #include "KarbonConfigureDialog.h"
50
51 // The rest.
52 #include "Karbon.h"
53 #include "KarbonFactory.h"
54 #include "KarbonPart.h"
55 #include "KarbonDocument.h"
56 #include "KarbonSmallStylePreview.h"
57 #include "KarbonDocumentMergeCommand.h"
58 #include "KarbonPaletteBarWidget.h"
59 #include "KarbonUiDebug.h"
60 #include "KarbonOutlinePaintingStrategy.h"
61
62 #include <KoPACanvas.h>
63 #include <KoCanvasResourceManager.h>
64 #include <KoPAPageBase.h>
65
66 #include <KoMainWindow.h>
67 #include <KoShapeStroke.h>
68 #include <KoCanvasControllerWidget.h>
69 #include <KoDocumentResourceManager.h>
70 #include <KoCanvasResourceManager.h>
71 #include <KoFilterManager.h>
72 #include <KoRuler.h>
73 #include <KoToolManager.h>
74 #include <KoStandardAction.h>
75 #include <KoToolProxy.h>
76 #include <KoShapeManager.h>
77 #include <KoShapeController.h>
78 #include <KoShapeContainer.h>
79 #include <KoShapeGroup.h>
80 #include <KoShapeCreateCommand.h>
81 #include <KoShapeDeleteCommand.h>
82 #include <KoShapeReorderCommand.h>
83 #include <KoShapeStrokeCommand.h>
84 #include <KoShapeBackgroundCommand.h>
85 #include <KoParameterToPathCommand.h>
86 #include <KoShapeClipCommand.h>
87 #include <KoShapeUnclipCommand.h>
88 #include <KoSelection.h>
89 #include <KoZoomAction.h>
90 #include <KoZoomHandler.h>
91 #include <KoPathShape.h>
92 #include <KoPathPoint.h>
93 #include <KoPathPointData.h>
94 #include <KoPathCombineCommand.h>
95 #include <KoPathReverseCommand.h>
96 #include <KoPathPointMoveCommand.h>
97 #include <KoShapeTransformCommand.h>
98 #include <KoShapeGroupCommand.h>
99 #include <KoToolBoxFactory.h>
100 #include <KoParameterShape.h>
101 #include <KoRulerController.h>
102 #include <KoDockRegistry.h>
103 #include <KoDockerManager.h>
104 #include <KoGridData.h>
105 #include <KoGuidesData.h>
106 #include <KoShapeLayer.h>
107 #include <KoColorBackground.h>
108 #include <KoCutController.h>
109 #include <KoCopyController.h>
110 #include <KoPasteController.h>
111 #include <KoSnapGuide.h>
112 #include <KoShapeFactoryBase.h>
113 #include <KoShapeRegistry.h>
114 #include <KoImageCollection.h>
115 #include <KoImageData.h>
116 #include <KoProperties.h>
117 #include <KoZoomController.h>
118 #include <KoIcon.h>
119 #include <KoFileDialog.h>
120 #include <KoUnit.h>
121 #include <KoPluginLoader.h>
122 #include <KoComponentData.h>
123
124 // KF5 header
125 #include <kcolormimedata.h>
126 #include <klocalizedstring.h>
127 #include <kmessagebox.h>
128 #include <kactioncollection.h>
129 #include <kstandardaction.h>
130 #include <ktoggleaction.h>
131 #include <KPluginFactory>
132 #include <KXMLGUIFactory>
133
134 // qt header
135 #include <QMimeDatabase>
136 #include <QAction>
137 #include <QResizeEvent>
138 #include <QDropEvent>
139 #include <QGridLayout>
140 #include <QStatusBar>
141 #include <QLabel>
142 #include <QImageReader>
143 #include <QPluginLoader>
144 #include <QLocale>
145
146 #include <unistd.h>
147 #include <KConfigGroup>
148
149 class Q_DECL_HIDDEN KarbonView::Private
150 {
151 public:
Private(KarbonPart * part,KarbonDocument * doc)152 Private(KarbonPart *part, KarbonDocument * doc)
153 : karbonPart(part), part(doc)
154 , colorBar(0), closePath(0), combinePath(0)
155 , separatePath(0), reversePath(0), intersectPath(0), subtractPath(0)
156 , unitePath(0), excludePath(0), pathSnapToGrid(0), configureAction(0)
157 , deleteSelectionAction(0), clipObjects(0), unclipObjects(0)
158 , flipVertical(0), flipHorizontal(0), viewAction(0)
159 , snapGridAction(0), showPageMargins(0), showGuidesAction(0)
160 , showPaletteAction(0)
161 , status(0), cursorCoords(0), smallPreview(0)
162 {}
163
164 KarbonPart * karbonPart;
165 KarbonDocument * part;
166 KarbonPaletteBarWidget *colorBar;
167
168 // actions:
169 QAction * closePath;
170 QAction * combinePath;
171 QAction * separatePath;
172 QAction * reversePath;
173 QAction * intersectPath;
174 QAction * subtractPath;
175 QAction * unitePath;
176 QAction * excludePath;
177 QAction * pathSnapToGrid;
178 QAction * configureAction;
179 QAction * deleteSelectionAction;
180 QAction * clipObjects;
181 QAction * unclipObjects;
182 QAction * flipVertical;
183 QAction * flipHorizontal;
184
185 KToggleAction * viewAction;
186
187 KToggleAction * snapGridAction;
188 KToggleAction * showPageMargins;
189 KToggleAction * showGuidesAction;
190
191 KToggleAction * showPaletteAction;
192
193 //Status Bar
194 QLabel * status; ///< ordinary status
195 QLabel * cursorCoords; ///< cursor coordinates
196 KarbonSmallStylePreview * smallPreview; ///< small style preview
197 };
198
KarbonView(KarbonPart * karbonPart,KarbonDocument * doc,QWidget * parent)199 KarbonView::KarbonView(KarbonPart *karbonPart, KarbonDocument* doc, QWidget* parent)
200 : KoPAView(karbonPart, doc, KoPAView::NormalMode, parent)
201 , d(new Private(karbonPart, doc))
202 {
203 setAcceptDrops(true);
204
205 setXMLFile(QString::fromLatin1("karbon.rc"));
206
207 d->cursorCoords = new QLabel(QString(), this);
208 d->cursorCoords->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
209 d->cursorCoords->setMinimumWidth(50);
210 addStatusBarItem(d->cursorCoords, 0);
211 connect(canvasController()->proxyObject, SIGNAL(canvasMousePositionChanged(QPoint)), this, SLOT(mousePositionChanged(QPoint)));
212
213 d->smallPreview = new KarbonSmallStylePreview(this);
214 connect(d->smallPreview, SIGNAL(fillApplied()), this, SLOT(applyFillToSelection()));
215 connect(d->smallPreview, SIGNAL(strokeApplied()), this, SLOT(applyStrokeToSelection()));
216 addStatusBarItem(d->smallPreview, 0);
217 // FIXME: This was not neccessary before refactoring to pageapp, why now?
218 // Also, changing colors of a shape does not update preview
219 connect(shapeManager(), SIGNAL(selectionChanged()), d->smallPreview, SLOT(selectionChanged()));
220
221 initActions();
222
223 // Load all plugins
224 const QList<KPluginFactory *> pluginFactories =
225 KoPluginLoader::instantiatePluginFactories(QStringLiteral("karbon/extensions"));
226 foreach (KPluginFactory* factory, pluginFactories) {
227 QObject *object = factory->create<QObject>(this, QVariantList());
228 KXMLGUIClient *clientPlugin = dynamic_cast<KXMLGUIClient*>(object);
229 if (clientPlugin) {
230 insertChildClient(clientPlugin);
231 } else {
232 // not our/valid plugin, so delete the created object
233 object->deleteLater();
234 }
235 }
236
237 unsigned int max = static_cast<KarbonDocument*>(kopaDocument())->maxRecentFiles();
238 setNumberOfRecentFiles(max);
239
240 d->colorBar = new KarbonPaletteBarWidget(Qt::Horizontal, this);
241 connect(d->colorBar, SIGNAL(colorSelected(KoColor)), this, SLOT(applyPaletteColor(KoColor)));
242 connect(shapeManager(), SIGNAL(selectionContentChanged()), d->colorBar, SLOT(updateDocumentColors()));
243 connect(kopaDocument(), SIGNAL(shapeAdded(KoShape*)), d->colorBar, SLOT(updateDocumentColors()));
244 connect(kopaDocument(), SIGNAL(shapeRemoved(KoShape*)), d->colorBar, SLOT(updateDocumentColors()));
245
246 if (mainWindow()) {
247 KSharedConfigPtr config = KSharedConfig::openConfig();
248 if (config->hasGroup("Interface")) {
249 KConfigGroup interfaceGroup = config->group( "Interface" );
250 if (!interfaceGroup.readEntry<bool>("ShowPalette", true)) {
251 d->colorBar->setVisible(false);
252 d->showPaletteAction->setChecked(false);
253 }
254 }
255 }
256
257 reorganizeGUI();
258
259 setFocusPolicy(Qt::NoFocus);
260 }
261
~KarbonView()262 KarbonView::~KarbonView()
263 {
264 removeStatusBarItem(d->cursorCoords);
265 removeStatusBarItem(d->smallPreview);
266
267 if (factory()) {
268 factory()->removeClient(this);
269 }
270 delete d;
271 }
272
colorBar() const273 KarbonPaletteBarWidget *KarbonView::colorBar() const
274 {
275 return d->colorBar;
276 }
277
part() const278 KarbonDocument * KarbonView::part() const
279 {
280 return static_cast<KarbonDocument*>(kopaDocument());
281 }
282
resourceManager() const283 KoCanvasResourceManager *KarbonView::resourceManager() const
284 {
285 return kopaCanvas()->resourceManager();
286 }
287
canvasWidget() const288 KoPACanvas *KarbonView::canvasWidget() const
289 {
290 return dynamic_cast<KoPACanvas*>(kopaCanvas());
291 }
292
resizeEvent(QResizeEvent *)293 void KarbonView::resizeEvent(QResizeEvent* /*event*/)
294 {
295 if (!kopaCanvas())
296 return;
297
298 reorganizeGUI();
299 }
300
dragEnterEvent(QDragEnterEvent * event)301 void KarbonView::dragEnterEvent(QDragEnterEvent * event)
302 {
303 QColor color = KColorMimeData::fromMimeData(event->mimeData());
304 if (color.isValid()) {
305 event->accept();
306 }
307 KoView::dragEnterEvent(event);
308 }
309
dropEvent(QDropEvent * e)310 void KarbonView::dropEvent(QDropEvent *e)
311 {
312
313 //Accepts QColor - from Color Manager's KColorPatch
314 QColor color = KColorMimeData::fromMimeData(e->mimeData());
315 if (color.isValid()) {
316 KoSelection * selection = shapeManager()->selection();
317 if (! selection)
318 return;
319
320 if (! kopaDocument())
321 return;
322
323 if (resourceManager()->intResource(KoCanvasResourceManager::ActiveStyleType) == KoFlake::Foreground) {
324 QList<KoShapeStrokeModel*> strokes;
325 QList<KoShape*> selectedShapes = selection->selectedShapes();
326 foreach(KoShape * shape, selectedShapes) {
327 KoShapeStroke * stroke = dynamic_cast<KoShapeStroke*>(shape->stroke());
328 KoShapeStroke * newStroke = 0;
329 if (stroke) {
330 newStroke = new KoShapeStroke(*stroke);
331 newStroke->setColor(color);
332 } else {
333 newStroke = new KoShapeStroke(1.0, color);
334 }
335 strokes.append(newStroke);
336 }
337 kopaCanvas()->addCommand(new KoShapeStrokeCommand(selectedShapes, strokes, 0));
338 } else {
339 QSharedPointer<KoShapeBackground> fill(new KoColorBackground(color));
340 kopaCanvas()->addCommand(new KoShapeBackgroundCommand(selection->selectedShapes(), fill, 0));
341 }
342 }
343
344 KoPAView::dropEvent(e);
345 }
346
fileImportGraphic()347 void KarbonView::fileImportGraphic()
348 {
349 QByteArray nativeMimeType = kopaDocument()->nativeFormatMimeType();
350 QStringList filter = KoFilterManager::mimeFilter(nativeMimeType, KoFilterManager::Import);
351
352 QStringList imageFilter;
353 // add filters for all formats supported by QImage
354 foreach(const QByteArray &mimeType, QImageReader::supportedMimeTypes()) {
355 imageFilter << QLatin1String(mimeType);
356 }
357 filter.append(imageFilter);
358
359 KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument");
360 dialog.setCaption(i18n("Choose Graphic to Add"));
361 dialog.setMimeTypeFilters(imageFilter);
362 QString fname = dialog.filename();
363
364 if (fname.isEmpty()) return;
365
366 KarbonPart importPart(0);
367 KarbonDocument importDocument(&importPart);
368 importPart.setDocument(&importDocument);
369
370 bool success = true;
371
372 // check if we have an empty mime type (probably because the "All supported files"
373 // filter was active)
374 QString currentMimeFilter;
375 // get mime type from file
376 QMimeType mimeType = QMimeDatabase().mimeTypeForFile(fname);
377 if (mimeType.isValid()) {
378 const QString mime = mimeType.name();
379 if (mime == nativeMimeType) {
380 currentMimeFilter = nativeMimeType;
381 } else {
382 foreach(const QString &filter, imageFilter) {
383 if (mime == filter) {
384 currentMimeFilter = filter;
385 break;
386 }
387 }
388 }
389 }
390
391 // check if we are loading an image format
392 if (imageFilter.contains(currentMimeFilter)) {
393 QImage image;
394 if (!image.load(fname)) {
395 KMessageBox::error(0, i18n("Could not load image."), i18n("Import graphic"), 0);
396 return;
397 }
398 KoShapeFactoryBase * factory = KoShapeRegistry::instance()->get("PictureShape");
399 if (!factory) {
400 KMessageBox::error(0, i18n("Could not create image shape."), i18n("Import graphic"), 0);
401 return;
402 }
403
404 KoShape *picture = factory->createDefaultShape(kopaDocument()->resourceManager());
405 KoImageCollection *imageCollection = kopaDocument()->resourceManager()->imageCollection();
406 if (!picture || !imageCollection) {
407 KMessageBox::error(0, i18n("Could not create image shape."), i18n("Import graphic"), 0);
408 return;
409 }
410
411 // calculate shape size in point from image resolution
412 qreal pxWidth = static_cast<qreal>(image.width());
413 qreal pxHeight = static_cast<qreal>(image.height());
414 qreal width = DM_TO_POINT(pxWidth / static_cast<qreal>(image.dotsPerMeterX()) * 10.0);
415 qreal height = DM_TO_POINT(pxHeight / static_cast<qreal>(image.dotsPerMeterY()) * 10.0);
416
417 // set shape data
418 picture->setUserData(imageCollection->createImageData(image));
419 picture->setSize(QSizeF(width, height));
420 picture->setPosition(QPointF());
421 picture->setKeepAspectRatio(true);
422
423 KUndo2Command * cmd = kopaCanvas()->shapeController()->addShapeDirect(picture);
424 cmd->setText(kundo2_i18n("Insert graphics"));
425 kopaCanvas()->addCommand(cmd);
426 shapeManager()->selection()->select(picture);
427 return;
428 }
429 // TODO: It is not obvious how this is best implemented when importing multipage docs
430 // Append pages?
431 // Append layers to existing pages?
432 // Add shapes to active page?
433 // etc?
434 // check if we are loading our native format
435 if (nativeMimeType == currentMimeFilter) {
436 // directly load the native format
437 success = importDocument.loadNativeFormat(fname);
438 if (!success) {
439 importDocument.showLoadingErrorDialog();
440 }
441 } else {
442 // use import filters to load the file
443 KoFilterManager man(&importDocument);
444 KoFilter::ConversionStatus status = KoFilter::OK;
445 QString importedFile = man.importDocument(fname, QString(), status);
446 if (status != KoFilter::OK) {
447 importDocument.showLoadingErrorDialog();
448 success = false;
449 } else if (!importedFile.isEmpty()) {
450 success = importDocument.loadNativeFormat(importedFile);
451 if (!success) {
452 importDocument.showLoadingErrorDialog();
453 }
454 // remove the temporary file created during format conversion
455 unlink(QFile::encodeName(importedFile));
456 }
457 }
458
459 if (success) {
460 KarbonDocumentMergeCommand * cmd = new KarbonDocumentMergeCommand(dynamic_cast<KarbonDocument*>(kopaDocument()), importDocument);
461 kopaCanvas()->addCommand(cmd);
462 /*
463 foreach(KoShape * shape, importedShapes) {
464 d->canvas->shapeManager()->selection()->select(shape, false);
465 }*/
466 }
467 }
468
selectionDuplicate()469 void KarbonView::selectionDuplicate()
470 {
471 kopaCanvas()->toolProxy()->copy();
472 kopaCanvas()->toolProxy()->paste();
473 }
474
editSelectAll()475 void KarbonView::editSelectAll()
476 {
477 KoSelection* selection = shapeManager()->selection();
478 if (! selection) {
479 return;
480 }
481 QList<KoShape*> shapes;
482 for (int i = 0; i < kopaDocument()->pages().count(); ++i) {
483 KoShapeLayer *l = dynamic_cast<KoShapeLayer*>(kopaDocument()->pages().at(i));
484 shapes += l->shapes();
485 }
486 debugKarbonUi << "shapes.size() =" << shapes.size();
487
488 foreach(KoShape* shape, shapes) {
489 selection->select(shape);
490 shape->update();
491 }
492
493 selectionChanged();
494 }
495
editDeselectAll()496 void KarbonView::editDeselectAll()
497 {
498 KoSelection* selection = shapeManager()->selection();
499 if (selection)
500 selection->deselectAll();
501
502 selectionChanged();
503 }
504
editDeleteSelection()505 void KarbonView::editDeleteSelection()
506 {
507 kopaCanvas()->toolProxy()->deleteSelection();
508 }
509
selectionDistributeHorizontalCenter()510 void KarbonView::selectionDistributeHorizontalCenter()
511 {
512 selectionDistribute(KoShapeDistributeCommand::HorizontalCenterDistribution);
513 }
514
selectionDistributeHorizontalGap()515 void KarbonView::selectionDistributeHorizontalGap()
516 {
517 selectionDistribute(KoShapeDistributeCommand::HorizontalGapsDistribution);
518 }
519
selectionDistributeHorizontalLeft()520 void KarbonView::selectionDistributeHorizontalLeft()
521 {
522 selectionDistribute(KoShapeDistributeCommand::HorizontalLeftDistribution);
523 }
524
selectionDistributeHorizontalRight()525 void KarbonView::selectionDistributeHorizontalRight()
526 {
527 selectionDistribute(KoShapeDistributeCommand::HorizontalRightDistribution);
528 }
529
selectionDistributeVerticalCenter()530 void KarbonView::selectionDistributeVerticalCenter()
531 {
532 selectionDistribute(KoShapeDistributeCommand::VerticalCenterDistribution);
533 }
534
selectionDistributeVerticalGap()535 void KarbonView::selectionDistributeVerticalGap()
536 {
537 selectionDistribute(KoShapeDistributeCommand::VerticalGapsDistribution);
538 }
539
selectionDistributeVerticalBottom()540 void KarbonView::selectionDistributeVerticalBottom()
541 {
542 selectionDistribute(KoShapeDistributeCommand::VerticalBottomDistribution);
543 }
544
selectionDistributeVerticalTop()545 void KarbonView::selectionDistributeVerticalTop()
546 {
547 selectionDistribute(KoShapeDistributeCommand::VerticalTopDistribution);
548 }
549
selectionDistribute(KoShapeDistributeCommand::Distribute distribute)550 void KarbonView::selectionDistribute(KoShapeDistributeCommand::Distribute distribute)
551 {
552 KoSelection* selection = shapeManager()->selection();
553 if (! selection)
554 return;
555
556 QList<KoShape*> selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection);
557 if (selectedShapes.count() < 2) return;
558
559 KoShapeDistributeCommand *cmd = new KoShapeDistributeCommand(selectedShapes, distribute, selection->boundingRect());
560
561 kopaCanvas()->addCommand(cmd);
562 }
563
clipObjects()564 void KarbonView::clipObjects()
565 {
566 KoSelection* selection = shapeManager()->selection();
567 if( ! selection )
568 return;
569
570 QList<KoShape*> selectedShapes = selection->selectedShapes( KoFlake::TopLevelSelection );
571 if( ! selectedShapes.count() )
572 return;
573
574 KoShape * shapeToClip = selectedShapes.first();
575 selectedShapes.removeOne( shapeToClip );
576
577 QList<KoPathShape*> clipPaths;
578 foreach( KoShape * shape, selectedShapes )
579 {
580 KoPathShape * path = dynamic_cast<KoPathShape*>( shape );
581 if( path )
582 clipPaths.append( path );
583 }
584
585 if( ! clipPaths.count() )
586 return;
587
588 KUndo2Command * cmd = new KoShapeClipCommand( kopaDocument(), shapeToClip, clipPaths );
589 kopaCanvas()->addCommand( cmd );
590 }
591
unclipObjects()592 void KarbonView::unclipObjects()
593 {
594 KoSelection* selection = shapeManager()->selection();
595 if( ! selection )
596 return;
597
598 QList<KoShape*> selectedShapes = selection->selectedShapes( KoFlake::TopLevelSelection );
599 if( ! selectedShapes.count() )
600 return;
601
602 QList<KoShape*> shapesToUnclip;
603 foreach(KoShape *shape, selectedShapes) {
604 if (shape->clipPath())
605 shapesToUnclip.append(shape);
606 }
607 if (!shapesToUnclip.count())
608 return;
609
610 kopaCanvas()->addCommand(new KoShapeUnclipCommand(kopaDocument(), shapesToUnclip));
611 }
612
flipVertical()613 void KarbonView::flipVertical()
614 {
615 selectionFlip(false, true);
616 }
617
flipHorizontal()618 void KarbonView::flipHorizontal()
619 {
620 selectionFlip(true, false);
621 }
622
selectionFlip(bool horizontally,bool vertically)623 void KarbonView::selectionFlip(bool horizontally, bool vertically)
624 {
625 if (!horizontally && !vertically)
626 return;
627
628 KoSelection* selection = shapeManager()->selection();
629 if( ! selection )
630 return;
631
632 QList<KoShape*> selectedShapes = selection->selectedShapes( KoFlake::StrippedSelection );
633 const int selectedShapesCount = selectedShapes.count();
634 if( selectedShapesCount < 1 )
635 return;
636
637 // mirror about center point
638 QPointF mirrorCenter = selection->absolutePosition(KoFlake::CenteredPosition);
639
640 QTransform mirrorMatrix;
641 mirrorMatrix.translate(mirrorCenter.x(), mirrorCenter.y());
642 mirrorMatrix.scale( horizontally ? -1.0 : 1.0, vertically ? -1.0 : 1.0);
643 mirrorMatrix.translate(-mirrorCenter.x(), -mirrorCenter.y());
644
645 QVector<QTransform> oldState;
646 QVector<QTransform> newState;
647 oldState.reserve(selectedShapesCount);
648 newState.reserve(selectedShapesCount);
649
650 foreach( KoShape* shape, selectedShapes ) {
651 shape->update();
652 oldState << shape->transformation();
653 // apply the mirror transformation
654 shape->applyAbsoluteTransformation(mirrorMatrix);
655 newState << shape->transformation();
656 }
657 selection->applyAbsoluteTransformation(mirrorMatrix);
658
659 KUndo2Command *cmd = new KoShapeTransformCommand(selectedShapes, oldState, newState);
660 if (horizontally && !vertically)
661 cmd->setText(kundo2_i18n("Mirror Horizontally"));
662 else if (!horizontally && vertically)
663 cmd->setText(kundo2_i18n("Mirror Vertically"));
664 else
665 cmd->setText(kundo2_i18n("Mirror Horizontally and Vertically"));
666 kopaCanvas()->addCommand(cmd);
667 }
668
closePath()669 void KarbonView::closePath()
670 {
671 // TODO add the new close path command here
672 }
673
combinePath()674 void KarbonView::combinePath()
675 {
676 KoSelection* selection = shapeManager()->selection();
677 if (! selection)
678 return;
679
680 QList<KoShape*> selectedShapes = selection->selectedShapes();
681 QList<KoPathShape*> paths;
682
683 foreach(KoShape* shape, selectedShapes) {
684 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
685 if (path) {
686 KoParameterShape * paramShape = dynamic_cast<KoParameterShape*>(path);
687 if (paramShape && paramShape->isParametricShape())
688 continue;
689 paths << path;
690 selection->deselect(shape);
691 }
692 }
693
694 if (paths.size())
695 kopaCanvas()->addCommand(new KoPathCombineCommand(kopaDocument(), paths));
696 }
697
separatePath()698 void KarbonView::separatePath()
699 {
700 KoSelection* selection = shapeManager()->selection();
701 if (! selection)
702 return;
703
704 QList<KoShape*> selectedShapes = selection->selectedShapes();
705 QList<KoPathShape*> paths;
706
707 foreach(KoShape* shape, selectedShapes) {
708 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
709 if (path) {
710 paths << path;
711 selection->deselect(shape);
712 }
713 }
714
715 if (!paths.size()) {
716 return;
717 }
718
719 KUndo2Command *cmd = new KUndo2Command;
720 cmd->setText(kundo2_i18n("Separate paths"));
721
722 foreach(KoPathShape* p, paths) {
723 QList<KoPathShape*> separatedPaths;
724 QList<KoShape*> newShapes;
725 if (p->separate(separatedPaths)) {
726 foreach(KoPathShape *subPath, separatedPaths) {
727 new KoShapeCreateCommand(kopaDocument(), subPath, cmd);
728 newShapes << subPath;
729 }
730 // make sure we put the new subpaths into the parent
731 // of the original path
732 KoShapeGroup *parentGroup = dynamic_cast<KoShapeGroup*>(p->parent());
733 if (parentGroup) {
734 new KoShapeGroupCommand(parentGroup, newShapes, cmd);
735 }
736 new KoShapeDeleteCommand(kopaDocument(), p, cmd);
737 }
738 }
739 kopaCanvas()->addCommand(cmd);
740 }
741
reversePath()742 void KarbonView::reversePath()
743 {
744 QList<KoPathShape*> paths = selectedPathShapes();
745 if (paths.size())
746 kopaCanvas()->addCommand(new KoPathReverseCommand(paths));
747 }
748
intersectPaths()749 void KarbonView::intersectPaths()
750 {
751 booleanOperation(KarbonBooleanCommand::Intersection);
752 }
753
subtractPaths()754 void KarbonView::subtractPaths()
755 {
756 booleanOperation(KarbonBooleanCommand::Subtraction);
757 }
758
unitePaths()759 void KarbonView::unitePaths()
760 {
761 booleanOperation(KarbonBooleanCommand::Union);
762 }
763
excludePaths()764 void KarbonView::excludePaths()
765 {
766 booleanOperation(KarbonBooleanCommand::Exclusion);
767 }
768
booleanOperation(KarbonBooleanCommand::BooleanOperation operation)769 void KarbonView::booleanOperation(KarbonBooleanCommand::BooleanOperation operation)
770 {
771 KoSelection* selection = shapeManager()->selection();
772 if (! selection)
773 return;
774
775 QList<KoShape*> selectedShapes = selection->selectedShapes();
776 QList<KoPathShape*> paths;
777
778 foreach(KoShape* shape, selectedShapes) {
779 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
780 if (path) {
781 paths << path;
782 selection->deselect(shape);
783 }
784 }
785
786 if (paths.size() == 2) {
787 KUndo2Command * macro = new KUndo2Command(kundo2_i18n("Boolean Operation"));
788 KoParameterShape * paramShape = dynamic_cast<KoParameterShape*>(paths[0]);
789 if (paramShape && paramShape->isParametricShape())
790 new KoParameterToPathCommand(paramShape, macro);
791 paramShape = dynamic_cast<KoParameterShape*>(paths[1]);
792 if (paramShape && paramShape->isParametricShape())
793 new KoParameterToPathCommand(paramShape, macro);
794 new KarbonBooleanCommand(kopaDocument(), paths[0], paths[1], operation, macro);
795 new KoShapeDeleteCommand(kopaDocument(), paths[0], macro);
796 new KoShapeDeleteCommand(kopaDocument(), paths[1], macro);
797 kopaCanvas()->addCommand(macro);
798 }
799 }
800
pathSnapToGrid()801 void KarbonView::pathSnapToGrid()
802 {
803 KoSelection* selection = shapeManager()->selection();
804 if (! selection)
805 return;
806
807 QList<KoShape*> selectedShapes = selection->selectedShapes();
808 QList<KoPathPointData> points;
809 QVector<QPointF> offsets;
810
811 // store current grid snap state
812 bool oldSnapToGrid = kopaDocument()->gridData().snapToGrid();
813 // enable grid snapping
814 kopaDocument()->gridData().setSnapToGrid(true);
815
816 KoSnapGuide snapGuide(kopaCanvas());
817 snapGuide.enableSnapStrategies(KoSnapGuide::GridSnapping);
818 snapGuide.setSnapDistance(INT_MAX);
819
820 foreach(KoShape* shape, selectedShapes) {
821 KoParameterShape * paramShape = dynamic_cast<KoParameterShape*>(shape);
822 if (paramShape && paramShape->isParametricShape())
823 continue;
824
825 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
826 if (! path)
827 continue;
828
829 uint subpathCount = path->subpathCount();
830 for (uint i = 0; i < subpathCount; ++i) {
831 uint pointCount = path->subpathPointCount(i);
832 for (uint j = 0; j < pointCount; ++j) {
833 KoPathPointIndex index(i, j);
834 KoPathPoint * p = path->pointByIndex(index);
835 if (!p)
836 continue;
837
838 QPointF docPoint = path->shapeToDocument(p->point());
839 QPointF offset = snapGuide.snap(docPoint, 0) - docPoint;
840 points.append(KoPathPointData(path, index));
841 offsets.append(offset);
842 }
843 }
844 }
845
846 // reset grid snapping state to old value
847 kopaDocument()->gridData().setSnapToGrid(oldSnapToGrid);
848
849 kopaCanvas()->addCommand(new KoPathPointMoveCommand(points, offsets));
850 }
851
viewModeChanged(bool outlineMode)852 void KarbonView::viewModeChanged(bool outlineMode)
853 {
854 if (outlineMode) {
855 new KarbonOutlinePaintingStrategy(shapeManager());
856 } else {
857 shapeManager()->setPaintingStrategy(new KoShapeManagerPaintingStrategy(shapeManager()));
858 }
859 }
860
zoomSelection()861 void KarbonView::zoomSelection()
862 {
863 KoSelection* selection = shapeManager()->selection();
864 if (! selection)
865 return;
866
867 if (! selection->count())
868 return;
869
870 const KoZoomHandler * zoomHandler = dynamic_cast<const KoZoomHandler*>(viewConverter());
871 if (! zoomHandler)
872 return;
873
874 QRectF bbox = selection->boundingRect();
875 QRect viewRect = zoomHandler->documentToView(bbox).toRect();
876
877 kopaCanvas()->canvasController()->zoomTo(viewRect.translated(kopaCanvas()->documentOrigin()));
878 // QPointF newCenter = kopaCanvas()->documentOrigin() + zoomHandler->documentToView(bbox.center());
879 // kopaCanvas()->setPreferredCenter(newCenter.toPoint());
880 }
881
zoomDrawing()882 void KarbonView::zoomDrawing()
883 {
884 const KoZoomHandler * zoomHandler = dynamic_cast<const KoZoomHandler*>(kopaCanvas()->viewConverter());
885 if (! zoomHandler)
886 return;
887
888 QRectF bbox = activePage()->contentRect();
889 if (bbox.isNull())
890 return;
891
892 QRect viewRect = zoomHandler->documentToView(bbox).toRect();
893 kopaCanvas()->canvasController()->zoomTo(viewRect.translated(kopaCanvas()->documentOrigin()));
894 // QPointF newCenter = kopaCanvas()->documentOrigin() + zoomHandler->documentToView(bbox.center());
895 // kopaCanvas()->setPreferredCenter(newCenter.toPoint());
896 }
897
initActions()898 void KarbonView::initActions()
899 {
900 // view ----->
901 d->viewAction = new KToggleAction(i18n("Outline &Mode"), this);
902 actionCollection()->addAction("view_mode", d->viewAction);
903 connect(d->viewAction, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)));
904
905 // No need for the other actions in read-only (embedded) mode
906 if (!mainWindow())
907 return;
908
909 // edit ----->
910 QAction *action = actionCollection()->addAction(KStandardAction::Cut, "edit_cut", 0, 0);
911 new KoCutController(kopaCanvas(), action);
912 action = actionCollection()->addAction(KStandardAction::Copy, "edit_copy", 0, 0);
913 new KoCopyController(kopaCanvas(), action);
914 action = actionCollection()->addAction(KStandardAction::Paste, "edit_paste", 0, 0);
915 new KoPasteController(kopaCanvas(), action);
916 actionCollection()->addAction(KStandardAction::SelectAll, "edit_select_all", this, SLOT(editSelectAll()));
917 actionCollection()->addAction(KStandardAction::Deselect, "edit_deselect_all", this, SLOT(editDeselectAll()));
918
919 QAction *actionImportGraphic = new QAction(i18n("&Import Graphic..."), this);
920 actionCollection()->addAction("file_import", actionImportGraphic);
921 connect(actionImportGraphic, SIGNAL(triggered()), this, SLOT(fileImportGraphic()));
922
923 d->deleteSelectionAction = new QAction(koIcon("edit-delete"), i18n("D&elete"), this);
924 actionCollection()->addAction("edit_delete", d->deleteSelectionAction);
925 d->deleteSelectionAction->setShortcut(QKeySequence("Del"));
926 connect(d->deleteSelectionAction, SIGNAL(triggered()), this, SLOT(editDeleteSelection()));
927 connect(kopaCanvas()->toolProxy(), SIGNAL(selectionChanged(bool)), d->deleteSelectionAction, SLOT(setEnabled(bool)));
928
929 QAction *actionEditGuides = new QAction(koIcon("edit-guides"), i18n("Edit Guides"), this);
930 actionCollection()->addAction("edit_guides", actionEditGuides);
931 connect(actionEditGuides, SIGNAL(triggered()), this, SLOT(editGuides()));
932 // edit <-----
933
934 // object ----->
935 QAction *actionDuplicate = new QAction(i18nc("Duplicate selection", "&Duplicate"), this);
936 actionCollection()->addAction("object_duplicate", actionDuplicate);
937 actionDuplicate->setShortcut(QKeySequence("Ctrl+D"));
938 connect(actionDuplicate, SIGNAL(triggered()), this, SLOT(selectionDuplicate()));
939
940 QAction *actionDistributeHorizontalCenter = new QAction(koIcon("distribute-horizontal-center"), i18n("Distribute Center (Horizontal)"), this);
941 actionCollection()->addAction("object_distribute_horizontal_center", actionDistributeHorizontalCenter);
942 connect(actionDistributeHorizontalCenter, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalCenter()));
943
944 QAction *actionDistributeHorizontalGap = new QAction(koIcon("distribute-horizontal-equal"), i18n("Distribute Gaps (Horizontal)"), this);
945 actionCollection()->addAction("object_distribute_horizontal_gap", actionDistributeHorizontalGap);
946 connect(actionDistributeHorizontalGap, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalGap()));
947
948 QAction *actionDistributeLeft = new QAction(koIcon("distribute-horizontal-left"), i18n("Distribute Left Borders"), this);
949 actionCollection()->addAction("object_distribute_horizontal_left", actionDistributeLeft);
950 connect(actionDistributeLeft, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalLeft()));
951
952 QAction *actionDistributeRight = new QAction(koIcon("distribute-horizontal-right"), i18n("Distribute Right Borders"), this);
953 actionCollection()->addAction("object_distribute_horizontal_right", actionDistributeRight);
954 connect(actionDistributeRight, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalRight()));
955
956 QAction *actionDistributeVerticalCenter = new QAction(koIcon("distribute-vertical-center"), i18n("Distribute Center (Vertical)"), this);
957 actionCollection()->addAction("object_distribute_vertical_center", actionDistributeVerticalCenter);
958 connect(actionDistributeVerticalCenter, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalCenter()));
959
960 QAction *actionDistributeVerticalGap = new QAction(koIcon("distribute-vertical-equal"), i18n("Distribute Gaps (Vertical)"), this);
961 actionCollection()->addAction("object_distribute_vertical_gap", actionDistributeVerticalGap);
962 connect(actionDistributeVerticalGap, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalGap()));
963
964 QAction *actionDistributeBottom = new QAction(koIcon("distribute-vertical-bottom"), i18n("Distribute Bottom Borders"), this);
965 actionCollection()->addAction("object_distribute_vertical_bottom", actionDistributeBottom);
966 connect(actionDistributeBottom, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalBottom()));
967
968 QAction *actionDistributeTop = new QAction(koIcon("distribute-vertical-top"), i18n("Distribute Top Borders"), this);
969 actionCollection()->addAction("object_distribute_vertical_top", actionDistributeTop);
970 connect(actionDistributeTop, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalTop()));
971
972 d->showPaletteAction = new KToggleAction(i18n("Show Color Palette"), this);
973 actionCollection()->addAction("view_show_palette", d->showPaletteAction);
974 d->showPaletteAction->setToolTip(i18n("Show or hide color palette"));
975 d->showPaletteAction->setChecked(true);
976 connect(d->showPaletteAction, SIGNAL(triggered()), this, SLOT(showPalette()));
977
978 action = actionCollection()->action("object_group");
979 if (action) {
980 action->setShortcut(QKeySequence("Ctrl+G"));
981 }
982 action = actionCollection()->action("object_ungroup");
983 if (action) {
984 action->setShortcut(QKeySequence("Ctrl+Shift+G"));
985 }
986
987 d->clipObjects = new QAction(i18n("&Clip Object"), this);
988 actionCollection()->addAction("object_clip", d->clipObjects );
989 connect(d->clipObjects, SIGNAL(triggered()), this, SLOT(clipObjects()));
990
991 d->unclipObjects = new QAction(i18n("&Unclip Objects"), this);
992 actionCollection()->addAction("object_unclip", d->unclipObjects );
993 connect(d->unclipObjects, SIGNAL(triggered()), this, SLOT(unclipObjects()));
994
995 d->flipVertical = new QAction(koIcon("object-flip-vertical"), i18n("Mirror Vertically"), this);
996 actionCollection()->addAction("object_flip_vertical", d->flipVertical);
997 connect(d->flipVertical, SIGNAL(triggered()), this, SLOT(flipVertical()));
998
999 d->flipHorizontal = new QAction(koIcon("object-flip-horizontal"), i18n("Mirror Horizontally"), this);
1000 actionCollection()->addAction("object_flip_horizontal", d->flipHorizontal);
1001 connect(d->flipHorizontal, SIGNAL(triggered()), this, SLOT(flipHorizontal()));
1002
1003 // object <-----
1004
1005 // path ------->
1006 d->closePath = new QAction(i18n("&Close Path"), this);
1007 actionCollection()->addAction("close_path", d->closePath);
1008 d->closePath->setShortcut(QKeySequence("Ctrl+U"));
1009 d->closePath->setEnabled(false);
1010 connect(d->closePath, SIGNAL(triggered()), this, SLOT(closePath()));
1011
1012 d->combinePath = new QAction(i18n("Com&bine Path"), this);
1013 actionCollection()->addAction("combine_path", d->combinePath);
1014 d->combinePath->setShortcut(QKeySequence("Ctrl+K"));
1015 d->combinePath->setEnabled(false);
1016 connect(d->combinePath, SIGNAL(triggered()), this, SLOT(combinePath()));
1017
1018 d->separatePath = new QAction(i18n("Se¶te Path"), this);
1019 actionCollection()->addAction("separate_path", d->separatePath);
1020 d->separatePath->setShortcut(QKeySequence("Shift+Ctrl+K"));
1021 d->separatePath->setEnabled(false);
1022 connect(d->separatePath, SIGNAL(triggered()), this, SLOT(separatePath()));
1023
1024 d->reversePath = new QAction(i18n("Re&verse Path"), this);
1025 actionCollection()->addAction("reverse_path", d->reversePath);
1026 d->reversePath->setShortcut(QKeySequence("Ctrl+R"));
1027 d->reversePath->setEnabled(false);
1028 connect(d->reversePath, SIGNAL(triggered()), this, SLOT(reversePath()));
1029
1030 d->intersectPath = new QAction(i18n("Intersect Paths"), this);
1031 actionCollection()->addAction("intersect_path", d->intersectPath);
1032 //d->intersectPath->setShortcut(QKeySequence("Shift+Ctrl+K"));
1033 d->intersectPath->setEnabled(false);
1034 connect(d->intersectPath, SIGNAL(triggered()), this, SLOT(intersectPaths()));
1035
1036 d->subtractPath = new QAction(i18n("Subtract Paths"), this);
1037 actionCollection()->addAction("subtract_path", d->subtractPath);
1038 //d->subtractPath->setShortcut(QKeySequence("Shift+Ctrl+K"));
1039 d->subtractPath->setEnabled(false);
1040 connect(d->subtractPath, SIGNAL(triggered()), this, SLOT(subtractPaths()));
1041
1042 d->unitePath = new QAction(i18n("Unite Paths"), this);
1043 actionCollection()->addAction("unite_path", d->unitePath);
1044 //d->unitePath->setShortcut(QKeySequence("Shift+Ctrl+K"));
1045 d->unitePath->setEnabled(false);
1046 connect(d->unitePath, SIGNAL(triggered()), this, SLOT(unitePaths()));
1047
1048 d->excludePath = new QAction(i18n("Exclude Paths"), this);
1049 actionCollection()->addAction("exclude_path", d->excludePath);
1050 //d->excludePath->setShortcut(QKeySequence("Shift+Ctrl+K"));
1051 d->excludePath->setEnabled(false);
1052 connect(d->excludePath, SIGNAL(triggered()), this, SLOT(excludePaths()));
1053
1054 d->pathSnapToGrid = new QAction(i18n("Snap Path to Grid"), this);
1055 actionCollection()->addAction("path_snap_to_grid", d->pathSnapToGrid);
1056 d->pathSnapToGrid->setEnabled(false);
1057 connect(d->pathSnapToGrid, SIGNAL(triggered()), this, SLOT(pathSnapToGrid()));
1058
1059 // path <-----
1060
1061 // view ---->
1062 QAction * zoomSelection = new QAction(koIcon("zoom-select"), i18n("Zoom to Selection"), this);
1063 actionCollection()->addAction("view_zoom_selection", zoomSelection);
1064 connect(zoomSelection, SIGNAL(triggered()), this, SLOT(zoomSelection()));
1065
1066 QAction * zoomDrawing = new QAction(koIcon("zoom-draw"), i18n("Zoom to Drawing"), this);
1067 actionCollection()->addAction("view_zoom_drawing", zoomDrawing);
1068 connect(zoomDrawing, SIGNAL(triggered()), this, SLOT(zoomDrawing()));
1069 // view <-----
1070 }
1071
mousePositionChanged(const QPoint & position)1072 void KarbonView::mousePositionChanged(const QPoint &position)
1073 {
1074 const QPoint canvasOffset(canvasController()->canvasOffsetX(), canvasController()->canvasOffsetY() );
1075 const QPoint viewPos = position - kopaCanvas()->documentOrigin() - canvasOffset;
1076
1077 QPointF documentPos = kopaCanvas()->viewConverter()->viewToDocument(viewPos);
1078 qreal x = kopaDocument()->unit().toUserValue(documentPos.x());
1079 qreal y = kopaDocument()->unit().toUserValue(documentPos.y());
1080
1081 if (statusBar() && statusBar()->isVisible()) {
1082 QLocale locale;
1083 d->cursorCoords->setText(QString::fromLatin1("%1, %2").arg(locale.toString(x, 'f', 2), locale.toString(y, 'f', 2)));
1084 }
1085 }
1086
reorganizeGUI()1087 void KarbonView::reorganizeGUI()
1088 {
1089 // TODO: Find a better solution, maybe move to KoPAView?
1090 if (statusBar()) {
1091 bool show = true;
1092 if (mainWindow()) {
1093 KSharedConfigPtr config = KSharedConfig::openConfig();
1094 if (config->hasGroup("Interface")) {
1095 KConfigGroup interfaceGroup = config->group( "Interface" );
1096 if (!interfaceGroup.readEntry<bool>("ShowStatusBar", true)) {
1097 show = false;
1098 }
1099 }
1100 }
1101 statusBar()->setVisible(show);
1102 }
1103 }
1104
setNumberOfRecentFiles(unsigned int number)1105 void KarbonView::setNumberOfRecentFiles(unsigned int number)
1106 {
1107 if (mainWindow()) { // 0L when embedded into konq !
1108 mainWindow()->setMaxRecentItems(number);
1109 }
1110 }
1111
editGuides()1112 void KarbonView::editGuides()
1113 {
1114 KoToolManager::instance()->switchToolRequested("GuidesTool_ID");
1115 }
1116
showPalette()1117 void KarbonView::showPalette()
1118 {
1119 if(!mainWindow())
1120 return;
1121
1122 const bool showPalette = d->showPaletteAction->isChecked();
1123 d->colorBar->setVisible(showPalette);
1124
1125 // this will make the last setting of the ruler visibility persistent
1126 KConfigGroup interfaceGroup = KarbonFactory::global().config()->group("Interface");
1127 if (showPalette && !interfaceGroup.hasDefault("ShowPalette"))
1128 interfaceGroup.revertToDefault("ShowPalette");
1129 else
1130 interfaceGroup.writeEntry("ShowPalette", showPalette);
1131 }
1132
openConfiguration()1133 void KarbonView::openConfiguration()
1134 {
1135 QPointer<KarbonConfigureDialog> dialog = new KarbonConfigureDialog(this);
1136 dialog->exec();
1137 delete dialog;
1138 reorganizeGUI();
1139 }
1140
selectionChanged()1141 void KarbonView::selectionChanged()
1142 {
1143 if (!mainWindow())
1144 return;
1145 KoSelection *selection = kopaCanvas()->shapeManager()->selection();
1146 QList<KoShape*> selectedShapes = selection->selectedShapes(KoFlake::FullSelection);
1147 const int count = selectedShapes.count();
1148
1149 d->closePath->setEnabled(false);
1150 d->combinePath->setEnabled(false);
1151 d->excludePath->setEnabled(false);
1152 d->intersectPath->setEnabled(false);
1153 d->subtractPath->setEnabled(false);
1154 d->unitePath->setEnabled(false);
1155 d->pathSnapToGrid->setEnabled(false);
1156 d->clipObjects->setEnabled(false);
1157 d->unclipObjects->setEnabled(false);
1158 d->flipHorizontal->setEnabled(count > 0);
1159 d->flipVertical->setEnabled(count > 0);
1160
1161 debugKarbonUi << count << " shapes selected";
1162
1163 if (count > 0) {
1164 uint selectedPaths = 0;
1165 uint selectedParametrics = 0;
1166 // check for different shape types for enabling specific actions
1167 foreach(KoShape* shape, selectedShapes) {
1168 if (dynamic_cast<KoPathShape*>(shape)) {
1169 KoParameterShape * ps = dynamic_cast<KoParameterShape*>(shape);
1170 if (ps && ps->isParametricShape())
1171 selectedParametrics++;
1172 else
1173 selectedPaths++;
1174 }
1175 }
1176 debugKarbonUi << selectedPaths << " path shapes selected";
1177 debugKarbonUi << selectedParametrics << " parameter shapes selected";
1178 //TODO enable action when the ClosePath command is ported
1179 //d->closePath->setEnabled( selectedPaths > 0 );
1180 d->combinePath->setEnabled(selectedPaths > 1);
1181 d->separatePath->setEnabled(selectedPaths > 0);
1182 d->reversePath->setEnabled(selectedPaths > 0);
1183 d->excludePath->setEnabled(selectedPaths + selectedParametrics == 2);
1184 d->intersectPath->setEnabled(selectedPaths + selectedParametrics == 2);
1185 d->subtractPath->setEnabled(selectedPaths + selectedParametrics == 2);
1186 d->unitePath->setEnabled(selectedPaths + selectedParametrics == 2);
1187 d->pathSnapToGrid->setEnabled(selectedPaths > 0);
1188 d->clipObjects->setEnabled(selectedPaths > 0 && count > 1);
1189 d->unclipObjects->setEnabled(selectedShapes.first()->clipPath() != 0);
1190 // if only one shape selected, set its parent layer as the active layer
1191 if (count == 1) {
1192 KoShapeContainer * parent = selection->selectedShapes().first()->parent();
1193 while (parent) {
1194 if (parent->parent())
1195 parent = parent->parent();
1196 else
1197 break;
1198 }
1199 KoShapeLayer * layer = dynamic_cast<KoShapeLayer*>(parent);
1200 if (layer)
1201 selection->setActiveLayer(layer);
1202 }
1203 }
1204 }
1205
setCursor(const QCursor & c)1206 void KarbonView::setCursor(const QCursor &c)
1207 {
1208 kopaCanvas()->setCursor(c);
1209 }
1210
updateReadWrite(bool readwrite)1211 void KarbonView::updateReadWrite(bool readwrite)
1212 {
1213 Q_UNUSED(readwrite);
1214 }
1215
selectedPathShapes()1216 QList<KoPathShape*> KarbonView::selectedPathShapes()
1217 {
1218 KoSelection* selection = shapeManager()->selection();
1219 if (! selection)
1220 return QList<KoPathShape*>();
1221
1222 QList<KoShape*> selectedShapes = selection->selectedShapes();
1223 QList<KoPathShape*> paths;
1224
1225 foreach(KoShape* shape, selectedShapes) {
1226 KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
1227 if (path) {
1228 paths << path;
1229 selection->deselect(shape);
1230 }
1231 }
1232
1233 return paths;
1234 }
1235
applyFillToSelection()1236 void KarbonView::applyFillToSelection()
1237 {
1238 KoSelection *selection = shapeManager()->selection();
1239 if (! selection->count())
1240 return;
1241
1242 KoShape * shape = selection->firstSelectedShape();
1243 kopaCanvas()->addCommand(new KoShapeBackgroundCommand(selection->selectedShapes(), shape->background()));
1244 }
1245
applyStrokeToSelection()1246 void KarbonView::applyStrokeToSelection()
1247 {
1248 KoSelection *selection = shapeManager()->selection();
1249 if (! selection->count())
1250 return;
1251
1252 KoShape * shape = selection->firstSelectedShape();
1253 kopaCanvas()->addCommand(new KoShapeStrokeCommand(selection->selectedShapes(), shape->stroke()));
1254 }
1255
applyPaletteColor(const KoColor & color)1256 void KarbonView::applyPaletteColor(const KoColor &color)
1257 {
1258 KoSelection *selection = shapeManager()->selection();
1259 if (! selection->count())
1260 return;
1261
1262 int style = resourceManager()->intResource(KoCanvasResourceManager::ActiveStyleType);
1263 if (style == KoFlake::Foreground) {
1264 QList<KoShapeStrokeModel*> newStrokes;
1265 foreach(KoShape *shape, selection->selectedShapes()) {
1266 KoShapeStroke *stroke = dynamic_cast<KoShapeStroke*>(shape->stroke());
1267 if (stroke) {
1268 // preserve stroke properties
1269 KoShapeStroke *newStroke = new KoShapeStroke(*stroke);
1270 newStroke->setColor(color.toQColor());
1271 newStrokes << newStroke;
1272 } else {
1273 newStrokes << new KoShapeStroke(1.0, color.toQColor());
1274 }
1275 }
1276 kopaCanvas()->addCommand(new KoShapeStrokeCommand(selection->selectedShapes(), newStrokes));
1277 resourceManager()->setForegroundColor(color);
1278 } else {
1279 QSharedPointer<KoShapeBackground> fill(new KoColorBackground(color.toQColor()));
1280 kopaCanvas()->addCommand(new KoShapeBackgroundCommand(selection->selectedShapes(), fill));
1281 resourceManager()->setBackgroundColor(color);
1282 }
1283 }
1284
replaceActivePage(KoPAPageBase * page,KoPAPageBase * newActivePage)1285 void KarbonView::replaceActivePage(KoPAPageBase *page, KoPAPageBase *newActivePage)
1286 {
1287 if (page == activePage() ) {
1288 viewMode()->updateActivePage(newActivePage);
1289 }
1290 }
1291
1292