Exemplo n.º 1
0
class MSMainWindow(QMainWindow):
    """Gui of the main window"""

    # MAX_RECENT_FILES = 10
    # start putting links spyder numpy scipy et tutti quanti
    links = (
        "http://numpy.scipy.org/",
        "http://packages.python.org/spyder/",
        "http://www.riverbankcomputing.co.uk/software/pyqt/intro",
    )

    pluginPath = path.normcase("pluginmanager/plugins/")

    def __init__(self, availablePlugins):
        """
        Constructor with all the models needed setup menus
        
        """
        QMainWindow.__init__(self)
        self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks)
        self.plugins = availablePlugins
        self.pluginsInst = []
        settings = QSettings(
            "INRA/INSA", "-".join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR])
        )
        self.recentFiles = list(settings.value("RecentFiles").toStringList())
        self.setStyleSheet(stylesheet)
        self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self)
        self.addToolBar(0x1, self.pipeline)

        self._setupModels()
        self._setupUi()
        self._setupMenus()

    def _setupModels(self):
        """
        Warning:Causes segfault when horizontal labels set to True
        
        on aura peu etre a la fin un model par sampleList c'est ce qui parait
        le plus logique
        
        """
        # drag and drop table sample
        self.sampleModel = QStandardItemModel(self)
        self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"])
        # treeView1
        self.spectraModel = QStandardItemModel(self)
        # treeview2
        self.peakModel = QStandardItemModel(self)
        # treeview3
        self.clusterModel = QStandardItemModel(self)

    def _setupMenus(self):
        # file
        self.fileMenu = QMenu("&File")
        self.fileMenu.setTearOffEnabled(True)
        self.op = QMenu("&Open...", self.fileMenu)
        self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png")))

        open_ = QAction("&Open rawfiles", self)
        open_.setToolTip("Open an mzXML or netCDF file")
        open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O))
        open_icon = QIcon(path.normcase("gui/icons/fileopen.png"))
        open_.setIcon(open_icon)
        self.op.addAction(open_)

        load_ = QAction("&Open projects...", self)
        load_.setToolTip("load binary file containing saved objects")
        load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        load_icon = QIcon(QPixmap(path.normcase("gui/icons/project_open.png")))
        load_.setIcon(load_icon)
        self.op.addAction(load_)

        self.fileMenu.addMenu(self.op)

        save_ = QAction("&Save...", self)
        save_.setToolTip("save the actual application model")
        save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        save_icon = QIcon(path.normcase("gui/icons/save_all.png"))
        save_.setIcon(save_icon)
        self.fileMenu.addAction(save_)

        pkl = QAction("&load a peaklist", self)  # TODO:load peaklist
        pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P))
        pkl.setToolTip("load a peaklist and process it")
        pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png")))
        self.fileMenu.addAction(pkl)

        convert_ = QAction("&Convert...", self)
        convert_.setEnabled(False)
        convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed")
        convert_icon = QIcon(path.normcase("gui/icons/goto.png"))
        convert_.setIcon(convert_icon)
        self.fileMenu.addAction(convert_)

        a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch")
        a.setEnabled(False)

        b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge")
        b.setToolTip("Merge MRM file")
        # b.setEnabled(False)

        self.fileMenu.addSeparator()
        #
        #        for i in xrange(self.MAX_RECENT_FILES):
        #            a = QAction('', self)
        #            a.setVisible(False)
        #            self.fileMenu.addAction(a)
        #
        #        for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))):
        #            self.fileMenu.actions()[5+i].setVisible(True)
        #            self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1])

        exit_action = QAction("&Exit", self)
        exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q))
        exit_action.setIcon(QIcon(QPixmap(path.normcase("gui/icons/exit.png"))))
        self.fileMenu.addAction(exit_action)

        self.menuBar().addMenu(self.fileMenu)

        self.editMenu = QMenu("&Edit")
        self.editMenu.setTearOffEnabled(True)
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_undo.png")), "&Undo...")
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_redo.png")), "&Redo...")
        self.editMenu.actions()[0].setEnabled(False)
        self.editMenu.actions()[1].setEnabled(False)
        self.editMenu.addSeparator()
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/run.png")), "&Preferences")
        self.exportMenu = QMenu("&Export...")
        self.exportMenu.setIcon(QIcon(path.normcase("gui/icons/file_export.png")))
        self.exportMenu.addAction("&Peaklist")
        self.exportMenu.addAction("&Clusters intensity matrix")
        self.editMenu.addMenu(self.exportMenu)
        self.menuBar().addMenu(self.editMenu)

        # view
        self.viewMenu = QMenu("&View")
        self.viewMenu.setTearOffEnabled(True)
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/window_duplicate")),
            "&Cascade View",
            self.mdiArea.cascadeSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_K),
        )
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/view_icon")),
            "&Title View",
            self.mdiArea.tileSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_N),
        )
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/stop_process.png")),
            "&Close all subWindows",
            self.mdiArea.closeAllSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_W),
        )

        self.plotting = QMenu("&Plotting...")
        self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png"))))
        self.plotting.addAction("&3D Plot")
        # self.plotting.addAction("&Cytoscape web")
        self.plotting.addAction("&Spectrogram Plot")

        # self.multiplePlot = QAction("&Visualize Raw/Treated Data", self)
        # self.multiplePlot.setCheckable(True)
        # self.multiplePlot.setEnabled(False)
        # self.sub_plot_.addAction(self.multiplePlot)

        self.viewMenu.addMenu(self.plotting)
        self.viewMenu.addSeparator()
        self.show_hide = QMenu("&Show/Hide")
        m = self.createPopupMenu()
        m.setTitle("&Show/Hide")
        self.viewMenu.addMenu(m)
        # self.pref = QMenu("&Preferences")

        # self.pref.addAction(self.multiplePlot)
        # self.viewMenu.addMenu(self.pref)
        self.menuBar().addMenu(self.viewMenu)

        # algorithm
        self.algoMenu = QMenu("&Algorithm")
        self.algoMenu.setTearOffEnabled(True)
        self.preProcessing = QMenu("&PreProcessing(experimental)")
        self.preProcessing.addAction("&Smoothing raw data...")
        self.preProcessing.addAction("&Cut off raw data...")
        self.preProcessing.addAction("&Calibration (mz dimension)")
        self.preProcessing.addAction("&Resize sample...")

        self.algoMenu.addMenu(self.preProcessing)

        self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self)
        self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png")))

        matched = QAction("&MatchedFiltered", self)
        matched.setIcon(QIcon(path.normcase("gui/icons/RLogo")))
        matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm")
        self.peakPickingMenu.addAction(matched)

        centwave = QAction("&CentWave", self)
        centwave.setIcon(QIcon(path.normcase("gui/icons/RLogo")))
        centwave.setToolTip("Peak Detection and Integration using CentWave algorithm")
        self.peakPickingMenu.addAction(centwave)
        # peak_.setShortcut(.QKeySequence(CTRL + Key_P))
        # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png")))
        # peak_.setIcon(peak_icon)
        self.algoMenu.addMenu(self.peakPickingMenu)

        self.alignment = QMenu("&Alignment")
        self.alignment.setIcon(QIcon(path.normcase("gui/icons/format_indent_more.png")))
        self.alignment.addAction("&Polynomial fitting(exp)")
        self.alignment.addAction("&DynamicTimeWarping")
        self.alignment.addAction("&ObiWarp")
        self.alignment.actions()[2].setEnabled(False)
        self.algoMenu.addMenu(self.alignment)

        self.algoMenu.addAction("Normalization")

        clust_ = QAction("&Clustering", self)
        clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L))
        clust_icon = QIcon(QPixmap(path.normcase("gui/icons/cluster.png")))
        clust_.setIcon(clust_icon)
        self.algoMenu.addAction(clust_)

        id_ = QAction("&Identification", self)
        id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I))
        id_.setToolTip("Try to identify peaks with several methods")
        id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png"))))
        self.algoMenu.addAction(id_)
        self.menuBar().addMenu(self.algoMenu)

        # tools
        self.toolsMenu = QMenu("&Tools")
        self.toolsMenu.setTearOffEnabled(True)
        web = QAction("&Web Browser", self)
        web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png"))))
        self.toolsMenu.addAction(web)
        # cyto = QAction("&cytoscape", self)
        # cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg")))
        # cyto.setIcon(cyto_icon)
        # self.toolsMenu.addAction(cyto)
        editor = QAction("&Editor", self)
        editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png"))))
        self.toolsMenu.addAction(editor)
        pet = QAction("&Short Periodic Table", self)
        pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg"))))
        self.toolsMenu.addAction(pet)
        self.menuBar().addMenu(self.toolsMenu)

        # plugins
        self.pluginMenu = QMenu("&Plugins")
        self.pluginMenu.setTearOffEnabled(True)
        instPl = QAction("&Install a plugin", self)
        instPl.setIcon(QIcon(path.normcase("gui/icons/pluginInstall.png")))
        self.pluginMenu.addAction(instPl)
        self.launchingMenu = QMenu("&Launch PLugins", self)
        self.launchingMenu.setIcon(QIcon(path.normcase("gui/icons/plugin")))

        for plug in self.plugins:
            # fullname="".join([self.pluginPath, str(plug)])
            mod = imp.load_source(self.__module__, plug)
            if mod.autoActivation:
                qApp = QApplication.instance()
                name = getattr(mod, "className")
                cls = getattr(mod, name)
                p = cls(qApp.model, self, parent=self)
                # p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1])
                self.pluginsInst.append(p)
            else:
                self.launchingMenu.addAction(plug.split("/")[-1])
        self.pluginMenu.addMenu(self.launchingMenu)
        self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin")
        self.menuBar().addMenu(self.pluginMenu)

        # about
        self.aboutMenu = QMenu("&About")
        self.aboutMenu.setTearOffEnabled(True)
        metms = QAction(QIcon(path.normcase("gui/icons/deluge.png")), "&about metMS...", self)
        self.aboutMenu.addAction(metms)

        pyqt = QAction("&about PyQt4...", self)
        pyqt_icon = QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png")))
        pyqt.setIcon(pyqt_icon)
        self.aboutMenu.addAction(pyqt)
        metms = QAction("&metMS Documentation", self)
        metms_icon = QIcon(QPixmap(path.normcase("gui/icons/deluge.png")))
        metms.setIcon(metms_icon)
        self.aboutMenu.addAction(metms)
        self.menuBar().addMenu(self.aboutMenu)

    def _setupUi(self, background=None):
        """        
        Make the GUI
        
        """
        # mdi
        self.mdiArea = MSMdiArea(self)
        self.mdiArea.setBackground(QBrush(QPixmap(path.normcase("gui/icons/blac2.png"))))  # QColor(Qt.blue).darker()))
        self.setCentralWidget(self.mdiArea)

        # sample dock widget
        self.sampleDockWidget = QDockWidget("Samples", self)
        # sampleWidget = QWidget()
        self.sampleTableView = MSDragFromTableView()
        self.sampleTableView.setModel(self.sampleModel)
        self.sampleTableView.setSelectionBehavior(1)
        self.sampleTableView.verticalHeader().hide()
        self.sampleTableView.verticalHeader().setDefaultSectionSize(15)
        self.sampleTableView.horizontalHeader().setDefaultSectionSize(150)

        self.sampleDockWidget.setWidget(self.sampleTableView)  # sampleWidget)
        self.sampleDockWidget.visible = True

        # workflow dock
        self.workflowDockWidget = QDockWidget("Visualizer", self)
        self.workflowDockWidget.visible = True

        a = QWidget(self)
        v = QVBoxLayout(a)
        q = QToolBar()
        # self.workingSample = QLabel("Working Sample:None")
        # q.addWidget(self.workingSample)
        q.addWidget(QLabel("ppm :"))
        self.ppmEditer = QDoubleSpinBox()
        self.usePpm = QCheckBox("use ?")
        q.addWidget(self.ppmEditer)
        q.addWidget(self.usePpm)

        q.addSeparator()

        self.removeButton = QToolButton(self)
        self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png")))
        q.addWidget(self.removeButton)

        self.markAsGood = QAction(QIcon(path.normcase("gui/icons/button_ok.png")), "mark peak as good", self)
        self.markAsBad = QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self)
        self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self)

        q.addAction(self.markAsGood)
        q.addAction(self.markAsBad)
        q.addAction(self.hideItem)
        v.addWidget(q)

        self.tabWidget = QTabWidget()
        self.tab = QWidget()
        verticalLayout = QVBoxLayout(self.tab)
        self.treeView = MSToDropTableView()
        self.treeView.verticalHeader().setDefaultSectionSize(20)

        self.treeView.setModel(self.spectraModel)
        self.spectraLabel = QLabel("Sample: None")
        verticalLayout.addWidget(self.treeView)
        verticalLayout.addWidget(self.spectraLabel)
        self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")), "Spectra")

        self.tab_2 = QWidget()
        verticalLayout_4 = QVBoxLayout(self.tab_2)
        self.treeView_2 = MSToDropTableView()  # MSTreeView(self.tab_2)# QTableView(self)#
        self.treeView_2.verticalHeader().setDefaultSectionSize(20)
        self.treeView_2.setModel(self.peakModel)
        self.peakLabel = QLabel("Sample: None")
        verticalLayout_4.addWidget(self.treeView_2)
        verticalLayout_4.addWidget(self.peakLabel)
        self.tabWidget.addTab(self.tab_2, QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List")

        self.tab_3 = QWidget()
        verticalLayout_5 = QVBoxLayout(self.tab_3)
        self.treeView_3 = MSToDropTreeView()
        self.treeView_3.setAnimated(True)
        self.treeView_3.setModel(self.clusterModel)
        self.clusterLabel = QLabel("Sample: None")
        verticalLayout_5.addWidget(self.treeView_3)
        verticalLayout_5.addWidget(self.clusterLabel)
        self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters")

        self.tabWidget.setCurrentIndex(0)

        for l in (self.spectraLabel, self.peakLabel, self.clusterLabel):
            l.setAutoFillBackground(True)

        v.addWidget(self.tabWidget)
        self.workflowDockWidget.setWidget(a)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.workflowDockWidget)

        from gui.MetBaseGui import MSIsoCalculator

        self.isoCalc = MSIsoCalculator(self)
        self.isoCalcDockWidget = QDockWidget("isotopes calculation", self)
        self.isoCalcDockWidget.setWidget(self.isoCalc)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget)
        self.isoCalcDockWidget.setVisible(False)
        self.isoCalcDockWidget.visible = False

        from gui.MetBaseGui import FormulaGenerator

        self.generator = FormulaGenerator(self)
        self.generatorDockWidget = QDockWidget("formula generator", self)
        self.generatorDockWidget.setWidget(self.generator)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget)
        self.generatorDockWidget.setVisible(False)
        self.generatorDockWidget.visible = False

        self.compoundTreeView = MSCompoundTreeView(self)
        self.compoundDockWidget = QDockWidget("Compounds", self)
        self.compoundDockWidget.setWidget(self.compoundTreeView)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.compoundDockWidget)
        self.compoundDockWidget.setVisible(False)
        self.compoundDockWidget.visible = False

        self.comparativeTableView = QTableView(self)
        self.comparativeTableView.horizontalHeader().setStretchLastSection(True)
        self.comparativeTableView.verticalHeader().setDefaultSectionSize(20)
        self.comparativeDock = QDockWidget("Comparative View", self)
        self.comparativeDock.setWidget(self.comparativeTableView)
        self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock)
        self.comparativeDock.setVisible(False)
        self.comparativeDock.visible = False

        self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget)
        self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget)
        self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget)
        # set the end

        # WARNING: possible that the internal shell widget cause random segfault
        # with the error of QObject::killTimers...? not sure !
        self.shell = QWidget()  # InternalShell(namespace={'metms': QApplication.instance()},
        #              parent=self,
        #              multithreaded=False)
        self.shellDock = QDockWidget("Python Shell", self)
        self.shellDock.setWindowIcon(QIcon(path.normcase("gui/icons/stop.png")))
        self.shellDock.setWidget(self.shell)
        self.shellDock.setMinimumWidth(255)
        self.shellDock.visible = True
        self.addDockWidget(0x2, self.shellDock)

        self.addDockWidget(0x2, self.sampleDockWidget)
        self.tabifyDockWidget(self.shellDock, self.sampleDockWidget)

        self.pb = QProgressBar(self)
        self.pb.setMaximumWidth(245)

        self.stopProcess = QToolButton(self)
        self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png")))
        m = QMenu()
        # self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName)
        self.stopProcess.setMenu(m)
        self.stopProcess.setPopupMode(1)  # Menu Button
        # self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread)

        self.statusBar().addPermanentWidget(self.stopProcess)
        self.statusBar().addPermanentWidget(self.pb)

    def updateStopProcessMenu(self):
        """
        update the menu of the stop process
        button, based directly on the processes
        stored by the task manager
        
        """
        self.stopProcess.menu().clear()
        for c in QApplication.instance().taskManager:
            self.stopProcess.menu().addAction(c.title)

        # QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1])

    def addMdiSubWindow(self, plot, title="", showMaximized=False):
        """ 
        Allow addition of new window in the mdiarea
        
        """
        win = self.mdiArea.addSubWindow(plot)
        # print "widget parent", plot.parent()
        win.setAttribute(Qt.WA_DeleteOnClose)
        # win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy)
        # plot.setParent(win)
        win.setWindowTitle(title)
        if showMaximized:
            win.showMaximized()
        else:
            win.resize(400, 300)
        win.show()
        return win

    def updateTreeView(self):
        """
        Tree View update switch spectre/chromato
        
        """
        if self.treeView.model() == self.spectraModel:
            self.treeView.setModel(self.chromaModel)
            self.tabWidget.setTabText(0, "Chroma")
        else:
            self.treeView.setModel(self.spectraModel)
            # self.treeView.setSelectionMode(1)
            self.tabWidget.setTabText(0, "Spectra")

    def addTreeViewModel(self, model1, model2):
        """Add a model """
        self.chromaModel.appendRow(model1)
        self.spectraModel.appendRow(model2)

    def _actionHovered(self, action):
        """emulate tooltip cause they do not work that much"""
        tip = action.toolTip()
        QToolTip.showText(QCursor.pos(), tip)

    def showErrorMessage(self, title, string):
        QMessageBox.critical(self, title, string, 0, 0)

    def showWarningMessage(self, title, string):
        return QMessageBox.warning(self, title, string, QMessageBox.Ok | QMessageBox.Cancel)

    def showInformationMessage(self, title, string):
        QMessageBox.information(self, title, string, 0)

    def updateProgressBar(self, i):
        """update the value of the progress bar for all the treatment"""

        self.pb.setValue(min(i, 100))

    def to_indetermined_mode(self):
        self.pb.setMaximum(0)

    def to_determined_mode(self):
        self.pb.setMaximum(100)

    def showInStatusBar(self, string, time=5000):
        self.statusBar().showMessage(string, time)

    def addInterpreterDock(self, shell):
        self.shellDock = QDockWidget(self)
        self.shellDock.setWidget(shell)
        self.shellDock.setWindowTitle("shell")
        self.addDockWidget(0x2, self.shellDock)

    def showMetMSInformation(self):

        QMessageBox.about(
            self,
            self.tr("About %1").arg("metMS"),
            self.tr(
                """<b>%1 %2</b>
            <br>metabolite Mass Spectrometry
            <p>Copyright &copy; 2010 Marco INSA, INRA
            <br>Licensed under the terms of the CeciLL License
            <p>Developed and maintained by Marco
            <br>Bug reports and feature requests: 
            <a href="http://github.com/jerkos/metms">metMS site</a><br>
            Discussions around the project: 
            <a href="http://groups.google.com/group/spyderlib">Google Group</a>
            <p>This project is part of the BRIDGE project
            <p>Python %3, Qt %4, PyQt %5"""
            )
            .arg("metMS")
            .arg(__version__)
            .arg(platform.python_version())
            .arg(QT_VERSION_STR)
            .arg(PYQT_VERSION_STR),
        )
    def lauchGUI(self, WorkSpace, aCase, sobjXML, Args):
        """
        mw.dockWidgetBrowser is the Browser of the CFD MainView
        """
        log.debug("lauchGUI")
        from cs_gui import process_cmd_line

        if CFD_Code() == CFD_Saturne:
            from cs_package import package
            from code_saturne.Base.MainView import MainView
        elif CFD_Code() == CFD_Neptune:
            from nc_package import package
            from neptune_cfd.core.MainView import MainView

        if sobjXML == None:
            Title = "unnamed"
        else:
            Title = sobjXML.GetName()

        self.Workspace = WorkSpace
        pkg = package()
        case, splash = process_cmd_line(Args)
        mw = MainView(pkg, case, aCase)

        # Put the standard panel of the MainView inside a QDockWidget
        # in the SALOME Desktop
        aTitle = self.setWindowTitle_CFD(mw, aCase, Title)
        dsk = sgPyQt.getDesktop()
        dock = QDockWidget(aTitle)

        dock.setWidget(mw.frame)
        dock.setMinimumWidth(520)
        dsk.addDockWidget(Qt.RightDockWidgetArea, dock)

        dock.setVisible(True)
        dock.show()

        # Put the QTreeView of the MainView which is already inside a QDockWidget
        # in the SALOME Desktop
        BrowserTitle = aTitle  + " Browser"
        mw.dockWidgetBrowser.setWindowTitle(BrowserTitle)
        dsk.addDockWidget(Qt.LeftDockWidgetArea, mw.dockWidgetBrowser)

        mw.dockWidgetBrowser.setVisible(True)
        mw.dockWidgetBrowser.show()
        mw.dockWidgetBrowser.raise_()
        dock.raise_()

        #Add Dock windows are managed by CFDGUI_Management class
        studyId = sgPyQt.getStudyId()
        aStudyCFD = aCase.GetFather()
        aCaseCFD  = aCase
        xmlFileName = str(Title)
        _c_CFDGUI.set_d_CfdCases(studyId, dock, mw.dockWidgetBrowser, mw, aStudyCFD, aCaseCFD, xmlFileName, sobjXML)

        self.connect(dock, SIGNAL("visibilityChanged(bool)"), self.setdockWindowBrowserActivated)
        self.connect(mw.dockWidgetBrowser, SIGNAL("visibilityChanged(bool)"),self.setdockWindowActivated)

        self.connect(dock.toggleViewAction(), SIGNAL("toggled(bool)"), self.setdockWB)
        self.connect(mw.dockWidgetBrowser.toggleViewAction(), SIGNAL("toggled(bool)"), self.setdock)

        _c_CFDGUI.tabifyDockWindows(dsk, studyId)
        self.showDockWindows(studyId, xmlFileName, aCaseCFD.GetName(), aStudyCFD.GetName())
        updateObjectBrowser()

        return mw
