#!/usr/bin/env python

"""PyQt4 port of the painting/svgviewer example from Qt v4.x"""

import sys
from PyQt4 import QtCore, QtGui, QtOpenGL, QtSvg

import svgviewer_rc


class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        self.currentPath = QtCore.QString()

        self.area = SvgWindow()

        fileMenu = QtGui.QMenu(self.tr("&File"), self)
        self.openAction = fileMenu.addAction(self.tr("&Open..."))
        self.openAction.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+O")))
        self.quitAction = fileMenu.addAction(self.tr("E&xit"))
        self.quitAction.setShortcut(QtGui.QKeySequence(self.tr("Ctrl+Q")))

        self.menuBar().addMenu(fileMenu)

        rendererMenu = QtGui.QMenu(self.tr("&Renderer"), self)
        self.nativeAction = rendererMenu.addAction(self.tr("&Native"))
        self.nativeAction.setCheckable(True)

        if QtOpenGL.QGLFormat.hasOpenGL():
            self.glAction = rendererMenu.addAction(self.tr("&OpenGL"))
            self.glAction.setCheckable(True)

        self.imageAction = rendererMenu.addAction(self.tr("&Image"))
        self.imageAction.setCheckable(True)
        self.imageAction.setChecked(True)

        rendererGroup = QtGui.QActionGroup(self)
        rendererGroup.addAction(self.nativeAction)

        if QtOpenGL.QGLFormat.hasOpenGL():
            rendererGroup.addAction(self.glAction)

        rendererGroup.addAction(self.imageAction)

        self.menuBar().addMenu(rendererMenu)

        self.connect(self.openAction, QtCore.SIGNAL("triggered()"), self.openFile)
        self.connect(self.quitAction, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("quit()"))
        self.connect(rendererGroup, QtCore.SIGNAL("triggered(QAction *)"), self.setRenderer)

        self.setCentralWidget(self.area)
        self.setWindowTitle(self.tr("SVG Viewer"))

    def openFile(self, path=""):
        path = QtCore.QString(path)
        if path.isEmpty():
            fileName = QtGui.QFileDialog.getOpenFileName(self, self.tr("Open SVG File"),
                                                         self.currentPath, "*.svg")
        else:
            fileName = path

        if not fileName.isEmpty():
            self.area.openFile(fileName)
            if not fileName.startsWith(":/"):
                self.currentPath = fileName
                self.setWindowTitle(self.tr("%1 - SVGViewer").arg(self.currentPath))

    def setRenderer(self, action):
        if action == self.nativeAction:
            self.area.setRenderer(SvgWindow.Native)
        elif action == self.glAction:
            if QtOpenGL.QGLFormat.hasOpenGL():
                self.area.setRenderer(SvgWindow.OpenGL)
        elif action == self.imageAction:
            self.area.setRenderer(SvgWindow.Image)


class SvgWindow(QtGui.QScrollArea):
    Native, OpenGL, Image = range(3)

    def __init__(self):
        QtGui.QScrollArea.__init__(self)

        self.mousePressPos = QtCore.QPoint()
        self.scrollBarValuesOnMousePress = QtCore.QPoint()
        self.currentPath = QtCore.QString()

        self.view = QtGui.QWidget(self)
        self.renderer = SvgWindow.Image
        self.setWidget(self.view)

    def openFile(self, path):
        self.currentPath = path
        self.setRenderer(self.renderer)

    def setRenderer(self, renderer):
        self.renderer = renderer

        if self.renderer == SvgWindow.OpenGL:
            if QtOpenGL.QGLFormat.hasOpenGL():
                view = SvgGLView(self.currentPath, self)
            else:
                view = QtGui.QWidget()
        elif self.renderer == SvgWindow.Image:
            view = SvgRasterView(self.currentPath, self)
        else:
            view = SvgNativeView(self.currentPath, self)

        self.setWidget(view)
        view.show()

    def mousePressEvent(self, event):
        self.mousePressPos = QtCore.QPoint(event.pos())
        self.scrollBarValuesOnMousePress.setX(self.horizontalScrollBar().value())
        self.scrollBarValuesOnMousePress.setY(self.verticalScrollBar().value())
        event.accept()

    def mouseMoveEvent(self, event):
        if self.mousePressPos.isNull():
            event.ignore()
            return

        self.horizontalScrollBar().setValue(self.scrollBarValuesOnMousePress.x() - event.pos().x() + self.mousePressPos.x())
        self.verticalScrollBar().setValue(self.scrollBarValuesOnMousePress.y() - event.pos().y() + self.mousePressPos.y())
        self.horizontalScrollBar().update()
        self.verticalScrollBar().update()
        event.accept()

    def mouseReleaseEvent(self, event):
        self.mousePressPos = QtCore.QPoint()
        event.accept()


