예제 #1
0
class AppendDialog(QDialog):
    def __init__(self, parent, compatibles, title="Append data"):
        super().__init__(parent)
        self.setWindowTitle(title)

        vbox = QVBoxLayout(self)
        grid = QGridLayout()

        grid.addWidget(QLabel("Source"), 0, 0, Qt.AlignCenter)
        grid.addWidget(QLabel("Destination"), 0, 2, Qt.AlignCenter)

        source = QListWidget(self)
        source.setAcceptDrops(True)
        source.setDragEnabled(True)
        source.setSelectionMode(QAbstractItemView.ExtendedSelection)
        source.setDefaultDropAction(Qt.DropAction.MoveAction)
        source.insertItems(0, [d["name"] for d in compatibles])
        grid.addWidget(source, 1, 0)

        grid.addWidget(QLabel("->"), 1, 1, Qt.AlignHCenter)

        self.destination = QListWidget(self)
        self.destination.setAcceptDrops(True)
        self.destination.setDragEnabled(True)
        self.destination.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.destination.setDefaultDropAction(Qt.DropAction.MoveAction)
        grid.addWidget(self.destination, 1, 2)
        vbox.addLayout(grid)

        self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
        self.buttonbox.accepted.connect(self.accept)
        self.buttonbox.rejected.connect(self.reject)

        vbox.addWidget(self.buttonbox)
        vbox.setSizeConstraint(QVBoxLayout.SetFixedSize)
        self.destination.model().rowsInserted.connect(self.toggle_buttons)
        self.destination.model().rowsRemoved.connect(self.toggle_buttons)
        self.toggle_buttons()

    @property
    def names(self):
        names = []
        for it in range(self.destination.count()):
            names.append(self.destination.item(it).text())
        return names

    @Slot()
    def toggle_buttons(self):
        """Toggle OK button.
        """
        if self.destination.count() > 0:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(True)
        else:
            self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(False)
예제 #2
0
class Q7ComboBox(QComboBox):
    def __init__(self, arg):
        QComboBox.__init__(self, arg)
        self.actorlist = QListWidget()
        self.setModel(self.actorlist.model())
        self.setView(self.actorlist)
        self.view().installEventFilter(self)
        self.parent = None

    def setParent(self, parent):
        self.parent = parent

    def eventFilter(self, o, e):
        if e.type() == QEvent.KeyPress:
            # kmod = e.modifiers()
            kval = e.key()
            if kval in [Qt.Key_Z]:
                path = self.actorlist.currentItem().text()
                actor = self.parent.findPathObject(path)
                self.parent.changeCurrentActor([path, actor])
                return True
            if kval in [Qt.Key_H]:
                path = self.actorlist.currentItem().text()
                actor = self.parent.findPathObject(path)
                self.parent.changeCurrentActor([path, actor])
                self.parent.hideActor(None)
                return True
        return QComboBox.eventFilter(self, o, e)

    def keyPressEvent(self, event):
        kmod = event.modifiers()
        kval = event.key()
        print(kmod, kval)
