def _create_theme_menu(self):
        theme_menu = QMenu(self)
        theme_menu.setTitle('Buttons Theme')
        theme_menu.setTearOffEnabled(True)
        theme_menu.setWindowTitle(TAG)
        theme_actions = QActionGroup(self)
        theme_actions.setExclusive(True)
        # create ordered theme list
        custom_order_theme = sorted(THEMES.iterkeys())
        custom_order_theme.remove('Maya Theme')
        custom_order_theme.insert(0, 'Maya Theme')
        default_item = True
        for theme in custom_order_theme:
            current_theme_action = QAction(theme, theme_actions)
            current_theme_action.setCheckable(True)
            current_theme_action.setChecked(
                MTTSettings.value('theme', 'Maya Theme') == theme)
            current_theme_action.triggered.connect(self.on_change_theme)
            theme_menu.addAction(current_theme_action)

            if default_item:
                theme_menu.addSeparator()
                default_item = False

        return theme_menu
    def on_show_prompt_instance_delay_menu(self):
        prompt_instance_state = cmds.optionVar(query='MTT_prompt_instance_state')

        if prompt_instance_state == PROMPT_INSTANCE_WAIT:
            elapsed_time = time() - cmds.optionVar(query='MTT_prompt_instance_suspend')
            if elapsed_time > PROMPT_INSTANCE_WAIT_DURATION:
                prompt_instance_state = PROMPT_INSTANCE_ASK
                cmds.optionVar(iv=['MTT_prompt_instance_state', prompt_instance_state])
            else:
                mtt_log('Remaining %.2fs' % (PROMPT_INSTANCE_WAIT_DURATION - elapsed_time))
        elif prompt_instance_state == PROMPT_INSTANCE_SESSION:
            if 'mtt_prompt_session' not in __main__.__dict__:
                prompt_instance_state = PROMPT_INSTANCE_ASK
                cmds.optionVar(iv=['MTT_prompt_instance_state', prompt_instance_state])

        self.instance_menu.clear()

        prompt_delay = QActionGroup(self)
        prompt_delay.setExclusive(True)
        for i in range(len(PROMPT_INSTANCE_STATE.keys())):
            current_delay_action = QAction(PROMPT_INSTANCE_STATE[i], prompt_delay)
            current_delay_action.setCheckable(True)
            current_delay_action.setChecked(prompt_instance_state == i)
            current_delay_action.triggered.connect(
                partial(self.view.on_choose_instance_delay, i, prompt=i != 0))
            self.instance_menu.addAction(current_delay_action)
    def on_show_debug_menu(self):
        self.debug_menu.clear()

        if self.is_master_cmd or self.power_user:
            power_user_mode = QAction('Power User Mode', self)
            power_user_mode.setCheckable(True)
            power_user_mode.setChecked(MTTSettings.value('powerUser'))
            power_user_mode.triggered.connect(self.__on_toggle_power_user)
            self.debug_menu.addAction(power_user_mode)
            self.is_master_cmd = False

            self.debug_menu.addSeparator()

        open_pref_folder_action = QAction('Open Preferences Folder', self)
        open_pref_folder_action.setStatusTip('Open MTT preference folder')
        open_pref_folder_action.triggered.connect(
            self.on_open_preference_folder)
        self.debug_menu.addAction(open_pref_folder_action)

        self.debug_menu.addSeparator()

        database_dump_csv = QAction('Dump Database as CSV', self)
        database_dump_csv.triggered.connect(self.view.model.database_dump_csv)
        self.debug_menu.addAction(database_dump_csv)

        database_dump_sql = QAction('Dump Database as SQL', self)
        database_dump_sql.triggered.connect(self.view.model.database_dump_sql)
        self.debug_menu.addAction(database_dump_sql)

        self.debug_menu.addSeparator()

        support_info = QMenu(self)
        support_info.setTitle('Supported Node Type')
        support_info.aboutToShow.connect(self.on_show_supported_type)
        self.debug_menu.addMenu(support_info)
Esempio n. 4
0
 def showContextMenu(self, point):
     'Show the Columns context menu'
     if self.model() is None:
         return
     
     # If we are viewing a proxy model, skip to the source model
     mdl = self.model()
     while isinstance(mdl, QAbstractProxyModel):
         mdl = mdl.sourceModel()
     
     if mdl is None or not hasattr(mdl, 'columns'):
         return
     
     # Generate and show the Menu
     m = QMenu()
     for i in range(len(mdl.columns)):
         c = mdl.columns[i]
         if c.internal:
             continue
         
         a = QAction(mdl.headerData(i, Qt.Horizontal, Qt.DisplayRole), m)
         a.setCheckable(True)
         a.setChecked(not self.isColumnHidden(i))
         a.triggered.connect(partial(self.showHideColumn, c=i, s=self.isColumnHidden(i)))
         m.addAction(a)
         
     m.exec_(self.header().mapToGlobal(point))
    def on_show_prompt_instance_delay_menu(self):
        prompt_instance_state = cmds.optionVar(
            query='MTT_prompt_instance_state')

        if prompt_instance_state == PROMPT_INSTANCE_WAIT:
            elapsed_time = time() - cmds.optionVar(
                query='MTT_prompt_instance_suspend')
            if elapsed_time > PROMPT_INSTANCE_WAIT_DURATION:
                prompt_instance_state = PROMPT_INSTANCE_ASK
                cmds.optionVar(
                    iv=['MTT_prompt_instance_state', prompt_instance_state])
            else:
                mtt_log('Remaining %.2fs' %
                        (PROMPT_INSTANCE_WAIT_DURATION - elapsed_time))
        elif prompt_instance_state == PROMPT_INSTANCE_SESSION:
            if 'mtt_prompt_session' not in __main__.__dict__:
                prompt_instance_state = PROMPT_INSTANCE_ASK
                cmds.optionVar(
                    iv=['MTT_prompt_instance_state', prompt_instance_state])

        self.instance_menu.clear()

        prompt_delay = QActionGroup(self)
        prompt_delay.setExclusive(True)
        for i in range(len(PROMPT_INSTANCE_STATE.keys())):
            current_delay_action = QAction(PROMPT_INSTANCE_STATE[i],
                                           prompt_delay)
            current_delay_action.setCheckable(True)
            current_delay_action.setChecked(prompt_instance_state == i)
            current_delay_action.triggered.connect(
                partial(self.view.on_choose_instance_delay, i, prompt=i != 0))
            self.instance_menu.addAction(current_delay_action)
    def _create_theme_menu(self):
        theme_menu = QMenu(self)
        theme_menu.setTitle('Buttons Theme')
        theme_menu.setTearOffEnabled(True)
        theme_menu.setWindowTitle(TAG)
        theme_actions = QActionGroup(self)
        theme_actions.setExclusive(True)
        # create ordered theme list
        custom_order_theme = sorted(THEMES.iterkeys())
        custom_order_theme.remove('Maya Theme')
        custom_order_theme.insert(0, 'Maya Theme')
        default_item = True
        for theme in custom_order_theme:
            current_theme_action = QAction(theme, theme_actions)
            current_theme_action.setCheckable(True)
            current_theme_action.setChecked(
                MTTSettings.value('theme', 'Maya Theme') == theme)
            current_theme_action.triggered.connect(self.on_change_theme)
            theme_menu.addAction(current_theme_action)

            if default_item:
                theme_menu.addSeparator()
                default_item = False

        return theme_menu
Esempio n. 7
0
    def setup_ui(self):
        """ Setup the UI for the window.

        """
        central_widget = QWidget()
        layout = QVBoxLayout()
        layout.addWidget(self.clock_view)
        layout.addWidget(self.message_view)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        menubar = self.menuBar()

        file_menu = QMenu('File')

        preferences_action = QAction('Preferences', file_menu)
        preferences_action.triggered.connect(self.on_preferences_triggered)

        quit_action = QAction('Quit', file_menu)
        quit_action.triggered.connect(self.on_quit_triggered)

        file_menu.addAction(preferences_action)
        file_menu.addAction(quit_action)
        menubar.addMenu(file_menu)

        view_menu = QMenu('View')

        fullscreen_action = QAction('Fullscreen', view_menu)
        fullscreen_action.setCheckable(True)
        fullscreen_action.setChecked(Config.get('FULLSCREEN', True))
        fullscreen_action.setShortcut('Ctrl+Meta+F')
        fullscreen_action.toggled.connect(self.on_fullscreen_changed)

        view_menu.addAction(fullscreen_action)
        menubar.addMenu(view_menu)
    def on_show_debug_menu(self):
        self.debug_menu.clear()

        if self.is_master_cmd or self.power_user:
            power_user_mode = QAction('Power User Mode', self)
            power_user_mode.setCheckable(True)
            power_user_mode.setChecked(MTTSettings.value('powerUser'))
            power_user_mode.triggered.connect(self.__on_toggle_power_user)
            self.debug_menu.addAction(power_user_mode)
            self.is_master_cmd = False

            self.debug_menu.addSeparator()

        open_pref_folder_action = QAction('Open Preferences Folder', self)
        open_pref_folder_action.setStatusTip('Open MTT preference folder')
        open_pref_folder_action.triggered.connect(self.on_open_preference_folder)
        self.debug_menu.addAction(open_pref_folder_action)

        self.debug_menu.addSeparator()

        database_dump_csv = QAction('Dump Database as CSV', self)
        database_dump_csv.triggered.connect(self.view.model.database_dump_csv)
        self.debug_menu.addAction(database_dump_csv)

        database_dump_sql = QAction('Dump Database as SQL', self)
        database_dump_sql.triggered.connect(self.view.model.database_dump_sql)
        self.debug_menu.addAction(database_dump_sql)

        self.debug_menu.addSeparator()

        support_info = QMenu(self)
        support_info.setTitle('Supported Node Type')
        support_info.aboutToShow.connect(self.on_show_supported_type)
        self.debug_menu.addMenu(support_info)
        def add_action(lbl, tip, cmd, checkable=False, checked=False):
            a = QAction(lbl, self)
            a.setStatusTip(tip)
            a.triggered.connect(cmd)
            if checkable:
                a.setCheckable(True)
                a.setChecked(checked)

            return a
        def add_action(lbl, tip, cmd, checkable=False, checked=False):
            a = QAction(lbl, self)
            a.setStatusTip(tip)
            a.triggered.connect(cmd)
            if checkable:
                a.setCheckable(True)
                a.setChecked(checked)

            return a
    def on_show_supported_type(self):
        node_types = sorted(
            [n_type for (n_type, nice, attr) in
             MTTSettings.SUPPORTED_TYPE] + MTTSettings.UNSUPPORTED_TYPE)
        support_info = self.sender()
        support_info.clear()

        for node_type in node_types:
            current = QAction(node_type, self)
            current.setEnabled(False)
            current.setCheckable(True)
            current.setChecked(node_type not in MTTSettings.UNSUPPORTED_TYPE)
            support_info.addAction(current)
    def on_show_supported_type(self):
        node_types = sorted(
            [n_type for (n_type, nice, attr) in MTTSettings.SUPPORTED_TYPE] +
            MTTSettings.UNSUPPORTED_TYPE)
        support_info = self.sender()
        support_info.clear()

        for node_type in node_types:
            current = QAction(node_type, self)
            current.setEnabled(False)
            current.setCheckable(True)
            current.setChecked(node_type not in MTTSettings.UNSUPPORTED_TYPE)
            support_info.addAction(current)
Esempio n. 13
0
 def create_size_menu(self):
     """ Create the toolbar's buttons size menu
     """
     menu = QMenu(self)
     group = QActionGroup(self)
     sizes = (_("Tiny"), 16), (_("Small"), 32), (_("Medium"),
                                                 48), (_("Big"), 64)
     for name, size in sizes:
         action = QAction(name, menu)
         action.setCheckable(True)
         if size == self.base.toolbar_size:
             action.setChecked(True)
         action.triggered.connect(partial(self.set_btn_size, size))
         group.addAction(action)
         menu.addAction(action)
     return menu
Esempio n. 14
0
    def __init__(self, parent=None):
        super(Status, self).__init__(parent)
        self.setupUi(self)
        self.base = parent

        self.wait_anim = QMovie(":/stuff/wait.gif")
        self.anim_lbl.setMovie(self.wait_anim)
        self.anim_lbl.hide()

        self.show_menu = QMenu(self)
        for i in [
                self.act_page, self.act_date, self.act_text, self.act_comment
        ]:
            self.show_menu.addAction(i)
            # noinspection PyUnresolvedReferences
            i.triggered.connect(self.on_show_items)
            i.setChecked(True)

        sort_menu = QMenu(self)
        ico_sort = QIcon(":/stuff/sort.png")
        group = QActionGroup(self)

        action = QAction(_("Date"), sort_menu)
        action.setCheckable(True)
        action.setChecked(not self.base.high_by_page)
        action.triggered.connect(self.base.set_highlight_sort)
        action.setData(False)
        group.addAction(action)
        sort_menu.addAction(action)

        action = QAction(_("Page"), sort_menu)
        action.setCheckable(True)
        action.setChecked(self.base.high_by_page)
        action.triggered.connect(self.base.set_highlight_sort)
        action.setData(True)
        group.addAction(action)
        sort_menu.addAction(action)

        sort_menu.setIcon(ico_sort)
        sort_menu.setTitle(_("Sort by"))
        self.show_menu.addMenu(sort_menu)

        self.show_items_btn.setMenu(self.show_menu)
Esempio n. 15
0
    def __init__(self):
        QMainWindow.__init__(self)
        # setup ui (the pcef GenericEditor is created there using
        # the promoted widgets system)
        self.ui = simple_editor_ui.Ui_MainWindow()
        self.ui.setupUi(self)
        self.setWindowTitle("PCEF - Generic Example")
        editor = self.ui.genericEditor

        # open this file
        try:
            openFileInEditor(self.ui.genericEditor, __file__)
        except:
            pass

        # install Panel where user can add its own markers
        p = UserMarkersPanel()
        editor.installPanel(p, editor.PANEL_ZONE_LEFT)

        # add a fold indicator around our class and the main
        editor.foldPanel.addIndicator(136, 141)

        # add styles actions
        allStyles = styles.getAllStyles()
        allStyles.sort()
        self.styleActionGroup = QActionGroup(self)
        for style in allStyles:
            action = QAction(unicode(style), self.ui.menuStyle)
            action.setCheckable(True)
            action.setChecked(style == "Default")
            self.styleActionGroup.addAction(action)
            self.ui.menuStyle.addAction(action)
        self.styleActionGroup.triggered.connect(
            self.on_styleActionGroup_triggered)

        # add panels actions
        allPanels = self.ui.genericEditor.panels()
        allPanels.sort()
        self.panels_actions = []
        for panel in allPanels:
            action = QAction(unicode(panel), self.ui.menuPanels)
            action.setCheckable(True)
            action.setChecked(panel.enabled)
            self.ui.menuPanels.addAction(action)
            self.panels_actions.append(action)
            action.triggered.connect(self.onPanelActionTriggered)

        # add panels actions
        allModes = self.ui.genericEditor.modes()
        allModes.sort()
        self.modes_actions = []
        for mode in allModes:
            action = QAction(unicode(mode), self.ui.menuModes)
            action.setCheckable(True)
            action.setChecked(mode.enabled)
            self.ui.menuModes.addAction(action)
            self.modes_actions.append(action)
            action.triggered.connect(self.onModeActionTriggered)
Esempio n. 16
0
    def __init__(self):
        QMainWindow.__init__(self)
        # setup ui (the pcef PythonEditor is created in the Ui_MainWindow using
        # the promoted widgets system)
        self.ui = simple_python_editor_ui.Ui_MainWindow()
        self.ui.setupUi(self)
        self.setWindowTitle("PCEF - Python Editor Example")
        self.acceptDrops()

        # open this file
        try:
            openFileInEditor(self.ui.genericEditor, __file__)
        except:
            pass

        # add styles actions
        allStyles = styles.getAllStyles()
        allStyles.sort()
        self.styleActionGroup = QActionGroup(self)
        for style in allStyles:
            action = QAction(unicode(style), self.ui.menuStyle)
            action.setCheckable(True)
            action.setChecked(style == "Default")
            self.styleActionGroup.addAction(action)
            self.ui.menuStyle.addAction(action)
        self.styleActionGroup.triggered.connect(
            self.on_styleActionGroup_triggered)

        # add panels actions
        allPanels = self.ui.genericEditor.panels()
        allPanels.sort()
        self.panels_actions = []
        for panel in allPanels:
            action = QAction(unicode(panel), self.ui.menuPanels)
            action.setCheckable(True)
            action.setChecked(panel.enabled)
            self.ui.menuPanels.addAction(action)
            self.panels_actions.append(action)
            action.triggered.connect(self.onPanelActionTriggered)

        # add panels actions
        allModes = self.ui.genericEditor.modes()
        allModes.sort()
        self.modes_actions = []
        for mode in allModes:
            action = QAction(unicode(mode), self.ui.menuModes)
            action.setCheckable(True)
            action.setChecked(mode.enabled)
            self.ui.menuModes.addAction(action)
            self.modes_actions.append(action)
            action.triggered.connect(self.onModeActionTriggered)
