Exemple #1
0
            def func_wrapper(plugin, workspace, *args, **kwargs):
                """
                Wrapper function that, when called, causes the plugin to be
                loaded into a specific workspace.
                """

                if workspace is None:
                    return

                parent = workspace.main_tool_bar
                action = QAction(parent)
                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None and isinstance(location, str):
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                if isinstance(location, int):
                    parent.insertAction(parent.actions()[location], action)
                else:
                    parent.addAction(action)

                action.triggered.connect(lambda: func(plugin, *args, **kwargs))
Exemple #2
0
def create_action(parent,
                  text,
                  on_triggered=None,
                  shortcut=None,
                  shortcut_context=None,
                  icon_name=None):
    """Create a QAction based on the give properties

    :param parent: The parent object
    :param text: Text string to display
    :param on_triggered: An optional slot to call on the triggered signal
    :param shortcut: An optional shortcut
    :param shortcut_context: An optional context for the supplied shortcut.
    Only applies if a shortcut has been given
    :param icon_name: The name of the qt awesome uri for an icon.
    :return: A new QAction object
    """
    action = QAction(text, parent)
    if on_triggered is not None:
        action.triggered.connect(on_triggered)
    if shortcut is not None:
        action.setShortcut(shortcut)
        if shortcut_context is not None:
            action.setShortcutContext(shortcut_context)
    if icon_name is not None:
        action.setIcon(get_icon(icon_name))

    return action
Exemple #3
0
            def func_wrapper(plugin, workspace, *args, **kwargs):
                """
                Wrapper function that, when called, causes the plugin to be
                loaded into a specific workspace.
                """

                if workspace is None:
                    return

                if workspace.current_plot_window is None:
                    return

                parent = workspace.current_plot_window.tool_bar
                action = QAction(parent)

                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None and isinstance(location, str):
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                before_action = [x for x in parent.actions()
                                 if x.isSeparator()].pop(-2)
                parent.insertAction(before_action, action)
                action.triggered.connect(lambda: func(plugin, *args, **kwargs))
Exemple #4
0
            def func_wrapper(plugin, workspace, *args, **kwargs):
                """
                Wrapper function that, when called, causes the plugin to be
                loaded into a specific workspace.
                """

                if workspace is None:
                    return

                if workspace.current_plot_window is None:
                    return

                parent = workspace.current_plot_window.tool_bar
                action = QAction(parent)

                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None and isinstance(location, str):
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                before_action = [
                    x for x in parent.actions() if x.isSeparator()
                ].pop(-2)
                parent.insertAction(before_action, action)
                action.triggered.connect(lambda: func(plugin, *args, **kwargs))
Exemple #5
0
            def func_wrapper(plugin, workspace, *args, **kwargs):
                """
                Wrapper function that, when called, causes the plugin to be
                loaded into a specific workspace.
                """

                if workspace is None:
                    return

                parent = workspace.main_tool_bar
                action = QAction(parent)
                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None and isinstance(location, str):
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                if isinstance(location, int):
                    parent.insertAction(parent.actions()[location], action)
                else:
                    parent.addAction(action)

                action.triggered.connect(lambda: func(plugin, *args, **kwargs))
Exemple #6
0
    def _cfg_action(
        self,
        menu,
        title,
        setting,
        icon=None,
        shortcut=None
    ):

        action = QAction(title, self)
        if icon:
            action.setIcon(self._ide.theme.qicon(icon))
        if shortcut:
            action.setShortcut(shortcut)
            action.setToolTip(
                u'{} ({})'.format(title.replace(u'&', u''), shortcut)
            )
        
        def change_setting(value):
            self._ide.extension_manager.fire(
                'setting_changed',
                setting=setting,
                value=value
            )
            
        action.triggered.connect(change_setting)
        action.setCheckable(True)
        action.setChecked(cfg[setting])
        action.setPriority(QAction.HighPriority)
        menu.addAction(action)
        self._cfg_actions[setting] = action
        return action
Exemple #7
0
def create_action(parent, text, shortcut=None, icon=None, tip=None,
                  toggled=None, triggered=None, data=None, menurole=None,
                  context=Qt.WindowShortcut):
    """Create a QAction"""
    action = QAction(text, parent)
    if triggered is not None:
        action.triggered.connect(triggered)
    if toggled is not None:
        action.toggled.connect(toggled)
        action.setCheckable(True)
    if icon is not None:
        if is_text_string(icon):
            icon = get_icon(icon)
        action.setIcon(icon)
    if shortcut is not None:
        action.setShortcut(shortcut)
    if tip is not None:
        action.setToolTip(tip)
        action.setStatusTip(tip)
    if data is not None:
        action.setData(to_qvariant(data))
    if menurole is not None:
        action.setMenuRole(menurole)
    #TODO: Hard-code all shortcuts and choose context=Qt.WidgetShortcut
    # (this will avoid calling shortcuts from another dockwidget
    #  since the context thing doesn't work quite well with these widgets)
    action.setShortcutContext(context)
    return action
def create_action(parent,
                  text,
                  shortcut=None,
                  icon=None,
                  tip=None,
                  toggled=None,
                  triggered=None,
                  data=None,
                  menurole=None,
                  context=Qt.WindowShortcut):
    """Create a QAction."""
    action = QAction(text, parent)
    if triggered is not None:
        action.triggered.connect(triggered)
    if toggled is not None:
        action.toggled.connect(toggled)
        action.setCheckable(True)
    if icon is not None:
        action.setIcon(icon)
    if shortcut is not None:
        action.setShortcut(shortcut)
    if tip is not None:
        action.setToolTip(tip)
        action.setStatusTip(tip)
    if data is not None:
        action.setData(to_qvariant(data))
    if menurole is not None:
        action.setMenuRole(menurole)
    # TODO: Hard-code all shortcuts and choose context=Qt.WidgetShortcut
    # (this will avoid calling shortcuts from another dockwidget
    #  since the context thing doesn't work quite well with these widgets)
    action.setShortcutContext(context)
    return action
    def __init__(self, env):
        super().__init__()

        self._env = env
        self._extra_menu_actions = []
        self._extra_toolbar_actions = []

        self.update_title()

        main_menu = self.menuBar()
        self.main_menu = main_menu
        project_menu = main_menu.addMenu("&Project")

        toolbar = self.addToolBar("Top")
        self.toolbar = toolbar

        new_action = QAction("&New", self)
        new_action.setShortcut("Ctrl+N")
        new_action.setStatusTip("Create a new empty project")
        new_action.triggered.connect(lambda: env.new())
        project_menu.addAction(new_action)

        open_action = QAction("&Open...", self)
        open_action.setShortcut("Ctrl+O")
        open_action.setStatusTip("Open an existing project")
        open_action.triggered.connect(lambda: env.open())
        project_menu.addAction(open_action)

        save_action = QAction("&Save", self)
        self.save_action = save_action
        save_action.setShortcut("Ctrl+S")
        save_action.setIcon(QIcon.fromTheme("document-save"))
        #save_action.setIcon(self.style().standardIcon(
        #    self.style().SP_DialogSaveButton))
        save_action.setStatusTip("Save project")
        save_action.setEnabled(False)
        save_action.triggered.connect(lambda: env.save())
        project_menu.addAction(save_action)
        toolbar.addAction(save_action)

        save_as_action = QAction("Save &As...", self)
        save_as_action.setStatusTip("Save project under a new name")
        save_as_action.triggered.connect(lambda: env.save_as())
        project_menu.addAction(save_as_action)

        quit_action = QAction("&Quit", self)
        quit_action.setShortcut("Ctrl+Q")
        quit_action.setStatusTip("Quit Hildegard")
        quit_action.triggered.connect(self.handle_quit)
        project_menu.addAction(quit_action)

        self.tabs = QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(
            lambda index: env.close(self.tabs.widget(index).entity, quit=True))
        self.tabs.currentChanged.connect(self._handle_switch_to_tab)
        self.setCentralWidget(self.tabs)

        self.statusBar()
Exemple #10
0
        def _set_rf_menu(self, sec):
            menu = LEVEL2M('RF', self)
            menu.setObjectName(sec.upper() + 'App')

            status = QAction('Main', menu)
            status.setIcon(qta.icon('mdi.waves'))
            self.connect_newprocess(
                status, 'sirius-hla-' + sec.lower() + '-rf-control.py')
            menu.addAction(status)
            return menu
Exemple #11
0
class Main(QMainWindow):
    def __init__(self, tracker: Tracker) -> None:
        super().__init__()
        self.qttracker = QtTracker(tracker)
        self.bg_thread = QThread(self)
        self.qttracker.moveToThread(self.bg_thread)
        self.bg_thread.start()
        self.qttracker.start_recording()

        self.setCentralWidget(Controls(self.qttracker))
        toolbar = QToolBar()
        self.addToolBar(toolbar)
        toolbar.setMovable(False)
        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.new_action = QAction("New", self)
        self.new_action.setToolTip("Create a new file for tracking.")
        icon = self.style().standardIcon(QStyle.SP_FileIcon)
        self.new_action.setIcon(icon)
        self.new_action.triggered.connect(self.new_db)
        toolbar.addAction(self.new_action)

        self.load_action = QAction("Load", self)
        self.load_action.setToolTip("Load a existing file for tracking.")
        icon = self.style().standardIcon(QStyle.SP_DialogOpenButton)
        self.load_action.setIcon(icon)
        self.load_action.triggered.connect(self.load_db)
        toolbar.addAction(self.load_action)

    @Slot()
    def load_db(self):
        fname, ftype = QFileDialog.getOpenFileName(
            self,
            "Tracking files",
            str(Path.home()),
            "CamTrack Files (*.camtrack)",
            options=QFileDialog.DontUseNativeDialog)
        if fname != "":
            self.qttracker.tracker.open_db(fname)

    @Slot()
    def new_db(self):
        fname, ftype = QFileDialog.getSaveFileName(
            self,
            "New file",
            str(Path.home()),
            "CamTrack Files (*.camtrack)",
            options=QFileDialog.DontUseNativeDialog)
        if fname != 0:
            if (p := Path(fname).with_suffix('.camtrack')).exists():
                p.unlink()
            self.qttracker.tracker.open_db(fname + '.camtrack')
