Warning, file /office/calligra/braindump/src/View.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  Copyright (c) 2009,2010 Cyrille Berger <cberger@cberger.net>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation;
0007  * either version 2, or (at your option) any later version of the License.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public License
0015  * along with this library; see the file COPYING.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "View.h"
0021 
0022 #include <QGridLayout>
0023 #include <QString>
0024 #include <QVariant>
0025 #include <QToolBar>
0026 #include <QScrollBar>
0027 #include <QStatusBar>
0028 #include <QTimer>
0029 #include <QApplication>
0030 #include <QClipboard>
0031 #include <QPluginLoader>
0032 #include <QMimeData>
0033 #include <QDebug>
0034 #include <QAction>
0035 
0036 #include <kactioncollection.h>
0037 #include <KPluginFactory>
0038 
0039 #include <KoCanvasControllerWidget.h>
0040 #include <KoToolManager.h>
0041 #include <KoToolProxy.h>
0042 #include <KoZoomHandler.h>
0043 #include <KoShapeController.h>
0044 #include <KoShapeManager.h>
0045 #include <KoSelection.h>
0046 #include <KoMainWindow.h>
0047 #include <KoDockRegistry.h>
0048 #include <KoShapeLayer.h>
0049 #include <KoDrag.h>
0050 #include <KoCutController.h>
0051 #include <KoCopyController.h>
0052 #include "KoZoomController.h"
0053 #include <KoZoomAction.h>
0054 #include <KoIcon.h>
0055 #include "KoToolBoxFactory.h"
0056 #include <KoPluginLoader.h>
0057 #include "KoOdf.h"
0058 #include "KoShapeGroup.h"
0059 #include "KoShapeDeleteCommand.h"
0060 #include "KoShapeCreateCommand.h"
0061 #include "KoShapeGroupCommand.h"
0062 #include "KoShapeUngroupCommand.h"
0063 
0064 #include "Canvas.h"
0065 #include "RootSection.h"
0066 #include "Section.h"
0067 #include "ViewManager.h"
0068 #include "import/DockerManager.h"
0069 #include "MainWindow.h"
0070 #include "SectionContainer.h"
0071 #include "SectionsBoxDock.h"
0072 #include "Layout.h"
0073 #include "SectionPropertiesDock.h"
0074 #include "commands/RememberPositionCommand.h"
0075 
0076 View::View(RootSection *document, MainWindow* parent)
0077     : QWidget(parent)
0078     , m_doc(document)
0079     , m_canvas(0)
0080     , m_activeSection(0)
0081     , m_mainWindow(parent)
0082     , m_cutController(0)
0083     , m_copyController(0)
0084 {
0085     setXMLFile("braindumpview.rc");
0086 
0087     m_doc->viewManager()->addView(this);
0088 
0089     m_editPaste = actionCollection()->addAction(KStandardAction::Paste, "edit_paste", this, SLOT(editPaste()));
0090     m_editCut = actionCollection()->addAction(KStandardAction::Cut, "edit_cut", 0, 0);
0091     m_editCopy = actionCollection()->addAction(KStandardAction::Copy, "edit_copy", 0, 0);
0092     initGUI();
0093     initActions();
0094     loadExtensions();
0095 
0096     if(m_doc->sections().count() > 0) {
0097         setActiveSection(m_doc->sections()[0]);
0098     } else {
0099         setActiveSection(0);
0100     }
0101 
0102     m_doc->viewManager()->viewHasFocus(this);
0103 }
0104 
0105 View::~View()
0106 {
0107     m_doc->viewManager()->removeView(this);
0108     KoToolManager::instance()->removeCanvasController(m_canvasController);
0109     delete m_zoomController;
0110 }
0111 
0112 
0113 Section* View::activeSection() const
0114 {
0115     return m_activeSection;
0116 }
0117 
0118 void View::initGUI()
0119 {
0120     // add all plugins.
0121     foreach(const QString & docker, KoDockRegistry::instance()->keys()) {
0122         qDebug() << "Creating docker: " << docker;
0123         KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker);
0124         m_mainWindow->createDockWidget(factory);
0125     }
0126 
0127     // Init the widgets
0128     QGridLayout * gridLayout = new QGridLayout(this);
0129     gridLayout->setMargin(0);
0130     gridLayout->setSpacing(0);
0131     setLayout(gridLayout);
0132 
0133 
0134     m_canvasController = new KoCanvasControllerWidget(actionCollection(), this);
0135     m_canvasController->setCanvasMode(KoCanvasController::Infinite);
0136 
0137     createCanvas(0);
0138 
0139     KoToolManager::instance()->addController(m_canvasController);
0140     KoToolManager::instance()->registerTools(actionCollection(), m_canvasController);
0141 
0142     m_zoomController = new KoZoomController(m_canvasController, &m_zoomHandler, actionCollection());
0143     connect(m_zoomController, SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)),
0144             this, SLOT(slotZoomChanged(KoZoomMode::Mode,qreal)));
0145 
0146     m_zoomAction = m_zoomController->zoomAction();
0147     m_mainWindow->addStatusBarItem(m_zoomAction->createWidget(m_mainWindow->statusBar()), 0, this);
0148 
0149     m_zoomController->setZoomMode(KoZoomMode::ZOOM_WIDTH);
0150 
0151     gridLayout->addWidget(m_canvasController, 1, 1);
0152 
0153     connect(m_canvasController->proxyObject, SIGNAL(canvasMousePositionChanged(QPoint)),
0154             this, SLOT(updateMousePosition(QPoint)));
0155 
0156     KoToolBoxFactory toolBoxFactory;
0157     m_mainWindow->createDockWidget(&toolBoxFactory);
0158 
0159     connect(m_canvasController, SIGNAL(toolOptionWidgetsChanged(QList<QPointer<QWidget> >)), m_mainWindow->dockerManager(), SLOT(newOptionWidgets(QList<QPointer<QWidget> >)));
0160 
0161     SectionsBoxDockFactory structureDockerFactory;
0162     m_sectionsBoxDock = qobject_cast<SectionsBoxDock*>(m_mainWindow->createDockWidget(&structureDockerFactory));
0163     Q_ASSERT(m_sectionsBoxDock);
0164     m_sectionsBoxDock->setup(m_doc, this);
0165 
0166     SectionPropertiesDockFactory sectionPropertiesDockerFactory;
0167     m_sectionPropertiesDock = qobject_cast<SectionPropertiesDock*>(m_mainWindow->createDockWidget(&sectionPropertiesDockerFactory));
0168     Q_ASSERT(m_sectionPropertiesDock);
0169     m_sectionPropertiesDock->setRootSection(m_doc);
0170 
0171     KoToolManager::instance()->requestToolActivation(m_canvasController);
0172 
0173     show();
0174 }
0175 
0176 void View::initActions()
0177 {
0178     connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
0179     clipboardDataChanged();
0180     actionCollection()->addAction(KStandardAction::SelectAll,  "edit_select_all", this, SLOT(editSelectAll()));
0181     actionCollection()->addAction(KStandardAction::Deselect,  "edit_deselect_all", this, SLOT(editDeselectAll()));
0182 
0183     m_deleteSelectionAction = new QAction(koIcon("edit-delete"), i18n("D&elete"), this);
0184     actionCollection()->addAction("edit_delete", m_deleteSelectionAction);
0185     actionCollection()->setDefaultShortcut(m_deleteSelectionAction, QKeySequence("Del"));
0186     connect(m_deleteSelectionAction, SIGNAL(triggered()), this, SLOT(editDeleteSelection()));
0187 
0188     // Shapes menu
0189     // TODO: get an icon "edit-duplicate"
0190     QAction *actionDuplicate  = new QAction(i18nc("Duplicate selection", "&Duplicate"), this);
0191     actionCollection()->addAction("shapes_duplicate", actionDuplicate);
0192     actionCollection()->setDefaultShortcut(actionDuplicate, QKeySequence("Ctrl+D"));
0193     connect(actionDuplicate, SIGNAL(triggered()), this, SLOT(selectionDuplicate()));
0194 
0195     m_groupShapes = new QAction(koIcon("object-group"), i18n("Group Shapes"), this);
0196     actionCollection()->addAction("shapes_group", m_groupShapes);
0197     actionCollection()->setDefaultShortcut(m_groupShapes, QKeySequence("Ctrl+G"));
0198     connect(m_groupShapes, SIGNAL(triggered()), this, SLOT(groupSelection()));
0199 
0200     m_ungroupShapes  = new QAction(koIcon("object-ungroup"), i18n("Ungroup Shapes"), this);
0201     actionCollection()->addAction("shapes_ungroup", m_ungroupShapes);
0202     actionCollection()->setDefaultShortcut(m_ungroupShapes, QKeySequence("Ctrl+Shift+G"));
0203     connect(m_ungroupShapes, SIGNAL(triggered()), this, SLOT(ungroupSelection()));
0204 
0205 }
0206 
0207 void View::loadExtensions()
0208 {
0209     const QList<KPluginFactory *> pluginFactories =
0210         KoPluginLoader::instantiatePluginFactories(QStringLiteral("braindump/extensions"));
0211 
0212     foreach (KPluginFactory* factory, pluginFactories) {
0213         QObject *object = factory->create<QObject>(this, QVariantList());
0214         KXMLGUIClient *clientPlugin = dynamic_cast<KXMLGUIClient*>(object);
0215         if (clientPlugin) {
0216             insertChildClient(clientPlugin);
0217         } else {
0218             // not our/valid plugin, so delete the created object
0219             object->deleteLater();
0220         }
0221     }
0222 }
0223 
0224 
0225 void View::editPaste()
0226 {
0227     m_canvas->toolProxy()->paste();
0228 }
0229 
0230 void View::editDeleteSelection()
0231 {
0232     m_canvas->toolProxy()->deleteSelection();
0233 }
0234 
0235 void View::editSelectAll()
0236 {
0237     KoSelection* selection = canvas()->shapeManager()->selection();
0238     if(!selection)
0239         return;
0240 
0241     KoShapeLayer *layer = activeSection()->sectionContainer()->layer();
0242 
0243     QList<KoShape*> layerShapes(layer->shapes());
0244     foreach(KoShape * layerShape, layerShapes) {
0245         selection->select(layerShape);
0246         layerShape->update();
0247     }
0248 }
0249 
0250 void View::editDeselectAll()
0251 {
0252     KoSelection* selection = canvas()->shapeManager()->selection();
0253     if(selection)
0254         selection->deselectAll();
0255 
0256     canvas()->update();
0257 }
0258 
0259 void View::slotZoomChanged(KoZoomMode::Mode mode, qreal zoom)
0260 {
0261     Q_UNUSED(mode);
0262     Q_UNUSED(zoom);
0263     canvas()->updateOriginAndSize();
0264     canvas()->update();
0265 }
0266 
0267 void View::createCanvas(Section* _currentSection)
0268 {
0269     Canvas* canvas = new Canvas(this, m_doc, _currentSection);
0270     m_canvasController->setCanvas(canvas);
0271     // No need to delete the current canvas, it will be deleted in Viewport::setCanvas (flake/KoCanvasController_p.cpp)
0272     m_canvas = canvas;
0273 
0274     delete m_cutController;
0275     m_cutController = new KoCutController(m_canvas, m_editCut);
0276     delete m_copyController;
0277     m_copyController = new KoCopyController(m_canvas, m_editCopy);
0278 
0279     connect(m_canvas, SIGNAL(canvasReceivedFocus()), SLOT(canvasReceivedFocus()));
0280     connect(m_canvas, SIGNAL(documentRect(QRectF)), SLOT(documentRectChanged(QRectF)));
0281     connect(m_canvasController->proxyObject, SIGNAL(moveDocumentOffset(QPoint)),
0282             m_canvas, SLOT(setDocumentOffset(QPoint)));
0283     connect(m_canvas->toolProxy(), SIGNAL(toolChanged(QString)), this, SLOT(clipboardDataChanged()));
0284 
0285     m_canvas->updateOriginAndSize();
0286 
0287     setEnabled(_currentSection);
0288 }
0289 
0290 void View::setActiveSection(Section* page)
0291 {
0292 
0293     m_activeSection = page;
0294 
0295     m_doc->setCurrentSection(page);
0296 
0297     createCanvas(m_activeSection);
0298 
0299     if(m_activeSection) {
0300         documentRectChanged(m_activeSection->layout()->boundingBox());
0301     }
0302 
0303     m_sectionsBoxDock->updateGUI();
0304     m_sectionPropertiesDock->setSection(m_activeSection);
0305 }
0306 
0307 void View::updateMousePosition(const QPoint& /*position*/)
0308 {
0309     QPoint canvasOffset(m_canvasController->canvasOffsetX(), m_canvasController->canvasOffsetY());
0310     // the offset is positive it the canvas is shown fully visible
0311     canvasOffset.setX(canvasOffset.x() < 0 ? canvasOffset.x() : 0);
0312     canvasOffset.setY(canvasOffset.y() < 0 ? canvasOffset.y() : 0);
0313 }
0314 
0315 void View::clipboardDataChanged()
0316 {
0317     const QMimeData* data = QApplication::clipboard()->mimeData();
0318     bool paste = false;
0319 
0320     if(data) {
0321         // TODO see if we can use the KoPasteController instead of having to add this feature in each calligra app.
0322         QStringList mimeTypes = m_canvas->toolProxy()->supportedPasteMimeTypes();
0323         mimeTypes << KoOdf::mimeType(KoOdf::Graphics);
0324         mimeTypes << KoOdf::mimeType(KoOdf::Presentation);
0325 
0326         foreach(const QString & mimeType, mimeTypes) {
0327             if(data->hasFormat(mimeType)) {
0328                 paste = true;
0329                 break;
0330             }
0331         }
0332 
0333     }
0334 
0335     m_editPaste->setEnabled(paste);
0336 }
0337 
0338 void View::focusInEvent(QFocusEvent * event)
0339 {
0340     QWidget::focusInEvent(event);
0341     m_doc->viewManager()->viewHasFocus(this);
0342 }
0343 
0344 void View::canvasReceivedFocus()
0345 {
0346     m_doc->viewManager()->viewHasFocus(this);
0347 }
0348 
0349 void View::documentRectChanged(const QRectF& bb)
0350 {
0351     QSizeF pageSize(400, 400);
0352     // Make sure we never use an empty size
0353     if(!bb.isNull() && !bb.isEmpty()) {
0354         pageSize = bb.size();
0355     }
0356     m_zoomController->setPageSize(pageSize);
0357     m_zoomController->setDocumentSize(pageSize);
0358 }
0359 
0360 void View::selectionDuplicate()
0361 {
0362     m_canvas->toolProxy()->copy();
0363     m_canvas->toolProxy()->paste();
0364 }
0365 
0366 void View::groupSelection()
0367 {
0368     KoSelection* selection = m_canvas->shapeManager()->selection();
0369     if(! selection)
0370         return;
0371 
0372     QList<KoShape*> selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection);
0373     QList<KoShape*> groupedShapes;
0374 
0375     // only group shapes with an unselected parent
0376     foreach(KoShape * shape, selectedShapes) {
0377         if(selectedShapes.contains(shape->parent()))
0378             continue;
0379         groupedShapes << shape;
0380     }
0381     KoShapeGroup *group = new KoShapeGroup();
0382     if(selection->activeLayer())
0383         selection->activeLayer()->addShape(group);
0384     KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Group shapes"));
0385     new KoShapeCreateCommand(m_activeSection->sectionContainer(), group, cmd);
0386     new KoShapeGroupCommand(group, groupedShapes, cmd);
0387     m_canvas->addCommand(cmd);
0388 }
0389 
0390 void View::ungroupSelection()
0391 {
0392     KoSelection* selection = m_canvas->shapeManager()->selection();
0393     if(! selection)
0394         return;
0395 
0396     QList<KoShape*> selectedShapes = selection->selectedShapes(KoFlake::TopLevelSelection);
0397     QList<KoShape*> containerSet;
0398 
0399     // only ungroup shape containers with an unselected parent
0400     foreach(KoShape * shape, selectedShapes) {
0401         if(selectedShapes.contains(shape->parent()))
0402             continue;
0403         containerSet << shape;
0404     }
0405 
0406     KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Ungroup shapes"));
0407 
0408     // add a ungroup command for each found shape container to the macro command
0409     foreach(KoShape * shape, containerSet) {
0410         KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
0411         if(container) {
0412             new KoShapeUngroupCommand(container, container->shapes(), QList<KoShape*>(), cmd);
0413             new KoShapeDeleteCommand(m_activeSection->sectionContainer(), container, cmd);
0414             new RememberPositionCommand(container->shapes(), cmd);
0415         }
0416     }
0417     m_canvas->addCommand(cmd);
0418 }