Esempio n. 1
0
class OptionsViewer(base.BaseWidget):

    OPTION_LIST_CLASS = optionlist.OptionList

    editModeChanged = Signal(bool)

    def __init__(self, option_object=None, settings=None, parent=None):

        self._option_object = None
        self._settings = settings
        self._edit_mode = False
        self._current_widgets = list()
        self._widget_to_copy = None

        super(OptionsViewer, self).__init__(parent)

        policy = self.sizePolicy()
        policy.setHorizontalPolicy(policy.Expanding)
        policy.setVerticalPolicy(policy.Expanding)
        self.main_layout.setContentsMargins(2, 2, 2, 2)
        self.main_layout.setSpacing(2)
        self.setSizePolicy(policy)

        if option_object:
            self.set_option_object(option_object=option_object)

    def ui(self):
        super(OptionsViewer, self).ui()

        edit_mode_icon = resources.icon('edit')
        move_up_icon = resources.icon('sort_up')
        move_down_icon = resources.icon('sort_down')
        remove_icon = resources.icon('delete')

        self._edit_widget = QWidget()
        top_layout = layouts.HorizontalLayout()
        top_layout.setContentsMargins(0, 0, 0, 0)
        top_layout.setSpacing(2)
        self._edit_widget.setLayout(top_layout)
        self.main_layout.addWidget(self._edit_widget)
        self._edit_mode_btn = buttons.BaseButton(parent=self)
        self._edit_mode_btn.setIcon(edit_mode_icon)
        self._edit_mode_btn.setCheckable(True)
        top_layout.addWidget(self._edit_mode_btn)

        horizontal_separator = QFrame()
        horizontal_separator.setFrameShape(QFrame.VLine)
        horizontal_separator.setFrameShadow(QFrame.Sunken)
        top_layout.addWidget(horizontal_separator)

        self._move_up_btn = buttons.BaseButton(parent=self)
        self.move_down_btn = buttons.BaseButton(parent=self)
        self.remove_btn = buttons.BaseButton(parent=self)
        self._move_up_btn.setIcon(move_up_icon)
        self.move_down_btn.setIcon(move_down_icon)
        self.remove_btn.setIcon(remove_icon)
        self._move_up_btn.setVisible(False)
        self.move_down_btn.setVisible(False)
        self.remove_btn.setVisible(False)
        top_layout.addWidget(self._move_up_btn)
        top_layout.addWidget(self.move_down_btn)
        top_layout.addWidget(self.remove_btn)
        top_layout.addStretch()
        self.main_layout.addWidget(dividers.Divider())

        self._scroll = QScrollArea()
        self._scroll.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        self._scroll.setFocusPolicy(Qt.NoFocus)
        self._scroll.setWidgetResizable(True)
        self.setFocusPolicy(Qt.NoFocus)
        self._options_list = self.OPTION_LIST_CLASS(parent=self)
        self._scroll.setWidget(self._options_list)

        self.main_layout.addWidget(self._scroll)

    def setup_signals(self):
        self._edit_mode_btn.toggled.connect(self._on_edit_mode)
        self._move_up_btn.clicked.connect(self._on_move_up)
        self.move_down_btn.clicked.connect(self._on_move_down)
        self.remove_btn.clicked.connect(self._on_remove)

    def settings(self):
        """
        Returns settings object
        :return: JSONSettings
        """

        return self._settings

    def set_settings(self, settings):
        """
        Sets save widget settings
        :param settings: JSONSettings
        """

        self._settings = settings

    def get_option_object(self):
        """
        Returns the option object linked to this widget
        :return: object
        """

        return self._option_object

    def set_option_object(self, option_object, force_update=True):
        """
        Sets option_object linked to this widget
        :param option_object: object
        :param force_update: bool
        """

        self._option_object = option_object
        self._options_list.set_option_object(option_object)
        if option_object and force_update:
            self.update_options()

    def get_option_type(self):
        """
        Returns option widget type
        :return: str
        """

        return self._option_type

    def is_edit_mode(self):
        """
        Returns whether current option is editable or not
        :return: bool
        """

        return self._edit_mode

    def set_edit_mode(self, flag):
        """
        Sets whether the current option is editable or not
        :param flag: bool
        """

        self._on_edit_mode(flag)

    def is_widget_to_copy(self):
        """
        Returns whether an option widget is being copied or not
        :return: bool
        """

        return self._widget_to_copy

    def set_widget_to_copy(self, widget_to_copy):
        """
        Sets widget that we want to copy
        :param QWidget
        """

        self._widget_to_copy = widget_to_copy

    def show_edit_widget(self):
        self._edit_widget.setVisible(True)
        self._edit_splitter.setVisible(True)

    def hide_edit_widget(self):
        self._edit_widget.setVisible(False)
        self._edit_splitter.setVisible(False)

    def update_options(self):
        """
        Function that updates the current options of the selected task
        """

        if not self._option_object:
            self._options_list.clear_widgets()
            LOGGER.warning(
                'Impossible to update options because option object is not defined!'
            )
            return

        self._options_list.update_options()

    def clear_options(self):
        """
        Clears all the options
        """

        self._options_list.clear_widgets()
        if self._option_object:
            self._option_object = None

    def has_options(self):
        """
        Checks if the current task has options or not
        :return: bool
        """

        if not self._option_object:
            LOGGER.warning(
                'Impossible to check options because option object is not defined!'
            )
            return

        return self._option_object.has_options()

    def _edit_activate(self, edit_value):
        """
        Internal function that updates widget states when edit button is pressed
        :param edit_value: bool
        """

        self._edit_mode = edit_value
        self.move_down_btn.setVisible(edit_value)
        self._move_up_btn.setVisible(edit_value)
        self.remove_btn.setVisible(edit_value)
        if not edit_value:
            self._options_list.clear_selection()
        self._options_list.set_edit(edit_value)

    def _on_edit_mode(self, edit_value):
        """
        Internal callback function that is called when the user presses edit mode button
        :param edit_value: bool
        """

        self._edit_activate(edit_value)
        self.editModeChanged.emit(edit_value)

    def _on_move_up(self):
        """
        Internal callback function that is called when the user pressed move up button
        Move selected items up in the list
        """

        widgets = self._current_widgets
        if not widgets:
            return

        widgets = self._options_list.sort_widgets(widgets,
                                                  widgets[0].get_parent())
        if not widgets:
            return
        for w in widgets:
            w.move_up()

    def _on_move_down(self):
        """
        Internal callback function that is called when the user pressed move down button
        Move selected items down in the list
        """

        widgets = self._current_widgets
        if not widgets:
            return

        widgets = self._options_list.sort_widgets(widgets,
                                                  widgets[0].get_parent())
        if not widgets:
            return
        for w in widgets:
            w.move_down()

    def _on_remove(self):
        """
        Internal callback function that is called when the user pressed remove button
        Remove selected options
        """

        widgets = self._current_widgets
        if not widgets:
            return

        widgets = self._options_list.sort_widgets(widgets,
                                                  widgets[0].get_parent())
        if not widgets:
            return
        for w in widgets:
            w.remove()