Exemple #12
0
def create_action(parent,
                  text,
                  shortcut=None,
                  icon=None,
                  tip=None,
                  toggled=None,
                  triggered=None,
                  data=None,
                  menurole=None,
                  context=Qt.WindowShortcut):
    """Create a QAction"""
    action = QAction(text, parent)
    if triggered is not None:
        action.triggered.connect(triggered)
    if toggled is not None:
        action.toggled.connect(toggled)
        action.setCheckable(True)
    if icon is not None:
        if is_text_string(icon):
            icon = get_icon(icon)
        action.setIcon(icon)
    if tip is not None:
        action.setToolTip(tip)
        action.setStatusTip(tip)
    if data is not None:
        action.setData(to_qvariant(data))
    if menurole is not None:
        action.setMenuRole(menurole)

    # Workround for Mac because setting context=Qt.WidgetShortcut
    # there doesn't have any effect
    if sys.platform == 'darwin':
        action._shown_shortcut = None
        if context == Qt.WidgetShortcut:
            if shortcut is not None:
                action._shown_shortcut = shortcut
            else:
                # This is going to be filled by
                # main.register_shortcut
                action._shown_shortcut = 'missing'
        else:
            if shortcut is not None:
                action.setShortcut(shortcut)
            action.setShortcutContext(context)
    else:
        if shortcut is not None:
            action.setShortcut(shortcut)
        action.setShortcutContext(context)

    return action
Exemple #13
0
 def add_menu_to(self, button_name: str,
                 action_texts: List[str],
                 action_commands: List['Callable'],
                 action_icon: QIcon = None) -> Optional[QMenu]:
     button = self.get_control_widget(button_name)
     if button is not None:
         menu = QMenu(self)
         for text, cmd in zip(action_texts, action_commands):
             a = QAction(text=text, parent=menu)
             if action_icon is not None:
                 a.setIcon(action_icon)
             menu.addAction(a)
             a.triggered.connect(cmd)
         button.setMenu(menu)
         return menu
     return None
Exemple #14
0
    def __init__(self, entity, env):
        d = Diagram_Item(entity)
        d.modified_callback = self.set_modified
        super().__init__(d)
        self.modified_callback = env.set_modified
        self.entity = entity

        show_ports_action = QAction("Connection Ports", self)
        self._show_ports_action = show_ports_action
        show_ports_action.setStatusTip("Show connection ports when hovering")
        show_ports_action.setCheckable(True)
        show_ports_action.setChecked(False)
        show_ports_action.setIcon(QIcon.fromTheme("edit-find"))
        show_ports_action.triggered.connect(
            lambda x: d.set_show_connection_ports_on_hover(x))
        self.view_menu.addAction(show_ports_action)
        self.tools.append(show_ports_action)
Exemple #15
0
            def func_wrapper(plugin, workspace, *args, **kwargs):
                if workspace is None:
                    return

                parent = workspace.main_tool_bar
                action = QAction(parent)
                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None:
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                parent.addAction(action)
                action.triggered.connect(lambda: func(plugin, *args, **kwargs))
Exemple #16
0
    def append_menu(self, button_name: str, action_text: str, action_command: 'Callable',
                    action_icon: QIcon = None) -> 'QAction':
        button: 'QToolButton' = self.get_control_widget(button_name)
        action = None
        if button is not None:
            menu = button.menu()
            if menu is None:
                menu = self.add_menu_to(button_name, [action_text], [action_command], action_icon=action_icon)
                return menu.actions()[0]
            else:
                action = QAction(text=action_text, parent=menu)
                if action_icon is not None:
                    action.setIcon(action_icon)
                menu.addAction(action)
                action.triggered.connect(action_command)

        return action
Exemple #17
0
def create_action(parent,
                  text,
                  icon=None,
                  triggered=None,
                  shortcut=None,
                  statustip=None):
    """Create a QAction"""
    action = QAction(text, parent)
    if triggered is not None:
        action.triggered.connect(triggered)
    if icon is not None:
        action.setIcon(icon)
    if shortcut is not None:
        action.setShortcut(shortcut)
    if statustip is not None:
        action.setStatusTip(statustip)
    # action.setShortcutContext(Qt.WidgetShortcut)
    return action
Exemple #18
0
def create_action(parent, text, shortcut=None, icon=None, tip=None,
                  toggled=None, triggered=None, data=None, menurole=None,
                  context=Qt.WindowShortcut):
    """Create a QAction"""
    action = QAction(text, parent)
    if triggered is not None:
        action.triggered.connect(triggered)
    if toggled is not None:
        action.toggled.connect(toggled)
        action.setCheckable(True)
    if icon is not None:
        if is_text_string(icon):
            icon = get_icon(icon)
        action.setIcon(icon)
    if tip is not None:
        action.setToolTip(tip)
        action.setStatusTip(tip)
    if data is not None:
        action.setData(to_qvariant(data))
    if menurole is not None:
        action.setMenuRole(menurole)

    # Workround for Mac because setting context=Qt.WidgetShortcut
    # there doesn't have any effect
    if sys.platform == 'darwin':
        action._shown_shortcut = None
        if context == Qt.WidgetShortcut:
            if shortcut is not None:
                action._shown_shortcut = shortcut
            else:
                # This is going to be filled by
                # main.register_shortcut
                action._shown_shortcut = 'missing'
        else:
            if shortcut is not None:
                action.setShortcut(shortcut)
            action.setShortcutContext(context)
    else:
        if shortcut is not None:
            action.setShortcut(shortcut)
        action.setShortcutContext(context)

    return action
Exemple #19
0
            def func_wrapper(*args, **kwargs):
                app = QApplication.instance()

                if app.current_workspace is None:
                    return

                parent = app.current_workspace.main_tool_bar
                action = QAction(parent)
                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None:
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                parent.addAction(action)
                action.triggered.connect(lambda: func(*args, **kwargs))
Exemple #20
0
class SpyderAction(QAction):
    """Spyder QAction class wrapper to handle cross platform patches."""
    def __init__(self, *args, **kwargs):
        """Spyder QAction class wrapper to handle cross platform patches."""
        super(SpyderAction, self).__init__(*args, **kwargs)
        self._action_no_icon = None

        if sys.platform == 'darwin':
            self._action_no_icon = QAction(*args, **kwargs)
            self._action_no_icon.setIcon(QIcon())
            self._action_no_icon.triggered.connect(self.triggered)
            self._action_no_icon.toggled.connect(self.toggled)
            self._action_no_icon.changed.connect(self.changed)
            self._action_no_icon.hovered.connect(self.hovered)
        else:
            self._action_no_icon = self

    def __getattribute__(self, name):
        """Intercept method calls and apply to both actions, except signals."""
        attr = super(SpyderAction, self).__getattribute__(name)

        if hasattr(attr, '__call__') and name not in [
                'triggered', 'toggled', 'changed', 'hovered'
        ]:

            def newfunc(*args, **kwargs):
                result = attr(*args, **kwargs)
                if name not in ['setIcon']:
                    action_no_icon = self.__dict__['_action_no_icon']
                    attr_no_icon = super(QAction,
                                         action_no_icon).__getattribute__(name)
                    attr_no_icon(*args, **kwargs)
                return result

            return newfunc
        else:
            return attr

    @property
    def no_icon_action(self):
        """Return the action without an Icon."""
        return self._action_no_icon
Exemple #21
0
def makeAction(parent,
               descr,
               menutext,
               slot,
               icon=None,
               key=None,
               checkable=False):
    a = QAction(parent)
    a.setText(menutext)
    a.setStatusTip(descr)
    a.setToolTip(textwrap.fill(descr, 25))
    if slot:
        a.triggered.connect(slot)
    if icon:
        a.setIcon(getIcon(icon))
    if key:
        a.setShortcut(QKeySequence(key))
    if checkable:
        a.setCheckable(True)
    return a
Exemple #22
0
    def _action(self,
                title,
                icon,
                shortcut,
                target,
                checkable=False,
                checked=False):

        action = QAction(title, self)
        if icon:
            action.setIcon(self._ide.theme.qicon(icon))
        if shortcut:
            action.setShortcut(shortcut)
            action.setToolTip(u'{} ({})'.format(title.replace(u'&', u''),
                                                shortcut))
        action.triggered.connect(target)
        if checkable:
            action.setCheckable(True)
            action.setChecked(checked)
        action.setPriority(QAction.HighPriority)
        return action
