# -*- coding: utf-8 -*-
### Copyright (C) 2008-2012 Antonio Valentino <a_valentino@users.sf.net>
### This file is part of GSDView.
### GSDView is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.
### GSDView is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.
### You should have received a copy of the GNU General Public License
### along with GSDView; if not, write to the Free Software
### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
'''Custom QtGui.QGraphicsView component.'''
from qt import QtCore, QtGui
__author__ = 'Antonio Valentino <a_valentino@users.sf.net>'
__date__ = '$Date$'
__revision__ = '$Revision$'
# @TODO: move to gdalqt4.py
# @TODO: maybe this is not the best solution. Maybe a custom GraphicsItem
#        would be better
# @TODO: use event filters instead
[docs]class GraphicsView(QtGui.QGraphicsView):
    pass
    # @TODO: check
    #~ enter = QtCore.Signal()
    #~ leave = QtCore.Signal()
    #~ mousePositionUpdated = QtCore.Signal(QtCore.QPoint)
    #~ posMarked = QtCore.Signal(QtCore.QPoint)
    #~ newSize = QtCore.Signal(QtCore.QSize)
    #~ scaled = QtCore.Signal()
    #~ def __init__(self, *args, **kwargs):
        #~ super(GraphicsView, self).__init__(*args, **kwargs)
        #~ graphicsview.setMouseTracking(True)
    # @TODO: move to GraphicsViewMonitor
    #~ def enterEvent(self, event):
        #~ self.enter.emit()
        #~ return QtGui.QGraphicsView.enterEvent(self, event)
    # @TODO: move to GraphicsViewMonitor
    #~ def leaveEvent(self, event):
        #~ self.leave.emit()
        #~ return QtGui.QGraphicsView.leaveEvent(self, event)
    # @TODO: move to GraphicsViewMonitor
    # @TODO: use GraphicsSceneMouseMove
    #~ def mouseMoveEvent(self, event):
        #~ #if self.dragMode() == QtGui.QGraphicsView.NoDrag:
        #~ self.mousePositionUpdated.emit(event.pos())
        #~ if event.buttons() & QtCore.Qt.LeftButton:
            #~ self.posMarked.emit(event.pos())
        #~ #event.accept()
        #~ return QtGui.QGraphicsView.mouseMoveEvent(self, event)
    # @TODO: move to GraphicsViewMonitor
    # @TODO: use GraphicsSceneMousePress
    #~ def mousePressEvent(self, event):
        #~ if self.dragMode() == QtGui.QGraphicsView.NoDrag:
            #~ if event.buttons() & QtCore.Qt.LeftButton:
                #~ self.posMarked.emit(event.pos())
            #~ #event.accept()
        #~ return QtGui.QGraphicsView.mousePressEvent(self, event)
    # @TODO: move to GraphicsViewMonitor
    #~ def resizeEvent(self, event):
        #~ self.newSize.emit(event.size())
        #~ return QtGui.QGraphicsView.resizeEvent(self, event)
    ### Emit signals on transform modifications ###############################
    #~ def scale(self, sx, sy):
        #~ QtGui.QGraphicsView.scale(self, sx, sy)
        #~ self.scaled.emit()
    #~ def resetMatrix(self):
        #~ if not self.matrix().isIdentity():
            #~ QtGui.QGraphicsView.resetMatrix(self)
            #~ self.scaled.emit()
    # @TODO: remove
    #~ def clearScene(self):
        #~ scene = self.scene()
        #~ for item in scene.items():
            #~ scene.removeItem(item)
        #~ scene.setSceneRect(0, 0, 1, 1)
        #~ self.setSceneRect(scene.sceneRect())
        #~ self.resetTransform()
 