class SvgGLView(QtOpenGL.QGLWidget):
    def __init__(self, path, parent):
        QtOpenGL.QGLWidget.__init__(self, QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers))

        self.doc = QtSvg.QSvgRenderer(path, self)
        self.connect(self.doc, QtCore.SIGNAL("repaintNeeded()"),
                     self, QtCore.SLOT("update()"))

    def paintEvent(self, e):
        p = QtGui.QPainter(self)
        self.doc.render(p)

    def sizeHint(self):
        if self.doc:
            return self.doc.defaultSize()
        return QtOpenGL.QGLWidget.sizeHint(self)

    def wheelEvent(self, e):
        diff = 0.1
        size = QtCore.QSize(self.doc.defaultSize())
        width = size.width()
        height = size.height()
        if e.delta() > 0:
            width = int(self.width() + self.width() * diff)
            height = int(self.height() + self.height() * diff)
        else:
            width = int(self.width() - self.width() * diff)
            height = int(self.height() - self.height() * diff)

        self.resize(width, height)


class SvgRasterView(QtGui.QWidget):
    def __init__(self, path, parent):
        QtGui.QWidget.__init__(self, parent)

        self.buffer = QtGui.QImage()
        self.m_dirty = False

        self.doc = QtSvg.QSvgRenderer(path, self)
        self.connect(self.doc, QtCore.SIGNAL("repaintNeeded()"), self.poluteImage)

    def paintEvent(self, e):
        if self.buffer.size() != self.size() or self.m_dirty:
            self.buffer = QtGui.QImage(self.size(), QtGui.QImage.Format_ARGB32_Premultiplied)
            p = QtGui.QPainter(self.buffer)
            p.setViewport(0, 0, self.width(), self.height())
            p.eraseRect(0, 0, self.width(), self.height())
            self.doc.render(p)

        pt = QtGui.QPainter(self)
        pt.drawImage(0, 0, self.buffer)

    def sizeHint(self):
        if self.doc:
            return self.doc.defaultSize()
        return QtGui.QWidget.sizeHint(self)

    def poluteImage(self):
        self.m_dirty = True
        self.update()

    def wheelEvent(self, e):
        diff = 0.1
        size = QtCore.QSize(self.doc.defaultSize())
        width = size.width()
        height = size.height()
        if e.delta() > 0:
            width = int(self.width() + self.width() * diff)
            height = int(self.height() + self.height() * diff)
        else:
            width = int(self.width() - self.width() * diff)
            height = int(self.height() - self.height() * diff)

        self.resize(width, height)


class SvgNativeView(QtGui.QWidget):
    def __init__(self, path, parent):
        QtGui.QWidget.__init__(self, parent)

        self.doc = QtSvg.QSvgRenderer(path, self)
        self.connect(self.doc, QtCore.SIGNAL("repaintNeeded()"),
                     self, QtCore.SLOT("update()"))

    def paintEvent(self, e):
        p = QtGui.QPainter(self)
        p.setViewport(0, 0, self.width(), self.height())
        self.doc.render(p)

    def sizeHint(self):
        if self.doc:
            return self.doc.defaultSize()
        return QtGui.QWidget.sizeHint(self)

    def wheelEvent(self, e):
        diff = 0.1
        size = QtCore.QSize(self.doc.defaultSize())
        width = size.width()
        height = size.height()
        if e.delta() > 0:
            width = int(self.width() + self.width() * diff)
            height = int(self.height() + self.height() * diff)
        else:
            width = int(self.width() - self.width() * diff)
            height = int(self.height() - self.height() * diff)

        self.resize(width, height)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    window = MainWindow()
    if len(sys.argv) == 2:
        window.openFile(sys.argv[1])
    else:
        window.openFile(":/files/cubic.svg")
    window.show()
    sys.exit(app.exec_())