예제 #3
0
class FindOptions(QWidget):
    """Find widget with options"""
    REGEX_INVALID = "background-color:rgb(255, 175, 90);"
    find = Signal()
    stop = Signal()
    redirect_stdio = Signal(bool)

    def __init__(self, parent, search_text, search_text_regexp, search_path,
                 exclude, exclude_idx, exclude_regexp,
                 supported_encodings, in_python_path, more_options,
                 case_sensitive, external_path_history):
        QWidget.__init__(self, parent)

        if search_path is None:
            search_path = getcwd()

        self.path = ''
        self.project_path = None
        self.file_path = None
        self.external_path = None
        self.external_path_history = external_path_history

        if not isinstance(search_text, (list, tuple)):
            search_text = [search_text]
        if not isinstance(search_path, (list, tuple)):
            search_path = [search_path]
        if not isinstance(exclude, (list, tuple)):
            exclude = [exclude]
        if not isinstance(external_path_history, (list, tuple)):
            external_path_history = [external_path_history]

        self.supported_encodings = supported_encodings

        # Layout 1
        hlayout1 = QHBoxLayout()
        self.search_text = PatternComboBox(self, search_text,
                                           _("Search pattern"))
        self.edit_regexp = create_toolbutton(self,
                                             icon=ima.icon('advanced'),
                                             tip=_('Regular expression'))
        self.case_button = create_toolbutton(self,
                                             icon=get_icon("upper_lower.png"),
                                             tip=_("Case Sensitive"))
        self.case_button.setCheckable(True)
        self.case_button.setChecked(case_sensitive)
        self.edit_regexp.setCheckable(True)
        self.edit_regexp.setChecked(search_text_regexp)
        self.more_widgets = ()
        self.more_options = create_toolbutton(self,
                                              toggled=self.toggle_more_options)
        self.more_options.setCheckable(True)
        self.more_options.setChecked(more_options)

        self.ok_button = create_toolbutton(self, text=_("Search"),
                                           icon=ima.icon('find'),
                                           triggered=lambda: self.find.emit(),
                                           tip=_("Start search"),
                                           text_beside_icon=True)
        self.ok_button.clicked.connect(self.update_combos)
        self.stop_button = create_toolbutton(self, text=_("Stop"),
                                             icon=ima.icon('editclear'),
                                             triggered=lambda:
                                             self.stop.emit(),
                                             tip=_("Stop search"),
                                             text_beside_icon=True)
        self.stop_button.setEnabled(False)
        for widget in [self.search_text, self.edit_regexp, self.case_button,
                       self.ok_button, self.stop_button, self.more_options]:
            hlayout1.addWidget(widget)

        # Layout 2
        hlayout2 = QHBoxLayout()
        self.exclude_pattern = PatternComboBox(self, exclude,
                                               _("Excluded filenames pattern"))
        if exclude_idx is not None and exclude_idx >= 0 \
           and exclude_idx < self.exclude_pattern.count():
            self.exclude_pattern.setCurrentIndex(exclude_idx)
        self.exclude_regexp = create_toolbutton(self,
                                                icon=ima.icon('advanced'),
                                                tip=_('Regular expression'))
        self.exclude_regexp.setCheckable(True)
        self.exclude_regexp.setChecked(exclude_regexp)
        exclude_label = QLabel(_("Exclude:"))
        exclude_label.setBuddy(self.exclude_pattern)
        for widget in [exclude_label, self.exclude_pattern,
                       self.exclude_regexp]:
            hlayout2.addWidget(widget)

        # Layout 3
        hlayout3 = QHBoxLayout()

        search_on_label = QLabel(_("Search in:"))
        self.path_selection_combo = PatternComboBox(self, exclude,
                                                    _('Search directory'))
        self.path_selection_combo.setEditable(False)
        self.path_selection_contents = QListWidget(self.path_selection_combo)
        self.path_selection_contents.hide()
        self.path_selection_combo.setModel(
            self.path_selection_contents.model())

        self.path_selection_contents.addItem(_("Current working directory"))
        item = self.path_selection_contents.item(0)
        item.setToolTip(_("Search in all files and "
                          "directories present on the"
                          "current Spyder path"))

        self.path_selection_contents.addItem(_("Project"))
        item = self.path_selection_contents.item(1)
        item.setToolTip(_("Search in all files and "
                          "directories present on the"
                          "current project path "
                          "(If opened)"))
        item.setFlags(item.flags() & ~Qt.ItemIsEnabled)

        self.path_selection_contents.addItem(_("File").replace('&', ''))
        item = self.path_selection_contents.item(2)
        item.setToolTip(_("Search in current opened file"))

        self.path_selection_contents.addItem(_("Select other directory"))
        item = self.path_selection_contents.item(3)
        item.setToolTip(_("Search in other folder present on the file system"))

        self.path_selection_combo.insertSeparator(3)
        self.path_selection_combo.insertSeparator(5)
        for path in external_path_history:
            item = ExternalPathItem(None, path)
            self.path_selection_contents.addItem(item)

        self.path_selection_combo.currentIndexChanged.connect(
            self.path_selection_changed)

        hlayout3.addWidget(search_on_label)
        hlayout3.addWidget(self.path_selection_combo)

        self.search_text.valid.connect(lambda valid: self.find.emit())
        self.exclude_pattern.valid.connect(lambda valid: self.find.emit())

        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.addLayout(hlayout1)
        vlayout.addLayout(hlayout2)
        vlayout.addLayout(hlayout3)
        self.more_widgets = (hlayout2,)
        self.toggle_more_options(more_options)
        self.setLayout(vlayout)

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

    @Slot(bool)
    def toggle_more_options(self, state):
        for layout in self.more_widgets:
            for index in range(layout.count()):
                if state and self.isVisible() or not state:
                    layout.itemAt(index).widget().setVisible(state)
        if state:
            icon = ima.icon('options_less')
            tip = _('Hide advanced options')
        else:
            icon = ima.icon('options_more')
            tip = _('Show advanced options')
        self.more_options.setIcon(icon)
        self.more_options.setToolTip(tip)

    @Slot()
    def path_selection_changed(self):
        idx = self.path_selection_combo.currentIndex()
        if idx == EXTERNAL_PATH:
            external_path = self.select_directory()
            if len(external_path) > 0:
                item = ExternalPathItem(None, external_path)
                self.path_selection_contents.addItem(item)

                total_items = (self.path_selection_combo.count() -
                               MAX_PATH_HISTORY)
                for i in range(6, total_items):
                    self.path_selection_contents.takeItem(i)

                self.path_selection_combo.setCurrentIndex(
                    self.path_selection_combo.count() - 1)
            else:
                self.path_selection_combo.setCurrentIndex(CWD)
        elif idx > EXTERNAL_PATH:
            item = self.path_selection_contents.item(idx)
            self.external_path = item.path

    def update_combos(self):
        self.search_text.lineEdit().returnPressed.emit()
        self.exclude_pattern.lineEdit().returnPressed.emit()

    def set_search_text(self, text):
        if text:
            self.search_text.add_text(text)
            self.search_text.lineEdit().selectAll()
        self.search_text.setFocus()

    def get_options(self, all=False):
        # Getting options
        self.search_text.lineEdit().setStyleSheet("")
        self.exclude_pattern.lineEdit().setStyleSheet("")

        utext = to_text_string(self.search_text.currentText())
        if not utext:
            return
        try:
            texts = [(utext.encode('utf-8'), 'utf-8')]
        except UnicodeEncodeError:
            texts = []
            for enc in self.supported_encodings:
                try:
                    texts.append((utext.encode(enc), enc))
                except UnicodeDecodeError:
                    pass
        text_re = self.edit_regexp.isChecked()
        exclude = to_text_string(self.exclude_pattern.currentText())
        exclude_re = self.exclude_regexp.isChecked()
        case_sensitive = self.case_button.isChecked()
        python_path = False

        if not case_sensitive:
            texts = [(text[0].lower(), text[1]) for text in texts]

        file_search = False
        selection_idx = self.path_selection_combo.currentIndex()
        if selection_idx == CWD:
            path = self.path
        elif selection_idx == PROJECT:
            path = self.project_path
        elif selection_idx == FILE_PATH:
            path = self.file_path
            file_search = True
        else:
            path = self.external_path

        # Finding text occurrences
        if not exclude_re:
            exclude = fnmatch.translate(exclude)
        else:
            try:
                exclude = re.compile(exclude)
            except Exception:
                exclude_edit = self.exclude_pattern.lineEdit()
                exclude_edit.setStyleSheet(self.REGEX_INVALID)
                return None

        if text_re:
            try:
                texts = [(re.compile(x[0]), x[1]) for x in texts]
            except Exception:
                self.search_text.lineEdit().setStyleSheet(self.REGEX_INVALID)
                return None

        if all:
            search_text = [to_text_string(self.search_text.itemText(index))
                           for index in range(self.search_text.count())]
            exclude = [to_text_string(self.exclude_pattern.itemText(index))
                       for index in range(self.exclude_pattern.count())]
            path_history = [to_text_string(
                            self.path_selection_contents.item(index))
                            for index in range(
                                6, self.path_selection_combo.count())]
            exclude_idx = self.exclude_pattern.currentIndex()
            more_options = self.more_options.isChecked()
            return (search_text, text_re, [],
                    exclude, exclude_idx, exclude_re,
                    python_path, more_options, case_sensitive, path_history)
        else:
            return (path, file_search, exclude, texts, text_re, case_sensitive)

    @Slot()
    def select_directory(self):
        """Select directory"""
        self.redirect_stdio.emit(False)
        directory = getexistingdirectory(self, _("Select directory"),
                                         self.path)
        if directory:
            directory = to_text_string(osp.abspath(to_text_string(directory)))
        self.redirect_stdio.emit(True)
        return directory

    def set_directory(self, directory):
        self.path = to_text_string(osp.abspath(to_text_string(directory)))

    def set_project_path(self, path):
        self.project_path = to_text_string(osp.abspath(to_text_string(path)))
        item = self.path_selection_contents.item(PROJECT)
        item.setFlags(item.flags() | Qt.ItemIsEnabled)

    def disable_project_search(self):
        item = self.path_selection_contents.item(PROJECT)
        item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
        self.project_path = None

    def set_file_path(self, path):
        self.file_path = path

    def keyPressEvent(self, event):
        """Reimplemented to handle key events"""
        ctrl = event.modifiers() & Qt.ControlModifier
        shift = event.modifiers() & Qt.ShiftModifier
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            self.find.emit()
        elif event.key() == Qt.Key_F and ctrl and shift:
            # Toggle find widgets
            self.parent().toggle_visibility.emit(not self.isVisible())
        else:
            QWidget.keyPressEvent(self, event)