Esempio n. 17
0
    class MainWindow(QWidget):
        def __init__(self, grid, U):
            assert isinstance(U, Communicable)
            super(MainWindow, self).__init__()

            U = U.data

            layout = QVBoxLayout()

            plotBox = QHBoxLayout()
            plot = GlumpyPatchWidget(self, grid, vmin=np.min(U), vmax=np.max(U), bounding_box=bounding_box, codim=codim)
            bar = ColorBarWidget(self, vmin=np.min(U), vmax=np.max(U))
            plotBox.addWidget(plot)
            plotBox.addWidget(bar)
            layout.addLayout(plotBox)

            if len(U) == 1:
                plot.set(U.ravel())
            else:
                plot.set(U[0])

                hlayout = QHBoxLayout()

                self.slider = QSlider(Qt.Horizontal)
                self.slider.setMinimum(0)
                self.slider.setMaximum(len(U) - 1)
                self.slider.setTickPosition(QSlider.TicksBelow)
                hlayout.addWidget(self.slider)

                lcd = QLCDNumber(m.ceil(m.log10(len(U))))
                lcd.setDecMode()
                lcd.setSegmentStyle(QLCDNumber.Flat)
                hlayout.addWidget(lcd)

                layout.addLayout(hlayout)

                hlayout = QHBoxLayout()

                toolbar = QToolBar()
                self.a_play = QAction(self.style().standardIcon(QStyle.SP_MediaPlay), 'Play', self)
                self.a_play.setCheckable(True)
                self.a_rewind = QAction(self.style().standardIcon(QStyle.SP_MediaSeekBackward), 'Rewind', self)
                self.a_toend = QAction(self.style().standardIcon(QStyle.SP_MediaSeekForward), 'End', self)
                self.a_step_backward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipBackward), 'Step Back', self)
                self.a_step_forward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipForward), 'Step', self)
                self.a_loop = QAction(self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop', self)
                self.a_loop.setCheckable(True)
                toolbar.addAction(self.a_play)
                toolbar.addAction(self.a_rewind)
                toolbar.addAction(self.a_toend)
                toolbar.addAction(self.a_step_backward)
                toolbar.addAction(self.a_step_forward)
                toolbar.addAction(self.a_loop)
                hlayout.addWidget(toolbar)

                self.speed = QSlider(Qt.Horizontal)
                self.speed.setMinimum(0)
                self.speed.setMaximum(100)
                hlayout.addWidget(QLabel('Speed:'))
                hlayout.addWidget(self.speed)

                layout.addLayout(hlayout)

                self.timer = QTimer()
                self.timer.timeout.connect(self.update_solution)

                self.slider.valueChanged.connect(self.slider_changed)
                self.slider.valueChanged.connect(lcd.display)
                self.speed.valueChanged.connect(self.speed_changed)
                self.a_play.toggled.connect(self.toggle_play)
                self.a_rewind.triggered.connect(self.rewind)
                self.a_toend.triggered.connect(self.to_end)
                self.a_step_forward.triggered.connect(self.step_forward)
                self.a_step_backward.triggered.connect(self.step_backward)

                self.speed.setValue(50)

            self.setLayout(layout)
            self.plot = plot
            self.U = U

        def slider_changed(self, ind):
            self.plot.set(self.U[ind])

        def speed_changed(self, val):
            self.timer.setInterval(val * 20)

        def update_solution(self):
            ind = self.slider.value() + 1
            if ind >= len(self.U):
                if self.a_loop.isChecked():
                    ind = 0
                else:
                    self.a_play.setChecked(False)
                    return
            self.slider.setValue(ind)

        def toggle_play(self, checked):
            if checked:
                if self.slider.value() + 1 == len(self.U):
                    self.slider.setValue(0)
                self.timer.start()
            else:
                self.timer.stop()

        def rewind(self):
            self.slider.setValue(0)

        def to_end(self):
            self.a_play.setChecked(False)
            self.slider.setValue(len(self.U) - 1)

        def step_forward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() + 1
            if ind == len(self.U) and self.a_loop.isChecked():
                ind = 0
            if ind < len(self.U):
                self.slider.setValue(ind)

        def step_backward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() - 1
            if ind == -1 and self.a_loop.isChecked():
                ind = len(self.U) - 1
            if ind >= 0:
                self.slider.setValue(ind)
Esempio n. 18
0
    class PlotMainWindow(QWidget):
        """Base class for plot main windows."""

        def __init__(self, U, plot, length=1, title=None):
            super(PlotMainWindow, self).__init__()

            layout = QVBoxLayout()

            if title:
                title = QLabel('<b>' + title + '</b>')
                title.setAlignment(Qt.AlignHCenter)
                layout.addWidget(title)
            layout.addWidget(plot)

            plot.set(U, 0)

            if length > 1:
                hlayout = QHBoxLayout()

                self.slider = QSlider(Qt.Horizontal)
                self.slider.setMinimum(0)
                self.slider.setMaximum(length - 1)
                self.slider.setTickPosition(QSlider.TicksBelow)
                hlayout.addWidget(self.slider)

                lcd = QLCDNumber(m.ceil(m.log10(length)))
                lcd.setDecMode()
                lcd.setSegmentStyle(QLCDNumber.Flat)
                hlayout.addWidget(lcd)

                layout.addLayout(hlayout)

                hlayout = QHBoxLayout()

                toolbar = QToolBar()
                self.a_play = QAction(self.style().standardIcon(QStyle.SP_MediaPlay), 'Play', self)
                self.a_play.setCheckable(True)
                self.a_rewind = QAction(self.style().standardIcon(QStyle.SP_MediaSeekBackward), 'Rewind', self)
                self.a_toend = QAction(self.style().standardIcon(QStyle.SP_MediaSeekForward), 'End', self)
                self.a_step_backward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipBackward),
                                               'Step Back', self)
                self.a_step_forward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipForward), 'Step', self)
                self.a_loop = QAction(self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop', self)
                self.a_loop.setCheckable(True)
                toolbar.addAction(self.a_play)
                toolbar.addAction(self.a_rewind)
                toolbar.addAction(self.a_toend)
                toolbar.addAction(self.a_step_backward)
                toolbar.addAction(self.a_step_forward)
                toolbar.addAction(self.a_loop)
                if hasattr(self, 'save'):
                    self.a_save = QAction(self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self)
                    toolbar.addAction(self.a_save)
                    self.a_save.triggered.connect(self.save)
                hlayout.addWidget(toolbar)

                self.speed = QSlider(Qt.Horizontal)
                self.speed.setMinimum(0)
                self.speed.setMaximum(100)
                hlayout.addWidget(QLabel('Speed:'))
                hlayout.addWidget(self.speed)

                layout.addLayout(hlayout)

                self.timer = QTimer()
                self.timer.timeout.connect(self.update_solution)

                self.slider.valueChanged.connect(self.slider_changed)
                self.slider.valueChanged.connect(lcd.display)
                self.speed.valueChanged.connect(self.speed_changed)
                self.a_play.toggled.connect(self.toggle_play)
                self.a_rewind.triggered.connect(self.rewind)
                self.a_toend.triggered.connect(self.to_end)
                self.a_step_forward.triggered.connect(self.step_forward)
                self.a_step_backward.triggered.connect(self.step_backward)

                self.speed.setValue(50)

            elif hasattr(self, 'save'):
                hlayout = QHBoxLayout()
                toolbar = QToolBar()
                self.a_save = QAction(self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self)
                toolbar.addAction(self.a_save)
                hlayout.addWidget(toolbar)
                layout.addLayout(hlayout)
                self.a_save.triggered.connect(self.save)

            self.setLayout(layout)
            self.plot = plot
            self.U = U
            self.length = length

        def slider_changed(self, ind):
            self.plot.set(self.U, ind)

        def speed_changed(self, val):
            self.timer.setInterval(val * 20)

        def update_solution(self):
            ind = self.slider.value() + 1
            if ind >= self.length:
                if self.a_loop.isChecked():
                    ind = 0
                else:
                    self.a_play.setChecked(False)
                    return
            self.slider.setValue(ind)

        def toggle_play(self, checked):
            if checked:
                if self.slider.value() + 1 == self.length:
                    self.slider.setValue(0)
                self.timer.start()
            else:
                self.timer.stop()

        def rewind(self):
            self.slider.setValue(0)

        def to_end(self):
            self.a_play.setChecked(False)
            self.slider.setValue(self.length - 1)

        def step_forward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() + 1
            if ind == self.length and self.a_loop.isChecked():
                ind = 0
            if ind < self.length:
                self.slider.setValue(ind)

        def step_backward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() - 1
            if ind == -1 and self.a_loop.isChecked():
                ind = self.length - 1
            if ind >= 0:
                self.slider.setValue(ind)
Esempio n. 19
0
class SymbolWort(QWidget):
	def __init__(self):
		QWidget.__init__(self)
		self.setWindowTitle("Symbol-Worte")
		
		self.thread=MyWorker(self)
		self.thread.start()
		self.thread.calculator.calculationDone.connect(self.calculationDone)
		
		self.initUI()
	
	def about(self):
		QMessageBox.information(self,u"Über Symbol-Worte",u"Symbol-Worte ist ein kleines, zum Spaß entwickeltes, Programm. Es nutzt die Open-Source Entwicklungsumgebung Python (www.python.org) und PySide (Qt-Schnittstelle). Es ist unter GPL v.3 veröffentlicht. Entwickelt von Peter Waldert.")
	
	def update(self):
		text=self.lineEdit.text()
		if text.lower() != self.responseLabel.text().lower():
			self.thread.startCalculation(text)
	
	def calculationDone(self,ok):
		if ok:
			self.responseLabel.setText(self.thread.calculator.result)
		else:
			self.responseLabel.setText(u"Keine Treffer")
		self.updateTable(self.thread.calculator.resultElements)
	
	def updateAuto(self,checked):
		if checked:
			self.lineEdit.textEdited.connect(self.update)
		else:
			self.lineEdit.textEdited.disconnect(self.update)
	
	def updateMaxLength(self,checked):
		if checked:
			self.lineEdit.setMaxLength(10)
		else:
			self.lineEdit.setMaxLength(100)
	
	def setupTable(self):
		self.tableWidget.setColumnCount(3)
		self.tableWidget.setHorizontalHeaderLabels(["OZ","Sym","Name"])
		self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
		self.tableWidget.setSelectionMode(QTableWidget.SingleSelection)
		self.tableWidget.setEditTriggers(QTableWidget.NoEditTriggers)
		self.tableWidget.setAlternatingRowColors(True)
	
	def updateTable(self,elements):
		self.tableWidget.clearContents()
		self.tableWidget.setRowCount(len(elements))
		row=0
		for element in elements:
			self.tableWidget.setItem(row,0,QTableWidgetItem(str(element.atomicNumber)))
			self.tableWidget.setItem(row,1,QTableWidgetItem(elements[row].symbol))
			self.tableWidget.setItem(row,2,QTableWidgetItem(elements[row].name))
			row+=1
		self.tableWidget.resizeColumnsToContents()
	
	def initUI(self):
		wordLabel=QLabel("&Wort:")
		responseLabel=QLabel("Symbol-Wort:")
		progressLabel=QLabel("Rechen-Fortschritt:")
		
		self.lineEdit=QLineEdit()
		self.updateButton=QPushButton("&Berechnen")
		self.autoUpdate=QCheckBox("&Auto-Berechnung")
		self.responseLabel=QLabel()
		wordLabel.setBuddy(self.lineEdit)
		self.tableWidget=QTableWidget()
		self.progressView=ProgressView()
		
		self.disableMaxLengthAction=QAction("Zeichenmaximum (Achtung!)",self)
		self.disableMaxLengthAction.setCheckable(True)
		self.disableMaxLengthAction.toggled.connect(self.updateMaxLength)
		self.disableMaxLengthAction.setChecked(True)
		
		self.setupTable()
		self.progressView.setProgress(self.thread.calculator.progress)
		self.progressView.abortButton.setIcon(QIcon.fromTheme("process-stopp",QIcon("Abort.png")))
		self.progressView.abortButton.setToolTip("Stoppe die Berechnung")
		self.lineEdit.setValidator(QRegExpValidator(QRegExp("[A-Za-z]+")))
		self.lineEdit.setToolTip("Nur Zeichen von A-Z")
		self.lineEdit.setContextMenuPolicy(Qt.ActionsContextMenu)
		self.lineEdit.addAction(self.disableMaxLengthAction)
		self.responseLabel.setSizePolicy(QSizePolicy.Preferred,QSizePolicy.Fixed)
		self.responseLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
		self.aboutButton=QPushButton(u"Über")
		f=self.responseLabel.font()
		f.setPointSize(24)
		self.responseLabel.setFont(f)
		
		self.lineEdit.returnPressed.connect(self.update)
		self.updateButton.clicked.connect(self.update)
		self.autoUpdate.stateChanged.connect(self.updateAuto)
		self.aboutButton.clicked.connect(self.about)
		
		layout=QGridLayout()
		layout.addWidget(wordLabel,0,0)
		layout.addWidget(self.lineEdit,0,1)
		layout.addWidget(self.updateButton,0,2)
		layout.addWidget(self.autoUpdate,1,1,1,2)
		layout.addWidget(responseLabel,2,0)
		layout.addWidget(self.responseLabel,2,1,1,2)
		layout.addWidget(self.tableWidget,3,0,1,3)
		layout.addWidget(progressLabel,4,0)
		layout.addWidget(self.progressView,5,0,1,3)
		layout.addWidget(self.aboutButton,6,2)
		self.setLayout(layout)
	
	def closeEvent(self,event):
		self.thread.quit()
		self.thread.wait()
		event.accept()
	
	def keyPressEvent(self,event):
		if event.key() == Qt.Key_Escape:
			self.thread.calculator.progress.abort()
			event.accept()
		else:
			event.ignore()
Esempio n. 20
0
class MainWindow(QMainWindow):
    start_acq = Signal(str)
    start_rec = Signal(str)
    collect_frame = Signal(object)
    collect_threshed = Signal(object)

    def __init__(self, parent=None):
        ''' sets up the whole main window '''

        #standard init
        super(MainWindow, self).__init__(parent)

        #set the window title
        self.setWindowTitle('Open Ephys Control GUI')

        self.window_height = 700
        self.window_width = 1100

        self.screen2 = QDesktopWidget().screenGeometry(0)
        self.move(
            self.screen2.left() +
            (self.screen2.width() - self.window_width) / 2.,
            self.screen2.top() +
            (self.screen2.height() - self.window_height) / 2.)

        self.get_info()
        self.noinfo = True

        while self.noinfo:
            loop = QEventLoop()
            QTimer.singleShot(500., loop.quit)
            loop.exec_()

        subprocess.Popen('start %s' % open_ephys_path, shell=True)

        self.collect_frame.connect(self.update_frame)
        self.collect_threshed.connect(self.update_threshed)
        self.acquiring = False
        self.recording = False

        self.video_height = self.window_height * .52
        self.video_width = self.window_width * .48

        self.resize(self.window_width, self.window_height)

        #create QTextEdit window 'terminal' for receiving stdout and stderr
        self.terminal = QTextEdit(self)
        #set the geometry
        self.terminal.setGeometry(
            QRect(self.window_width * .02,
                  self.window_height * .15 + self.video_height,
                  self.video_width * .96, 150))

        #make widgets
        self.setup_video_frames()
        self.setup_thresh_buttons()

        self.overlay = True

        #create thread and worker for video processing
        self.videoThread = QThread(self)
        self.videoThread.start()
        self.videoproc_worker = VideoWorker(self)
        self.videoproc_worker.moveToThread(self.videoThread)

        self.vt_file = None
        """""" """""" """""" """""" """""" """""" """""" """
        set up menus
        """ """""" """""" """""" """""" """""" """""" """"""

        #create a QMenuBar and set geometry
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(
            QRect(0, 0, self.window_width * .5, self.window_height * .03))
        #set the QMenuBar as menu bar for main window
        self.setMenuBar(self.menubar)

        #create a QStatusBar
        statusbar = QStatusBar(self)
        #set it as status bar for main window
        self.setStatusBar(statusbar)

        #create icon toolbar with default image
        iconToolBar = self.addToolBar("iconBar.png")

        #create a QAction for the acquire button
        self.action_Acq = QAction(self)
        #make it checkable
        self.action_Acq.setCheckable(True)
        #grab an icon for the button
        acq_icon = self.style().standardIcon(QStyle.SP_MediaPlay)
        #set the icon for the action
        self.action_Acq.setIcon(acq_icon)
        #when the button is pressed, call the Acquire function
        self.action_Acq.triggered.connect(self.Acquire)

        #create a QAction for the record button
        self.action_Record = QAction(self)
        #make it checkable
        self.action_Record.setCheckable(True)
        #grab an icon for the button
        record_icon = self.style().standardIcon(QStyle.SP_DialogYesButton)
        #set the icon for the action
        self.action_Record.setIcon(record_icon)
        #when the button is pressed, call advanced_settings function
        self.action_Record.triggered.connect(self.Record)

        #create QAction for stop button
        action_Stop = QAction(self)
        #grab close icon
        stop_icon = self.style().standardIcon(QStyle.SP_MediaStop)
        #set icon for action
        action_Stop.setIcon(stop_icon)
        #when button pressed, close window
        action_Stop.triggered.connect(self.Stop)

        #show tips for each action in the status bar
        self.action_Acq.setStatusTip("Start acquiring")
        self.action_Record.setStatusTip("Start recording")
        action_Stop.setStatusTip("Stop acquiring/recording")

        #add actions to icon toolbar
        iconToolBar.addAction(self.action_Acq)
        iconToolBar.addAction(self.action_Record)
        iconToolBar.addAction(action_Stop)

        #        self.sort_button = QPushButton('Sort Now',self)
        #        self.sort_button.setGeometry(QRect(self.window_width*.85,0,self.window_width*.15,self.window_height*.05))
        #        self.sort_button.clicked.connect(self.sort_now)

        #show the window if minimized by windows
        self.showMinimized()
        self.showNormal()
        """""" """""" """""" """""" """""" """""" """""" """""" """""" """""" ""
        """""" """""" """""" """""" """""" """""" """""" """""" """""" """""" ""

    #this function acts as a slot to accept 'message' signal
    @Slot(str)
    def print_message(self, message):
        ''' print stdout and stderr to terminal window '''

        #move terminal cursor to end
        self.terminal.moveCursor(QTextCursor.End)
        #write message to terminal
        self.terminal.insertPlainText(message)

    def setup_thresh_buttons(self):
        ''' set up buttons for overlay/clearing thresh view '''

        self.button_frame = QFrame(self)
        self.button_frame.setGeometry(
            QRect(self.window_width * .52,
                  self.window_height * .13 + self.video_height,
                  self.video_width * .98, 50))
        button_layout = QHBoxLayout()
        self.button_frame.setLayout(button_layout)
        self.clear_button = QPushButton('Clear')
        self.overlay_button = QPushButton('Overlay')
        button_layout.addWidget(self.clear_button)
        button_layout.addWidget(self.overlay_button)

        self.clear_button.setEnabled(False)
        self.clear_button.clicked.connect(self.clear_threshed)
        self.overlay_button.setEnabled(False)
        self.overlay_button.clicked.connect(self.overlay_threshed)

    def setup_video_frames(self):
        ''' set up spots for playing video frames '''

        filler_frame = np.zeros((360, 540, 3))
        filler_frame = qimage2ndarray.array2qimage(filler_frame)

        self.raw_frame = QFrame(self)
        self.raw_label = QLabel()
        self.raw_label.setText('raw')
        self.raw_frame.setGeometry(
            QRect(self.window_width * .01, self.window_height * .15,
                  self.video_width, self.video_height))
        self.raw_frame
        raw_layout = QVBoxLayout()
        self.raw_frame.setLayout(raw_layout)
        raw_layout.addWidget(self.raw_label)

        self.threshed_frame = QFrame(self)
        self.threshed_label = QLabel()
        self.threshed_label.setText('Threshed')
        self.threshed_frame.setGeometry(
            QRect(self.window_width * .51, self.window_height * .15,
                  self.video_width, self.video_height))
        threshed_layout = QVBoxLayout()
        self.threshed_frame.setLayout(threshed_layout)
        threshed_layout.addWidget(self.threshed_label)

        self.label_frame = QFrame(self)
        self.label_frame.setGeometry(
            QRect(self.window_width * .01, self.window_height * .11,
                  self.video_width * 2, 50))
        self.label_rawlabel = QLabel()
        self.label_rawlabel.setText('Raw Video')
        self.label_threshedlabel = QLabel()
        self.label_threshedlabel.setText('Threshold View')
        label_layout = QHBoxLayout()
        self.label_frame.setLayout(label_layout)
        label_layout.addWidget(self.label_rawlabel)
        label_layout.addWidget(self.label_threshedlabel)

        self.raw_label.setPixmap(QPixmap.fromImage(filler_frame))
        self.threshed_label.setPixmap(QPixmap.fromImage(filler_frame))

    def Acquire(self):

        if self.action_Acq.isChecked():

            self.vidbuffer = []

            if self.recording:

                while 1:
                    try:
                        self.sock.send('StopRecord')
                        self.sock.recv()
                    except:
                        continue
                    break

                self.recording = False

            else:
                #create and start a thread to transport a worker to later
                self.workerThread = QThread(self)
                self.workerThread.start()
                #create a worker object based on Worker class and move it to our
                #worker thread
                self.worker = Worker(self)
                self.worker.moveToThread(self.workerThread)

                try:
                    self.start_acq.disconnect()
                except:
                    pass

                while 1:
                    try:
                        self.sock.send('StartAcquisition')
                        self.sock.recv()
                    except:
                        continue
                    break

                self.acquiring = True
                self.start_acq.connect(self.worker.acquire)
                self.start_acq.emit('start!')

            self.action_Acq.setEnabled(False)
            self.action_Record.setChecked(False)
            self.action_Record.setEnabled(True)

            record_icon = self.style().standardIcon(QStyle.SP_DialogYesButton)
            #set the icon for the action
            self.action_Record.setIcon(record_icon)

    def Record(self):

        if self.action_Record.isChecked():

            if not self.acquiring:
                self.workerThread = QThread(self)
                self.workerThread.start()

                self.worker = Worker(self)
                self.worker.moveToThread(self.workerThread)

                try:
                    self.start_rec.disconnect()
                except:
                    pass

                while 1:
                    try:
                        self.sock.send('StartAcquisition')
                        self.sock.recv()
                    except:
                        continue
                    break

                while 1:
                    try:
                        self.sock.send('StartRecord')
                        self.sock.recv()
                    except:
                        continue
                    break

                self.vidbuffer = []
                self.start_rec.connect(self.worker.acquire)
                self.recording = True
                self.start_rec.emit('start!')

            else:

                while 1:
                    try:
                        self.sock.send('StartRecord')
                        self.sock.recv()
                    except:
                        continue
                    break

                self.vidbuffer = []
                self.recording = True

            record_icon = self.style().standardIcon(QStyle.SP_DialogNoButton)
            #set the icon for the action
            self.action_Record.setIcon(record_icon)
            self.action_Record.setEnabled(False)

            self.action_Acq.setChecked(False)
            self.action_Acq.setEnabled(True)

    def Stop(self):

        self.acquiring = False
        self.recording = False

        while 1:
            try:
                self.sock.send('isRecording')
                rec = self.sock.recv()
            except:
                continue
            break

        if rec == '1':
            while 1:
                try:
                    self.sock.send('StopRecord')
                    self.sock.recv()
                except:
                    continue
                break

            self.action_Record.setEnabled(True)
            self.action_Record.setChecked(False)

        while 1:
            try:
                self.sock.send('isAcquiring')
                acq = self.sock.recv_string()
            except:
                continue
            break

        if acq == '1':
            while 1:
                try:
                    self.sock.send('StopAcquisition')
                    self.sock.recv()
                except:
                    continue
                break

        self.action_Acq.setEnabled(True)
        self.action_Acq.setChecked(False)

        try:
            #open a csv file for saving tracking data
            with open(self.vt_file, 'a') as csvfile:
                #create a writer
                vidwriter = csv.writer(csvfile, dialect='excel-tab')
                #check if it's an empty file
                for row in self.vidbuffer:
                    vidwriter.writerow(row)

        except:
            pass

        record_icon = self.style().standardIcon(QStyle.SP_DialogYesButton)
        #set the icon for the action
        self.action_Record.setIcon(record_icon)

    def update_frame(self, image):
        self.raw_label.setPixmap(QPixmap.fromImage(image))

    def update_threshed(self, threshed_image):
        self.threshed_label.setPixmap(QPixmap.fromImage(threshed_image))

    def clear_threshed(self):
        self.green_frame = np.zeros_like(self.green_frame)
        self.red_frame = np.zeros_like(self.red_frame)

    def overlay_threshed(self):
        if self.overlay:
            self.overlay = False
        elif not self.overlay:
            self.overlay = True


#    def sort_now(self):
#
#        if self.recdir is not None:
#            os.chdir('./kilosort_control')
#            #create and show the main window
#            self.sort_frame = kilosort_control.sort_gui.MainWindow()
#            self.sort_frame.show()
#
#            #set up stream for stdout and stderr based on outputStream class
#            self.outputStream = kilosort_control.sort_gui.outputStream()
#            #when outputStream sends messages, connect to appropriate function for
#            #writing to terminal window
#            self.outputStream.message.connect(self.sort_frame.print_message)
#
#            #connect stdout and stderr to outputStream
#            sys.stdout = self.outputStream
#            sys.stderr = self.outputStream
#
#            self.sort_frame.run_now(self.recdir)
#
#            self.close()

    def get_info(self):

        self.info_window = QWidget()
        self.info_window.resize(400, 350)
        #set title
        self.info_window.setWindowTitle('Session Info')
        #give layout
        info_layout = QVBoxLayout(self.info_window)

        with open('info_fields.pickle', 'rb') as f:
            default_fields = pickle.load(f)
            f.close()

        #set label for pic_resolution setting
        experimenter_label = QLabel('Experimenter:')
        #make a QLineEdit box for displaying/editing settings
        experimenter = QComboBox(self.info_window)
        experimenter.setEditable(True)
        experimenter.addItems(default_fields['experimenter'])
        #add label and box to current window
        info_layout.addWidget(experimenter_label)
        info_layout.addWidget(experimenter)

        #set label for pic_resolution setting
        whose_animal_label = QLabel('Whose animal?')
        #make a QLineEdit box for displaying/editing settings
        whose_animal = QComboBox(self.info_window)
        whose_animal.setEditable(True)
        whose_animal.addItems(default_fields['whose_animal'])
        #add label and box to current window
        info_layout.addWidget(whose_animal_label)
        info_layout.addWidget(whose_animal)

        animal_number_label = QLabel('Animal number:')
        animal_number = QComboBox(self.info_window)
        animal_number.setEditable(True)
        animal_number.addItems(default_fields['animal_number'])
        info_layout.addWidget(animal_number_label)
        info_layout.addWidget(animal_number)

        session_number_label = QLabel('Session number:')
        session_number = QTextEdit(self.info_window)
        session_number.setText('1')
        info_layout.addWidget(session_number_label)
        info_layout.addWidget(session_number)

        session_type_label = QLabel('Session type:')
        session_type = QComboBox(self.info_window)
        session_type.setEditable(True)
        session_type.addItems(default_fields['session_type'])
        info_layout.addWidget(session_type_label)
        info_layout.addWidget(session_type)

        def save_info(self):

            info_fields = {}
            info_fields['experimenter'] = [
                experimenter.itemText(i) for i in range(experimenter.count())
            ]
            info_fields['whose_animal'] = [
                whose_animal.itemText(i) for i in range(whose_animal.count())
            ]
            info_fields['animal_number'] = [
                animal_number.itemText(i) for i in range(animal_number.count())
            ]
            info_fields['session_type'] = [
                session_type.itemText(i) for i in range(session_type.count())
            ]

            with open('info_fields.pickle', 'wb') as f:
                pickle.dump(info_fields, f, protocol=2)
                f.close()

            current_experimenter = str(experimenter.currentText())
            current_whose_animal = str(whose_animal.currentText())
            current_animal_number = str(animal_number.currentText())
            current_session_number = str(session_number.toPlainText())
            current_session_type = str(session_type.currentText())

            recdir = data_save_dir + current_whose_animal + '/' + current_animal_number

            if not os.path.exists(recdir):
                os.makedirs(recdir)

            self.experiment_info = '###### Experiment Info ######\r\n'
            self.experiment_info += 'Experimenter: %s\r\n' % current_experimenter
            self.experiment_info += 'Whose animal? %s\r\n' % current_whose_animal
            self.experiment_info += 'Animal number: %s\r\n' % current_animal_number
            self.experiment_info += 'Session number: %s\r\n' % current_session_number
            self.experiment_info += 'Session type: %s\r\n' % current_session_type

            self.experiment_info = self.experiment_info.encode()

            config_file = config_path + '/' + current_animal_number + '.xml'

            if not os.path.exists(config_file):
                shutil.copy(default_config, config_file)

            tree = et.parse(config_file)
            root = tree.getroot()
            for child in root:
                if child.tag == 'CONTROLPANEL':
                    child.attrib['recordPath'] = recdir.replace('/', '\\')
            tree.write(config_file)
            tree.write(default_config)

            self.info_window.close()
            self.noinfo = False

        ready_button = QPushButton('Ready!')
        ready_button.clicked.connect(lambda: save_info(self))
        info_layout.addWidget(ready_button)

        self.info_window.show()
Esempio n. 21
0
File: gui.py Progetto: tinavas/FSERP
class Gui():
    """main gui class"""
    def __init__(self):
        self.mainwindow = QMainWindow()
        settings.get_settings()
        self.access = tuple(settings.access.items())
        self.progress = QProgressDialog("Setting up modules...", "cancel", 0,
                                        7, self.mainwindow)
        self.progress.setWindowTitle(
            QApplication.translate("MainWindow", str(settings.company), None,
                                   QApplication.UnicodeUTF8))

    def setup(self):
        """initializes the uio of the erp client"""
        self.progress.setFixedWidth(1000)
        self.progress.setCancelButton(None)
        # self.progress.setWindowModality(Qt.WindowModal)
        self.progress.setValue(1)
        self.mainwindow.setObjectName("MainWindow")
        self.mainwindow.resize(832, 668)
        self.mainwindow.setStyleSheet(
            "QToolBar{\n"
            "background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n"
            "stop:0 rgba(0,0,0),stop:1 rgb(162, 162, 162, 162));\n"
            "border: 0px;\n"
            "}\n"
            "QToolBar > QWidget{\n"
            "color:white;\n"
            "}\n"
            "QToolBar > QWidget:hover {\n"
            "background:transparent;\n"
            " }\n"
            "QToolBar > QWidget:checked {\n"
            "background:transparent;\n"
            " }\n"
            "#MainWindow{\n"
            "background: qlineargradient(x1:0, y1:0, x2:1, y2:1,\n"
            "stop:0 rgba(0,0,0),stop:1 rgb(162, 162, 162, 162));\n"
            "border: 0px;\n"
            "}\n"
            "")
        self.centralWidget = QWidget(self.mainwindow)
        self.centralWidget.setObjectName("centralWidget")
        self.gridLayout_2 = QGridLayout(self.centralWidget)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.stackedWidget = QStackedWidget(self.centralWidget)
        self.stackedWidget.setStyleSheet("")
        self.stackedWidget.setObjectName("stackedWidget")
        self.shortcut = NewShortcut()
        scroll = QScrollArea()
        scroll.setWidget(self.shortcut.shortcut_setting)
        self.stackedWidget.addWidget(self.shortcut.shortcut_setting)
        self.home_page = QWidget()
        self.home_page.setObjectName("home_page")
        self.gridLayout = QGridLayout(self.home_page)
        self.gridLayout.setObjectName("gridLayout")
        self.billing_frame_2 = QFrame(self.home_page)
        self.billing_frame_2.setStyleSheet(
            "background-image:url(:/images/billing_frame.png);\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "background-color:#6CBED2;")
        self.billing_frame_2.setFrameShape(QFrame.StyledPanel)
        self.billing_frame_2.setFrameShadow(QFrame.Raised)
        self.billing_frame_2.setObjectName("billing_frame_2")
        self.verticalLayout_4 = QVBoxLayout(self.billing_frame_2)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        spacerItem = QSpacerItem(20, 217, QSizePolicy.Minimum,
                                 QSizePolicy.Expanding)
        self.verticalLayout_4.addItem(spacerItem)
        self.label_10 = QLabel(self.billing_frame_2)
        self.label_10.setStyleSheet("background:transparent;")
        self.label_10.setObjectName("label_10")
        self.verticalLayout_4.addWidget(self.label_10)
        self.gridLayout.addWidget(self.billing_frame_2, 0, 1, 1, 1)
        self.employee_frame_3 = QFrame(self.home_page)
        self.employee_frame_3.setStyleSheet(
            "background-image:url(:/images/employee_frame.png);\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "background-color:#0099CC;")
        self.employee_frame_3.setFrameShape(QFrame.StyledPanel)
        self.employee_frame_3.setFrameShadow(QFrame.Raised)
        self.employee_frame_3.setObjectName("employee_frame_3")
        self.verticalLayout_5 = QVBoxLayout(self.employee_frame_3)
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        spacerItem1 = QSpacerItem(20, 217, QSizePolicy.Minimum,
                                  QSizePolicy.Expanding)
        self.verticalLayout_5.addItem(spacerItem1)
        self.label_11 = QLabel(self.employee_frame_3)
        self.label_11.setStyleSheet("background:transparent;")
        self.label_11.setObjectName("label_11")
        self.verticalLayout_5.addWidget(self.label_11)
        self.gridLayout.addWidget(self.employee_frame_3, 0, 2, 1, 1)
        self.menu_frame_4 = QFrame(self.home_page)
        self.menu_frame_4.setStyleSheet(
            "background-image:url(:/images/menu_frame.png);\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "background-color:#297ACC;")
        self.menu_frame_4.setFrameShape(QFrame.StyledPanel)
        self.menu_frame_4.setFrameShadow(QFrame.Raised)
        self.menu_frame_4.setObjectName("menu_frame_4")
        self.verticalLayout_3 = QVBoxLayout(self.menu_frame_4)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        spacerItem2 = QSpacerItem(20, 216, QSizePolicy.Minimum,
                                  QSizePolicy.Expanding)
        self.verticalLayout_3.addItem(spacerItem2)
        self.label_12 = QLabel(self.menu_frame_4)
        self.label_12.setStyleSheet("background:transparent;")
        self.label_12.setObjectName("label_12")
        self.verticalLayout_3.addWidget(self.label_12)
        self.gridLayout.addWidget(self.menu_frame_4, 1, 0, 1, 1)
        self.report_frame_5 = QFrame(self.home_page)
        self.report_frame_5.setStyleSheet(
            "background-image:url(:/images/report_frame.png);\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "background-color:#006BB2;")
        self.report_frame_5.setFrameShape(QFrame.StyledPanel)
        self.report_frame_5.setFrameShadow(QFrame.Raised)
        self.report_frame_5.setObjectName("report_frame_5")
        self.verticalLayout_6 = QVBoxLayout(self.report_frame_5)
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        spacerItem3 = QSpacerItem(20, 216, QSizePolicy.Minimum,
                                  QSizePolicy.Expanding)
        self.verticalLayout_6.addItem(spacerItem3)
        self.label_13 = QLabel(self.report_frame_5)
        self.label_13.setStyleSheet("background:transparent;")
        self.label_13.setObjectName("label_13")
        self.verticalLayout_6.addWidget(self.label_13)
        self.gridLayout.addWidget(self.report_frame_5, 1, 1, 1, 1)
        self.waste_frame_6 = QFrame(self.home_page)
        self.waste_frame_6.setStyleSheet(
            "background-image:url(:/images/waste_frame.png);\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "background-color:#003D7A;")
        self.waste_frame_6.setFrameShape(QFrame.StyledPanel)
        self.waste_frame_6.setFrameShadow(QFrame.Raised)
        self.waste_frame_6.setObjectName("waste_frame_6")
        self.verticalLayout_7 = QVBoxLayout(self.waste_frame_6)
        self.verticalLayout_7.setObjectName("verticalLayout_7")
        spacerItem4 = QSpacerItem(20, 216, QSizePolicy.Minimum,
                                  QSizePolicy.Expanding)
        self.verticalLayout_7.addItem(spacerItem4)
        self.label_14 = QLabel(self.waste_frame_6)
        self.label_14.setStyleSheet("background:transparent;")
        self.label_14.setObjectName("label_14")
        self.verticalLayout_7.addWidget(self.label_14)
        self.gridLayout.addWidget(self.waste_frame_6, 1, 2, 1, 1)
        self.inventory_frame_1 = QFrame(self.home_page)
        self.inventory_frame_1.setStyleSheet(
            "background-image:url(:/images/inventory_frame.png);\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "background-color:#ADEBFF;")
        self.inventory_frame_1.setFrameShape(QFrame.StyledPanel)
        self.inventory_frame_1.setFrameShadow(QFrame.Raised)
        self.inventory_frame_1.setObjectName("inventory_frame_1")
        self.verticalLayout_2 = QVBoxLayout(self.inventory_frame_1)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        spacerItem5 = QSpacerItem(20, 217, QSizePolicy.Minimum,
                                  QSizePolicy.Expanding)
        self.verticalLayout_2.addItem(spacerItem5)
        self.label_9 = QLabel(self.inventory_frame_1)
        self.label_9.setStyleSheet("background:transparent;")
        self.label_9.setObjectName("label_9")
        self.verticalLayout_2.addWidget(self.label_9)
        self.gridLayout.addWidget(self.inventory_frame_1, 0, 0, 1, 1)
        self.stackedWidget.addWidget(self.home_page)
        self.detail_page = QWidget()
        self.detail_page.setObjectName("detail_page")
        self.horizontalLayout_2 = QHBoxLayout(self.detail_page)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.main_tabWidget = QTabWidget(self.detail_page)
        self.main_tabWidget.setAutoFillBackground(False)
        self.main_tabWidget.setStyleSheet("")
        self.main_tabWidget.setTabPosition(QTabWidget.West)
        self.main_tabWidget.setIconSize(QSize(60, 60))
        self.main_tabWidget.setElideMode(Qt.ElideNone)
        self.main_tabWidget.setObjectName("main_tabWidget")
        ##initializes the tabs
        self.add_tabs()
        self.main_tabWidget.setFocusPolicy(Qt.StrongFocus)
        self.main_tabWidget.focusInEvent = self.change_focus
        self.main_tabWidget.currentChanged.connect(self.change_focus)
        self.stackedWidget.currentChanged.connect(self.change_focus)
        ######
        self.horizontalLayout_2.addWidget(self.main_tabWidget)
        self.stackedWidget.addWidget(self.detail_page)
        if ('Admin', True) in self.access:
            self.stackedWidget.addWidget(Admin(self.mainwindow))
        notification = NotificationTab()
        tab = notification.notificationTab_tab_4
        tab.custom_class_object = notification  # class_object is used to access the api through the
        self.stackedWidget.addWidget(tab)
        self.gridLayout_2.addWidget(self.stackedWidget, 0, 0, 1, 1)
        self.mainwindow.setCentralWidget(self.centralWidget)
        self.menuBar = QMenuBar(self.mainwindow)
        self.menuBar.setGeometry(QRect(0, 0, 832, 29))
        self.menuBar.setObjectName("menuBar")
        self.mainwindow.setMenuBar(self.menuBar)
        self.mainToolBar = QToolBar(self.mainwindow)
        self.mainToolBar.setLayoutDirection(Qt.RightToLeft)
        self.mainToolBar.setStyleSheet("")
        self.mainToolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.mainToolBar.setObjectName("mainToolBar")
        self.mainwindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)
        self.statusBar = QStatusBar(self.mainwindow)
        self.statusBar.setObjectName("statusBar")
        self.mainwindow.setStatusBar(self.statusBar)
        self.toolBar = QToolBar(self.mainwindow)
        self.toolBar.setLayoutDirection(Qt.RightToLeft)
        self.toolBar.setStyleSheet("")
        self.toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toolBar.setObjectName("toolBar")
        self.mainwindow.addToolBar(Qt.TopToolBarArea, self.toolBar)
        self.actionNotification = QAction(self.mainwindow)
        self.actionNotification.setCheckable(True)
        self.actionNotification.setChecked(False)
        self.actionNotification.setEnabled(True)
        icon6 = QIcon()
        icon6.addPixmap(QPixmap(":/images/notification.png"), QIcon.Normal,
                        QIcon.Off)
        self.actionNotification.setIcon(icon6)
        self.actionNotification.setAutoRepeat(True)
        self.actionNotification.setVisible(True)
        self.actionNotification.setIconVisibleInMenu(False)
        self.actionNotification.setObjectName("actionNotification")
        self.actionNotification
        self.actionAdmin = QAction(self.mainwindow)
        # self.actionAdmin.setCheckable(True)
        icon7 = QIcon()
        icon7.addPixmap(QPixmap(":/images/admin.png"), QIcon.Normal, QIcon.Off)
        self.actionAdmin.setIcon(icon7)
        self.actionAdmin.setObjectName("actionAdmin")
        self.actionRefresh = QAction(self.mainwindow)
        icon8 = QIcon()
        icon8.addPixmap(QPixmap(":/images/refresh.png"), QIcon.Normal,
                        QIcon.Off)
        self.actionRefresh.setIcon(icon8)
        self.actionRefresh.setObjectName("actionRefresh")
        self.actionHome = QAction(self.mainwindow)
        # self.actionHome.setCheckable(True)
        icon9 = QIcon()
        icon9.addPixmap(QPixmap(":/images/home.png"), QIcon.Normal, QIcon.Off)
        self.actionHome.setIcon(icon9)
        self.actionHome.setObjectName("actionHome")
        self.actionSettings = QAction(self.mainwindow)
        icon10 = QIcon()
        icon10.addPixmap(QPixmap(":/images/settings.png"), QIcon.Normal,
                         QIcon.Off)
        self.actionSettings.setIcon(icon10)
        self.actionSettings.setObjectName("actionRefresh")
        self.toolBar.addAction(self.actionNotification)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionAdmin)
        if ('Admin', True) in self.access:
            self.toolBar.addSeparator()
        else:
            self.actionAdmin.setVisible(False)
        self.toolBar.addAction(self.actionHome)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionRefresh)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionSettings)
        ##retranslates
        self.mainwindow.setWindowTitle(
            QApplication.translate("MainWindow", settings.company, None,
                                   QApplication.UnicodeUTF8))
        self.label_10.setText(
            QApplication.translate(
                "MainWindow",
                "<html><head/><body><p align=\"center\">BILLING</p></body></html>",
                None, QApplication.UnicodeUTF8))
        self.label_11.setText(
            QApplication.translate(
                "MainWindow",
                "<html><head/><body><p align=\"center\">EMPLOYEE</p></body></html>",
                None, QApplication.UnicodeUTF8))
        self.label_12.setText(
            QApplication.translate(
                "MainWindow",
                "<html><head/><body><p align=\"center\">MENU</p></body></html>",
                None, QApplication.UnicodeUTF8))
        self.label_13.setText(
            QApplication.translate(
                "MainWindow",
                "<html><head/><body><p align=\"center\">REPORT</p></body></html>",
                None, QApplication.UnicodeUTF8))
        self.label_14.setText(
            QApplication.translate(
                "MainWindow",
                "<html><head/><body><p align=\"center\">WASTE</p></body></html>",
                None, QApplication.UnicodeUTF8))
        self.label_9.setText(
            QApplication.translate(
                "MainWindow",
                "<html><head/><body><p align=\"center\">INVENTORY</p></body></html>",
                None, QApplication.UnicodeUTF8))
        self.inventory_frame_1.setToolTip(
            QApplication.translate("MainWindow", "Go to the Inventory Tab",
                                   None, QApplication.UnicodeUTF8))
        self.billing_frame_2.setToolTip(
            QApplication.translate("MainWindow", "Go to the Billing Tab", None,
                                   QApplication.UnicodeUTF8))
        self.employee_frame_3.setToolTip(
            QApplication.translate("MainWindow", "Go to the Employee Tab",
                                   None, QApplication.UnicodeUTF8))
        self.menu_frame_4.setToolTip(
            QApplication.translate("MainWindow", "Go to the Menu Tab", None,
                                   QApplication.UnicodeUTF8))
        self.report_frame_5.setToolTip(
            QApplication.translate("MainWindow", "Go to the Report Tab", None,
                                   QApplication.UnicodeUTF8))
        self.waste_frame_6.setToolTip(
            QApplication.translate("MainWindow", "Go to the Waste Tab", None,
                                   QApplication.UnicodeUTF8))
        self.toolBar.setWindowTitle(
            QApplication.translate("MainWindow", "toolBar", None,
                                   QApplication.UnicodeUTF8))
        self.actionNotification.setText("&&Notification")
        # QApplication.translate("MainWindow", "&Notification", None, QApplication.UnicodeUTF8))
        self.actionNotification.setToolTip(
            QApplication.translate("MainWindow",
                                   "Click to see new notifications", None,
                                   QApplication.UnicodeUTF8))
        # self.actionNotification.setShortcut(
        # QApplication.translate("MainWindow", "Ctrl+Shift+N", None, QApplication.UnicodeUTF8))
        self.actionAdmin.setText('&&Admin')
        # QApplication.translate("MainWindow", "Admin", None, QApplication.UnicodeUTF8))
        self.actionAdmin.setToolTip(
            QApplication.translate("MainWindow",
                                   "Click to go to admin interface", None,
                                   QApplication.UnicodeUTF8))
        # self.actionAdmin.setShortcut(
        # QApplication.translate("MainWindow", "Ctrl+Shift+A", None, QApplication.UnicodeUTF8))
        self.actionRefresh.setText("&&Refresh")
        # QApplication.translate("MainWindow", "Refresh", None, QApplication.UnicodeUTF8))
        self.actionRefresh.setToolTip(
            QApplication.translate("MainWindow",
                                   "refreshes the data from the server", None,
                                   QApplication.UnicodeUTF8))
        # self.actionRefresh.setShortcut(
        # QApplication.translate("MainWindow", "Ctrl+Shift+R", None, QApplication.UnicodeUTF8))
        self.actionHome.setText('&&Home')
        # QApplication.translate("MainWindow", "Home", None, QApplication.UnicodeUTF8))
        self.actionHome.setToolTip(
            QApplication.translate("MainWindow", "Go back to the home screen",
                                   None, QApplication.UnicodeUTF8))
        self.actionSettings.setText('&&Settings')
        # QApplication.translate("MainWindow", "Settings", None, QApplication.UnicodeUTF8))
        self.actionSettings.setToolTip(
            QApplication.translate("MainWindow", "Go to the settings panel",
                                   None, QApplication.UnicodeUTF8))
        # self.actionHome.setShortcut(
        #     QApplication.translate("MainWindow", "Ctrl+Shift+H", None, QApplication.UnicodeUTF8))
        self.stackedWidget.setCurrentIndex(1)
        self.main_tabWidget.setCurrentIndex(0)

        self.ob = self.main_tabWidget.tabBar()
        # self.add_tool_tip(self.ob) todo avoided due to segmentation fault error, left for future fixes
        self.tb = EventHandlerForTabBar()
        self.ob.installEventFilter(self.tb)

        QMetaObject.connectSlotsByName(self.mainwindow)

    def add_tabs(self):
        """
        adds new tabs
        """
        global logger
        if ('Inventory', True) in self.access:
            logger.info('initiating Inventory')
            icon = QIcon()
            icon.addPixmap(QPixmap(":/images/inventory.png"), QIcon.Normal,
                           QIcon.Off)
            from inventory.inventory import Inventory

            inventory = Inventory()
            # inventory.inventory_tab_1.setToolTip("Inventory Section")
            self.main_tabWidget.addTab(inventory.inventory_tab_1, icon, "")
            inventory.inventory_detail_tabWidget.setCurrentIndex(0)
        else:
            self.inventory_frame_1.setVisible(False)
        self.progress.setLabelText('Inventory Done....')
        self.progress.setValue(2)

        if ('Billing', True) in self.access:
            logger.info('initiating Billing')
            icon1 = QIcon()
            icon1.addPixmap(QPixmap(":/images/billing.png"), QIcon.Normal,
                            QIcon.Off)
            from billing.billing import Billing

            bill = Billing()
            # bill.billing_tab_2.setToolTip("Billing Section")
            self.main_tabWidget.addTab(bill.billing_tab_2, icon1, "")
            bill.billing_detail_tabWidget.setCurrentIndex(0)
        else:
            self.billing_frame_2.setVisible(False)
        self.progress.setLabelText('Billing Done...')
        self.progress.setValue(3)

        if ('Employee', True) in self.access:
            logger.info('initiating Employee')
            icon2 = QIcon()
            icon2.addPixmap(QPixmap(":/images/employee.png"), QIcon.Normal,
                            QIcon.Off)
            from employee.employee import Employee

            employee = Employee()
            # employee.employee_tab_3.setToolTip("Employee Section")
            self.main_tabWidget.addTab(employee.employee_tab_3, icon2, "")
            employee.employee_detail_tabWidget.setCurrentIndex(0)
        else:
            self.employee_frame_3.setVisible(False)
        self.progress.setLabelText('Employee Done...')
        self.progress.setValue(4)

        if ('Menu', True) in self.access:
            logger.info('initiating Menu')
            icon3 = QIcon()
            icon3.addPixmap(QPixmap(":/images/menu.png"), QIcon.Normal,
                            QIcon.Off)
            from menu.menu import Menu

            menu = Menu()
            # menu.menu_tab_4.setToolTip("Menu Section")
            self.main_tabWidget.addTab(menu.menu_tab_4, icon3, "")
            menu.menu_detail_tabWidget.setCurrentIndex(0)
        else:
            self.menu_frame_4.setVisible(False)
        self.progress.setLabelText('Menu Done....')
        self.progress.setValue(5)

        if ('Report', True) in self.access:
            logger.info('initiating Report')
            icon4 = QIcon()
            icon4.addPixmap(QPixmap(":/images/report.png"), QIcon.Normal,
                            QIcon.Off)
            from report.report import Report

            report = Report()
            # report.report_tab_5.setToolTip("Report Section")
            self.main_tabWidget.addTab(report.report_tab_5, icon4, "")
            report.report_detail_tabWidget.setCurrentIndex(0)
        else:
            self.report_frame_5.setVisible(False)
        self.progress.setLabelText('Report Done....')
        self.progress.setValue(6)

        if ('Waste', True) in self.access:
            logger.info('initiating Waste')
            icon5 = QIcon()
            icon5.addPixmap(QPixmap(":/images/waste.png"), QIcon.Normal,
                            QIcon.Off)
            from waste.waste import Waste

            waste = Waste()
            # waste.waste_tab_6.setToolTip("Waste Section")
            self.main_tabWidget.addTab(waste.waste_tab_6, icon5, "")
            waste.waste_detail_tabWidget.setCurrentIndex(0)
        else:
            self.waste_frame_6.setVisible(False)
        self.progress.setLabelText('Waste Done....')
        self.progress.setValue(7)

    def change_focus(self, event=None):
        """
        focus method to set focus to a tab to initialize the corresponding events of the tab
        """
        wid = self.main_tabWidget.currentWidget()
        if wid:
            if wid.isVisible():
                # print wid.objectName()
                # print '1y'
                wid.setFocus()

    def add_tool_tip(
        self, ob
    ):  # todo not working causing segmentation fault, avoided calling this function
        """
        method to add tool tip to the tabs
        :param ob: Tab bar
        """
        obj = ob
        count = obj.count()
        hardcode = {
            0: 'Inventory Section',
            1: "Billing Section",
            2: "Employee Section",
            3: "Menu Section",
            4: "Report Section",
            5: "Waste Section"
        }
        for i in range(count):
            obj.setTabToolTip(i, hardcode[i])
Esempio n. 22
0
class MainWindow(QtGui.QMainWindow):
    """The application's main window
    """
    FILE_FILTER = "inselect files (*{0})".format(InselectDocument.EXTENSION)

    def __init__(self, app, filename=None):
        super(MainWindow, self).__init__()
        self.app = app

        # Boxes view
        self.view_graphics_item = GraphicsItemView()
        # self.boxes_view is a QGraphicsView, not a QAbstractItemView
        self.boxes_view = BoxesView(self.view_graphics_item.scene)

        # Metadata view
        self.view_specimen = SpecimenView()
        self.view_metadata = MetadataView()

        self.specimens = QtGui.QSplitter()
        self.specimens.addWidget(self.view_specimen)
        self.specimens.addWidget(self.view_metadata.widget)
        self.specimens.setSizes([600, 300])

        # Views in tabs
        self.tabs = QtGui.QTabWidget(self)
        self.tabs.addTab(self.boxes_view, 'Boxes')
        self.tabs.addTab(self.specimens, 'Specimens')
        self.tabs.setCurrentIndex(0)

        # Summary view
        self.view_summary = SummaryView()

        # Main window layout
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.view_summary.widget)
        layout.addWidget(self.tabs)
        box = QtGui.QWidget()
        box.setLayout(layout)
        self.setCentralWidget(box)

        # Document
        self.document = None
        self.document_path = None

        # Model
        self.model = Model()
        self.view_graphics_item.setModel(self.model)
        self.view_specimen.setModel(self.model)
        self.view_metadata.setModel(self.model)
        self.view_summary.setModel(self.model)

        # A consistent selection across all views
        sm = self.view_specimen.selectionModel()
        self.view_graphics_item.setSelectionModel(sm)
        self.view_metadata.setSelectionModel(sm)
        self.view_summary.setSelectionModel(sm)

        # Plugins
        self.plugins = [SegmentPlugin, SubsegmentPlugin, BarcodePlugin]
        self.plugin_actions = len(self.plugins) * [None]  # QActions
        self.plugin_image = None
        self.plugin_image_visible = False

        # Long-running operations are run in their own thread.
        self.running_operation = None

        self.create_actions()
        self.create_menus()

        # Conect signals
        self.tabs.currentChanged.connect(self.current_tab_changed)
        sm.selectionChanged.connect(self.selection_changed)

        # Filter events
        self.tabs.installEventFilter(self)
        self.boxes_view.installEventFilter(self)
        self.view_specimen.installEventFilter(self)
        self.view_metadata.installEventFilter(self)

        self.empty_document()

        self.setAcceptDrops(True)

        if filename:
            self.open_file(filename)

    def eventFilter(self, obj, event):
        if event.type() in (QEvent.DragEnter, QEvent.Drop):
            return True
        else:
            return super(MainWindow, self).eventFilter(obj, event)

    @report_to_user
    def open_file(self, path=None):
        """Opens path, which can be None, the path to an inselect document or
        the path to an image file. If None, the user is prompted to select a
        file.

        * If a .inselect file, the file is opened
        * If an image file for which a .inselect document already exists, the
        .inselect file is opened
        * If a _thumbnail.jpg file corresponding to an existing .inselect file,
        the .inselect file is opened
        * If an image file, a new .inselect file is created and opened
        """
        debug_print(u'MainWindow.open_file [{0}]'.format(path))

        if not path:
            folder = QSettings().value(
                'working_directory',
                QDesktopServices.storageLocation(
                    QDesktopServices.DocumentsLocation))

            filter = u'Inselect documents (*{0});;Images ({1})'
            filter = filter.format(InselectDocument.EXTENSION,
                                   u' '.join(IMAGE_PATTERNS))
            path, selectedFilter = QtGui.QFileDialog.getOpenFileName(
                self, "Open", folder, filter)

        if path:
            # Will be None if user cancelled getOpenFileName
            if not self.close_document():
                # User does not want to close the existing document
                pass
            else:
                path = Path(path)

                if path.suffix in IMAGE_SUFFIXES:
                    # Compute the path to the inselect document (which may or
                    # may not already exist) of the image file
                    doc_of_image = path.name.replace(
                        InselectDocument.THUMBNAIL_SUFFIX, u'')
                    doc_of_image = path.parent / doc_of_image
                    doc_of_image = doc_of_image.with_suffix(
                        InselectDocument.EXTENSION)
                else:
                    doc_of_image = None

                if InselectDocument.EXTENSION == path.suffix:
                    # Open the .inselect document
                    debug_print('Opening inselect document [{0}]'.format(path))
                    self.open_document(path)
                elif doc_of_image and doc_of_image.is_file():
                    # An image file corresponding to an existing .inselect file
                    msg = u'Opening inselect document [{0}] of thumbnail [{1}]'
                    debug_print(msg.format(doc_of_image, path))
                    self.open_document(doc_of_image)
                elif path.suffix in IMAGE_SUFFIXES:
                    msg = u'Creating new inselect document for image [{0}]'
                    debug_print(msg.format(path))
                    self.new_document(path)
                else:
                    raise InselectError('Unknown file type [{0}]'.format(path))

    def new_document(self, path):
        """Creates and opens a new inselect document for the scanned image
        given in path
        """
        debug_print('MainWindow.new_document [{0}]'.format(path))

        path = Path(path)
        if not path.is_file():
            raise InselectError(
                u'Image file [{0}] does not exist'.format(path))
        else:
            # Callable for worker thread
            class NewDoc(object):
                def __init__(self, image):
                    self.image = image

                def __call__(self, progress):
                    progress('Creating thumbnail of scanned image')
                    doc = ingest_image(self.image, self.image.parent)
                    self.document_path = doc.document_path

            self.run_in_worker(NewDoc(path), 'New document',
                               self.new_document_finished)

    def new_document_finished(self, operation):
        """Called when new_document worker has finished
        """
        debug_print('MainWindow.new_document_finished')

        document_path = operation.document_path
        QSettings().setValue('working_directory', str(document_path.parent))

        self.open_file(document_path)
        msg = u'New Inselect document [{0}] created in [{1}]'
        msg = msg.format(document_path.stem, document_path.parent)
        QMessageBox.information(self, "Document created", msg)

    def open_document(self, path):
        """Opens the inselect document given by path
        """
        debug_print('MainWindow.open_document [{0}]'.format(path))

        path = Path(path)
        document = InselectDocument.load(path)
        QSettings().setValue("working_directory", str(path.parent))

        self.document = document
        self.document_path = path
        self.model.from_document(self.document)

        # TODO LH Prefer setWindowFilePath to setWindowTitle?
        self.setWindowTitle(u"Inselect [{0}]".format(self.document_path.stem))

        self.sync_ui()

    @report_to_user
    def save_document(self):
        """Saves the document
        """
        debug_print('MainWindow.save_document')
        items = []

        self.model.to_document(self.document)
        self.document.save()
        self.model.clear_modified()

    @report_to_user
    def save_crops(self):
        """Saves cropped specimen images
        """
        debug_print('MainWindow.save_crops')
        res = QMessageBox.Yes
        existing_crops = self.document.crops_dir.is_dir()

        if existing_crops:
            msg = 'Overwrite the existing cropped specimen images?'
            res = QMessageBox.question(self, 'Write cropped specimen images?',
                                       msg, QMessageBox.No, QMessageBox.Yes)

        if QMessageBox.Yes == res:

            def save_crops(progress):
                progress('Loading full-resolution scanned image')
                self.document.scanned.array

                progress('Saving crops')
                self.document.save_crops(progress)

            def completed(operation):
                QMessageBox.information(self, "Crops saved", msg)

            self.model.to_document(self.document)
            msg = "{0} crops saved in {1}"
            msg = msg.format(self.document.n_items, self.document.crops_dir)
            self.run_in_worker(save_crops, 'Save crops', completed)

    @report_to_user
    def export_csv(self):
        debug_print('MainWindow.export_csv')

        path = self.document.document_path.with_suffix('.csv')

        res = QMessageBox.Yes
        existing_csv = path.is_file()

        if existing_csv:
            msg = 'Overwrite the existing CSV file?'
            res = QMessageBox.question(self, 'Export CSV file?', msg,
                                       QMessageBox.No, QMessageBox.Yes)

        if QMessageBox.Yes == res:
            self.model.to_document(self.document)
            self.document.export_csv(path)
            msg = "Data for {0} boxes written to {1}"
            msg = msg.format(self.document.n_items, path)
            QMessageBox.information(self, "CSV saved", msg)

    @report_to_user
    def close_document(self):
        """Closes the document and returns True if not modified or if modified
        and user does not cancel. Does not close the document and returns False
        if modified and users cancels.
        """
        debug_print('MainWindow.close_document')
        if self.model.modified:
            # Ask the user if they work like to save before closing
            res = QMessageBox.question(
                self, 'Save document?', 'Save the document before closing?',
                (QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel),
                QMessageBox.Yes)

            if QMessageBox.Yes == res:
                self.save_document()

            # Answering Yes or No means the document will be closed
            close = QMessageBox.Cancel != res
        else:
            # The document is not modified so it is OK to close it
            close = True

        if close:
            self.empty_document()

        return close

    @report_to_user
    def empty_document(self):
        """Creates an empty document
        """
        debug_print('MainWindow.empty_document')
        self.document = None
        self.plugin_image = None
        self.plugin_image_visible = False
        self.model.clear()

        # TODO LH Prefer setWindowFilePath to setWindowTitle?
        self.setWindowTitle("Inselect")

        self.sync_ui()

    def closeEvent(self, event):
        """QWidget virtual
        """
        debug_print('MainWindow.closeEvent')
        if self.close_document():
            # User wants to close
            self.write_geometry_settings()
            event.accept()
        else:
            # User does not want to close
            event.ignore()

    @report_to_user
    def zoom_in(self):
        self.boxes_view.zoom_in()

    @report_to_user
    def zoom_out(self):
        self.boxes_view.zoom_out()

    @report_to_user
    def toggle_zoom(self):
        self.boxes_view.toggle_zoom()

    @report_to_user
    def zoom_home(self):
        self.boxes_view.zoom_home()

    @report_to_user
    def show_grid(self):
        self.view_specimen.show_grid()

    @report_to_user
    def show_expanded(self):
        self.view_specimen.show_expanded()

    @report_to_user
    def about(self):
        text = u"""<h1>Inselect {version}</h1>
           <h2>Contributors</h2>
           <p>
               <strong>Stefan van der Walt</strong>: Application development
               and segmentation algorithm
           </p>
           <p>
               <strong>Pieter Holtzhausen</strong>: Application development
               and segmentation algorithm
           </p>
           <p>
               <strong>Alice Heaton</strong>: Application development
           </p>
           <p>
               <strong>Lawrence Hudson</strong>: Application development
           </p>
        """.format(version=inselect.__version__)
        QMessageBox.about(self, 'Inselect', text)

    @report_to_user
    def help(self):
        """Open the help dialog"""
        d = HelpDialog(self)
        d.exec_()

    def run_in_worker(self, operation, name, complete_fn=None):
        """Runs the callable operation in a worker thread. The callable
        complete_fn is called when the operation has finished.
        """
        debug_print("MainWindow.run_in_worker")

        if self.running_operation:
            debug_print('Operation already running')
        else:
            worker = WorkerThread(operation, name, self)
            worker.completed.connect(self.worker_finished)

            self.running_operation = (operation, name, complete_fn, worker)
            worker.start()

    @report_to_user
    def worker_finished(self, user_cancelled, error_message):
        debug_print("MainWindow.worker_finished", user_cancelled,
                    error_message)

        operation, name, complete_fn, worker = self.running_operation
        self.running_operation = None

        if user_cancelled:
            QMessageBox.information(self, 'Cancelled',
                                    "'{0} cancelled'".format(name))
        elif error_message:
            QMessageBox.information(
                self, "An error occurred running '{0}'".format(name),
                error_message + '\n\nExisting data has not been altered')
        else:
            if complete_fn:
                complete_fn(operation)
            self.sync_ui()

    @report_to_user
    def run_plugin(self, plugin_number):
        """Passes each cropped specimen image through plugin
        """
        debug_print("MainWindow.run_plugin")

        if plugin_number < 0 or plugin_number > len(self.plugins):
            raise ValueError('Unexpected plugin [{0}]'.format(plugin_number))
        else:
            plugin = self.plugins[plugin_number]

            self.model.to_document(self.document)

            # Create the plugin
            operation = plugin(self.document, self)
            if operation.proceed():
                self.run_in_worker(operation, operation.name(),
                                   self.plugin_finished)
            else:
                pass

    def plugin_finished(self, operation):
        """Called when a plugin has finished running in a worker thread
        """
        debug_print("MainWindow.plugin_finished")

        if hasattr(operation, 'items'):
            self.model.set_new_boxes(operation.items)

        if hasattr(operation, 'display'):
            # An image that can be displayed instead of the main image
            display = operation.display
            self.plugin_image = QtGui.QPixmap.fromImage(qimage_of_bgr(display))
            self.update_boxes_display_pixmap()

    @report_to_user
    def select_all(self):
        """Selects all boxes in the model
        """
        sm = self.view_specimen.selectionModel()
        m = self.model
        sm.select(
            QtGui.QItemSelection(m.index(0, 0), m.index(m.rowCount() - 1, 0)),
            QtGui.QItemSelectionModel.Select)

    @report_to_user
    def select_none(self):
        sm = self.view_specimen.selectionModel()
        sm.select(QtGui.QItemSelection(), QtGui.QItemSelectionModel.Clear)

    @report_to_user
    def delete_selected(self):
        """Deletes the selected boxes
        """
        # Delete contiguous blocks of rows
        selected = self.view_specimen.selectionModel().selectedIndexes()
        selected = sorted([i.row() for i in selected])

        # Remove blocks in reverse order so that row indices are not invalidated
        # TODO LH We shouldn't need to remove blocks in reverse order - stems
        # from crummy GraphicsItemView
        for row, count in reversed(list(contiguous(selected))):
            self.model.removeRows(row, count)

    @report_to_user
    def select_next_prev(self, next):
        """Selects the next box in the mode if next is True, the previous
        box in the model if next if False.
        """
        sm = self.view_specimen.selectionModel()
        current = sm.currentIndex()
        current = current.row() if current else -1

        select = current + (1 if next else -1)
        if select == self.model.rowCount():
            select = 0
        elif -1 == select:
            select = self.model.rowCount() - 1

        debug_print('Will move selection [{0}] from [{1}]'.format(
            current, select))
        select = self.model.index(select, 0)
        sm.select(QtGui.QItemSelection(select, select),
                  QtGui.QItemSelectionModel.ClearAndSelect)
        sm.setCurrentIndex(select, QtGui.QItemSelectionModel.Current)

    @report_to_user
    def rotate90(self, clockwise):
        """Rotates the selected boxes 90 either clockwise or counter-clockwise.
        """
        debug_print('MainWindow.rotate')
        value = 90 if clockwise else -90
        selected = self.view_specimen.selectionModel().selectedIndexes()
        for index in selected:
            current = index.data(RotationRole)
            self.model.setData(index, current + value, RotationRole)

    def update_boxes_display_pixmap(self):
        """Sets the pixmap in the boxes view
        """
        pixmap = self.plugin_image if self.plugin_image_visible else None
        self.view_graphics_item.show_alternative_pixmap(pixmap)

    @report_to_user
    def toggle_plugin_image(self):
        """Action method to switch between display of the last plugin's 
        information image (if any) and the actual image.
        """
        self.plugin_image_visible = not self.plugin_image_visible
        self.update_boxes_display_pixmap()

    def create_actions(self):
        # File menu
        self.open_action = QAction("&Open...",
                                   self,
                                   shortcut=QtGui.QKeySequence.Open,
                                   triggered=self.open_file,
                                   icon=self.style().standardIcon(
                                       QtGui.QStyle.SP_DialogOpenButton))
        self.save_action = QAction("&Save",
                                   self,
                                   shortcut=QtGui.QKeySequence.Save,
                                   triggered=self.save_document,
                                   icon=self.style().standardIcon(
                                       QtGui.QStyle.SP_DialogSaveButton))
        self.save_crops_action = QAction("&Save crops",
                                         self,
                                         triggered=self.save_crops)
        self.export_csv_action = QAction("&Export CSV",
                                         self,
                                         triggered=self.export_csv)
        self.close_action = QAction("&Close",
                                    self,
                                    shortcut=QtGui.QKeySequence.Close,
                                    triggered=self.close_document)
        self.exit_action = QAction("E&xit",
                                   self,
                                   shortcut=QtGui.QKeySequence.Quit,
                                   triggered=self.close)

        # Edit menu
        self.select_all_action = QAction("Select &All",
                                         self,
                                         shortcut=QtGui.QKeySequence.SelectAll,
                                         triggered=self.select_all)
        # QT does not provide a 'select none' key sequence
        self.select_none_action = QAction("Select &None",
                                          self,
                                          shortcut="ctrl+D",
                                          triggered=self.select_none)
        self.next_box_action = QAction("Next box",
                                       self,
                                       shortcut="N",
                                       triggered=partial(self.select_next_prev,
                                                         next=True))
        self.previous_box_action = QAction("Previous box",
                                           self,
                                           shortcut="P",
                                           triggered=partial(
                                               self.select_next_prev,
                                               next=False))

        # TODO LH Does CMD + Backspace work on a mac?
        self.delete_action = QAction("&Delete selected",
                                     self,
                                     shortcut=QtGui.QKeySequence.Delete,
                                     triggered=self.delete_selected)
        self.rotate_clockwise_action = QAction("Rotate clockwise",
                                               self,
                                               shortcut="R",
                                               triggered=partial(
                                                   self.rotate90,
                                                   clockwise=True))
        self.rotate_counter_clockwise_action = QAction(
            "Rotate counter-clockwise",
            self,
            shortcut="L",
            triggered=partial(self.rotate90, clockwise=False))

        # Plugins
        # Plugin shortcuts start at F5
        shortcut_offset = 5
        for index, plugin in enumerate(self.plugins):
            action = QAction(plugin.name(),
                             self,
                             triggered=partial(self.run_plugin, index))
            shortcut_fkey = index + shortcut_offset
            if shortcut_fkey < 13:
                # Keyboards typically have 12 function keys
                action.setShortcut('f{0}'.format(shortcut_fkey))
            icon = plugin.icon()
            if icon:
                action.setIcon(icon)
            self.plugin_actions[index] = action

        # View menu
        # The obvious approach is to set the trigger to
        # partial(self.tabs.setCurrentIndex, 0) but this causes a segfault when
        # the application exits on linux.
        self.boxes_view_action = QAction("&Boxes",
                                         self,
                                         checkable=True,
                                         triggered=partial(self.show_tab, 0))
        self.metadata_view_action = QAction("&Specimens",
                                            self,
                                            checkable=True,
                                            triggered=partial(
                                                self.show_tab, 1))

        # FullScreen added in Qt 5.something
        # https://qt.gitorious.org/qt/qtbase-miniak/commit/1ef8a6d
        if not hasattr(QtGui.QKeySequence, 'FullScreen'):
            if 'darwin' == sys.platform:
                KeySequenceFullScreen = 'shift+ctrl+f'
            else:
                KeySequenceFullScreen = 'f11'
        else:
            KeySequenceFullScreen = QtGui.QKeySequence.FullScreen
        self.full_screen_action = QAction("&Full screen",
                                          self,
                                          shortcut=KeySequenceFullScreen,
                                          triggered=self.toggle_full_screen)

        self.zoom_in_action = QAction("Zoom &In",
                                      self,
                                      shortcut=QtGui.QKeySequence.ZoomIn,
                                      triggered=self.zoom_in,
                                      icon=self.style().standardIcon(
                                          QtGui.QStyle.SP_ArrowUp))
        self.zoom_out_action = QAction("Zoom &Out",
                                       self,
                                       shortcut=QtGui.QKeySequence.ZoomOut,
                                       triggered=self.zoom_out,
                                       icon=self.style().standardIcon(
                                           QtGui.QStyle.SP_ArrowDown))
        self.toogle_zoom_action = QAction("&Toogle Zoom",
                                          self,
                                          shortcut='Z',
                                          triggered=self.toggle_zoom)
        self.zoom_home_action = QAction(
            "Fit To Window",
            self,
            shortcut=QtGui.QKeySequence.MoveToStartOfDocument,
            triggered=self.zoom_home)
        # TODO LH Is F3 (normally meaning 'find next') really the right
        # shortcut for the 'toggle plugin image' action?
        self.toggle_plugin_image_action = QAction(
            "&Display plugin image",
            self,
            shortcut="f3",
            triggered=self.toggle_plugin_image,
            statusTip="Display plugin image",
            checkable=True)

        self.show_specimen_grid_action = QAction('Show grid',
                                                 self,
                                                 shortcut='g',
                                                 triggered=self.show_grid)
        self.show_specimen_expanded_action = QAction(
            'Show expanded', self, shortcut='e', triggered=self.show_expanded)

        # Help menu
        self.about_action = QAction("&About", self, triggered=self.about)
        self.help_action = QAction("&Help",
                                   self,
                                   shortcut=QtGui.QKeySequence.HelpContents,
                                   triggered=self.help)

    def create_menus(self):
        self.toolbar = self.addToolBar("Edit")
        self.toolbar.addAction(self.open_action)
        self.toolbar.addAction(self.save_action)
        for action in [a for a in self.plugin_actions if a.icon()]:
            self.toolbar.addAction(action)
        self.toolbar.addAction(self.zoom_in_action)
        self.toolbar.addAction(self.zoom_out_action)
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        self.fileMenu = QMenu("&File", self)
        self.fileMenu.addAction(self.open_action)
        self.fileMenu.addAction(self.save_action)
        self.fileMenu.addAction(self.save_crops_action)
        self.fileMenu.addAction(self.export_csv_action)
        self.fileMenu.addAction(self.close_action)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exit_action)

        self.editMenu = QMenu("&Edit", self)
        self.editMenu.addAction(self.select_all_action)
        self.editMenu.addAction(self.select_none_action)
        self.editMenu.addAction(self.delete_action)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.next_box_action)
        self.editMenu.addAction(self.previous_box_action)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.rotate_clockwise_action)
        self.editMenu.addAction(self.rotate_counter_clockwise_action)
        self.editMenu.addSeparator()
        for action in self.plugin_actions:
            self.editMenu.addAction(action)

        self.viewMenu = QMenu("&View", self)
        self.viewMenu.addAction(self.boxes_view_action)
        self.viewMenu.addAction(self.metadata_view_action)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.full_screen_action)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.zoom_in_action)
        self.viewMenu.addAction(self.zoom_out_action)
        self.viewMenu.addAction(self.toogle_zoom_action)
        self.viewMenu.addAction(self.zoom_home_action)
        self.viewMenu.addAction(self.toggle_plugin_image_action)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.show_specimen_grid_action)
        self.viewMenu.addAction(self.show_specimen_expanded_action)

        self.helpMenu = QMenu("&Help", self)
        self.helpMenu.addAction(self.help_action)
        self.helpMenu.addAction(self.about_action)

        self.menuBar().addMenu(self.fileMenu)
        self.menuBar().addMenu(self.editMenu)
        self.menuBar().addMenu(self.viewMenu)
        self.menuBar().addMenu(self.helpMenu)

    def show_tab(self, index):
        self.tabs.setCurrentIndex(index)

    def current_tab_changed(self, index):
        """Slot for self.tabs.currentChanged() signal
        """
        self.sync_ui()

    def selection_changed(self, selected, deselected):
        """Slot for self.grid_view.selectionModel().selectionChanged() signal
        """
        self.sync_ui()

    @report_to_user
    def toggle_full_screen(self):
        """Toggles between full screen and normal
        """
        if self.isFullScreen():
            self.showNormal()
        else:
            self.showFullScreen()

    def _accept_drag_drop(self, event):
        """If event refers to a single file that can opened, returns the path.
        Returns None otherwise.
        """
        urls = event.mimeData().urls() if event.mimeData() else None
        path = Path(urls[0].toLocalFile()) if urls and 1 == len(urls) else None
        if (path and path.suffix in chain([InselectDocument.EXTENSION],
                                          IMAGE_SUFFIXES)):
            return urls[0].toLocalFile()
        else:
            return None

    def dragEnterEvent(self, event):
        """QWidget virtual
        """
        debug_print('MainWindow.dragEnterEvent')
        if self._accept_drag_drop(event):
            event.acceptProposedAction()
        else:
            super(MainWindow, self).dragEnterEvent(event)

    def dropEvent(self, event):
        """QWidget virtual
        """
        debug_print('MainWindow.dropEvent')
        res = self._accept_drag_drop(event)
        if res:
            event.acceptProposedAction()
            self.open_file(res)
        else:
            super(MainWindow, self).dropEvent(event)

    def write_geometry_settings(self):
        "Writes geometry to settings"
        debug_print('MainWindow.write_geometry_settings')

        # Taken from http://stackoverflow.com/a/8736705
        # TODO LH Test on multiple display system
        s = QSettings()

        s.setValue("mainwindow/geometry", self.saveGeometry())
        s.setValue("mainwindow/pos", self.pos())
        s.setValue("mainwindow/size", self.size())

    def show_from_geometry_settings(self):
        debug_print('MainWindow.show_from_geometry_settings')

        # TODO LH What if screen resolution, desktop config change or roaming
        # profile means that restored state is outside desktop?
        s = QSettings()

        self.restoreGeometry(
            s.value("mainwindow/geometry", self.saveGeometry()))
        if not (self.isMaximized() or self.isFullScreen()):
            self.move(s.value("mainwindow/pos", self.pos()))
            self.resize(s.value("mainwindow/size", self.size()))
        self.show()
        # if read_bool("mainwindow/maximized", self.isMaximized()):
        #     debug_print('Will show maximized')
        #     self.showMaximized()
        # elif read_bool("mainwindow/full_screen", self.isMaximized()):
        #     debug_print('Will show full screen')
        #     self.showFullScreen()
        # else:
        #     debug_print('Will show normally')
        #     self.show()

    def sync_ui(self):
        """Synchronise the user interface with the application state
        """
        document = self.document is not None
        has_rows = self.model.rowCount() > 0 if self.model else False
        boxes_view_visible = self.boxes_view == self.tabs.currentWidget()
        specimens_view_visible = self.specimens == self.tabs.currentWidget()
        has_selection = len(self.view_specimen.selectedIndexes()) > 0

        # File
        self.save_action.setEnabled(document)
        self.save_crops_action.setEnabled(has_rows)
        self.export_csv_action.setEnabled(has_rows)
        self.close_action.setEnabled(document)

        # Edit
        self.select_all_action.setEnabled(has_rows)
        self.select_none_action.setEnabled(document)
        self.delete_action.setEnabled(has_selection)
        self.next_box_action.setEnabled(has_rows)
        self.previous_box_action.setEnabled(has_rows)
        self.rotate_clockwise_action.setEnabled(has_selection)
        self.rotate_counter_clockwise_action.setEnabled(has_selection)
        for action in self.plugin_actions:
            action.setEnabled(document)

        # View
        self.boxes_view_action.setChecked(boxes_view_visible)
        self.metadata_view_action.setChecked(not boxes_view_visible)
        self.zoom_in_action.setEnabled(document and boxes_view_visible)
        self.zoom_out_action.setEnabled(document and boxes_view_visible)
        self.toogle_zoom_action.setEnabled(document and boxes_view_visible)
        self.zoom_home_action.setEnabled(document and boxes_view_visible)
        self.toggle_plugin_image_action.setEnabled(document
                                                   and boxes_view_visible)
        self.show_specimen_grid_action.setEnabled(specimens_view_visible)
        self.show_specimen_expanded_action.setEnabled(specimens_view_visible)