Exemplo n.º 3
0
class ComposerWrapper(QObject):
    """
    Embeds custom STDM tools in a QgsComposer instance for managing map-based
    STDM document templates.
    """
    dataSourceSelected = pyqtSignal(str)

    def __init__(self, composerView, iface):
        QObject.__init__(self, composerView)

        self._compView = composerView
        self._stdmTB = self.mainWindow().addToolBar("STDM Document Designer")
        self._selectMoveAction = None
        self._iface = iface

        #Container for custom editor widgets
        self._widgetMappings = {}

        #Hide default dock widgets
        if self.itemDock() is not None:
            self.itemDock().hide()

        if self.atlasDock() is not None:
            self.atlasDock().hide()

        if self.generalDock() is not None:
            self.generalDock().hide()

        # Remove default toolbars
        self._remove_composer_toolbar('mAtlasToolbar')

        self._remove_composer_toolbar('mComposerToolbar')

        #Create dock widget for configuring STDM data source
        self._stdmDataSourceDock = QDockWidget(
            QApplication.translate("ComposerWrapper", "STDM Data Source"),
            self.mainWindow())
        self._stdmDataSourceDock.setObjectName("STDMDataSourceDock")
        self._stdmDataSourceDock.setMinimumWidth(300)
        self._stdmDataSourceDock.setFeatures(QDockWidget.DockWidgetMovable
                                             | QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,
                                        self._stdmDataSourceDock)

        self._dataSourceWidget = ComposerDataSourceSelector()
        self._stdmDataSourceDock.setWidget(self._dataSourceWidget)
        self._stdmDataSourceDock.show()

        #Re-insert dock widgets
        if self.generalDock() is not None:
            self.generalDock().show()

        if self.itemDock() is not None:
            self.itemDock().show()

        #Create dock widget for configuring STDM item properties
        self._stdmItemPropDock = QDockWidget(
            QApplication.translate("ComposerWrapper", "STDM item properties"),
            self.mainWindow())

        self._stdmItemPropDock.setObjectName("STDMItemDock")
        self._stdmItemPropDock.setMinimumWidth(300)
        self._stdmItemPropDock.setFeatures(QDockWidget.DockWidgetMovable
                                           | QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,
                                        self._stdmItemPropDock)
        self._stdmItemPropDock.show()

        #Re-arrange dock widgets and push up STDM data source dock widget
        if self.generalDock() is not None:
            self.mainWindow().splitDockWidget(self._stdmDataSourceDock,
                                              self.generalDock(), Qt.Vertical)

        if self.itemDock() is not None:
            self.mainWindow().splitDockWidget(self._stdmDataSourceDock,
                                              self.itemDock(), Qt.Vertical)
            if self.generalDock() is not None:
                self.mainWindow().tabifyDockWidget(self.generalDock(),
                                                   self.itemDock())

        if self.itemDock() is not None:
            self.mainWindow().splitDockWidget(self.itemDock(),
                                              self._stdmItemPropDock,
                                              Qt.Vertical)

        #Set focus on composition properties window
        if self.generalDock() is not None:
            self.generalDock().activateWindow()
            self.generalDock().raise_()

        #Connect signals
        self.composition().itemRemoved.connect(self._onItemRemoved)
        self._dataSourceWidget.cboDataSource.currentIndexChanged.connect(
            self.propagateDataSourceSelection)
        self.composerView().selectedItemChanged.connect(self._onItemSelected)

        #Current template document file
        self._currDocFile = None

        #Copy of template document file
        self._copy_template_file = None

        self._selected_item_uuid = unicode()

        self._current_ref_table_index = -1

    @property
    def copy_template_file(self):
        return self._copy_template_file

    @copy_template_file.setter
    def copy_template_file(self, value):
        self._copy_template_file = value

    @property
    def selected_item_uuid(self):
        return self._selected_item_uuid

    @selected_item_uuid.setter
    def selected_item_uuid(self, uuid):
        self._selected_item_uuid = uuid

    @property
    def current_ref_table_index(self):
        return self._current_ref_table_index

    @current_ref_table_index.setter
    def current_ref_table_index(self, value):
        self._current_ref_table_index = value

    def _remove_composer_toolbar(self, object_name):
        """
        Removes toolbars from composer window.
        :param object_name: The object name of the toolbar
        :type object_name: String
        :return: None
        :rtype: NoneType
        """
        composers = self._iface.activeComposers()
        for i in range(len(composers)):
            comp = composers[i].composerWindow()
            widgets = comp.findChildren(QToolBar, object_name)
            for widget in widgets:
                comp.removeToolBar(widget)

    def _removeActions(self):
        """
        Remove inapplicable actions and their corresponding toolbars and menus.
        """
        removeActions = [
            "mActionSaveProject", "mActionNewComposer",
            "mActionDuplicateComposer"
        ]

        composerToolbar = self.composerMainToolBar()
        if composerToolbar != None:
            saveProjectAction = None

            for itemAction in composerToolbar.actions():
                if itemAction.objectName() == "mActionSaveProject":
                    saveProjectAction = itemAction
                    break

            if saveProjectAction != None:
                composerMenu = saveProjectAction.menu()

    def configure(self):
        #Create instances of custom STDM composer item configurations
        for ciConfig in ComposerItemConfig.itemConfigurations:
            ciConfig(self)

    def addWidgetMapping(self, uniqueIdentifier, widget):
        """
        Add custom STDM editor widget based on the unique identifier of the composer item
        """
        self._widgetMappings[uniqueIdentifier] = widget

    def widgetMappings(self):
        """
        Returns a dictionary containing uuid values of composer items linked to STDM widgets.
        """
        return self._widgetMappings

    def clearWidgetMappings(self):
        """
        Resets the widget mappings collection.
        """
        self._widgetMappings = {}

    def mainWindow(self):
        """
        Returns the QMainWindow used by the composer view.
        """
        return self._compView.composerWindow()

    def stdmToolBar(self):
        """
        Returns the instance of the STDM toolbar added to the QgsComposer.
        """
        return self._stdmTB

    def composerView(self):
        """
        Returns the composer view.
        """
        return self._compView

    def composition(self):
        """
        Returns the QgsComposition instance used in the composer view.
        """
        return self._compView.composition()

    def composerItemToolBar(self):
        """
        Returns the toolbar containing actions for adding composer items.
        """
        return self.mainWindow().findChild(QToolBar, "mItemToolbar")

    def composerMainToolBar(self):
        """
        Returns the toolbar containing actions for managing templates.
        """
        return self.mainWindow().findChild(QToolBar, "mComposerToolbar")

    def selectMoveAction(self):
        """
        Returns the QAction for selecting or moving composer items.
        """
        if self.composerItemToolBar() != None:
            if self._selectMoveAction == None:
                for itemAction in self.composerItemToolBar().actions():
                    if itemAction.objectName() == "mActionSelectMoveItem":
                        self._selectMoveAction = itemAction
                        break

        return self._selectMoveAction

    def checkedItemAction(self):
        """
        Returns the currently selected composer item action.
        """
        if self.selectMoveAction() != None:
            return self.selectMoveAction().actionGroup().checkedAction()

        return None

    def itemDock(self):
        """
        Get the 'Item Properties' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget, "ItemDock")

    def atlasDock(self):
        """
        Get the 'Atlas generation' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget, "AtlasDock")

    def generalDock(self):
        """
        Get the 'Composition' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget, "CompositionDock")

    def stdmDataSourceDock(self):
        """
        Returns the STDM data source dock widget.
        """
        return self._stdmDataSourceDock

    def stdmItemDock(self):
        """
        Returns the STDM item dock widget.
        """
        return self._stdmItemPropDock

    def documentFile(self):
        """
        Returns the QFile instance associated with the current document. 'None' will be returned for
        new, unsaved documents.
        """
        return self._currDocFile

    def setDocumentFile(self, docFile):
        """
        Sets the document file.
        """
        if not isinstance(docFile, QFile):
            return

        self._currDocFile = docFile

    def selectedDataSource(self):
        """
        Returns the name of the data source specified by the user.
        """
        row = self._stdmDataSourceDock.widget().cboDataSource.currentIndex()
        table_name = self._stdmDataSourceDock.widget().cboDataSource.itemData(
            row)

        return table_name

    def selected_referenced_table(self):
        """
        :return: Returns the name of currently specified referenced table name.
        :rtype: str
        """
        return self._stdmDataSourceDock.widget().referenced_table_name()

    def selectedDataSourceCategory(self):
        """
        Returns the category (view or table) that the data source belongs to.
        """
        if not self.stdmDataSourceDock().widget() is None:
            return self.stdmDataSourceDock().widget().category()

        return ""

    def propagateDataSourceSelection(self, index):
        """
        Propagates the signal when a user select a data source. Listening objects can hook on to it.
        """
        data_source_name = self._stdmDataSourceDock.widget(
        ).cboDataSource.itemData(index)
        self.dataSourceSelected.emit(data_source_name)

    def composer_items(self):
        """
        :return: Returns a list of custom composer items.
        :rtype: list
        """
        return [
            self.composition().getComposerItemById(uuid)
            for uuid in self._widgetMappings.keys()
            if not self.composition().getComposerItemById(uuid) is None
        ]

    def _clear_composition(self):
        """
        Removes composer items which, otherwise, are causing QGIS to crash
        when loading a subsequent document template.
        """
        items = self.composition().items()

        for c_item in items:
            if isinstance(c_item, QgsComposerItem) and not isinstance(
                    c_item, QgsPaperItem):
                if c_item.uuid() in self._widgetMappings:
                    #Remove corresponding widget as well as reference in the collection
                    del self._widgetMappings[c_item.uuid()]

                self.composition().removeItem(c_item)
                self.composition().itemRemoved.emit(c_item)

                del c_item

        self.composition().undoStack().clear()
        self.composition().itemsModel().clear()

    def create_new_document_designer(self, file_path):
        """
        Creates a new document designer and loads the document template
        defined in file path.
        :param file_path: Path to document template
        :type file_path: str
        """
        if len(self.composerView().items()) == 3:
            self.composerView().composerWindow().close()

        document_designer = self._iface.createNewComposer(
            "STDM Document Designer")

        #Embed STDM customizations
        cw = ComposerWrapper(document_designer, self._iface)
        cw.configure()

        #Load template
        cw.loadTemplate(file_path)

    def loadTemplate(self, filePath):
        """
        Loads a document template into the view and updates the necessary STDM-related composer items.
        """
        if not QFile.exists(filePath):
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("OpenTemplateConfig",
                                       "Open Template Error"),
                QApplication.translate(
                    "OpenTemplateConfig",
                    "The specified template does not exist."))
            return

        copy_file = filePath.replace('sdt', 'cpy')

        # remove existing copy file
        if QFile.exists(copy_file):
            copy_template = QFile(copy_file)
            copy_template.remove()

        orig_template_file = QFile(filePath)

        self.setDocumentFile(orig_template_file)

        # make a copy of the original
        orig_template_file.copy(copy_file)

        #templateFile = QFile(filePath)

        # work with copy
        templateFile = QFile(copy_file)

        self.copy_template_file = templateFile

        if not templateFile.open(QIODevice.ReadOnly):
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("ComposerWrapper",
                                       "Open Operation Error"),
                "{0}\n{1}".format(
                    QApplication.translate("ComposerWrapper",
                                           "Cannot read template file."),
                    templateFile.errorString()))
            return

        templateDoc = QDomDocument()

        if templateDoc.setContent(templateFile):
            table_config_collection = TableConfigurationCollection.create(
                templateDoc)
            '''
            First load vector layers for the table definitions in the config
            collection before loading the composition from file.
            '''
            load_table_layers(table_config_collection)

            self.clearWidgetMappings()

            #Load items into the composition and configure STDM data controls
            self.composition().loadFromTemplate(templateDoc)

            #Load data controls
            composerDS = ComposerDataSource.create(templateDoc)

            #Set title by appending template name
            title = QApplication.translate("STDMPlugin",
                                           "STDM Document Designer")

            composer_el = templateDoc.documentElement()
            if not composer_el is None:
                template_name = ""
                if composer_el.hasAttribute("title"):
                    template_name = composer_el.attribute("title", "")
                elif composer_el.hasAttribute("_title"):
                    template_name = composer_el.attribute("_title", "")

                if template_name:
                    win_title = u"{0} - {1}".format(title, template_name)
                    self.mainWindow().setWindowTitle(template_name)

            self._configure_data_controls(composerDS)

            #Load symbol editors
            spatialFieldsConfig = SpatialFieldsConfiguration.create(
                templateDoc)
            self._configureSpatialSymbolEditor(spatialFieldsConfig)

            #Load photo editors
            photo_config_collection = PhotoConfigurationCollection.create(
                templateDoc)
            self._configure_photo_editors(photo_config_collection)

            # Load table editors
            self._configure_table_editors(table_config_collection)

            items = self.composerView().items()
            items = []

            #Load chart property editors
            chart_config_collection = ChartConfigurationCollection.create(
                templateDoc)
            self._configure_chart_editors(chart_config_collection)

            # Load QR code property editors
            qrc_config_collection = QRCodeConfigurationCollection.create(
                templateDoc)
            self._configure_qr_code_editors(qrc_config_collection)

            self._sync_ids_with_uuids()

    def saveTemplate(self):
        """
        Creates and saves a new document template.
        """
        # Validate if the user has specified the data source
        if not self.selectedDataSource():
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("ComposerWrapper", "Error"),
                QApplication.translate(
                    "ComposerWrapper", "Please specify the "
                    "data source name for the document composition."))
            return

        # Assert if the referenced table name has been set
        if not self.selected_referenced_table():
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("ComposerWrapper", "Error"),
                QApplication.translate(
                    "ComposerWrapper", "Please specify the "
                    "referenced table name for the selected data source."))
            return

        # If it is a new unsaved document template then prompt for the document name.
        docFile = self.documentFile()

        if docFile is None:
            docName, ok = QInputDialog.getText(
                self.composerView(),
                QApplication.translate("ComposerWrapper", "Template Name"),
                QApplication.translate("ComposerWrapper",
                                       "Please enter the template name below"),
            )

            if not ok:
                return

            if ok and not docName:
                QMessageBox.critical(
                    self.composerView(),
                    QApplication.translate("ComposerWrapper", "Error"),
                    QApplication.translate("ComposerWrapper",
                                           "Please enter a template name!"))
                self.saveTemplate()

            if ok and docName:
                templateDir = self._composerTemplatesPath()

                if templateDir is None:
                    QMessageBox.critical(
                        self.composerView(),
                        QApplication.translate("ComposerWrapper", "Error"),
                        QApplication.translate(
                            "ComposerWrapper",
                            "Directory for document templates cannot not be found."
                        ))

                    return

                absPath = templateDir + "/" + docName + ".sdt"

                #Check if there is an existing document with the same name
                caseInsenDic = CaseInsensitiveDict(documentTemplates())
                if docName in caseInsenDic:
                    result = QMessageBox.warning(
                        self.composerView(),
                        QApplication.translate("ComposerWrapper",
                                               "Existing Template"),
                        u"'{0}' {1}.\nDo you want to replace the "
                        "existing template?".format(
                            docName,
                            QApplication.translate("ComposerWrapper",
                                                   "already exists")),
                        QMessageBox.Yes | QMessageBox.No)

                    if result == QMessageBox.Yes:
                        #Delete the existing template
                        delFile = QFile(absPath)
                        remStatus = delFile.remove()
                        if not remStatus:
                            QMessageBox.critical(
                                self.composerView(),
                                QApplication.translate("ComposerWrapper",
                                                       "Delete Error"),
                                "'{0}' {1}.".format(
                                    docName,
                                    QApplication.translate(
                                        "ComposerWrapper",
                                        "template could not be removed by the system,"
                                        " please remove it manually from the document templates directory."
                                    )))
                            return

                    else:
                        return

                docFile = QFile(absPath)

            else:
                return

        docFileInfo = QFileInfo(docFile)

        if not docFile.open(QIODevice.WriteOnly):
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("ComposerWrapper",
                                       "Save Operation Error"),
                "{0}\n{1}".format(
                    QApplication.translate("ComposerWrapper",
                                           "Could not save template file."),
                    docFile.errorString()))

            return

        templateDoc = QDomDocument()
        template_name = docFileInfo.completeBaseName()

        # Catch exception raised when writing items' elements
        try:
            self._writeXML(templateDoc, template_name)
        except Exception as exc:
            msg = unicode(exc)
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("ComposerWrapper", "Save Error"), msg)
            docFile.close()
            docFile.remove()

            return

        if docFile.write(templateDoc.toByteArray()) == -1:
            QMessageBox.critical(
                self.composerView(),
                QApplication.translate("ComposerWrapper", "Save Error"),
                QApplication.translate("ComposerWrapper",
                                       "Could not save template file."))

            return

        else:
            self.mainWindow().setWindowTitle(template_name)

        self.setDocumentFile(docFile)
        docFile.close()

        if self.copy_template_file:
            self.copy_template_file.close()

    def _writeXML(self, xml_doc, doc_name):
        """
        Write the template configuration into the XML document.
        """
        #Write default composer configuration
        composer_element = xml_doc.createElement("Composer")
        composer_element.setAttribute("title", doc_name)
        composer_element.setAttribute("visible", 1)

        xml_doc.appendChild(composer_element)

        self.composition().writeXML(composer_element, xml_doc)

        #Write STDM data field configurations
        dataSourceElement = ComposerDataSource.domElement(self, xml_doc)
        composer_element.appendChild(dataSourceElement)

        #Write spatial field configurations
        spatialColumnsElement = SpatialFieldsConfiguration.domElement(
            self, xml_doc)
        dataSourceElement.appendChild(spatialColumnsElement)

        #Write photo configuration
        photos_element = PhotoConfigurationCollection.dom_element(
            self, xml_doc)
        dataSourceElement.appendChild(photos_element)

        #Write table configuration
        tables_element = TableConfigurationCollection.dom_element(
            self, xml_doc)
        dataSourceElement.appendChild(tables_element)

        #Write chart configuration
        charts_element = ChartConfigurationCollection.dom_element(
            self, xml_doc)
        dataSourceElement.appendChild(charts_element)

        # Write QRCode configuration
        qr_codes_element = QRCodeConfigurationCollection.dom_element(
            self, xml_doc)
        dataSourceElement.appendChild(qr_codes_element)

    def _configure_data_controls(self, composer_data_source):
        """
        Configure the data source and data field controls based on the composer data
        source configuration.
        """
        if not self.stdmDataSourceDock().widget() is None:
            #Set data source
            dataSourceWidget = self.stdmDataSourceDock().widget()
            dataSourceWidget.setCategory(composer_data_source.category())
            dataSourceWidget.setSelectedSource(composer_data_source.name())
            dataSourceWidget.set_referenced_table(
                composer_data_source.referenced_table_name)

            #Set data field controls
            for composerId in composer_data_source.dataFieldMappings().reverse:
                #Use composer item id since the uuid is stripped off
                composerItem = self.composition().getComposerItemById(
                    composerId)

                if not composerItem is None:
                    compFieldSelector = ComposerFieldSelector(
                        self, composerItem, self.composerView())
                    compFieldSelector.selectFieldName(
                        composer_data_source.dataFieldName(composerId))

                    #Add widget to the collection but now use the current uuid of the composition item
                    self.addWidgetMapping(composerItem.uuid(),
                                          compFieldSelector)

    def _configureSpatialSymbolEditor(self, spatial_field_config):
        """
        Configure symbol editor controls.
        """
        if not self.stdmDataSourceDock().widget() is None:
            for item_id, spFieldsMappings in spatial_field_config.spatialFieldsMapping(
            ).iteritems():
                mapItem = self.composition().getComposerItemById(item_id)

                if not mapItem is None:
                    composerSymbolEditor = ComposerSymbolEditor(
                        self, self.composerView())
                    composerSymbolEditor.add_spatial_field_mappings(
                        spFieldsMappings)

                    #Add widget to the collection but now use the current uuid of the composer map
                    self.addWidgetMapping(mapItem.uuid(), composerSymbolEditor)

    def _configure_photo_editors(self, photo_config_collection):
        """
        Creates widgets for editing photo data sources.
        :param photo_config_collection: PhotoConfigurationCollection instance.
        :type photo_config_collection: PhotoConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, photo_config in photo_config_collection.mapping(
        ).iteritems():
            pic_item = self.composition().getComposerItemById(item_id)

            if not pic_item is None:
                photo_editor = ComposerPhotoDataSourceEditor(
                    self, self.composerView())
                photo_editor.set_configuration(photo_config)

                self.addWidgetMapping(pic_item.uuid(), photo_editor)

    def _configure_chart_editors(self, chart_config_collection):
        """
        Creates widgets for editing chart properties.
        :param chart_config_collection: ChartConfigurationCollection instance.
        :type chart_config_collection: ChartConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, chart_config in chart_config_collection.mapping(
        ).iteritems():
            chart_item = self.composition().getComposerItemById(item_id)

            if not chart_item is None:
                chart_editor = ComposerChartConfigEditor(
                    self, self.composerView())
                chart_editor.set_configuration(chart_config)

                self.addWidgetMapping(chart_item.uuid(), chart_editor)

    def _configure_table_editors(self, table_config_collection):
        """
        Creates widgets for editing table data sources.
        :param table_config_collection: TableConfigurationCollection instance.
        :type table_config_collection: TableConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, table_config in table_config_collection.mapping(
        ).iteritems():
            table_item = self.composition().getComposerItemById(item_id)
            if table_item is not None:
                table_editor = ComposerTableDataSourceEditor(
                    self, table_item, self.composerView())

                table_editor.set_configuration(table_config)

                table_editor.ref_table.cbo_ref_table.currentIndexChanged[
                    str].connect(table_editor.set_table_vector_layer)

                self.addWidgetMapping(table_item.uuid(), table_editor)

    def _configure_qr_code_editors(self, qr_code_config_collection):
        """
        Creates widgets for editing QR code properties.
        :param qr_code_config_collection: QRCodeConfigurationCollection instance.
        :type qr_code_config_collection: QRCodeConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, qrc_config in qr_code_config_collection.mapping(
        ).iteritems():
            qrc_item = self.composition().getComposerItemById(item_id)

            if not qrc_item is None:
                qrc_editor_cls = qr_code_config_collection.editor_type
                qrc_editor = qrc_editor_cls(self, self.composerView())
                qrc_editor.set_configuration(qrc_config)

                self.addWidgetMapping(qrc_item.uuid(), qrc_editor)

    def _sync_ids_with_uuids(self):
        """
        Matches IDs of custom STDM items with the corresponding UUIDs. This
        is applied when loading existing templates so that the saved
        document contains a matching pair of ID and UUID for each composer
        item.
        """
        items = self._widgetMappings.keys()
        for item_uuid in self._widgetMappings.keys():
            item = self.composition().getComposerItemByUuid(item_uuid)
            if not item is None:
                item.setId(item_uuid)

    def _composerTemplatesPath(self):
        """
        Reads the path of composer templates in the registry.
        """
        regConfig = RegistryConfig()
        keyName = "ComposerTemplates"

        valueCollection = regConfig.read([keyName])

        if len(valueCollection) == 0:
            return None

        else:
            return valueCollection[keyName]

    def _onItemRemoved(self, item):
        """
        Slot raised when a composer item is removed from the scene.
        """
        """
        Code will not work since a QObject instance is returned instead of a QgsComposerItem
        if item.uuid() in self._widgetMappings:
            del self._widgetMappings[item.uuid()]
        """
        pass

    def _onItemSelected(self, item):
        """
        Slot raised when a composer item is selected. Load the corresponding field selector
        if the selection is an STDM data field label.
        QComposerLabel is returned as a QObject in the slot argument hence, we have resorted to
        capturing the current selected items in the composition.
        """
        selectedItems = self.composition().selectedComposerItems()

        if len(selectedItems) == 0:
            self._stdmItemPropDock.setWidget(None)

        elif len(selectedItems) == 1:
            composer_item = selectedItems[0]

            if composer_item.uuid() in self._widgetMappings:
                stdmWidget = self._widgetMappings[composer_item.uuid()]

                self.selected_item_uuid = composer_item.uuid()

                if stdmWidget == self._stdmItemPropDock.widget():
                    return
                else:
                    self._stdmItemPropDock.setWidget(stdmWidget)

                #Playing it safe in applying the formatting for the editor controls where applicable
                itemFormatter = None

                if isinstance(stdmWidget, ComposerTableDataSourceEditor):
                    itemFormatter = TableFormatter()

                if isinstance(composer_item, QgsComposerArrow):
                    itemFormatter = LineFormatter()

                elif isinstance(composer_item, QgsComposerLabel):
                    itemFormatter = DataLabelFormatter()

                elif isinstance(composer_item, QgsComposerMap):
                    itemFormatter = MapFormatter()

                elif isinstance(composer_item, QgsComposerPicture):
                    """
                    Use widget attribute to distinguish type i.e.
                    whether it is a photo, graph etc.
                    """
                    editor_widget = self._widgetMappings[composer_item.uuid()]

                    if isinstance(editor_widget,
                                  ComposerPhotoDataSourceEditor):
                        itemFormatter = PhotoFormatter()

                    elif isinstance(editor_widget, ComposerChartConfigEditor):
                        itemFormatter = ChartFormatter()

                    elif isinstance(editor_widget,
                                    QRCodeConfigurationCollection.editor_type):
                        itemFormatter = QRCodeFormatter()

                elif isinstance(composer_item, QgsComposerAttributeTableV2):
                    itemFormatter = TableFormatter()

                if itemFormatter is not None:
                    itemFormatter.apply(composer_item, self, True)

            else:
                self._stdmItemPropDock.setWidget(None)

        elif len(selectedItems) > 1:
            self._stdmItemPropDock.setWidget(None)
Exemplo n.º 4
0
class ComposerWrapper(QObject):
    """
    Embeds custom STDM tools in a QgsComposer instance for managing map-based
    STDM document templates.
    """
    dataSourceSelected = pyqtSignal(str)
    
    def __init__(self, composerView, iface):
        QObject.__init__(self, composerView)
        
        self._compView = composerView
        self._stdmTB = self.mainWindow().addToolBar("STDM")
        self._selectMoveAction = None
        self._iface = iface
        
        #Container for custom editor widgets
        self._widgetMappings = {}

        #Hide default dock widgets
        if not self.itemDock() is None:
            self.itemDock().hide()

        if not self.atlasDock() is None:
            self.atlasDock().hide()

        if not self.generalDock() is None:
            self.generalDock().hide()
        
        #Create dock widget for configuring STDM data source
        self._stdmDataSourceDock = QDockWidget(
            QApplication.translate("ComposerWrapper","STDM Data Source"),
            self.mainWindow())
        self._stdmDataSourceDock.setObjectName("STDMDataSourceDock")
        self._stdmDataSourceDock.setMinimumWidth(300)
        self._stdmDataSourceDock.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,
                                        self._stdmDataSourceDock)
        
        self._dataSourceWidget = ComposerDataSourceSelector()
        self._stdmDataSourceDock.setWidget(self._dataSourceWidget)
        self._stdmDataSourceDock.show()

        #Re-insert dock widgets
        if not self.generalDock() is None:
            self.generalDock().show()

        if not self.itemDock() is None:
            self.itemDock().show()
        
        #Create dock widget for configuring STDM item properties
        self._stdmItemPropDock = QDockWidget(
            QApplication.translate("ComposerWrapper","STDM item properties"),
            self.mainWindow())

        self._stdmItemPropDock.setObjectName("STDMItemDock")
        self._stdmItemPropDock.setMinimumWidth(300)
        self._stdmItemPropDock.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,self._stdmItemPropDock)
        self._stdmItemPropDock.show()

        #Re-arrange dock widgets and push up STDM data source dock widget
        if not self.generalDock() is None:
            self.mainWindow().splitDockWidget(self._stdmDataSourceDock,
                                              self.generalDock(),Qt.Vertical)
        
        if not self.itemDock() is None:
            self.mainWindow().splitDockWidget(self._stdmDataSourceDock,
                                             self.itemDock(),Qt.Vertical)
            if not self.generalDock() is None:
                self.mainWindow().tabifyDockWidget(self.generalDock(),
                                              self.itemDock())

        if not self.itemDock() is None:
            self.mainWindow().splitDockWidget(self.itemDock(),
                                              self._stdmItemPropDock,
                                              Qt.Vertical)

        #Set focus on composition properties window
        if not self.generalDock() is None:
            self.generalDock().activateWindow()
            self.generalDock().raise_()
            
        #Connect signals
        self.composition().itemRemoved.connect(self._onItemRemoved)
        self._dataSourceWidget.cboDataSource.currentIndexChanged[str].connect(
            self.propagateDataSourceSelection
        )
        self.composerView().selectedItemChanged.connect(self._onItemSelected)
        
        #Current template document file
        self._currDocFile = None
        
    def _removeActions(self):
        """
        Remove inapplicable actions and their corresponding toolbars and menus.
        """
        removeActions = ["mActionSaveProject","mActionNewComposer","mActionDuplicateComposer"]
        
        composerToolbar = self.composerMainToolBar()
        if composerToolbar != None:
            saveProjectAction = None
            
            for itemAction in composerToolbar.actions():
                if itemAction.objectName() == "mActionSaveProject":
                    saveProjectAction = itemAction
                    break
                
            if saveProjectAction != None:
                composerMenu = saveProjectAction.menu()
        
    def configure(self):
        #Create instances of custom STDM composer item configurations
        for ciConfig in ComposerItemConfig.itemConfigurations:
            ciConfigObj = ciConfig(self)
            
    def addWidgetMapping(self,uniqueIdentifier,widget):
        """
        Add custom STDM editor widget based on the unique identifier of the composer item
        """
        self._widgetMappings[uniqueIdentifier] = widget
        
    def widgetMappings(self):
        """
        Returns a dictionary containing uuid values of composer items linked to STDM widgets.
        """
        return self._widgetMappings
    
    def clearWidgetMappings(self):
        """
        Resets the widget mappings collection.
        """
        self._widgetMappings = {}
        
    def mainWindow(self):
        """
        Returns the QMainWindow used by the composer view.
        """
        return self._compView.composerWindow()
    
    def stdmToolBar(self):
        """
        Returns the instance of the STDM toolbar added to the QgsComposer.
        """
        return self._stdmTB
    
    def composerView(self):
        """
        Returns the composer view.
        """
        return self._compView
    
    def composition(self):
        """
        Returns the QgsComposition instance used in the composer view.
        """
        return self._compView.composition()
    
    def composerItemToolBar(self):
        """
        Returns the toolbar containing actions for adding composer items.
        """
        return self.mainWindow().findChild(QToolBar,"mItemToolbar")
    
    def composerMainToolBar(self):
        """
        Returns the toolbar containing actions for managing templates.
        """
        return self.mainWindow().findChild(QToolBar,"mComposerToolbar")
    
    def selectMoveAction(self):
        """
        Returns the QAction for selecting or moving composer items.
        """
        if self.composerItemToolBar() != None:
            if self._selectMoveAction == None:
                for itemAction in self.composerItemToolBar().actions():
                    if itemAction.objectName() == "mActionSelectMoveItem":
                        self._selectMoveAction = itemAction
                        break
        
        return self._selectMoveAction
    
    def checkedItemAction(self):
        """
        Returns the currently selected composer item action.
        """
        if self.selectMoveAction() != None:
            return self.selectMoveAction().actionGroup().checkedAction()
        
        return None
    
    def itemDock(self):
        """
        Get the 'Item Properties' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget,"ItemDock")
    
    def atlasDock(self):
        """
        Get the 'Atlas generation' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget,"AtlasDock")
    
    def generalDock(self):
        """
        Get the 'Composition' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget,"CompositionDock")
    
    def stdmDataSourceDock(self):
        """
        Returns the STDM data source dock widget.
        """
        return self._stdmDataSourceDock
    
    def stdmItemDock(self):
        """
        Returns the STDM item dock widget.
        """
        return self._stdmItemPropDock
    
    def documentFile(self):
        """
        Returns the QFile instance associated with the current document. 'None' will be returned for
        new, unsaved documents.
        """
        return self._currDocFile
    
    def setDocumentFile(self,docFile):
        """
        Sets the document file.
        """
        if not isinstance(docFile,QFile):
            return
        
        self._currDocFile = docFile
    
    def selectedDataSource(self):
        """
        Returns the name of the data source specified by the user.
        """
        return self._stdmDataSourceDock.widget().cboDataSource.currentText()
    
    def selectedDataSourceCategory(self):
        """
        Returns the category (view or table) that the data source belongs to.
        """
        if self.stdmDataSourceDock().widget() != None:
            return self.stdmDataSourceDock().widget().category()
        
        return ""
    
    def propagateDataSourceSelection(self, dataSourceName):
        """
        Propagates the signal when a user select a data source. Listening objects can hook on to it.
        """
        self.dataSourceSelected.emit(dataSourceName)

    def composer_items(self):
        """
        :return: Returns a list of custom composer items.
        :rtype: list
        """
        return [self.composition().getComposerItemById(uuid) for uuid in self._widgetMappings.keys()
                if not self.composition().getComposerItemById(uuid) is None]

    def _clear_composition(self):
        """
        Removes composer items which, otherwise, are causing QGIS to crash
        when loading a subsequent document template.
        """
        items = self.composition().items()

        for c_item in items:
            if isinstance(c_item, QgsComposerItem) and not isinstance(c_item, QgsPaperItem):
                if c_item.uuid() in self._widgetMappings:
                    #Remove corresponding widget as well as reference in the collection
                    del self._widgetMappings[c_item.uuid()]

                self.composition().removeItem(c_item)
                self.composition().itemRemoved.emit(c_item)

                del c_item

        self.composition().undoStack().clear()
        self.composition().itemsModel().clear()

    def create_new_document_designer(self, file_path):
        """
        Creates a new document designer and loads the document template
        defined in file path.
        :param file_path: Path to document template
        :type file_path: str
        """
        document_designer = self._iface.createNewComposer("STDM Document Designer")

        #Embed STDM customizations
        cw = ComposerWrapper(document_designer, self._iface)
        cw.configure()

        #Load template
        cw.loadTemplate(file_path)
        
    def loadTemplate(self, filePath):
        """
        Loads a document template into the view and updates the necessary STDM-related composer items.
        """
        if not QFile.exists(filePath):
                QMessageBox.critical(self.composerView(),
                                     QApplication.translate("OpenTemplateConfig",
                                                            "Open Template Error"),
                                    QApplication.translate("OpenTemplateConfig",
                                                           "The specified template does not exist."))
                return
            
        templateFile = QFile(filePath)
        
        if not templateFile.open(QIODevice.ReadOnly):
            QMessageBox.critical(self.composerView(),
                                 QApplication.translate("ComposerWrapper",
                                                        "Open Operation Error"),
                                            "{0}\n{1}".format(QApplication.translate(
                                                "ComposerWrapper",
                                                "Cannot read template file."),
                                                      templateFile.errorString()
                                                      ))
            return    
         
        templateDoc = QDomDocument()
        
        if templateDoc.setContent(templateFile):
            table_config_collection = TableConfigurationCollection.create(templateDoc)

            '''
            First load vector layers for the table definitions in the config
            collection before loading rhe composition from file.
            '''
            load_table_layers(table_config_collection)

            #Load items into the composition and configure STDM data controls
            self.composition().loadFromTemplate(templateDoc)

            self.clearWidgetMappings()
            
            #Load data controls
            composerDS = ComposerDataSource.create(templateDoc)

            #Set title by appending template name
            title = QApplication.translate("STDMPlugin", "STDM Document Designer")

            composer_el = templateDoc.documentElement()
            if not composer_el is None:
                template_name = ""
                if composer_el.hasAttribute("title"):
                    template_name = composer_el.attribute("title", "")
                elif composer_el.hasAttribute("_title"):
                    template_name = composer_el.attribute("_title", "")

                if template_name:
                    win_title = u"{0} - {1}".format(title, template_name)
                    self.mainWindow().setWindowTitle(template_name)

            self._configure_data_controls(composerDS)
            
            #Load symbol editors
            spatialFieldsConfig = SpatialFieldsConfiguration.create(templateDoc)
            self._configureSpatialSymbolEditor(spatialFieldsConfig)

            #Load photo editors
            photo_config_collection = PhotoConfigurationCollection.create(templateDoc)
            self._configure_photo_editors(photo_config_collection)

            #Load table editors
            self._configure_table_editors(table_config_collection)

            #Load chart property editors
            chart_config_collection = ChartConfigurationCollection.create(templateDoc)
            self._configure_chart_editors(chart_config_collection)

            self._sync_ids_with_uuids()
            
    def saveTemplate(self):
        """
        Creates and saves a new document template.
        """
        #Validate if the user has specified the data source
        if not self.selectedDataSource():
            QMessageBox.critical(self.composerView(),
                                 QApplication.translate("ComposerWrapper","Error"),
                                QApplication.translate("ComposerWrapper","Please specify the "
                                            "data source name for the document composition."))
            return
            
        #If it is a new unsaved document template then prompt for the document name.
        docFile = self.documentFile()
        
        if docFile is None:
            docName,ok = QInputDialog.getText(self.composerView(),
                            QApplication.translate("ComposerWrapper","Template Name"),
                            QApplication.translate("ComposerWrapper","Please enter the template name below"),
                            )

            if ok and docName:
                templateDir = self._composerTemplatesPath()
                
                if templateDir is None:
                    QMessageBox.critical(self.composerView(),
                        QApplication.translate("ComposerWrapper","Error"),
                        QApplication.translate("ComposerWrapper",
                        "Directory for document templates cannot not be found."))

                    return

                absPath = templateDir + "/" + docName + ".sdt"

                #Check if there is an existing document with the same name
                caseInsenDic = CaseInsensitiveDict(documentTemplates())
                if docName in caseInsenDic:
                    result = QMessageBox.warning(self.composerView(),
                            QApplication.translate("ComposerWrapper",
                                                   "Existing Template"),
                                            u"'{0}' {1}.\nDo you want to replace the "
                                            "existing template?".format(docName,
                                            QApplication.translate("ComposerWrapper",
                                                                   "already exists")),
                                            QMessageBox.Yes|QMessageBox.No)

                    if result == QMessageBox.Yes:
                        #Delete the existing template
                        delFile = QFile(absPath)
                        remStatus = delFile.remove()
                        if not remStatus:
                            QMessageBox.critical(self.composerView(),
                            QApplication.translate("ComposerWrapper",
                                                   "Delete Error"),
                                            "'{0}' {1}.".format(docName,
                            QApplication.translate("ComposerWrapper",
                            "template could not be removed by the system,"
                            " please remove it manually from the document templates directory.")))
                            return

                    else:
                        return

                docFile= QFile(absPath)
            
            else:
                return
        
        docFileInfo = QFileInfo(docFile)
        
        if not docFile.open(QIODevice.WriteOnly):
            QMessageBox.critical(self.composerView(),
                                 QApplication.translate("ComposerWrapper",
                                "Save Operation Error"),
                                "{0}\n{1}".format(QApplication.translate("ComposerWrapper",
                                "Could not save template file."),
                                                      docFile.errorString()
                                ))

            return
                                              
        templateDoc = QDomDocument()
        template_name = docFileInfo.completeBaseName()
        self._writeXML(templateDoc, template_name)
        
        if docFile.write(templateDoc.toByteArray()) == -1:
            QMessageBox.critical(self.composerView(),
            QApplication.translate("ComposerWrapper","Save Error"),
            QApplication.translate("ComposerWrapper","Could not save template file."))

            return

        else:
            self.mainWindow().setWindowTitle(template_name)
        
        docFile.close()
        
    def _writeXML(self, xml_doc, doc_name):
        """
        Write the template configuration into the XML document.
        """        
        #Write default composer configuration
        composer_element = xml_doc.createElement("Composer")
        composer_element.setAttribute("title", doc_name)
        composer_element.setAttribute("visible", 1)
        
        xml_doc.appendChild(composer_element)
        
        self.composition().writeXML(composer_element, xml_doc)
        
        #Write STDM data field configurations
        dataSourceElement = ComposerDataSource.domElement(self, xml_doc)
        composer_element.appendChild(dataSourceElement)
        
        #Write spatial field configurations
        spatialColumnsElement = SpatialFieldsConfiguration.domElement(self, xml_doc)
        dataSourceElement.appendChild(spatialColumnsElement)

        #Write photo configuration
        tables_element = PhotoConfigurationCollection.dom_element(self, xml_doc)
        dataSourceElement.appendChild(tables_element)

        #Write table configuration
        tables_element = TableConfigurationCollection.dom_element(self, xml_doc)
        dataSourceElement.appendChild(tables_element)

        #Write chart configuration
        charts_element = ChartConfigurationCollection.dom_element(self, xml_doc)
        dataSourceElement.appendChild(charts_element)
        
    def _configure_data_controls(self, composer_data_source):
        """
        Configure the data source and data field controls based on the composer data
        source configuration.
        """
        if not self.stdmDataSourceDock().widget() is None:
            #Set data source
            dataSourceWidget = self.stdmDataSourceDock().widget()
            dataSourceWidget.setCategory(composer_data_source.category())
            dataSourceWidget.setSelectedSource(composer_data_source.name())
            
            #Set data field controls
            for composerId in composer_data_source.dataFieldMappings().reverse:
                #Use composer item id since the uuid is stripped off
                composerItem = self.composition().getComposerItemById(composerId)
                
                if not composerItem is None:
                    compFieldSelector = ComposerFieldSelector(self, composerItem, self.composerView())
                    compFieldSelector.selectFieldName(composer_data_source.dataFieldName(composerId))
                    
                    #Add widget to the collection but now use the current uuid of the composition item
                    self.addWidgetMapping(composerItem.uuid(), compFieldSelector)
                    
    def _configureSpatialSymbolEditor(self,spatial_field_config):
        """
        Configure symbol editor controls.
        """
        if not self.stdmDataSourceDock().widget() is None:
            for item_id, spFieldsMappings in spatial_field_config.spatialFieldsMapping().iteritems():
                mapItem = self.composition().getComposerItemById(item_id)
                
                if not mapItem is None:
                    composerSymbolEditor = ComposerSymbolEditor(self, self.composerView())
                    composerSymbolEditor.add_spatial_field_mappings(spFieldsMappings)
                    
                    #Add widget to the collection but now use the current uuid of the composer map
                    self.addWidgetMapping(mapItem.uuid(), composerSymbolEditor)

    def _configure_photo_editors(self, photo_config_collection):
        """
        Creates widgets for editing photo data sources.
        :param photo_config_collection: PhotoConfigurationCollection instance.
        :type photo_config_collection: PhotoConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, photo_config in photo_config_collection.mapping().iteritems():
            pic_item = self.composition().getComposerItemById(item_id)

            if not pic_item is None:
                photo_editor = ComposerPhotoDataSourceEditor(self, self.composerView())
                photo_editor.set_configuration(photo_config)

                self.addWidgetMapping(pic_item.uuid(), photo_editor)


    def _configure_chart_editors(self, chart_config_collection):
        """
        Creates widgets for editing chart properties.
        :param chart_config_collection: ChartConfigurationCollection instance.
        :type chart_config_collection: ChartConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, chart_config in chart_config_collection.mapping().iteritems():
            chart_item = self.composition().getComposerItemById(item_id)

            if not chart_item is None:
                chart_editor = ComposerChartConfigEditor(self, self.composerView())
                chart_editor.set_configuration(chart_config)

                self.addWidgetMapping(chart_item.uuid(), chart_editor)

    def _configure_table_editors(self, table_config_collection):
        """
        Creates widgets for editing table data sources.
        :param table_config_collection: TableConfigurationCollection instance.
        :type table_config_collection: TableConfigurationCollection
        """
        if self.stdmDataSourceDock().widget() is None:
            return

        for item_id, table_config in table_config_collection.mapping().iteritems():
            table_item = self.composition().getComposerItemById(item_id)

            if not table_item is None:
                table_editor = ComposerTableDataSourceEditor(self, table_item, self.composerView())
                table_editor.set_configuration(table_config)

                self.addWidgetMapping(table_item.uuid(), table_editor)

    def _sync_ids_with_uuids(self):
        """
        Matches IDs of custom STDM items with the corresponding UUIDs. This
        is applied when loading existing templates so that the saved
        document contains a matching pair of ID and UUID for each composer
        item.
        """
        items = self._widgetMappings.keys()
        for item_uuid in self._widgetMappings.keys():
            item = self.composition().getComposerItemByUuid(item_uuid)
            if not item is None:
                item.setId(item_uuid)
                        
    def _composerTemplatesPath(self):
        """
        Reads the path of composer templates in the registry.
        """
        regConfig = RegistryConfig()
        keyName = "ComposerTemplates"
        
        valueCollection = regConfig.read([keyName])
        
        if len(valueCollection) == 0:
            return None
        
        else:
            return valueCollection[keyName]
    
    def _onItemRemoved(self,item):
        """
        Slot raised when a composer item is removed from the scene.
        """
        """
        Code will not work since a QObject instance is returned instead of a QgsComposerItem
        if item.uuid() in self._widgetMappings:
            del self._widgetMappings[item.uuid()]
        """
        pass
    
    def _onItemSelected(self, item):
        """
        Slot raised when a composer item is selected. Load the corresponding field selector
        if the selection is an STDM data field label.
        QComposerLabel is returned as a QObject in the slot argument hence, we have resorted to 
        capturing the current selected items in the composition.
        """
        selectedItems = self.composition().selectedComposerItems()
        
        if len(selectedItems) == 0:
            self._stdmItemPropDock.setWidget(None)
        
        elif len(selectedItems) == 1:
            composer_item = selectedItems[0]
            
            if composer_item.uuid() in self._widgetMappings:
                stdmWidget = self._widgetMappings[composer_item.uuid()]
                
                if stdmWidget == self._stdmItemPropDock.widget():
                    return
                
                else:
                    self._stdmItemPropDock.setWidget(stdmWidget)
                    
                #Playing it safe in applying the formatting for the editor controls where applicable
                itemFormatter = None

                if isinstance(composer_item, QgsComposerArrow):
                    itemFormatter = LineFormatter()

                elif isinstance(composer_item, QgsComposerLabel):
                    itemFormatter = DataLabelFormatter()

                elif isinstance(composer_item, QgsComposerMap):
                    itemFormatter = MapFormatter()

                elif isinstance(composer_item, QgsComposerPicture):
                    """
                    Use widget attribute to distinguish type i.e.
                    whether it is a photo, graph etc.
                    """
                    editor_widget = self._widgetMappings[composer_item.uuid()]

                    if isinstance(editor_widget, ComposerPhotoDataSourceEditor):
                        itemFormatter = PhotoFormatter()

                    elif isinstance(editor_widget, ComposerChartConfigEditor):
                        itemFormatter = ChartFormatter()

                elif isinstance(composer_item, QgsComposerAttributeTable):
                    itemFormatter = TableFormatter()
                        
                if not itemFormatter is None:
                    itemFormatter.apply(composer_item, self, True)
                    
            else:
                self._stdmItemPropDock.setWidget(None)
            
        elif len(selectedItems) > 1:
            self._stdmItemPropDock.setWidget(None)
