F:/KPlato/koffice/libs/kofficeui/KoToolManager.cpp

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (c) 2005-2006 Boudewijn Rempt <boud@valdyas.org>
00004  * Copyright (C) 2006 Thomas Zander <zander@kde.org>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public License
00017  * along with this library; see the file COPYING.LIB.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  */
00021 #include "KoToolManager.h"
00022 #include "KoToolManager_p.h"
00023 
00024 #include <QWidget>
00025 #include <QEvent>
00026 #include <QWheelEvent>
00027 #include <QMouseEvent>
00028 #include <QPaintEvent>
00029 #include <QTabletEvent>
00030 #include <QKeyEvent>
00031 
00032 #include "KoToolRegistry.h"
00033 #include <KoTool.h>
00034 #include <KoToolBox.h>
00035 #include <KoCreateShapesToolFactory.h>
00036 #include <KoCreateShapesTool.h>
00037 #include <KoInteractionToolFactory.h>
00038 #include <KoPointerEvent.h>
00039 #include <KoShapeControllerBase.h>
00040 #include <KoCanvasController.h>
00041 #include <KoShapeRegistry.h>
00042 #include <KoShapeManager.h>
00043 #include <KoInputDevice.h>
00044 #include <kactioncollection.h>
00045 #include <kdebug.h>
00046 #include <kstaticdeleter.h>
00047 
00048 #include <QStringList>
00049 #include <QAbstractButton>
00050 #include <QApplication>
00051 
00052 namespace {
00053 
00054     // Time in ms that must pass after a tablet event before a mouse event is allowed to
00055     // change the input device to the mouse. This is needed because mouse events are always
00056     // sent to a receiver if it does not accept the tablet event.
00057     static const int MOUSE_CHANGE_EVENT_DELAY = 100;
00058 
00059 
00060     // Helper class to determine when the user might switch between
00061     // tablet and mouse.
00062     class TabletProximityFilter {
00063     public:
00064 
00065         TabletProximityFilter( KoToolManager * manager )
00066             : m_manager( manager )
00067             {
00068             }
00069 
00070         virtual ~TabletProximityFilter();
00071 
00072         bool eventFilter( QObject * object,  QEvent * event ) {
00073 
00074             if ( object == qApp ) {
00075                 switch( event->type() ) {
00076                     case QEvent::TabletEnterProximity:
00077                         break;
00078                     case QEvent::TabletLeaveProximity:
00079                         break;
00080                     default:
00081                         break;
00082                 }
00083             }
00084             return false;
00085         }
00086 
00087     private:
00088 
00089         KoToolManager * m_manager;
00090     };
00091 
00092 }
00093 
00094 // ******** DummyTool **********
00095 class DummyTool : public KoTool {
00096 
00097 public:
00098 
00099     DummyTool() : KoTool(0) {}
00100     ~DummyTool() {}
00101     void paint( QPainter &, KoViewConverter &) {}
00102     void mousePressEvent( KoPointerEvent *) {}
00103     void mouseMoveEvent( KoPointerEvent *) {}
00104     void mouseReleaseEvent( KoPointerEvent *) {}
00105 
00106 };
00107 
00108 
00109 
00110 // ******** KoToolManager **********
00111 KoToolManager::KoToolManager()
00112     : QObject()
00113     , m_activeCanvas(0)
00114     , m_activeTool(0)
00115 {
00116     m_dummyTool = new DummyTool();
00117     connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)),
00118             this, SLOT(movedFocus(QWidget*,QWidget*)));
00119 }
00120 
00121 KoToolManager::~KoToolManager() {
00122     delete m_dummyTool;
00123 }
00124 
00125 void KoToolManager::paint( QPainter &painter, KoViewConverter &converter )
00126 {
00127     if (m_activeTool) m_activeTool->paint(painter, converter);
00128 }
00129 
00130 void KoToolManager::repaintDecorations()
00131 {
00132     if (m_activeTool) m_activeTool->repaintDecorations();
00133 }
00134 
00135 void KoToolManager::tabletEvent( QTabletEvent *event, const QPointF &pnt )
00136 {
00137     KoPointerEvent ev( event, pnt );
00138     switch( event->type() ) {
00139     case ( QEvent::TabletPress ):
00140         if (m_activeTool) m_activeTool->mousePressEvent( &ev );
00141         break;
00142     case ( QEvent::TabletRelease ):
00143         if (m_activeTool) m_activeTool->mouseReleaseEvent( &ev );
00144         break;
00145     case ( QEvent::TabletMove ):
00146     default:
00147         if (m_activeTool) m_activeTool->mouseMoveEvent( &ev );
00148     }
00149 }
00150 
00151 void KoToolManager::mousePressEvent( QMouseEvent *event, const QPointF &pnt )
00152 {
00153     KoPointerEvent ev( event, pnt );
00154     if (m_activeTool) m_activeTool->mousePressEvent( &ev );
00155 }
00156 
00157 void KoToolManager::mouseDoubleClickEvent( QMouseEvent *event, const QPointF &pnt )
00158 {
00159     KoPointerEvent ev( event, pnt );
00160     if (m_activeTool) m_activeTool->mouseDoubleClickEvent( &ev );
00161 }
00162 
00163 void KoToolManager::mouseMoveEvent( QMouseEvent *event, const QPointF &pnt )
00164 {
00165     KoPointerEvent ev( event, pnt );
00166     if (m_activeTool) m_activeTool->mouseMoveEvent( &ev );
00167 }
00168 
00169 void KoToolManager::mouseReleaseEvent( QMouseEvent *event, const QPointF &pnt )
00170 {
00171     KoPointerEvent ev( event, pnt );
00172     if (m_activeTool) m_activeTool->mouseReleaseEvent( &ev );
00173 }
00174 
00175 void KoToolManager::keyPressEvent(QKeyEvent *event)
00176 {
00177     if (m_activeTool) m_activeTool->keyPressEvent( event );
00178 }
00179 
00180 void KoToolManager::keyReleaseEvent(QKeyEvent *event)
00181 {
00182     if (m_activeTool) m_activeTool->keyReleaseEvent( event );
00183 }
00184 
00185 void KoToolManager::wheelEvent ( QWheelEvent * event, const QPointF &pnt )
00186 {
00187     KoPointerEvent ev( event, pnt );
00188     if (m_activeTool) m_activeTool->wheelEvent( &ev );
00189 }
00190 
00191 
00192 void KoToolManager::setup() {
00193     if (m_tools.size() > 0)
00194         return;
00195 
00196     // add defaults. XXX: Make these settable? We have not yet solved
00197     // the problem of application-specific versus generic flake tools,
00198     // have we?
00199     m_tools.append( new ToolHelper(new KoCreateShapesToolFactory(this, QStringList())) );
00200     m_defaultTool = new ToolHelper(new KoInteractionToolFactory(this, QStringList()));
00201     m_tools.append(m_defaultTool);
00202 
00203     KoShapeRegistry::instance();
00204     KoToolRegistry *registry = KoToolRegistry::instance();
00205     foreach(QString id, registry->keys()) {
00206         ToolHelper *t = new ToolHelper(registry->get(id));
00207         connect(t, SIGNAL(toolActivated(ToolHelper*)), this, SLOT(toolActivated(ToolHelper*)));
00208         m_tools.append(t);
00209     }
00210 
00211     // connect to all tools so we can hear their button-clicks
00212     foreach(ToolHelper *tool, m_tools)
00213         connect(tool, SIGNAL(toolActivated(ToolHelper*)), this, SLOT(toolActivated(ToolHelper*)));
00214 }
00215 
00216 KoToolBox *KoToolManager::toolBox(const QString &applicationName) {
00217     setup();
00218     KoToolBox *toolBox = new KoToolBox();
00219     foreach(ToolHelper *tool, m_tools) {
00220         QAbstractButton *but = tool->createButton();
00221         toolBox->addButton(but, tool->toolType(), tool->priority(), tool->uniqueId());
00222         if (tool->toolType() == KoToolFactory::dynamicToolType())
00223             toolBox->setVisibilityCode(but, tool->activationShapeId());
00224     }
00225 
00226     toolBox->setup();
00227     toolBox->setWindowTitle(applicationName);
00228     toolBox->setObjectName("ToolBox_"+ applicationName);
00229     connect(this, SIGNAL(changedTool(int)), toolBox, SLOT(setActiveTool(int)));
00230     connect(this, SIGNAL(toolCodesSelected(QList<QString>)),
00231             toolBox, SLOT(setButtonsVisible(QList<QString>)));
00232     QList<QString> empty;
00233     toolBox->setButtonsVisible(empty);
00234     toolBox->setActiveTool(m_defaultTool->uniqueId());
00235     return toolBox;
00236 }
00237 
00238 void KoToolManager::registerTools(KActionCollection *ac) {
00239     Q_UNUSED(ac);
00240     setup();
00241     // TODO
00242 }
00243 
00244 void KoToolManager::addControllers(KoCanvasController *controller, KoShapeControllerBase *sc) {
00245     if (m_canvases.contains(controller))
00246         return;
00247     setup();
00248     m_canvases.append(controller);
00249     m_shapeControllers.insert(controller, sc);
00250     if (m_activeCanvas == 0)
00251         m_activeCanvas = controller;
00252     if (controller->canvas())
00253         attachCanvas(controller);
00254     connect(controller, SIGNAL(canvasRemoved(KoCanvasController*)), this, SLOT(detachCanvas(KoCanvasController*)));
00255     connect(controller, SIGNAL(canvasSet(KoCanvasController*)), this, SLOT(attachCanvas(KoCanvasController*)));
00256 }
00257 
00258 void KoToolManager::removeCanvasController(KoCanvasController *controller) {
00259     m_canvases.removeAll(controller);
00260     m_shapeControllers.remove(controller);
00261     QMap<QString, KoTool*> toolsMap = m_allTools.value(controller);
00262     foreach(KoTool *tool, toolsMap.values()) {
00263         m_uniqueToolIds.remove(tool);
00264         delete tool;
00265     }
00266     m_allTools.remove(controller);
00267     if (controller->canvas())
00268         detachCanvas(controller);
00269     disconnect(controller, SIGNAL(canvasRemoved(KoCanvasController*)), this, SLOT(detachCanvas(KoCanvasController*)));
00270     disconnect(controller, SIGNAL(canvasSet(KoCanvasController*)), this, SLOT(attachCanvas(KoCanvasController*)));
00271 }
00272 
00273 void KoToolManager::toolActivated(ToolHelper *tool) {
00274 
00275     QMap<QString, KoTool*> toolsMap = m_allTools.value(m_activeCanvas);
00276     KoTool *t = toolsMap.value(tool->id());
00277 
00278     m_activeToolId = tool->id();
00279 
00280     // cache all the selected shapes relevant to the activated tool
00281     if ( m_activeToolId != KoInteractionTool_ID ) {
00282         m_lastSelectedShapes.clear();
00283         KoSelection *selection = m_activeCanvas->canvas()->shapeManager()->selection();
00284         foreach( KoShape *shape, selection->selectedShapes() ) {
00285             if ( tool->activationShapeId().isNull() || tool->activationShapeId() == shape->shapeId() )
00286                 m_lastSelectedShapes.append( shape );
00287         }
00288     }
00289 
00290     switchTool(t);
00291 }
00292 
00293 void KoToolManager::switchTool(const QString &id, bool temporary) {
00294 
00295     if (!m_activeCanvas) kDebug() << kBacktrace();
00296     Q_ASSERT(m_activeCanvas);
00297     if (m_activeTool && temporary)
00298         m_stack.push(m_activeToolId);
00299     m_activeToolId = id;
00300     QMap<QString, KoTool*> toolsMap = m_allTools.value(m_activeCanvas);
00301     KoTool *tool = toolsMap.value(id);
00302     if (! tool) {
00303         kWarning(30004) << "Tool requested " << (temporary?"temporary":"") << "switch to unknown tool: '" << id << "'\n";
00304         return;
00305     }
00306     switchTool(tool);
00307 }
00308 
00309 void KoToolManager::switchTool(KoTool *tool) {
00310 
00311     if (!tool) kDebug() << kBacktrace();
00312     Q_ASSERT(tool);
00313     if (m_activeCanvas == 0) {
00314         return;
00315     }
00316     if (m_activeTool) {
00317         m_activeTool->deactivate();
00318         disconnect(m_activeTool, SIGNAL(sigCursorChanged(QCursor)),
00319                 this, SLOT(updateCursor(QCursor)));
00320         disconnect(m_activeTool, SIGNAL(sigActivateTool(const QString &)),
00321                 this, SLOT(switchToolRequested(const QString &)));
00322         disconnect(m_activeTool, SIGNAL(sigActivateTemporary(const QString &)),
00323                 this, SLOT(switchToolTemporaryRequested(const QString &)));
00324         disconnect(m_activeTool, SIGNAL(sigDone()), this, SLOT(switchBackRequested()));
00325     }
00326     m_activeTool = tool;
00327     connect(m_activeTool, SIGNAL(sigCursorChanged(QCursor)),
00328             this, SLOT(updateCursor(QCursor)));
00329     connect(m_activeTool, SIGNAL(sigActivateTool(const QString &)),
00330             this, SLOT(switchToolRequested(const QString &)));
00331     connect(m_activeTool, SIGNAL(sigActivateTemporary(const QString &)),
00332             this, SLOT(switchToolTemporaryRequested(const QString &)));
00333     connect(m_activeTool, SIGNAL(sigDone()), this, SLOT(switchBackRequested()));
00334 
00335     // and set it.
00336     foreach(KoCanvasController *controller, m_canvases) {
00337         if (!controller->canvas())
00338             continue;
00339         // XXX: Obsolete with toolproxy? (Did I write this XXX? BSAR)
00340         // controller->canvas()->setTool(controller==m_activeCanvas ? m_activeTool : m_dummyTool);
00341         // we expect the tool to emit a cursor on activation.  This is for quick-fail :)
00342         controller->canvas()->canvasWidget()->setCursor(Qt::ForbiddenCursor);
00343     }
00344     m_activeTool->activate();
00345     emit changedTool(m_uniqueToolIds.value(m_activeTool));
00346 }
00347 
00348 void KoToolManager::attachCanvas(KoCanvasController *controller) {
00349     QMap<QString, KoTool*> toolsMap;
00350     foreach(ToolHelper *tool, m_tools) {
00351         kDebug() << "Creating tool " << tool->id() << ", " << tool->activationShapeId() << endl;
00352         KoTool *tl = tool->createTool(controller->canvas());
00353         m_uniqueToolIds.insert(tl, tool->uniqueId());
00354         toolsMap.insert(tool->id(), tl);
00355     }
00356     KoCreateShapesTool *createTool = dynamic_cast<KoCreateShapesTool*>(toolsMap.value(KoCreateShapesTool_ID));
00357     Q_ASSERT(createTool);
00358     createTool->setShapeController(m_shapeControllers[controller]);
00359     QString id = KoShapeRegistry::instance()->keys()[0];
00360     createTool->setShapeId(id);
00361 
00362     m_allTools.remove(controller);
00363     m_allTools.insert(controller, toolsMap);
00364 
00365     if (m_activeTool == 0)
00366         toolActivated(m_defaultTool);
00367     else {
00368         // XXX: Obsolete?
00369         // controller->canvas()->setTool(m_dummyTool);
00370         controller->canvas()->canvasWidget()->setCursor(Qt::ForbiddenCursor);
00371     }
00372 
00373     Connector *connector = new Connector(controller->canvas()->shapeManager());
00374     connect(connector, SIGNAL(selectionChanged(QList<KoShape*>)), this,
00375             SLOT(selectionChanged(QList<KoShape*>)));
00376 }
00377 
00378 void KoToolManager::movedFocus(QWidget *from, QWidget *to) {
00379     Q_UNUSED(from);
00380     if (to == 0 || to == m_activeCanvas)
00381         return;
00382 
00383     KoCanvasController *newCanvas = 0;
00384     // if the 'to' is one of our canvasses, or one of its children, then switch.
00385     foreach(KoCanvasController* canvas, m_canvases) {
00386         if (canvas == to || canvas->canvas()->canvasWidget() == to) {
00387             newCanvas = canvas;
00388             break;
00389         }
00390     }
00391 
00392     if (newCanvas == 0)
00393         return;
00394     if (newCanvas == m_activeCanvas)
00395         return;
00396     if (m_activeCanvas) {
00397         // XXX: Obsolete?
00398         // m_activeCanvas->canvas()->setTool(m_dummyTool);
00399         m_activeCanvas->canvas()->canvasWidget()->setCursor(Qt::ForbiddenCursor);
00400     }
00401     m_activeCanvas = newCanvas;
00402 
00403     switchTool(m_activeToolId, false);
00404     selectionChanged(m_activeCanvas->canvas()->shapeManager()->selection()->selectedShapes().toList());
00405 }
00406 
00407 void KoToolManager::detachCanvas(KoCanvasController *controller) {
00408     if (m_activeCanvas == controller)
00409         m_activeCanvas = 0;
00410     m_activeTool = 0;
00411     QMap<QString, KoTool*> toolsMap = m_allTools.value(controller);
00412     foreach(KoTool *tool, toolsMap.values())
00413         delete tool;
00414     toolsMap.clear();
00415     // XXX: Obsolete?
00416     //controller->canvas()->setTool(m_dummyTool);
00417 }
00418 
00419 void KoToolManager::updateCursor(QCursor cursor) {
00420     Q_ASSERT(m_activeCanvas);
00421     Q_ASSERT(m_activeCanvas->canvas());
00422     m_activeCanvas->canvas()->canvasWidget()->setCursor(cursor);
00423 }
00424 
00425 void KoToolManager::switchToolRequested(const QString & id) {
00426     while (!m_stack.isEmpty()) // switching means to flush the stack
00427         m_stack.pop();
00428     switchTool(id, false);
00429 }
00430 
00431 void KoToolManager::switchToolTemporaryRequested(const QString &id) {
00432     switchTool(id, true);
00433 }
00434 
00435 void KoToolManager::switchBackRequested() {
00436     if (m_stack.isEmpty()) {
00437         // default to changing to the interactionTool
00438         switchTool(KoInteractionTool_ID, false);
00439         return;
00440     }
00441     switchTool(m_stack.pop(), false);
00442 }
00443 
00444 KoShapeController *KoToolManager::shapeCreatorTool(KoCanvasBase *canvas) const {
00445     return shapeController(canvas);
00446 }
00447 
00448 KoShapeController *KoToolManager::shapeController(KoCanvasBase *canvas) const {
00449     foreach(KoCanvasController *controller, m_canvases) {
00450         if (controller->canvas() == canvas) {
00451             QMap<QString, KoTool*> tools = m_allTools.value(controller);
00452             KoShapeController *sc =
00453                 dynamic_cast<KoShapeController*>(tools.value(KoCreateShapesTool_ID));
00454             Q_ASSERT(sc /* ID changed? */);
00455             return sc;
00456         }
00457     }
00458     kWarning(30004) << "KoToolManager: can't find the canvas, did you register it?" << endl;
00459     return 0;
00460 }
00461 
00462 KoInputDevice KoToolManager::currentInputDevice() const
00463 {
00464     return KoInputDevice::mouse();
00465 }
00466 
00467 void KoToolManager::selectionChanged(QList<KoShape*> shapes) {
00468 
00469 
00470 
00471     QList<QString> types;
00472     foreach(KoShape *shape, shapes) {
00473         if (! types.contains(shape->shapeId())) {
00474             types.append(shape->shapeId());
00475         }
00476     }
00477 
00478     // check if all previous selected shapes are still selected
00479     // if not change the current tool to the default tool
00480     if ( m_activeToolId != KoInteractionTool_ID ) {
00481         foreach( KoShape* shape, m_lastSelectedShapes ) {
00482             if ( ! shapes.contains( shape ) ) {
00483                 switchTool(KoInteractionTool_ID, false);
00484                 break;
00485             }
00486         }
00487     }
00488     m_lastSelectedShapes = shapes;
00489 
00490     emit toolCodesSelected(types);
00491 }
00492 
00493 KoCanvasController *KoToolManager::activeCanvasController() const {
00494     return m_activeCanvas;
00495 }
00496 
00497 //static
00498 KoToolManager* KoToolManager::s_instance = 0;
00499 static KStaticDeleter<KoToolManager> staticToolManagerDeleter;
00500 
00501 KoToolManager* KoToolManager::instance() {
00502     if (s_instance == 0)
00503         staticToolManagerDeleter.setObject(s_instance, new KoToolManager());
00504     return s_instance;
00505 }
00506 
00507 #include "KoToolManager.moc"

Généré le Wed Nov 22 23:41:05 2006 pour KPlato par  doxygen 1.5.1-p1