Exemple #23
0
class SpyderAction(QAction):
    """Spyder QAction class wrapper to handle cross platform patches."""

    def __init__(self, *args, **kwargs):
        """Spyder QAction class wrapper to handle cross platform patches."""
        super(SpyderAction, self).__init__(*args, **kwargs)
        self._action_no_icon = None

        if sys.platform == 'darwin':
            self._action_no_icon = QAction(*args, **kwargs)
            self._action_no_icon.setIcon(QIcon())
            self._action_no_icon.triggered.connect(self.triggered)
            self._action_no_icon.toggled.connect(self.toggled)
            self._action_no_icon.changed.connect(self.changed)
            self._action_no_icon.hovered.connect(self.hovered)
        else:
            self._action_no_icon = self

    def __getattribute__(self, name):
        """Intercept method calls and apply to both actions, except signals."""
        attr = super(SpyderAction, self).__getattribute__(name)

        if hasattr(attr, '__call__') and name not in ['triggered', 'toggled',
                                                      'changed', 'hovered']:
            def newfunc(*args, **kwargs):
                result = attr(*args, **kwargs)
                if name not in ['setIcon']:
                    action_no_icon = self.__dict__['_action_no_icon']
                    attr_no_icon = super(QAction,
                                         action_no_icon).__getattribute__(name)
                    attr_no_icon(*args, **kwargs)
                return result
            return newfunc
        else:
            return attr

    @property
    def no_icon_action(self):
        """Return the action without an Icon."""
        return self._action_no_icon
Exemple #24
0
    def addMenuItem(self,
                    menu,
                    text,
                    triggered,
                    checkcall=None,
                    enabled=True,
                    statusTip=None,
                    icon=None,
                    enablecall=None):

        menuTrace = getMenuTrace(menu)
        menuTrace.append(text)
        catMenyShortCuts = self.qapp.menuCallShortCuts.get(self.category, {})
        keySequence = catMenyShortCuts.get(relax_menu_trace(menuTrace), None)

        # if not keySequence is None:
        # Note that the \t will place the keySequence in a nice second column
        # Like a real shortcut
        # text = f'{text}\t[{keySequence}]'

        action = QAction(text, self, enabled=enabled, statusTip=statusTip)
        #action = TriggerlessShortcutAction(text, self, enabled=enabled, statusTip=statusTip)
        action.triggered.connect(triggered)

        if not keySequence is None:
            action.setShortcut(QtGui.QKeySequence(keySequence))
            #Disable the shortcut,
            #it is handled by the qapp.panelsDialog window
            #Shortcuts are send to the correct selected panel
            action.setShortcutContext(Qt.WidgetShortcut)

        if isinstance(icon, str):
            icon = QtGui.QIcon(str(respath / 'icons' / 'px16' / icon))

        if not icon is None:
            action.setIcon(icon)

        menu.addAction(action, checkcall=checkcall, enablecall=enablecall)
        return action
Exemple #25
0
def create_action(
    parent,
    title,
    triggered=None,
    toggled=None,
    shortcut=None,
    icon=None,
    tip=None,
    checkable=None,
    context=Qt.WindowShortcut,
    enabled=None,
):
    """
    Create a new QAction
    """
    action = QAction(title, parent)
    if triggered:
        if checkable:
            action.triggered.connect(triggered)
        else:
            action.triggered.connect(lambda checked=False: triggered())
    if checkable is not None:
        # Action may be checkable even if the toggled signal is not connected
        action.setCheckable(checkable)
    if toggled:
        action.toggled.connect(toggled)
        action.setCheckable(True)
    if icon is not None:
        assert isinstance(icon, QIcon)
        action.setIcon(icon)
    if shortcut is not None:
        action.setShortcut(shortcut)
    if tip is not None:
        action.setToolTip(tip)
        action.setStatusTip(tip)
    if enabled is not None:
        action.setEnabled(enabled)
    action.setShortcutContext(context)
    return action
Exemple #26
0
            def func_wrapper(*args, **kwargs):
                app = QApplication.instance()

                if app.current_workspace is None:
                    return

                parent = app.current_workspace.current_plot_window.tool_bar
                action = QAction(parent)

                action.setText(name)

                if icon is not None:
                    action.setIcon(icon)

                if location is not None:
                    for level in location.split('/'):
                        parent = self.get_action(parent, level)

                before_action = [
                    x for x in parent.actions() if x.isSeparator()
                ].pop()
                parent.insertAction(before_action, action)
                action.triggered.connect(lambda: func(*args, **kwargs))
Exemple #27
0
    def setAddRemoveColumnMenu(self, columns):
        """
        Fill the "add/remove column" menu. This function is triggered each time
        the menu is displayed to display a correct icon depending on the status
        of the column (hidden or not).

        Args:
            columns (list(str)): list of column titles
        """
        if self.menuAddRemoveColumn.receivers(QMenu.triggered):
            self.menuAddRemoveColumn.triggered.disconnect()
        self.menuAddRemoveColumn.clear()
        hidden = self.table.getHiddenColumns()
        for c in columns:
            action = QAction(c, self.menuAddRemoveColumn)
            if c in hidden:
                action.setIcon(icons.get_icon("mdi.close"))
            else:
                action.setIcon(icons.get_icon("mdi.check"))
            self.menuAddRemoveColumn.addAction(action)

        self.menuAddRemoveColumn.triggered.connect(
            lambda action: self.table.toggleColumnVisibility(action.text()))
Exemple #28
0
def create_action(parent, text, on_triggered=None, shortcut=None,
                  shortcut_context=None, icon_name=None, shortcut_visible_in_context_menu=None):
    """Create a QAction based on the give properties

    :param parent: The parent object
    :param text: Text string to display
    :param on_triggered: An optional slot to call on the triggered signal
    :param shortcut: An optional shortcut
    :param shortcut_context: An optional context for the supplied shortcut.
    Only applies if a shortcut has been given
    :param icon_name: The name of the qt awesome uri for an icon.
    :param shortcut_visible_in_context_menu: Qt 5.10 decided that all QMenus that are NOT inside a QMenuBar
                                             are context menus, and are styled as such. By default keyboard shortcuts
                                             are NOT shown on context menus. Set this to True to show them.
    :return: A new QAction object
    """
    from ...icons import get_icon  # noqa
    action = QAction(text, parent)
    if on_triggered is not None:
        action.triggered.connect(on_triggered)
    if shortcut is not None:
        if isinstance(shortcut, tuple) or isinstance(shortcut, list):
            qshortcuts = [QKeySequence(s) for s in shortcut]
            action.setShortcuts(qshortcuts)
        else:
            action.setShortcut(shortcut)

        if shortcut_context is not None:
            action.setShortcutContext(shortcut_context)
    if icon_name is not None:
        action.setIcon(get_icon(icon_name))

    # shortcuts in context menus option is only available after Qt 5.10
    if hasattr(action, 'setShortcutVisibleInContextMenu') and shortcut_visible_in_context_menu:
        action.setShortcutVisibleInContextMenu(shortcut_visible_in_context_menu)

    return action
Exemple #29
0
 def _create_action(self,
                    text,
                    slot=None,
                    shortcut=None,
                    icon=None,
                    tip=None,
                    checkable=False,
                    checked=False):
     """Convenience function to create actions"""
     action = QAction(text, self)
     if icon is not None:
         action.setIcon(QIcon(icon))
     if shortcut is not None:
         action.setShortcut(shortcut)
     if tip is not None:
         action.setToolTip(tip)
         action.setStatusTip(tip)
     if slot is not None:
         action.triggered.connect(slot)
     if checkable:
         action.setCheckable(True)
         if checked:
             action.setChecked(True)
     return action
Exemple #30
0
def create_action(parent, text, on_triggered=None, shortcut=None,
                  shortcut_context=None, icon_name=None):
    """Create a QAction based on the give properties

    :param parent: The parent object
    :param text: Text string to display
    :param on_triggered: An optional slot to call on the triggered signal
    :param shortcut: An optional shortcut
    :param shortcut_context: An optional context for the supplied shortcut.
    Only applies if a shortcut has been given
    :param icon_name: The name of the qt awesome uri for an icon.
    :return: A new QAction object
    """
    action = QAction(text, parent)
    if on_triggered is not None:
        action.triggered.connect(on_triggered)
    if shortcut is not None:
        action.setShortcut(shortcut)
        if shortcut_context is not None:
            action.setShortcutContext(shortcut_context)
    if icon_name is not None:
        action.setIcon(get_icon(icon_name))

    return action
Exemple #31
0
        def _set_optics_menu(self, sec):
            optics = LEVEL2M('Optics', self)
            optics.setObjectName(sec.upper() + 'App')

            if sec in {'tb', 'ts'}:
                launcher = QAction('Main', optics)
                self.connect_newprocess(launcher,
                                        'sirius-hla-' + sec + '-ap-control.py')
                optics.addAction(launcher)
            elif sec == 'bo':
                injbo = QAction('InjBO', optics)
                self.connect_newprocess(injbo,
                                        'sirius-hla-bo-ap-injcontrol.py')
                optics.addAction(injbo)

            sofb = QAction('SOFB', optics)
            sofb.setIcon(qta.icon('fa5s.hammer'))
            self.connect_newprocess(sofb, 'sirius-hla-' + sec + '-ap-sofb.py')
            optics.addAction(sofb)

            if sec in {'tb', 'ts'}:
                PosAng = QAction('PosAng', optics)
                self.connect_newprocess(PosAng,
                                        'sirius-hla-' + sec + '-ap-posang.py')
                optics.addAction(PosAng)
            if 'tb' in sec:
                Emittance = QAction('Emittance Meas', optics)
                self.connect_newprocess(Emittance,
                                        'sirius-hla-tb-ap-emittance.py')
                optics.addAction(Emittance)
            if sec in {'bo', 'si'}:
                TuneCorr = QAction('Tune Correction', optics)
                icon = qta.icon('mdi.pulse',
                                'mdi.hammer',
                                options=[
                                    dict(scale_factor=1.3, offset=(0.0, 0.05)),
                                    dict(scale_factor=0.72,
                                         offset=(-0.1, -0.3),
                                         hflip=True)
                                ])
                TuneCorr.setIcon(icon)
                self.connect_newprocess(
                    TuneCorr, 'sirius-hla-' + sec + '-ap-tunecorr.py')
                optics.addAction(TuneCorr)

                ChromCorr = QAction('Chromaticity Correction', optics)
                self.connect_newprocess(
                    ChromCorr, 'sirius-hla-' + sec + '-ap-chromcorr.py')
                optics.addAction(ChromCorr)

                trajfit = QAction('Trajectory Fitting', optics)
                self.connect_newprocess(trajfit,
                                        'sirius-hla-' + sec + '-ap-trajfit.py')
                optics.addAction(trajfit)
            if 'si' in sec:
                CurrLT = QAction('Current and Lifetime', optics)
                self.connect_newprocess(CurrLT, 'sirius-hla-si-ap-currlt.py')
                optics.addAction(CurrLT)

                coupm = QAction('Coupling Meas', optics)
                self.connect_newprocess(coupm, 'sirius-hla-si-ap-coupmeas.py')
                optics.addAction(coupm)
            if 'bo' in sec:
                ChargeMon = QAction('Charge Monitor', optics)
                self.connect_newprocess(ChargeMon,
                                        'sirius-hla-bo-ap-chargemon.py')
                optics.addAction(ChargeMon)

                ramp = QAction('Ramp', optics)
                ramp.setIcon(qta.icon('mdi.escalator', scale_factor=1.5))
                self.connect_newprocess(ramp, 'sirius-hla-bo-ap-ramp.py')
                optics.addAction(ramp)
            return optics