Exemplo n.º 5
0
class Main(plugin.Plugin):
    " Main Class "
    def initialize(self, *args, **kwargs):
        " Init Main Class "
        ec = ExplorerContainer()
        super(Main, self).initialize(*args, **kwargs)

        self.editor_s = self.locator.get_service('editor')
        # directory auto completer
        self.completer = QCompleter(self)
        self.dirs = QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)

        self.group0 = QGroupBox()
        self.group0.setTitle(' Source ')
        self.source = QComboBox()
        self.source.addItems(['Clipboard', 'Local File', 'Remote URL', 'Ninja'])
        self.source.currentIndexChanged.connect(self.on_source_changed)
        self.infile = QLineEdit(path.expanduser("~"))
        self.infile.setPlaceholderText(' /full/path/to/file.html ')
        self.infile.setCompleter(self.completer)
        self.open = QPushButton(QIcon.fromTheme("folder-open"), 'Open')
        self.open.setCursor(QCursor(Qt.PointingHandCursor))
        self.open.clicked.connect(lambda: self.infile.setText(str(
            QFileDialog.getOpenFileName(self.dock, "Open a File to read from",
            path.expanduser("~"), ';;'.join(['{}(*.{})'.format(e.upper(), e)
            for e in ['css', 'html', 'js', 'txt', '*']])))))
        self.inurl = QLineEdit('http://www.')
        self.inurl.setPlaceholderText('http://www.full/url/to/remote/file.html')
        self.output = QPlainTextEdit(SAMPLE_TEXT)
        vboxg0 = QVBoxLayout(self.group0)
        for each_widget in (self.source, self.infile, self.open, self.inurl,
            self.output, ):
            vboxg0.addWidget(each_widget)
        [a.hide() for a in iter((self.infile, self.open, self.inurl))]

        self.group1 = QGroupBox()
        self.group1.setTitle(' CSS3 ')
        self.group1.setCheckable(True)
        self.group1.setGraphicsEffect(QGraphicsBlurEffect(self))
        self.group1.graphicsEffect().setEnabled(False)
        self.group1.toggled.connect(self.toggle_css_group)
        self.ckcss1 = QCheckBox('Remove unnecessary Comments')
        self.ckcss2 = QCheckBox('Remove unnecessary Whitespace characters')
        self.ckcss3 = QCheckBox('Remove unnecessary Semicolons')
        self.ckcss4 = QCheckBox('Remove unnecessary Empty rules')
        self.ckcss5 = QCheckBox('Condense and Convert Colors from RGB to HEX')
        self.ckcss6 = QCheckBox('Condense all Zero units')
        self.ckcss7 = QCheckBox('Condense Multidimensional Zero units')
        self.ckcss8 = QCheckBox('Condense Floating point numbers')
        self.ckcss9 = QCheckBox('Condense HEX Colors')
        self.ckcss10 = QCheckBox('Condense multiple adjacent Whitespace chars')
        self.ckcss11 = QCheckBox('Condense multiple adjacent semicolon chars')
        self.ckcss12 = QCheckBox('Wrap the lines of the to 80 character length')
        self.ckcss13 = QCheckBox('Condense Font Weight values')
        self.ckcss14 = QCheckBox('Condense the 17 Standard Named Colors values')
        self.ckcss15 = QCheckBox('Condense the 124 Extra Named Colors values')
        self.ckcss16 = QCheckBox('Condense all Percentages values when posible')
        self.ckcss17 = QCheckBox('Condense all Pixels values when posible')
        self.ckcss18 = QCheckBox('Remove unnecessary quotes from url()')
        self.ckcss19 = QCheckBox('Add standard Encoding Declaration if missing')
        vboxg1 = QVBoxLayout(self.group1)
        for each_widget in (self.ckcss1, self.ckcss2, self.ckcss3, self.ckcss4,
            self.ckcss5, self.ckcss6, self.ckcss7, self.ckcss8, self.ckcss9,
            self.ckcss10, self.ckcss11, self.ckcss12, self.ckcss13,
            self.ckcss14, self.ckcss15, self.ckcss16, self.ckcss17,
            self.ckcss18, self.ckcss19):
            vboxg1.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group2 = QGroupBox()
        self.group2.setTitle(' HTML5 ')
        self.group2.setCheckable(True)
        self.group2.setGraphicsEffect(QGraphicsBlurEffect(self))
        self.group2.graphicsEffect().setEnabled(False)
        self.group2.toggled.connect(self.toggle_html_group)
        self.ckhtml0 = QCheckBox('Condense Style and Script HTML Tags')
        self.ckhtml1 = QCheckBox('Condense DOCTYPE to new HTML5 Tags')
        self.ckhtml2 = QCheckBox('Condense Href and Src to protocol agnostic')
        self.ckhtml4 = QCheckBox('Remove unnecessary Tags but keep HTML valid')
        self.help1 = QLabel('''<a href=
            "https://developers.google.com/speed/articles/optimizing-html">
            <small><center>Help about Unneeded Unnecessary HTML tags ?</a>''')
        self.help1.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.help1.setOpenExternalLinks(True)
        vboxg2 = QVBoxLayout(self.group2)
        for each_widget in (self.ckhtml0, self.ckhtml1, self.ckhtml2,
            self.ckhtml4, self.help1, ):
            vboxg2.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group3 = QGroupBox()
        self.group3.setTitle(' Javascript ')
        self.ckjs0 = QCheckBox('Condense and Compress Javascript')
        self.ckjs1 = QCheckBox('Condense $(document).ready(function(){ });')
        vboxg2 = QVBoxLayout(self.group3)
        for each_widget in (self.ckjs0, self.ckjs1):
            vboxg2.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        self.group4 = QGroupBox()
        self.group4.setTitle(' General ')
        self.chckbx1 = QCheckBox('Lower case ALL the text')
        self.chckbx2 = QCheckBox('Remove Spaces, Tabs, New Lines, Empty Lines')
        self.befor, self.after = QProgressBar(), QProgressBar()
        self.befor.setFormat("%v Chars")
        self.after.setFormat("%v Chars")
        vboxg4 = QVBoxLayout(self.group4)
        for each_widget in (self.chckbx1, self.chckbx2,
            QLabel('<b>Before:'), self.befor, QLabel('<b>After:'), self.after):
            vboxg4.addWidget(each_widget)
            each_widget.setToolTip(each_widget.text())

        [a.setChecked(True) for a in iter((self.ckcss1, self.ckcss2,
            self.ckcss3, self.ckcss4, self.ckcss5, self.ckcss6, self.ckcss7,
            self.ckcss8, self.ckcss9, self.ckcss10, self.ckcss11, self.ckcss12,
            self.ckcss13, self.ckcss14, self.ckcss15, self.ckcss16,
            self.ckcss17, self.ckcss18, self.ckcss19, self.ckjs1, self.ckhtml0,
            self.ckhtml1, self.ckhtml2, self.ckhtml4, self.chckbx1,
            self.chckbx2))]

        self.button = QPushButton(QIcon.fromTheme("face-cool"), 'Process Text')
        self.button.setCursor(QCursor(Qt.PointingHandCursor))
        self.button.setMinimumSize(100, 50)
        self.button.clicked.connect(self.run)

        def must_glow(widget_list):
            ' apply an glow effect to the widget '
            for glow, each_widget in enumerate(widget_list):
                try:
                    if each_widget.graphicsEffect() is None:
                        glow = QGraphicsDropShadowEffect(self)
                        glow.setOffset(0)
                        glow.setBlurRadius(99)
                        glow.setColor(QColor(99, 255, 255))
                        each_widget.setGraphicsEffect(glow)
                        glow.setEnabled(True)
                except:
                    pass

        must_glow((self.button, ))

        class TransientWidget(QWidget):
            ' persistant widget thingy '
            def __init__(self, widget_list):
                ' init sub class '
                super(TransientWidget, self).__init__()
                vbox = QVBoxLayout(self)
                for each_widget in widget_list:
                    vbox.addWidget(each_widget)

        tw = TransientWidget((QLabel('<b>HTML5/CSS3/JS Optimizer Compressor'),
            self.group0, self.group1, self.group2, self.group3, self.group4,
            self.button, ))
        self.scrollable = QScrollArea()
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(tw)
        self.dock = QDockWidget()
        self.dock.setWindowTitle(__doc__)
        self.dock.setStyleSheet('QDockWidget::title{text-align: center;}')
        self.dock.setMinimumWidth(350)
        self.dock.setWidget(self.scrollable)
        ec.addTab(self.dock, "Web")
        QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock
          ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__,
            HELPMSG))

    def run(self):
        ' run the string replacing '
        if self.source.currentText() == 'Local File':
            with open(path.abspath(str(self.infile.text()).strip()), 'r') as f:
                txt = f.read()
        elif self.source.currentText() == 'Remote URL':
            txt = urlopen(str(self.inurl.text()).strip()).read()
        elif  self.source.currentText() == 'Clipboard':
            txt = str(self.output.toPlainText()) if str(self.output.toPlainText()) is not '' else str(QApplication.clipboard().text())
        else:
            txt = self.editor_s.get_text()
        self.output.clear()
        self.befor.setMaximum(len(txt) + 10)
        self.after.setMaximum(len(txt) + 10)
        self.befor.setValue(len(txt))
        txt = txt.lower() if self.chckbx1.isChecked() is True else txt
        txt = condense_style(txt) if self.ckhtml0.isChecked() is True else txt
        txt = condense_script(txt) if self.ckhtml0.isChecked() is True else txt
        txt = condense_doctype(txt) if self.ckhtml1.isChecked() is True else txt
        txt = condense_href_src(txt) if self.ckhtml2 is True else txt
        txt = clean_unneeded_tags(txt) if self.ckhtml4.isChecked() is True else txt
        txt = condense_doc_ready(txt) if self.ckjs1.isChecked() is True else txt
        txt = jsmin(txt) if self.ckjs0.isChecked() is True else txt
        txt = remove_comments(txt) if self.ckcss1.isChecked() is True else txt
        txt = condense_whitespace(txt) if self.ckcss10.isChecked() is True else txt
        txt = remove_empty_rules(txt) if self.ckcss4.isChecked() is True else txt
        txt = remove_unnecessary_whitespace(txt) if self.ckcss2.isChecked() is True else txt
        txt = remove_unnecessary_semicolons(txt) if self.ckcss3.isChecked() is True else txt
        txt = condense_zero_units(txt) if self.ckcss6.isChecked() is True else txt
        txt = condense_multidimensional_zeros(txt) if self.ckcss7.isChecked() is True else txt
        txt = condense_floating_points(txt) if self.ckcss8.isChecked() is True else txt
        txt = normalize_rgb_colors_to_hex(txt) if self.ckcss5.isChecked() is True else txt
        txt = condense_hex_colors(txt) if self.ckcss9.isChecked() is True else txt
        txt = wrap_css_lines(txt, 80) if self.ckcss12.isChecked() is True else txt
        txt = condense_semicolons(txt) if self.ckcss11.isChecked() is True else txt
        txt = condense_font_weight(txt) if self.ckcss13.isChecked() is True else txt
        txt = condense_std_named_colors(txt) if self.ckcss14.isChecked() is True else txt
        # txt = condense_xtra_named_colors(txt) if self.ckcss14.isChecked() is True else txt  # FIXME
        txt = condense_percentage_values(txt) if self.ckcss16.isChecked() is True else txt
        txt = condense_pixel_values(txt) if self.ckcss17.isChecked() is True else txt
        txt = remove_url_quotes(txt) if self.ckcss18.isChecked() is True else txt
        txt = add_encoding(txt) if self.ckcss19.isChecked() is True else txt
        txt = " ".join(txt.strip().split()) if self.chckbx2.isChecked() is True else txt
        self.after.setValue(len(txt))
        self.output.setPlainText(txt)
        self.output.show()
        self.output.setFocus()
        self.output.selectAll()

    def on_source_changed(self):
        ' do something when the desired source has changed '
        if self.source.currentText() == 'Local File':
            self.open.show()
            self.infile.show()
            self.inurl.hide()
            self.output.hide()
        elif  self.source.currentText() == 'Remote URL':
            self.inurl.show()
            self.open.hide()
            self.infile.hide()
            self.output.hide()
        elif  self.source.currentText() == 'Clipboard':
            self.output.show()
            self.open.hide()
            self.infile.hide()
            self.inurl.hide()
            self.output.setText(QApplication.clipboard().text())
        else:
            self.output.show()
            self.open.hide()
            self.infile.hide()
            self.inurl.hide()
            self.output.setText(self.editor_s.get_text())

    def toggle_css_group(self):
        ' toggle on or off the css checkboxes '
        if self.group1.isChecked() is True:
            [a.setChecked(True) for a in iter((self.ckcss1, self.ckcss2,
            self.ckcss3, self.ckcss4, self.ckcss5, self.ckcss6, self.ckcss7,
            self.ckcss8, self.ckcss9, self.ckcss10, self.ckcss11, self.ckcss12,
            self.ckcss13, self.ckcss14, self.ckcss15, self.ckcss16,
            self.ckcss17, self.ckcss18, self.ckcss19))]
            self.group1.graphicsEffect().setEnabled(False)
        else:
            [a.setChecked(False) for a in iter((self.ckcss1, self.ckcss2,
            self.ckcss3, self.ckcss4, self.ckcss5, self.ckcss6, self.ckcss7,
            self.ckcss8, self.ckcss9, self.ckcss10, self.ckcss11, self.ckcss12,
            self.ckcss13, self.ckcss14, self.ckcss15, self.ckcss16,
            self.ckcss17, self.ckcss18, self.ckcss19))]
            self.group1.graphicsEffect().setEnabled(True)

    def toggle_html_group(self):
        ' toggle on or off the css checkboxes '
        if self.group2.isChecked() is True:
            [a.setChecked(True) for a in iter((self.ckhtml0, self.ckhtml1,
                                               self.ckhtml2, self.ckhtml4))]
            self.group2.graphicsEffect().setEnabled(False)
        else:
            [a.setChecked(False) for a in iter((self.ckhtml0, self.ckhtml1,
                                                self.ckhtml2, self.ckhtml4))]
            self.group2.graphicsEffect().setEnabled(True)