class FindOptions(QWidget):
    """Find widget with options"""
    REGEX_INVALID = "background-color:rgb(255, 175, 90);"
    find = Signal()
    stop = Signal()

    def __init__(self, parent, search_text, search_text_regexp, search_path,
                 exclude, exclude_idx, exclude_regexp, supported_encodings,
                 in_python_path, more_options, case_sensitive,
                 external_path_history):
        QWidget.__init__(self, parent)

        if search_path is None:
            search_path = getcwd_or_home()

        self.path = ''
        self.project_path = None
        self.file_path = None
        self.external_path = None
        self.external_path_history = external_path_history

        if not isinstance(search_text, (list, tuple)):
            search_text = [search_text]
        if not isinstance(search_path, (list, tuple)):
            search_path = [search_path]
        if not isinstance(exclude, (list, tuple)):
            exclude = [exclude]
        if not isinstance(external_path_history, (list, tuple)):
            external_path_history = [external_path_history]

        self.supported_encodings = supported_encodings

        # Layout 1
        hlayout1 = QHBoxLayout()
        self.search_text = PatternComboBox(self, search_text,
                                           _("Search pattern"))
        self.edit_regexp = create_toolbutton(self,
                                             icon=ima.icon('advanced'),
                                             tip=_('Regular expression'))
        self.case_button = create_toolbutton(self,
                                             icon=get_icon("upper_lower.png"),
                                             tip=_("Case Sensitive"))
        self.case_button.setCheckable(True)
        self.case_button.setChecked(case_sensitive)
        self.edit_regexp.setCheckable(True)
        self.edit_regexp.setChecked(search_text_regexp)
        self.more_widgets = ()
        self.more_options = create_toolbutton(self,
                                              toggled=self.toggle_more_options)
        self.more_options.setCheckable(True)
        self.more_options.setChecked(more_options)

        self.ok_button = create_toolbutton(self,
                                           text=_("Search"),
                                           icon=ima.icon('find'),
                                           triggered=lambda: self.find.emit(),
                                           tip=_("Start search"),
                                           text_beside_icon=True)
        self.ok_button.clicked.connect(self.update_combos)
        self.stop_button = create_toolbutton(
            self,
            text=_("Stop"),
            icon=ima.icon('editclear'),
            triggered=lambda: self.stop.emit(),
            tip=_("Stop search"),
            text_beside_icon=True)
        self.stop_button.setEnabled(False)
        for widget in [
                self.search_text, self.edit_regexp, self.case_button,
                self.ok_button, self.stop_button, self.more_options
        ]:
            hlayout1.addWidget(widget)

        # Layout 2
        hlayout2 = QHBoxLayout()
        self.exclude_pattern = PatternComboBox(self, exclude,
                                               _("Excluded filenames pattern"))
        if exclude_idx is not None and exclude_idx >= 0 \
           and exclude_idx < self.exclude_pattern.count():
            self.exclude_pattern.setCurrentIndex(exclude_idx)
        self.exclude_regexp = create_toolbutton(self,
                                                icon=ima.icon('advanced'),
                                                tip=_('Regular expression'))
        self.exclude_regexp.setCheckable(True)
        self.exclude_regexp.setChecked(exclude_regexp)
        exclude_label = QLabel(_("Exclude:"))
        exclude_label.setBuddy(self.exclude_pattern)
        for widget in [
                exclude_label, self.exclude_pattern, self.exclude_regexp
        ]:
            hlayout2.addWidget(widget)

        # Layout 3
        hlayout3 = QHBoxLayout()

        search_on_label = QLabel(_("Search in:"))
        self.path_selection_combo = PatternComboBox(self, exclude,
                                                    _('Search directory'))
        self.path_selection_combo.setEditable(False)
        self.path_selection_contents = QListWidget(self.path_selection_combo)
        self.path_selection_contents.hide()
        self.path_selection_combo.setModel(
            self.path_selection_contents.model())

        self.path_selection_contents.addItem(_("Current working directory"))
        item = self.path_selection_contents.item(0)
        item.setToolTip(
            _("Search in all files and "
              "directories present on the"
              "current Spyder path"))

        self.path_selection_contents.addItem(_("Project"))
        item = self.path_selection_contents.item(1)
        item.setToolTip(
            _("Search in all files and "
              "directories present on the"
              "current project path "
              "(If opened)"))
        item.setFlags(item.flags() & ~Qt.ItemIsEnabled)

        self.path_selection_contents.addItem(_("File").replace('&', ''))
        item = self.path_selection_contents.item(2)
        item.setToolTip(_("Search in current opened file"))

        self.path_selection_contents.addItem(_("Select other directory"))
        item = self.path_selection_contents.item(3)
        item.setToolTip(_("Search in other folder present on the file system"))

        self.path_selection_combo.insertSeparator(3)
        self.path_selection_combo.insertSeparator(5)
        for path in external_path_history:
            item = ExternalPathItem(None, path)
            self.path_selection_contents.addItem(item)

        self.path_selection_combo.currentIndexChanged.connect(
            self.path_selection_changed)

        hlayout3.addWidget(search_on_label)
        hlayout3.addWidget(self.path_selection_combo)

        self.search_text.valid.connect(lambda valid: self.find.emit())
        self.exclude_pattern.valid.connect(lambda valid: self.find.emit())

        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.addLayout(hlayout1)
        vlayout.addLayout(hlayout2)
        vlayout.addLayout(hlayout3)
        self.more_widgets = (hlayout2, )
        self.toggle_more_options(more_options)
        self.setLayout(vlayout)

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

    @Slot(bool)
    def toggle_more_options(self, state):
        for layout in self.more_widgets:
            for index in range(layout.count()):
                if state and self.isVisible() or not state:
                    layout.itemAt(index).widget().setVisible(state)
        if state:
            icon = ima.icon('options_less')
            tip = _('Hide advanced options')
        else:
            icon = ima.icon('options_more')
            tip = _('Show advanced options')
        self.more_options.setIcon(icon)
        self.more_options.setToolTip(tip)

    @Slot()
    def path_selection_changed(self):
        idx = self.path_selection_combo.currentIndex()
        if idx == EXTERNAL_PATH:
            external_path = self.select_directory()
            if len(external_path) > 0:
                item = ExternalPathItem(None, external_path)
                self.path_selection_contents.addItem(item)

                total_items = (self.path_selection_combo.count() -
                               MAX_PATH_HISTORY)
                for i in range(6, total_items):
                    self.path_selection_contents.takeItem(i)

                self.path_selection_combo.setCurrentIndex(
                    self.path_selection_combo.count() - 1)
            else:
                self.path_selection_combo.setCurrentIndex(CWD)
        elif idx > EXTERNAL_PATH:
            item = self.path_selection_contents.item(idx)
            self.external_path = item.path

    def update_combos(self):
        self.search_text.lineEdit().returnPressed.emit()
        self.exclude_pattern.lineEdit().returnPressed.emit()

    def set_search_text(self, text):
        if text:
            self.search_text.add_text(text)
            self.search_text.lineEdit().selectAll()
        self.search_text.setFocus()

    def get_options(self, all=False):
        # Getting options
        self.search_text.lineEdit().setStyleSheet("")
        self.exclude_pattern.lineEdit().setStyleSheet("")

        utext = to_text_string(self.search_text.currentText())
        if not utext:
            return
        try:
            texts = [(utext.encode('utf-8'), 'utf-8')]
        except UnicodeEncodeError:
            texts = []
            for enc in self.supported_encodings:
                try:
                    texts.append((utext.encode(enc), enc))
                except UnicodeDecodeError:
                    pass
        text_re = self.edit_regexp.isChecked()
        exclude = to_text_string(self.exclude_pattern.currentText())
        exclude_re = self.exclude_regexp.isChecked()
        case_sensitive = self.case_button.isChecked()
        python_path = False

        if not case_sensitive:
            texts = [(text[0].lower(), text[1]) for text in texts]

        file_search = False
        selection_idx = self.path_selection_combo.currentIndex()
        if selection_idx == CWD:
            path = self.path
        elif selection_idx == PROJECT:
            path = self.project_path
        elif selection_idx == FILE_PATH:
            path = self.file_path
            file_search = True
        else:
            path = self.external_path

        # Finding text occurrences
        if not exclude_re:
            exclude = fnmatch.translate(exclude)
        else:
            try:
                exclude = re.compile(exclude)
            except Exception:
                exclude_edit = self.exclude_pattern.lineEdit()
                exclude_edit.setStyleSheet(self.REGEX_INVALID)
                return None

        if text_re:
            try:
                texts = [(re.compile(x[0]), x[1]) for x in texts]
            except Exception:
                self.search_text.lineEdit().setStyleSheet(self.REGEX_INVALID)
                return None

        if all:
            search_text = [
                to_text_string(self.search_text.itemText(index))
                for index in range(self.search_text.count())
            ]
            exclude = [
                to_text_string(self.exclude_pattern.itemText(index))
                for index in range(self.exclude_pattern.count())
            ]
            path_history = [
                to_text_string(self.path_selection_contents.item(index))
                for index in range(6, self.path_selection_combo.count())
            ]
            exclude_idx = self.exclude_pattern.currentIndex()
            more_options = self.more_options.isChecked()
            return (search_text, text_re, [], exclude, exclude_idx, exclude_re,
                    python_path, more_options, case_sensitive, path_history)
        else:
            return (path, file_search, exclude, texts, text_re, case_sensitive)

    @Slot()
    def select_directory(self):
        """Select directory"""
        self.parent().redirect_stdio.emit(False)
        directory = getexistingdirectory(self, _("Select directory"),
                                         self.path)
        if directory:
            directory = to_text_string(osp.abspath(to_text_string(directory)))
        self.parent().redirect_stdio.emit(True)
        return directory

    def set_directory(self, directory):
        self.path = to_text_string(osp.abspath(to_text_string(directory)))

    def set_project_path(self, path):
        self.project_path = to_text_string(osp.abspath(to_text_string(path)))
        item = self.path_selection_contents.item(PROJECT)
        item.setFlags(item.flags() | Qt.ItemIsEnabled)

    def disable_project_search(self):
        item = self.path_selection_contents.item(PROJECT)
        item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
        self.project_path = None

    def set_file_path(self, path):
        self.file_path = path

    def keyPressEvent(self, event):
        """Reimplemented to handle key events"""
        ctrl = event.modifiers() & Qt.ControlModifier
        shift = event.modifiers() & Qt.ShiftModifier
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            self.find.emit()
        elif event.key() == Qt.Key_F and ctrl and shift:
            # Toggle find widgets
            self.parent().toggle_visibility.emit(not self.isVisible())
        else:
            QWidget.keyPressEvent(self, event)