Exemple #32
0
        def _set_diagnostic_menu(self, sec):
            diag = LEVEL2M('DI', self)
            diag.setObjectName(sec.upper() + 'App')
            BPMs = self._set_bpm_menu(sec)
            act = QAction('BPMs', diag)
            act.setIcon(qta.icon('mdi.currency-sign'))
            act.setMenu(BPMs)
            diag.addAction(act)
            # diag.addMenu(BPMs)
            if sec in {'tb', 'ts'}:
                ICTs = QAction('ICTs', diag)
                self.connect_newprocess(ICTs,
                                        'sirius-hla-' + sec + '-di-icts.py')
                diag.addAction(ICTs)
            elif sec in {'bo', 'si'}:
                DCCT = QMenu('DCCTs', diag)
                DCCT.setObjectName(sec.upper() + 'App')
                DCCT.setIcon(qta.icon('mdi.current-dc'))
                for dev in get_dcct_list(sec.upper()):
                    act_dev = DCCT.addAction(dev)
                    self.connect_newprocess(act_dev,
                                            ['sirius-hla-as-di-dcct.py', dev])
                diag.addMenu(DCCT)
            if 'tb' in sec:
                Slits = QAction('Slits', diag)
                self.connect_newprocess(Slits, 'sirius-hla-tb-di-slits.py')
                diag.addAction(Slits)
            if sec in {'bo', 'si'}:
                Tune = QAction('Tune', diag)
                Tune.setIcon(qta.icon('mdi.pulse', scale_factor=1.3))
                self.connect_newprocess(Tune,
                                        'sirius-hla-' + sec + '-di-tune.py')
                diag.addAction(Tune)
                VLight = QAction('VLight', diag)
                self.connect_newprocess(VLight,
                                        'sirius-hla-' + sec + '-di-vlight.py')
                diag.addAction(VLight)
            if 'si' not in sec:
                Scrns = QMenu('Screens', diag)
                Scrns.setObjectName(sec.upper() + 'App')
                for dev in get_scrn_list(sec.upper()):
                    act_dev = Scrns.addAction(dev)
                    self.connect_newprocess(act_dev,
                                            ['sirius-hla-as-di-scrn.py', dev])
                diag.addMenu(Scrns)
            else:
                Scrap = QAction('Scrapers', diag)
                self.connect_newprocess(Scrap, 'sirius-hla-si-di-scraps.py')
                diag.addAction(Scrap)

                BbB = QMenu('BbB', diag)
                BbB.setObjectName(sec.upper() + 'App')

                AllBbB = BbB.addAction('All')
                self.connect_newprocess(
                    AllBbB, ['sirius-hla-si-di-bbb.py', '-dev', 'all'])

                for idc in ['Horizontal', 'Vertical', 'Longitudinal']:
                    dev_pref = 'SI-Glob:DI-BbBProc-' + idc[0]
                    act_dev = BbB.addAction(idc)
                    self.connect_newprocess(
                        act_dev, ['sirius-hla-si-di-bbb.py', '-dev', dev_pref])

                diag.addMenu(BbB)
            return diag
Exemple #33
0
class ObjectExplorer(QTreeView):
    nodevalue_changed = pyqtSignal(AbstractJsonItem)
    nodeproperty_changed = pyqtSignal(AbstractJsonItem)

    def __init__(self, rootnode: JsonNode, parent):
        super().__init__(parent)
        self.mainwindow = parent
        self.setModel(JsonDataModel(rootnode, self.mainwindow))
        self.model().dataChanged.connect(self.data_changed)
        self.setItemDelegate(MyItemDelegate())
        self.setDragDropMode(QTreeView.DragDrop)
        self.setDragEnabled(True)
        self.setAcceptDrops(True)
        self.setDropIndicatorShown(True)
        self.doubleClicked.connect(self.double_clicked)

        # context menu
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.show_contextmenu)

        # actions
        # properties action
        self.propertiesAction = QAction(self.tr("properties"), self)
        self.propertiesAction.setIcon(QIcon(pixmap("document_properties.png")))
        self.propertiesAction.triggered.connect(self.show_properties)

        # edit action
        self.editAction = QAction(self.tr("edit value"), self)
        self.editAction.setShortcut("F2")
        self.editAction.setIcon(QIcon(pixmap("edit.png")))
        self.editAction.triggered.connect(self.edit_value)

        # edit key action
        self.editkeyAction = QAction(self.tr("edit key"), self)
        self.editkeyAction.setIcon(QIcon(pixmap("kgpg_key1_kgpg.png")))
        self.editkeyAction.triggered.connect(self.edit_key)

        # insert item action
        self.insertitemAction = QAction(self.tr("insert item"), self)
        self.insertitemAction.setIcon(QIcon(pixmap("list_add.png")))
        self.insertitemAction.triggered.connect(self.insert_item)

        # insert node action
        self.insertnodeAction = QAction(self.tr("insert node"), self)
        self.insertnodeAction.setIcon(QIcon(pixmap("list_add.png")))
        self.insertnodeAction.triggered.connect(self.insert_node)

        # remove item action
        self.removeitemAction = QAction(self.tr("remove"), self)
        self.removeitemAction.setIcon(QIcon(pixmap("list_remove")))
        self.removeitemAction.triggered.connect(self.remove_item)

    def data_changed(self, topleft, bottomright, *args):
        node = topleft.internalPointer()
        if node is not None and isinstance(node, JsonItem):
            self.nodevalue_changed.emit(node)

    def double_clicked(self, *args, **kwargs):
        index = self.currentIndex()

        if not index.isValid():
            return

        column = self.model().columns[index.column()]
        if column.name == "value":
            self.edit_value()
        else:
            self.show_properties()

    def edit_key(self):
        index = self.currentIndex()
        if index.isValid():
            node = index.internalPointer()
            key, b = QInputDialog.getText(
                self, "Edit Json item", "Insert new key for item:",
                text=node.key
            )

            if not b:
                return

            node.key = key

            try:  # PyQt5
                self.model().dataChanged.emit(index, index, [Qt.DisplayRole])
            except TypeError:  # PyQt4, PySide
                self.model().dataChanged.emit(index, index)

    def edit_value(self):
        index = self.currentIndex()
        if not index.isValid():
            return

        i = self.model().index(index.row(), 2, index.parent())
        self.edit(i)

    def insert_item(self):
        index = self.currentIndex()

        if index.isValid():
            node = index.internalPointer()
        else:
            node = self.model().root

        key, b = QInputDialog.getText(
            self, "Insert Json item", "Insert key for new item:")

        if not b:
            return

        item = JsonItem(key)
        node.add(item)
        row = node.index(item)
        self.model().beginInsertRows(index, row, row)
        self.model().endInsertRows()

    def insert_node(self):
        index = self.currentIndex()
        parentnode = index.internalPointer() or self.model().root

        key, b = QInputDialog.getText(
            self, "Insert Json node", "Insert key for new node:")
        if not b:
            return
        node = JsonNode(key)
        parentnode.add(node)
        row = parentnode.index(node)
        self.model().beginInsertRows(index, row, row)
        self.model().endInsertRows()

    def mousePressEvent(self, event):
        index = self.indexAt(event.pos())
        if not index.isValid():
            self.setCurrentIndex(QModelIndex())
        super().mousePressEvent(event)

    def refresh(self):
        self.model().refresh()

    def remove_item(self):
        index = self.currentIndex()
        self.model().beginRemoveRows(index.parent(), index.row(), index.row())

        if index.isValid():
            node = index.internalPointer()
            if node.parent is not None:
                node.parent.remove(node.key)

        self.model().refresh()
        self.model().endRemoveRows()

    def show_contextmenu(self, pos: QPoint):
        menu = QMenu(self)
        index = self.currentIndex()
        node = index.internalPointer()

        # insert item and node
        menu.addAction(self.insertitemAction)
        menu.addAction(self.insertnodeAction)

        # edit key
        if isinstance(node, (JsonNode, JsonItem)):
            menu.addSeparator()
            menu.addAction(self.editkeyAction)
            if isinstance(node, JsonItem):
                menu.addAction(self.editAction)
                self.editAction.setEnabled(not node.readonly)

        # remove
        if isinstance(node, (JsonNode, JsonItem)):
            menu.addSeparator()
            menu.addAction(self.removeitemAction)

        # properties
        if isinstance(node, JsonItem):
            menu.addSeparator()
            menu.addAction(self.propertiesAction)
            menu.setDefaultAction(self.propertiesAction)

        menu.popup(self.viewport().mapToGlobal(pos), self.editAction)

    def show_properties(self):
        index = self.currentIndex()
        node = index.internalPointer()
        if not (index.isValid() and isinstance(node, JsonItem)):
            return

        dlg = ItemPropertyDialog(node, self.parent())
        if dlg.exec_() == QDialog.Accepted:
            self.nodeproperty_changed.emit(node)