[docs]class GraphicsViewMonitor(QtCore.QObject):
    '''Emit signals when a registered graphics view changes status.
    :SIGNALS:
        * :attr:`leave`
        * :attr:`scrolled`
        * :attr:`resized`
        * :attr:`viewportResized`
        * :attr:`mouseMoved`
    '''
    ##: SIGNAL: it is emitted when the mouse pointer enterss the scene
    ##:
    ##: :C++ signature: `void enter(QGraphicsView*)`
    ###enter = QtCore.Signal(QtGui.QGraphicsScene)
    ##enter = QtCore.Signal(QtCore.QObject) # @TODO: check
    #: SIGNAL: it is emitted when the mouse pointer leaves the scene
    #:
    #: :C++ signature: `void leave(QGraphicsView*)`
    leave = QtCore.Signal(QtGui.QGraphicsScene)
    #: SIGNAL: it is emitted when a graphics view is scrolled
    #:
    #: :C++ signature: `void scrolled(QGraphicsView*)`
    scrolled = QtCore.Signal(QtGui.QGraphicsView)
    #: SIGNAL: it is emitted when the graphicsview window is resized
    #:
    #: :C++ signature: `void resized(QGraphicsView*, QSize)`
    resized = QtCore.Signal(QtGui.QGraphicsView, QtCore.QSize)
    # @TODO: explain difference with previous
    #: SIGNAL:
    #:
    #: :C++ signature: `void viewportResized(QGraphicsView*)`
    viewportResized = QtCore.Signal(QtGui.QGraphicsView)
    #: SIGNAL: it is emitted when the mouse pointer is moved on the scene
    #:
    #: :C++ signature: `void mouseMoved(QtGui.QGraphicsScene, QtCore.QPointF,
    #:                                  QtCore.Qt.MuseButtons)`
    mouseMoved = QtCore.Signal(QtGui.QGraphicsScene, QtCore.QPointF,
                               QtCore.Qt.MouseButtons)
    ##: SIGNAL:
    ##:
    ##: :C++ signature: `newPos(QtCore.QObject, QPoint)`
    ###newPos = QtCore.Signal(QtGui.QGraphicsView, QtCore.QPoint)
    ##newPos = QtCore.Signal(QtCore.QObject, QtCore.QPoint) # @TODO: check
    # @TODO: use signal mappers
    #~ def __init__(self, parent=None, **kwargs):
        #~ super(GraphicsViewMonitor, self).__init__(parent, **kwargs)
        #~ self.mappers = {}
        #~ self.mappers['scroll'] = QtCore.QSignalMapper(self,
                                                      #~ mapped=self.scrolled)
        #~ #self.mappers['scroll'].mapped.connect(self.scrolled)
        #~ self.mappers['scale'] = QtCore.QSignalMapper(self, mapped=self.scaled)
        #~ #self.mappers['scale'].mapped.connect(self.scaled)
    #~ def register(self, graphicsview):
        #~ graphicsview.horizontalScrollBar().valueChanged.connect(
                                                #~ self.mappers['scroll'].map)
        #~ graphicsview.verticalScrollBar().valueChanged.connect(
                                                #~ self.mappers['scroll'].map)
        #~ self.mappers['scroll'].setMapping(graphicsview, graphicsview)
        #~ graphicsview.viewportResized.connect(self.mappers['scale'].map)
        #~ self.mappers['scale'].setMapping(graphicsview, graphicsview)
[docs]    def register(self, graphicsview):
        graphicsview.horizontalScrollBar().valueChanged.connect(
                                    lambda: self.scrolled.emit(graphicsview))
        graphicsview.verticalScrollBar().valueChanged.connect(
                                    lambda: self.scrolled.emit(graphicsview))
        graphicsview.horizontalScrollBar().rangeChanged.connect(
                            lambda: self.viewportResized.emit(graphicsview))
        graphicsview.verticalScrollBar().rangeChanged.connect(
                            lambda: self.viewportResized.emit(graphicsview))
        graphicsview.installEventFilter(self)
        # Many views can refer to the same scene so before installing a new
        # event filter old ones are removed
        scene = graphicsview.scene()
        if scene:
            scene.removeEventFilter(self)
            scene.installEventFilter(self)
 
[docs]    def eventFilter(self, obj, event):
        # @TODO: use an event map (??)
        if event.type() == QtCore.QEvent.Resize:
            assert isinstance(obj, QtGui.QGraphicsView)
            self.resized.emit(obj, event.size())
        elif event.type() == QtCore.QEvent.GraphicsSceneMouseMove:
            assert isinstance(obj, QtGui.QGraphicsScene)
            self.mouseMoved.emit(obj, event.scenePos(), event.buttons())
        elif event.type() == QtCore.QEvent.Leave:
            # Discard events from graphicsviews
            if isinstance(obj, QtGui.QGraphicsScene):
                self.leave.emit(obj)
        return obj.eventFilter(obj, event)
    #~ def eventFilter(self, obj, event):
        #~ '''bool QObject.eventFilter (self, QObject, QEvent)'''
        #~ QEvent = QtCore.QEvent
        #~ eventmap = {
            #~ QEvent.Enter: self.enterEvent,
            #~ QEvent.Leave: self.leaveEvent,
            #~ #QEvent.GraphicsSceneMouseDoubleClick
            #~ QEvent.GraphicsSceneMouseMove: self.mouseMoveEvent,
            #~ QEvent.GraphicsSceneMousePress: self.mousePressEvent,
            #~ #QEvent.GraphicsSceneMouseRelease
            #~ #QEvent.GraphicsSceneWheel
            #~ #QEvent.MouseButtonDblClick
            #~ #QEvent.MouseButtonPress: self.mouseMoveEvent,
            #~ #QEvent.MouseButtonRelease
            #~ #QEvent.MouseMove: self.mousePressEvent,
            #~ QEvent.Resize: self.resizeEvent,
        #~ }
        #~ methd = eventmap[event.type()]
        #~ return method(object, event)
        #~ #return True # stop event
    ### Mouse events ##########################################################
    #~ def enterEvent(self, obj, event):
        #~ self.enter.emit(obj)
        #~ return obj.eventFilter(obj, event)
    #~ def leaveEvent(self, obj, event):
        #~ self.leave.emit(obj)
        #~ return obj.eventFilter(obj, event)
    #~ def mouseMoveEvent(self, obj, event):
        #~ self.mouseMove.emit(obj, event.pos())
        #~ if event.buttons() & QtCore.Qt.LeftButton:
            #~ self.newPos.emit(obj, event.pos())
        #~ return obj.eventFilter(obj, event)
    #~ def mousePressEvent(self, obj, event):
        #~ if self.dragMode() == QtGui.QGraphicsView.NoDrag:
            #~ if event.buttons() & QtCore.Qt.LeftButton:
                #~ self.newPos.emit(obj, event.pos())
            #~ #event.accept()
        #~ return obj.eventFilter(obj, event)