Exemplo n.º 6
0
class MSMainWindow(QMainWindow):
    """Gui of the main window"""
    
    #MAX_RECENT_FILES = 10
    #start putting links spyder numpy scipy et tutti quanti
    links=('http://numpy.scipy.org/',
           'http://packages.python.org/spyder/',
           'http://www.riverbankcomputing.co.uk/software/pyqt/intro')
    
    pluginPath=path.normcase('pluginmanager/plugins/')    
    
    def __init__(self, availablePlugins):
        """
        Constructor with all the models needed setup menus
        
        """
        QMainWindow.__init__(self)
        self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks)
        self.plugins = availablePlugins
        self.pluginsInst=[]   
        settings=QSettings('INRA/INSA', '-'.join([QApplication.instance().APPLICATION_NAME_STR, 
                                                  QApplication.instance().VERSION_STR]))  
        self.recentFiles = list(settings.value("RecentFiles").toStringList())
        self.setStyleSheet(stylesheet)
        self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self)
        self.addToolBar(0x1,self.pipeline)
        
        self._setupModels()
        self._setupUi()        
        self._setupMenus()

    def _setupModels(self):
        """
        Warning:Causes segfault when horizontal labels set to True
        
        on aura peu etre a la fin un model par sampleList c'est ce qui parait
        le plus logique
        
        """        
        #drag and drop table sample
        self.sampleModel = QStandardItemModel(self)      
        self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"])
        #treeView1
        self.spectraModel = QStandardItemModel(self)
        #treeview2
        self.peakModel = QStandardItemModel(self)
        #treeview3
        self.clusterModel = QStandardItemModel(self)
 
    def _setupMenus(self):
        #file
        self.fileMenu = QMenu('&File')
        self.fileMenu.setTearOffEnabled(True)
        self.op=QMenu("&Open...",self.fileMenu)
        self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png")))
        
        open_=QAction("&Open rawfiles", self)
        open_.setToolTip("Open an mzXML or netCDF file")
        open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O))
        open_icon=QIcon(path.normcase("gui/icons/fileopen.png"))
        open_.setIcon(open_icon)
        self.op.addAction(open_)
        
        load_=QAction("&Open projects...", self)
        load_.setToolTip("load binary file containing saved objects")
        load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        load_icon=QIcon(QPixmap(path.normcase("gui/icons/project_open.png")))
        load_.setIcon(load_icon)
        self.op.addAction(load_)
        
        self.fileMenu.addMenu(self.op)
        
        save_=QAction("&Save...", self)
        save_.setToolTip("save the actual application model")
        save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        save_icon=QIcon(path.normcase("gui/icons/save_all.png"))
        save_.setIcon(save_icon)
        self.fileMenu.addAction(save_)
        
        pkl = QAction("&load a peaklist", self) #TODO:load peaklist
        pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P))
        pkl.setToolTip("load a peaklist and process it")
        pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png")))
        self.fileMenu.addAction(pkl)
        
        convert_=QAction("&Convert...", self)
        convert_.setEnabled(False)
        convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed")        
        convert_icon=QIcon(path.normcase("gui/icons/goto.png"))
        convert_.setIcon(convert_icon)
        self.fileMenu.addAction(convert_)
        
        a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch")
        a.setEnabled(False)
        
        b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge")
        b.setToolTip("Merge MRM file")
        #b.setEnabled(False)
        
        self.fileMenu.addSeparator()