Exemple #34
0
    def __init__(self, item):
        super().__init__()

        self._shown = False
        self.modified_callback = None

        scene = QGraphicsScene()
        self.scene = scene

        self.scene_item = item
        scene.addItem(item)

        layout = QBoxLayout(QBoxLayout.TopToBottom, self)

        scene_view = View(self)
        self.scene_view = scene_view
        scene_view.setScene(scene)
        scene_view.setMinimumSize(350, 350)
        scene_view.setRenderHint(QPainter.Antialiasing)
        layout.addWidget(scene_view)

        self.double_click_callback = None
        self.mouse_press_callback = None
        if hasattr(self.scene_item, "mouse_pressed_in"):
            self.mouse_press_callback = self.scene_item.mouse_pressed_in
        if hasattr(self.scene_item, "double_clicked_in_background"):
            self.double_click_callback = \
                self.scene_item.double_clicked_in_background
        if hasattr(self.scene_item, "mouse_moved_in_scene"):
            self.scene_view.mouse_move_callback = \
                self.scene_item.mouse_moved_in_scene

        self.menus = []
        view_menu = QMenu("&View")
        self.view_menu = view_menu
        self.menus.append(view_menu)
        export_menu = QMenu("&Export")
        self.menus.append(export_menu)

        self.tools = []

        fit_action = QAction("&Fit", self)
        fit_action.setShortcut("0")
        fit_action.setIcon(QIcon.fromTheme("zoom-fit-best"))
        fit_action.setStatusTip("Fit the entire scene to the viewport")
        fit_action.triggered.connect(self.scene_view.fit_all_in_view)
        view_menu.addAction(fit_action)
        self.tools.append(fit_action)

        reset_action = QAction("&Reset (1:1)", self)
        reset_action.setShortcut("9")
        reset_action.setIcon(QIcon.fromTheme("zoom-original"))
        reset_action.setStatusTip("Reset the view to 100% scale")
        reset_action.triggered.connect(self.scene_view.reset_scale)
        view_menu.addAction(reset_action)
        self.tools.append(reset_action)

        zoom_in_action = QAction("Zoom &In", self)
        zoom_in_action.setShortcuts(["+", "="])
        zoom_in_action.setStatusTip("Zoom in")
        zoom_in_action.triggered.connect(lambda: self.scene_view.zoom_in())
        view_menu.addAction(zoom_in_action)

        zoom_out_action = QAction("Zoom &Out", self)
        zoom_out_action.setShortcuts(["-", "_"])
        zoom_out_action.setStatusTip("Zoom out")
        zoom_out_action.triggered.connect(lambda: self.scene_view.zoom_out())
        view_menu.addAction(zoom_out_action)

        export_svg_action = QAction("As &SVG...", self)
        export_svg_action.setStatusTip("Export the current tab as an SVG file")
        export_svg_action.triggered.connect(lambda: export_as_svg(self.scene))
        export_menu.addAction(export_svg_action)

        export_png_action = QAction("As PN&G...", self)
        export_png_action.setStatusTip("Export the current tab as an PNG file")
        export_png_action.triggered.connect(lambda: export_as_png(self.scene))
        export_menu.addAction(export_png_action)

        export_pdf_action = QAction("As &PDF...", self)
        export_pdf_action.setStatusTip("Export the current tab as an PDF file")
        export_pdf_action.triggered.connect(lambda: export_as_pdf(self.scene))
        export_menu.addAction(export_pdf_action)

        export_svg_clip_action = QAction("To Clipboard as SVG", self)
        export_svg_clip_action.setStatusTip(
            "Export the current tab to the clipoard in SVG format")
        export_svg_clip_action.triggered.connect(
            lambda: export_to_clipboard_as_svg(self.scene))
        export_menu.addAction(export_svg_clip_action)

        export_image_clip_action = QAction("To &Clipboard as Image", self)
        export_image_clip_action.setStatusTip(
            "Export the current tab to the clipoard as an image")
        export_image_clip_action.triggered.connect(
            lambda: export_to_clipboard_as_image(self.scene))
        export_menu.addAction(export_image_clip_action)

        self.resize(800, 600)
class ActionCollection:
    def __init__(self, parent):
        # Tree Actions
        self.action_show = QAction('&Show', parent)
        self.action_show.setIcon(IconCollection.get('flash_on.svg'))

        self.action_hide = QAction('&Hide', parent)
        self.action_hide.setIcon(IconCollection.get('flash_off.svg'))

        self.action_delete = QAction('&Delete', parent)
        self.action_delete.setIcon(IconCollection.get('cancel.svg'))

        self.action_focus_camera = QAction('&Focus camera', parent)
        self.action_focus_camera.setIcon(IconCollection.get('collect.svg'))

        self.action_highlight = QAction('H&ighlight', parent)
        self.action_highlight.setIcon(IconCollection.get('idea.svg'))
        self.action_highlight.setCheckable(True)

        self.action_wireframe = QAction('&Wireframe', parent)
        self.action_wireframe.setIcon(IconCollection.get('grid.svg'))
        self.action_wireframe.setCheckable(True)

        self.action_properties = QAction('&Properties', parent)
        self.action_properties.setIcon(IconCollection.get('settings.svg'))

        self.action_setup_colors = QAction('Setup c&olors', parent)
        self.action_setup_colors.setIcon(IconCollection.get('picture.svg'))

        self.action_setup_multiple = QAction('Setup &multiple', parent)
        self.action_setup_multiple.setIcon(IconCollection.get('picture.svg'))

        self.action_export_element = QAction('&Export', parent)
        self.action_export_element.setIcon(IconCollection.get('export.svg'))

        # MainWindow Actions
        self.action_load_mesh = QAction('Load &mesh', parent)
        self.action_load_mesh.setIcon(IconCollection.get('area_chart.svg'))
        self.action_load_mesh.setShortcut('Ctrl+A')

        self.action_load_blocks = QAction('Load &blocks', parent)
        self.action_load_blocks.setIcon(IconCollection.get('data_sheet.svg'))
        self.action_load_blocks.setShortcut('Ctrl+E')

        self.action_load_points = QAction('Load &points', parent)
        self.action_load_points.setIcon(IconCollection.get('scatter_plot.svg'))
        self.action_load_points.setShortcut('Ctrl+P')

        self.action_load_lines = QAction('Load &lines', parent)
        self.action_load_lines.setIcon(IconCollection.get('line_chart.svg'))
        self.action_load_lines.setShortcut('Ctrl+L')

        self.action_load_tubes = QAction('Load &tubes', parent)
        self.action_load_tubes.setIcon(IconCollection.get('radar_plot.svg'))
        self.action_load_tubes.setShortcut('Ctrl+T')

        self.action_load_mesh_folder = QAction('Load m&esh folder', parent)
        self.action_load_mesh_folder.setIcon(
            IconCollection.get('area_chart.svg'))
        self.action_load_mesh_folder.setShortcut('Ctrl+Shift+A')

        self.action_load_blocks_folder = QAction('Load b&locks folder', parent)
        self.action_load_blocks_folder.setIcon(
            IconCollection.get('data_sheet.svg'))
        self.action_load_blocks_folder.setShortcut('Ctrl+Shift+E')

        self.action_load_points_folder = QAction('Load p&oints folder', parent)
        self.action_load_points_folder.setIcon(
            IconCollection.get('scatter_plot.svg'))
        self.action_load_points_folder.setShortcut('Ctrl+Shift+P')

        self.action_load_lines_folder = QAction('Load l&ines folder', parent)
        self.action_load_lines_folder.setIcon(
            IconCollection.get('line_chart.svg'))
        self.action_load_lines_folder.setShortcut('Ctrl+Shift+L')

        self.action_load_tubes_folder = QAction('Load t&ubes folder', parent)
        self.action_load_tubes_folder.setIcon(
            IconCollection.get('radar_plot.svg'))
        self.action_load_tubes_folder.setShortcut('Ctrl+Shift+T')

        self.action_quit = QAction('&Quit', parent)
        self.action_quit.setIcon(IconCollection.get('cancel.svg'))
        self.action_quit.setShortcut('Ctrl+Q')

        self.action_show_tree = QAction('Show &tree', parent)
        self.action_show_tree.setIcon(IconCollection.get('list.svg'))
        self.action_show_tree.setShortcut('Ctrl+W')

        self.action_help = QAction('&Help', parent)
        self.action_help.setIcon(IconCollection.get('document.svg'))
        self.action_help.setShortcut('F1')

        self.action_about = QAction('&About', parent)
        self.action_about.setIcon(IconCollection.get('about.svg'))
        self.action_about.setShortcut('?')

        self.action_animated = QAction('A&nimate movements', parent)
        self.action_animated.setIcon(IconCollection.get('film_reel.svg'))
        self.action_animated.setShortcut('Shift+N')
        self.action_animated.setCheckable(True)

        self.action_autofit = QAction('&Auto-fit to screen', parent)
        self.action_autofit.setIcon(IconCollection.get('globe.svg'))
        self.action_autofit.setShortcut('Shift+F')
        self.action_autofit.setCheckable(True)

        self.action_autorotate = QAction('Auto-&rotate on slice', parent)
        self.action_autorotate.setIcon(IconCollection.get('process.svg'))
        self.action_autorotate.setShortcut('Shift+R')
        self.action_autorotate.setCheckable(True)

        self.action_turbo_rendering = QAction('&Turbo rendering', parent)
        self.action_turbo_rendering.setIcon(
            IconCollection.get('sports_mode.svg'))
        self.action_turbo_rendering.setShortcut('Shift+T')
        self.action_turbo_rendering.setCheckable(True)

        self.action_normal_controller = QAction('&Normal controller', parent)
        self.action_normal_controller.setIcon(
            IconCollection.get('rotate_camera.svg'))
        self.action_normal_controller.setShortcut('Ctrl+N')

        self.action_measurement_controller = QAction('&Measure meshes', parent)
        self.action_measurement_controller.setIcon(
            IconCollection.get('ruler.svg'))
        self.action_measurement_controller.setShortcut('Ctrl+M')

        self.action_detection_controller = QAction('&Detect meshes/lines',
                                                   parent)
        self.action_detection_controller.setIcon(
            IconCollection.get('cursor.svg'))
        self.action_detection_controller.setShortcut('Ctrl+D')

        self.action_slice_meshes = QAction('&Slice meshes', parent)
        self.action_slice_meshes.setIcon(IconCollection.get('flash_on.svg'))
        self.action_slice_meshes.setShortcut('Ctrl+S')

        self.action_slice_blocks = QAction('Slice &blocks', parent)
        self.action_slice_blocks.setIcon(IconCollection.get('flash_on.svg'))
        self.action_slice_blocks.setShortcut('Ctrl+B')

        self.action_slice_points = QAction('Slice &points', parent)
        self.action_slice_points.setIcon(IconCollection.get('flash_on.svg'))
        self.action_slice_points.setShortcut('Ctrl+Shift+P')

        self.action_xsection = QAction('&Cross-section', parent)
        self.action_xsection.setIcon(IconCollection.get('flash_on.svg'))
        self.action_xsection.setShortcut('Ctrl+Shift+S')

        self.action_grid = QAction('&Grid settings', parent)
        self.action_grid.setIcon(IconCollection.get('grid.svg'))
        self.action_grid.setShortcut('Ctrl+G')

        self.action_viewer_properties = QAction('&Viewer properties', parent)
        self.action_viewer_properties.setIcon(
            IconCollection.get('compact_camera.svg'))
        self.action_viewer_properties.setShortcut('Ctrl+C')

        self.action_plan_view = QAction('&Plan view', parent)
        self.action_plan_view.setIcon(IconCollection.get('upload.svg'))
        self.action_plan_view.setShortcut('Ctrl+1')

        self.action_north_view = QAction('&North view', parent)
        self.action_north_view.setIcon(IconCollection.get('up.svg'))
        self.action_north_view.setShortcut('Ctrl+2')

        self.action_east_view = QAction('&East view', parent)
        self.action_east_view.setIcon(IconCollection.get('right.svg'))
        self.action_east_view.setShortcut('Ctrl+3')

        self.action_fit_to_screen = QAction('&Fit to screen', parent)
        self.action_fit_to_screen.setIcon(IconCollection.get('collect.svg'))
        self.action_fit_to_screen.setShortcut('Ctrl+F')

        self.action_perspective_projection = QAction('P&erspective projection',
                                                     parent)
        self.action_perspective_projection.setIcon(
            IconCollection.get('ruler.svg'))
        self.action_perspective_projection.setShortcut('Ctrl+4')

        self.action_orthographic_projection = QAction(
            'O&rthographic projection', parent)
        self.action_orthographic_projection.setIcon(
            IconCollection.get('ruler.svg'))
        self.action_orthographic_projection.setShortcut('Ctrl+5')

        self.action_take_screenshot = QAction('&Take screenshot', parent)
        self.action_take_screenshot.setIcon(IconCollection.get('webcam.svg'))
        self.action_take_screenshot.setShortcut('Shift+S')