예제 #5
0
class HeaderEditDialog(QDialog):

    # name of the current preset; whether to set this preset as default; list of Columns
    header_changed = Signal(str, bool, list)

    def __init__(self, parent, table_header):
        super().__init__(parent)

        self.table_header = table_header
        self.default_preset_name = None
        self.preset_name = table_header.preset_name
        self.columns = deepcopy(table_header.columns)
        self.setupUi()
        self.update_output()

    def setupUi(self):
        self.resize(240, 400)
        self.vbox = QVBoxLayout(self)
        self.presetLabel = QLabel(self)
        self.columnList = QListWidget(self)
        self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self)
        self.vbox.addWidget(self.presetLabel)
        self.vbox.addWidget(self.columnList)
        self.vbox.addWidget(self.setAsDefaultCheckbox)

        self.columnList.setDragDropMode(QListWidget.InternalMove)
        self.columnList.setDefaultDropAction(Qt.MoveAction)
        self.columnList.setSelectionMode(QListWidget.ExtendedSelection)
        self.columnList.setAlternatingRowColors(True)
        self.columnList.installEventFilter(self)
        self.columnList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.columnList.customContextMenuRequested.connect(self.open_menu)
        self.columnList.model().rowsMoved.connect(self.read_columns_from_list)

        # for a dumb qss hack to make selected checkboxes not white on a light theme
        self.columnList.setObjectName("ColumnList")

        buttons = QDialogButtonBox.Reset | QDialogButtonBox.Save | QDialogButtonBox.Cancel
        self.buttonBox = QDialogButtonBox(buttons, self)
        self.vbox.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.resetButton = self.buttonBox.button(QDialogButtonBox.Reset)
        self.resetButton.clicked.connect(self.reset_to_stock)

    def eventFilter(self, object, event):
        if event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
                self.toggle_selected_columns()
                return True
            if event.key() == Qt.Key_Delete:
                self.delete_selected()
                return True
        return False

    def update_output(self):
        self.presetLabel.setText("Preset: {}".format(self.preset_name))
        self.setAsDefaultCheckbox.setChecked(
            CONFIG['default_header_preset'] == self.preset_name)
        self.columnList.clear()
        for column in self.columns:
            ColumnListItem(self.columnList, column)

    def accept(self):
        self.read_columns_from_list()
        self.header_changed.emit(self.preset_name,
                                 self.setAsDefaultCheckbox.isChecked(),
                                 self.columns)
        self.done(0)

    def reject(self):
        self.done(0)

    def reset_to_stock(self):
        self.columns = deepcopy(DEFAULT_COLUMNS)
        self.update_output()

    def read_columns_from_list(self):
        new_columns = []
        for i in range(self.columnList.count()):
            item = self.columnList.item(i)
            new_columns.append(item.column)
        self.columns = new_columns

    def toggle_selected_columns(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            value_now = item.data(Qt.CheckStateRole)
            item.setData(Qt.CheckStateRole, not value_now)
        self.columnList.reset(
        )  # @Improvement: is there a better way to update QListWidget?

    def open_menu(self, position):
        menu = QMenu(self)

        preset_menu = menu.addMenu('Presets')
        preset_menu.addAction('New preset', self.new_preset_dialog)
        preset_menu.addSeparator()

        preset_names = CONFIG.get_header_presets()

        if len(preset_names) == 0:
            action = preset_menu.addAction('No presets')
            action.setEnabled(False)
        else:
            delete_menu = menu.addMenu('Delete preset')
            for name in preset_names:
                preset_menu.addAction(name, partial(self.load_preset, name))
                delete_menu.addAction(name, partial(self.delete_preset, name))

        menu.addSeparator()
        menu.addAction('New column...', self.create_new_column_dialog)

        if len(self.columnList.selectedIndexes()) > 0:
            menu.addAction('Delete selected', self.delete_selected)

        menu.popup(self.columnList.viewport().mapToGlobal(position))

    def load_preset(self, name):
        new_columns = CONFIG.load_header_preset(name)
        if not new_columns:
            return

        self.columns = new_columns
        self.preset_name = name
        self.update_output()

    def new_preset_dialog(self):
        d = QInputDialog(self)
        d.setLabelText('Enter the new name for the new preset:')
        d.setWindowTitle('Create new preset')
        d.textValueSelected.connect(self.create_new_preset)
        d.open()

    def create_new_preset(self, name):
        if name in CONFIG.get_header_presets():
            show_warning_dialog(
                self, "Preset creation error",
                'Preset named "{}" already exists.'.format(name))
            return
        if len(name.strip()) == 0:
            show_warning_dialog(
                self, "Preset creation error",
                'This preset name is not allowed.'.format(name))
            return

        self.preset_name = name
        self.update_output()
        CONFIG.save_header_preset(name, self.columns)

    def delete_preset(self, name):
        CONFIG.delete_header_preset(name)
        if name == self.preset_name:
            self.columns = deepcopy(DEFAULT_COLUMNS)
            self.update_output()

    def create_new_column_dialog(self):
        d = CreateNewColumnDialog(self)
        d.add_new_column.connect(self.add_new_column)
        d.setWindowTitle('Create new column')
        d.open()

    def add_new_column(self, name, title):
        new_column = Column(name, title)
        # if the last column is message, insert this column before it (I think that makes sense?)
        if len(self.columns) == 0:
            self.columns.append(new_column)
        elif self.columns[-1].name in ('message', 'msg'):
            self.columns.insert(-1, new_column)
        else:
            self.columns.append(new_column)
        self.update_output()

    def delete_selected(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            self.columnList.takeItem(self.columnList.row(item))
        self.read_columns_from_list()
        self.update_output()