# -*- coding: utf-8 -*-

# Copyright (c) 2004 - 2006 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the UI Previewer main window.
"""

import sys

from qt import *
from qtui import QWidgetFactory

from KdeQt import KQFileDialog, KQMessageBox
from KdeQt.KQPrinter import KQPrinter
import KdeQt

import Preferences
import UI.PixmapCache


class UIPreviewer(QMainWindow):
    """
    Class implementing the UI Previewer main window.
    """
    def __init__(self, filename = None, parent = None, name = None):
        """
        Constructor
        
        @param filename name of a UI file to load
        @param parent parent widget of this window (QWidget)
        @param name name of this window (string or QString)
        """
        self.mainWidget = None
        self.currentFile = QDir.homeDirPath()
        
        QMainWindow.__init__(self, parent, name, Qt.WDestructiveClose)
        self.statusBar()
        
        self.setIcon(UI.PixmapCache.getPixmap("eric.png"))
        self.setCaption(self.trUtf8("UI Previewer"))

        if not name:
            self.setName("UIPreviewer")

        self.setCentralWidget(QWidget(self, "qt_central_widget"))
        UIPreviewerLayout = QVBoxLayout(self.centralWidget(), 6, 6, "UIPreviewerLayout")

        styleLayout = QHBoxLayout(None,0,6,"styleLayout")

        self.styleLabel = QLabel(self.trUtf8("Select GUI Theme"), 
            self.centralWidget(), "styleLabel")
        styleLayout.addWidget(self.styleLabel)

        self.styleCombo = QComboBox(0, self.centralWidget(), "styleCombo")
        QToolTip.add(self.styleCombo, self.trUtf8("Select the GUI Theme"))
        styleLayout.addWidget(self.styleCombo)
        self.styleCombo.insertStringList(QStyleFactory().keys())
        self.styleCombo.setCurrentItem(\
            Preferences.Prefs.settings.readNumEntry('/eric3/UIPreviewer/style')[0])
        
        styleSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        styleLayout.addItem(styleSpacer)
        UIPreviewerLayout.addLayout(styleLayout)

        self.previewSV = QScrollView(self.centralWidget(), "preview")
        self.previewSV.setFrameShape(QFrame.NoFrame)
        self.previewSV.setFrameShadow(QFrame.Plain)
        UIPreviewerLayout.addWidget(self.previewSV)
        self.preview = QVBox(self.previewSV.viewport())
        self.previewSV.addChild(self.preview)

        self.resize(QSize(600, 480).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

        self.connect(self.styleCombo,SIGNAL("activated(const QString&)"),
                     self.handleStyleSelected)
        
        self.initActions()
        self.initMenus()
        self.initToolbars()
        
        self.updateActions()
        
        # defere loading of a UI file until we are shown
        self.fileToLoad = filename
        
    def show(self):
        """
        Public slot to show this dialog.
        
        This overloaded slot loads a UI file to be previewed after
        the main window has been shown. This way, previewing a dialog
        doesn't interfere with showing the main window.
        """
        QMainWindow.show(self)
        if self.fileToLoad is not None:
            fn, self.fileToLoad = (self.fileToLoad, None)
            self.loadFile(fn)
            
    def initActions(self):
        """
        Private method to define the user interface actions.
        """
        self.openAct = QAction(self.trUtf8('Open File'), 
                        QIconSet(UI.PixmapCache.getPixmap("openUI.png")), 
                        self.trUtf8('&Open File'), 
                        QKeySequence(self.trUtf8("CTRL+O","File|Open")), 
                        self)
        self.openAct.setStatusTip(self.trUtf8('Open a UI file for display'))
        self.openAct.setWhatsThis(self.trUtf8(
                """<b>Open File</b>"""
                """<p>This opens a new UI file for display.</p>"""
        ))
        self.connect(self.openAct, SIGNAL('activated()'), self.handleOpenFile)
        
        self.printAct = QAction(self.trUtf8('Print'), 
                        QIconSet(UI.PixmapCache.getPixmap("print.png")), 
                        self.trUtf8('&Print'), 
                        QKeySequence(self.trUtf8("CTRL+P","File|Print")), 
                        self)
        self.printAct.setStatusTip(self.trUtf8('Print a screen capture'))
        self.printAct.setWhatsThis(self.trUtf8(
                """<b>Print</b>"""
                """<p>Print a screen capture.</p>"""
        ))
        self.connect(self.printAct, SIGNAL('activated()'), self.handlePrint)
        
        self.imageAct = QAction(self.trUtf8('Screen Capture'), 
                        QIconSet(UI.PixmapCache.getPixmap("screenCapture.png")), 
                        self.trUtf8('&Screen Capture'), 
                        QKeySequence(self.trUtf8("CTRL+S","File|Screen Capture")), 
                        self)
        self.imageAct.setStatusTip(self.trUtf8('Save a screen capture to an image file'))
        self.imageAct.setWhatsThis(self.trUtf8(
                """<b>Screen Capture</b>"""
                """<p>Save a screen capture to an image file.</p>"""
        ))
        self.connect(self.imageAct, SIGNAL('activated()'), self.handleSaveImage)
        
        self.exitAct = QAction(self.trUtf8('Quit'), 
                        QIconSet(UI.PixmapCache.getPixmap("exit.png")), 
                        self.trUtf8('&Quit'), 
                        QKeySequence(self.trUtf8("CTRL+Q","File|Quit")), 
                        self)
        self.exitAct.setStatusTip(self.trUtf8('Quit the application'))
        self.exitAct.setWhatsThis(self.trUtf8(
                """<b>Quit</b>"""
                """<p>Quit the application.</p>"""
        ))
        self.connect(self.exitAct, SIGNAL('activated()'), qApp, SLOT('closeAllWindows()'))
        
        self.copyAct = QAction(self.trUtf8('Copy'),
                            QIconSet(UI.PixmapCache.getPixmap("editCopy.png")),
                            self.trUtf8('&Copy'),
                            QKeySequence(self.trUtf8("CTRL+C","Edit|Copy")), 
                            self)
        self.copyAct.setStatusTip(self.trUtf8('Copy screen capture to clipboard'))
        self.copyAct.setWhatsThis(self.trUtf8(
                """<b>Copy</b>"""
                """<p>Copy screen capture to clipboard.</p>"""
        ))
        self.connect(self.copyAct,SIGNAL('activated()'),self.handleCopy)
        
        self.whatsThisAct = QAction(self.trUtf8('What\'s This?'),
                                QIconSet(UI.PixmapCache.getPixmap("whatsThis.png")),
                                self.trUtf8('&What\'s This?'),
                                Qt.SHIFT+Qt.Key_F1,self)
        self.whatsThisAct.setStatusTip(self.trUtf8('Context sensitive help'))
        self.whatsThisAct.setWhatsThis(self.trUtf8(
                """<b>Display context sensitive help</b>"""
                """<p>In What's This? mode, the mouse cursor shows an arrow with a question"""
                """ mark, and you can click on the interface elements to get a short"""
                """ description of what they do and how to use them. In dialogs, this"""
                """ feature can be accessed using the context help button in the"""
                """ titlebar.</p>"""
        ))
        self.connect(self.whatsThisAct,SIGNAL('activated()'),self.whatsThis)

        self.aboutAct = QAction(self.trUtf8('About'),
                            self.trUtf8('&About'),0,self)
        self.aboutAct.setStatusTip(self.trUtf8('Display information about this software'))
        self.aboutAct.setWhatsThis(self.trUtf8(
                """<b>About</b>"""
                """<p>Display some information about this software.</p>"""
        ))
        self.connect(self.aboutAct,SIGNAL('activated()'),self.handleAbout)
                     
        self.aboutQtAct = QAction(self.trUtf8('About Qt'),
                            self.trUtf8('About &Qt'),0,self)
        self.aboutQtAct.setStatusTip(self.trUtf8('Display information about the Qt toolkit'))
        self.aboutQtAct.setWhatsThis(self.trUtf8(
                """<b>About Qt</b>"""
                """<p>Display some information about the Qt toolkit.</p>"""
        ))
        self.connect(self.aboutQtAct,SIGNAL('activated()'),self.handleAboutQt)

    def initMenus(self):
        """
        Private method to create the menus.
        """
        mb = self.menuBar()

        menu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&File'),menu)
        menu.insertTearOffHandle()
        self.openAct.addTo(menu)
        self.imageAct.addTo(menu)
        self.printAct.addTo(menu)
        menu.insertSeparator()
        self.exitAct.addTo(menu)
        
        menu = QPopupMenu(self)
        mb.insertItem(self.trUtf8("&Edit"),menu)
        menu.insertTearOffHandle()
        self.copyAct.addTo(menu)
        
        mb.insertSeparator()
        
        menu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Help'),menu)
        menu.insertTearOffHandle()
        self.aboutAct.addTo(menu)
        self.aboutQtAct.addTo(menu)
        menu.insertSeparator()
        self.whatsThisAct.addTo(menu)

    def initToolbars(self):
        """
        Private method to create the toolbars.
        """
        filetb = QToolBar(self)
        edittb = QToolBar(self)
        helptb = QToolBar(self)
        
        self.openAct.addTo(filetb)
        self.imageAct.addTo(filetb)
        self.printAct.addTo(filetb)
        filetb.addSeparator()
        self.exitAct.addTo(filetb)
        
        self.copyAct.addTo(edittb)
        
        self.whatsThisAct.addTo(helptb)

    def handleStyleSelected(self, selectedStyle):
        """
        Private slot to handle the selection of a GUI style.
        
        @param selectedStyle name of the selected style (QString)
        """
        if self.mainWidget:
            self.updateChildren(selectedStyle)
    
    def handleAbout(self):
        """
        Private slot to show the about information.
        """
        KQMessageBox.about(self, self.trUtf8("UI Previewer"), self.trUtf8(
            """<h3> About UI Previewer </h3>"""
            """<p>The UI Previewer loads and displays Qt User-Interface files"""
            """ with various styles, which are selectable via a selection list.</p>"""
        ))
    
    def handleAboutQt(self):
        """
        Private slot to show info about Qt.
        """
        QMessageBox.aboutQt(self, self.trUtf8("UI Previewer"))

    def handleOpenFile(self):
        """
        Private slot to load a new file.
        """
        fn = KQFileDialog.getOpenFileName(\
            self.currentFile,
            self.trUtf8("Qt User-Interface Files (*.ui)"),
            None, None,
            self.trUtf8("Select UI file"),
            None, 1)
        if fn.isEmpty():
            return
            
        self.loadFile(fn)
        
    def loadFile(self, fn):
        """
        Private slot to load a ui file.
        
        @param fn name of the ui file to be laoded (string or QString)
        """
        if self.mainWidget:
            self.mainWidget.close()
            del self.mainWidget
            self.mainWidget = None
            
        # load the file
        self.mainWidget = QWidgetFactory.create(fn, None, self.preview, "EmbeddedWidget")
        
        if self.mainWidget:
            self.currentFile = fn
            self.updateChildren(self.styleCombo.currentText())
            if isinstance(self.mainWidget, QDialog):
                dlg = self.mainWidget
                self.updateActions()
                dlg.exec_loop()
                if dlg == self.mainWidget:
                    self.handleCloseEvent()
                return
            elif isinstance(self.mainWidget, QMainWindow):
                self.mainWidget.show()
                self.mainWidget.installEventFilter(self)
            else:
                self.mainWidget.show()
        else:
            KQMessageBox.warning(None,
                self.trUtf8("Load UI File"),
                self.trUtf8("""<p>The file <b>%1</b> could not be loaded.</p>""")\
                    .arg(fn),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)
        self.updateActions()
    
    def updateChildren(self, style):
        """
        Private slot to change the style of the show UI.
        
        @param style name of the selected style (QString)
        """
        qApp.setOverrideCursor(Qt.waitCursor)
        self.mainWidget.setStyle(style)
        
        lst = self.mainWidget.queryList("QWidget")
        for obj in lst:
            try:
                obj.setStyle(style)
            except AttributeError:
                pass
        del lst
        
        self.mainWidget.show()
        
        self.lastStyle = QString(style)
        Preferences.Prefs.settings.writeEntry('/eric3/UIPreviewer/style', 
            self.styleCombo.currentItem())
        qApp.restoreOverrideCursor()
    
    def updateActions(self):
        """
        Private slot to update the actions state.
        """
        if self.mainWidget:
            self.imageAct.setEnabled(1)
            self.printAct.setEnabled(1)
            self.copyAct.setEnabled(1)
            self.styleCombo.setEnabled(1)
        else:
            self.imageAct.setEnabled(0)
            self.printAct.setEnabled(0)
            self.copyAct.setEnabled(0)
            self.styleCombo.setEnabled(0)

    def handleCloseEvent(self):
        """
        Private slot to handle the close event of a viewed QMainWidget.
        """
        if self.mainWidget:
            del self.mainWidget
            self.mainWidget = None
        self.updateActions()
    
    def eventFilter(self, obj, ev):
        """
        Protected method called to filter an event.
        
        @param object object, that generated the event (QObject)
        @param event the event, that was generated by object (QEvent)
        @return flag indicating if event was filtered out
        """
        if obj == self.mainWidget:
            if ev.type() == QEvent.Close:
                self.handleCloseEvent()
            return 0
        else:
            return QMainWindow.eventFilter(self, obj, ev)
    
    def handleSaveImage(self):
        """
        Private slot to handle the Save Image menu action.
        """
        if self.mainWidget is None:
            KQMessageBox.critical(None,
                self.trUtf8("Save Image"),
                self.trUtf8("""There is no UI file loaded.""")
                    .arg(fname),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)
            return
        
        defaultExt = "PNG"
        filters = ""
        formats = QImageIO.outputFormats()
        for format in formats:
            filters = "%s*.%s " % (filters, str(format.lower()))
        filter = self.trUtf8("Images (%1)").arg(QString(filters[:-1]))
        
        fname = KQFileDialog.getSaveFileName(\
            QString.null,
            filter,
            None, None,
            self.trUtf8("Save Image"))
        if fname.isEmpty():
            return
            
        ext = QFileInfo(fname).extension().upper()
        if ext.isEmpty():
            ext = defaultExt
            fname.append(".%s" % defaultExt.lower())
        
        pix = QPixmap.grabWidget(self.mainWidget)
        self.updateChildren(self.lastStyle)
        if not pix.save(fname, str(ext)):
            KQMessageBox.critical(None,
                self.trUtf8("Save Image"),
                self.trUtf8("""<p>The file <b>%1</b> could not be saved.</p>""")
                    .arg(fname),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)

    def handleCopy(self):
        """
        Private slot to handle the Copy Image menu action.
        """
        if self.mainWidget is None:
            KQMessageBox.critical(None,
                self.trUtf8("Save Image"),
                self.trUtf8("""There is no UI file loaded.""")
                    .arg(fname),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)
            return
        
        cb = qApp.clipboard()
        cb.setPixmap(QPixmap.grabWidget(self.mainWidget))
        self.updateChildren(self.lastStyle)
    
    def handlePrint(self):
        """
        Private slot to handle the Print Image menu action.
        """
        if self.mainWidget is None:
            KQMessageBox.critical(None,
                self.trUtf8("Save Image"),
                self.trUtf8("""There is no UI file loaded.""")
                    .arg(fname),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)
            return
        
        settings = Preferences.Prefs.settings
        printer = KQPrinter()
        printer.setFullPage(1)
        
        if not KdeQt.isKDE():
            printer.setPrinterName(settings.readEntry("/eric3/UIPreviewer/printername")[0])
            printer.setPageSize(settings.readNumEntry("/eric3/UIPreviewer/pagesize")[0])
            printer.setPageOrder(settings.readNumEntry("/eric3/UIPreviewer/pageorder")[0])
            printer.setOrientation(settings.readNumEntry("/eric3/UIPreviewer/orientation")[0])
            printer.setColorMode(settings.readNumEntry("/eric3/UIPreviewer/colormode")[0])
        
        if printer.setup(self):
            self.statusBar().message(self.trUtf8("Printing the image..."))
            p = QPainter(printer)
            metrics = QPaintDeviceMetrics(p.device())
            marginX = printer.margins().width()
            marginY = printer.margins().height()
            
            # double the margin on bottom of page
            if printer.orientation() == KQPrinter.Portrait:
                width = metrics.width() - marginX * 2
                height = metrics.height() - marginY * 3
            else:
                marginX *= 2
                width = metrics.width() - marginX * 2
                height = metrics.height() - marginY * 2
            img = QPixmap.grabWidget(self.mainWidget).convertToImage()
            self.updateChildren(self.lastStyle)
            p.drawImage(marginX, marginY, 
                        img.smoothScale(width, height, QImage.ScaleMin))
            p.end()
            
            if not KdeQt.isKDE():
                settings.writeEntry("/eric3/UIPreviewer/printername", printer.printerName())
                settings.writeEntry("/eric3/UIPreviewer/pagesize", printer.pageSize())
                settings.writeEntry("/eric3/UIPreviewer/pageorder", printer.pageOrder())
                settings.writeEntry("/eric3/UIPreviewer/orientation", printer.orientation())
                settings.writeEntry("/eric3/UIPreviewer/colormode", printer.colorMode())
        
        self.statusBar().message(self.trUtf8("Image sent to printer..."), 2000)