Exemple #36
0
    def createMenus(self):
        self.layoutMenu = QtWidgets.QMenu()

        panDiaAct = QAction("Panels Dialog",
                            self,
                            triggered=self.qapp.showDialog)
        panDiaAct.setIcon(
            QIcon(
                str(respath / 'icons' / 'px16' /
                    'application_view_gallery.png')))
        self.layoutMenu.addAction(panDiaAct)
        self.newPanelMenu = NewPanelMenu(self, showIcon=True)
        self.layoutMenu.addMenu(self.newPanelMenu)

        self.panelMenu = ShowMenu(self, showIcon=True)
        self.layoutMenu.addMenu(self.panelMenu)
        self.layoutMenu.addMenu(WindowMenu(self, showIcon=True))

        def addWindowMenuItem(caption, function, icon=None):
            keySequence = self.qapp.menuCallShortCuts.get('window', {}).get(
                (relax_menu_text(caption), ), None)
            if not keySequence is None:
                caption = f'{caption}\t{keySequence}'
            if isinstance(icon, str):
                icon = QtGui.QIcon(str(respath / 'icons' / 'px16' / icon))
            if not icon is None:
                action = QAction(caption,
                                 self.windowMenu,
                                 triggered=function,
                                 icon=icon)
            else:
                action = QAction(caption, self.windowMenu, triggered=function)
            self.windowMenu.addAction(action)

        self.windowMenu = CheckMenu("&Layout Edit")
        self.windowMenu.setIcon(
            QtGui.QIcon(str(respath / 'icons' / 'px16' / 'layout_edit.png')))
        self.layoutMenu.addMenu(self.windowMenu)

        self.toolWinAction = QAction(self.winActionLabel(),
                                     self,
                                     triggered=self.asToolWindow)
        self.windowMenu.addAction(self.toolWinAction,
                                  checkcall=self.isToolWindow)

        addWindowMenuItem("Distribute", self.container.distribute,
                          'layouts_six_grid.png')
        addWindowMenuItem("Drop In",
                          lambda: self.qapp.panels.ezm.drop_in(self.container),
                          'layouts_body_select.png')
        addWindowMenuItem("Screenshot to Clipboard", self.screenShot,
                          'lcd_tv_image.png')
        addWindowMenuItem("Cycle Tag Level", self.cycle_tag_level)
        addWindowMenuItem("Full Screen", self.fullScreen,
                          'view_fullscreen_view.png')
        addWindowMenuItem("Hide/Show Menu && Statusbar",
                          self.toggleMenuStatusbar)
        addWindowMenuItem('Save Layout...',
                          self.qapp.panelsDialog.layoutMenu.saveLayout)

        self.layoutMenu.addSeparator()
        self.qapp.panelsDialog.layoutMenu.addLayoutActions(self.layoutMenu)
        self.layoutMenu.addSeparator()

        act = QAction("E&xit",
                      self,
                      shortcut=QKeySequence.Quit,
                      statusTip="Exit the application",
                      triggered=QApplication.instance().quit)
        act.setIcon(
            QtGui.QIcon(str(respath / 'icons' / 'px16' / 'door_out.png')))
        self.layoutMenu.addAction(act)

        self.panelsDialogBtn = QtWidgets.QToolButton(self)
        self.panelsDialogBtn.setIcon(
            QIcon(
                str(respath / 'icons' / 'px16' /
                    'application_view_gallery.png')))
        self.panelsDialogBtn.clicked.connect(self.qapp.showDialog)
        self.panelsDialogBtn.setMenu(self.layoutMenu)
        self.panelsDialogBtn.setPopupMode(
            QtWidgets.QToolButton.MenuButtonPopup)
        self.menuBar().setCornerWidget(self.panelsDialogBtn,
                                       corner=Qt.TopLeftCorner)

        self.cycleTabBtn = QtWidgets.QToolButton(self)
        self.cycleTabBtn.setIcon(
            QIcon(str(respath / 'icons' / 'px16' / 'layout_content.png')))
        self.cycleTabBtn.clicked.connect(self.cycle_tag_level)
        self.cycleTabBtn.setMenu(self.windowMenu)
        self.cycleTabBtn.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
        self.menuBar().setCornerWidget(self.cycleTabBtn,
                                       corner=Qt.TopRightCorner)