Esempio n. 2
0
class ExpandableLine(QWidget, object):
    def __init__(self, title='', animation_duration=300, parent=None):
        super(ExpandableLine, self).__init__(parent=parent)

        self._animation_duration = animation_duration

        base_layout = layouts.GridLayout(margins=(0, 0, 0, 0))
        base_layout.setVerticalSpacing(0)
        self.setLayout(base_layout)

        self.expand_btn = QToolButton()
        self.expand_btn.setText(str(title))
        self.expand_btn.setStyleSheet('QToolButton { border : none; }')
        self.expand_btn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.expand_btn.setArrowType(Qt.ArrowType.RightArrow)
        self.expand_btn.setCheckable(True)
        self.expand_btn.setChecked(True)

        header_line = QFrame()
        header_line.setFrameShape(QFrame.HLine)
        header_line.setFrameShadow(QFrame.Sunken)
        header_line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)

        self.content_area = QScrollArea()
        self.content_area.setStyleSheet('QScrollArea { border: none;}')
        self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)

        self.toggle_anim = QParallelAnimationGroup()
        self.toggle_anim.addAnimation(QPropertyAnimation(self, 'minimumHeight'))
        self.toggle_anim.addAnimation(QPropertyAnimation(self, 'maximumHeight'))
        self.toggle_anim.addAnimation(QPropertyAnimation(self.content_area, 'maximumHeight'))

        row = 0
        base_layout.addWidget(self.expand_btn, row, 0, 1, 1, Qt.AlignLeft)
        base_layout.addWidget(header_line, row, 2, 1, 1)
        row += 1
        base_layout.addWidget(self.content_area, row, 0, 1, 3)

        def expand_view(checked):
            arrow_type = Qt.DownArrow if checked else Qt.RightArrow
            direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
            self.expand_btn.setArrowType(arrow_type)
            self.toggle_anim.setDirection(direction)
            self.toggle_anim.start()

        # === SIGNALS === #
        self.expand_btn.toggled.connect(expand_view)

        expand_view(True)

    def set_content_layout(self, content_layout):
        self.content_area.destroy()
        self.content_area.setLayout(content_layout)
        collapsed_height = self.sizeHint().height() - self.content_area.maximumHeight()
        content_height = content_layout.sizeHint().height() + 300
        for i in range(self.toggle_anim.animationCount() - 1):
            expand_anim = self.toggle_anim.animationAt(i)
            expand_anim.setDuration(self._animation_duration)
            expand_anim.setStartValue(collapsed_height)
            expand_anim.setEndValue(collapsed_height + content_height)
        content_anim = self.toggle_anim.animationAt(self.toggle_anim.animationCount() - 1)
        content_anim.setDuration(self._animation_duration)
        content_anim.setStartValue(0)
        content_anim.setEndValue(content_height)