Esempio n. 23
0
class MainWindow(QMainWindow):
    """ Starting point of the GUI based application """
    isMyProgressTimer = False
    def __init__(self):        
        """ MainWindow Constructor Function"""
        super(MainWindow, self).__init__()
        wdgt = QWidget()
        wdgt.setWindowTitle = "ManageHD"
        self.setCentralWidget(wdgt)
        self.InitUI()
        self.GetParameterFileInfo()        
    
    def InitUI(self):        
        """ Initialize user created UI elements """
        self.qlVidsDone         = QLabel('0', self)
        self.qlVidsInProgress   = QLabel('0', self)
        self.qlStartTime        = QLabel(datetime.now().strftime("%a, %d %b %Y %H:%M:%S"), self)
        self.qlEndTime          = QLabel('', self)
        self.qlTimeLeft         = QLabel('', self)
        self.qlDestinationSpace = QLabel('', self)
        self.qlArcSpace         = QLabel('', self)
        self.qlProcessingSpeed  = QLabel('', self)
        
        self.qleSourceDir       = QLineEditDirectoriesOnly()
        self.qleArchiveDir      = QLineEditDirectoriesOnly()
        self.qleDestinationDir  = QLineEditDirectoriesOnly()
        self.qleMaxVidsCap      = QLineEditIntsOnly()
        self.qleVideoTypes      = QLineEditNoPeriodsOrCommas()
        self.qleVideoTypes.installEventFilter(self)
        
        self.qpbSourceDir       = self.__CreateButton('folder.png',"", 50, self.SelectSingleFileForSourceDirectory)
        self.qpbArchiveDir      = self.__CreateButton('folder.png',"", 50, self.SelectSingleFileForArchiveDirectory)
        self.qpbTargetDir       = self.__CreateButton('folder.png',"", 50, self.SelectSingleFileForTargetDirectory)
        self.qpbRun             = self.__CreateButton(None,"Run", 75, self.Process)        
        
        self.setWindowTitle("Manage HD Video")
        self.videoExtensionFileFilter = "Video (*.mkv *.mp4 *.avi)"
        self.qleVideoTypes.setText("mkv mp4 avi")
        self.statusLabel = QLabel('Showing Progress')
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(100)
        self.__CreateActions()
        self.__CreateMenus()
        self.fileMenu.addAction(self.stdAction)
        self.fileMenu.addAction(self.altAction)
        if Progress.runPlatform == 'win':
            self.stdAction.setIcon(QIcon('checked.jpg'))
        self.stdAction.setChecked(True)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAction)
        self.fileMenu.addSeparator()
        self.helpMenu.addAction(self.aboutAction)
        self.__SetIcon()
        self.__CenterWindow()
        self.__CreateGrid()       

    def eventFilter(self, source, event): #Override
        """ Override the QMainWindow eventFilter method to add File Mask Validation. """
        if (event.type() == QEvent.FocusOut and
            source is self.qleVideoTypes):
            self.ValidateFileMask()
        return QMainWindow.eventFilter(self, source, event)
    
    def DisableGuiElements(self):
        """ Change the setEnabled property of the main GUI elements to False. """
        self.qleArchiveDir.setEnabled(False)
        self.qleDestinationDir.setEnabled(False)
        self.qleMaxVidsCap.setEnabled(False)
        self.qleSourceDir.setEnabled(False)
        self.qleVideoTypes.setEnabled(False)

        self.qpbArchiveDir.setEnabled(False)
        self.qpbSourceDir.setEnabled(False)
        self.qpbTargetDir.setEnabled(False)
        self.qpbRun.setEnabled(False)

    def EnableGuiElements(self):
        """ Change the setEnabled property of the main GUI elements to True. """
        self.qleArchiveDir.setEnabled(True)
        self.qleDestinationDir.setEnabled(True)
        self.qleMaxVidsCap.setEnabled(True)
        self.qleSourceDir.setEnabled(True)
        self.qleVideoTypes.setEnabled(True)
        
        self.qpbArchiveDir.setEnabled(True)
        self.qpbSourceDir.setEnabled(True)
        self.qpbTargetDir.setEnabled(True)
        self.qpbRun.setEnabled(True)

    def __AddGridLabel(self, grid, lblText, custFont, row, column, justification):
        sd = QLabel(lblText, self)
        sd.setFont(custFont)
        grid.addWidget(sd, row, column, alignment = justification)        

    def SelectSingleFileForSourceDirectory(self):
        self.qleSourceDir.setText( self.InvokeSingleSelectionDirectoryDialog() )
        self.ValidateFileMask()

    def SelectSingleFileForArchiveDirectory(self):
        self.qleArchiveDir.setText( self.InvokeSingleSelectionDirectoryDialog() )
    
    def SelectSingleFileForTargetDirectory(self):
        self.qleDestinationDir.setText( self.InvokeSingleSelectionDirectoryDialog() )

    def InvokeSingleSelectionFileDialog(self):
        """ Prompts the user to select a single file from a file dialog window. """
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setFilter(self.videoExtensionFileFilter)        
        ret = dialog.exec_()
        FileNames = dialog.selectedFiles()
        if len(FileNames) == 0:
            FileNames.append(None)
        return FileNames[0]
    
    def InvokeSingleSelectionDirectoryDialog(self):
        """ Prompts the user to select a single directory from a directory dialog window. """
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.DirectoryOnly)        
        DirectoryName = dialog.getExistingDirectory()
        if len(DirectoryName) == 0:
            DirectoryName = None
        return DirectoryName

    def ValidateFileMask(self):
        """ Function to validate that the entered file mask is valid. """
        extensionList = ""
        if len(self.qleVideoTypes.text().split(" ")) > 0:
            for videoExtension in self.qleVideoTypes.text().split(" "):
                extensionList += ("*." + videoExtension + " ")
            extensionList = extensionList[:-1]
        self.videoExtensionFileFilter = "Video ({})".format(extensionList)        
        
    def __CreateGrid(self):
        g1 = QGridLayout()
        self.centralWidget().setLayout(g1)

        g1.setSpacing(5)

        bold = QFont()
        bold.setBold(True)
        self.__AddGridLabel(g1, 'Source Directory:', QFont(), 0, 0, -1)
        self.__AddGridLabel(g1, 'Archive Directory:', QFont(), 1, 0, -1)
        self.__AddGridLabel(g1, 'Target Directory:', QFont(), 2, 0, -1)
        self.__AddGridLabel(g1, 'Max Number of Videos:', QFont(), 3, 0, -1)
        self.__AddGridLabel(g1, 'Video File Types:', QFont(), 3, 2, -1)
        #self.__AddGridLabel(g1, 'Max Run Time in Hours:', QFont(), 4, 2, -1)

        g1.addWidget(self.qleSourceDir, 0, 1, 1, 3)
        g1.addWidget(self.qleArchiveDir, 1, 1, 1, 3)
        g1.addWidget(self.qleDestinationDir, 2, 1, 1, 3)
        g1.addWidget(self.qleMaxVidsCap, 3, 1)
        g1.addWidget(self.qleVideoTypes, 3, 3)
        #g1.addWidget(self.qleRunTimeMax, 4, 3)
        
        g1.addWidget(self.qpbRun, 10, 3, alignment = -1)
        
        g1.addWidget(QLabel('', self), 4, 0,) # Empty Column As Separator
        g1.addWidget(QLabel('', self), 5, 0,) # Empty Column As Separator
        
        self.__AddGridLabel(g1, 'Videos Completed:',   bold, 5, 0, -1)
        self.__AddGridLabel(g1, 'Start Time:',         bold, 5, 2, -1)
        self.__AddGridLabel(g1, 'Videos In Progress:', bold, 6, 0, -1)
        self.__AddGridLabel(g1, 'Time Remaining:',     bold, 7, 2, -1)
        self.__AddGridLabel(g1, 'Target Space Left:',  bold, 7, 0, -1)
        self.__AddGridLabel(g1, 'Archive Space Left:', bold, 8, 0, -1)
        self.__AddGridLabel(g1, 'End Time:',           bold, 6, 2, -1)
        self.__AddGridLabel(g1, 'Processing Speed:',   bold, 8, 2, -1)
        
        g1.addWidget(self.qlVidsDone,        5, 1,) 
        g1.addWidget(self.qlVidsInProgress,  6, 1)
        g1.addWidget(self.qlStartTime,       5, 3,) 
        g1.addWidget(self.qlEndTime,         6, 3,) 
        g1.addWidget(self.qlTimeLeft,        7, 3,) 
        g1.addWidget(self.qlDestinationSpace,     7, 1,) 
        g1.addWidget(self.qlArcSpace,        8, 1,)
        g1.addWidget(self.qlProcessingSpeed, 8, 3,)
        
        g1.addWidget(self.qpbSourceDir,      0, 4,)
        g1.addWidget(self.qpbArchiveDir,     1, 4,)
        g1.addWidget(self.qpbTargetDir,      2, 4,)        
        self.show
        
    def GetParameterFileInfo(self):
        Progress.DeterminePlatform()
        fm = FileManip()
        #params = Progress.cliParams.copy()
        params = fm.ReadSettingsFile()
        self.qlProcessingSpeed.setText(str(Progress.cliParams['ProcessingSpeedInGBperHour']))
        self.qleSourceDir.setText(params['sourceDir'])
        self.qleArchiveDir.setText(params['archiveDir'])
        self.qleDestinationDir.setText(params['destinationDir'])
        
    def GetDriveSpace(self, path):
        """ Call the GetDriveSpace() method using an instance of the FileManip class. """
        fm = FileManip() 
        return fm.GetDriveSpace(path)

    def ResetStats(self):
        """ Change statistical data displays back to their original initialized values. """
        Progress.ResetStatuses()
        self.qlVidsDone.setText( '0')
        self.qlVidsInProgress.setText('0')
        self.qlStartTime.setText(datetime.now().strftime("%a, %d %b %Y %H:%M:%S"))
        self.qlTimeLeft.setText("")
        if self.qleDestinationDir.text() != "":
            self.qlDestinationSpace.setText(str(self.GetDriveSpace(self.qleDestinationDir.text())))
        if self.qleArchiveDir.text() != "":
            self.qlArcSpace.setText(str(self.GetDriveSpace(self.qleArchiveDir.text())))
        self.qlEndTime.setText("")
        self.qlProcessingSpeed.setText("")
    
    def VerifyRequiredFieldsFilled(self):
        """ Cancels the RUN functionality and informs the user via Message Box if the required fields are not all completed. """
        if self.qleSourceDir.text() == "" or \
            self.qleVideoTypes.text() == "" or \
            self.qleDestinationDir.text() == "":
            QMessageBox.critical(self, "Required Field Error", 
                                 "You have not filled out the three required fields. "
                                 "'Source Directory', "
                                 "'Target Directory' and "
                                 "'Video File Types' "
                                 "are all required Fields.", QMessageBox.Ok)
            return 0
        return True        

    def Process(self):
        """ Batch processing of the source video files begins here. """
        result = self.VerifyRequiredFieldsFilled()
        if result != True:
            return
        self.ResetStats()
        
        Progress.statuses['ProcessingComplete'] = False
        self.DisableGuiElements()
        Params = Progress.cliParams.copy() 
        Params['sourceDir']      = self.qleSourceDir.text()
        Params['archiveDir']     = self.qleArchiveDir.text()
        Params['destinationDir'] = self.qleDestinationDir.text()

        maximumNumVids = ""
        for idx in range(0, len(self.qleMaxVidsCap.text())):
            if self.qleMaxVidsCap.text()[idx] != '.':
                maximumNumVids = maximumNumVids + self.qleMaxVidsCap.text()[idx]

        if maximumNumVids.isnumeric():
            Params['maxNumberOfVideosToProcess']  = '%1.f' % float(self.qleMaxVidsCap.text())

        if len(self.qleVideoTypes.text().split(" ")) > 0:
            extensionList = ""
            for videoExtension in self.qleVideoTypes.text().split(" "):
                extensionList += (videoExtension + ",")
        else:
            extensionList = None

        Params['videoTypes']     = extensionList
        
        #Create and instance of the processing class
        pm = ProcessMovies()

        #Disable applicable GUI elements
        self.DisableGuiElements

        #Spawn a thread to run this
        Thread(target=pm.StartWithGUI, args=(Params,)).start()

        sleep(1)
        self.qlTimeLeft.setText(Progress.CalculateTimeRemaining())
        Progress.statuses['StatusesHaveChanged'] = True
        return

    def __CreateButton(self, folderIcon, txt, pxSize, actionFunction):
        """ Function to add a button """
        if folderIcon != None:
            folderIcon = QIcon('folder.png')
            myButton = QPushButton(folderIcon, "")
        else:
            myButton = QPushButton(txt)
        myButton.setMaximumWidth(pxSize)
        myButton.clicked.connect(actionFunction)
        return myButton

    def aboutHelp(self):
        """ Displays the ABOUT box and sets its content. """
        QMessageBox.about(self, "About ManageHD",
                          "Program written in Python v3.4 \n\n"
                          "ManageHD allows you to select an entire "
                          "directory of HD video files and lower their "
                          "resolution from 1080 HD to 720 HD, in batch. "
                          "It calls the HandBrake Command Line Interface "
                          "(CLI) in order to re-encode each video. \n\nYou must "
                          "have the Handbrake CLI installed to use this "
                          "software. "
                          "The CLI (command line interface) can be downloaded at:\n\n "
                          "     http://handbrake.fr/downloads2.php \n\n"
                          "The average video file at 720 HD "
                          "is generally one fourth to one sixth the size "
                          "of its 1080 HD source file. \n\n"
                          "Coding was done by InfanteLabz. \n\n"
                          "This sofware is released under GPL v3 "
                          "licensing. \n\n Developed on Wing IDE")

    def exitFile(self):
        """ Exits the Main Window, ending the program. """
        self.close()

    def __CreateActions(self):
        """ Function to create actions for menus """
        self.stdAction = QAction(QIcon('convert.png'), 
                                'Create MKV files',
                                self, shortcut = "Ctrl+K",
                                statusTip = "File format set to MKV container",
                                triggered = self.stdConversion,
                                checkable = True)

        self.altAction = QAction(QIcon('convert.png'), 
                                'Create MP4 files',
                                self, shortcut = "Ctrl+P",
                                statusTip = "File format set to MP4 file",
                                triggered = self.altConversion,
                                checkable = True)

        self.exitAction = QAction(QIcon('exit.png'),
                                  '&Quit',
                                  self, shortcut="Ctrl+Q",
                                  statusTip = "Exit the Application",
                                  triggered=self.exitFile)

        #self.copyAction = QAction(QIcon('copy.png'), 'C&opy',
                                  #self, shortcut="Ctrl+C",
                                  #statusTip="Copy",
                                  #triggered=self.CopyFunction)

        self.aboutAction = QAction(QIcon('about.png'), 'A&bout',
                                   self, statusTip="Displays info about ManageHD",
                                   triggered=self.aboutHelp)

    def __CreateMenus(self):
        """ Function to create actual menu bar """
        self.fileMenu = self.menuBar().addMenu("&File")
        self.helpMenu = self.menuBar().addMenu("&Help")
        
    def __CenterWindow(self):
        """ Function to center the window """
        qRect = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qRect.moveCenter(centerPoint)
        self.move(qRect.topLeft())
    
    def __SetAboutBox(self):
        """ Function to position and wire the ABOUT box """
        self.aboutButton = QPushButton("About", self)
        self.aboutButton.move(200, 100)
        self.aboutButton.clicked.connect(self.ShowAbout)
        
    def __SetIcon(self):
        """ Function to set Icon """
        appIcon = QIcon('ManageHD_Icon.png')
        self.setWindowIcon(appIcon)

    def DisplayAbnormalTerminationStatus(self, status): # Not Implemented
        pass

    def GetArchiveDirectory(self): # Not Implemented
        pass
    
    def stdConversion(self):
        """ Called by the STANDARD menu item under FILE. Sets ManageHD to perform the standard Handbrake conversion. """
        Progress.statuses['HandbrakeOptionsString'] = str(" -i {0} -o {1} -f mkv --width 1280 --crop 0:0:0:0 --decomb -s 1 -N eng -m --large-file --encoder x264 -q 19 -E ffac3")
        Progress.statuses['OutputExtension'] = 'mkv'
        self.altAction.setChecked(False)
        if Progress.runPlatform == "win":
            self.altAction.setIcon(QIcon('convert.png'))
            self.stdAction.setIcon(QIcon('checked.jpg'))
        self.stdAction.setChecked(True)
    
    def altConversion(self):
        """ Called by the ALTERNATE menu item under FILE. Sets ManageHD to perform Handbrake conversions using an alternate series of settings. """
        Progress.statuses['HandbrakeOptionsString'] = str(" -i {0} -o {1} -f mp4 --width 1280 --crop 0:0:0:0 --decomb -s 1 -N eng -m --large-file --encoder x264 -q 19 -E ffac3")
        Progress.statuses['OutputExtension'] = 'mp4'
        self.stdAction.setChecked(False)
        if Progress.runPlatform == "win":
            self.altAction.setIcon(QIcon('checked.jpg'))
            self.stdAction.setIcon(QIcon('convert.png'))
        self.altAction.setChecked(True)

    def CopyFunction(): # Not Implemented
        pass
        
    def ValidateAndRun(self): # Not Implemented
        pass