#        
#        for i in xrange(self.MAX_RECENT_FILES):
#            a = QAction('', self)
#            a.setVisible(False)
#            self.fileMenu.addAction(a)
#        
#        for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))):
#            self.fileMenu.actions()[5+i].setVisible(True)
#            self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1])
            
        
        exit_action =QAction("&Exit", self)
        exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q))
        exit_action.setIcon(QIcon(QPixmap(path.normcase('gui/icons/exit.png'))))
        self.fileMenu.addAction(exit_action)
        
        self.menuBar().addMenu(self.fileMenu)
        
        self.editMenu=QMenu("&Edit")
        self.editMenu.setTearOffEnabled(True)
        self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_undo.png')), '&Undo...')
        self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_redo.png')), '&Redo...')
        self.editMenu.actions()[0].setEnabled(False)
        self.editMenu.actions()[1].setEnabled(False)
        self.editMenu.addSeparator()
        self.editMenu.addAction(QIcon(path.normcase('gui/icons/run.png')), '&Preferences')
        self.exportMenu = QMenu("&Export...")
        self.exportMenu.setIcon(QIcon(path.normcase('gui/icons/file_export.png')))
        self.exportMenu.addAction("&Peaklist")        
        self.exportMenu.addAction("&Clusters intensity matrix")
        self.editMenu.addMenu(self.exportMenu)        
        self.menuBar().addMenu(self.editMenu)
        
        
        #view
        self.viewMenu =QMenu("&View")
        self.viewMenu.setTearOffEnabled(True)
        self.viewMenu.addAction(QIcon(path.normcase('gui/icons/window_duplicate')),
                                "&Cascade View", 
                                self.mdiArea.cascadeSubWindows, 
                                QKeySequence(Qt.CTRL + Qt.Key_K))
        self.viewMenu.addAction(QIcon(path.normcase('gui/icons/view_icon')),
                                "&Title View", 
                                self.mdiArea.tileSubWindows, 
                                QKeySequence(Qt.CTRL + Qt.Key_N))
        self.viewMenu.addAction(QIcon(path.normcase("gui/icons/stop_process.png")),
                                "&Close all subWindows",
                                self.mdiArea.closeAllSubWindows,
                                QKeySequence(Qt.CTRL+Qt.Key_W))
        
        self.plotting =QMenu("&Plotting...")
        self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png"))))
        self.plotting.addAction("&3D Plot")
        #self.plotting.addAction("&Cytoscape web")
        self.plotting.addAction("&Spectrogram Plot")
        
        #self.multiplePlot = QAction("&Visualize Raw/Treated Data", self)
        #self.multiplePlot.setCheckable(True)
        #self.multiplePlot.setEnabled(False)
        #self.sub_plot_.addAction(self.multiplePlot)
       
        self.viewMenu.addMenu(self.plotting)
        self.viewMenu.addSeparator()
        self.show_hide=QMenu("&Show/Hide")
        m=self.createPopupMenu()
        m.setTitle("&Show/Hide")
        self.viewMenu.addMenu(m)
        #self.pref = QMenu("&Preferences")
       
        #self.pref.addAction(self.multiplePlot)
        #self.viewMenu.addMenu(self.pref)
        self.menuBar().addMenu(self.viewMenu)

        #algorithm
        self.algoMenu= QMenu("&Algorithm")
        self.algoMenu.setTearOffEnabled(True)
        self.preProcessing=QMenu("&PreProcessing(experimental)")
        self.preProcessing.addAction("&Smoothing raw data...")
        self.preProcessing.addAction("&Cut off raw data...")
        self.preProcessing.addAction('&Calibration (mz dimension)')
        self.preProcessing.addAction("&Resize sample...")
        
        self.algoMenu.addMenu(self.preProcessing)
        
        self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self)
        self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png")))
        
        matched = QAction("&MatchedFiltered", self)
        matched.setIcon(QIcon(path.normcase('gui/icons/RLogo')))
        matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm")
        self.peakPickingMenu.addAction(matched)        
        
        centwave=QAction("&CentWave", self)
        centwave.setIcon(QIcon(path.normcase('gui/icons/RLogo')))
        centwave.setToolTip("Peak Detection and Integration using CentWave algorithm")
        self.peakPickingMenu.addAction(centwave)
        #peak_.setShortcut(.QKeySequence(CTRL + Key_P))
       # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png")))
        #peak_.setIcon(peak_icon)
        self.algoMenu.addMenu(self.peakPickingMenu)
        
        self.alignment = QMenu("&Alignment")
        self.alignment.setIcon(QIcon(path.normcase('gui/icons/format_indent_more.png')))
        self.alignment.addAction("&Polynomial fitting(exp)")
        self.alignment.addAction("&DynamicTimeWarping")
        self.alignment.addAction("&ObiWarp")
        self.alignment.actions()[2].setEnabled(False)
        self.algoMenu.addMenu(self.alignment)
        
        self.algoMenu.addAction("Normalization")
        
        clust_ =  QAction("&Clustering", self)
        clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L))
        clust_icon=QIcon(QPixmap(path.normcase("gui/icons/cluster.png")))
        clust_.setIcon(clust_icon)
        self.algoMenu.addAction(clust_)
        
        id_ =  QAction("&Identification", self)
        id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I))
        id_.setToolTip("Try to identify peaks with several methods")
        id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png"))))
        self.algoMenu.addAction(id_)
        self.menuBar().addMenu(self.algoMenu)        
        
     
        
        #tools
        self.toolsMenu =QMenu("&Tools")
        self.toolsMenu.setTearOffEnabled(True)
        web =  QAction("&Web Browser", self)
        web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png"))))
        self.toolsMenu.addAction(web)
        #cyto = QAction("&cytoscape", self)
        #cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg")))
        #cyto.setIcon(cyto_icon)
        #self.toolsMenu.addAction(cyto)
        editor = QAction("&Editor", self)
        editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png"))))
        self.toolsMenu.addAction(editor)
        pet=QAction("&Short Periodic Table", self)  
        pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg"))))
        self.toolsMenu.addAction(pet)
        self.menuBar().addMenu(self.toolsMenu)
        
        #plugins
        self.pluginMenu = QMenu('&Plugins')
        self.pluginMenu.setTearOffEnabled(True)
        instPl=  QAction("&Install a plugin", self)
        instPl.setIcon(QIcon(path.normcase('gui/icons/pluginInstall.png')))
        self.pluginMenu.addAction(instPl)
        self.launchingMenu = QMenu("&Launch PLugins", self)
        self.launchingMenu.setIcon(QIcon(path.normcase('gui/icons/plugin')))
        
        for plug in self.plugins:
            #fullname="".join([self.pluginPath, str(plug)])
            mod=imp.load_source(self.__module__, plug)
            if mod.autoActivation:
                qApp=QApplication.instance()
                name=getattr(mod, 'className')
                cls=getattr(mod, name)
                p=cls(qApp.model, self, parent=self)                
                #p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1])
                self.pluginsInst.append(p)
            else:
                self.launchingMenu.addAction(plug.split('/')[-1])
        self.pluginMenu.addMenu(self.launchingMenu)
        self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")),
                                        "&Remove loaded Plugin")
        self.menuBar().addMenu(self.pluginMenu)
        
        #about
        self.aboutMenu= QMenu("&About")
        self.aboutMenu.setTearOffEnabled(True)
        metms = QAction(QIcon(path.normcase('gui/icons/deluge.png')), "&about metMS...", self)
        self.aboutMenu.addAction(metms)
        
        pyqt =  QAction("&about PyQt4...", self)
        pyqt_icon =QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png")))
        pyqt.setIcon(pyqt_icon)
        self.aboutMenu.addAction(pyqt)
        metms =  QAction("&metMS Documentation", self)
        metms_icon =QIcon(QPixmap(path.normcase("gui/icons/deluge.png")))
        metms.setIcon(metms_icon)
        self.aboutMenu.addAction(metms)
        self.menuBar().addMenu(self.aboutMenu)
        

    def _setupUi(self, background=None):
        """        
        Make the GUI
        
        """
        #mdi
        self.mdiArea = MSMdiArea(self)
        self.mdiArea.setBackground(QBrush(QPixmap(path.normcase('gui/icons/blac2.png'))))#QColor(Qt.blue).darker()))
        self.setCentralWidget(self.mdiArea)
        
        
        #sample dock widget
        self.sampleDockWidget = QDockWidget("Samples", self)
        #sampleWidget = QWidget()
        self.sampleTableView = MSDragFromTableView()
        self.sampleTableView.setModel(self.sampleModel)
        self.sampleTableView.setSelectionBehavior(1)
        self.sampleTableView.verticalHeader().hide()
        self.sampleTableView.verticalHeader().setDefaultSectionSize(15)        
        self.sampleTableView.horizontalHeader().setDefaultSectionSize(150)
        

        self.sampleDockWidget.setWidget(self.sampleTableView)#sampleWidget)
        self.sampleDockWidget.visible=True
        
        
        #workflow dock
        self.workflowDockWidget = QDockWidget("Visualizer", self)
        self.workflowDockWidget.visible = True

        a=QWidget(self)
        v=QVBoxLayout(a)
        q=QToolBar()
        #self.workingSample = QLabel("Working Sample:None")
        #q.addWidget(self.workingSample)
        q.addWidget(QLabel("ppm :"))
        self.ppmEditer=QDoubleSpinBox()
        self.usePpm=QCheckBox("use ?")  
        q.addWidget(self.ppmEditer)
        q.addWidget(self.usePpm)
        
        q.addSeparator()
        
        self.removeButton=QToolButton(self)
        self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png")))           
        q.addWidget(self.removeButton)
        
        self.markAsGood=QAction(QIcon(path.normcase("gui/icons/button_ok.png")),"mark peak as good", self)
        self.markAsBad=QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self)
        self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self)
        
        q.addAction(self.markAsGood)
        q.addAction(self.markAsBad)
        q.addAction(self.hideItem)
        v.addWidget(q)        
        
        
        self.tabWidget = QTabWidget()
        self.tab = QWidget()
        verticalLayout = QVBoxLayout(self.tab)
        self.treeView = MSToDropTableView()
        self.treeView.verticalHeader().setDefaultSectionSize(20)
        
        self.treeView.setModel(self.spectraModel)
        self.spectraLabel = QLabel("Sample: None")
        verticalLayout.addWidget(self.treeView)
        verticalLayout.addWidget(self.spectraLabel)
        self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")),"Spectra")
        
        self.tab_2 = QWidget()
        verticalLayout_4 = QVBoxLayout(self.tab_2)
        self.treeView_2 = MSToDropTableView()#MSTreeView(self.tab_2)# QTableView(self)#
        self.treeView_2.verticalHeader().setDefaultSectionSize(20)
        self.treeView_2.setModel(self.peakModel)
        self.peakLabel = QLabel("Sample: None")
        verticalLayout_4.addWidget(self.treeView_2)
        verticalLayout_4.addWidget(self.peakLabel)
        self.tabWidget.addTab(self.tab_2,QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List")
        
        self.tab_3 = QWidget()
        verticalLayout_5 = QVBoxLayout(self.tab_3)
        self.treeView_3 = MSToDropTreeView()
        self.treeView_3.setAnimated(True)
        self.treeView_3.setModel(self.clusterModel)
        self.clusterLabel = QLabel("Sample: None")
        verticalLayout_5.addWidget(self.treeView_3)
        verticalLayout_5.addWidget(self.clusterLabel)
        self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters")
        
        self.tabWidget.setCurrentIndex(0)
        
        for l in (self.spectraLabel, self.peakLabel, self.clusterLabel):
            l.setAutoFillBackground(True)
            
        v.addWidget(self.tabWidget)
        self.workflowDockWidget.setWidget(a)
        self.addDockWidget(Qt.DockWidgetArea(0x2),self.workflowDockWidget)        
        
                
        from gui.MetBaseGui import MSIsoCalculator
        self.isoCalc = MSIsoCalculator(self)
        self.isoCalcDockWidget=QDockWidget('isotopes calculation', self)
        self.isoCalcDockWidget.setWidget(self.isoCalc)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget)
        self.isoCalcDockWidget.setVisible(False)
        self.isoCalcDockWidget.visible=False
        
        from gui.MetBaseGui import FormulaGenerator
        self.generator=FormulaGenerator(self)
        self.generatorDockWidget=QDockWidget('formula generator', self)
        self.generatorDockWidget.setWidget(self.generator)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget)
        self.generatorDockWidget.setVisible(False)
        self.generatorDockWidget.visible=False
        
        self.compoundTreeView = MSCompoundTreeView(self)
        self.compoundDockWidget = QDockWidget("Compounds", self)
        self.compoundDockWidget.setWidget(self.compoundTreeView)
        self.addDockWidget(Qt.DockWidgetArea(0x2),self.compoundDockWidget)
        self.compoundDockWidget.setVisible(False)
        self.compoundDockWidget.visible=False
        
        self.comparativeTableView = QTableView(self)
        self.comparativeTableView.horizontalHeader().setStretchLastSection(True)
        self.comparativeTableView.verticalHeader().setDefaultSectionSize(20)
        self.comparativeDock = QDockWidget("Comparative View", self)
        self.comparativeDock.setWidget(self.comparativeTableView)
        self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock)
        self.comparativeDock.setVisible(False)
        self.comparativeDock.visible = False
        
        self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget)
        self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget )
        self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget)
        #set the end
        
        #WARNING: possible that the internal shell widget cause random segfault
        #with the error of QObject::killTimers...? not sure !
        self.shell = QWidget()#InternalShell(namespace={'metms': QApplication.instance()}, 
                     #              parent=self, 
                     #              multithreaded=False)
        self.shellDock = QDockWidget("Python Shell", self)
        self.shellDock.setWindowIcon(QIcon(path.normcase('gui/icons/stop.png')))
        self.shellDock.setWidget(self.shell)
        self.shellDock.setMinimumWidth(255)
        self.shellDock.visible=True
        self.addDockWidget(0x2, self.shellDock)

        self.addDockWidget(0x2, self.sampleDockWidget)
        self.tabifyDockWidget(self.shellDock, self.sampleDockWidget)
        
        self.pb = QProgressBar(self)
        self.pb.setMaximumWidth(245)
        
        self.stopProcess = QToolButton(self)
        self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png")))        
        m = QMenu()
        #self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName)
        self.stopProcess.setMenu(m)
        self.stopProcess.setPopupMode(1) #Menu Button
        #self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread)
        
        self.statusBar().addPermanentWidget(self.stopProcess)
        self.statusBar().addPermanentWidget(self.pb)
    
    def updateStopProcessMenu(self):
        """
        update the menu of the stop process
        button, based directly on the processes
        stored by the task manager
        
        """
        self.stopProcess.menu().clear()
        for c in QApplication.instance().taskManager:
            self.stopProcess.menu().addAction(c.title)
        
        #QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1])
        
    def addMdiSubWindow(self, plot, title="", showMaximized=False):
        """ 
        Allow addition of new window in the mdiarea
        
        """        
        win=self.mdiArea.addSubWindow(plot)
        #print "widget parent", plot.parent()
        win.setAttribute(Qt.WA_DeleteOnClose)
        #win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy)
        #plot.setParent(win)
        win.setWindowTitle(title)
        if showMaximized:
            win.showMaximized()
        else:
            win.resize(400, 300)
        win.show()
        return win
   

           
    def updateTreeView(self):
        """
        Tree View update switch spectre/chromato
        
        """
        if self.treeView.model() == self.spectraModel:
            self.treeView.setModel(self.chromaModel)
            self.tabWidget.setTabText(0, "Chroma")
        else:
            self.treeView.setModel(self.spectraModel)
            #self.treeView.setSelectionMode(1)
            self.tabWidget.setTabText(0, "Spectra")
    
    def addTreeViewModel (self,model1, model2):
        """Add a model """
        self.chromaModel.appendRow(model1)
        self.spectraModel.appendRow(model2)
    
    
    def _actionHovered(self, action):
        """emulate tooltip cause they do not work that much"""
        tip = action.toolTip()
        QToolTip.showText(QCursor.pos(), tip)
    

    def showErrorMessage(self, title, string):
        QMessageBox.critical(self, title, string, 0, 0)
    
    
    def showWarningMessage(self, title, string):
        return QMessageBox.warning(self, title, string, QMessageBox.Ok|QMessageBox.Cancel)
    
    
    def showInformationMessage(self, title, string):
        QMessageBox.information(self, title, string, 0)
        
    
    def updateProgressBar(self, i):
        """update the value of the progress bar for all the treatment"""
        
        self.pb.setValue(min(i, 100))

    def to_indetermined_mode(self):
        self.pb.setMaximum(0)
        
    
    def to_determined_mode(self):
        self.pb.setMaximum(100)
        
    
    def showInStatusBar(self, string, time=5000):
        self.statusBar().showMessage(string, time)
    
    
    
    def addInterpreterDock(self, shell):
        self.shellDock = QDockWidget(self)
        self.shellDock.setWidget(shell)
        self.shellDock.setWindowTitle("shell")
        self.addDockWidget(0x2, self.shellDock)
        
    
    
    def showMetMSInformation(self):
        
        QMessageBox.about(self,
            self.tr("About %1").arg("metMS"),
            self.tr("""<b>%1 %2</b>
            <br>metabolite Mass Spectrometry
            <p>Copyright &copy; 2010 Marco INSA, INRA
            <br>Licensed under the terms of the CeciLL License
            <p>Developed and maintained by Marco
            <br>Bug reports and feature requests: 
            <a href="http://github.com/jerkos/metms">metMS site</a><br>
            Discussions around the project: 
            <a href="http://groups.google.com/group/spyderlib">Google Group</a>
            <p>This project is part of the BRIDGE project
            <p>Python %3, Qt %4, PyQt %5""") \
            .arg("metMS").arg(__version__) \
            .arg(platform.python_version()).arg(QT_VERSION_STR) \
            .arg(PYQT_VERSION_STR))
