File indexing completed on 2024-05-12 16:30:49

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2001-2002 Lennart Kudling <kudling@kde.org>
0003  * Copyright (C) 2001-2005,2007 Rob Buis <buis@kde.org>
0004  * Copyright (C) 2002-2003,2005 Tomislav Lukman <tomislav.lukman@ck.t-com.hr>
0005  * Copyright (C) 2002-2003,2006 Laurent Montel <montel@kde.org>
0006  * Copyright (C) 2002-2006 Stephan Binner <binner@kde.org>
0007  * Copyright (C) 2002,2005 David Faure <faure@kde.org>
0008  * Copyright (C) 2002 Benoit Vautrin <benoit.vautrin@free.fr>
0009  * Copyright (C) 2002,2005-2007 Thomas Zander <zander@kde.org>
0010  * Copyright (C) 2003 Dirk Mueller <mueller@kde.org>
0011  * Copyright (C) 2003,2006 Stephan Kulow <coolo@kde.org>
0012  * Copyright (C) 2004 Brad Hards <bradh@frogmouth.net>
0013  * Copyright (C) 2005-2006 Tim Beaulen <tbscope@gmail.com>
0014  * Copyright (C) 2005 Yann Bodson <yann.bodson@online.fr>
0015  * Copyright (C) 2005-2010 Boudewijn Rempt <boud@valdyas.org>
0016  * Copyright (C) 2005-2009,2011 Jan Hambrecht <jaham@gmx.net>
0017  * Copyright (C) 2005-2006 Peter Simonsson <psn@linux.se>
0018  * Copyright (C) 2005-2006 Sven Langkamp <sven.langkamp@gmail.com>
0019  * Copyright (C) 2005-2006 Inge Wallin <inge@lysator.liu.se>
0020  * Copyright (C) 2005-2006 C. Boemann <cbo@boemann.dk>
0021  * Copyright (C) 2006 Martin Ellis <martin.ellis@kdemail.net>
0022  * Copyright (C) 2006 Adriaan de Groot <groot@kde.org>
0023  * Copyright (C) 2006 Sebastian Sauer <mail@dipe.org>
0024  * Copyright (C) 2006-2007 Thorsten Zachmann <t.zachmann@zagge.de>
0025  * Copyright (C) 2006 Andreas Hartmetz <ahartmetz@gmail.com>
0026  * Copyright (C) 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0027  * Copyright (C) 2006-2007 Aaron J. Seigo <aseigo@kde.org>
0028  * Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
0029  *
0030  * This library is free software; you can redistribute it and/or
0031  * modify it under the terms of the GNU Library General Public
0032  * License as published by the Free Software Foundation; either
0033  * version 2 of the License, or (at your option) any later version.
0034  *
0035  * This library is distributed in the hope that it will be useful,
0036  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0037  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0038  * Library General Public License for more details.
0039  *
0040  * You should have received a copy of the GNU Library General Public License
0041  * along with this library; see the file COPYING.LIB.  If not, write to
0042  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0043  * Boston, MA 02110-1301, USA.
0044  */
0045 
0046 #include "KarbonView.h"
0047 
0048 // Dialogs.
0049 #include "KarbonConfigureDialog.h"
0050 
0051 // The rest.
0052 #include "Karbon.h"
0053 #include "KarbonFactory.h"
0054 #include "KarbonPart.h"
0055 #include "KarbonDocument.h"
0056 #include "KarbonSmallStylePreview.h"
0057 #include "KarbonDocumentMergeCommand.h"
0058 #include "KarbonPaletteBarWidget.h"
0059 #include "KarbonUiDebug.h"
0060 #include "KarbonOutlinePaintingStrategy.h"
0061 
0062 #include <KoPACanvas.h>
0063 #include <KoCanvasResourceManager.h>
0064 #include <KoPAPageBase.h>
0065 
0066 #include <KoMainWindow.h>
0067 #include <KoShapeStroke.h>
0068 #include <KoCanvasControllerWidget.h>
0069 #include <KoDocumentResourceManager.h>
0070 #include <KoCanvasResourceManager.h>
0071 #include <KoFilterManager.h>
0072 #include <KoRuler.h>
0073 #include <KoToolManager.h>
0074 #include <KoStandardAction.h>
0075 #include <KoToolProxy.h>
0076 #include <KoShapeManager.h>
0077 #include <KoShapeController.h>
0078 #include <KoShapeContainer.h>
0079 #include <KoShapeGroup.h>
0080 #include <KoShapeCreateCommand.h>
0081 #include <KoShapeDeleteCommand.h>
0082 #include <KoShapeReorderCommand.h>
0083 #include <KoShapeStrokeCommand.h>
0084 #include <KoShapeBackgroundCommand.h>
0085 #include <KoParameterToPathCommand.h>
0086 #include <KoShapeClipCommand.h>
0087 #include <KoShapeUnclipCommand.h>
0088 #include <KoSelection.h>
0089 #include <KoZoomAction.h>
0090 #include <KoZoomHandler.h>
0091 #include <KoPathShape.h>
0092 #include <KoPathPoint.h>
0093 #include <KoPathPointData.h>
0094 #include <KoPathCombineCommand.h>
0095 #include <KoPathReverseCommand.h>
0096 #include <KoPathPointMoveCommand.h>
0097 #include <KoShapeTransformCommand.h>
0098 #include <KoShapeGroupCommand.h>
0099 #include <KoToolBoxFactory.h>
0100 #include <KoParameterShape.h>
0101 #include <KoRulerController.h>
0102 #include <KoDockRegistry.h>
0103 #include <KoDockerManager.h>
0104 #include <KoGridData.h>
0105 #include <KoGuidesData.h>
0106 #include <KoShapeLayer.h>
0107 #include <KoColorBackground.h>
0108 #include <KoCutController.h>
0109 #include <KoCopyController.h>
0110 #include <KoPasteController.h>
0111 #include <KoSnapGuide.h>
0112 #include <KoShapeFactoryBase.h>
0113 #include <KoShapeRegistry.h>
0114 #include <KoImageCollection.h>
0115 #include <KoImageData.h>
0116 #include <KoProperties.h>
0117 #include <KoZoomController.h>
0118 #include <KoIcon.h>
0119 #include <KoFileDialog.h>
0120 #include <KoUnit.h>
0121 #include <KoPluginLoader.h>
0122 #include <KoComponentData.h>
0123 
0124 // KF5 header
0125 #include <kcolormimedata.h>
0126 #include <klocalizedstring.h>
0127 #include <kmessagebox.h>
0128 #include <kactioncollection.h>
0129 #include <kstandardaction.h>
0130 #include <ktoggleaction.h>
0131 #include <KPluginFactory>
0132 #include <KXMLGUIFactory>
0133 
0134 // qt header
0135 #include <QMimeDatabase>
0136 #include <QAction>
0137 #include <QResizeEvent>
0138 #include <QDropEvent>
0139 #include <QGridLayout>
0140 #include <QStatusBar>
0141 #include <QLabel>
0142 #include <QImageReader>
0143 #include <QPluginLoader>
0144 #include <QLocale>
0145 
0146 #include <unistd.h>
0147 #include <KConfigGroup>
0148 
0149 class Q_DECL_HIDDEN KarbonView::Private
0150 {
0151 public:
0152     Private(KarbonPart *part, KarbonDocument * doc)
0153             : karbonPart(part), part(doc)
0154             , colorBar(0), closePath(0), combinePath(0)
0155             , separatePath(0), reversePath(0), intersectPath(0)
0156             , subtractPath(0), unitePath(0), excludePath(0)
0157             , pathSnapToGrid(0), configureAction(0), clipObjects(0)
0158             , unclipObjects(0), flipVertical(0), flipHorizontal(0)
0159             , viewAction(0), snapGridAction(0), showPageMargins(0)
0160             , showGuidesAction(0), showPaletteAction(0)
0161             , status(0), cursorCoords(0), smallPreview(0)
0162     {}
0163 
0164     KarbonPart * karbonPart;
0165     KarbonDocument * part;
0166     KarbonPaletteBarWidget *colorBar;
0167 
0168     // actions:
0169     QAction * closePath;
0170     QAction * combinePath;
0171     QAction * separatePath;
0172     QAction * reversePath;
0173     QAction * intersectPath;
0174     QAction * subtractPath;
0175     QAction * unitePath;
0176     QAction * excludePath;
0177     QAction * pathSnapToGrid;
0178     QAction * configureAction;
0179     QAction * clipObjects;
0180     QAction * unclipObjects;
0181     QAction * flipVertical;
0182     QAction * flipHorizontal;
0183 
0184     KToggleAction * viewAction;
0185 
0186     KToggleAction * snapGridAction;
0187     KToggleAction * showPageMargins;
0188     KToggleAction * showGuidesAction;
0189 
0190     KToggleAction * showPaletteAction;
0191 
0192     //Status Bar
0193     QLabel * status;       ///< ordinary status
0194     QLabel * cursorCoords; ///< cursor coordinates
0195     KarbonSmallStylePreview * smallPreview; ///< small style preview
0196 };
0197 
0198 KarbonView::KarbonView(KarbonPart *karbonPart, KarbonDocument* doc, QWidget* parent)
0199     : KoPAView(karbonPart, doc, KoPAView::NormalMode, parent)
0200     , d(new Private(karbonPart, doc))
0201 {
0202     setAcceptDrops(true);
0203 
0204     setXMLFile(QString::fromLatin1("karbon.rc"));
0205 
0206     d->cursorCoords = new QLabel(QString(), this);
0207     d->cursorCoords->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0208     d->cursorCoords->setMinimumWidth(50);
0209     addStatusBarItem(d->cursorCoords, 0);
0210     connect(canvasController()->proxyObject, SIGNAL(canvasMousePositionChanged(QPoint)), this, SLOT(mousePositionChanged(QPoint)));
0211 
0212     d->smallPreview = new KarbonSmallStylePreview(this);
0213     connect(d->smallPreview, SIGNAL(fillApplied()), this, SLOT(applyFillToSelection()));
0214     connect(d->smallPreview, SIGNAL(strokeApplied()), this, SLOT(applyStrokeToSelection()));
0215     addStatusBarItem(d->smallPreview, 0);
0216     // FIXME: This was not neccessary before refactoring to pageapp, why now?
0217     // Also, changing colors of a shape does not update preview
0218     connect(shapeManager(), SIGNAL(selectionChanged()), d->smallPreview, SLOT(selectionChanged()));
0219 
0220     initActions();
0221 
0222     // Load all plugins
0223     const QList<KPluginFactory *> pluginFactories =
0224         KoPluginLoader::instantiatePluginFactories(QStringLiteral("karbon/extensions"));
0225     foreach (KPluginFactory* factory, pluginFactories) {
0226         QObject *object = factory->create<QObject>(this, QVariantList());
0227         KXMLGUIClient *clientPlugin = dynamic_cast<KXMLGUIClient*>(object);
0228         if (clientPlugin) {
0229             insertChildClient(clientPlugin);
0230         } else {
0231             // not our/valid plugin, so delete the created object
0232             object->deleteLater();
0233         }
0234     }
0235 
0236     unsigned int max = static_cast<KarbonDocument*>(kopaDocument())->maxRecentFiles();
0237     setNumberOfRecentFiles(max);
0238 
0239     d->colorBar = new KarbonPaletteBarWidget(Qt::Horizontal, this);
0240     connect(d->colorBar, SIGNAL(colorSelected(KoColor)), this, SLOT(applyPaletteColor(KoColor)));
0241     connect(shapeManager(), SIGNAL(selectionContentChanged()), d->colorBar, SLOT(updateDocumentColors()));
0242     connect(kopaDocument(), SIGNAL(shapeAdded(KoShape*)), d->colorBar, SLOT(updateDocumentColors()));
0243     connect(kopaDocument(), SIGNAL(shapeRemoved(KoShape*)), d->colorBar, SLOT(updateDocumentColors()));
0244 
0245     if (mainWindow()) {
0246         KSharedConfigPtr config = KSharedConfig::openConfig();
0247         if (config->hasGroup("Interface")) {
0248             KConfigGroup interfaceGroup = config->group( "Interface" );
0249             if (!interfaceGroup.readEntry<bool>("ShowPalette", true)) {
0250                 d->colorBar->setVisible(false);
0251                 d->showPaletteAction->setChecked(false);
0252             }
0253         }
0254     }
0255 
0256     reorganizeGUI();
0257 
0258     setFocusPolicy(Qt::NoFocus);
0259 }
0260 
0261 KarbonView::~KarbonView()
0262 {
0263     removeStatusBarItem(d->cursorCoords);
0264     removeStatusBarItem(d->smallPreview);
0265 
0266     if (factory()) {
0267         factory()->removeClient(this);
0268     }
0269     delete d;
0270 }
0271 
0272 KarbonPaletteBarWidget *KarbonView::colorBar() const
0273 {
0274     return d->colorBar;
0275 }
0276 
0277 KarbonDocument * KarbonView::part() const
0278 {
0279     return static_cast<KarbonDocument*>(kopaDocument());
0280 }
0281 
0282 KoCanvasResourceManager *KarbonView::resourceManager() const
0283 {
0284     return kopaCanvas()->resourceManager();
0285 }
0286 
0287 KoPACanvas *KarbonView::canvasWidget() const
0288 {
0289     return dynamic_cast<KoPACanvas*>(kopaCanvas());
0290 }
0291 
0292 void KarbonView::resizeEvent(QResizeEvent* /*event*/)
0293 {
0294     if (!kopaCanvas())
0295         return;
0296 
0297     reorganizeGUI();
0298 }
0299 
0300 void KarbonView::dragEnterEvent(QDragEnterEvent * event)
0301 {
0302     QColor color = KColorMimeData::fromMimeData(event->mimeData());
0303     if (color.isValid()) {
0304         event->accept();
0305     }
0306     KoView::dragEnterEvent(event);
0307 }
0308 
0309 void KarbonView::dropEvent(QDropEvent *e)
0310 {
0311 
0312     //Accepts QColor - from Color Manager's KColorPatch
0313     QColor color = KColorMimeData::fromMimeData(e->mimeData());
0314     if (color.isValid()) {
0315         KoSelection * selection = shapeManager()->selection();
0316         if (! selection)
0317             return;
0318 
0319         if (! kopaDocument())
0320             return;
0321 
0322         if (resourceManager()->intResource(KoCanvasResourceManager::ActiveStyleType) == KoFlake::Foreground) {
0323             QList<KoShapeStrokeModel*> strokes;
0324             QList<KoShape*> selectedShapes = selection->selectedShapes();
0325             foreach(KoShape * shape, selectedShapes) {
0326                 KoShapeStroke * stroke = dynamic_cast<KoShapeStroke*>(shape->stroke());
0327                 KoShapeStroke * newStroke = 0;
0328                 if (stroke) {
0329                     newStroke = new KoShapeStroke(*stroke);
0330                     newStroke->setColor(color);
0331                 } else {
0332                     newStroke = new KoShapeStroke(1.0, color);
0333                 }
0334                 strokes.append(newStroke);
0335             }
0336             kopaCanvas()->addCommand(new KoShapeStrokeCommand(selectedShapes, strokes, 0));
0337         } else {
0338             QSharedPointer<KoShapeBackground> fill(new KoColorBackground(color));
0339             kopaCanvas()->addCommand(new KoShapeBackgroundCommand(selection->selectedShapes(), fill, 0));
0340         }
0341     }
0342 
0343     KoPAView::dropEvent(e);
0344 }
0345 
0346 void KarbonView::fileImportGraphic()
0347 {
0348     QByteArray nativeMimeType = kopaDocument()->nativeFormatMimeType();
0349     QStringList filter = KoFilterManager::mimeFilter(nativeMimeType, KoFilterManager::Import);
0350 
0351     QStringList imageFilter;
0352     // add filters for all formats supported by QImage
0353     foreach(const QByteArray &mimeType, QImageReader::supportedMimeTypes()) {
0354         imageFilter << QLatin1String(mimeType);
0355     }
0356     filter.append(imageFilter);
0357 
0358     KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument");
0359     dialog.setCaption(i18n("Choose Graphic to Add"));
0360     dialog.setMimeTypeFilters(imageFilter);
0361     QString fname = dialog.filename();
0362 
0363     if (fname.isEmpty()) return;
0364 
0365     KarbonPart importPart(0);
0366     KarbonDocument importDocument(&importPart);
0367     importPart.setDocument(&importDocument);
0368 
0369     bool success = true;
0370 
0371     // check if we have an empty mime type (probably because the "All supported files"
0372     // filter was active)
0373     QString currentMimeFilter;
0374     // get mime type from file
0375     QMimeType mimeType = QMimeDatabase().mimeTypeForFile(fname);
0376     if (mimeType.isValid()) {
0377         const QString mime = mimeType.name();
0378         if (mime == nativeMimeType) {
0379             currentMimeFilter = nativeMimeType;
0380         } else {
0381             foreach(const QString &filter, imageFilter) {
0382                 if (mime == filter) {
0383                     currentMimeFilter = filter;
0384                     break;
0385                 }
0386             }
0387         }
0388     }
0389 
0390     // check if we are loading an image format
0391     if (imageFilter.contains(currentMimeFilter)) {
0392         QImage image;
0393         if (!image.load(fname)) {
0394             KMessageBox::error(0, i18n("Could not load image."), i18n("Import graphic"), 0);
0395             return;
0396         }
0397         KoShapeFactoryBase * factory = KoShapeRegistry::instance()->get("PictureShape");
0398         if (!factory) {
0399             KMessageBox::error(0, i18n("Could not create image shape."), i18n("Import graphic"), 0);
0400             return;
0401         }
0402 
0403         KoShape *picture = factory->createDefaultShape(kopaDocument()->resourceManager());
0404         KoImageCollection *imageCollection = kopaDocument()->resourceManager()->imageCollection();
0405         if (!picture || !imageCollection) {
0406             KMessageBox::error(0, i18n("Could not create image shape."), i18n("Import graphic"), 0);
0407             return;
0408         }
0409 
0410         // calculate shape size in point from image resolution
0411         qreal pxWidth = static_cast<qreal>(image.width());
0412         qreal pxHeight = static_cast<qreal>(image.height());
0413         qreal width = DM_TO_POINT(pxWidth / static_cast<qreal>(image.dotsPerMeterX()) * 10.0);
0414         qreal height = DM_TO_POINT(pxHeight / static_cast<qreal>(image.dotsPerMeterY()) * 10.0);
0415 
0416         // set shape data
0417         picture->setUserData(imageCollection->createImageData(image));
0418         picture->setSize(QSizeF(width, height));
0419         picture->setPosition(QPointF());
0420         picture->setKeepAspectRatio(true);
0421 
0422         KUndo2Command * cmd = kopaCanvas()->shapeController()->addShapeDirect(picture);
0423         cmd->setText(kundo2_i18n("Insert graphics"));
0424         kopaCanvas()->addCommand(cmd);
0425         shapeManager()->selection()->select(picture);
0426         return;
0427     }
0428     // TODO: It is not obvious how this is best implemented when importing multipage docs
0429     // Append pages?
0430     // Append layers to existing pages?
0431     // Add shapes to active page?
0432     // etc?
0433     // check if we are loading our native format
0434     if (nativeMimeType == currentMimeFilter) {
0435         // directly load the native format
0436         success = importDocument.loadNativeFormat(fname);
0437         if (!success) {
0438             importDocument.showLoadingErrorDialog();
0439         }
0440     } else {
0441         // use import filters to load the file
0442         KoFilterManager man(&importDocument);
0443         KoFilter::ConversionStatus status = KoFilter::OK;
0444         QString importedFile = man.importDocument(fname, QString(), status);
0445         if (status != KoFilter::OK) {
0446             importDocument.showLoadingErrorDialog();
0447             success = false;
0448         } else if (!importedFile.isEmpty()) {
0449             success = importDocument.loadNativeFormat(importedFile);
0450             if (!success) {
0451                 importDocument.showLoadingErrorDialog();
0452             }
0453             // remove the temporary file created during format conversion
0454             unlink(QFile::encodeName(importedFile));
0455         }
0456     }
0457 
0458     if (success) {
0459         KarbonDocumentMergeCommand * cmd = new KarbonDocumentMergeCommand(dynamic_cast<KarbonDocument*>(kopaDocument()), importDocument);
0460         kopaCanvas()->addCommand(cmd);
0461 /*
0462         foreach(KoShape * shape, importedShapes) {
0463             d->canvas->shapeManager()->selection()->select(shape, false);
0464         }*/
0465     }
0466 }
0467 
0468 void KarbonView::selectionDuplicate()
0469 {
0470     kopaCanvas()->toolProxy()->copy();
0471     kopaCanvas()->toolProxy()->paste();
0472 }
0473 
0474 void KarbonView::selectionDistributeHorizontalCenter()
0475 {
0476     selectionDistribute(KoShapeDistributeCommand::HorizontalCenterDistribution);
0477 }
0478 
0479 void KarbonView::selectionDistributeHorizontalGap()
0480 {
0481     selectionDistribute(KoShapeDistributeCommand::HorizontalGapsDistribution);
0482 }
0483 
0484 void KarbonView::selectionDistributeHorizontalLeft()
0485 {
0486     selectionDistribute(KoShapeDistributeCommand::HorizontalLeftDistribution);
0487 }
0488 
0489 void KarbonView::selectionDistributeHorizontalRight()
0490 {
0491     selectionDistribute(KoShapeDistributeCommand::HorizontalRightDistribution);
0492 }
0493 
0494 void KarbonView::selectionDistributeVerticalCenter()
0495 {
0496     selectionDistribute(KoShapeDistributeCommand::VerticalCenterDistribution);
0497 }
0498 
0499 void KarbonView::selectionDistributeVerticalGap()
0500 {
0501     selectionDistribute(KoShapeDistributeCommand::VerticalGapsDistribution);
0502 }
0503 
0504 void KarbonView::selectionDistributeVerticalBottom()
0505 {
0506     selectionDistribute(KoShapeDistributeCommand::VerticalBottomDistribution);
0507 }
0508 
0509 void KarbonView::selectionDistributeVerticalTop()
0510 {
0511     selectionDistribute(KoShapeDistributeCommand::VerticalTopDistribution);
0512 }
0513 
0514 void KarbonView::selectionDistribute(KoShapeDistributeCommand::Distribute distribute)
0515 {
0516     KoSelection* selection = shapeManager()->selection();
0517     if (! selection)
0518         return;
0519 
0520     QList<KoShape*> selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection);
0521     if (selectedShapes.count() < 2) return;
0522 
0523     KoShapeDistributeCommand *cmd = new KoShapeDistributeCommand(selectedShapes, distribute, selection->boundingRect());
0524 
0525     kopaCanvas()->addCommand(cmd);
0526 }
0527 
0528 void KarbonView::clipObjects()
0529 {
0530     KoSelection* selection = shapeManager()->selection();
0531     if( ! selection )
0532         return;
0533 
0534     QList<KoShape*> selectedShapes = selection->selectedShapes( KoFlake::TopLevelSelection );
0535     if( ! selectedShapes.count() )
0536         return;
0537 
0538     KoShape * shapeToClip = selectedShapes.first();
0539     selectedShapes.removeOne( shapeToClip );
0540 
0541     QList<KoPathShape*> clipPaths;
0542     foreach( KoShape * shape, selectedShapes )
0543     {
0544         KoPathShape * path = dynamic_cast<KoPathShape*>( shape );
0545         if( path )
0546             clipPaths.append( path );
0547     }
0548 
0549     if( ! clipPaths.count() )
0550         return;
0551 
0552     KUndo2Command * cmd = new KoShapeClipCommand( kopaDocument(), shapeToClip, clipPaths );
0553     kopaCanvas()->addCommand( cmd );
0554 }
0555 
0556 void KarbonView::unclipObjects()
0557 {
0558     KoSelection* selection = shapeManager()->selection();
0559     if( ! selection )
0560         return;
0561 
0562     QList<KoShape*> selectedShapes = selection->selectedShapes( KoFlake::TopLevelSelection );
0563     if( ! selectedShapes.count() )
0564         return;
0565 
0566     QList<KoShape*> shapesToUnclip;
0567     foreach(KoShape *shape, selectedShapes) {
0568         if (shape->clipPath())
0569             shapesToUnclip.append(shape);
0570     }
0571     if (!shapesToUnclip.count())
0572         return;
0573 
0574     kopaCanvas()->addCommand(new KoShapeUnclipCommand(kopaDocument(), shapesToUnclip));
0575 }
0576 
0577 void KarbonView::flipVertical()
0578 {
0579     selectionFlip(false, true);
0580 }
0581 
0582 void KarbonView::flipHorizontal()
0583 {
0584     selectionFlip(true, false);
0585 }
0586 
0587 void KarbonView::selectionFlip(bool horizontally, bool vertically)
0588 {
0589     if (!horizontally && !vertically)
0590         return;
0591 
0592     KoSelection* selection = shapeManager()->selection();
0593     if( ! selection )
0594         return;
0595 
0596     QList<KoShape*> selectedShapes = selection->selectedShapes( KoFlake::StrippedSelection );
0597     const int selectedShapesCount = selectedShapes.count();
0598     if( selectedShapesCount < 1 )
0599         return;
0600 
0601     // mirror about center point
0602     QPointF mirrorCenter = selection->absolutePosition(KoFlake::CenteredPosition);
0603 
0604     QTransform mirrorMatrix;
0605     mirrorMatrix.translate(mirrorCenter.x(), mirrorCenter.y());
0606     mirrorMatrix.scale( horizontally ? -1.0 : 1.0, vertically ? -1.0 : 1.0);
0607     mirrorMatrix.translate(-mirrorCenter.x(), -mirrorCenter.y());
0608 
0609     QVector<QTransform> oldState;
0610     QVector<QTransform> newState;
0611     oldState.reserve(selectedShapesCount);
0612     newState.reserve(selectedShapesCount);
0613 
0614     foreach( KoShape* shape, selectedShapes ) {
0615         shape->update();
0616         oldState << shape->transformation();
0617         // apply the mirror transformation
0618         shape->applyAbsoluteTransformation(mirrorMatrix);
0619         newState << shape->transformation();
0620     }
0621     selection->applyAbsoluteTransformation(mirrorMatrix);
0622 
0623     KUndo2Command *cmd = new KoShapeTransformCommand(selectedShapes, oldState, newState);
0624     if (horizontally && !vertically)
0625         cmd->setText(kundo2_i18n("Mirror Horizontally"));
0626     else if (!horizontally && vertically)
0627         cmd->setText(kundo2_i18n("Mirror Vertically"));
0628     else
0629         cmd->setText(kundo2_i18n("Mirror Horizontally and Vertically"));
0630     kopaCanvas()->addCommand(cmd);
0631 }
0632 
0633 void KarbonView::closePath()
0634 {
0635     // TODO add the new close path command here
0636 }
0637 
0638 void KarbonView::combinePath()
0639 {
0640     KoSelection* selection = shapeManager()->selection();
0641     if (! selection)
0642         return;
0643 
0644     QList<KoShape*> selectedShapes = selection->selectedShapes();
0645     QList<KoPathShape*> paths;
0646 
0647     foreach(KoShape* shape, selectedShapes) {
0648         KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
0649         if (path) {
0650             KoParameterShape * paramShape = dynamic_cast<KoParameterShape*>(path);
0651             if (paramShape && paramShape->isParametricShape())
0652                 continue;
0653             paths << path;
0654             selection->deselect(shape);
0655         }
0656     }
0657 
0658     if (paths.size())
0659         kopaCanvas()->addCommand(new KoPathCombineCommand(kopaDocument(), paths));
0660 }
0661 
0662 void KarbonView::separatePath()
0663 {
0664     KoSelection* selection = shapeManager()->selection();
0665     if (! selection)
0666         return;
0667 
0668     QList<KoShape*> selectedShapes = selection->selectedShapes();
0669     QList<KoPathShape*> paths;
0670 
0671     foreach(KoShape* shape, selectedShapes) {
0672         KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
0673         if (path) {
0674             paths << path;
0675             selection->deselect(shape);
0676         }
0677     }
0678 
0679     if (!paths.size()) {
0680         return;
0681     }
0682 
0683     KUndo2Command *cmd = new KUndo2Command;
0684     cmd->setText(kundo2_i18n("Separate paths"));
0685 
0686     foreach(KoPathShape* p, paths) {
0687         QList<KoPathShape*> separatedPaths;
0688         QList<KoShape*> newShapes;
0689         if (p->separate(separatedPaths)) {
0690             foreach(KoPathShape *subPath, separatedPaths) {
0691                 new KoShapeCreateCommand(kopaDocument(), subPath, cmd);
0692                 newShapes << subPath;
0693             }
0694             // make sure we put the new subpaths into the parent
0695             // of the original path
0696             KoShapeGroup *parentGroup = dynamic_cast<KoShapeGroup*>(p->parent());
0697             if (parentGroup) {
0698                 new KoShapeGroupCommand(parentGroup, newShapes, cmd);
0699             }
0700             new KoShapeDeleteCommand(kopaDocument(), p, cmd);
0701         }
0702     }
0703     kopaCanvas()->addCommand(cmd);
0704 }
0705 
0706 void KarbonView::reversePath()
0707 {
0708     QList<KoPathShape*> paths = selectedPathShapes();
0709     if (paths.size())
0710         kopaCanvas()->addCommand(new KoPathReverseCommand(paths));
0711 }
0712 
0713 void KarbonView::intersectPaths()
0714 {
0715     booleanOperation(KarbonBooleanCommand::Intersection);
0716 }
0717 
0718 void KarbonView::subtractPaths()
0719 {
0720     booleanOperation(KarbonBooleanCommand::Subtraction);
0721 }
0722 
0723 void KarbonView::unitePaths()
0724 {
0725     booleanOperation(KarbonBooleanCommand::Union);
0726 }
0727 
0728 void KarbonView::excludePaths()
0729 {
0730     booleanOperation(KarbonBooleanCommand::Exclusion);
0731 }
0732 
0733 void KarbonView::booleanOperation(KarbonBooleanCommand::BooleanOperation operation)
0734 {
0735     KoSelection* selection = shapeManager()->selection();
0736     if (! selection)
0737         return;
0738 
0739     QList<KoShape*> selectedShapes = selection->selectedShapes();
0740     QList<KoPathShape*> paths;
0741 
0742     foreach(KoShape* shape, selectedShapes) {
0743         KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
0744         if (path) {
0745             paths << path;
0746             selection->deselect(shape);
0747         }
0748     }
0749 
0750     if (paths.size() == 2) {
0751         KUndo2Command * macro = new KUndo2Command(kundo2_i18n("Boolean Operation"));
0752         KoParameterShape * paramShape = dynamic_cast<KoParameterShape*>(paths[0]);
0753         if (paramShape && paramShape->isParametricShape())
0754             new KoParameterToPathCommand(paramShape, macro);
0755         paramShape = dynamic_cast<KoParameterShape*>(paths[1]);
0756         if (paramShape && paramShape->isParametricShape())
0757             new KoParameterToPathCommand(paramShape, macro);
0758         new KarbonBooleanCommand(kopaDocument(), paths[0], paths[1], operation, macro);
0759         new KoShapeDeleteCommand(kopaDocument(), paths[0], macro);
0760         new KoShapeDeleteCommand(kopaDocument(), paths[1], macro);
0761         kopaCanvas()->addCommand(macro);
0762     }
0763 }
0764 
0765 void KarbonView::pathSnapToGrid()
0766 {
0767     KoSelection* selection = shapeManager()->selection();
0768     if (! selection)
0769         return;
0770 
0771     QList<KoShape*> selectedShapes = selection->selectedShapes();
0772     QList<KoPathPointData> points;
0773     QVector<QPointF> offsets;
0774 
0775     // store current grid snap state
0776     bool oldSnapToGrid = kopaDocument()->gridData().snapToGrid();
0777     // enable grid snapping
0778     kopaDocument()->gridData().setSnapToGrid(true);
0779 
0780     KoSnapGuide snapGuide(kopaCanvas());
0781     snapGuide.enableSnapStrategies(KoSnapGuide::GridSnapping);
0782     snapGuide.setSnapDistance(INT_MAX);
0783 
0784     foreach(KoShape* shape, selectedShapes) {
0785         KoParameterShape * paramShape = dynamic_cast<KoParameterShape*>(shape);
0786         if (paramShape && paramShape->isParametricShape())
0787             continue;
0788 
0789         KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
0790         if (! path)
0791             continue;
0792 
0793         uint subpathCount = path->subpathCount();
0794         for (uint i = 0; i < subpathCount; ++i) {
0795             uint pointCount = path->subpathPointCount(i);
0796             for (uint j = 0; j < pointCount; ++j) {
0797                 KoPathPointIndex index(i, j);
0798                 KoPathPoint * p = path->pointByIndex(index);
0799                 if (!p)
0800                     continue;
0801 
0802                 QPointF docPoint = path->shapeToDocument(p->point());
0803                 QPointF offset = snapGuide.snap(docPoint, 0) - docPoint;
0804                 points.append(KoPathPointData(path, index));
0805                 offsets.append(offset);
0806             }
0807         }
0808     }
0809 
0810     // reset grid snapping state to old value
0811     kopaDocument()->gridData().setSnapToGrid(oldSnapToGrid);
0812 
0813     kopaCanvas()->addCommand(new KoPathPointMoveCommand(points, offsets));
0814 }
0815 
0816 void KarbonView::viewModeChanged(bool outlineMode)
0817 {
0818     if (outlineMode) {
0819         new KarbonOutlinePaintingStrategy(shapeManager());
0820     } else {
0821         shapeManager()->setPaintingStrategy(new KoShapeManagerPaintingStrategy(shapeManager()));
0822     }
0823 }
0824 
0825 void KarbonView::zoomSelection()
0826 {
0827     KoSelection* selection = shapeManager()->selection();
0828     if (! selection)
0829         return;
0830 
0831     if (! selection->count())
0832         return;
0833 
0834     const KoZoomHandler * zoomHandler = dynamic_cast<const KoZoomHandler*>(viewConverter());
0835     if (! zoomHandler)
0836         return;
0837 
0838     QRectF bbox = selection->boundingRect();
0839     QRect viewRect = zoomHandler->documentToView(bbox).toRect();
0840 
0841     kopaCanvas()->canvasController()->zoomTo(viewRect.translated(kopaCanvas()->documentOrigin()));
0842 //     QPointF newCenter = kopaCanvas()->documentOrigin() + zoomHandler->documentToView(bbox.center());
0843 //     kopaCanvas()->setPreferredCenter(newCenter.toPoint());
0844 }
0845 
0846 void KarbonView::zoomDrawing()
0847 {
0848     const KoZoomHandler * zoomHandler = dynamic_cast<const KoZoomHandler*>(kopaCanvas()->viewConverter());
0849     if (! zoomHandler)
0850         return;
0851 
0852     QRectF bbox = activePage()->contentRect();
0853     if (bbox.isNull())
0854         return;
0855 
0856     QRect viewRect = zoomHandler->documentToView(bbox).toRect();
0857     kopaCanvas()->canvasController()->zoomTo(viewRect.translated(kopaCanvas()->documentOrigin()));
0858 //     QPointF newCenter = kopaCanvas()->documentOrigin() + zoomHandler->documentToView(bbox.center());
0859 //     kopaCanvas()->setPreferredCenter(newCenter.toPoint());
0860 }
0861 
0862 void KarbonView::initActions()
0863 {
0864     // view ----->
0865     d->viewAction  = new KToggleAction(i18n("Outline &Mode"), this);
0866     actionCollection()->addAction("view_mode", d->viewAction);
0867     connect(d->viewAction, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)));
0868 
0869     // No need for the other actions in read-only (embedded) mode
0870     if (!mainWindow())
0871         return;
0872 
0873     QAction *actionImportGraphic  = new QAction(i18n("&Import Graphic..."), this);
0874     actionCollection()->addAction("file_import", actionImportGraphic);
0875     connect(actionImportGraphic, SIGNAL(triggered()), this, SLOT(fileImportGraphic()));
0876 
0877     QAction *actionEditGuides = new QAction(koIcon("edit-guides"), i18n("Edit Guides"), this);
0878     actionCollection()->addAction("edit_guides", actionEditGuides);
0879     connect(actionEditGuides, SIGNAL(triggered()), this, SLOT(editGuides()));
0880     // edit <-----
0881 
0882     // object ----->
0883     QAction *actionDuplicate  = new QAction(i18nc("Duplicate selection", "&Duplicate"), this);
0884     actionCollection()->addAction("object_duplicate", actionDuplicate);
0885     actionDuplicate->setShortcut(QKeySequence("Ctrl+D"));
0886     connect(actionDuplicate, SIGNAL(triggered()), this, SLOT(selectionDuplicate()));
0887 
0888     QAction *actionDistributeHorizontalCenter  = new QAction(koIcon("distribute-horizontal-center"), i18n("Distribute Center (Horizontal)"), this);
0889     actionCollection()->addAction("object_distribute_horizontal_center", actionDistributeHorizontalCenter);
0890     connect(actionDistributeHorizontalCenter, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalCenter()));
0891 
0892     QAction *actionDistributeHorizontalGap  = new QAction(koIcon("distribute-horizontal-equal"), i18n("Distribute Gaps (Horizontal)"), this);
0893     actionCollection()->addAction("object_distribute_horizontal_gap", actionDistributeHorizontalGap);
0894     connect(actionDistributeHorizontalGap, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalGap()));
0895 
0896     QAction *actionDistributeLeft  = new QAction(koIcon("distribute-horizontal-left"), i18n("Distribute Left Borders"), this);
0897     actionCollection()->addAction("object_distribute_horizontal_left", actionDistributeLeft);
0898     connect(actionDistributeLeft, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalLeft()));
0899 
0900     QAction *actionDistributeRight  = new QAction(koIcon("distribute-horizontal-right"), i18n("Distribute Right Borders"), this);
0901     actionCollection()->addAction("object_distribute_horizontal_right", actionDistributeRight);
0902     connect(actionDistributeRight, SIGNAL(triggered()), this, SLOT(selectionDistributeHorizontalRight()));
0903 
0904     QAction *actionDistributeVerticalCenter  = new QAction(koIcon("distribute-vertical-center"), i18n("Distribute Center (Vertical)"), this);
0905     actionCollection()->addAction("object_distribute_vertical_center", actionDistributeVerticalCenter);
0906     connect(actionDistributeVerticalCenter, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalCenter()));
0907 
0908     QAction *actionDistributeVerticalGap  = new QAction(koIcon("distribute-vertical-equal"), i18n("Distribute Gaps (Vertical)"), this);
0909     actionCollection()->addAction("object_distribute_vertical_gap", actionDistributeVerticalGap);
0910     connect(actionDistributeVerticalGap, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalGap()));
0911 
0912     QAction *actionDistributeBottom  = new QAction(koIcon("distribute-vertical-bottom"), i18n("Distribute Bottom Borders"), this);
0913     actionCollection()->addAction("object_distribute_vertical_bottom", actionDistributeBottom);
0914     connect(actionDistributeBottom, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalBottom()));
0915 
0916     QAction *actionDistributeTop  = new QAction(koIcon("distribute-vertical-top"), i18n("Distribute Top Borders"), this);
0917     actionCollection()->addAction("object_distribute_vertical_top", actionDistributeTop);
0918     connect(actionDistributeTop, SIGNAL(triggered()), this, SLOT(selectionDistributeVerticalTop()));
0919 
0920     d->showPaletteAction = new KToggleAction(i18n("Show Color Palette"), this);
0921     actionCollection()->addAction("view_show_palette", d->showPaletteAction);
0922     d->showPaletteAction->setToolTip(i18n("Show or hide color palette"));
0923     d->showPaletteAction->setChecked(true);
0924     connect(d->showPaletteAction, SIGNAL(triggered()), this, SLOT(showPalette()));
0925 
0926     d->clipObjects  = new QAction(i18n("&Clip Object"), this);
0927     actionCollection()->addAction("object_clip", d->clipObjects );
0928     connect(d->clipObjects, SIGNAL(triggered()), this, SLOT(clipObjects()));
0929 
0930     d->unclipObjects  = new QAction(i18n("&Unclip Objects"), this);
0931     actionCollection()->addAction("object_unclip", d->unclipObjects );
0932     connect(d->unclipObjects, SIGNAL(triggered()), this, SLOT(unclipObjects()));
0933 
0934     d->flipVertical = new QAction(koIcon("object-flip-vertical"), i18n("Mirror Vertically"), this);
0935     actionCollection()->addAction("object_flip_vertical", d->flipVertical);
0936     connect(d->flipVertical, SIGNAL(triggered()), this, SLOT(flipVertical()));
0937 
0938     d->flipHorizontal = new QAction(koIcon("object-flip-horizontal"), i18n("Mirror Horizontally"), this);
0939     actionCollection()->addAction("object_flip_horizontal", d->flipHorizontal);
0940     connect(d->flipHorizontal, SIGNAL(triggered()), this, SLOT(flipHorizontal()));
0941 
0942     // object <-----
0943 
0944     // path ------->
0945     d->closePath  = new QAction(i18n("&Close Path"), this);
0946     actionCollection()->addAction("close_path", d->closePath);
0947     d->closePath->setShortcut(QKeySequence("Ctrl+U"));
0948     d->closePath->setEnabled(false);
0949     connect(d->closePath, SIGNAL(triggered()), this, SLOT(closePath()));
0950 
0951     d->combinePath  = new QAction(i18n("Com&bine Path"), this);
0952     actionCollection()->addAction("combine_path", d->combinePath);
0953     d->combinePath->setShortcut(QKeySequence("Ctrl+K"));
0954     d->combinePath->setEnabled(false);
0955     connect(d->combinePath, SIGNAL(triggered()), this, SLOT(combinePath()));
0956 
0957     d->separatePath  = new QAction(i18n("Se&parate Path"), this);
0958     actionCollection()->addAction("separate_path", d->separatePath);
0959     d->separatePath->setShortcut(QKeySequence("Shift+Ctrl+K"));
0960     d->separatePath->setEnabled(false);
0961     connect(d->separatePath, SIGNAL(triggered()), this, SLOT(separatePath()));
0962 
0963     d->reversePath  = new QAction(i18n("Re&verse Path"), this);
0964     actionCollection()->addAction("reverse_path", d->reversePath);
0965     d->reversePath->setShortcut(QKeySequence("Ctrl+R"));
0966     d->reversePath->setEnabled(false);
0967     connect(d->reversePath, SIGNAL(triggered()), this, SLOT(reversePath()));
0968 
0969     d->intersectPath = new QAction(i18n("Intersect Paths"), this);
0970     actionCollection()->addAction("intersect_path", d->intersectPath);
0971     //d->intersectPath->setShortcut(QKeySequence("Shift+Ctrl+K"));
0972     d->intersectPath->setEnabled(false);
0973     connect(d->intersectPath, SIGNAL(triggered()), this, SLOT(intersectPaths()));
0974 
0975     d->subtractPath = new QAction(i18n("Subtract Paths"), this);
0976     actionCollection()->addAction("subtract_path", d->subtractPath);
0977     //d->subtractPath->setShortcut(QKeySequence("Shift+Ctrl+K"));
0978     d->subtractPath->setEnabled(false);
0979     connect(d->subtractPath, SIGNAL(triggered()), this, SLOT(subtractPaths()));
0980 
0981     d->unitePath = new QAction(i18n("Unite Paths"), this);
0982     actionCollection()->addAction("unite_path", d->unitePath);
0983     //d->unitePath->setShortcut(QKeySequence("Shift+Ctrl+K"));
0984     d->unitePath->setEnabled(false);
0985     connect(d->unitePath, SIGNAL(triggered()), this, SLOT(unitePaths()));
0986 
0987     d->excludePath = new QAction(i18n("Exclude Paths"), this);
0988     actionCollection()->addAction("exclude_path", d->excludePath);
0989     //d->excludePath->setShortcut(QKeySequence("Shift+Ctrl+K"));
0990     d->excludePath->setEnabled(false);
0991     connect(d->excludePath, SIGNAL(triggered()), this, SLOT(excludePaths()));
0992 
0993     d->pathSnapToGrid = new QAction(i18n("Snap Path to Grid"), this);
0994     actionCollection()->addAction("path_snap_to_grid", d->pathSnapToGrid);
0995     d->pathSnapToGrid->setEnabled(false);
0996     connect(d->pathSnapToGrid, SIGNAL(triggered()), this, SLOT(pathSnapToGrid()));
0997 
0998     // path <-----
0999 
1000     // view ---->
1001     QAction * zoomSelection = new QAction(koIcon("zoom-select"), i18n("Zoom to Selection"), this);
1002     actionCollection()->addAction("view_zoom_selection", zoomSelection);
1003     connect(zoomSelection, SIGNAL(triggered()), this, SLOT(zoomSelection()));
1004 
1005     QAction * zoomDrawing = new QAction(koIcon("zoom-draw"), i18n("Zoom to Drawing"), this);
1006     actionCollection()->addAction("view_zoom_drawing", zoomDrawing);
1007     connect(zoomDrawing, SIGNAL(triggered()), this, SLOT(zoomDrawing()));
1008     // view <-----
1009 }
1010 
1011 void KarbonView::mousePositionChanged(const QPoint &position)
1012 {
1013     const QPoint canvasOffset(canvasController()->canvasOffsetX(), canvasController()->canvasOffsetY() );
1014     const QPoint viewPos = position - kopaCanvas()->documentOrigin() - canvasOffset;
1015 
1016     QPointF documentPos = kopaCanvas()->viewConverter()->viewToDocument(viewPos);
1017     qreal x = kopaDocument()->unit().toUserValue(documentPos.x());
1018     qreal y = kopaDocument()->unit().toUserValue(documentPos.y());
1019 
1020     if (statusBar() && statusBar()->isVisible()) {
1021         QLocale locale;
1022         d->cursorCoords->setText(QString::fromLatin1("%1, %2").arg(locale.toString(x, 'f', 2), locale.toString(y, 'f', 2)));
1023     }
1024 }
1025 
1026 void KarbonView::reorganizeGUI()
1027 {
1028     // TODO: Find a better solution, maybe move to KoPAView?
1029     if (statusBar()) {
1030         bool show = true;
1031         if (mainWindow()) {
1032             KSharedConfigPtr config = KSharedConfig::openConfig();
1033             if (config->hasGroup("Interface")) {
1034                 KConfigGroup interfaceGroup = config->group( "Interface" );
1035                 if (!interfaceGroup.readEntry<bool>("ShowStatusBar", true)) {
1036                     show = false;
1037                 }
1038             }
1039         }
1040         statusBar()->setVisible(show);
1041     }
1042 }
1043 
1044 void KarbonView::setNumberOfRecentFiles(unsigned int number)
1045 {
1046     if (mainWindow()) {    // 0L when embedded into konq !
1047         mainWindow()->setMaxRecentItems(number);
1048     }
1049 }
1050 
1051 void KarbonView::editGuides()
1052 {
1053     KoToolManager::instance()->switchToolRequested("GuidesTool_ID");
1054 }
1055 
1056 void KarbonView::showPalette()
1057 {
1058     if(!mainWindow())
1059         return;
1060 
1061     const bool showPalette = d->showPaletteAction->isChecked();
1062     d->colorBar->setVisible(showPalette);
1063 
1064     // this will make the last setting of the ruler visibility persistent
1065     KConfigGroup interfaceGroup = KarbonFactory::global().config()->group("Interface");
1066     if (showPalette && !interfaceGroup.hasDefault("ShowPalette"))
1067         interfaceGroup.revertToDefault("ShowPalette");
1068     else
1069         interfaceGroup.writeEntry("ShowPalette", showPalette);
1070 }
1071 
1072 void KarbonView::openConfiguration()
1073 {
1074     QPointer<KarbonConfigureDialog> dialog = new KarbonConfigureDialog(this);
1075     dialog->exec();
1076     delete dialog;
1077     reorganizeGUI();
1078 }
1079 
1080 void KarbonView::selectionChanged()
1081 {
1082     if (!mainWindow())
1083         return;
1084     KoSelection *selection = kopaCanvas()->shapeManager()->selection();
1085     QList<KoShape*> selectedShapes = selection->selectedShapes(KoFlake::FullSelection);
1086     const int count = selectedShapes.count();
1087 
1088     d->closePath->setEnabled(false);
1089     d->combinePath->setEnabled(false);
1090     d->excludePath->setEnabled(false);
1091     d->intersectPath->setEnabled(false);
1092     d->subtractPath->setEnabled(false);
1093     d->unitePath->setEnabled(false);
1094     d->pathSnapToGrid->setEnabled(false);
1095     d->clipObjects->setEnabled(false);
1096     d->unclipObjects->setEnabled(false);
1097     d->flipHorizontal->setEnabled(count > 0);
1098     d->flipVertical->setEnabled(count > 0);
1099 
1100     debugKarbonUi << count << " shapes selected";
1101 
1102     if (count > 0) {
1103         uint selectedPaths = 0;
1104         uint selectedParametrics = 0;
1105         // check for different shape types for enabling specific actions
1106         foreach(KoShape* shape, selectedShapes) {
1107             if (dynamic_cast<KoPathShape*>(shape)) {
1108                 KoParameterShape * ps = dynamic_cast<KoParameterShape*>(shape);
1109                 if (ps && ps->isParametricShape())
1110                     selectedParametrics++;
1111                 else
1112                     selectedPaths++;
1113             }
1114         }
1115         debugKarbonUi << selectedPaths << " path shapes selected";
1116         debugKarbonUi << selectedParametrics << " parameter shapes selected";
1117         //TODO enable action when the ClosePath command is ported
1118         //d->closePath->setEnabled( selectedPaths > 0 );
1119         d->combinePath->setEnabled(selectedPaths > 1);
1120         d->separatePath->setEnabled(selectedPaths > 0);
1121         d->reversePath->setEnabled(selectedPaths > 0);
1122         d->excludePath->setEnabled(selectedPaths + selectedParametrics == 2);
1123         d->intersectPath->setEnabled(selectedPaths + selectedParametrics == 2);
1124         d->subtractPath->setEnabled(selectedPaths + selectedParametrics == 2);
1125         d->unitePath->setEnabled(selectedPaths + selectedParametrics == 2);
1126         d->pathSnapToGrid->setEnabled(selectedPaths > 0);
1127         d->clipObjects->setEnabled(selectedPaths > 0 && count > 1);
1128         d->unclipObjects->setEnabled(selectedShapes.first()->clipPath() != 0);
1129         // if only one shape selected, set its parent layer as the active layer
1130         if (count == 1) {
1131             KoShapeContainer * parent = selection->selectedShapes().first()->parent();
1132             while (parent) {
1133                 if (parent->parent())
1134                     parent = parent->parent();
1135                 else
1136                     break;
1137             }
1138             KoShapeLayer * layer = dynamic_cast<KoShapeLayer*>(parent);
1139             if (layer)
1140                 selection->setActiveLayer(layer);
1141         }
1142     }
1143 }
1144 
1145 void KarbonView::setCursor(const QCursor &c)
1146 {
1147     kopaCanvas()->setCursor(c);
1148 }
1149 
1150 void KarbonView::updateReadWrite(bool readwrite)
1151 {
1152     Q_UNUSED(readwrite);
1153 }
1154 
1155 QList<KoPathShape*> KarbonView::selectedPathShapes()
1156 {
1157     KoSelection* selection = shapeManager()->selection();
1158     if (! selection)
1159         return QList<KoPathShape*>();
1160 
1161     QList<KoShape*> selectedShapes = selection->selectedShapes();
1162     QList<KoPathShape*> paths;
1163 
1164     foreach(KoShape* shape, selectedShapes) {
1165         KoPathShape *path = dynamic_cast<KoPathShape*>(shape);
1166         if (path) {
1167             paths << path;
1168             selection->deselect(shape);
1169         }
1170     }
1171 
1172     return paths;
1173 }
1174 
1175 void KarbonView::applyFillToSelection()
1176 {
1177     KoSelection *selection = shapeManager()->selection();
1178     if (! selection->count())
1179         return;
1180 
1181     KoShape * shape = selection->firstSelectedShape();
1182     kopaCanvas()->addCommand(new KoShapeBackgroundCommand(selection->selectedShapes(), shape->background()));
1183 }
1184 
1185 void KarbonView::applyStrokeToSelection()
1186 {
1187     KoSelection *selection = shapeManager()->selection();
1188     if (! selection->count())
1189         return;
1190 
1191     KoShape * shape = selection->firstSelectedShape();
1192     kopaCanvas()->addCommand(new KoShapeStrokeCommand(selection->selectedShapes(), shape->stroke()));
1193 }
1194 
1195 void KarbonView::applyPaletteColor(const KoColor &color)
1196 {
1197     KoSelection *selection = shapeManager()->selection();
1198     if (! selection->count())
1199         return;
1200 
1201     int style = resourceManager()->intResource(KoCanvasResourceManager::ActiveStyleType);
1202     if (style == KoFlake::Foreground) {
1203         QList<KoShapeStrokeModel*> newStrokes;
1204         foreach(KoShape *shape, selection->selectedShapes()) {
1205             KoShapeStroke *stroke = dynamic_cast<KoShapeStroke*>(shape->stroke());
1206             if (stroke) {
1207                 // preserve stroke properties
1208                 KoShapeStroke *newStroke = new KoShapeStroke(*stroke);
1209                 newStroke->setColor(color.toQColor());
1210                 newStrokes << newStroke;
1211             } else {
1212                 newStrokes << new KoShapeStroke(1.0, color.toQColor());
1213             }
1214         }
1215         kopaCanvas()->addCommand(new KoShapeStrokeCommand(selection->selectedShapes(), newStrokes));
1216         resourceManager()->setForegroundColor(color);
1217     } else {
1218         QSharedPointer<KoShapeBackground> fill(new KoColorBackground(color.toQColor()));
1219         kopaCanvas()->addCommand(new KoShapeBackgroundCommand(selection->selectedShapes(), fill));
1220         resourceManager()->setBackgroundColor(color);
1221     }
1222 }
1223 
1224 void KarbonView::replaceActivePage(KoPAPageBase *page, KoPAPageBase *newActivePage)
1225 {
1226     if (page == activePage() ) {
1227         viewMode()->updateActivePage(newActivePage);
1228     }
1229 }
1230