Example #1
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(978, 711)
        icon = QtGui.QIcon()
        icon.addPixmap(
            QtGui.QPixmap(_fromUtf8(":/exterminator/icons/program_icon.png")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        MainWindow.setToolTip(_fromUtf8(""))
        MainWindow.setWindowFilePath(_fromUtf8(""))
        MainWindow.setTabShape(QtGui.QTabWidget.Rounded)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.verticalLayout_5 = QtGui.QVBoxLayout(self.centralwidget)
        self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5"))
        self.label_4 = QtGui.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.label_4.setFont(font)
        self.label_4.setObjectName(_fromUtf8("label_4"))
        self.verticalLayout_5.addWidget(self.label_4)
        self.overviewComboBox = QtGui.QComboBox(self.centralwidget)
        font = QtGui.QFont()
        font.setBold(True)
        font.setItalic(True)
        font.setWeight(75)
        self.overviewComboBox.setFont(font)
        self.overviewComboBox.setObjectName(_fromUtf8("overviewComboBox"))
        self.verticalLayout_5.addWidget(self.overviewComboBox)
        self.line = QtGui.QFrame(self.centralwidget)
        self.line.setLineWidth(17)
        self.line.setObjectName(_fromUtf8("line"))
        self.verticalLayout_5.addWidget(self.line)
        self.tabWidget = QtGui.QTabWidget(self.centralwidget)
        self.tabWidget.setEnabled(True)
        self.tabWidget.setFocusPolicy(QtCore.Qt.TabFocus)
        self.tabWidget.setAcceptDrops(False)
        self.tabWidget.setAutoFillBackground(False)
        self.tabWidget.setTabPosition(QtGui.QTabWidget.North)
        self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded)
        self.tabWidget.setElideMode(QtCore.Qt.ElideNone)
        self.tabWidget.setDocumentMode(False)
        self.tabWidget.setTabsClosable(False)
        self.tabWidget.setMovable(True)
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.tab_tiles = QtGui.QWidget()
        self.tab_tiles.setObjectName(_fromUtf8("tab_tiles"))
        self.horizontalLayout = QtGui.QHBoxLayout(self.tab_tiles)
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.splitter = QtGui.QSplitter(self.tab_tiles)
        self.splitter.setOrientation(QtCore.Qt.Vertical)
        self.splitter.setObjectName(_fromUtf8("splitter"))
        self.treeDataTiles = QtGui.QTreeWidget(self.splitter)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(
            self.treeDataTiles.sizePolicy().hasHeightForWidth())
        self.treeDataTiles.setSizePolicy(sizePolicy)
        self.treeDataTiles.setWhatsThis(
            _fromUtf8(
                "This is widget where in tree maner all input data are presented.\n"
                "This can be composed just from one detector (in. example BSE) images, or can be complicated more than ten element mappings.\n"
                "This is not interactive view. If this doesn\'t work after importing or appending data something is broken."
            ))
        self.treeDataTiles.setObjectName(_fromUtf8("treeDataTiles"))
        self.treeDataTiles.headerItem().setText(0, _fromUtf8("data files"))
        self.verticalLayoutWidget = QtGui.QWidget(self.splitter)
        self.verticalLayoutWidget.setObjectName(
            _fromUtf8("verticalLayoutWidget"))
        self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setMargin(0)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.label_2 = QtGui.QLabel(self.verticalLayoutWidget)
        self.label_2.setObjectName(_fromUtf8("label_2"))
        self.verticalLayout.addWidget(self.label_2)
        self.plainTextEdit = QtGui.QPlainTextEdit(self.verticalLayoutWidget)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding,
                                       QtGui.QSizePolicy.MinimumExpanding)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(
            self.plainTextEdit.sizePolicy().hasHeightForWidth())
        self.plainTextEdit.setSizePolicy(sizePolicy)
        self.plainTextEdit.setMinimumSize(QtCore.QSize(200, 100))
        self.plainTextEdit.setWhatsThis(
            _fromUtf8(
                "Not inteactive text widget which gets and presents statistics of widget above (data widget)"
            ))
        self.plainTextEdit.setReadOnly(True)
        self.plainTextEdit.setPlainText(_fromUtf8(""))
        self.plainTextEdit.setObjectName(_fromUtf8("plainTextEdit"))
        self.verticalLayout.addWidget(self.plainTextEdit)
        self.horizontalLayout.addWidget(self.splitter)
        self.tabWidget.addTab(self.tab_tiles, _fromUtf8(""))
        self.tab_param = QtGui.QWidget()
        self.tab_param.setEnabled(True)
        self.tab_param.setObjectName(_fromUtf8("tab_param"))
        self.gridLayout_4 = QtGui.QGridLayout(self.tab_param)
        self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4"))
        self.splitter_2 = QtGui.QSplitter(self.tab_param)
        self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
        self.splitter_2.setObjectName(_fromUtf8("splitter_2"))
        self.gridLayoutWidget = QtGui.QWidget(self.splitter_2)
        self.gridLayoutWidget.setObjectName(_fromUtf8("gridLayoutWidget"))
        self.gridLayout_3 = QtGui.QGridLayout(self.gridLayoutWidget)
        self.gridLayout_3.setMargin(0)
        self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
        self.treeParameters = ParameterTree(self.gridLayoutWidget)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding,
                                       QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.treeParameters.sizePolicy().hasHeightForWidth())
        self.treeParameters.setSizePolicy(sizePolicy)
        self.treeParameters.setMinimumSize(QtCore.QSize(280, 0))
        self.treeParameters.setObjectName(_fromUtf8("treeParameters"))
        self.gridLayout_3.addWidget(self.treeParameters, 0, 0, 1, 1)
        self.setAsDefault = QtGui.QPushButton(self.gridLayoutWidget)
        self.setAsDefault.setObjectName(_fromUtf8("setAsDefault"))
        self.gridLayout_3.addWidget(self.setAsDefault, 1, 0, 1, 1)
        self.gridLayout_4.addWidget(self.splitter_2, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tab_param, _fromUtf8(""))
        self.tab_filters = QtGui.QWidget()
        self.tab_filters.setObjectName(_fromUtf8("tab_filters"))
        self.verticalLayout_7 = QtGui.QVBoxLayout(self.tab_filters)
        self.verticalLayout_7.setObjectName(_fromUtf8("verticalLayout_7"))
        self.splitter_3 = QtGui.QSplitter(self.tab_filters)
        self.splitter_3.setOrientation(QtCore.Qt.Vertical)
        self.splitter_3.setObjectName(_fromUtf8("splitter_3"))
        self.filtersTreeView = ParameterTree(self.splitter_3)
        self.filtersTreeView.setEditTriggers(
            QtGui.QAbstractItemView.NoEditTriggers)
        self.filtersTreeView.setAlternatingRowColors(True)
        self.filtersTreeView.setObjectName(_fromUtf8("filtersTreeView"))
        self.filterParamView = ParameterTree(self.splitter_3)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
                                       QtGui.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.filterParamView.sizePolicy().hasHeightForWidth())
        self.filterParamView.setSizePolicy(sizePolicy)
        self.filterParamView.setMinimumSize(QtCore.QSize(0, 40))
        self.filterParamView.setMaximumSize(QtCore.QSize(16777215, 100))
        self.filterParamView.setObjectName(_fromUtf8("filterParamView"))
        self.verticalLayout_7.addWidget(self.splitter_3)
        self.tabWidget.addTab(self.tab_filters, _fromUtf8(""))
        self.tab_finish = QtGui.QWidget()
        self.tab_finish.setObjectName(_fromUtf8("tab_finish"))
        self.verticalLayout_3 = QtGui.QVBoxLayout(self.tab_finish)
        self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3"))
        self.treeFinalWidget = QtGui.QTreeWidget(self.tab_finish)
        self.treeFinalWidget.setObjectName(_fromUtf8("treeFinalWidget"))
        self.treeFinalWidget.headerItem().setText(
            0, _fromUtf8("stuff (do not edit!)"))
        self.treeFinalWidget.headerItem().setText(
            1, _fromUtf8("final names and titles (editable)"))
        self.verticalLayout_3.addWidget(self.treeFinalWidget)
        self.tabWidget.addTab(self.tab_finish, _fromUtf8(""))
        self.verticalLayout_5.addWidget(self.tabWidget)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 978, 20))
        self.menubar.setFocusPolicy(QtCore.Qt.NoFocus)
        self.menubar.setObjectName(_fromUtf8("menubar"))
        self.menuFile = QtGui.QMenu(self.menubar)
        self.menuFile.setObjectName(_fromUtf8("menuFile"))
        self.menuEdit = QtGui.QMenu(self.menubar)
        self.menuEdit.setObjectName(_fromUtf8("menuEdit"))
        self.menuHelp = QtGui.QMenu(self.menubar)
        self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
        self.menuView = QtGui.QMenu(self.menubar)
        self.menuView.setObjectName(_fromUtf8("menuView"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)
        self.toolBar = QtGui.QToolBar(MainWindow)
        self.toolBar.setMouseTracking(False)
        self.toolBar.setFocusPolicy(QtCore.Qt.NoFocus)
        self.toolBar.setWhatsThis(
            _fromUtf8("Toolbar, what else did you expect?"))
        self.toolBar.setMovable(True)
        self.toolBar.setIconSize(QtCore.QSize(64, 64))
        self.toolBar.setObjectName(_fromUtf8("toolBar"))
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.overviewWidget = QtGui.QDockWidget(MainWindow)
        self.overviewWidget.setEnabled(True)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.overviewWidget.sizePolicy().hasHeightForWidth())
        self.overviewWidget.setSizePolicy(sizePolicy)
        self.overviewWidget.setMinimumSize(QtCore.QSize(350, 150))
        self.overviewWidget.setToolTip(
            _fromUtf8("widget with vector\n"
                      "representation of the tiles"))
        self.overviewWidget.setAccessibleName(_fromUtf8(""))
        self.overviewWidget.setAccessibleDescription(_fromUtf8(""))
        self.overviewWidget.setFloating(True)
        self.overviewWidget.setFeatures(
            QtGui.QDockWidget.AllDockWidgetFeatures)
        self.overviewWidget.setWindowTitle(
            _fromUtf8("graphical overview of the tiles"))
        self.overviewWidget.setObjectName(_fromUtf8("overviewWidget"))
        self.dockWidgetContents = QtGui.QWidget()
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.dockWidgetContents.sizePolicy().hasHeightForWidth())
        self.dockWidgetContents.setSizePolicy(sizePolicy)
        self.dockWidgetContents.setObjectName(_fromUtf8("dockWidgetContents"))
        self.verticalLayout_2 = QtGui.QVBoxLayout(self.dockWidgetContents)
        self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
        self.graphicalOverview = GraphicsLayoutWidget(self.dockWidgetContents)
        self.graphicalOverview.setObjectName(_fromUtf8("graphicalOverview"))
        self.verticalLayout_2.addWidget(self.graphicalOverview)
        self.overviewWidget.setWidget(self.dockWidgetContents)
        MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1),
                                 self.overviewWidget)
        self.consoleWidget = QtGui.QDockWidget(MainWindow)
        self.consoleWidget.setWindowTitle(_fromUtf8("python console / debug"))
        self.consoleWidget.setObjectName(_fromUtf8("consoleWidget"))
        self.dockWidgetContents_2 = QtGui.QWidget()
        self.dockWidgetContents_2.setObjectName(
            _fromUtf8("dockWidgetContents_2"))
        self.verticalLayout_4 = QtGui.QVBoxLayout(self.dockWidgetContents_2)
        self.verticalLayout_4.setObjectName(_fromUtf8("verticalLayout_4"))
        self.pythonConsole = ConsoleWidget(self.dockWidgetContents_2)
        self.pythonConsole.setObjectName(_fromUtf8("pythonConsole"))
        self.verticalLayout_4.addWidget(self.pythonConsole)
        self.consoleWidget.setWidget(self.dockWidgetContents_2)
        MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(8),
                                 self.consoleWidget)
        self.stitchWidget = QtGui.QDockWidget(MainWindow)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.stitchWidget.sizePolicy().hasHeightForWidth())
        self.stitchWidget.setSizePolicy(sizePolicy)
        self.stitchWidget.setFloating(False)
        self.stitchWidget.setFeatures(QtGui.QDockWidget.AllDockWidgetFeatures)
        self.stitchWidget.setWindowTitle(_fromUtf8("image stitching preview"))
        self.stitchWidget.setObjectName(_fromUtf8("stitchWidget"))
        self.dockWidgetContents_5 = QtGui.QWidget()
        self.dockWidgetContents_5.setObjectName(
            _fromUtf8("dockWidgetContents_5"))
        self.horizontalLayout_2 = QtGui.QHBoxLayout(self.dockWidgetContents_5)
        self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
        self.graphicsView = GraphicsView(self.dockWidgetContents_5)
        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
        self.horizontalLayout_2.addWidget(self.graphicsView)
        self.stitchWidget.setWidget(self.dockWidgetContents_5)
        MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2),
                                 self.stitchWidget)
        self.filterDockWidget = QtGui.QDockWidget(MainWindow)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.filterDockWidget.sizePolicy().hasHeightForWidth())
        self.filterDockWidget.setSizePolicy(sizePolicy)
        self.filterDockWidget.setMinimumSize(QtCore.QSize(300, 242))
        self.filterDockWidget.setObjectName(_fromUtf8("filterDockWidget"))
        self.dockWidgetContents_3 = QtGui.QWidget()
        self.dockWidgetContents_3.setObjectName(
            _fromUtf8("dockWidgetContents_3"))
        self.gridLayout = QtGui.QGridLayout(self.dockWidgetContents_3)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.label_3 = QtGui.QLabel(self.dockWidgetContents_3)
        self.label_3.setObjectName(_fromUtf8("label_3"))
        self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
        self.originalView = ImageView(self.dockWidgetContents_3)
        self.originalView.setObjectName(_fromUtf8("originalView"))
        self.gridLayout.addWidget(self.originalView, 1, 0, 1, 1)
        self.filteredView = ImageView(self.dockWidgetContents_3)
        self.filteredView.setObjectName(_fromUtf8("filteredView"))
        self.gridLayout.addWidget(self.filteredView, 3, 0, 1, 1)
        self.label = QtGui.QLabel(self.dockWidgetContents_3)
        self.label.setObjectName(_fromUtf8("label"))
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.filterDockWidget.setWidget(self.dockWidgetContents_3)
        MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2),
                                 self.filterDockWidget)
        self.actionAbout = QtGui.QAction(MainWindow)
        self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
        self.actionImportDataFolder = QtGui.QAction(MainWindow)
        self.actionImportDataFolder.setEnabled(True)
        icon1 = QtGui.QIcon()
        icon1.addPixmap(
            QtGui.QPixmap(
                _fromUtf8(":/exterminator/icons/import_from_dir.svg")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.actionImportDataFolder.setIcon(icon1)
        self.actionImportDataFolder.setObjectName(
            _fromUtf8("actionImportDataFolder"))
        self.actionImportMetadata = QtGui.QAction(MainWindow)
        self.actionImportMetadata.setEnabled(False)
        icon2 = QtGui.QIcon()
        icon2.addPixmap(
            QtGui.QPixmap(_fromUtf8(":/exterminator/icons/import_rtj.svg")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.actionImportMetadata.setIcon(icon2)
        self.actionImportMetadata.setObjectName(
            _fromUtf8("actionImportMetadata"))
        self.actionExportHdf5 = QtGui.QAction(MainWindow)
        self.actionExportHdf5.setEnabled(False)
        icon3 = QtGui.QIcon()
        icon3.addPixmap(
            QtGui.QPixmap(_fromUtf8(":/exterminator/icons/export_hdf5.svg")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.actionExportHdf5.setIcon(icon3)
        self.actionExportHdf5.setObjectName(_fromUtf8("actionExportHdf5"))
        self.actionExportImages = QtGui.QAction(MainWindow)
        self.actionExportImages.setEnabled(False)
        icon4 = QtGui.QIcon()
        icon4.addPixmap(
            QtGui.QPixmap(_fromUtf8(":/exterminator/icons/export_images.svg")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.actionExportImages.setIcon(icon4)
        self.actionExportImages.setObjectName(_fromUtf8("actionExportImages"))
        self.actionQuit = QtGui.QAction(MainWindow)
        icon5 = QtGui.QIcon()
        icon5.addPixmap(
            QtGui.QPixmap(
                _fromUtf8(":/exterminator/icons/system-log-out.svg")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.actionQuit.setIcon(icon5)
        self.actionQuit.setShortcutContext(QtCore.Qt.ApplicationShortcut)
        self.actionQuit.setObjectName(_fromUtf8("actionQuit"))
        self.actionClear = QtGui.QAction(MainWindow)
        icon6 = QtGui.QIcon()
        icon6.addPixmap(
            QtGui.QPixmap(_fromUtf8(":/exterminator/icons/edit-delete.svg")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.actionClear.setIcon(icon6)
        self.actionClear.setObjectName(_fromUtf8("actionClear"))
        self.actionChangelog = QtGui.QAction(MainWindow)
        self.actionChangelog.setObjectName(_fromUtf8("actionChangelog"))
        self.actionAbout_Qt = QtGui.QAction(MainWindow)
        self.actionAbout_Qt.setObjectName(_fromUtf8("actionAbout_Qt"))
        self.actionDynamicWidgets = QtGui.QAction(MainWindow)
        self.actionDynamicWidgets.setCheckable(True)
        self.actionDynamicWidgets.setChecked(True)
        self.actionDynamicWidgets.setText(
            _fromUtf8("toggle dynamic visibility of widgets"))
        self.actionDynamicWidgets.setToolTip(
            _fromUtf8(
                "uncheck to prevent closing/showing graphical dockable widgets by changing tabs in main window"
            ))
        self.actionDynamicWidgets.setObjectName(
            _fromUtf8("actionDynamicWidgets"))
        self.menuFile.addAction(self.actionImportDataFolder)
        self.menuFile.addAction(self.actionImportMetadata)
        self.menuFile.addAction(self.actionExportImages)
        self.menuFile.addAction(self.actionExportHdf5)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionQuit)
        self.menuEdit.addAction(self.actionClear)
        self.menuHelp.addAction(self.actionAbout)
        self.menuHelp.addAction(self.actionChangelog)
        self.menuHelp.addSeparator()
        self.menuHelp.addAction(self.actionAbout_Qt)
        self.menuView.addAction(self.actionDynamicWidgets)
        self.menuView.addSeparator()
        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuEdit.menuAction())
        self.menubar.addAction(self.menuView.menuAction())
        self.menubar.addAction(self.menuHelp.menuAction())
        self.toolBar.addAction(self.actionImportDataFolder)
        self.toolBar.addAction(self.actionImportMetadata)
        self.toolBar.addAction(self.actionExportImages)
        self.toolBar.addAction(self.actionExportHdf5)
        self.toolBar.addAction(self.actionClear)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QObject.connect(self.actionQuit,
                               QtCore.SIGNAL(_fromUtf8("triggered()")),
                               MainWindow.close)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        MainWindow.setTabOrder(self.overviewComboBox, self.tabWidget)
        MainWindow.setTabOrder(self.tabWidget, self.treeDataTiles)
        MainWindow.setTabOrder(self.treeDataTiles, self.plainTextEdit)
        MainWindow.setTabOrder(self.plainTextEdit, self.treeParameters)
        MainWindow.setTabOrder(self.treeParameters, self.setAsDefault)
        MainWindow.setTabOrder(self.setAsDefault, self.filtersTreeView)
        MainWindow.setTabOrder(self.filtersTreeView, self.filterParamView)
        MainWindow.setTabOrder(self.filterParamView, self.treeFinalWidget)
        MainWindow.setTabOrder(self.treeFinalWidget, self.graphicalOverview)
        MainWindow.setTabOrder(self.graphicalOverview, self.graphicsView)
        MainWindow.setTabOrder(self.graphicsView, self.originalView)
        MainWindow.setTabOrder(self.originalView, self.filteredView)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(
            _translate("MainWindow", "Exterminator-Stitchinator", None))
        MainWindow.setWhatsThis(
            _translate(
                "MainWindow",
                "dont be silly, what is this? what is that? Are you serious?",
                None))
        self.label_4.setText(_translate("MainWindow", "SAMPLE:", None))
        self.label_2.setText(_translate("MainWindow", "data overview", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_tiles),
                                  _translate("MainWindow", "data", None))
        self.setAsDefault.setText(
            _translate("MainWindow", "values to new temporary default", None))
        self.tabWidget.setTabText(
            self.tabWidget.indexOf(self.tab_param),
            _translate("MainWindow", "stitching parameters", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_filters),
                                  _translate("MainWindow", "filters", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_finish),
                                  _translate("MainWindow", "finish", None))
        self.menuFile.setTitle(_translate("MainWindow", "File", None))
        self.menuEdit.setTitle(_translate("MainWindow", "Edit", None))
        self.menuHelp.setTitle(_translate("MainWindow", "Help", None))
        self.menuView.setTitle(_translate("MainWindow", "View", None))
        self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar", None))
        self.filterDockWidget.setWindowTitle(
            _translate("MainWindow", "Filtering preview:", None))
        self.label_3.setText(_translate("MainWindow", "filtered:", None))
        self.label.setText(_translate("MainWindow", "original:", None))
        self.actionAbout.setText(_translate("MainWindow", "About", None))
        self.actionImportDataFolder.setText(
            _translate("MainWindow", "import data folder", None))
        self.actionImportDataFolder.setShortcut(
            _translate("MainWindow", "Ctrl+O", None))
        self.actionImportMetadata.setText(
            _translate("MainWindow", "import metadata", None))
        self.actionImportMetadata.setShortcut(
            _translate("MainWindow", "Ctrl+B", None))
        self.actionExportHdf5.setText(
            _translate("MainWindow", "export as hdf5", None))
        self.actionExportHdf5.setShortcut(
            _translate("MainWindow", "Ctrl+5", None))
        self.actionExportImages.setText(
            _translate("MainWindow", "export as plain images", None))
        self.actionExportImages.setShortcut(
            _translate("MainWindow", "Ctrl+I", None))
        self.actionQuit.setText(_translate("MainWindow", "close", None))
        self.actionQuit.setShortcut(_translate("MainWindow", "Ctrl+Q", None))
        self.actionClear.setText(
            _translate("MainWindow", "clear everything", None))
        self.actionChangelog.setText(
            _translate("MainWindow", "Changelog", None))
        self.actionAbout_Qt.setText(_translate("MainWindow", "About Qt", None))
Example #2
0
class TyphonSuite(TyphonBase):
    """
    Complete Typhon Window

    This contains all the neccesities to load tools and devices into a Typhon
    window.

    Parameters
    ----------
    parent : QWidget, optional
    """
    default_tools = {
        'Log': TyphonLogDisplay,
        'StripTool': TyphonTimePlot,
        'Console': TyphonConsole
    }

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        # Setup parameter tree
        self._tree = ParameterTree(parent=self, showHeader=False)
        self._tree.setAlternatingRowColors(False)
        # Setup layout
        self._layout = QHBoxLayout()
        self._layout.setSizeConstraint(QHBoxLayout.SetFixedSize)
        self._layout.addWidget(self._tree)
        self.setLayout(self._layout)
        self.embedded_dock = None

    def add_subdisplay(self, name, display, category):
        """
        Add an arbitrary widget to the tree of available widgets and tools

        Parameters
        ----------
        name : str
            Name to be displayed in the tree

        display : QWidget
            QWidget to show in the dock when expanded.

        category : str
            The top level group to place the controls under in the tree. If the
            category does not exist, a new one will be made
        """
        logger.debug("Adding widget %r with %r to %r ...", name, display,
                     category)
        # Create our parameter
        parameter = SidebarParameter(value=display, name=name)
        self._add_to_sidebar(parameter, category)

    @property
    def top_level_groups(self):
        """All top-level groups as name, ``QGroupParameterItem`` pairs"""
        root = self._tree.invisibleRootItem()
        return dict((root.child(idx).param.name(), root.child(idx).param)
                    for idx in range(root.childCount()))

    def add_tool(self, name, tool):
        """
        Add a widget to the toolbar

        Shortcut for:

        .. code:: python

           suite.add_subdisplay(name, tool, category='Tools')

        Parameters
        ----------
        name :str
            Name of tool to be displayed in sidebar

        tool: QWidget
            Widget to be added to ``.ui.subdisplay``
        """
        self.add_subdisplay(name, tool, 'Tools')

    def get_subdisplay(self, display):
        """
        Get a subdisplay by name or contained device

        Parameters
        ----------
        display :str or Device
            Name of screen or device

        Returns
        -------
        widget : QWidget
            Widget that is a member of the :attr:`.ui.subdisplay`

        Example
        -------
        .. code:: python

            suite.get_subdisplay(my_device.x)
            suite.get_subdisplay('My Tool')
        """
        if isinstance(display, SidebarParameter):
            return display.value()
        for group in self.top_level_groups.values():
            tree = flatten_tree(group)
            for param in tree:
                match = (display in getattr(param.value(), 'devices', [])
                         or param.name() == display)
                if match:
                    return param.value()
        # If we got here we can't find the subdisplay
        raise ValueError(f"Unable to find subdisplay {display}")

    @Slot(str)
    @Slot(object)
    def show_subdisplay(self, widget):
        """
        Open a display in the dock system

        Parameters
        ----------
        widget: QWidget, SidebarParameter or str
            If given a ``SidebarParameter`` from the tree, the widget will be
            shown and the sidebar item update. Otherwise, the information is
            passed to :meth:`.get_subdisplay`
        """
        # Grab true widget
        if not isinstance(widget, QWidget):
            widget = self.get_subdisplay(widget)
        # Setup the dock
        dock = SubDisplay(self)
        # Set sidebar properly
        self._show_sidebar(widget, dock)
        # Add the widget to the dock
        logger.debug("Showing widget %r ...", widget)
        if hasattr(widget, 'display_type'):
            widget.display_type = widget.detailed_screen
        widget.setVisible(True)
        dock.setWidget(widget)
        # Add to layout
        self.layout().addWidget(dock)

    @Slot(str)
    @Slot(object)
    def embed_subdisplay(self, widget):
        """Embed a display in the dock system"""
        # Grab the relevant display
        if not self.embedded_dock:
            self.embedded_dock = SubDisplay()
            self.embedded_dock.setWidget(QWidget())
            self.embedded_dock.widget().setLayout(QVBoxLayout())
            self.embedded_dock.widget().layout().addStretch(1)
            self.layout().addWidget(self.embedded_dock)

        if not isinstance(widget, QWidget):
            widget = self.get_subdisplay(widget)
        # Set sidebar properly
        self._show_sidebar(widget, self.embedded_dock)
        # Set our widget to be embedded
        widget.setVisible(True)
        widget.display_type = widget.embedded_screen
        widget_count = self.embedded_dock.widget().layout().count()
        self.embedded_dock.widget().layout().insertWidget(
            widget_count - 1, widget)

    @Slot()
    @Slot(object)
    def hide_subdisplay(self, widget):
        """
        Hide a visible subdisplay

        Parameters
        ----------
        widget: SidebarParameter or Subdisplay
            If you give a SidebarParameter, we will find the corresponding
            widget and hide it. If the widget provided to us is inside a
            DockWidget we will close that, otherwise the widget is just hidden.
        """
        if not isinstance(widget, QWidget):
            widget = self.get_subdisplay(widget)
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_hidden()
        else:
            logger.warning("Unable to find sidebar item for %r", widget)
        # Make sure the actual widget is hidden
        logger.debug("Hiding widget %r ...", widget)
        if isinstance(widget.parent(), QDockWidget):
            logger.debug("Closing dock ...")
            widget.parent().close()
        # Hide the full dock if this is the last widget
        elif (self.embedded_dock
              and widget.parent() == self.embedded_dock.widget()):
            logger.debug("Removing %r from embedded widget layout ...", widget)
            self.embedded_dock.widget().layout().removeWidget(widget)
            widget.hide()
            if self.embedded_dock.widget().layout().count() == 1:
                logger.debug("Closing embedded layout ...")
                self.embedded_dock.close()
                self.embedded_dock = None
        else:
            widget.hide()

    @Slot()
    def hide_subdisplays(self):
        """
        Hide all open displays
        """
        # Grab children from devices
        for group in self.top_level_groups.values():
            for param in flatten_tree(group)[1:]:
                self.hide_subdisplay(param)

    @property
    def tools(self):
        """Tools loaded into the TyphonDeviceDisplay"""
        if 'Tools' in self.top_level_groups:
            return [
                param.value()
                for param in self.top_level_groups['Tools'].childs
            ]
        return []

    def add_device(self, device, children=True, category='Devices'):
        """
        Add a device to the ``TyphonSuite``

        Parameters
        ----------
        device: ophyd.Device

        children: bool, optional
            Also add any ``subdevices`` of this device to the suite as well.

        category: str, optional
            Category of device. By default, all devices will just be added to
            the "Devices" group
        """
        super().add_device(device)
        # Create DeviceParameter and add to top level category
        dev_param = DeviceParameter(device, subdevices=children)
        self._add_to_sidebar(dev_param, category)
        # Grab children
        for child in flatten_tree(dev_param)[1:]:
            self._add_to_sidebar(child)
        # Add a device to all the tool displays
        for tool in self.tools:
            try:
                tool.add_device(device)
            except Exception:
                logger.exception("Unable to add %s to tool %s", device.name,
                                 type(tool))

    @classmethod
    def from_device(cls, device, parent=None, tools=dict(), **kwargs):
        """
        Create a new TyphonDeviceDisplay from an ophyd.Device

        Parameters
        ----------
        device: ophyd.Device

        children: bool, optional
            Choice to include child Device components

        parent: QWidgets

        tools: dict, optional
            Tools to load for the object. ``dict`` should be name, class pairs.
            By default these will be ``.default_tools``, but ``None`` can be
            passed to avoid tool loading completely.

        kwargs:
            Passed to :meth:`TyphonSuite.add_device`
        """
        display = cls(parent=parent)
        if tools is not None:
            if not tools:
                logger.debug("Using default TyphonSuite tools ...")
                tools = cls.default_tools
                for name, tool in tools.items():
                    try:
                        display.add_tool(name, tool())
                    except Exception:
                        logger.exception("Unable to load %s", type(tool))
        display.add_device(device, **kwargs)
        display.show_subdisplay(device)
        return display

    def _get_sidebar(self, widget):
        items = {}
        for group in self.top_level_groups.values():
            for item in flatten_tree(group):
                items[item.value()] = item
        return items.get(widget)

    def _show_sidebar(self, widget, dock):
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_shown()
            # Make sure we react if the dock is closed outside of our menu
            dock.closing.connect(partial(self.hide_subdisplay, sidebar))
        else:
            logger.warning("Unable to find sidebar item for %r", widget)

    def _add_to_sidebar(self, parameter, category=None):
        """Add an item to the sidebar, connecting necessary signals"""
        if category:
            # Create or grab our category
            if category in self.top_level_groups:
                group = self.top_level_groups[category]
            else:
                logger.debug("Creating new category %r ...", category)
                group = ptypes.GroupParameter(name=category)
                self._tree.addParameters(group)
                self._tree.sortItems(0, Qt.AscendingOrder)
            logger.debug("Adding %r to category %r ...", parameter.name(),
                         group.name())
            group.addChild(parameter)
        # Setup window to have a parent
        parameter.value().setParent(self)
        parameter.value().setHidden(True)
        logger.debug("Connecting parameter signals ...")
        parameter.sigOpen.connect(partial(self.show_subdisplay, parameter))
        parameter.sigHide.connect(partial(self.hide_subdisplay, parameter))
        if parameter.embeddable:
            parameter.sigEmbed.connect(
                partial(self.embed_subdisplay, parameter))
        return parameter
Example #3
0
class TyphosSuite(TyphosBase):
    """
    This suite combines tools and devices into a single widget.

    A :class:`ParameterTree` is contained in a :class:`~pcdsutils.qt.QPopBar`
    which shows tools and the hierarchy of a device along with options to
    show or hide them.

    Parameters
    ----------
    parent : QWidget, optional

    pin : bool, optional
        Pin the parameter tree on startup.

    Attributes
    ----------
    default_tools : dict
        The default tools to use in the suite.  In the form of
        ``{'tool_name': ToolClass}``.
    """

    DEFAULT_TITLE = 'Typhos Suite'
    DEFAULT_TITLE_DEVICE = 'Typhos Suite - {device.name}'

    default_tools = {
        'Log': TyphosLogDisplay,
        'StripTool': TyphosTimePlot,
        'Console': TyphosConsole
    }

    def __init__(self, parent=None, *, pin=False):
        super().__init__(parent=parent)

        self._update_title()

        self._tree = ParameterTree(parent=self, showHeader=False)
        self._tree.setAlternatingRowColors(False)
        self._save_action = ptypes.ActionParameter(name='Save Suite')
        self._tree.addParameters(self._save_action)
        self._save_action.sigActivated.connect(self.save)

        self._bar = pcdsutils.qt.QPopBar(title='Suite',
                                         parent=self,
                                         widget=self._tree,
                                         pin=pin)

        self._content_frame = QtWidgets.QFrame(self)
        self._content_frame.setObjectName("content")
        self._content_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self._content_frame.setLayout(QtWidgets.QHBoxLayout())

        # Horizontal box layout: [PopBar] [Content Frame]
        layout = QtWidgets.QHBoxLayout()
        self.setLayout(layout)
        layout.setSpacing(1)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self._bar)
        layout.addWidget(self._content_frame)

        self.embedded_dock = None

    def add_subdisplay(self, name, display, category):
        """
        Add an arbitrary widget to the tree of available widgets and tools.

        Parameters
        ----------
        name : str
            Name to be displayed in the tree

        display : QWidget
            QWidget to show in the dock when expanded.

        category : str
            The top level group to place the controls under in the tree. If the
            category does not exist, a new one will be made
        """
        logger.debug("Adding widget %r with %r to %r ...", name, display,
                     category)
        # Create our parameter
        parameter = SidebarParameter(value=display, name=name)
        self._add_to_sidebar(parameter, category)

    @property
    def top_level_groups(self):
        """
        Get top-level groups.

        This is of the form:

        .. code:: python

            {'name': QGroupParameterItem}
        """
        root = self._tree.invisibleRootItem()
        return dict((root.child(idx).param.name(), root.child(idx).param)
                    for idx in range(root.childCount()))

    def add_tool(self, name, tool):
        """
        Add a widget to the toolbar.

        Shortcut for:

        .. code:: python

           suite.add_subdisplay(name, tool, category='Tools')

        Parameters
        ----------
        name :str
            Name of tool to be displayed in sidebar

        tool: QWidget
            Widget to be added to ``.ui.subdisplay``
        """
        self.add_subdisplay(name, tool, 'Tools')

    def get_subdisplay(self, display):
        """
        Get a subdisplay by name or contained device.

        Parameters
        ----------
        display :str or Device
            Name of screen or device

        Returns
        -------
        widget : QWidget
            Widget that is a member of the :attr:`.ui.subdisplay`

        Example
        -------
        .. code:: python

            suite.get_subdisplay(my_device.x)
            suite.get_subdisplay('My Tool')
        """
        if not isinstance(display, SidebarParameter):
            for group in self.top_level_groups.values():
                tree = flatten_tree(group)
                matches = [
                    param for param in tree if hasattr(param, 'has_device')
                    and param.has_device(display)
                ]

                if matches:
                    display = matches[0]
                    break

        if not isinstance(display, SidebarParameter):
            # If we got here we can't find the subdisplay
            raise ValueError(f"Unable to find subdisplay {display}")

        subdisplay = display.value()
        if isinstance(subdisplay, partial):
            subdisplay = subdisplay()
            display.setValue(subdisplay)
        return subdisplay

    @QtCore.Slot(str)
    @QtCore.Slot(object)
    def show_subdisplay(self, widget):
        """
        Open a display in the dock system.

        Parameters
        ----------
        widget: QWidget, SidebarParameter or str
            If given a ``SidebarParameter`` from the tree, the widget will be
            shown and the sidebar item update. Otherwise, the information is
            passed to :meth:`.get_subdisplay`
        """
        # Grab true widget
        if not isinstance(widget, QtWidgets.QWidget):
            widget = self.get_subdisplay(widget)
        # Setup the dock
        dock = widgets.SubDisplay(self)
        # Set sidebar properly
        self._show_sidebar(widget, dock)
        # Add the widget to the dock
        logger.debug("Showing widget %r ...", widget)
        if hasattr(widget, 'display_type'):
            widget.display_type = widget.detailed_screen
        widget.setVisible(True)
        dock.setWidget(widget)
        # Add to layout
        self._content_frame.layout().addWidget(dock)

    @QtCore.Slot(str)
    @QtCore.Slot(object)
    def embed_subdisplay(self, widget):
        """Embed a display in the dock system."""
        # Grab the relevant display
        if not self.embedded_dock:
            self.embedded_dock = widgets.SubDisplay()
            self.embedded_dock.setWidget(QtWidgets.QWidget())
            self.embedded_dock.widget().setLayout(QtWidgets.QVBoxLayout())
            self.embedded_dock.widget().layout().addStretch(1)
            self._content_frame.layout().addWidget(self.embedded_dock)

        if not isinstance(widget, QtWidgets.QWidget):
            widget = self.get_subdisplay(widget)
        # Set sidebar properly
        self._show_sidebar(widget, self.embedded_dock)
        # Set our widget to be embedded
        widget.setVisible(True)
        widget.display_type = widget.embedded_screen
        widget_count = self.embedded_dock.widget().layout().count()
        self.embedded_dock.widget().layout().insertWidget(
            widget_count - 1, widget)

    @QtCore.Slot()
    @QtCore.Slot(object)
    def hide_subdisplay(self, widget):
        """
        Hide a visible subdisplay.

        Parameters
        ----------
        widget: SidebarParameter or Subdisplay
            If you give a SidebarParameter, we will find the corresponding
            widget and hide it. If the widget provided to us is inside a
            DockWidget we will close that, otherwise the widget is just hidden.
        """
        if not isinstance(widget, QtWidgets.QWidget):
            widget = self.get_subdisplay(widget)
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_hidden()
        else:
            logger.warning("Unable to find sidebar item for %r", widget)
        # Make sure the actual widget is hidden
        logger.debug("Hiding widget %r ...", widget)
        if isinstance(widget.parent(), QtWidgets.QDockWidget):
            logger.debug("Closing dock ...")
            widget.parent().close()
        # Hide the full dock if this is the last widget
        elif (self.embedded_dock
              and widget.parent() == self.embedded_dock.widget()):
            logger.debug("Removing %r from embedded widget layout ...", widget)
            self.embedded_dock.widget().layout().removeWidget(widget)
            widget.hide()
            if self.embedded_dock.widget().layout().count() == 1:
                logger.debug("Closing embedded layout ...")
                self.embedded_dock.close()
                self.embedded_dock = None
        else:
            widget.hide()

    @QtCore.Slot()
    def hide_subdisplays(self):
        """Hide all open displays."""
        # Grab children from devices
        for group in self.top_level_groups.values():
            for param in flatten_tree(group)[1:]:
                self.hide_subdisplay(param)

    @property
    def tools(self):
        """Tools loaded into the suite."""
        if 'Tools' in self.top_level_groups:
            return [
                param.value()
                for param in self.top_level_groups['Tools'].childs
            ]
        return []

    def _update_title(self, device=None):
        """
        Update the window title, optionally with a device.

        Parameters
        ----------
        device : ophyd.Device, optional
            Device to indicate in the title.
        """
        title_fmt = (self.DEFAULT_TITLE
                     if device is None else self.DEFAULT_TITLE_DEVICE)

        self.setWindowTitle(title_fmt.format(self=self, device=device))

    def add_device(self, device, children=True, category='Devices'):
        """
        Add a device to the suite.

        Parameters
        ----------
        device: ophyd.Device
            The device to add.

        children: bool, optional
            Also add any ``subdevices`` of this device to the suite as well.

        category: str, optional
            Category of device. By default, all devices will just be added to
            the "Devices" group
        """
        super().add_device(device)
        self._update_title(device)
        # Create DeviceParameter and add to top level category
        dev_param = DeviceParameter(device, subdevices=children)
        self._add_to_sidebar(dev_param, category)
        # Grab children
        for child in flatten_tree(dev_param)[1:]:
            self._add_to_sidebar(child)
        # Add a device to all the tool displays
        for tool in self.tools:
            try:
                tool.add_device(device)
            except Exception:
                logger.exception("Unable to add %s to tool %s", device.name,
                                 type(tool))

    @classmethod
    def from_device(cls,
                    device,
                    parent=None,
                    tools=DEFAULT_TOOLS,
                    pin=False,
                    **kwargs):
        """
        Create a new :class:`TyphosSuite` from an :class:`ophyd.Device`.

        Parameters
        ----------
        device : ophyd.Device
            The device to use.

        children : bool, optional
            Choice to include child Device components

        parent : QWidget

        tools : dict, optional
            Tools to load for the object. ``dict`` should be name, class pairs.
            By default these will be ``.default_tools``, but ``None`` can be
            passed to avoid tool loading completely.

        **kwargs :
            Passed to :meth:`TyphosSuite.add_device`
        """
        return cls.from_devices([device],
                                parent=parent,
                                tools=tools,
                                pin=pin,
                                **kwargs)

    @classmethod
    def from_devices(cls,
                     devices,
                     parent=None,
                     tools=DEFAULT_TOOLS,
                     pin=False,
                     **kwargs):
        """
        Create a new TyphosSuite from an iterator of :class:`ophyd.Device`

        Parameters
        ----------
        device : ophyd.Device

        children : bool, optional
            Choice to include child Device components

        parent : QWidget

        tools : dict, optional
            Tools to load for the object. ``dict`` should be name, class pairs.
            By default these will be ``.default_tools``, but ``None`` can be
            passed to avoid tool loading completely.

        **kwargs :
            Passed to :meth:`TyphosSuite.add_device`
        """
        suite = cls(parent=parent, pin=pin)
        if tools is not None:
            logger.info("Loading Tools ...")
            if tools is DEFAULT_TOOLS:
                logger.debug("Using default TyphosSuite tools ...")
                tools = cls.default_tools
            for name, tool in tools.items():
                try:
                    suite.add_tool(name, tool())
                except Exception:
                    logger.exception("Unable to load %s", type(tool))
        logger.info("Adding devices ...")
        for device in devices:
            try:
                suite.add_device(device, **kwargs)
                suite.show_subdisplay(device)
            except Exception:
                logger.exception("Unable to add %r to TyphosSuite",
                                 device.name)
        return suite

    def save(self):
        """
        Save suite settings to a file using :meth:`typhos.utils.save_suite`.

        A ``QFileDialog`` will be used to query the user for the desired
        location of the created Python file

        The template will be of the form:

        .. code::
        """
        # Note: the above docstring is appended below

        logger.debug("Requesting file location for saved TyphosSuite")
        root_dir = os.getcwd()
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save TyphosSuite', root_dir, "Python (*.py)")
        if filename:
            try:
                with open(filename[0], 'w+') as handle:
                    save_suite(self, handle)
            except Exception as exc:
                logger.exception("Failed to save TyphosSuite")
                utils.raise_to_operator(exc)
        else:
            logger.debug("No filename chosen")

    # Add the template to the docstring
    save.__doc__ += textwrap.indent('\n' + utils.saved_template, '\t\t')

    def _get_sidebar(self, widget):
        items = {}
        for group in self.top_level_groups.values():
            for item in flatten_tree(group):
                items[item.value()] = item
        return items.get(widget)

    def _show_sidebar(self, widget, dock):
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_shown()
            # Make sure we react if the dock is closed outside of our menu
            dock.closing.connect(partial(self.hide_subdisplay, sidebar))
        else:
            logger.warning("Unable to find sidebar item for %r", widget)

    def _add_to_sidebar(self, parameter, category=None):
        """Add an item to the sidebar, connecting necessary signals."""
        if category:
            # Create or grab our category
            if category in self.top_level_groups:
                group = self.top_level_groups[category]
            else:
                logger.debug("Creating new category %r ...", category)
                group = ptypes.GroupParameter(name=category)
                self._tree.addParameters(group)
                self._tree.sortItems(0, QtCore.Qt.AscendingOrder)
            logger.debug("Adding %r to category %r ...", parameter.name(),
                         group.name())
            group.addChild(parameter)

        widget = parameter.value()
        if isinstance(widget, QtWidgets.QWidget):
            # Setup window to have a parent
            widget.setParent(self)
            widget.setHidden(True)

        logger.debug("Connecting parameter signals ...")
        parameter.sigOpen.connect(partial(self.show_subdisplay, parameter),
                                  QtCore.Qt.QueuedConnection)
        parameter.sigHide.connect(partial(self.hide_subdisplay, parameter),
                                  QtCore.Qt.QueuedConnection)
        if parameter.embeddable:
            parameter.sigEmbed.connect(
                partial(self.embed_subdisplay, parameter),
                QtCore.Qt.QueuedConnection)
        return parameter