Exemplo n.º 7
0
class ComposerWrapper(QObject):
    """
    Embeds custom STDM tools in a QgsComposer instance for managing map-based
    STDM document templates.
    """
    dataSourceSelected = pyqtSignal(str)
    
    def __init__(self,composerView):
        QObject.__init__(self,composerView)
        
        self._compView = composerView
        self._stdmTB = self.mainWindow().addToolBar("STDM")
        self._selectMoveAction = None
        
        #Container for custom editor widgets
        self._widgetMappings = {}
        
        #Create dock widget for configuring STDM data source
        self._stdmDataSourceDock = QDockWidget(QApplication.translate("ComposerWrapper","STDM Data Source"),self.mainWindow())
        self._stdmDataSourceDock.setObjectName("STDMDataSourceDock")
        self._stdmDataSourceDock.setMinimumWidth(300)
        self._stdmDataSourceDock.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,self._stdmDataSourceDock)
        
        dataSourceWidget = ComposerDataSourceSelector()
        self._stdmDataSourceDock.setWidget(dataSourceWidget)
        self._stdmDataSourceDock.show()
        
        #Create dock widget for configuring STDM item properties
        self._stdmItemPropDock = QDockWidget(QApplication.translate("ComposerWrapper","STDM data properties"),self.mainWindow())
        self._stdmItemPropDock.setObjectName("STDMItemDock")
        self._stdmItemPropDock.setMinimumWidth(300)
        self._stdmItemPropDock.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,self._stdmItemPropDock)
        self._stdmItemPropDock.show()
        
        if self.itemDock() != None:
            self.mainWindow().tabifyDockWidget(self.itemDock(),self._stdmItemPropDock)
            
        if self.atlasDock() != None:
            self.atlasDock().hide()
            
        if self.generalDock() != None:
            self.generalDock().raise_()
            
        #Connect signals
        self.composition().itemRemoved.connect(self._onItemRemoved)
        dataSourceWidget.cboDataSource.currentIndexChanged[str].connect(self.propagateDataSourceSelection)
        self.composerView().selectedItemChanged.connect(self._onItemSelected)
        
        #Current template document file
        self._currDocFile = None
        
    def _removeActions(self):
        """
        Remove inapplicable actions and their corresponding toolbars and menus.
        """
        removeActions = ["mActionSaveProject","mActionNewComposer","mActionDuplicateComposer"]
        
        composerToolbar = self.composerMainToolBar()
        if composerToolbar != None:
            saveProjectAction = None
            
            for itemAction in composerToolbar.actions():
                if itemAction.objectName() == "mActionSaveProject":
                    saveProjectAction = itemAction
                    break
                
            if saveProjectAction != None:
                composerMenu = saveProjectAction.menu()
        
    def configure(self):
        #Create instances of custom STDM composer item configurations
        for ciConfig in ComposerItemConfig.itemConfigurations:
            ciConfigObj = ciConfig(self)
            
    def addWidgetMapping(self,uniqueIdentifier,widget):
        """
        Add custom STDM editor widget based on the unique identifier of the composer item
        """
        self._widgetMappings[uniqueIdentifier] = widget
        
    def widgetMappings(self):
        """
        Returns a dictionary containing uuid values of composer items linked to STDM widgets.
        """
        return self._widgetMappings
    
    def clearWidgetMappings(self):
        """
        Resets the widget mappings collection.
        """
        self._widgetMappings = {}
        
    def mainWindow(self):
        """
        Returns the QMainWindow used by the composer view.
        """
        return self._compView.composerWindow()
    
    def stdmToolBar(self):
        """
        Returns the instance of the STDM toolbar added to the QgsComposer.
        """
        return self._stdmTB
    
    def composerView(self):
        """
        Returns the composer view.
        """
        return self._compView
    
    def composition(self):
        """
        Returns the QgsComposition instance used in the composer view.
        """
        return self._compView.composition()
    
    def composerItemToolBar(self):
        """
        Returns the toolbar containing actions for adding composer items.
        """
        return self.mainWindow().findChild(QToolBar,"mItemToolbar")
    
    def composerMainToolBar(self):
        """
        Returns the toolbar containing actions for managing templates.
        """
        return self.mainWindow().findChild(QToolBar,"mComposerToolbar")
    
    def selectMoveAction(self):
        """
        Returns the QAction for selecting or moving composer items.
        """
        if self.composerItemToolBar() != None:
            if self._selectMoveAction == None:
                for itemAction in self.composerItemToolBar().actions():
                    if itemAction.objectName() == "mActionSelectMoveItem":
                        self._selectMoveAction = itemAction
                        break
        
        return self._selectMoveAction
    
    def checkedItemAction(self):
        """
        Returns the currently selected composer item action.
        """
        if self.selectMoveAction() != None:
            return self.selectMoveAction().actionGroup().checkedAction()
        
        return None
    
    def itemDock(self):
        """
        Get the 'Item Properties' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget,"ItemDock")
    
    def atlasDock(self):
        """
        Get the 'Atlas generation' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget,"AtlasDock")
    
    def generalDock(self):
        """
        Get the 'Composition' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget,"CompositionDock")
    
    def stdmDataSourceDock(self):
        """
        Returns the STDM data source dock widget.
        """
        return self._stdmDataSourceDock
    
    def stdmItemDock(self):
        """
        Returns the STDM item dock widget.
        """
        return self._stdmItemPropDock
    
    def documentFile(self):
        """
        Returns the QFile instance associated with the current document. 'None' will be returned for
        new, unsaved documents.
        """
        return self._currDocFile
    
    def setDocumentFile(self,docFile):
        """
        Sets the document file.
        """
        if not isinstance(docFile,QFile):
            return
        
        self._currDocFile = docFile
    
    def selectedDataSource(self):
        """
        Returns the name of the data source specified by the user.
        """
        return self._stdmDataSourceDock.widget().cboDataSource.currentText()
    
    def selectedDataSourceCategory(self):
        """
        Returns the category (view or table) that the data source belongs to.
        """
        if self.stdmDataSourceDock().widget() != None:
            return self.stdmDataSourceDock().widget().category()
        
        return ""
    
    def propagateDataSourceSelection(self,dataSourceName):
        """
        Propagates the signal when a user select a data source. Listening objects can hook on to it.
        """
        self.dataSourceSelected.emit(dataSourceName)
        
    def loadTemplate(self,filePath):
        """
        Loads a document template into the view and updates the necessary STDM-related controls.
        """
        if not QFile.exists(filePath):
                QMessageBox.critical(self.composerView(), QApplication.translate("OpenTemplateConfig","Open Template Error"), \
                                            QApplication.translate("OpenTemplateConfig","The specified template does not exist."))
                return
            
        templateFile = QFile(filePath)
        
        if not templateFile.open(QIODevice.ReadOnly):
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Open Operation Error"), \
                                            "{0}\n{1}".format(QApplication.translate("ComposerWrapper","Cannot read template file."), \
                                                      templateFile.errorString()
                                                      ))
            return    
         
        templateDoc = QDomDocument()
        
        if templateDoc.setContent(templateFile):
            #Load items into the composition and configure STDM data controls
            self.composition().loadFromTemplate(templateDoc)
            self.clearWidgetMappings()
            
            #Load data controls
            composerDS = ComposerDataSource.create(templateDoc)
            self._configureDataControls(composerDS)
            
            #Load symbol editors
            spatialFieldsConfig = SpatialFieldsConfiguration.create(templateDoc)
            self._configureSpatialSymbolEditor(spatialFieldsConfig)
            
    def saveTemplate(self):
        """
        Creates and saves a new document template.
        """
        #Validate if the user has specified the data source
        if self.selectedDataSource() == "":
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Error"), \
                                            QApplication.translate("ComposerWrapper","Please specify the " \
                                                                   "data source name for the document composition."))
            return
            
        #If it is a new unsaved document template then prompt for the document name.
        docFile = self.documentFile()
        
        if docFile == None:
            docName,ok = QInputDialog.getText(self.composerView(), \
                                              QApplication.translate("ComposerWrapper","Template Name"), \
                                              QApplication.translate("ComposerWrapper","Please enter the template name below"), \
                                              )
            if ok and docName != "":
                templateDir = self._composerTemplatesPath()
                
                if templateDir == None:
                    QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Error"), \
                                            QApplication.translate("ComposerWrapper","Directory for document templates could not be found."))
                    return
                
                absPath = templateDir + "/" + docName + ".sdt"            
                docFile= QFile(absPath)
            
            else:
                return
        
        docFileInfo = QFileInfo(docFile)    
        
        if not docFile.open(QIODevice.WriteOnly):
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Save Operation Error"), \
                                            "{0}\n{1}".format(QApplication.translate("ComposerWrapper","Could not save template file."), \
                                                      docFile.errorString()
                                                      ))
            return
                                              
        templateDoc = QDomDocument()
        self._writeXML(templateDoc,docFileInfo.completeBaseName())
        
        if docFile.write(templateDoc.toByteArray()) == -1:
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Save Error"), \
                                            QApplication.translate("ComposerWrapper","Could not save template file."))
            return
        
        docFile.close()                   
        self.setDocumentFile(docFile)
        
    def _writeXML(self,xmlDoc,docName):
        """
        Write the template configuration into the XML document.
        """        
        #Write default composer configuration
        composerElement = xmlDoc.createElement("Composer")
        composerElement.setAttribute("title",docName)
        composerElement.setAttribute("visible",1)
        
        xmlDoc.appendChild(composerElement)
        
        self.composition().writeXML(composerElement,xmlDoc)
        
        #Write STDM data field configurations
        dataSourceElement = ComposerDataSource.domElement(self, xmlDoc)
        composerElement.appendChild(dataSourceElement)
        
        #Write spatial field configurations
        spatialColumnsElement = SpatialFieldsConfiguration.domElement(self, xmlDoc)
        dataSourceElement.appendChild(spatialColumnsElement)
        
    def _configureDataControls(self,composerDataSource):
        """
        Configure the data source and data field controls based on the composer data
        source configuration.
        """
        if self.stdmDataSourceDock().widget() != None:
            #Set data source
            dataSourceWidget = self.stdmDataSourceDock().widget()
            dataSourceWidget.setCategory(composerDataSource.category())
            dataSourceWidget.setSelectedSource(composerDataSource.name())
            
            #Set data field controls
            for composerId in composerDataSource.dataFieldMappings().reverse:
                #Use composer item id since the uuid is stripped off
                composerItem = self.composition().getComposerItemById(composerId)
                
                if composerItem != None:
                    compFieldSelector = ComposerFieldSelector(self,composerItem,self.composerView())
                    compFieldSelector.selectFieldName(composerDataSource.dataFieldName(composerId))
                    
                    #Add widget to the collection but now use the current uuid of the composition item
                    self.addWidgetMapping(composerItem.uuid(),compFieldSelector)
                    
    def _configureSpatialSymbolEditor(self,spatialFieldConfig):
        """
        Configure symbol editor controls.
        """
        if self.stdmDataSourceDock().widget() != None:
            for itemId,spFieldsMappings in spatialFieldConfig.spatialFieldsMapping().iteritems():
                mapItem =  self.composition().getComposerItemById(itemId)
                
                if mapItem != None:
                    composerSymbolEditor = ComposerSymbolEditor(self,self.composerView())
                    composerSymbolEditor.addSpatialFieldMappings(spFieldsMappings)
                    
                    #Add widget to the collection but now use the current uuid of the composer map
                    self.addWidgetMapping(mapItem.uuid(),composerSymbolEditor)
                        
    def _composerTemplatesPath(self):
        """
        Reads the path of composer templates in the registry.
        """
        regConfig = RegistryConfig()
        keyName = "ComposerTemplates"
        
        valueCollection = regConfig.read([keyName])
        
        if len(valueCollection) == 0:
            return None
        
        else:
            return valueCollection[keyName]
    
    def _onItemRemoved(self,item):
        """
        Slot raised when a composer item is removed from the scene.
        """
        """
        Code will not work since a QObject instance is returned instead of a QgsComposerItem
        if item.uuid() in self._widgetMappings:
            del self._widgetMappings[item.uuid()]
        """
        pass
    
    def _onItemSelected(self,item):
        """
        Slot raised when a composer item is selected. Load the corresponding field selector
        if the selection is an STDM data field label.
        QComposerLabel is returned as a QObject in the slot argument hence, we have resorted to 
        capturing the currently selected items in the composition.
        """
        selectedItems = self.composition().selectedComposerItems()
        
        if len(selectedItems) == 0:
            self._stdmItemPropDock.setWidget(None)
        
        elif len(selectedItems) == 1:
            composerItem = selectedItems[0]
            
            if composerItem.uuid() in self._widgetMappings:
                stdmWidget = self._widgetMappings[composerItem.uuid()]
                
                if stdmWidget == self._stdmItemPropDock.widget():
                    return
                
                else:
                    self._stdmItemPropDock.setWidget(stdmWidget)
                    
                #Playing it safe in applying the formatting for the editor controls where applicable
                itemFormatter = None
                if isinstance(composerItem,QgsComposerArrow):
                    itemFormatter = LineFormatter()
                elif isinstance(composerItem,QgsComposerLabel):
                    itemFormatter = DataLabelFormatter()
                elif isinstance(composerItem,QgsComposerMap):
                    itemFormatter = MapFormatter()
                        
                if itemFormatter != None:
                    itemFormatter.apply(composerItem,self,True)
                    
            else:
                self._stdmItemPropDock.setWidget(None)
            
        elif len(selectedItems) > 1:
            self._stdmItemPropDock.setWidget(None)
Exemplo n.º 8
0
    def lauchGUI(self, WorkSpace, aCase, sobjXML, Args):
        """
        mw.dockWidgetBrowser is the Browser of the CFD MainView
        """
        log.debug("lauchGUI")
        from cs_gui import process_cmd_line

        if CFD_Code() == CFD_Saturne:
            from cs_package import package
            from code_saturne.Base.MainView import MainView
        elif CFD_Code() == CFD_Neptune:
            from nc_package import package
            from neptune_cfd.core.MainView import MainView

        if sobjXML == None:
            Title = "unnamed"
        else:
            Title = sobjXML.GetName()

        self.Workspace = WorkSpace
        pkg = package()
        case, splash = process_cmd_line(Args)
        mw = MainView(pkg, case, aCase)

        # Put the standard panel of the MainView inside a QDockWidget
        # in the SALOME Desktop
        aTitle = self.setWindowTitle_CFD(mw, aCase, Title)
        dsk = sgPyQt.getDesktop()
        dock = QDockWidget(aTitle)

        dock.setWidget(mw.frame)
        dock.setMinimumWidth(520)
        dsk.addDockWidget(Qt.RightDockWidgetArea, dock)

        dock.setVisible(True)
        dock.show()

        # Put the QTreeView of the MainView which is already inside a QDockWidget
        # in the SALOME Desktop
        BrowserTitle = aTitle + " Browser"
        mw.dockWidgetBrowser.setWindowTitle(BrowserTitle)
        dsk.addDockWidget(Qt.LeftDockWidgetArea, mw.dockWidgetBrowser)

        mw.dockWidgetBrowser.setVisible(True)
        mw.dockWidgetBrowser.show()
        mw.dockWidgetBrowser.raise_()
        dock.raise_()

        #Add Dock windows are managed by CFDGUI_Management class
        studyId = sgPyQt.getStudyId()
        aStudyCFD = aCase.GetFather()
        aCaseCFD = aCase
        xmlFileName = str(Title)
        _c_CFDGUI.set_d_CfdCases(studyId, dock, mw.dockWidgetBrowser, mw,
                                 aStudyCFD, aCaseCFD, xmlFileName, sobjXML)

        self.connect(dock, SIGNAL("visibilityChanged(bool)"),
                     self.setdockWindowBrowserActivated)
        self.connect(mw.dockWidgetBrowser, SIGNAL("visibilityChanged(bool)"),
                     self.setdockWindowActivated)

        self.connect(dock.toggleViewAction(), SIGNAL("toggled(bool)"),
                     self.setdockWB)
        self.connect(mw.dockWidgetBrowser.toggleViewAction(),
                     SIGNAL("toggled(bool)"), self.setdock)

        _c_CFDGUI.tabifyDockWindows(dsk, studyId)
        self.showDockWindows(studyId, xmlFileName, aCaseCFD.GetName(),
                             aStudyCFD.GetName())
        updateObjectBrowser()

        return mw
Exemplo n.º 9
0
class ComposerWrapper(QObject):
    """
    Embeds custom STDM tools in a QgsComposer instance for managing map-based
    STDM document templates.
    """
    dataSourceSelected = pyqtSignal(str)

    def __init__(self, composerView):
        QObject.__init__(self, composerView)

        self._compView = composerView
        self._stdmTB = self.mainWindow().addToolBar("STDM")
        self._selectMoveAction = None

        #Container for custom editor widgets
        self._widgetMappings = {}

        #Create dock widget for configuring STDM data source
        self._stdmDataSourceDock = QDockWidget(
            QApplication.translate("ComposerWrapper", "STDM Data Source"),
            self.mainWindow())
        self._stdmDataSourceDock.setObjectName("STDMDataSourceDock")
        self._stdmDataSourceDock.setMinimumWidth(300)
        self._stdmDataSourceDock.setFeatures(QDockWidget.DockWidgetMovable
                                             | QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,
                                        self._stdmDataSourceDock)

        dataSourceWidget = ComposerDataSourceSelector()
        self._stdmDataSourceDock.setWidget(dataSourceWidget)
        self._stdmDataSourceDock.show()

        #Create dock widget for configuring STDM item properties
        self._stdmItemPropDock = QDockWidget(
            QApplication.translate("ComposerWrapper", "STDM data properties"),
            self.mainWindow())
        self._stdmItemPropDock.setObjectName("STDMItemDock")
        self._stdmItemPropDock.setMinimumWidth(300)
        self._stdmItemPropDock.setFeatures(QDockWidget.DockWidgetMovable
                                           | QDockWidget.DockWidgetClosable)
        self.mainWindow().addDockWidget(Qt.RightDockWidgetArea,
                                        self._stdmItemPropDock)
        self._stdmItemPropDock.show()

        if self.itemDock() != None:
            self.mainWindow().tabifyDockWidget(self.itemDock(),
                                               self._stdmItemPropDock)

        if self.atlasDock() != None:
            self.atlasDock().hide()

        if self.generalDock() != None:
            self.generalDock().raise_()

        #Connect signals
        self.composition().itemRemoved.connect(self._onItemRemoved)
        dataSourceWidget.cboDataSource.currentIndexChanged[str].connect(
            self.propagateDataSourceSelection)
        self.composerView().selectedItemChanged.connect(self._onItemSelected)

        #Current template document file
        self._currDocFile = None

    def _removeActions(self):
        """
        Remove inapplicable actions and their corresponding toolbars and menus.
        """
        removeActions = [
            "mActionSaveProject", "mActionNewComposer",
            "mActionDuplicateComposer"
        ]

        composerToolbar = self.composerMainToolBar()
        if composerToolbar != None:
            saveProjectAction = None

            for itemAction in composerToolbar.actions():
                if itemAction.objectName() == "mActionSaveProject":
                    saveProjectAction = itemAction
                    break

            if saveProjectAction != None:
                composerMenu = saveProjectAction.menu()

    def configure(self):
        #Create instances of custom STDM composer item configurations
        for ciConfig in ComposerItemConfig.itemConfigurations:
            ciConfigObj = ciConfig(self)

    def addWidgetMapping(self, uniqueIdentifier, widget):
        """
        Add custom STDM editor widget based on the unique identifier of the composer item
        """
        self._widgetMappings[uniqueIdentifier] = widget

    def widgetMappings(self):
        """
        Returns a dictionary containing uuid values of composer items linked to STDM widgets.
        """
        return self._widgetMappings

    def clearWidgetMappings(self):
        """
        Resets the widget mappings collection.
        """
        self._widgetMappings = {}

    def mainWindow(self):
        """
        Returns the QMainWindow used by the composer view.
        """
        return self._compView.composerWindow()

    def stdmToolBar(self):
        """
        Returns the instance of the STDM toolbar added to the QgsComposer.
        """
        return self._stdmTB

    def composerView(self):
        """
        Returns the composer view.
        """
        return self._compView

    def composition(self):
        """
        Returns the QgsComposition instance used in the composer view.
        """
        return self._compView.composition()

    def composerItemToolBar(self):
        """
        Returns the toolbar containing actions for adding composer items.
        """
        return self.mainWindow().findChild(QToolBar, "mItemToolbar")

    def composerMainToolBar(self):
        """
        Returns the toolbar containing actions for managing templates.
        """
        return self.mainWindow().findChild(QToolBar, "mComposerToolbar")

    def selectMoveAction(self):
        """
        Returns the QAction for selecting or moving composer items.
        """
        if self.composerItemToolBar() != None:
            if self._selectMoveAction == None:
                for itemAction in self.composerItemToolBar().actions():
                    if itemAction.objectName() == "mActionSelectMoveItem":
                        self._selectMoveAction = itemAction
                        break

        return self._selectMoveAction

    def checkedItemAction(self):
        """
        Returns the currently selected composer item action.
        """
        if self.selectMoveAction() != None:
            return self.selectMoveAction().actionGroup().checkedAction()

        return None

    def itemDock(self):
        """
        Get the 'Item Properties' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget, "ItemDock")

    def atlasDock(self):
        """
        Get the 'Atlas generation' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget, "AtlasDock")

    def generalDock(self):
        """
        Get the 'Composition' dock widget.
        """
        return self.mainWindow().findChild(QDockWidget, "CompositionDock")

    def stdmDataSourceDock(self):
        """
        Returns the STDM data source dock widget.
        """
        return self._stdmDataSourceDock

    def stdmItemDock(self):
        """
        Returns the STDM item dock widget.
        """
        return self._stdmItemPropDock

    def documentFile(self):
        """
        Returns the QFile instance associated with the current document. 'None' will be returned for
        new, unsaved documents.
        """
        return self._currDocFile

    def setDocumentFile(self, docFile):
        """
        Sets the document file.
        """
        if not isinstance(docFile, QFile):
            return

        self._currDocFile = docFile

    def selectedDataSource(self):
        """
        Returns the name of the data source specified by the user.
        """
        return self._stdmDataSourceDock.widget().cboDataSource.currentText()

    def selectedDataSourceCategory(self):
        """
        Returns the category (view or table) that the data source belongs to.
        """
        if self.stdmDataSourceDock().widget() != None:
            return self.stdmDataSourceDock().widget().category()

        return ""

    def propagateDataSourceSelection(self, dataSourceName):
        """
        Propagates the signal when a user select a data source. Listening objects can hook on to it.
        """
        self.dataSourceSelected.emit(dataSourceName)

    def loadTemplate(self, filePath):
        """
        Loads a document template into the view and updates the necessary STDM-related controls.
        """
        if not QFile.exists(filePath):
            QMessageBox.critical(self.composerView(), QApplication.translate("OpenTemplateConfig","Open Template Error"), \
                                        QApplication.translate("OpenTemplateConfig","The specified template does not exist."))
            return

        templateFile = QFile(filePath)

        if not templateFile.open(QIODevice.ReadOnly):
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Open Operation Error"), \
                                            "{0}\n{1}".format(QApplication.translate("ComposerWrapper","Cannot read template file."), \
                                                      templateFile.errorString()
                                                      ))
            return

        templateDoc = QDomDocument()

        if templateDoc.setContent(templateFile):
            #Load items into the composition and configure STDM data controls
            self.composition().loadFromTemplate(templateDoc)
            self.clearWidgetMappings()

            #Load data controls
            composerDS = ComposerDataSource.create(templateDoc)
            self._configureDataControls(composerDS)

            #Load symbol editors
            spatialFieldsConfig = SpatialFieldsConfiguration.create(
                templateDoc)
            self._configureSpatialSymbolEditor(spatialFieldsConfig)

    def saveTemplate(self):
        """
        Creates and saves a new document template.
        """
        #Validate if the user has specified the data source
        if self.selectedDataSource() == "":
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Error"), \
                                            QApplication.translate("ComposerWrapper","Please specify the " \
                                                                   "data source name for the document composition."))
            return

        #If it is a new unsaved document template then prompt for the document name.
        docFile = self.documentFile()

        if docFile == None:
            docName,ok = QInputDialog.getText(self.composerView(), \
                                              QApplication.translate("ComposerWrapper","Template Name"), \
                                              QApplication.translate("ComposerWrapper","Please enter the template name below"), \
                                              )
            if ok and docName != "":
                templateDir = self._composerTemplatesPath()

                if templateDir == None:
                    QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Error"), \
                                            QApplication.translate("ComposerWrapper","Directory for document templates could not be found."))
                    return

                absPath = templateDir + "/" + docName + ".sdt"
                docFile = QFile(absPath)

            else:
                return

        docFileInfo = QFileInfo(docFile)

        if not docFile.open(QIODevice.WriteOnly):
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Save Operation Error"), \
                                            "{0}\n{1}".format(QApplication.translate("ComposerWrapper","Could not save template file."), \
                                                      docFile.errorString()
                                                      ))
            return

        templateDoc = QDomDocument()
        self._writeXML(templateDoc, docFileInfo.completeBaseName())

        if docFile.write(templateDoc.toByteArray()) == -1:
            QMessageBox.critical(self.composerView(), QApplication.translate("ComposerWrapper","Save Error"), \
                                            QApplication.translate("ComposerWrapper","Could not save template file."))
            return

        docFile.close()
        self.setDocumentFile(docFile)

    def _writeXML(self, xmlDoc, docName):
        """
        Write the template configuration into the XML document.
        """
        #Write default composer configuration
        composerElement = xmlDoc.createElement("Composer")
        composerElement.setAttribute("title", docName)
        composerElement.setAttribute("visible", 1)

        xmlDoc.appendChild(composerElement)

        self.composition().writeXML(composerElement, xmlDoc)

        #Write STDM data field configurations
        dataSourceElement = ComposerDataSource.domElement(self, xmlDoc)
        composerElement.appendChild(dataSourceElement)

        #Write spatial field configurations
        spatialColumnsElement = SpatialFieldsConfiguration.domElement(
            self, xmlDoc)
        dataSourceElement.appendChild(spatialColumnsElement)

    def _configureDataControls(self, composerDataSource):
        """
        Configure the data source and data field controls based on the composer data
        source configuration.
        """
        if self.stdmDataSourceDock().widget() != None:
            #Set data source
            dataSourceWidget = self.stdmDataSourceDock().widget()
            dataSourceWidget.setCategory(composerDataSource.category())
            dataSourceWidget.setSelectedSource(composerDataSource.name())

            #Set data field controls
            for composerId in composerDataSource.dataFieldMappings().reverse:
                #Use composer item id since the uuid is stripped off
                composerItem = self.composition().getComposerItemById(
                    composerId)

                if composerItem != None:
                    compFieldSelector = ComposerFieldSelector(
                        self, composerItem, self.composerView())
                    compFieldSelector.selectFieldName(
                        composerDataSource.dataFieldName(composerId))

                    #Add widget to the collection but now use the current uuid of the composition item
                    self.addWidgetMapping(composerItem.uuid(),
                                          compFieldSelector)

    def _configureSpatialSymbolEditor(self, spatialFieldConfig):
        """
        Configure symbol editor controls.
        """
        if self.stdmDataSourceDock().widget() != None:
            for itemId, spFieldsMappings in spatialFieldConfig.spatialFieldsMapping(
            ).iteritems():
                mapItem = self.composition().getComposerItemById(itemId)

                if mapItem != None:
                    composerSymbolEditor = ComposerSymbolEditor(
                        self, self.composerView())
                    composerSymbolEditor.addSpatialFieldMappings(
                        spFieldsMappings)

                    #Add widget to the collection but now use the current uuid of the composer map
                    self.addWidgetMapping(mapItem.uuid(), composerSymbolEditor)

    def _composerTemplatesPath(self):
        """
        Reads the path of composer templates in the registry.
        """
        regConfig = RegistryConfig()
        keyName = "ComposerTemplates"

        valueCollection = regConfig.read([keyName])

        if len(valueCollection) == 0:
            return None

        else:
            return valueCollection[keyName]

    def _onItemRemoved(self, item):
        """
        Slot raised when a composer item is removed from the scene.
        """
        """
        Code will not work since a QObject instance is returned instead of a QgsComposerItem
        if item.uuid() in self._widgetMappings:
            del self._widgetMappings[item.uuid()]
        """
        pass

    def _onItemSelected(self, item):
        """
        Slot raised when a composer item is selected. Load the corresponding field selector
        if the selection is an STDM data field label.
        QComposerLabel is returned as a QObject in the slot argument hence, we have resorted to 
        capturing the currently selected items in the composition.
        """
        selectedItems = self.composition().selectedComposerItems()

        if len(selectedItems) == 0:
            self._stdmItemPropDock.setWidget(None)

        elif len(selectedItems) == 1:
            composerItem = selectedItems[0]

            if composerItem.uuid() in self._widgetMappings:
                stdmWidget = self._widgetMappings[composerItem.uuid()]

                if stdmWidget == self._stdmItemPropDock.widget():
                    return

                else:
                    self._stdmItemPropDock.setWidget(stdmWidget)

                #Playing it safe in applying the formatting for the editor controls where applicable
                itemFormatter = None
                if isinstance(composerItem, QgsComposerArrow):
                    itemFormatter = LineFormatter()
                elif isinstance(composerItem, QgsComposerLabel):
                    itemFormatter = DataLabelFormatter()
                elif isinstance(composerItem, QgsComposerMap):
                    itemFormatter = MapFormatter()

                if itemFormatter != None:
                    itemFormatter.apply(composerItem, self, True)

            else:
                self._stdmItemPropDock.setWidget(None)

        elif len(selectedItems) > 1:
            self._stdmItemPropDock.setWidget(None)