Esempio n. 24
0
    class PlotMainWindow(QWidget):
        """Base class for plot main windows."""
        def __init__(self, U, plot, length=1, title=None):
            super().__init__()

            layout = QVBoxLayout()

            if title:
                title = QLabel('<b>' + title + '</b>')
                title.setAlignment(Qt.AlignHCenter)
                layout.addWidget(title)
            layout.addWidget(plot)

            plot.set(U, 0)

            if length > 1:
                hlayout = QHBoxLayout()

                self.slider = QSlider(Qt.Horizontal)
                self.slider.setMinimum(0)
                self.slider.setMaximum(length - 1)
                self.slider.setTickPosition(QSlider.TicksBelow)
                hlayout.addWidget(self.slider)

                lcd = QLCDNumber(m.ceil(m.log10(length)))
                lcd.setDecMode()
                lcd.setSegmentStyle(QLCDNumber.Flat)
                hlayout.addWidget(lcd)

                layout.addLayout(hlayout)

                hlayout = QHBoxLayout()

                toolbar = QToolBar()
                self.a_play = QAction(
                    self.style().standardIcon(QStyle.SP_MediaPlay), 'Play',
                    self)
                self.a_play.setCheckable(True)
                self.a_rewind = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSeekBackward),
                    'Rewind', self)
                self.a_toend = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSeekForward),
                    'End', self)
                self.a_step_backward = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSkipBackward),
                    'Step Back', self)
                self.a_step_forward = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSkipForward),
                    'Step', self)
                self.a_loop = QAction(
                    self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop',
                    self)
                self.a_loop.setCheckable(True)
                toolbar.addAction(self.a_play)
                toolbar.addAction(self.a_rewind)
                toolbar.addAction(self.a_toend)
                toolbar.addAction(self.a_step_backward)
                toolbar.addAction(self.a_step_forward)
                toolbar.addAction(self.a_loop)
                if hasattr(self, 'save'):
                    self.a_save = QAction(
                        self.style().standardIcon(QStyle.SP_DialogSaveButton),
                        'Save', self)
                    toolbar.addAction(self.a_save)
                    self.a_save.triggered.connect(self.save)
                hlayout.addWidget(toolbar)

                self.speed = QSlider(Qt.Horizontal)
                self.speed.setMinimum(0)
                self.speed.setMaximum(100)
                hlayout.addWidget(QLabel('Speed:'))
                hlayout.addWidget(self.speed)

                layout.addLayout(hlayout)

                self.timer = QTimer()
                self.timer.timeout.connect(self.update_solution)

                self.slider.valueChanged.connect(self.slider_changed)
                self.slider.valueChanged.connect(lcd.display)
                self.speed.valueChanged.connect(self.speed_changed)
                self.a_play.toggled.connect(self.toggle_play)
                self.a_rewind.triggered.connect(self.rewind)
                self.a_toend.triggered.connect(self.to_end)
                self.a_step_forward.triggered.connect(self.step_forward)
                self.a_step_backward.triggered.connect(self.step_backward)

                self.speed.setValue(50)

            elif hasattr(self, 'save'):
                hlayout = QHBoxLayout()
                toolbar = QToolBar()
                self.a_save = QAction(
                    self.style().standardIcon(QStyle.SP_DialogSaveButton),
                    'Save', self)
                toolbar.addAction(self.a_save)
                hlayout.addWidget(toolbar)
                layout.addLayout(hlayout)
                self.a_save.triggered.connect(self.save)

            self.setLayout(layout)
            self.plot = plot
            self.U = U
            self.length = length

        def slider_changed(self, ind):
            self.plot.set(self.U, ind)

        def speed_changed(self, val):
            self.timer.setInterval(val * 20)

        def update_solution(self):
            ind = self.slider.value() + 1
            if ind >= self.length:
                if self.a_loop.isChecked():
                    ind = 0
                else:
                    self.a_play.setChecked(False)
                    return
            self.slider.setValue(ind)

        def toggle_play(self, checked):
            if checked:
                if self.slider.value() + 1 == self.length:
                    self.slider.setValue(0)
                self.timer.start()
            else:
                self.timer.stop()

        def rewind(self):
            self.slider.setValue(0)

        def to_end(self):
            self.a_play.setChecked(False)
            self.slider.setValue(self.length - 1)

        def step_forward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() + 1
            if ind == self.length and self.a_loop.isChecked():
                ind = 0
            if ind < self.length:
                self.slider.setValue(ind)

        def step_backward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() - 1
            if ind == -1 and self.a_loop.isChecked():
                ind = self.length - 1
            if ind >= 0:
                self.slider.setValue(ind)