Esempio n. 3
0
class PreferencesWidget(base.BaseWidget, object):

    closed = Signal(bool, dict)

    def __init__(self, settings=None, parent=None):
        self._settings = settings
        super(PreferencesWidget, self).__init__(parent=parent)

        self._indexes = dict()
        self._category_buttons = dict()
        self._settings = settings

        self._try_create_defaults()

    def ui(self):
        super(PreferencesWidget, self).ui()

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self._splitter = QSplitter()
        self._splitter.setOrientation(Qt.Horizontal)
        self._splitter.setSizePolicy(QSizePolicy.Preferred,
                                     QSizePolicy.Expanding)
        self._scroll_area = QScrollArea()
        self._scroll_area.setWidgetResizable(True)
        self._scroll_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        # self._scroll_area.setMinimumWidth(200)
        self._scroll_area_widget_contents = QWidget()
        # self._scroll_area_widget_contents.setGeometry(QRect(0, 0, 480, 595))
        self._scroll_area_layout = layouts.VerticalLayout(spacing=2,
                                                          margins=(1, 1, 1, 1))
        self._scroll_area_layout.setAlignment(Qt.AlignTop)
        self._scroll_area_widget_contents.setLayout(self._scroll_area_layout)
        self._categories_layout = layouts.VerticalLayout()
        self._stack = stack.SlidingStackedWidget()
        self._stack.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._stack.set_vertical_mode()
        self._buttons_layout = layouts.HorizontalLayout(spacing=1,
                                                        margins=(0, 0, 0, 0))
        self._save_prefs_close_btn = buttons.BaseButton(
            'Save and Close', icon=resources.icon('save'), parent=self)
        self._close_btn = buttons.BaseButton('Close',
                                             icon=resources.icon('cancel'),
                                             parent=self)

        self._buttons_layout.addStretch()
        self._buttons_layout.addWidget(self._save_prefs_close_btn)
        self._buttons_layout.addWidget(self._close_btn)
        self._scroll_area_layout.addLayout(self._categories_layout)
        self._scroll_area.setWidget(self._scroll_area_widget_contents)
        self._splitter.addWidget(self._scroll_area)
        self._splitter.addWidget(self._stack)
        self._splitter.setSizes([150, 450])

        self.main_layout.addWidget(self._splitter)
        self.main_layout.addWidget(dividers.Divider(parent=self))
        self.main_layout.addLayout(self._buttons_layout)

    def setup_signals(self):
        self._save_prefs_close_btn.clicked.connect(
            self._on_save_and_close_prefs)
        self._close_btn.clicked.connect(self._on_close)

    def showEvent(self, event):
        settings = self.settings()
        if not settings:
            return

        groups = settings.childGroups()
        for name, index_widget in self._indexes.items():
            index, widget = index_widget
            settings.beginGroup(name)
            if name not in groups:
                widget.init_defaults(settings)
            widget.show_widget(settings)
            settings.endGroup()

    def settings(self):
        return self._settings

    def set_settings(self, settings):
        if not settings:
            return
        self._settings = settings
        self._try_create_defaults()

    def add_category(self, name, widget):
        category_button = CategoryButton(text=name, parent=self)
        self._categories_layout.insertWidget(
            self._categories_layout.count() - 2, category_button)
        widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        index = self._stack.addWidget(widget)
        self._indexes[name] = (index, widget)
        self._category_buttons[index] = category_button
        category_button.clicked.connect(lambda checked=False, idx=index: self.
                                        _on_switch_category_content(idx))
        widget.init_defaults(settings=self.settings())
        self.closed.connect(widget._on_reset)

    def select_by_name(self, name):
        if name not in self._indexes:
            return
        index = self._indexes[name][0]
        self._stack.setCurrentIndex(index)
        self._category_buttons[index].setChecked(True)

    def _try_create_defaults(self):
        settings = self.settings()
        if not settings:
            return

        groups = settings.childGroups()
        for name, index_widget in self._indexes.items():
            index, widget = index_widget
            init_defaults = False
            if name not in groups:
                init_defaults = True
            settings.beginGroup(name)
            if init_defaults:
                widget.init_defaults(settings)
            settings.endGroup()
        settings.sync()

    def _on_switch_category_content(self, index):
        self._stack.slide_in_index(index)
        self._category_buttons[index].toggle()

    def _on_save_prefs(self):
        settings = self.settings()
        if not settings:
            return

        stored_data = dict()

        for name, index_widget in self._indexes.items():
            index, widget = index_widget
            settings.beginGroup(name)
            data = widget.serialize(settings)
            if data:
                stored_data[name] = data
            settings.endGroup()
        settings.sync()

        return stored_data

    def _on_save_and_close_prefs(self):
        stored_data = self._on_save_prefs()
        self.closed.emit(True, stored_data)

    def _on_close(self):
        self.closed.emit(False, None)