Exemple #37
0
class UiLinelistsWindow(object):

    # this code was taken as-is from the Designer.
    # Cleaning it up sounds like a lower priority
    # task for now.
    def setupUi(self, MainWindow, title):
        MainWindow.setWindowTitle(title)
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(600, 850)
        MainWindow.setMinimumSize(QSize(300, 350))
        self.centralWidget = QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.gridLayout = QGridLayout(self.centralWidget)
        self.gridLayout.setContentsMargins(11, 11, 11, 11)
        self.gridLayout.setSpacing(6)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout_5 = QHBoxLayout()
        self.horizontalLayout_5.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_5.setSpacing(6)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.lines_selected_label = QLabel(self.centralWidget)
        self.lines_selected_label.setObjectName("lines_selected_label")
        self.horizontalLayout_5.addWidget(self.lines_selected_label)
        self.label = QLabel(self.centralWidget)
        self.label.setObjectName("label")
        self.horizontalLayout_5.addWidget(self.label)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem)
        self.draw_button = QPushButton(self.centralWidget)
        self.draw_button.setObjectName("draw_button")
        self.horizontalLayout_5.addWidget(self.draw_button)
        self.erase_button = QPushButton(self.centralWidget)
        self.erase_button.setObjectName("erase_button")
        self.horizontalLayout_5.addWidget(self.erase_button)
        self.dismiss_button = QPushButton(self.centralWidget)
        self.dismiss_button.setObjectName("dismiss_button")
        self.horizontalLayout_5.addWidget(self.dismiss_button)
        self.gridLayout.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
        self.verticalLayout_11 = QVBoxLayout()
        self.verticalLayout_11.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout_11.setSpacing(6)
        self.verticalLayout_11.setObjectName("verticalLayout_11")
        self.tabWidget = QTabWidget(self.centralWidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tabWidget.setTabsClosable(True)
        self.verticalLayout_11.addWidget(self.tabWidget)
        self.gridLayout.addLayout(self.verticalLayout_11, 0, 0, 1, 1)
        self.horizontalLayout_7 = QHBoxLayout()
        self.horizontalLayout_7.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_7.setSpacing(6)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.gridLayout.addLayout(self.horizontalLayout_7, 2, 0, 2, 1)
        MainWindow.setCentralWidget(self.centralWidget)

        # self.menuBar = QMenuBar(MainWindow)
        # self.menuBar.setGeometry(QRect(0, 0, 767, 22))
        # self.menuBar.setObjectName("menuBar")
        #
        # self.menuFile = QMenu(self.menuBar)
        # self.menuFile.setObjectName("menuFile")
        #
        # MainWindow.setMenuBar(self.menuBar)

        self.mainToolBar = QToolBar(MainWindow)
        self.mainToolBar.setMovable(False)
        self.mainToolBar.setFloatable(False)
        self.mainToolBar.setObjectName("mainToolBar")
        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)

        # self.statusBar = QStatusBar(MainWindow)
        # self.statusBar.setObjectName("statusBar")
        # MainWindow.setStatusBar(self.statusBar)

        self.actionOpen = QAction(MainWindow)
        icon = QIcon(os.path.join(ICON_PATH, "Open Folder-48.png"))
        self.actionOpen.setIcon(icon)
        self.actionOpen.setObjectName("actionOpen")

        self.actionExport = QAction(MainWindow)
        icon = QIcon(os.path.join(ICON_PATH, "Export-48.png"))
        self.actionExport.setIcon(icon)
        self.actionExport.setObjectName("actionExport")

        self.line_list_selector = QComboBox()
        self.line_list_selector.setToolTip(
            "Select line list from internal library")

        self.actionExit = QAction(MainWindow)
        self.actionExit.setObjectName("actionExit")
        self.actionRemove = QAction(MainWindow)
        self.actionRemove.setObjectName("actionRemove")
        self.actionChange_Color = QAction(MainWindow)
        self.actionChange_Color.setObjectName("actionChange_Color")
        # self.menuFile.addAction(self.actionOpen)
        # self.menuFile.addSeparator()
        # self.menuFile.addAction(self.actionExit)
        # self.menuBar.addAction(self.menuFile.menuAction())
        self.mainToolBar.addAction(self.actionOpen)
        self.mainToolBar.addAction(self.actionExport)
        self.mainToolBar.addSeparator()
        self.mainToolBar.addWidget(self.line_list_selector)
        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        self.lines_selected_label.setText(_translate("MainWindow", "0"))
        self.lines_selected_label.setToolTip(
            "Total number of lines selected in all sets.")
        self.label.setText(_translate("MainWindow", "lines selected"))
        self.label.setToolTip("Total number of lines selected in all sets.")
        self.draw_button.setText(_translate("MainWindow", "Draw"))
        self.draw_button.setToolTip(
            "Plot markers for all selected lines in all sets.")
        self.erase_button.setText(_translate("MainWindow", "Erase"))
        self.erase_button.setToolTip("Erase all markers")
        self.dismiss_button.setText(_translate("MainWindow", "Dismiss"))
        self.dismiss_button.setToolTip("Dismiss this window")
        # self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionOpen.setText(_translate("MainWindow", "Open"))
        self.actionExport.setText(
            _translate("MainWindow", "Export plotted lines"))
        self.actionExit.setText(_translate("MainWindow", "Exit"))
        self.actionRemove.setText(_translate("MainWindow", "Remove"))
        self.actionRemove.setToolTip(
            _translate("MainWindow", "Removes the selected layer"))
        self.actionChange_Color.setText(
            _translate("MainWindow", "Change Color"))
        self.actionChange_Color.setToolTip(
            _translate("MainWindow", "Change the line color selected layer"))