Esempio n. 25
0
class MainWindow(QMainWindow):
	def __init__(self):
		super(MainWindow, self).__init__()		
		self.debug = debug

		self.progset = QSettings("ADLMIDI-pyGUI", "ADLMIDI-pyGUI")
		
		self.about_window = None
		self.settings_window = None
		self.paused = False

		self.MaxRecentFiles = int(self.progset.value("file/MaxRecentFiles", 5))

		self.recentList = self.progset.value("file/recent", [])
		if type(self.recentList) is unicode: self.recentList = [self.recentList]

		self.banks = [	" 0 = AIL (Star Control 3, Albion, Empire 2, Sensible Soccer, Settlers 2, many others)",
						"01 = Bisqwit (selection of 4op and 2op)",
						"02 = HMI (Descent, Asterix)",
						"03 = HMI (Descent:: Int)",
						"04 = HMI (Descent:: Ham)",
						"05 = HMI (Descent:: Rick)",
						"06 = HMI (Descent 2)",
						"07 = HMI (Normality)",
						"08 = HMI (Shattered Steel)",
						"09 = HMI (Theme Park)",
						"10 = HMI (3d Table Sports, Battle Arena Toshinden)",
						"11 = HMI (Aces of the Deep)",
						"12 = HMI (Earthsiege)",
						"13 = HMI (Anvil of Dawn)",
						"14 = DMX (Doom           :: partially pseudo 4op)",
						"15 = DMX (Hexen, Heretic :: partially pseudo 4op)",
						"16 = DMX (MUS Play       :: partially pseudo 4op)",
						"17 = AIL (Discworld, Grandest Fleet, Pocahontas, Slob Zone 3d, Ultima 4, Zorro)",
						"18 = AIL (Warcraft 2)",
						"19 = AIL (Syndicate)",
						"20 = AIL (Guilty, Orion Conspiracy, Terra Nova Strike Force Centauri :: 4op)",
						"21 = AIL (Magic Carpet 2)",
						"22 = AIL (Nemesis)",
						"23 = AIL (Jagged Alliance)",
						"24 = AIL (When Two Worlds War :: 4op, MISSING INSTRUMENTS)",
						"25 = AIL (Bards Tale Construction :: MISSING INSTRUMENTS)",
						"26 = AIL (Return to Zork)",
						"27 = AIL (Theme Hospital)",
						"28 = AIL (National Hockey League PA)",
						"29 = AIL (Inherit The Earth)",
						"30 = AIL (Inherit The Earth, file two)",
						"31 = AIL (Little Big Adventure :: 4op)",
						"32 = AIL (Wreckin Crew)",
						"33 = AIL (Death Gate)",
						"34 = AIL (FIFA International Soccer)",
						"35 = AIL (Starship Invasion)",
						"36 = AIL (Super Street Fighter 2 :: 4op)",
						"37 = AIL (Lords of the Realm :: MISSING INSTRUMENTS)",
						"38 = AIL (SimFarm, SimHealth :: 4op)",
						"39 = AIL (SimFarm, Settlers, Serf City)",
						"40 = AIL (Caesar 2 :: partially 4op, MISSING INSTRUMENTS)",
						"41 = AIL (Syndicate Wars)",
						"42 = AIL (Bubble Bobble Feat. Rainbow Islands, Z)",
						"43 = AIL (Warcraft)",
						"44 = AIL (Terra Nova Strike Force Centuri :: partially 4op)",
						"45 = AIL (System Shock :: partially 4op)",
						"46 = AIL (Advanced Civilization)",
						"47 = AIL (Battle Chess 4000 :: partially 4op, melodic only)",
						"48 = AIL (Ultimate Soccer Manager :: partially 4op)",
						"49 = AIL (Air Bucks, Blue And The Gray, America Invades, Terminator 2029)",
						"50 = AIL (Ultima Underworld 2)",
						"51 = AIL (Kasparov's Gambit)",
						"52 = AIL (High Seas Trader :: MISSING INSTRUMENTS)",
						"53 = AIL (Master of Magic, Master of Orion 2 :: 4op, std percussion)",
						"54 = AIL (Master of Magic, Master of Orion 2 :: 4op, orchestral percussion)",
						"55 = SB  (Action Soccer)",
						"56 = SB  (3d Cyberpuck :: melodic only)",
						"57 = SB  (Simon the Sorcerer :: melodic only)",
						"58 = OP3 (The Fat Man 2op set)",
						"59 = OP3 (The Fat Man 4op set)",
						"60 = OP3 (JungleVision 2op set :: melodic only)",
						"61 = OP3 (Wallace 2op set, Nitemare 3D :: melodic only)",
						"62 = TMB (Duke Nukem 3D)",
						"63 = TMB (Shadow Warrior)",
						"64 = DMX (Raptor)"
					]
					
		self.openicon  = QIcon.fromTheme('document-open', QIcon('img/load.png'))
		self.saveicon  = QIcon.fromTheme('document-save', QIcon('img/save.png'))
		self.playicon  = QIcon.fromTheme('media-playback-start', QIcon('img/play.png'))
		self.pauseicon = QIcon.fromTheme('media-playback-pause', QIcon('img/pause.png'))
		self.stopicon  = QIcon.fromTheme('media-playback-stop', QIcon('img/stop.png'))
		self.quiticon  = QIcon.fromTheme('application-exit', QIcon('img/quit.png'))
		self.abouticon = QIcon.fromTheme('help-about', QIcon('img/about.png'))
		self.setticon  = QIcon.fromTheme('preferences-desktop', QIcon('img/settings.png'))

		self.winsetup()

	def addWorker(self, worker):
		worker.message.connect(self.update)
		worker.finished.connect(self.workerFinished)
		self.threads.append(worker)

	def workerFinished(self):
		pass
		#barf('MSG', 'Thread completed the task!')

	def killWorkers(self):
		pass
		#for worker in self.threads:
		#	worker.terminate()
		
	def winsetup(self):
		self.setWindowIcon(QIcon('img/note.png'))
		
		openFile = QAction(self.openicon, 'Open', self)
		openFile.setShortcut('Ctrl+O')
		openFile.triggered.connect(self.load)
		
		saveFile = QAction(self.saveicon, 'Save', self)
		saveFile.setShortcut('Ctrl+S')
		saveFile.triggered.connect(self.save)
		
		playFile = QAction(self.playicon, 'Play', self)
		playFile.setShortcut('Ctrl+P')
		playFile.triggered.connect(self.play)
		
		pausePlayb = QAction(self.pauseicon, 'Pause', self)
		pausePlayb.setShortcut('Ctrl+R')
		pausePlayb.triggered.connect(self.pause)
		
		stopPlay = QAction(self.stopicon, 'Stop', self)
		stopPlay.setShortcut('Ctrl+Z')
		stopPlay.triggered.connect(self.stop)
		
		exitAction = QAction(self.quiticon, 'Quit', self)
		exitAction.setShortcut('Ctrl+X')
		exitAction.triggered.connect(self.quit)
		
		aboutdlg = QAction(self.abouticon, 'About', self)
		aboutdlg.setShortcut('Ctrl+A')
		aboutdlg.triggered.connect(self.about)
		
		showSett = QAction(self.setticon, 'Settings', self)
		showSett.triggered.connect(self.settings)

		menubar = self.menuBar()

		fileMenu = menubar.addMenu('&File')
		configMenu = menubar.addMenu('&Options')
		configMenu.setStyleSheet("border: 1px solid black;")
		
		self.setLooped = QAction('Loop', configMenu, checkable=True)
		if self.progset.value("sound/Looped") == 'true': self.setLooped.setChecked(True)
		else: self.setLooped.setChecked(False)
		self.setLooped.setShortcut('Ctrl+L')
		
		self.setAutoplay = QAction('Autoplay', configMenu, checkable=True)
		if self.progset.value("sound/Autoplay") == 'true': self.setAutoplay.setChecked(True)
		else: self.setAutoplay.setChecked(False)
		self.setAutoplay.setShortcut('Ctrl+K')
		
		configMenu.addAction(self.setAutoplay)
		configMenu.addAction(self.setLooped)

		fileMenu.setStyleSheet("border: 1px solid black;")
		fileMenu.addAction(openFile)
		fileMenu.addAction(saveFile)
		fileMenu.addSeparator()

		self.recentMenu = fileMenu.addMenu('Recent')
		self.rfUpdate()

		fileMenu.addSeparator()
		fileMenu.addAction(showSett)
		fileMenu.addSeparator()
		fileMenu.addAction(exitAction)

		helpMenu = menubar.addMenu('&Help')
		helpMenu.setStyleSheet("border: 1px solid black;")
		helpMenu.addAction(aboutdlg)
		
		self.numCards = QSpinBox()
		numCards_text = QLabel(" OPL : ")
		self.numCards.setRange(1, 100)
		self.numCards.setValue(int(self.progset.value("sound/numCards", 3)))
		self.numCards.valueChanged.connect(self.updateMax4ops)
		
		self.fourOps = QSpinBox()
		fourOps_text = QLabel(" 4op Ch : ")
		self.fourOps.setRange(0, self.numCards.value()*6)
		self.fourOps.setValue(int(self.progset.value("sound/fourOps", self.numCards.value()*6)))
		
		self.twoOps = QSpinBox()
		twoOps_text = QLabel(" 2op Ch : ")
		self.twoOps.setValue((self.numCards.value()*12 - self.fourOps.value()))
		self.twoOps.setRange(self.twoOps.value(), self.twoOps.value())
		
		toolbar = self.addToolBar('Media')
		toolbar.addAction(playFile)
		toolbar.addAction(pausePlayb)
		toolbar.addAction(stopPlay)
		toolbar.setMovable(False)
		toolbar.addSeparator()
		toolbar.addWidget(numCards_text)
		toolbar.addWidget(self.numCards)
		toolbar.addSeparator()
		toolbar.addWidget(fourOps_text)
		toolbar.addWidget(self.fourOps)
		#toolbar.addSeparator()
		#toolbar.addWidget(twoOps_text)
		#toolbar.addWidget(self.twoOps)
		
		self.statusBar()
		
		self.setFixedSize(380, 90)
		self.center()
		self.setWindowTitle('ADLMIDI pyGUI')
		self.show()
		
		if self.debug: barf("MSG", "Loaded Main Window", True, False)
		self.update("ready")

		self.threads = []
		self.addWorker(AdlMidi(1))
		self.addWorker(AdlMidiSave(2))

	def rfUpdate(self):
		self.recentMenu.clear()
		def recentfile(f2l):
			return lambda: self.load2(f2l)
		self.recentFileActs = []
		recentLength = len(self.recentList)
		for i in range(self.MaxRecentFiles):
			try:
				if i >= recentLength: break
				rev = (recentLength-1)-i
				filetoload = self.recentList[rev]
				filename = path.split(filetoload)[1]
				self.fileact = QAction(filename, self.recentMenu)
				self.fileact.triggered.connect(recentfile(filetoload))
				self.recentFileActs.append(self.fileact)
			except Exception: pass
		for i in range(self.MaxRecentFiles):
			try: self.recentMenu.addAction(self.recentFileActs[i])
			except Exception: pass

	def get_bank(self):
		try:
			selection = self.settings_window.combo.currentText()
			selection = str(selection[0])+str(selection[1])
			return int(selection)
		except Exception: return 1
		
	def center(self):
		qr = self.frameGeometry()
		cp = QDesktopWidget().availableGeometry().center()
		qr.moveCenter(cp)
		self.move(qr.topLeft())

	def about(self):
		if self.about_window is None:
			window = QMessageBox(self)
			self.about_window = window
		else: window = self.about_window
		window = self.about_window
		window.setWindowIcon(QIcon(self.abouticon))
		window.setWindowTitle('About ADLMIDI pyGUI')
		
		credits = "<center><b>ADLMIDI pyGUI v%s (%s)</b><br>Developed by Tristy H. \"KittyTristy\"<br>[<a href=\"https://github.com/KittyTristy/ADLMIDI-pyGUI\">Website</a>] [<a href=\"mailto:[email protected]\">Email</a>] <br><br><br>" % (__version__, system())
		title = "<b>ADLMIDI pyGUI</b> is a GUI wrapper<br>written in Python for use with..<br><br><b>ADLMIDI: MIDI Player<br>for Linux and Windows with OPL3 emulation</b><br>"
		cw = "(C) -- <a href=\"http://iki.fi/bisqwit/source/adlmidi.html\">http://iki.fi/bisqwit/source/adlmidi.html</a></center>"
		credits = credits + title + cw
		window.setText(credits)
			
		window.show()
		window.activateWindow()
		window.raise_()
		
	def settings(self):
		if self.settings_window is None:
			window = QDialog(self)
			self.settings_window = window
		else: window = self.settings_window
		window = self.settings_window
		window.setWindowTitle('Settings')
		
		window.notelabel = QLabel("Currently these settings are only guaranteed to work prior to loading the first MIDI!\nYou'll have to restart ADLMIDI pyGui to change them again if they stop working. \n\nSorry! This will be fixed soon!")
		window.notelabel.setWordWrap(True)
		window.notelabel.setStyleSheet("font-size: 8pt; border-style: dotted; border-width: 1px; padding: 12px;")
		window.banklabel = QLabel("<B>Choose Instrument Bank</B>")
		window.space     = QLabel("")
		window.optlabel  = QLabel("<B>Options</B>")
		
		window.combo = QComboBox()
		window.combo.addItems(self.banks)
		#window.combo.setMaximumWidth(350)
		window.combo.setMaxVisibleItems(12)
		window.combo.setStyleSheet("combobox-popup: 0;")
		window.combo.setCurrentIndex(int(self.progset.value("sound/bank", 1)))
		window.combo.currentIndexChanged.connect(self.saveSettings)
		
		window.perc		= QCheckBox("Adlib Percussion Instrument Mode")
		#window.perc.stateChanged.connect(self.checkOpts)
		window.tremamp  = QCheckBox("Tremolo Amplification Mode")
		#window.tremamp.stateChanged.connect(self.checkOpts)
		window.vibamp   = QCheckBox("Vibrato Amplification Mode")
		#window.vibamp.stateChanged.connect(self.checkOpts)
		window.modscale = QCheckBox("Scaling of Modulator Volume")
		#window.modscale.stateChanged.connect(self.checkOpts)
		
		window.okButton = QPushButton('OK')
		window.okButton.clicked.connect(window.hide)
		
		vbox = QVBoxLayout()
		vbox.addWidget(window.space)
		vbox.addWidget(window.banklabel)
		vbox.addWidget(window.combo)
		vbox.addWidget(window.space)
		vbox.addWidget(window.optlabel)
		vbox.addWidget(window.perc)
		vbox.addWidget(window.tremamp)
		vbox.addWidget(window.vibamp)
		vbox.addWidget(window.modscale)
		vbox.addWidget(window.notelabel)
		
		hbox = QHBoxLayout()
		hbox.addStretch(1)
		hbox.addWidget(window.okButton)
		
		vbox.addLayout(hbox)
		window.setLayout(vbox) 
		
		window.setFixedSize(530, 369)
		window.show()
		window.activateWindow()
		window.raise_()
		
	def updateMax4ops(self):
		self.fourOps.setMaximum(self.numCards.value()*6)
		self.fourOps.setValue(self.numCards.value()*6)
		barf("DBG", "Updating Maximum of 4ops Chs to %s" % (self.numCards.value()*6), True, False)
		#self.twoOps.setValue(self.numCards.value()*12 - self.fourOps.value())
		#self.twoOps.setRange(self.twoOps.value(), self.twoOps.value())
		
	def checkOpts(self):
		global arglist
		#barf("ACT", "Checking if Options have changed..", True, False)
		arglist = []
		try:
			if QAbstractButton.isChecked(self.settings_window.perc) and not ('-p' in arglist): arglist.append('-p')
			elif not QAbstractButton.isChecked(self.settings_window.perc) and ('-p' in arglist): arglist.remove('-p')
		except Exception: pass
		try:
			if QAbstractButton.isChecked(self.settings_window.tremamp) and not ('-t' in arglist): arglist.append('-t')
			elif not QAbstractButton.isChecked(self.settings_window.tremamp) and ('-t' in arglist): arglist.remove('-t')
		except Exception: pass
		try:
			if QAbstractButton.isChecked(self.settings_window.vibamp) and not ('-v' in arglist): arglist.append('-v')
			elif not QAbstractButton.isChecked(self.settings_window.vibamp) and ('-v' in arglist): arglist.remove('-v')
		except Exception: pass
		try:
			if QAbstractButton.isChecked(self.settings_window.modscale) and not ('-s' in arglist): arglist.append('-s')
			elif not QAbstractButton.isChecked(self.settings_window.modscale) and ('-s' in arglist): arglist.remove('-s')
		except Exception: pass

		self.sel_bank = self.get_bank()

	def saveSettings(self):
		self.progset.setValue("sound/Autoplay", self.setAutoplay.isChecked())
		self.progset.setValue("sound/Looped", self.setLooped.isChecked())
		self.progset.setValue("sound/numCards", self.numCards.value())
		self.progset.setValue("sound/fourOps", self.fourOps.value())
		try: self.progset.setValue("sound/bank", self.settings_window.combo.currentIndex())
		except Exception: pass
		if len(self.recentList) >= 1: self.progset.setValue("file/recent", self.recentList[-self.MaxRecentFiles:])
		self.progset.setValue("file/MaxRecentFiles", self.MaxRecentFiles)
		#allkeys = self.progset.allKeys()
		#for key in allkeys:
		#	barf('DBG', str(key) + " " + str(self.progset.value(key)))
		
	def closeEvent(self, event):
		self.stop()
		#self.pkill()
		self.saveSettings()
		barf("DBG", "Quitting", True, False)
		
	def quit(self):
		self.stop()
		#self.pkill()
		self.saveSettings()
		barf("DBG", "Quitting", True, False)
		exit(0)

	def pkill(self):
		try: p.kill()
		except Exception: pass
		
	##############################################################
	##### Statusbar Functions ####################################
	##############################################################
	
	def clear(self):
		try: self.statusBar().removeWidget(self.playStatus)
		except Exception: pass
	
	@Slot(str)
	def update(self, status=''):
		self.clear()
		if status == "ready": text = "&nbsp;<B>Ready</b>"
		elif status == "play": text = "&nbsp;<B>Now Playing: </B>" + path.split(f.name)[1]
		elif status == "loop": text = "&nbsp;<B>Looping: </B>" + path.split(f.name)[1]
		elif status == "stop": text = "&nbsp;<B>Stopped: </B>" + path.split(f.name)[1]
		elif status == "pause": text = "&nbsp;<B>Paused: </B>" + path.split(f.name)[1]
		elif status == "loading": text = "&nbsp;<B>Loading.. </B>"
		elif status == "load": text = "&nbsp;<B>Loaded: </B>" + path.split(f.name)[1]
		elif status == "saving": text = "&nbsp;<B>Saving.. </B>"
		elif status == "saved": text = "&nbsp;<B>Saved as: </B>" + "saved/" + path.splitext(path.split(f.name)[1])[0] + ".wav"
		self.playStatus = QLabel(text)
		self.statusBar().addPermanentWidget(self.playStatus, 1)
		
	##############################################################
	####### Sound Functions ######################################
	##############################################################

	def play(self):
		global Paused, arglist
		if f != None and Paused == False:
			Paused = False
			self.stop()
			self.checkOpts()
			if not self.setLooped.isChecked(): arglist.append('-nl')
			arglist.append(str(self.progset.value("sound/bank", 1)))
			arglist.append(str(self.numCards.value()))
			arglist.append(str(self.fourOps.value()))
			for worker in self.threads:
				if worker.id == 1:
					worker.start()
		elif f != None and Paused == True:
			os.kill(p.pid, signal.SIGCONT)
			self.update("play")
			Paused = False

	def pause(self):
		global p, Paused
		if f != None:
			try:
				if Paused == False:
					os.kill(p.pid, signal.SIGSTOP)
					self.update("pause")
					Paused = True
				elif Paused == True:
					os.kill(p.pid, signal.SIGCONT)
					self.update("play")
					Paused = False
			except Exception: pass

	def stop(self):
		global Paused
		if f != None:
			Paused = False 
			self.pkill()
			self.killWorkers()
			self.update("stop")
				
	##############################################################
	##### Load/Save Functions ####################################
	##############################################################

	def load(self):
		global f
		lastdir = str(self.progset.value("file/lastdir", ""))
		fname, _ = QFileDialog.getOpenFileName(None, 'Open File', lastdir, "MIDI Audio File (*.mid *.MID)")
		if fname != "":
			f = file(fname, 'r')
			if not f.name in self.recentList: self.recentList.append(f.name)
			else:
				self.recentList.remove(f.name)
				self.recentList.append(f.name)
			self.progset.setValue("file/lastdir", path.split(f.name)[0])
			self.rfUpdate()
			self.update("load")
			self.pkill()
			if self.debug: barf("SAV", "Loaded %s" % path.split(f.name)[1], True, False)
			if self.setAutoplay.isChecked(): self.play()
			else: self.update("load")

	def load2(self, r_file=None):
		global f
		f = file(r_file, 'r')
		self.recentList.remove(f.name)
		self.recentList.append(f.name)
		self.rfUpdate()
		self.update("load")
		self.pkill()
		if self.debug: barf("SAV", "Loaded %s" % path.split(f.name)[1], True, False)
		if self.setAutoplay.isChecked(): self.play()
		else: self.update("load")
			
	def save(self):
		if f != None:
			self.stop()
			for worker in self.threads:
				if worker.id == 2:
					worker.start()