Exemple #38
0
class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.recording_enabled = False
        self.serial = serial.Serial()
        self.rootnode = JsonNode('')
        self._connected = False
        self._dirty = False
        self._filename = None

        # settings
        self.settings = QSettingsManager()
        set_default_settings(self.settings)

        # Controller Settings
        self.settingsDialog = None

        # object explorer
        self.objectexplorer = ObjectExplorer(self.rootnode, self)
        self.objectexplorer.nodevalue_changed.connect(self.send_serialdata)
        self.objectexplorer.nodeproperty_changed.connect(self.set_dirty)
        self.objectexplorerDockWidget = QDockWidget(self.tr("object explorer"),
                                                    self)
        self.objectexplorerDockWidget.setObjectName(
            "objectexplorer_dockwidget")
        self.objectexplorerDockWidget.setWidget(self.objectexplorer)

        # plot widget
        self.plot = PlotWidget(self.rootnode, self.settings, self)

        # plot settings
        self.plotsettings = PlotSettingsWidget(self.settings, self.plot, self)
        self.plotsettingsDockWidget = QDockWidget(self.tr("plot settings"),
                                                  self)
        self.plotsettingsDockWidget.setObjectName("plotsettings_dockwidget")
        self.plotsettingsDockWidget.setWidget(self.plotsettings)

        # log widget
        self.loggingWidget = LoggingWidget(self)
        self.loggingDockWidget = QDockWidget(self.tr("logger"), self)
        self.loggingDockWidget.setObjectName("logging_dockwidget")
        self.loggingDockWidget.setWidget(self.loggingWidget)

        # record widget
        self.recordWidget = RecordWidget(self.rootnode, self)
        self.recordDockWidget = QDockWidget(self.tr("data recording"), self)
        self.recordDockWidget.setObjectName("record_dockwidget")
        self.recordDockWidget.setWidget(self.recordWidget)

        # actions and menus
        self._init_actions()
        self._init_menus()

        # statusbar
        statusbar = self.statusBar()
        statusbar.setVisible(True)
        self.connectionstateLabel = QLabel(self.tr("Not connected"))
        statusbar.addPermanentWidget(self.connectionstateLabel)
        statusbar.showMessage(self.tr("Ready"))

        # layout
        self.setCentralWidget(self.plot)
        self.addDockWidget(Qt.LeftDockWidgetArea,
                           self.objectexplorerDockWidget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.plotsettingsDockWidget)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.loggingDockWidget)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.recordDockWidget)

        self.load_settings()

    def _init_actions(self):
        # Serial Dialog
        self.serialdlgAction = QAction(self.tr("Serial Settings..."), self)
        self.serialdlgAction.setShortcut("F6")
        self.serialdlgAction.setIcon(QIcon(pixmap("configure.png")))
        self.serialdlgAction.triggered.connect(self.show_serialdlg)

        # Connect
        self.connectAction = QAction(self.tr("Connect"), self)
        self.connectAction.setShortcut("F5")
        self.connectAction.setIcon(QIcon(pixmap("network-connect-3.png")))
        self.connectAction.triggered.connect(self.toggle_connect)

        # Quit
        self.quitAction = QAction(self.tr("Quit"), self)
        self.quitAction.setShortcut("Alt+F4")
        self.quitAction.setIcon(QIcon(pixmap("window-close-3.png")))
        self.quitAction.triggered.connect(self.close)

        # Save Config as
        self.saveasAction = QAction(self.tr("Save as..."), self)
        self.saveasAction.setShortcut("Ctrl+Shift+S")
        self.saveasAction.setIcon(QIcon(pixmap("document-save-as-5.png")))
        self.saveasAction.triggered.connect(self.show_savecfg_dlg)

        # Save file
        self.saveAction = QAction(self.tr("Save"), self)
        self.saveAction.setShortcut("Ctrl+S")
        self.saveAction.setIcon(QIcon(pixmap("document-save-5.png")))
        self.saveAction.triggered.connect(self.save_file)

        # Load file
        self.loadAction = QAction(self.tr("Open..."), self)
        self.loadAction.setShortcut("Ctrl+O")
        self.loadAction.setIcon(QIcon(pixmap("document-open-7.png")))
        self.loadAction.triggered.connect(self.show_opencfg_dlg)

        # New
        self.newAction = QAction(self.tr("New"), self)
        self.newAction.setShortcut("Ctrl+N")
        self.newAction.setIcon(QIcon(pixmap("document-new-6.png")))
        self.newAction.triggered.connect(self.new)

        # start recording
        self.startrecordingAction = QAction(self.tr("Start recording"), self)
        self.startrecordingAction.setShortcut("F9")
        self.startrecordingAction.setIcon(QIcon(pixmap("media-record-6.png")))
        self.startrecordingAction.triggered.connect(self.start_recording)

        # stop recording
        self.stoprecordingAction = QAction(self.tr("Stop recording"), self)
        self.stoprecordingAction.setShortcut("F10")
        self.stoprecordingAction.setIcon(QIcon(pixmap("media-playback-stop-8.png")))
        self.stoprecordingAction.setEnabled(False)
        self.stoprecordingAction.triggered.connect(self.stop_recording)

        # clear record
        self.clearrecordAction = QAction(self.tr("Clear"), self)
        self.clearrecordAction.setIcon(QIcon(pixmap("editclear.png")))
        self.clearrecordAction.triggered.connect(self.clear_record)

        # export record
        self.exportcsvAction = QAction(self.tr("Export to csv..."), self)
        self.exportcsvAction.setIcon(QIcon(pixmap("text_csv.png")))
        self.exportcsvAction.triggered.connect(self.export_csv)

        # show record settings
        self.recordsettingsAction = QAction(self.tr("Settings..."), self)
        self.recordsettingsAction.setIcon(QIcon(pixmap("configure.png")))
        self.recordsettingsAction.triggered.connect(self.show_recordsettings)

        # Info
        self.infoAction = QAction(self.tr("Info"), self)
        self.infoAction.setShortcut("F1")
        self.infoAction.triggered.connect(self.show_info)

    def _init_menus(self):
        # file menu
        self.fileMenu = self.menuBar().addMenu(self.tr("File"))
        self.fileMenu.addAction(self.newAction)
        self.fileMenu.addAction(self.loadAction)
        self.fileMenu.addAction(self.saveAction)
        self.fileMenu.addAction(self.saveasAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.connectAction)
        self.fileMenu.addAction(self.serialdlgAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAction)

        # view menu
        self.viewMenu = self.menuBar().addMenu(self.tr("View"))
        self.viewMenu.addAction(
            self.objectexplorerDockWidget.toggleViewAction())
        self.viewMenu.addAction(self.plotsettingsDockWidget.toggleViewAction())
        self.viewMenu.addAction(self.loggingDockWidget.toggleViewAction())
        self.viewMenu.addAction(self.recordDockWidget.toggleViewAction())

        # record menu
        self.recordMenu = self.menuBar().addMenu(self.tr("Record"))
        self.recordMenu.addAction(self.startrecordingAction)
        self.recordMenu.addAction(self.stoprecordingAction)
        self.recordMenu.addAction(self.exportcsvAction)
        self.recordMenu.addSeparator()
        self.recordMenu.addAction(self.clearrecordAction)
        self.recordMenu.addSeparator()
        self.recordMenu.addAction(self.recordsettingsAction)

        # info menu
        self.menuBar().addAction(self.infoAction)

    def show_info(self):
        QMessageBox.about(
            self, QApplication.applicationName(),
            "%s %s\n"
            "Copyright (c) by %s" %
            (
                QCoreApplication.applicationName(),
                QCoreApplication.applicationVersion(),
                QCoreApplication.organizationName(),
            )
        )

    def load_file(self, filename):
        old_filename = self.filename if self.filename != filename else None
        self.filename = filename

        try:
            with open(filename, 'rb') as f:
                try:
                    self.objectexplorer.model().beginResetModel()
                    self.rootnode.load(bytearray_to_utf8(f.read()))
                    self.objectexplorer.model().endResetModel()
                except ValueError as e:
                    critical(self, "File '%s' is not a valid config file."
                             % filename)
                    logger.error(str(e))
                    if old_filename is not None:
                        self.load_file(old_filename)
                    else:
                        self.filename = None

        except FileNotFoundError as e:
            logger.error(str(e))
            self.filename = None

        self.objectexplorer.refresh()

    def load_settings(self):
        settings = QSettings()

        # window geometry
        try:
            self.restoreGeometry(settings.value(GEOMETRY_SETTING))
        except:
            logger.debug("error restoring window geometry")

        # window state
        try:
            self.restoreState(settings.value(WINDOWSTATE_SETTING))
        except:
            logger.debug("error restoring window state")

        # filename
        self.filename = settings.value(FILENAME_SETTING)
        if self.filename is not None:
            self.load_file(self.filename)

    def save_settings(self):
        settings = QSettings()
        settings.setValue(WINDOWSTATE_SETTING, self.saveState())
        settings.setValue(GEOMETRY_SETTING, self.saveGeometry())
        settings.setValue(FILENAME_SETTING, self.filename)

    def closeEvent(self, event):
        if self.dirty:
            res = QMessageBox.question(
                self,
                QCoreApplication.applicationName(),
                self.tr("Save changes to file '%s'?" %
                        self.filename
                        if self.filename is not None else "unknown"),
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel
            )
            if res == QMessageBox.Cancel:
                event.ignore()
                return
            elif res == QMessageBox.Yes:
                self.save_file()

        self.save_settings()

        try:
            self.worker.quit()
        except AttributeError:
            pass

        try:
            self.serial.close()
        except (SerialException, AttributeError):
            pass

    def new(self):
        self.objectexplorer.model().beginResetModel()
        self.rootnode.clear()
        self.objectexplorer.model().endResetModel()

    def send_reset(self):
        jsonstring = json.dumps({"resetpid": 1})
        self.serial.write(bytearray(jsonstring, 'utf-8'))

    def receive_serialdata(self, time, data):
        self.loggingWidget.log_input(data)

        try:
            self.rootnode.from_json(data)
        except ValueError as e:
            logger.error(str(e))

        # refresh widgets
        self.objectexplorer.refresh()
        self.plot.refresh(time)
        if self.recording_enabled:
            self.recordWidget.add_data(time, self.rootnode)

    def send_serialdata(self, node):
        if isinstance(node, JsonItem):
            if self.serial.isOpen():
                s = node.to_json()
                self.serial.write(utf8_to_bytearray(s + '\n'))
                self.loggingWidget.log_output(s.strip())

    def show_serialdlg(self):
        dlg = SerialDialog(self.settings, self)
        dlg.exec_()

    def toggle_connect(self):
        if self.serial.isOpen():
            self.disconnect()
        else:
            self.connect()

    def connect(self):
        # Load port setting
        port = self.settings.get(PORT_SETTING)
        baudrate = self.settings.get(BAUDRATE_SETTING)

        # If no port has been selected before show serial settings dialog
        if port is None:
            if self.show_serialdlg() == QDialog.Rejected:
                return
            port = self.settings.get(PORT_SETTING)
            baudrate = self.settings.get(BAUDRATE_SETTING)

        # Serial connection
        try:
            self.serial.port = port
            self.serial.baudrate = baudrate
            self.serial.open()
        except ValueError:
            QMessageBox.critical(
                self, QCoreApplication.applicationName(),
                self.tr("Serial parameters e.g. baudrate, databits are out "
                        "of range.")
            )
        except SerialException:
            QMessageBox.critical(
                self, QCoreApplication.applicationName(),
                self.tr("The device '%s' can not be found or can not be "
                        "configured." % port)
            )
        else:
            self.worker = SerialWorker(self.serial, self)
            self.worker.data_received.connect(self.receive_serialdata)
            self.worker.start()

            self.connectAction.setText(self.tr("Disconnect"))
            self.connectAction.setIcon(QIcon(pixmap("network-disconnect-3.png")))
            self.serialdlgAction.setEnabled(False)
            self.connectionstateLabel.setText(
                self.tr("Connected to %s") % port)
            self._connected = True
            self.objectexplorer.refresh()

    def disconnect(self):
        self.worker.quit()
        self.serial.close()
        self.connectAction.setText(self.tr("Connect"))
        self.connectAction.setIcon(QIcon(pixmap("network-connect-3.png")))
        self.serialdlgAction.setEnabled(True)
        self.connectionstateLabel.setText(self.tr("Not connected"))
        self._connected = False
        self.objectexplorer.refresh()

    def show_savecfg_dlg(self):
        filename, _ = QFileDialog.getSaveFileName(
            self, self.tr("Save configuration file..."),
            directory=os.path.expanduser("~"),
            filter="Json file (*.json)"
        )

        if filename:
            self.filename = filename
            self.save_file()

    def save_file(self):
        if self.filename is not None:
            config_string = self.rootnode.dump()
            with open(self.filename, 'w') as f:
                f.write(config_string)
            self.dirty = False
        else:
            self.show_savecfg_dlg()

    def show_opencfg_dlg(self):
        # show file dialog
        filename, _ = QFileDialog.getOpenFileName(
            self, self.tr("Open configuration file..."),
            directory=os.path.expanduser("~"),
            filter=self.tr("Json file (*.json);;All files (*.*)")
        )

        # load config file
        if filename:
            self.load_file(filename)

    def refresh_window_title(self):
        s = "%s %s" % (QCoreApplication.applicationName(),
                       QCoreApplication.applicationVersion())
        if self.filename is not None:
            s += " - " + self.filename
        if self.dirty:
            s += "*"
        self.setWindowTitle(s)

    def start_recording(self):
        self.recording_enabled = True
        self.startrecordingAction.setEnabled(False)
        self.stoprecordingAction.setEnabled(True)

    def stop_recording(self):
        self.recording_enabled = False
        self.startrecordingAction.setEnabled(True)
        self.stoprecordingAction.setEnabled(False)

    def export_csv(self):
        filename, _ = QFileDialog.getSaveFileName(
            self, QCoreApplication.applicationName(),
            filter="CSV files(*.csv);;All files (*.*)"
        )

        if filename == "":
            return

        # get current dataframe and export to csv
        df = self.recordWidget.dataframe
        decimal = self.settings.get(DECIMAL_SETTING)
        df = df.applymap(lambda x: str(x).replace(".", decimal))
        df.to_csv(
            filename, index_label="time",
            sep=self.settings.get(SEPARATOR_SETTING)
        )

    def clear_record(self):
        self.recordWidget.clear()

    def show_recordsettings(self):
        dlg = CSVSettingsDialog(self)
        dlg.exec_()

    # filename property
    @property
    def filename(self):
        return self._filename

    @filename.setter
    def filename(self, value=""):
        self._filename = value
        self.refresh_window_title()

    # dirty property
    @property
    def dirty(self):
        return self._dirty

    @dirty.setter
    def dirty(self, value):
        self._dirty = value
        self.refresh_window_title()

    def set_dirty(self):
        self.dirty = True

    # connected property
    @property
    def connected(self):
        return self._connected