def __init__(self, parent=None):
        super().__init__(parent)
        self._model = LogRecordModel()
        filter_model = QSortFilterProxyModel()
        filter_model.setSourceModel(self._model)
        filter_model.setFilterKeyColumn(3)

        self.msg_filter = QLineEdit()
        self.log_view = QTableView()
        self.log_view.setModel(filter_model)
        header = self.log_view.horizontalHeader()
        #header.setSectionResizeMode(header.Stretch)
        header.setStretchLastSection(True)
        self.status_label = QLabel()

        # Connect signals:
        self.msg_filter.textChanged.connect(filter_model.setFilterFixedString)
        # Make nice layout:
        layout = QVBoxLayout(self)
        layout.addWidget(self.msg_filter)
        layout.addWidget(self.log_view)
        layout.addWidget(self.status_label)

        # Attach udp server:
        self._udpServer = UdpHandler(self._model)
        self._model.stats_changed.connect(self.status_label.setText)
Example #2
0
class UserAgentsDialog(QDialog, Ui_UserAgentsDialog):
    """
    Class implementing a dialog to show all saved user agent settings.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(UserAgentsDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.removeButton.clicked.connect(
            self.userAgentsTable.removeSelected)
        self.removeAllButton.clicked.connect(
            self.userAgentsTable.removeAll)
        
        self.userAgentsTable.verticalHeader().hide()
        self.__userAgentModel = UserAgentModel(
            Helpviewer.HelpWindow.HelpWindow.userAgentsManager(), self)
        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setSourceModel(self.__userAgentModel)
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)
        self.userAgentsTable.setModel(self.__proxyModel)
        
        fm = QFontMetrics(QFont())
        height = fm.height() + fm.height() // 3
        self.userAgentsTable.verticalHeader().setDefaultSectionSize(height)
        self.userAgentsTable.verticalHeader().setMinimumSectionSize(-1)
        
        self.userAgentsTable.resizeColumnsToContents()
        self.userAgentsTable.horizontalHeader().setStretchLastSection(True)
    def setSourceModel(self, model):
        QSortFilterProxyModel.setSourceModel(self, model)
        self.sourceModel().dataChanged.connect(self.mapModelMaybe)
        self.sourceModel().rowsInserted.connect(self.mapModel)
        self.sourceModel().rowsRemoved.connect(self.mapModel)
        self.sourceModel().rowsMoved.connect(self.mapModel)

        self.mapModel()
Example #4
0
    def __init__(self, core, parent=None):
        super().__init__(parent)
        uic.loadUi(resource_path('data/ObjectsTab.ui'), self)
        self._core = core

        model = models.ObjectModel(self._core.inv)
        proxyModel = QSortFilterProxyModel()
        proxyModel.setSourceModel(model)
        self.tableView.setModel(proxyModel)
Example #5
0
    def initUI(self, db):
        equipment = EquipmentModel(db)
        self.setModel(equipment)
        
        self.setStates()
        self.setSelectionMode(QAbstractItemView.MultiSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setSizes()

        proxy = QSortFilterProxyModel()
        self.setModel(proxy)
        proxy.setSourceModel(equipment)
Example #6
0
class ZoomValuesDialog(QDialog, Ui_ZoomValuesDialog):
    """
    Class implementing a dialog to show all saved zoom values.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(ZoomValuesDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.removeButton.clicked.connect(
            self.zoomValuesTable.removeSelected)
        self.removeAllButton.clicked.connect(self.zoomValuesTable.removeAll)
        
        import Helpviewer.HelpWindow
        from .ZoomValuesModel import ZoomValuesModel
        
        self.zoomValuesTable.verticalHeader().hide()
        self.__zoomValuesModel = ZoomValuesModel(
            Helpviewer.HelpWindow.HelpWindow.zoomManager(), self)
        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setSourceModel(self.__zoomValuesModel)
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)
        self.zoomValuesTable.setModel(self.__proxyModel)
        
        fm = QFontMetrics(QFont())
        height = fm.height() + fm.height() // 3
        self.zoomValuesTable.verticalHeader().setDefaultSectionSize(height)
        self.zoomValuesTable.verticalHeader().setMinimumSectionSize(-1)
        
        self.__calculateHeaderSizes()
    
    def __calculateHeaderSizes(self):
        """
        Private method to calculate the section sizes of the horizontal header.
        """
        fm = QFontMetrics(QFont())
        for section in range(self.__zoomValuesModel.columnCount()):
            header = self.zoomValuesTable.horizontalHeader()\
                .sectionSizeHint(section)
            if section == 0:
                header = fm.width("extraveryveryverylongsitename")
            elif section == 1:
                header = fm.width("averagelongzoomvalue")
            buffer = fm.width("mm")
            header += buffer
            self.zoomValuesTable.horizontalHeader()\
                .resizeSection(section, header)
        self.zoomValuesTable.horizontalHeader().setStretchLastSection(True)
class ClickToFlashWhitelistDialog(QDialog, Ui_ClickToFlashWhitelistDialog):
    """
    Class implementing a dialog to manage the ClickToFlash whitelist.
    """
    def __init__(self, whitelist, parent=None):
        """
        Constructor
        
        @param whitelist list of whitelisted hosts (list of string)
        @param parent reference to the parent widget (QWidget)
        """
        super(ClickToFlashWhitelistDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.iconLabel.setPixmap(UI.PixmapCache.getPixmap("flashBlock48.png"))
        
        self.__model = QStringListModel(whitelist[:], self)
        self.__model.sort(0)
        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.__proxyModel.setSourceModel(self.__model)
        self.whitelist.setModel(self.__proxyModel)
        
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)
        
        self.removeButton.clicked.connect(self.whitelist.removeSelected)
        self.removeAllButton.clicked.connect(self.whitelist.removeAll)
    
    @pyqtSlot()
    def on_addButton_clicked(self):
        """
        Private slot to add an entry to the whitelist.
        """
        host, ok = QInputDialog.getText(
            self,
            self.tr("ClickToFlash Whitelist"),
            self.tr("Enter host name to add to whitelist:"),
            QLineEdit.Normal)
        if ok and host != "" and host not in self.__model.stringList():
            self.__model.insertRow(self.__model.rowCount())
            self.__model.setData(
                self.__model.index(self.__model.rowCount() - 1), host)
            self.__model.sort(0)
    
    def getWhitelist(self):
        """
        Public method to get the whitelisted hosts.
        
        @return list of whitelisted hosts (list of string)
        """
        return self.__model.stringList()
    def __init__(self, parent=None):
        QSortFilterProxyModel.__init__(self, parent)

        # self.rootItem = QStandardItem()
        self.p1 = QStandardItem(self.tr("Main"))
        self.p2 = QStandardItem(self.tr("Secundary"))
        self.p3 = QStandardItem(self.tr("Minors"))

        self._cats = [
            self.p1,
            self.p2,
            self.p3
        ]
class E5ErrorMessageFilterDialog(QDialog, Ui_E5ErrorMessageFilterDialog):
    """
    Class implementing a dialog to manage the list of messages to be ignored.
    """
    def __init__(self, messageFilters, parent=None):
        """
        Constructor
        
        @param messageFilters list of message filters to be edited
            (list of strings)
        @param parent reference to the parent widget (QWidget)
        """
        super(E5ErrorMessageFilterDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.__model = QStringListModel(messageFilters, self)
        self.__model.sort(0)
        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.__proxyModel.setSourceModel(self.__model)
        self.filterList.setModel(self.__proxyModel)
        
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)
        
        self.removeButton.clicked.connect(self.filterList.removeSelected)
        self.removeAllButton.clicked.connect(self.filterList.removeAll)
    
    @pyqtSlot()
    def on_addButton_clicked(self):
        """
        Private slot to add an entry to the list.
        """
        filter, ok = QInputDialog.getText(
            self,
            self.tr("Error Messages Filter"),
            self.tr("Enter message filter to add to the list:"),
            QLineEdit.Normal)
        if ok and filter != "" and filter not in self.__model.stringList():
            self.__model.insertRow(self.__model.rowCount())
            self.__model.setData(
                self.__model.index(self.__model.rowCount() - 1), filter)
            self.__model.sort(0)
    
    def getFilters(self):
        """
        Public method to get the list of message filters.
        
        @return error message filters (list of strings)
        """
        return self.__model.stringList()[:]
Example #10
0
class SqlRelationalTableModel(QtSql.QSqlRelationalTableModel):
    def __init__(self, model, parent, db):
        super().__init__(parent, db)

        self.model = model
        self._proxyModel = QSortFilterProxyModel(self)
        self._proxyModel.setSortLocaleAware(True)
        self._proxyModel.setSourceModel(self)

    def relationModel(self, _column):
        return self.model

    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DecorationRole:
            if index.row() < 0:
                return None
            iconIndex = self.index(index.row(), self.fieldIndex('icon'))
            if not self.data(iconIndex) or self.data(iconIndex).isNull():
                return None
            icon = QPixmap()
            icon.loadFromData(self.data(iconIndex))
            return icon

        return super().data(index, role)

    def proxyModel(self):
        return self._proxyModel

    def sort(self, sort=True):
        if sort:
            self._proxyModel.sort(self.fieldIndex('value'))
        else:
            self._proxyModel.sort(-1)
    def __init__(self, settings, directory, check_id_fct, annotations_path, parent=None):
        super().__init__(parent)
        # FIXME Delayed refactoring of check_id_fct and annotations_path.

        # Variables section.

        library_id = settings["libraryID"]
        library_type = settings["libraryType"]
        api_key = settings["apiKey"]
        self._zotero = ZoteroWrap(library_id, library_type, api_key, directory)

        # Widgets section.

        model = ZoteroTableModel(self._zotero, check_id_fct, annotations_path)
        model.load()

        proxy_model = QSortFilterProxyModel()
        proxy_model.setSourceModel(model)
        proxy_model.setDynamicSortFilter(True)
        proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        proxy_model.setFilterKeyColumn(-1)  # NB: All columns.

        self.view = QTableView(self)
        self.view.setModel(proxy_model)
        self.view.setCornerButtonEnabled(False)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        # NB: Triggers a call to sortByColumn() which sorts by the first column.
        self.view.setSortingEnabled(True)
        self.view.setWordWrap(False)
        self.view.verticalHeader().hide()

        self.filter_edit = FilterEdit(self.view)

        # NB: The thread does not begin executing until start() is called.
        self.refresh_thread = ZoteroRefreshThread(model, self)

        # Layouts section.

        header_layout = QFormLayout()
        header_layout.addRow("Filter:", self.filter_edit)
        header_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        utils.configure_form_layout(header_layout)

        main_layout = QVBoxLayout()
        main_layout.addLayout(header_layout)
        main_layout.addWidget(self.view)
        self.setLayout(main_layout)

        # Signals section.

        self.filter_edit.textChanged.connect(proxy_model.setFilterFixedString)
        self.refresh_thread.started.connect(self.refresh_started)
        self.refresh_thread.finished.connect(self.refresh_finished)
Example #12
0
class NoCacheHostsDialog(QDialog, Ui_NoCacheHostsDialog):
    """
    Class implementing a dialog to manage the list of hosts not to be cached.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super(NoCacheHostsDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.__model = QStringListModel(
            Preferences.getHelp("NoCacheHosts"), self)
        self.__model.sort(0)
        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.__proxyModel.setSourceModel(self.__model)
        self.noCacheList.setModel(self.__proxyModel)
        
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)
        
        self.removeButton.clicked.connect(self.noCacheList.removeSelected)
        self.removeAllButton.clicked.connect(self.noCacheList.removeAll)
    
    @pyqtSlot()
    def on_addButton_clicked(self):
        """
        Private slot to add an entry to the list.
        """
        host, ok = QInputDialog.getText(
            self,
            self.tr("Not Cached Hosts"),
            self.tr("Enter host name to add to the list:"),
            QLineEdit.Normal)
        if ok and host != "" and host not in self.__model.stringList():
            self.__model.insertRow(self.__model.rowCount())
            self.__model.setData(
                self.__model.index(self.__model.rowCount() - 1), host)
            self.__model.sort(0)
    
    def accept(self):
        """
        Public method to accept the dialog data.
        """
        Preferences.setHelp("NoCacheHosts", self.__model.stringList())
        
        super(NoCacheHostsDialog, self).accept()
 def __init__(self, database, main_spectrum = None):
     super(ReferenceSpectraDialog, self).__init__()
     self.main_spectrum = main_spectrum
     self.ui = Ui_ReferenceSpectraDialog()
     self.ui.setupUi(self)
     self.reference_catalogues = ReferenceCatalogues(database)
     self.full_model = QStandardItemModel()
     self.catalogues_model = QStandardItemModel()
     self.ui.catalogue.setModel(self.catalogues_model)
     self.ui.catalogue.currentTextChanged.connect(lambda txt: self.populate())
     for catname, cat in self.reference_catalogues.catalogues.items():
         row = QStandardItem(catname)
         row.setData(cat)
         self.catalogues_model.appendRow(row)
     
     self.model = QSortFilterProxyModel()
     self.model.setSourceModel(self.full_model)
     self.model.setFilterCaseSensitivity(Qt.CaseInsensitive)
     self.model.setFilterKeyColumn(0)
     self.ui.entries.setModel(self.model)
     self.ui.type_filter.currentTextChanged.connect(lambda txt: self.model.setFilterWildcard("{}*".format(txt) ) )
     self.ui.buttonBox.button(QDialogButtonBox.Open).setEnabled(False)
     self.ui.entries.selectionModel().selectionChanged.connect(lambda selected, deselected: self.ui.buttonBox.button(QDialogButtonBox.Open).setEnabled(len(selected.indexes()) > 0)  )
     self.accepted.connect(self.load_fits)
     self.populate()
    def get_widget(self):

        if self.widget is None:
            self.widget = QWidget()
            self.ui = properties_dock_ui.Ui_PropertiesDock()
            self.ui.setupUi(self.widget)

            if self.tree_sheet is not None and self.core_part is not None:
                table_model = self.core_part.property_table_model

                # filter :
                self.filter = QSortFilterProxyModel(self.widget)
                self.filter.setFilterKeyColumn(-1)
                self.filter.setFilterCaseSensitivity(False)
                self.filter.setSourceModel(table_model)

                # model :
                self.ui.tableView.setModel(self.filter)

                # connect :
                self.ui.addPropButton.clicked.connect(self.add_property_row)
                self.ui.removePropButton.clicked.connect(
                    self.remove_property_row)
                self.ui.filterLineEdit.textChanged.connect(
                    self.filter.setFilterFixedString)
                self.ui.tableView.clicked.connect(self.set_current_row)

            self.widget.gui_part = self
        return self.widget
Example #15
0
    def __init__(self):
        QDialog.__init__(self)
        self.setupUi(self)
        self.settings = MySettings()
        SettingDialog.__init__(self, self.settings)

        # new declaration of ProjectFinder since changes can be cancelled
        self.project_finder = ProjectFinder(self)

        # table model
        self.project_search_model = ProjectSearchModel(self.project_finder)

        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.project_search_model)
        self.projectSearchTable.setModel(self.proxyModel)

        header = self.projectSearchTable.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)

        # open/create QuickFinder file
        self.createFileButton.clicked.connect(self.create_QFTS_file)
        self.openFileButton.clicked.connect(self.open_QFTS_file)
        self.read_QFTS_file()

        # project search
        self.addSearchButton.clicked.connect(self.add_project_search)
        self.removeSearchButton.clicked.connect(self.remove_project_search)
        self.editSearchButton.clicked.connect(self.edit_project_search)
        self.refreshButton.clicked.connect(self.refresh_project_search)
        self.projectSearchTable.selectionModel().selectionChanged.connect(self.enableButtons)
        self.enableButtons()

        # geomapfish
        self.geomapfishCrsButton.clicked.connect(self.geomapfishCrsButtonClicked)
Example #16
0
    def __init__(self, model, parent, db):
        super().__init__(parent, db)

        self.model = model
        self._proxyModel = QSortFilterProxyModel(self)
        self._proxyModel.setSortLocaleAware(True)
        self._proxyModel.setSourceModel(self)
 def __init__(self, data, info, parent=None):
     """
     Constructor
     
     @param data contents to be edited (string)
     @param info info string to show at the header (string)
     @param parent reference to the parent widget (QWidget)
     """
     super(SpellingDictionaryEditDialog, self).__init__(parent)
     self.setupUi(self)
     
     self.infoLabel.setText(info)
     
     self.__model = QStringListModel(data.splitlines(), self)
     self.__model.sort(0)
     self.__proxyModel = QSortFilterProxyModel(self)
     self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
     self.__proxyModel.setDynamicSortFilter(True)
     self.__proxyModel.setSourceModel(self.__model)
     self.wordList.setModel(self.__proxyModel)
     
     self.searchEdit.textChanged.connect(
         self.__proxyModel.setFilterFixedString)
     
     self.removeButton.clicked.connect(self.wordList.removeSelected)
     self.removeAllButton.clicked.connect(self.wordList.removeAll)
 def display(self, incidents, locations):
     self.model = IncidentModel(incidents, locations, self)
     self.proxy = QSortFilterProxyModel(self)
     self.proxy.setSourceModel(self.model)
     self.proxy.setFilterRole(self.model.filter_role)
     self.proxy.setFilterRegExp(QRegExp(self.filter.text()))
     self.view.setModel(self.proxy)
Example #19
0
 def __init__(self, parent=None):
     """
     Constructor
     
     @param parent reference to the parent widget (QWidget)
     """
     super(ZoomValuesDialog, self).__init__(parent)
     self.setupUi(self)
     
     self.removeButton.clicked.connect(
         self.zoomValuesTable.removeSelected)
     self.removeAllButton.clicked.connect(self.zoomValuesTable.removeAll)
     
     import Helpviewer.HelpWindow
     from .ZoomValuesModel import ZoomValuesModel
     
     self.zoomValuesTable.verticalHeader().hide()
     self.__zoomValuesModel = ZoomValuesModel(
         Helpviewer.HelpWindow.HelpWindow.zoomManager(), self)
     self.__proxyModel = QSortFilterProxyModel(self)
     self.__proxyModel.setSourceModel(self.__zoomValuesModel)
     self.searchEdit.textChanged.connect(
         self.__proxyModel.setFilterFixedString)
     self.zoomValuesTable.setModel(self.__proxyModel)
     
     fm = QFontMetrics(QFont())
     height = fm.height() + fm.height() // 3
     self.zoomValuesTable.verticalHeader().setDefaultSectionSize(height)
     self.zoomValuesTable.verticalHeader().setMinimumSectionSize(-1)
     
     self.__calculateHeaderSizes()
Example #20
0
    def lessThan(self, left, right):
        if left.column() == 1: # size
            return left.data(USER_ROLE_SIZE) < right.data(USER_ROLE_SIZE)
        elif left.column() == 2: # last modified
            return left.data(USER_ROLE_LAST_MODIFIED) < right.data(USER_ROLE_LAST_MODIFIED)

        return QSortFilterProxyModel.lessThan(self, left, right)
Example #21
0
    def setupUi(self):
        self.load_ui("typeattrquery.ui")

        # populate attr list
        self.attr_model = SEToolsListModel(self)
        self.attr_model.item_list = sorted(r for r in self.policy.typeattributes())
        self.attrs.setModel(self.attr_model)

        # populate type list
        self.type_model = SEToolsListModel(self)
        self.type_model.item_list = sorted(self.policy.types())
        self.types.setModel(self.type_model)

        # set up results
        self.table_results_model = TypeAttributeTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # setup indications of errors on level/range
        self.orig_palette = self.name.palette()
        self.error_palette = self.name.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_name_error()

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.typeattrquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.attrs.doubleClicked.connect(self.get_detail)
        self.attrs.get_detail.triggered.connect(self.get_detail)
        self.name.textEdited.connect(self.clear_name_error)
        self.name.editingFinished.connect(self.set_name)
        self.name_regex.toggled.connect(self.set_name_regex)
        self.types.selectionModel().selectionChanged.connect(self.set_types)
        self.invert_types.clicked.connect(self.invert_type_selection)
        self.buttonBox.clicked.connect(self.run)
Example #22
0
    def lessThan(self, left, right):
        if left.column() != 2: # position
            return QSortFilterProxyModel.lessThan(self, left, right)

        # Sort letters before digits, so that Bricklets connected to a
        # Master Brick are shown before Bricks stacked on the Master.
        # Also sort extensions after letters (i.e Bricks), so they are shown last.
        # Also sort slave stacks, having position 0, (i.e. from a RS485 Extension)
        # behind Bricks stacked on the Master.
        def get_sort_key(data):
            if len(data) == 0: # Put empty string before everything
                return 0

            diff = ord('z') - ord('0') + 1 # Put digits after letters

            if data.isdigit(): # Swap 0 behind 1-9
                if data == '0':
                    diff += 9
                else:
                    diff -= 1

            if 'Ext' in data:
                diff += 10 # Put digits of extensions after normal digits
                data = data[3:]
            return ord(data) + (diff if data.isdigit() else 0)

        # Compare by name if the position is the same
        if get_sort_key(left.data()) == get_sort_key(right.data()):
            return left.sibling(left.row(), 0).data() < right.sibling(right.row(), 0).data()

        return get_sort_key(left.data()) < get_sort_key(right.data())
Example #23
0
 def columnCount(self, parent):
     """
     Public method to return the number of columns.
     
     @param parent index of the parent (QModelIndex)
     @return number of columns (integer)
     """
     return min(1, QSortFilterProxyModel.columnCount(self, parent))
Example #24
0
class CompletingComboBox(QComboBox):
    """An editable combo box that filters and autocompletes."""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setEditable(True)
        self.filter = QSortFilterProxyModel(self)
        self.filter.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter.setSourceModel(self.model())
        self.completer = QCompleter(self.filter, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited.connect(
            self.filter.setFilterFixedString)
        self.currentIndexChanged.connect(self._index_changed)

    def _index_changed(self, index):
        self.lineEdit().selectAll()
Example #25
0
    def setupUi(self):
        self.load_ui("apol/defaultquery.ui")

        # set up results
        self.table_results_model = DefaultTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(1, Qt.AscendingOrder)

        # populate class list
        self.class_model = SEToolsListModel(self)
        self.class_model.item_list = sorted(self.policy.classes())
        self.tclass.setModel(self.class_model)

        # these two lists have empty string as their first item
        # (in the .ui file):
        # populate default value list
        for i, e in enumerate(DefaultValue, start=1):
            self.default_value.insertItem(i, e.name, e)

        # populate default range value list
        for i, e in enumerate(DefaultRangeValue, start=1):
            self.default_range_value.insertItem(i, e.name, e)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.defaultquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.default_range_value.setEnabled(self.default_range.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.default_range.toggled.connect(self.default_range_value.setEnabled)
        self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes)
        self.all_ruletypes.clicked.connect(self.set_all_ruletypes)
        self.tclass.selectionModel().selectionChanged.connect(self.set_tclass)
        self.invert_class.clicked.connect(self.invert_tclass_selection)
        self.buttonBox.clicked.connect(self.run)
Example #26
0
class TagChooser(QListView):
	changed = Signal()

	def __init__(self, db):
		super(TagChooser,self).__init__()
		self.db = db

		self.filter = u''

		self.data = QStandardItemModel()
		self.proxy = QSortFilterProxyModel()
		self.proxy.setSourceModel(self.data)
		self.setModel(self.proxy)

		self.data.itemChanged.connect(self.changed)
		for t in sorted(self.db.list_tags()):
			item = QStandardItem(t)
			item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
			item.setCheckState(Qt.Unchecked)
			self.data.appendRow(item)

	def setTags(self, tags):
		for i in range(self.data.rowCount()):
			item = self.data.item(i)
			if item.text() in tags:
				item.setCheckState(Qt.Checked)
			else:
				item.setCheckState(Qt.Unchecked)

	def selectedTags(self):
		tags = []
		for i in range(self.data.rowCount()):
			item = self.data.item(i)
			if item.checkState() == Qt.Checked:
				tags.append(item.text())
		return tags

	def matchingFiles(self):
		tags = self.selectedTags()

		if not tags:
			return []
		res = list(self.db.find_files_by_tags(tags))
		res.sort()
		return res
Example #27
0
 def __init__(self, networkAccessManager, parent=None):
     """
     Constructor
     
     @param networkAccessManager reference to the network access manager
         (QNetworkAccessManager)
     @param parent reference to the parent widget (QWidget)
     """
     super(E5NetworkMonitor, self).__init__(parent)
     self.setupUi(self)
     self.setWindowFlags(Qt.Window)
     
     self.__requestHeaders = QStandardItemModel(self)
     self.__requestHeaders.setHorizontalHeaderLabels(
         [self.tr("Name"), self.tr("Value")])
     self.requestHeadersList.setModel(self.__requestHeaders)
     self.requestHeadersList.horizontalHeader().setStretchLastSection(True)
     self.requestHeadersList.doubleClicked.connect(self.__showHeaderDetails)
     
     self.__replyHeaders = QStandardItemModel(self)
     self.__replyHeaders.setHorizontalHeaderLabels(
         [self.tr("Name"), self.tr("Value")])
     self.responseHeadersList.setModel(self.__replyHeaders)
     self.responseHeadersList.horizontalHeader().setStretchLastSection(True)
     self.responseHeadersList.doubleClicked.connect(
         self.__showHeaderDetails)
     
     self.requestsList.horizontalHeader().setStretchLastSection(True)
     self.requestsList.verticalHeader().setMinimumSectionSize(-1)
     
     self.__proxyModel = QSortFilterProxyModel(self)
     self.__proxyModel.setFilterKeyColumn(-1)
     self.searchEdit.textChanged.connect(
         self.__proxyModel.setFilterFixedString)
     
     self.removeButton.clicked.connect(self.requestsList.removeSelected)
     self.removeAllButton.clicked.connect(self.requestsList.removeAll)
     
     self.__model = E5RequestModel(networkAccessManager, self)
     self.__proxyModel.setSourceModel(self.__model)
     self.requestsList.setModel(self.__proxyModel)
     self.__proxyModel.rowsInserted.connect(
         self.requestsList.scrollToBottom)
     self.requestsList.selectionModel()\
         .currentChanged[QModelIndex, QModelIndex]\
         .connect(self.__currentChanged)
     
     fm = self.fontMetrics()
     em = fm.width("m")
     self.requestsList.horizontalHeader().resizeSection(0, em * 5)
     self.requestsList.horizontalHeader().resizeSection(1, em * 20)
     self.requestsList.horizontalHeader().resizeSection(3, em * 5)
     self.requestsList.horizontalHeader().resizeSection(4, em * 15)
     
     self.__headersDlg = None
Example #28
0
    def filterAcceptsRow(self, sourceRow, sourceParent):
        index = self.sourceModel().index(sourceRow, 0, sourceParent)
        rowCount = self.sourceModel().rowCount(index)
        accepted = QSortFilterProxyModel.filterAcceptsRow(self, sourceRow, sourceParent)

        if rowCount > 0 and not accepted:
            for row in range(rowCount):
                if self.filterAcceptsRow(row, index):
                    return True

        return accepted
Example #29
0
 def __init__(self, parent=None):
     super().__init__(parent)
     self.setEditable(True)
     self.filter = QSortFilterProxyModel(self)
     self.filter.setFilterCaseSensitivity(Qt.CaseInsensitive)
     self.filter.setSourceModel(self.model())
     self.completer = QCompleter(self.filter, self)
     self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
     self.setCompleter(self.completer)
     self.lineEdit().textEdited.connect(
         self.filter.setFilterFixedString)
     self.currentIndexChanged.connect(self._index_changed)
Example #30
0
def main():
    app = QGuiApplication(sys.argv)
    app.setApplicationName('InfiniteCopy')

    openDataBase()

    view = QQuickView()

    clipboardItemModel = ClipboardItemModel()
    clipboardItemModel.create()

    filterProxyModel = QSortFilterProxyModel()
    filterProxyModel.setSourceModel(clipboardItemModel)

    clipboard = Clipboard()
    clipboard.setFormats([
        mimeText,
        mimeHtml,
        mimePng,
        mimeSvg
        ])
    clipboard.changed.connect(clipboardItemModel.addItem)

    engine = view.engine()

    imageProvider = ClipboardItemModelImageProvider(clipboardItemModel)
    engine.addImageProvider("items", imageProvider)

    context = view.rootContext()
    context.setContextProperty('clipboardItemModel', clipboardItemModel)
    context.setContextProperty('clipboardItemModelFilterProxy', filterProxyModel)
    context.setContextProperty('clipboard', clipboard)

    view.setSource(QUrl.fromLocalFile('qml/MainWindow.qml'))
    view.setGeometry(100, 100, 400, 240)
    view.show()

    engine.quit.connect(QGuiApplication.quit)

    return app.exec_()
Example #31
0
class CookiesDialog(QDialog, Ui_CookiesDialog):
    """
    Class implementing a dialog to show all cookies.
    """
    def __init__(self, cookieJar, parent=None):
        """
        Constructor
        
        @param cookieJar reference to the cookie jar (CookieJar)
        @param parent reference to the parent widget (QWidget)
        """
        super(CookiesDialog, self).__init__(parent)
        self.setupUi(self)

        self.addButton.setEnabled(False)

        self.__cookieJar = cookieJar

        self.removeButton.clicked.connect(self.cookiesTable.removeSelected)
        self.removeAllButton.clicked.connect(self.cookiesTable.removeAll)

        self.cookiesTable.verticalHeader().hide()
        model = CookieModel(cookieJar, self)
        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setSourceModel(model)
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)
        self.cookiesTable.setModel(self.__proxyModel)
        self.cookiesTable.doubleClicked.connect(self.__showCookieDetails)
        self.cookiesTable.selectionModel().selectionChanged.connect(
            self.__tableSelectionChanged)
        self.cookiesTable.model().modelReset.connect(self.__tableModelReset)

        fm = QFontMetrics(QFont())
        height = fm.height() + fm.height() // 3
        self.cookiesTable.verticalHeader().setDefaultSectionSize(height)
        self.cookiesTable.verticalHeader().setMinimumSectionSize(-1)
        for section in range(model.columnCount()):
            header = self.cookiesTable.horizontalHeader()\
                .sectionSizeHint(section)
            if section == 0:
                header = fm.width("averagebiglonghost.averagedomain.info")
            elif section == 1:
                header = fm.width("_session_id")
            elif section == 4:
                header = fm.width(QDateTime.currentDateTime().toString(
                    Qt.LocalDate))
            buffer = fm.width("mm")
            header += buffer
            self.cookiesTable.horizontalHeader().resizeSection(section, header)
        self.cookiesTable.horizontalHeader().setStretchLastSection(True)
        self.cookiesTable.model().sort(
            self.cookiesTable.horizontalHeader().sortIndicatorSection(),
            Qt.AscendingOrder)

        self.__detailsDialog = None

    def __showCookieDetails(self, index):
        """
        Private slot to show a dialog with the cookie details.
        
        @param index index of the entry to show (QModelIndex)
        """
        if not index.isValid():
            return

        cookiesTable = self.sender()
        if cookiesTable is None:
            return

        model = cookiesTable.model()
        row = index.row()

        domain = model.data(model.index(row, 0))
        name = model.data(model.index(row, 1))
        path = model.data(model.index(row, 2))
        secure = model.data(model.index(row, 3))
        expires = model.data(model.index(row, 4)).toString("yyyy-MM-dd hh:mm")
        value = bytes(
            QByteArray.fromPercentEncoding(model.data(model.index(
                row, 5)))).decode()

        if self.__detailsDialog is None:
            from .CookieDetailsDialog import CookieDetailsDialog
            self.__detailsDialog = CookieDetailsDialog(self)
        self.__detailsDialog.setData(domain, name, path, secure, expires,
                                     value)
        self.__detailsDialog.show()

    @pyqtSlot()
    def on_addButton_clicked(self):
        """
        Private slot to add a new exception.
        """
        selection = self.cookiesTable.selectionModel().selectedRows()
        if len(selection) == 0:
            return

        from .CookiesExceptionsDialog import CookiesExceptionsDialog

        firstSelected = selection[0]
        domainSelection = firstSelected.sibling(firstSelected.row(), 0)
        domain = self.__proxyModel.data(domainSelection, Qt.DisplayRole)
        dlg = CookiesExceptionsDialog(self.__cookieJar, self)
        dlg.setDomainName(domain)
        dlg.exec_()

    def __tableSelectionChanged(self, selected, deselected):
        """
        Private slot to handle a change of selected items.
        
        @param selected selected indexes (QItemSelection)
        @param deselected deselected indexes (QItemSelection)
        """
        self.addButton.setEnabled(len(selected.indexes()) > 0)

    def __tableModelReset(self):
        """
        Private slot to handle a reset of the cookies table.
        """
        self.addButton.setEnabled(False)
Example #32
0
 def setSourceModel(self, source_model):
     try:
         self.source_model = source_model
         QSortFilterProxyModel.setSourceModel(self, self.source_model)
     except Exception as e:
         logging.exception('exception occurred')
Example #33
0
 def __init__(self, parent):
     QSortFilterProxyModel.__init__(self, parent)
     self.source_model: ExtSortFilterTableModel = None
Example #34
0
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QTableView

app = QApplication([])
window = QWidget()

# standard item model
model = QStandardItemModel(5, 3)
model.setHorizontalHeaderLabels(['ID', 'DATE', 'VALUE'])
for row, text in enumerate(['Cell', 'Fish', 'Apple', 'Ananas', 'Mango'] *
                           20000):
    item = QStandardItem(text)
    model.setItem(row, 2, item)

# filter proxy model
filter_proxy_model = QSortFilterProxyModel()
filter_proxy_model.setSourceModel(model)
filter_proxy_model.setFilterKeyColumn(2)  # third column

# line edit for filtering
layout = QVBoxLayout(window)
line_edit = QLineEdit()
line_edit.textChanged.connect(filter_proxy_model.setFilterRegExp)
layout.addWidget(line_edit)

# table view
table = QTableView()
table.setModel(filter_proxy_model)
layout.addWidget(table)

window.show()
Example #35
0
class Services(QWidget):
    """
    Klasa odpowiedzialna za widget usług
    """
    def __init__(self, parent, db):
        super(QWidget, self).__init__(parent)
        self.parent = parent
        self.proxy = QSortFilterProxyModel(self)
        self.view = QTableView()
        self.txt_nazwa = QLineEdit()
        self.txt_cena = QLineEdit()
        self.txt_czas = QLineEdit()
        self.txt_opis = QTextEdit()
        self.btn_mod = QPushButton('Modyfikuj')
        self.btn_usun = QPushButton('Usuń')
        self.id_modify = -1

        # Parametry połączenia z bazą
        self.model = QSqlTableModel(self, db)

        self.initUI()

    def initUI(self):
        """
        Inicjuje UI
        """
        self.table_init()
        self.btn_usun.setDisabled(True)
        self.btn_mod.setDisabled(True)
        self.txt_czas.setInputMask('99:00')

        # Tworzenie kontrolek
        lbl_wysz = QLabel("Wyszukaj zabieg:")
        txt_wysz = QLineEdit(self)
        btn_dodaj = QPushButton('Dodaj')
        lbl_nazwa = QLabel('Nazwa:')
        lbl_cena = QLabel('Cena:')
        lbl_czas = QLabel('Czas:')
        lbl_opis = QLabel('Opis:')

        # Tworzenie widoków
        centralbox = QHBoxLayout()
        findbox = QHBoxLayout()
        vbox = QVBoxLayout()
        groupbox = QGroupBox('Zabiegi')
        groupbox_layout = QVBoxLayout()
        button_hbox = QHBoxLayout()
        formbox = QFormLayout()

        # Metody
        self.view.clicked.connect(self.change)
        txt_wysz.textChanged.connect(self.searching)
        btn_dodaj.clicked.connect(self.add)
        self.btn_mod.clicked.connect(self.modify)
        self.btn_usun.clicked.connect(self.remove)

        # Ustawianie widoków
        findbox.addWidget(lbl_wysz)
        findbox.addWidget(txt_wysz)
        button_hbox.addWidget(btn_dodaj)
        button_hbox.addWidget(self.btn_mod)
        button_hbox.addWidget(self.btn_usun)
        formbox.addRow(lbl_nazwa, self.txt_nazwa)
        formbox.addRow(lbl_cena, self.txt_cena)
        formbox.addRow(lbl_czas, self.txt_czas)
        formbox.addRow(lbl_opis, self.txt_opis)
        groupbox_layout.addLayout(formbox)
        groupbox_layout.addLayout(button_hbox)
        groupbox.setLayout(groupbox_layout)
        vbox.addLayout(findbox)
        vbox.addWidget(groupbox)
        centralbox.addLayout(vbox)
        centralbox.addWidget(self.view)
        self.setLayout(centralbox)
        self.show()

    def table_init(self):
        """
        Inicjuje wygląd tabeli
        """
        self.model.setTable('uslugi')
        # query = QSqlQuery('SELECT uzytkownik_id, uzytkownik_nazwa, imie, nazwisko, pracownik FROM uzytkownik;')
        # self.model.setQuery(query)
        self.model.select()

        self.proxy.setSourceModel(self.model)

        naglowki = {
            'uslugi_id': 'ID',
            'nazwa': 'Nazwa',
            'cena': 'Cena',
            "czas": 'Czas',
            'Opis': 'Opis',
        }
        # Ustawianie nagłówków
        ilosc_kolumn = self.model.columnCount()
        for i in range(ilosc_kolumn):
            nazwa_kolumn = self.model.headerData(i, Qt.Horizontal)
            self.model.setHeaderData(i, Qt.Horizontal, naglowki[nazwa_kolumn])

        self.view.setSizeAdjustPolicy(
            QAbstractScrollArea.AdjustToContentsOnFirstShow)
        self.view.setSortingEnabled(True)
        self.view.setAlternatingRowColors(True)

        # Wczytanie danych
        self.view.setModel(self.proxy)
        self.view.hideColumn(0)
        self.view.sortByColumn(1, Qt.AscendingOrder)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)

    def change(self):
        """
        Metoda edytująca zaznaczone wiersze - Wstawia wartości z wierszy w odpowiednie pola
        """
        index = (self.view.selectionModel().currentIndex())
        value = index.sibling(index.row(), index.column()).data()
        self.id_modify = index.sibling(index.row(), 0).data()
        self.txt_nazwa.setText(index.sibling(index.row(), 1).data())
        self.txt_cena.setText(str(index.sibling(index.row(), 2).data()))
        self.txt_czas.setText(index.sibling(index.row(), 3).data())
        self.txt_opis.setText(index.sibling(index.row(), 4).data())

        if self.id_modify >= 0 and self.txt_nazwa.text(
        ) and self.txt_cena.text() and self.txt_czas.text():
            self.btn_mod.setEnabled(True)
            self.btn_usun.setEnabled(True)
        else:
            self.btn_usun.setDisabled(True)
            self.btn_mod.setDisabled(True)
            value.setText('')

    def if_checked(self, txt, q, val=None):
        """
        Sprawdza poprawność wprowadzonych damych.
        :param val: wartości do zapytania
        :param q: zapytanie query MySql
        :param txt: komunikat
        """
        if len(self.txt_nazwa.text()) < 3 or len(
                self.txt_cena.text()) < 1 or len(self.txt_czas.text()) < 2:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText(txt)
            msg.setWindowTitle("Popraw dane")
            msg.exec_()
            return False
        else:
            print('Trwa zmiana w bazie danych')
            if val:
                print('Połączenie')
                t = query_to_db(q, val)
                print(t)
                return t  # = polaczenie(q, val)
            else:
                print('Transakcja')
                return transaction_to_db(q)

    def add(self):
        """
        Dodaje nową usługę do bazy danych i odświeża widok.
        """
        tekst = 'Nie wprowadzono wszystkich danych'
        # Dodanie nowego użytkownika
        query = 'INSERT INTO uslugi (nazwa, cena, czas, Opis) VALUES (%s, %s, %s, %s)'
        val = (self.txt_nazwa.text(), self.txt_cena.text().replace(',', '.'),
               self.txt_czas.text(), self.txt_opis.toPlainText())

        if self.if_checked(tekst, query, val):
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Information)
            msg.setText('Dodano nową usługę')
            msg.setWindowTitle("Dodano nową usługę")
            msg.exec_()
        else:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Warning)
            msg.setText('Usługa znajduje się już w bazie')
            msg.setWindowTitle("Błąd!")
            msg.exec_()
        # Odświeżanie widoku tabeli
        self.model.select()
        self.view.reset()

    def modify(self):
        """
        Modyfikuje bazę danych
        """
        test = 'Dane zostały błędnie zmodyfikowane.'
        query = 'UPDATE uslugi SET nazwa = %s, cena = %s, czas = %s, Opis = %s WHERE uslugi_id = %s;'
        val = (self.txt_nazwa.text(), self.txt_cena.text().replace(',', '.'),
               self.txt_czas.text(), self.txt_opis.toPlainText(),
               self.id_modify)

        if self.if_checked(test, query, val):
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Information)
            msg.setText('Informacje o usłudze zostały pomyślnie zmodyfikowane')
            msg.setWindowTitle("Zmodyfikowano usługi")
            msg.exec_()
        # Odświeżanie widoku tabeli
        self.model.select()
        self.view.reset()

    def remove(self):
        """
        Usuwa dane z bazy danych
        """
        test = 'Błąd! Nie można usunąć danej usługi!'
        query2 = 'DELETE FROM wizyty WHERE uslugi_id = %s'
        query = 'DELETE FROM uslugi WHERE uslugi_id = %s'
        val = (self.id_modify, )
        query1 = 'DELETE FROM uzytkownik_usluga WHERE uslugi_id = %s'
        ret = QMessageBox.question(self, 'Usuwanie usługi',
                                   "Czy na pewno chcesz usunąć daną usługę?",
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.No)
        if ret == QMessageBox.Yes:
            if self.if_checked(test, [(query2, val), (query1, val),
                                      (query, val)]):
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Information)
                msg.setText('Usługa została usunięta')
                msg.setWindowTitle("Usunięto")
                msg.exec_()

                self.txt_nazwa.setText('')
                self.txt_cena.setText('')
                self.txt_czas.setText('')
                self.txt_opis.setText('')

        # Odświeżanie widoku tabeli
        self.model.select()
        self.view.reset()

    @pyqtSlot(str)
    def searching(self, text):
        """
        Wyszukuje po wszystkich kolumnach tabeli
        :param text:
        """
        search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
        self.proxy.setFilterRegExp(search)
        # Odpowiedzialne za kolumnę, po której filtruje
        self.proxy.setFilterKeyColumn(1)
Example #36
0
class PortconQueryTab(AnalysisTab):
    """An portcon query."""
    def __init__(self, parent, policy, perm_map):
        super(PortconQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = PortconQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)
        logging.getLogger("setools.portconquery").removeHandler(self.handler)

    def setupUi(self):
        self.load_ui("apol/portconquery.ui")

        # set up user autocompletion
        user_completion_list = [str(u) for u in self.policy.users()]
        user_completer_model = QStringListModel(self)
        user_completer_model.setStringList(sorted(user_completion_list))
        self.user_completion = QCompleter()
        self.user_completion.setModel(user_completer_model)
        self.user.setCompleter(self.user_completion)

        # set up role autocompletion
        role_completion_list = [str(r) for r in self.policy.roles()]
        role_completer_model = QStringListModel(self)
        role_completer_model.setStringList(sorted(role_completion_list))
        self.role_completion = QCompleter()
        self.role_completion.setModel(role_completer_model)
        self.role.setCompleter(self.role_completion)

        # set up type autocompletion
        type_completion_list = [str(t) for t in self.policy.types()]
        type_completer_model = QStringListModel(self)
        type_completer_model.setStringList(sorted(type_completion_list))
        self.type_completion = QCompleter()
        self.type_completion.setModel(type_completer_model)
        self.type_.setCompleter(self.type_completion)

        # setup indications of errors on source/target/default
        self.errors = set()
        self.orig_palette = self.type_.palette()
        self.error_palette = self.type_.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_ports_error()
        self.clear_user_error()
        self.clear_type_error()
        self.clear_role_error()
        self.clear_range_error()

        # populate protocol list. This has empty string as
        # the first item in the .ui file:
        for i, e in enumerate(PortconProtocol, start=1):
            self.protocol.insertItem(i, e.name.upper(), e)

        # set up results
        self.table_results_model = PortconTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.portconquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # Range criteria is available only if policy is MLS
        if not self.policy.mls:
            self.range_criteria.setEnabled(False)
            self.range_criteria.setToolTip("MLS is disabled in this policy.")
            self.range_.setToolTip("MLS is disabled in this policy.")
            self.range_exact.setToolTip("MLS is disabled in this policy.")
            self.range_overlap.setToolTip("MLS is disabled in this policy.")
            self.range_subset.setToolTip("MLS is disabled in this policy.")
            self.range_superset.setToolTip("MLS is disabled in this policy.")

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.ports.textEdited.connect(self.clear_ports_error)
        self.ports.editingFinished.connect(self.set_ports)
        self.user.textEdited.connect(self.clear_user_error)
        self.user.editingFinished.connect(self.set_user)
        self.user_regex.toggled.connect(self.set_user_regex)
        self.role.textEdited.connect(self.clear_role_error)
        self.role.editingFinished.connect(self.set_role)
        self.role_regex.toggled.connect(self.set_role_regex)
        self.type_.textEdited.connect(self.clear_type_error)
        self.type_.editingFinished.connect(self.set_type)
        self.type_regex.toggled.connect(self.set_type_regex)
        self.range_.textEdited.connect(self.clear_range_error)
        self.range_.editingFinished.connect(self.set_range)

    #
    # Ports criteria
    #
    def clear_ports_error(self):
        self.clear_criteria_error(self.ports, "Match the ports.")

    def set_ports(self):
        try:
            pending_ports = self.ports.text()
            if pending_ports:
                try:
                    ports = [int(i) for i in pending_ports.split("-")]
                except ValueError as ex:
                    raise ValueError(
                        "Enter a port number or range, e.g. 22 or 6000-6020"
                    ) from ex

                if len(ports) == 2:
                    self.query.ports = ports
                elif len(ports) == 1:
                    self.query.ports = (ports[0], ports[0])
                else:
                    raise ValueError(
                        "Enter a port number or range, e.g. 22 or 6000-6020")
            else:
                self.query.ports = (0, 0)

        except Exception as ex:
            self.log.error("Ports error: {0}".format(ex))
            self.set_criteria_error(self.ports, ex)

    #
    # User criteria
    #
    def clear_user_error(self):
        self.clear_criteria_error(self.user, "Match the user of the context.")

    def set_user(self):
        try:
            self.query.user = self.user.text()
        except Exception as ex:
            self.log.error("Context user error: {0}".format(ex))
            self.set_criteria_error(self.user, ex)

    def set_user_regex(self, state):
        self.log.debug("Setting user_regex {0}".format(state))
        self.query.user_regex = state
        self.clear_user_error()
        self.set_user()

    #
    # Role criteria
    #
    def clear_role_error(self):
        self.clear_criteria_error(self.role, "Match the role of the context.")

    def set_role(self):
        try:
            self.query.role = self.role.text()
        except Exception as ex:
            self.log.error("Context role error: {0}".format(ex))
            self.set_criteria_error(self.role, ex)

    def set_role_regex(self, state):
        self.log.debug("Setting role_regex {0}".format(state))
        self.query.role_regex = state
        self.clear_role_error()
        self.set_role()

    #
    # Type criteria
    #
    def clear_type_error(self):
        self.clear_criteria_error(self.type_, "Match the type of the context.")

    def set_type(self):
        try:
            self.query.type_ = self.type_.text()
        except Exception as ex:
            self.log.error("Context type error: {0}".format(ex))
            self.set_criteria_error(self.type_, ex)

    def set_type_regex(self, state):
        self.log.debug("Setting type_regex {0}".format(state))
        self.query.type_regex = state
        self.clear_type_error()
        self.set_type()

    #
    # Range criteria
    #
    def clear_range_error(self):
        self.clear_criteria_error(self.range_,
                                  "Match the range of the context.")

    def set_range(self):
        try:
            self.query.range_ = self.range_.text()
        except Exception as ex:
            self.log.info("Context range error: " + str(ex))
            self.set_criteria_error(self.range_, ex)

    #
    # Save/Load tab
    #
    def save(self):
        """Return a dictionary of settings."""
        if self.errors:
            raise TabFieldError("Field(s) are in error: {0}".format(" ".join(
                o.objectName() for o in self.errors)))

        settings = {}
        save_checkboxes(self, settings, [
            "criteria_expander", "notes_expander", "ports_exact",
            "ports_overlap", "ports_subset", "ports_superset", "user_regex",
            "role_regex", "type_regex", "range_exact", "range_overlap",
            "range_subset", "range_superset"
        ])
        save_lineedits(self, settings,
                       ["ports", "user", "role", "type_", "range_"])
        save_comboboxes(self, settings, ["protocol"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings, [
            "criteria_expander", "notes_expander", "ports_exact",
            "ports_overlap", "ports_subset", "ports_superset", "user_regex",
            "role_regex", "type_regex", "range_exact", "range_overlap",
            "range_subset", "range_superset"
        ])
        load_lineedits(self, settings,
                       ["ports", "user", "role", "type_", "range_"])
        load_comboboxes(self, settings, ["protocol"])
        load_textedits(self, settings, ["notes"])

    #
    # Results runner
    #
    def run(self, button):
        # right now there is only one button.
        self.query.ports_overlap = self.ports_overlap.isChecked()
        self.query.ports_subset = self.ports_subset.isChecked()
        self.query.ports_superset = self.ports_superset.isChecked()
        self.query.protocol = self.protocol.currentData(Qt.UserRole)
        self.query.range_overlap = self.range_overlap.isChecked()
        self.query.range_subset = self.range_subset.isChecked()
        self.query.range_superset = self.range_superset.isChecked()

        # start processing
        self.busy.setLabelText("Processing query...")
        self.busy.show()
        self.raw_results.clear()
        self.thread.start()

    def update_complete(self, count):
        self.log.info("{0} portcon statment(s) found.".format(count))

        # update sizes/location of result displays
        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's columns; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeColumnsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's rows; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeRowsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Moving the raw result to top; GUI may be unresponsive")
            self.busy.repaint()
            self.raw_results.moveCursor(QTextCursor.Start)

        self.busy.reset()
Example #37
0
class BreakPointViewer(QTreeView):
    """
    Class implementing the Breakpoint viewer widget.
    
    Breakpoints will be shown with all their details. They can be modified
    through the context menu of this widget.
    
    @signal sourceFile(str, int) emitted to show the source of a breakpoint
    """
    sourceFile = pyqtSignal(str, int)

    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent the parent (QWidget)
        """
        super(BreakPointViewer, self).__init__(parent)
        self.setObjectName("BreakPointViewer")

        self.__model = None

        self.setItemsExpandable(False)
        self.setRootIsDecorated(False)
        self.setAlternatingRowColors(True)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.setWindowTitle(self.tr("Breakpoints"))

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.__showContextMenu)
        self.doubleClicked.connect(self.__doubleClicked)

        self.__createPopupMenus()

        self.condHistory = []
        self.fnHistory = []
        self.fnHistory.append('')

    def setModel(self, model):
        """
        Public slot to set the breakpoint model.
        
        @param model reference to the breakpoint model (BreakPointModel)
        """
        self.__model = model

        self.sortingModel = QSortFilterProxyModel()
        self.sortingModel.setDynamicSortFilter(True)
        self.sortingModel.setSourceModel(self.__model)
        super(BreakPointViewer, self).setModel(self.sortingModel)

        header = self.header()
        header.setSortIndicator(0, Qt.AscendingOrder)
        header.setSortIndicatorShown(True)
        if qVersion() >= "5.0.0":
            header.setSectionsClickable(True)
        else:
            header.setClickable(True)

        self.setSortingEnabled(True)

        self.__layoutDisplay()

    def __layoutDisplay(self):
        """
        Private slot to perform a layout operation.
        """
        self.__resizeColumns()
        self.__resort()

    def __resizeColumns(self):
        """
        Private slot to resize the view when items get added, edited or
        deleted.
        """
        self.header().resizeSections(QHeaderView.ResizeToContents)
        self.header().setStretchLastSection(True)

    def __resort(self):
        """
        Private slot to resort the tree.
        """
        self.model().sort(self.header().sortIndicatorSection(),
                          self.header().sortIndicatorOrder())

    def __toSourceIndex(self, index):
        """
        Private slot to convert an index to a source index.
        
        @param index index to be converted (QModelIndex)
        @return mapped index (QModelIndex)
        """
        return self.sortingModel.mapToSource(index)

    def __fromSourceIndex(self, sindex):
        """
        Private slot to convert a source index to an index.
        
        @param sindex source index to be converted (QModelIndex)
        @return mapped index (QModelIndex)
        """
        return self.sortingModel.mapFromSource(sindex)

    def __setRowSelected(self, index, selected=True):
        """
        Private slot to select a complete row.
        
        @param index index determining the row to be selected (QModelIndex)
        @param selected flag indicating the action (bool)
        """
        if not index.isValid():
            return

        if selected:
            flags = QItemSelectionModel.SelectionFlags(
                QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
        else:
            flags = QItemSelectionModel.SelectionFlags(
                QItemSelectionModel.Deselect | QItemSelectionModel.Rows)
        self.selectionModel().select(index, flags)

    def __createPopupMenus(self):
        """
        Private method to generate the popup menus.
        """
        self.menu = QMenu()
        self.menu.addAction(self.tr("Add"), self.__addBreak)
        self.menu.addAction(self.tr("Edit..."), self.__editBreak)
        self.menu.addSeparator()
        self.menu.addAction(self.tr("Enable"), self.__enableBreak)
        self.menu.addAction(self.tr("Enable all"), self.__enableAllBreaks)
        self.menu.addSeparator()
        self.menu.addAction(self.tr("Disable"), self.__disableBreak)
        self.menu.addAction(self.tr("Disable all"), self.__disableAllBreaks)
        self.menu.addSeparator()
        self.menu.addAction(self.tr("Delete"), self.__deleteBreak)
        self.menu.addAction(self.tr("Delete all"), self.__deleteAllBreaks)
        self.menu.addSeparator()
        self.menu.addAction(self.tr("Goto"), self.__showSource)
        self.menu.addSeparator()
        self.menu.addAction(self.tr("Configure..."), self.__configure)

        self.backMenuActions = {}
        self.backMenu = QMenu()
        self.backMenu.addAction(self.tr("Add"), self.__addBreak)
        self.backMenuActions["EnableAll"] = \
            self.backMenu.addAction(self.tr("Enable all"),
                                    self.__enableAllBreaks)
        self.backMenuActions["DisableAll"] = \
            self.backMenu.addAction(self.tr("Disable all"),
                                    self.__disableAllBreaks)
        self.backMenuActions["DeleteAll"] = \
            self.backMenu.addAction(self.tr("Delete all"),
                                    self.__deleteAllBreaks)
        self.backMenu.aboutToShow.connect(self.__showBackMenu)
        self.backMenu.addSeparator()
        self.backMenu.addAction(self.tr("Configure..."), self.__configure)

        self.multiMenu = QMenu()
        self.multiMenu.addAction(self.tr("Add"), self.__addBreak)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.tr("Enable selected"),
                                 self.__enableSelectedBreaks)
        self.multiMenu.addAction(self.tr("Enable all"), self.__enableAllBreaks)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.tr("Disable selected"),
                                 self.__disableSelectedBreaks)
        self.multiMenu.addAction(self.tr("Disable all"),
                                 self.__disableAllBreaks)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.tr("Delete selected"),
                                 self.__deleteSelectedBreaks)
        self.multiMenu.addAction(self.tr("Delete all"), self.__deleteAllBreaks)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.tr("Configure..."), self.__configure)

    def __showContextMenu(self, coord):
        """
        Private slot to show the context menu.
        
        @param coord the position of the mouse pointer (QPoint)
        """
        cnt = self.__getSelectedItemsCount()
        if cnt <= 1:
            index = self.indexAt(coord)
            if index.isValid():
                cnt = 1
                self.__setRowSelected(index)
        coord = self.mapToGlobal(coord)
        if cnt > 1:
            self.multiMenu.popup(coord)
        elif cnt == 1:
            self.menu.popup(coord)
        else:
            self.backMenu.popup(coord)

    def __clearSelection(self):
        """
        Private slot to clear the selection.
        """
        for index in self.selectedIndexes():
            self.__setRowSelected(index, False)

    def __addBreak(self):
        """
        Private slot to handle the add breakpoint context menu entry.
        """
        from .EditBreakpointDialog import EditBreakpointDialog

        dlg = EditBreakpointDialog((self.fnHistory[0], None),
                                   None,
                                   self.condHistory,
                                   self,
                                   modal=1,
                                   addMode=1,
                                   filenameHistory=self.fnHistory)
        if dlg.exec_() == QDialog.Accepted:
            fn, line, cond, temp, enabled, count = dlg.getAddData()
            if fn is not None:
                if fn in self.fnHistory:
                    self.fnHistory.remove(fn)
                self.fnHistory.insert(0, fn)

            if cond:
                if cond in self.condHistory:
                    self.condHistory.remove(cond)
                self.condHistory.insert(0, cond)

            self.__model.addBreakPoint(fn, line, (cond, temp, enabled, count))
            self.__resizeColumns()
            self.__resort()

    def __doubleClicked(self, index):
        """
        Private slot to handle the double clicked signal.
        
        @param index index of the entry that was double clicked (QModelIndex)
        """
        if index.isValid():
            self.__editBreakpoint(index)

    def __editBreak(self):
        """
        Private slot to handle the edit breakpoint context menu entry.
        """
        index = self.currentIndex()
        if index.isValid():
            self.__editBreakpoint(index)

    def __editBreakpoint(self, index):
        """
        Private slot to edit a breakpoint.
        
        @param index index of breakpoint to be edited (QModelIndex)
        """
        sindex = self.__toSourceIndex(index)
        if sindex.isValid():
            bp = self.__model.getBreakPointByIndex(sindex)
            if not bp:
                return

            fn, line, cond, temp, enabled, count = bp[:6]

            from .EditBreakpointDialog import EditBreakpointDialog
            dlg = EditBreakpointDialog((fn, line),
                                       (cond, temp, enabled, count),
                                       self.condHistory,
                                       self,
                                       modal=True)
            if dlg.exec_() == QDialog.Accepted:
                cond, temp, enabled, count = dlg.getData()
                if cond:
                    if cond in self.condHistory:
                        self.condHistory.remove(cond)
                    self.condHistory.insert(0, cond)

                self.__model.setBreakPointByIndex(sindex, fn, line,
                                                  (cond, temp, enabled, count))
                self.__resizeColumns()
                self.__resort()

    def __setBpEnabled(self, index, enabled):
        """
        Private method to set the enabled status of a breakpoint.
        
        @param index index of breakpoint to be enabled/disabled (QModelIndex)
        @param enabled flag indicating the enabled status to be set (boolean)
        """
        sindex = self.__toSourceIndex(index)
        if sindex.isValid():
            self.__model.setBreakPointEnabledByIndex(sindex, enabled)

    def __enableBreak(self):
        """
        Private slot to handle the enable breakpoint context menu entry.
        """
        index = self.currentIndex()
        self.__setBpEnabled(index, True)
        self.__resizeColumns()
        self.__resort()

    def __enableAllBreaks(self):
        """
        Private slot to handle the enable all breakpoints context menu entry.
        """
        index = self.model().index(0, 0)
        while index.isValid():
            self.__setBpEnabled(index, True)
            index = self.indexBelow(index)
        self.__resizeColumns()
        self.__resort()

    def __enableSelectedBreaks(self):
        """
        Private slot to handle the enable selected breakpoints context menu
        entry.
        """
        for index in self.selectedIndexes():
            if index.column() == 0:
                self.__setBpEnabled(index, True)
        self.__resizeColumns()
        self.__resort()

    def __disableBreak(self):
        """
        Private slot to handle the disable breakpoint context menu entry.
        """
        index = self.currentIndex()
        self.__setBpEnabled(index, False)
        self.__resizeColumns()
        self.__resort()

    def __disableAllBreaks(self):
        """
        Private slot to handle the disable all breakpoints context menu entry.
        """
        index = self.model().index(0, 0)
        while index.isValid():
            self.__setBpEnabled(index, False)
            index = self.indexBelow(index)
        self.__resizeColumns()
        self.__resort()

    def __disableSelectedBreaks(self):
        """
        Private slot to handle the disable selected breakpoints context menu
        entry.
        """
        for index in self.selectedIndexes():
            if index.column() == 0:
                self.__setBpEnabled(index, False)
        self.__resizeColumns()
        self.__resort()

    def __deleteBreak(self):
        """
        Private slot to handle the delete breakpoint context menu entry.
        """
        index = self.currentIndex()
        sindex = self.__toSourceIndex(index)
        if sindex.isValid():
            self.__model.deleteBreakPointByIndex(sindex)

    def __deleteAllBreaks(self):
        """
        Private slot to handle the delete all breakpoints context menu entry.
        """
        self.__model.deleteAll()

    def __deleteSelectedBreaks(self):
        """
        Private slot to handle the delete selected breakpoints context menu
        entry.
        """
        idxList = []
        for index in self.selectedIndexes():
            sindex = self.__toSourceIndex(index)
            if sindex.isValid() and index.column() == 0:
                idxList.append(sindex)
        self.__model.deleteBreakPoints(idxList)

    def __showSource(self):
        """
        Private slot to handle the goto context menu entry.
        """
        index = self.currentIndex()
        sindex = self.__toSourceIndex(index)
        bp = self.__model.getBreakPointByIndex(sindex)
        if not bp:
            return

        fn, line = bp[:2]
        self.sourceFile.emit(fn, line)

    def highlightBreakpoint(self, fn, lineno):
        """
        Public slot to handle the clientLine signal.
        
        @param fn filename of the breakpoint (string)
        @param lineno line number of the breakpoint (integer)
        """
        sindex = self.__model.getBreakPointIndex(fn, lineno)
        if sindex.isValid():
            return

        index = self.__fromSourceIndex(sindex)
        if index.isValid():
            self.__clearSelection()
            self.__setRowSelected(index, True)

    def handleResetUI(self):
        """
        Public slot to reset the breakpoint viewer.
        """
        self.__clearSelection()

    def __showBackMenu(self):
        """
        Private slot to handle the aboutToShow signal of the background menu.
        """
        if self.model().rowCount() == 0:
            self.backMenuActions["EnableAll"].setEnabled(False)
            self.backMenuActions["DisableAll"].setEnabled(False)
            self.backMenuActions["DeleteAll"].setEnabled(False)
        else:
            self.backMenuActions["EnableAll"].setEnabled(True)
            self.backMenuActions["DisableAll"].setEnabled(True)
            self.backMenuActions["DeleteAll"].setEnabled(True)

    def __getSelectedItemsCount(self):
        """
        Private method to get the count of items selected.
        
        @return count of items selected (integer)
        """
        count = len(self.selectedIndexes()) // (self.__model.columnCount() - 1)
        # column count is 1 greater than selectable
        return count

    def __configure(self):
        """
        Private method to open the configuration dialog.
        """
        e5App().getObject("UserInterface").showPreferences(
            "debuggerGeneralPage")
Example #38
0
class TERuleQueryTab(AnalysisTab):
    """A Type Enforcement rule query."""
    def __init__(self, parent, policy, perm_map):
        super(TERuleQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = TERuleQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)
        logging.getLogger("setools.terulequery").removeHandler(self.handler)

    def setupUi(self):
        self.load_ui("apol/terulequery.ui")

        # set up source/target autocompletion
        typeattr_completion_list = [str(t) for t in self.policy.types()]
        typeattr_completion_list.extend(
            str(a) for a in self.policy.typeattributes())
        typeattr_completer_model = QStringListModel(self)
        typeattr_completer_model.setStringList(
            sorted(typeattr_completion_list))
        self.typeattr_completion = QCompleter()
        self.typeattr_completion.setModel(typeattr_completer_model)
        self.source.setCompleter(self.typeattr_completion)
        self.target.setCompleter(self.typeattr_completion)

        # set up default autocompletion
        type_completion_list = [str(t) for t in self.policy.types()]
        type_completer_model = QStringListModel(self)
        type_completer_model.setStringList(sorted(type_completion_list))
        self.type_completion = QCompleter()
        self.type_completion.setModel(type_completer_model)
        self.default_type.setCompleter(self.type_completion)

        # setup indications of errors on source/target/default
        self.errors = set()
        self.orig_palette = self.source.palette()
        self.error_palette = self.source.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_source_error()
        self.clear_target_error()
        self.clear_default_error()
        self.clear_xperm_error()

        # populate class list
        self.class_model = SEToolsListModel(self)
        self.class_model.item_list = sorted(self.policy.classes())
        self.tclass.setModel(self.class_model)

        # populate perm list
        self.perms_model = PermListModel(self, self.policy)
        self.perms.setModel(self.perms_model)

        # populate bool list
        self.bool_model = SEToolsListModel(self)
        self.bool_model.item_list = sorted(self.policy.bools())
        self.bool_criteria.setModel(self.bool_model)

        # set up results
        self.table_results_model = TERuleTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.terulequery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_source_regex(self.source_regex.isChecked())
        self.set_target_regex(self.target_regex.isChecked())
        self.set_default_regex(self.default_regex.isChecked())
        self.toggle_xperm_criteria()
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.allowxperm.toggled.connect(self.toggle_xperm_criteria)
        self.auditallowxperm.toggled.connect(self.toggle_xperm_criteria)
        self.neverallowxperm.toggled.connect(self.toggle_xperm_criteria)
        self.dontauditxperm.toggled.connect(self.toggle_xperm_criteria)
        self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes)
        self.all_ruletypes.clicked.connect(self.set_all_ruletypes)
        self.source.textEdited.connect(self.clear_source_error)
        self.source.editingFinished.connect(self.set_source)
        self.source_regex.toggled.connect(self.set_source_regex)
        self.target.textEdited.connect(self.clear_target_error)
        self.target.editingFinished.connect(self.set_target)
        self.target_regex.toggled.connect(self.set_target_regex)
        self.tclass.selectionModel().selectionChanged.connect(self.set_tclass)
        self.invert_class.clicked.connect(self.invert_tclass_selection)
        self.perms.selectionModel().selectionChanged.connect(self.set_perms)
        self.invert_perms.clicked.connect(self.invert_perms_selection)
        self.xperms.textEdited.connect(self.clear_xperm_error)
        self.xperms.editingFinished.connect(self.set_xperm)
        self.default_type.textEdited.connect(self.clear_default_error)
        self.default_type.editingFinished.connect(self.set_default_type)
        self.default_regex.toggled.connect(self.set_default_regex)
        self.bool_criteria.selectionModel().selectionChanged.connect(
            self.set_bools)

    #
    # Ruletype criteria
    #

    def _set_ruletypes(self, value):
        self.allow.setChecked(value)
        self.allowxperm.setChecked(value)
        self.auditallow.setChecked(value)
        self.auditallowxperm.setChecked(value)
        self.neverallow.setChecked(value)
        self.neverallowxperm.setChecked(value)
        self.dontaudit.setChecked(value)
        self.dontauditxperm.setChecked(value)
        self.type_transition.setChecked(value)
        self.type_member.setChecked(value)
        self.type_change.setChecked(value)

    def set_all_ruletypes(self):
        self._set_ruletypes(True)

    def clear_all_ruletypes(self):
        self._set_ruletypes(False)

    #
    # Source criteria
    #

    def clear_source_error(self):
        self.clear_criteria_error(
            self.source, "Match the source type/attribute of the rule.")

    def set_source(self):
        try:
            self.query.source = self.source.text()
        except Exception as ex:
            self.log.error("Source type/attribute error: {0}".format(ex))
            self.set_criteria_error(self.source, ex)

    def set_source_regex(self, state):
        self.log.debug("Setting source_regex {0}".format(state))
        self.query.source_regex = state
        self.clear_source_error()
        self.set_source()

    #
    # Target criteria
    #

    def clear_target_error(self):
        self.clear_criteria_error(
            self.target, "Match the target type/attribute of the rule.")

    def set_target(self):
        try:
            self.query.target = self.target.text()
        except Exception as ex:
            self.log.error("Target type/attribute error: {0}".format(ex))
            self.set_criteria_error(self.target, ex)

    def set_target_regex(self, state):
        self.log.debug("Setting target_regex {0}".format(state))
        self.query.target_regex = state
        self.clear_target_error()
        self.set_target()

    #
    # Class criteria
    #

    def set_tclass(self):
        selected_classes = []
        for index in self.tclass.selectionModel().selectedIndexes():
            selected_classes.append(self.class_model.data(index, Qt.UserRole))

        self.query.tclass = selected_classes
        self.perms_model.set_classes(selected_classes)

    def invert_tclass_selection(self):
        invert_list_selection(self.tclass.selectionModel())

    #
    # Permissions criteria
    #

    def set_perms(self):
        selected_perms = []
        for index in self.perms.selectionModel().selectedIndexes():
            selected_perms.append(self.perms_model.data(index, Qt.UserRole))

        self.query.perms = selected_perms

    def invert_perms_selection(self):
        invert_list_selection(self.perms.selectionModel())

    #
    # Extended permission criteria
    #
    def toggle_xperm_criteria(self):
        mode = any(
            (self.allowxperm.isChecked(), self.auditallowxperm.isChecked(),
             self.neverallowxperm.isChecked(),
             self.dontauditxperm.isChecked()))

        self.xperms.setEnabled(mode)
        self.xperms_equal.setEnabled(mode)

    def clear_xperm_error(self):
        self.clear_criteria_error(
            self.xperms, "Match the extended permissions of the rule. "
            "Comma-separated permissions or ranges of permissions.")

    def set_xperm(self):
        try:
            text = self.xperms.text()

            if text:
                self.query.xperms = xperm_str_to_tuple_ranges(text)
            else:
                self.query.xperms = None

        except Exception as ex:
            self.log.error("Extended permissions error: {0}".format(ex))
            self.set_criteria_error(self.xperms, ex)

    #
    # Default criteria
    #

    def clear_default_error(self):
        self.clear_criteria_error(self.default_type,
                                  "Match the default type the rule.")

    def set_default_type(self):
        self.query.default_regex = self.default_regex.isChecked()

        try:
            self.query.default = self.default_type.text()
        except Exception as ex:
            self.log.error("Default type error: {0}".format(ex))
            self.set_criteria_error(self.default_type, ex)

    def set_default_regex(self, state):
        self.log.debug("Setting default_regex {0}".format(state))
        self.query.default_regex = state
        self.clear_default_error()
        self.set_default_type()

    #
    # Boolean criteria
    #

    def set_bools(self):
        selected_bools = []
        for index in self.bool_criteria.selectionModel().selectedIndexes():
            selected_bools.append(self.bool_model.data(index, Qt.UserRole))

        self.query.boolean = selected_bools

    #
    # Save/Load tab
    #
    def save(self):
        """Return a dictionary of settings."""
        if self.errors:
            raise TabFieldError("Field(s) are in error: {0}".format(" ".join(
                o.objectName() for o in self.errors)))

        settings = {}
        save_checkboxes(self, settings, [
            "criteria_expander", "notes_expander", "allow", "allowxperm",
            "auditallow", "auditallowxperm", "neverallow", "neverallowxperm",
            "dontaudit", "dontauditxperm", "type_transition", "type_change",
            "type_member", "source_indirect", "source_regex",
            "target_indirect", "target_regex", "perms_subset", "xperms_equal",
            "default_regex", "bools_equal"
        ])
        save_lineedits(self, settings,
                       ["source", "target", "xperms", "default_type"])
        save_listviews(self, settings, ["tclass", "perms", "bool_criteria"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings, [
            "allow", "allowxperm", "auditallow", "auditallowxperm",
            "neverallow", "neverallowxperm", "dontaudit", "dontauditxperm",
            "type_transition", "type_change", "type_member",
            "criteria_expander", "notes_expander", "source_indirect",
            "source_regex", "target_indirect", "target_regex", "perms_subset",
            "xperms_equal", "default_regex", "bools_equal"
        ])
        load_lineedits(self, settings,
                       ["source", "target", "xperms", "default_type"])
        load_listviews(self, settings, ["tclass", "perms", "bool_criteria"])
        load_textedits(self, settings, ["notes"])

    #
    # Results runner
    #

    def run(self, button):
        # right now there is only one button.
        rule_types = []
        max_results = 0

        if self.allow.isChecked():
            rule_types.append("allow")
            max_results += self.policy.allow_count
        if self.allowxperm.isChecked():
            rule_types.append("allowxperm")
            max_results += self.policy.allowxperm_count
        if self.auditallow.isChecked():
            rule_types.append("auditallow")
            max_results += self.policy.auditallow_count
        if self.auditallowxperm.isChecked():
            rule_types.append("auditallowxperm")
            max_results += self.policy.auditallowxperm_count
        if self.neverallow.isChecked():
            rule_types.append("neverallow")
            max_results += self.policy.neverallow_count
        if self.neverallowxperm.isChecked():
            rule_types.append("neverallowxperm")
            max_results += self.policy.neverallowxperm_count
        if self.dontaudit.isChecked():
            rule_types.append("dontaudit")
            max_results += self.policy.dontaudit_count
        if self.dontauditxperm.isChecked():
            rule_types.append("dontauditxperm")
            max_results += self.policy.dontauditxperm_count
        if self.type_transition.isChecked():
            rule_types.append("type_transition")
            max_results += self.policy.type_transition_count
        if self.type_member.isChecked():
            rule_types.append("type_member")
            max_results += self.policy.type_member_count
        if self.type_change.isChecked():
            rule_types.append("type_change")
            max_results += self.policy.type_change_count

        self.query.ruletype = rule_types
        self.query.source_indirect = self.source_indirect.isChecked()
        self.query.target_indirect = self.target_indirect.isChecked()
        self.query.perms_subset = self.perms_subset.isChecked()
        self.query.boolean_equal = self.bools_equal.isChecked()

        # if query is broad, show warning.
        if not any((self.query.source, self.query.target, self.query.tclass, self.query.perms,
                    self.query.xperms, self.query.default, self.query.boolean)) \
                and max_results > 1000:

            reply = QMessageBox.question(
                self, "Continue?",
                "This is a broad query, estimated to return {0} results.  Continue?"
                .format(max_results), QMessageBox.Yes | QMessageBox.No)

            if reply == QMessageBox.No:
                return

        # start processing
        self.busy.setLabelText("Processing query...")
        self.busy.show()
        self.raw_results.clear()
        self.thread.start()

    def update_complete(self, count):
        self.log.info("{0} type enforcement rule(s) found.".format(count))

        # update sizes/location of result displays
        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's columns; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeColumnsToContents()
            # If the permissions column width is too long, pull back
            # to a reasonable size
            header = self.table_results.horizontalHeader()
            if header.sectionSize(4) > 400:
                header.resizeSection(4, 400)

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's rows; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeRowsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Moving the raw result to top; GUI may be unresponsive")
            self.busy.repaint()
            self.raw_results.moveCursor(QTextCursor.Start)

        self.busy.reset()
Example #39
0
    def setupUi(self):
        self.load_ui("apol/rbacrulequery.ui")

        # set up role autocompletion (source, default)
        role_completion_list = [str(r) for r in self.policy.roles()]
        role_completer_model = QStringListModel(self)
        role_completer_model.setStringList(sorted(role_completion_list))
        self.role_completion = QCompleter()
        self.role_completion.setModel(role_completer_model)
        self.source.setCompleter(self.role_completion)
        self.default_role.setCompleter(self.role_completion)

        # set up role/type autocompletion (target)
        roletype_completion_list = [str(r) for r in self.policy.roles()]
        # roletype_completion_list.extend(str(a) for a in self.policy.roleattributes())
        roletype_completion_list.extend(str(t) for t in self.policy.types())
        roletype_completion_list.extend(
            str(a) for a in self.policy.typeattributes())
        roletype_completer_model = QStringListModel(self)
        roletype_completer_model.setStringList(
            sorted(roletype_completion_list))
        self.roletype_completion = QCompleter()
        self.roletype_completion.setModel(roletype_completer_model)
        self.target.setCompleter(self.roletype_completion)

        # setup indications of errors on source/target/default
        self.errors = set()
        self.orig_palette = self.source.palette()
        self.error_palette = self.source.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_source_error()
        self.clear_target_error()
        self.clear_default_error()

        # populate class list
        self.class_model = SEToolsListModel(self)
        self.class_model.item_list = sorted(self.policy.classes())
        self.tclass.setModel(self.class_model)

        # set up results
        self.table_results_model = RBACRuleTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.rbacrulequery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_source_regex(self.source_regex.isChecked())
        self.set_target_regex(self.target_regex.isChecked())
        self.set_default_regex(self.default_regex.isChecked())
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes)
        self.all_ruletypes.clicked.connect(self.set_all_ruletypes)
        self.source.textEdited.connect(self.clear_source_error)
        self.source.editingFinished.connect(self.set_source)
        self.source_regex.toggled.connect(self.set_source_regex)
        self.target.textEdited.connect(self.clear_target_error)
        self.target.editingFinished.connect(self.set_target)
        self.target_regex.toggled.connect(self.set_target_regex)
        self.tclass.selectionModel().selectionChanged.connect(self.set_tclass)
        self.invert_class.clicked.connect(self.invert_tclass_selection)
        self.default_role.textEdited.connect(self.clear_default_error)
        self.default_role.editingFinished.connect(self.set_default_role)
        self.default_regex.toggled.connect(self.set_default_regex)
Example #40
0
class CustomerDialog(QDialog):
    def __init__(self):
        super(CustomerDialog, self).__init__()

        self.all_customers = Customer.objects.all()
        self.customer_fields = ['Id', 'Name', 'CIN']
        self.customers_model = QStandardItemModel(len(self.all_customers), 3)
        self.customers_model.setHorizontalHeaderLabels(self.customer_fields)

        self.customers_filter_proxy_model = QSortFilterProxyModel()
        self.customers_filter_proxy_model.setSourceModel(self.customers_model)
        self.selected_customer = ""

        self.ui = Ui_CustomerWidget()
        self.ui.setupUi(self)

        self.ui.lineEdit.textChanged.connect(self.customers_filter_proxy_model.setFilterRegExp)
        self.ui.CustomersList.setModel(self.customers_filter_proxy_model)

        self.populate_customers_list()

    def populate_customers_list(self):
        self.populate_customer_model()

        self.customers_filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.customers_filter_proxy_model.setFilterKeyColumn(1)

        self.ui.lineEdit.textChanged.connect(self.customers_filter_proxy_model.setFilterRegExp)
        self.ui.CustomersList.setModel(self.customers_filter_proxy_model)

        selection_model = self.ui.CustomersList.selectionModel()
        selection_model.selectionChanged.connect(self.on_customer_selectionChanged)

    def populate_customer_model(self):
        for row, customer in enumerate(self.all_customers):
            pid = QStandardItem(str(customer.id))
            name = QStandardItem(str(customer.get_full_name()))
            id_number = QStandardItem(str(customer.id_number))
            # code = QStandardItem(str(customer.code))

            self.customers_model.setItem(row, 0, pid)
            self.customers_model.setItem(row, 1, name)
            self.customers_model.setItem(row, 2, id_number)
            # self.product_model.setItem(row, 3, code)

    @pyqtSlot('QItemSelection', 'QItemSelection')
    def on_customer_selectionChanged(self, selected):
        item = selected.indexes()
        if item:
            pid = self.selected_customer = item[0].data()
            self.selected_customer = Customer.objects.get(pk=pid)
            self.populate_customer_info(self.selected_customer)

    def populate_customer_info(self, customer):
        # GENERAL INFO
        self.ui.label_32.setText(customer.salutation)
        self.ui.label_33.setText(customer.address.__str__())

        # INVOICING INFO
        self.ui.label_7.setText(customer.get_full_name())

        # SALES INFO
        self.ui.label_17.setText(customer.salutation)
        self.ui.label_18.setText(customer.address.__str__())
Example #41
0
class DictionaryEditorWidget(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent

        self.pyboDict = dict()
        self.initPyboDict()

        self.tokens = []
        self.resize(400, 600)
        self.setWindowTitle('Dictionary Editor')
        self.setupTable()
        self.initUI()

    def getDict(self):
        mergedDict = self.pyboDict.copy()
        # mergedDict = {'ཉམ་ཐག་པ': 'VERB'}

        for token in Token.objects.all():
            if token.type == Token.TYPE_UPDATE:
                mergedDict[token.text] = token.pos
            else:  # Dict.ACTION_DELETE
                del mergedDict[token.text]

        return mergedDict

    def setupTable(self):
        dict = self.getDict()
        self.model = TableModel(parent=self,
                                header=('Text', 'Tag'),
                                data=[[k, v] for k, v in dict.items()])

        # print(self.model.bt.has_word('ནང་ཆོས་'))

        self.proxyModel = QSortFilterProxyModel()
        self.proxyModel.eventFilter = lambda: self.removeButton.setDisabled(
            True)

        self.proxyModel.setSourceModel(self.model)

        self.tableView = QTableView()
        self.tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        self.tableView.setFixedHeight(500)
        self.tableView.setModel(self.proxyModel)

    def initUI(self):
        self.searchLabel = QLabel()
        self.searchLabel.setPixmap(
            QIcon(os.path.join(BASE_DIR, 'icons',
                               'searching.png')).pixmap(QSize(20, 20)))

        self.searchField = QLineEdit()
        self.searchField.textChanged.connect(self.search)

        hbox = QHBoxLayout()
        hbox.addWidget(self.searchLabel)
        hbox.addWidget(self.searchField)

        self.addButton = QPushButton()
        self.addButton.setFlat(True)
        self.addButton.setIcon(
            QIcon(os.path.join(BASE_DIR, 'icons', 'add.png')))
        self.addButton.setIconSize(QSize(30, 30))
        self.addButton.clicked.connect(self.addWord)

        self.removeButton = QPushButton()
        self.removeButton.setFlat(True)
        self.removeButton.setIcon(
            QIcon(os.path.join(BASE_DIR, "icons", "delete.png")))
        self.removeButton.setIconSize(QSize(30, 30))
        self.removeButton.clicked.connect(self.removeWord)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.addButton)
        hbox2.addStretch()
        hbox2.addWidget(self.removeButton)

        self.fbox = QFormLayout()
        self.fbox.addRow(hbox)
        self.fbox.addRow(hbox2)
        self.fbox.addRow(self.tableView)

        self.setLayout(self.fbox)

    def search(self, text):
        self.proxyModel.setFilterKeyColumn(-1)  # -1 means all cols
        self.proxyModel.setFilterFixedString(text)

    def initPyboDict(self):
        # import pkg_resources
        # resourcePkg = 'pybo'
        # resourcePath = '/'.join(('resources', 'lexica_bo', 'Tibetan.DICT'))
        # reader = pkg_resources.resource_stream(resourcePkg, resourcePath)

        resourcePath = os.path.join(BASE_DIR, 'resources', 'dictionaries',
                                    'lexica_bo', 'Tibetan.DICT')
        reader = open(resourcePath, mode="r", encoding="utf-8", newline="")
        file = reader.read()

        for line in file.splitlines():
            key, val = line.split()
            self.pyboDict[key] = val

        # file.decode()
        reader.close()

    def removeWord(self):
        rows = sorted(
            set(index.row() for index in
                self.tableView.selectionModel().selectedIndexes()))
        for row in reversed(rows):
            self.model.data.pop(row)
        self.model.saveDict()

    def addWord(self, text=None):
        if text is not None:
            self.model.data.insert(0, [text, ''])
        else:
            self.model.data.insert(0, ['', ''])
        self.model.layoutChanged.emit()

    def getAllTags(self):
        return set(self.getDict().values())
Example #42
0
class ListWidget(QWidget):
    deviceSelected = pyqtSignal(TasmotaDevice)
    openRulesEditor = pyqtSignal()
    openConsole = pyqtSignal()
    openTelemetry = pyqtSignal()
    openWebUI = pyqtSignal()

    def __init__(self, parent, *args, **kwargs):
        super(ListWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle("Devices list")
        self.setWindowState(Qt.WindowMaximized)
        self.setLayout(VLayout(margin=0, spacing=0))

        self.mqtt = parent.mqtt
        self.env = parent.env

        self.device = None
        self.idx = None

        self.nam = QNetworkAccessManager()
        self.backup = bytes()

        self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()), QSettings.IniFormat)
        views_order = self.settings.value("views_order", [])

        self.views = {}
        self.settings.beginGroup("Views")
        views = self.settings.childKeys()
        if views and views_order:
            for view in views_order.split(";"):
                view_list = self.settings.value(view).split(";")
                self.views[view] = base_view + view_list
        else:
            self.views = default_views
        self.settings.endGroup()

        self.tb = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonTextBesideIcon)
        self.tb_relays = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonIconOnly)
        # self.tb_filter = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonTextBesideIcon)
        self.tb_views = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonTextBesideIcon)

        self.pwm_sliders = []

        self.layout().addWidget(self.tb)
        self.layout().addWidget(self.tb_relays)
        # self.layout().addWidget(self.tb_filter)

        self.device_list = TableView()
        self.device_list.setIconSize(QSize(24, 24))
        self.model = parent.device_model
        self.model.setupColumns(self.views["Home"])

        self.sorted_device_model = QSortFilterProxyModel()
        self.sorted_device_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.sorted_device_model.setSourceModel(parent.device_model)
        self.sorted_device_model.setSortRole(Qt.InitialSortOrderRole)
        self.sorted_device_model.setSortLocaleAware(True)
        self.sorted_device_model.setFilterKeyColumn(-1)

        self.device_list.setModel(self.sorted_device_model)
        self.device_list.setupView(self.views["Home"])
        self.device_list.setSortingEnabled(True)
        self.device_list.setWordWrap(True)
        self.device_list.setItemDelegate(DeviceDelegate())
        self.device_list.sortByColumn(self.model.columnIndex("FriendlyName"), Qt.AscendingOrder)
        self.device_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.device_list.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.layout().addWidget(self.device_list)

        self.layout().addWidget(self.tb_views)

        self.device_list.clicked.connect(self.select_device)
        self.device_list.customContextMenuRequested.connect(self.show_list_ctx_menu)

        self.ctx_menu = QMenu()

        self.create_actions()
        self.create_view_buttons()
        # self.create_view_filter()

        self.device_list.doubleClicked.connect(lambda: self.openConsole.emit())

    def create_actions(self):
        actConsole = self.tb.addAction(QIcon("GUI/icons/console.png"), "Console", self.openConsole.emit)
        actConsole.setShortcut("Ctrl+E")

        actRules = self.tb.addAction(QIcon("GUI/icons/rules.png"), "Rules", self.openRulesEditor.emit)
        actRules.setShortcut("Ctrl+R")

        actTimers = self.tb.addAction(QIcon("GUI/icons/timers.png"), "Timers", self.configureTimers)

        actButtons = self.tb.addAction(QIcon("GUI/icons/buttons.png"), "Buttons", self.configureButtons)
        actButtons.setShortcut("Ctrl+B")

        actSwitches = self.tb.addAction(QIcon("GUI/icons/switches.png"), "Switches", self.configureSwitches)
        actSwitches.setShortcut("Ctrl+S")

        actPower = self.tb.addAction(QIcon("GUI/icons/power.png"), "Power", self.configurePower)
        actPower.setShortcut("Ctrl+P")

        # setopts = self.tb.addAction(QIcon("GUI/icons/setoptions.png"), "SetOptions", self.configureSO)
        # setopts.setShortcut("Ctrl+S")

        self.tb.addSpacer()

        actTelemetry = self.tb.addAction(QIcon("GUI/icons/telemetry.png"), "Telemetry", self.openTelemetry.emit)
        actTelemetry.setShortcut("Ctrl+T")

        actWebui = self.tb.addAction(QIcon("GUI/icons/web.png"), "WebUI", self.openWebUI.emit)
        actWebui.setShortcut("Ctrl+U")

        self.ctx_menu.addActions([actRules, actTimers, actButtons, actSwitches, actPower, actTelemetry, actWebui])
        self.ctx_menu.addSeparator()

        self.ctx_menu_cfg = QMenu("Configure")
        self.ctx_menu_cfg.setIcon(QIcon("GUI/icons/settings.png"))
        self.ctx_menu_cfg.addAction("Module", self.configureModule)
        self.ctx_menu_cfg.addAction("GPIO", self.configureGPIO)
        self.ctx_menu_cfg.addAction("Template", self.configureTemplate)
        # self.ctx_menu_cfg.addAction("Wifi", self.ctx_menu_teleperiod)
        # self.ctx_menu_cfg.addAction("Time", self.cfgTime.emit)
        # self.ctx_menu_cfg.addAction("MQTT", self.ctx_menu_teleperiod)

        # self.ctx_menu_cfg.addAction("Logging", self.ctx_menu_teleperiod)

        self.ctx_menu.addMenu(self.ctx_menu_cfg)
        self.ctx_menu.addSeparator()

        self.ctx_menu.addAction(QIcon("GUI/icons/refresh.png"), "Refresh", self.ctx_menu_refresh)

        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/clear.png"), "Clear retained", self.ctx_menu_clear_retained)
        self.ctx_menu.addAction("Clear Backlog", self.ctx_menu_clear_backlog)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/copy.png"), "Copy", self.ctx_menu_copy)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/restart.png"), "Restart", self.ctx_menu_restart)
        self.ctx_menu.addAction(QIcon(), "Reset", self.ctx_menu_reset)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/delete.png"), "Delete", self.ctx_menu_delete_device)

        # self.tb.addAction(QIcon(), "Multi Command", self.ctx_menu_webui)

        self.agAllPower = QActionGroup(self)
        self.agAllPower.addAction(QIcon("GUI/icons/P_ON.png"), "All ON")
        self.agAllPower.addAction(QIcon("GUI/icons/P_OFF.png"), "All OFF")
        self.agAllPower.setEnabled(False)
        self.agAllPower.setExclusive(False)
        self.agAllPower.triggered.connect(self.toggle_power_all)
        self.tb_relays.addActions(self.agAllPower.actions())

        self.agRelays = QActionGroup(self)
        self.agRelays.setVisible(False)
        self.agRelays.setExclusive(False)

        for a in range(1, 9):
            act = QAction(QIcon("GUI/icons/P{}_OFF.png".format(a)), "")
            act.setShortcut("F{}".format(a))
            self.agRelays.addAction(act)

        self.agRelays.triggered.connect(self.toggle_power)
        self.tb_relays.addActions(self.agRelays.actions())

        self.tb_relays.addSeparator()
        self.actColor = self.tb_relays.addAction(QIcon("GUI/icons/color.png"), "Color", self.set_color)
        self.actColor.setEnabled(False)

        self.actChannels = self.tb_relays.addAction(QIcon("GUI/icons/sliders.png"), "Channels")
        self.actChannels.setEnabled(False)
        self.mChannels = QMenu()
        self.actChannels.setMenu(self.mChannels)
        self.tb_relays.widgetForAction(self.actChannels).setPopupMode(QToolButton.InstantPopup)

    def create_view_buttons(self):
        self.tb_views.addWidget(QLabel("View mode: "))
        ag_views = QActionGroup(self)
        ag_views.setExclusive(True)
        for v in self.views.keys():
            a = QAction(v)
            a.triggered.connect(self.change_view)
            a.setCheckable(True)
            ag_views.addAction(a)
        self.tb_views.addActions(ag_views.actions())
        ag_views.actions()[0].setChecked(True)

        stretch = QWidget()
        stretch.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.tb_views.addWidget(stretch)
        # actEditView = self.tb_views.addAction("Edit views...")

    # def create_view_filter(self):
    #     # self.tb_filter.addWidget(QLabel("Show devices: "))
    #     # self.cbxLWT = QComboBox()
    #     # self.cbxLWT.addItems(["All", "Online"d, "Offline"])
    #     # self.cbxLWT.currentTextChanged.connect(self.build_filter_regex)
    #     # self.tb_filter.addWidget(self.cbxLWT)
    #
    #     self.tb_filter.addWidget(QLabel(" Search: "))
    #     self.leSearch = QLineEdit()
    #     self.leSearch.setClearButtonEnabled(True)
    #     self.leSearch.textChanged.connect(self.build_filter_regex)
    #     self.tb_filter.addWidget(self.leSearch)
    #
    # def build_filter_regex(self, txt):
    #     query = self.leSearch.text()
    #     # if self.cbxLWT.currentText() != "All":
    #     #     query = "{}|{}".format(self.cbxLWT.currentText(), query)
    #     self.sorted_device_model.setFilterRegExp(query)

    def change_view(self, a=None):
        view = self.views[self.sender().text()]
        self.model.setupColumns(view)
        self.device_list.setupView(view)

    def ctx_menu_copy(self):
        if self.idx:
            string = dumps(self.model.data(self.idx))
            if string.startswith('"') and string.endswith('"'):
                string = string[1:-1]
            QApplication.clipboard().setText(string)

    def ctx_menu_clear_retained(self):
        if self.device:
            relays = self.device.power()
            if relays and len(relays.keys()) > 0:
                for r in relays.keys():
                    self.mqtt.publish(self.device.cmnd_topic(r), retain=True)
            QMessageBox.information(self, "Clear retained", "Cleared retained messages.")

    def ctx_menu_clear_backlog(self):
        if self.device:
            self.mqtt.publish(self.device.cmnd_topic("backlog"), "")
            QMessageBox.information(self, "Clear Backlog", "Backlog cleared.")

    def ctx_menu_restart(self):
        if self.device:
            self.mqtt.publish(self.device.cmnd_topic("restart"), payload="1")
            for k in list(self.device.power().keys()):
                self.device.p.pop(k)

    def ctx_menu_reset(self):
        if self.device:
            reset, ok = QInputDialog.getItem(self, "Reset device and restart", "Select reset mode", resets, editable=False)
            if ok:
                self.mqtt.publish(self.device.cmnd_topic("reset"), payload=reset.split(":")[0])
                for k in list(self.device.power().keys()):
                    self.device.p.pop(k)

    def ctx_menu_refresh(self):
        if self.device:
            for k in list(self.device.power().keys()):
                self.device.p.pop(k)

            for c in initial_commands():
                cmd, payload = c
                cmd = self.device.cmnd_topic(cmd)
                self.mqtt.publish(cmd, payload, 1)

    def ctx_menu_delete_device(self):
        if self.device:
            if QMessageBox.question(self, "Confirm", "Do you want to remove the following device?\n'{}' ({})"
                    .format(self.device.p['FriendlyName1'], self.device.p['Topic'])) == QMessageBox.Yes:
                self.model.deleteDevice(self.idx)

    def ctx_menu_teleperiod(self):
        if self.device:
            teleperiod, ok = QInputDialog.getInt(self, "Set telemetry period", "Input 1 to reset to default\n[Min: 10, Max: 3600]", self.device.p['TelePeriod'], 1, 3600)
            if ok:
                if teleperiod != 1 and teleperiod < 10:
                    teleperiod = 10
            self.mqtt.publish(self.device.cmnd_topic("teleperiod"), teleperiod)

    def ctx_menu_config_backup(self):
        if self.device:
            self.backup = bytes()
            self.dl = self.nam.get(QNetworkRequest(QUrl("http://{}/dl".format(self.device.p['IPAddress']))))
            self.dl.readyRead.connect(self.get_dump)
            self.dl.finished.connect(self.save_dump)

    def ctx_menu_ota_set_url(self):
        if self.device:
            url, ok = QInputDialog.getText(self, "Set OTA URL", '100 chars max. Set to "1" to reset to default.', text=self.device.p['OtaUrl'])
            if ok:
                self.mqtt.publish(self.device.cmnd_topic("otaurl"), payload=url)

    def ctx_menu_ota_set_upgrade(self):
        if self.device:
            if QMessageBox.question(self, "OTA Upgrade", "Are you sure to OTA upgrade from\n{}".format(self.device.p['OtaUrl']), QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
                self.mqtt.publish(self.device.cmnd_topic("upgrade"), payload="1")

    def show_list_ctx_menu(self, at):
        self.select_device(self.device_list.indexAt(at))
        self.ctx_menu.popup(self.device_list.viewport().mapToGlobal(at))

    def select_device(self, idx):
        self.idx = self.sorted_device_model.mapToSource(idx)
        self.device = self.model.deviceAtRow(self.idx.row())
        self.deviceSelected.emit(self.device)

        relays = self.device.power()

        self.agAllPower.setEnabled(len(relays) >= 1)

        for i, a in enumerate(self.agRelays.actions()):
            a.setVisible(len(relays) > 1 and i < len(relays))

        color = self.device.color().get("Color", False)
        has_color = bool(color)
        self.actColor.setEnabled(has_color and not self.device.setoption(68))

        self.actChannels.setEnabled(has_color)

        if has_color:
            self.actChannels.menu().clear()

            max_val = 100
            if self.device.setoption(15) == 0:
                max_val = 1023

            for k, v in self.device.pwm().items():
                channel = SliderAction(self, k)
                channel.slider.setMaximum(max_val)
                channel.slider.setValue(int(v))
                self.mChannels.addAction(channel)
                channel.slider.valueChanged.connect(self.set_channel)

            dimmer = self.device.color().get("Dimmer")
            if dimmer:
                saDimmer = SliderAction(self, "Dimmer")
                saDimmer.slider.setValue(int(dimmer))
                self.mChannels.addAction(saDimmer)
                saDimmer.slider.valueChanged.connect(self.set_channel)

    def toggle_power(self, action):
        if self.device:
            idx = self.agRelays.actions().index(action)
            relay = sorted(list(self.device.power().keys()))[idx]
            self.mqtt.publish(self.device.cmnd_topic(relay), "toggle")

    def toggle_power_all(self, action):
        if self.device:
            idx = self.agAllPower.actions().index(action)
            for r in sorted(self.device.power().keys()):
                self.mqtt.publish(self.device.cmnd_topic(r), idx ^ 1)

    def set_color(self):
        if self.device:
            color = self.device.color().get("Color")
            if color:
                dlg = QColorDialog()
                new_color = dlg.getColor(QColor("#{}".format(color)))
                if new_color.isValid():
                    new_color = new_color.name()
                    if new_color != color:
                        self.mqtt.publish(self.device.cmnd_topic("color"), new_color)

    def set_channel(self, value=0):
        cmd = self.sender().objectName()

        if self.device:
            self.mqtt.publish(self.device.cmnd_topic(cmd), str(value))

    def configureSO(self):
        if self.device:
            dlg = SetOptionsDialog(self.device)
            dlg.sendCommand.connect(self.mqtt.publish)
            dlg.exec_()

    def configureModule(self):
        if self.device:
            dlg = ModuleDialog(self.device)
            dlg.sendCommand.connect(self.mqtt.publish)
            dlg.exec_()

    def configureGPIO(self):
        if self.device:
            dlg = GPIODialog(self.device)
            dlg.sendCommand.connect(self.mqtt.publish)
            dlg.exec_()

    def configureTemplate(self):
        if self.device:
            dlg = TemplateDialog(self.device)
            dlg.sendCommand.connect(self.mqtt.publish)
            dlg.exec_()

    def configureTimers(self):
        if self.device:
            self.mqtt.publish(self.device.cmnd_topic("timers"))
            timers = TimersDialog(self.device)
            self.mqtt.messageSignal.connect(timers.parseMessage)
            timers.sendCommand.connect(self.mqtt.publish)
            timers.exec_()

    def configureButtons(self):
        if self.device:
            backlog = []
            buttons = ButtonsDialog(self.device)
            if buttons.exec_() == QDialog.Accepted:
                for c, cw in buttons.command_widgets.items():
                    current_value = self.device.p.get(c)
                    new_value = ""

                    if isinstance(cw.input, SpinBox):
                        new_value = cw.input.value()

                    if isinstance(cw.input, QComboBox):
                        new_value = cw.input.currentIndex()

                    if current_value != new_value:
                        backlog.append("{} {}".format(c, new_value))

                so_error = False
                for so, sow in buttons.setoption_widgets.items():
                    current_value = None
                    try:
                        current_value = self.device.setoption(so)
                    except ValueError:
                        so_error = True

                    new_value = -1

                    if isinstance(sow.input, SpinBox):
                        new_value = sow.input.value()

                    if isinstance(sow.input, QComboBox):
                        new_value = sow.input.currentIndex()

                    if not so_error and current_value and current_value != new_value:
                        backlog.append("SetOption{} {}".format(so, new_value))

                if backlog:
                    backlog.append("status 3")
                    self.mqtt.publish(self.device.cmnd_topic("backlog"), "; ".join(backlog))

    def configureSwitches(self):
        if self.device:
            backlog = []
            switches = SwitchesDialog(self.device)
            if switches.exec_() == QDialog.Accepted:
                for c, cw in switches.command_widgets.items():
                    current_value = self.device.p.get(c)
                    new_value = ""

                    if isinstance(cw.input, SpinBox):
                        new_value = cw.input.value()

                    if isinstance(cw.input, QComboBox):
                        new_value = cw.input.currentIndex()

                    if current_value != new_value:
                        backlog.append("{} {}".format(c, new_value))

                so_error = False
                for so, sow in switches.setoption_widgets.items():
                    current_value = None
                    try:
                        current_value = self.device.setoption(so)
                    except ValueError:
                        so_error = True
                    new_value = -1

                    if isinstance(sow.input, SpinBox):
                        new_value = sow.input.value()

                    if isinstance(sow.input, QComboBox):
                        new_value = sow.input.currentIndex()

                    if not so_error and current_value != new_value:
                        backlog.append("SetOption{} {}".format(so, new_value))

                for sw, sw_mode in enumerate(self.device.p['SwitchMode']):
                    new_value = switches.sm.inputs[sw].currentIndex()

                    if sw_mode != new_value:
                        backlog.append("switchmode{} {}".format(sw+1, new_value))

                if backlog:
                    backlog.append("status")
                    backlog.append("status 3")
                self.mqtt.publish(self.device.cmnd_topic("backlog"), "; ".join(backlog))

    def configurePower(self):
        if self.device:
            backlog = []
            power = PowerDialog(self.device)
            if power.exec_() == QDialog.Accepted:
                for c, cw in power.command_widgets.items():
                    current_value = self.device.p.get(c)
                    new_value = ""

                    if isinstance(cw.input, SpinBox):
                        new_value = cw.input.value()

                    if isinstance(cw.input, QComboBox):
                        new_value = cw.input.currentIndex()

                    if current_value != new_value:
                        backlog.append("{} {}".format(c, new_value))

                so_error = False
                for so, sow in power.setoption_widgets.items():
                    current_value = None
                    try:
                        current_value = self.device.setoption(so)
                    except ValueError:
                        so_error = True
                    new_value = -1


                    if isinstance(sow.input, SpinBox):
                        new_value = sow.input.value()

                    if isinstance(sow.input, QComboBox):
                        new_value = sow.input.currentIndex()

                    if not so_error and current_value != new_value:
                        backlog.append("SetOption{} {}".format(so, new_value))

                new_interlock_value = power.ci.input.currentData()
                new_interlock_grps = " ".join([grp.text().replace(" ", "") for grp in power.ci.groups]).rstrip()

                if new_interlock_value != self.device.p.get("Interlock", "OFF"):
                    backlog.append("interlock {}".format(new_interlock_value))

                if new_interlock_grps != self.device.p.get("Groups", ""):
                    backlog.append("interlock {}".format(new_interlock_grps))

                for i, pt in enumerate(power.cpt.inputs):
                    ptime = "PulseTime{}".format(i+1)
                    current_ptime = self.device.p.get(ptime)
                    if current_ptime:
                        current_value = list(current_ptime.keys())[0]
                        new_value = str(pt.value())

                        if new_value != current_value:
                            backlog.append("{} {}".format(ptime, new_value))

                if backlog:
                    backlog.append("status")
                    backlog.append("status 3")
                    self.mqtt.publish(self.device.cmnd_topic("backlog"), "; ".join(backlog))

    def get_dump(self):
        self.backup += self.dl.readAll()

    def save_dump(self):
        fname = self.dl.header(QNetworkRequest.ContentDispositionHeader)
        if fname:
            fname = fname.split('=')[1]
            save_file = QFileDialog.getSaveFileName(self, "Save config backup", "{}/TDM/{}".format(QDir.homePath(), fname))[0]
            if save_file:
                with open(save_file, "wb") as f:
                    f.write(self.backup)

    def check_fulltopic(self, fulltopic):
        fulltopic += "/" if not fulltopic.endswith('/') else ''
        return "%prefix%" in fulltopic and "%topic%" in fulltopic

    def closeEvent(self, event):
        event.ignore()
Example #43
0
    def setupUi(self, MainWindow):
        self.bill_bool = 2
        self.totalbill = 0
        self.item_price = 0
        self.stock_list = QtWidgets.QTextEdit()
        self.stock_list.setReadOnly(1)
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 688)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setSizeConstraint(
            QtWidgets.QLayout.SetDefaultConstraint)
        self.verticalLayout.setObjectName("verticalLayout")
        self.quick_add_box = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.quick_add_box.sizePolicy().hasHeightForWidth())
        self.quick_add_box.setSizePolicy(sizePolicy)
        self.quick_add_box.setObjectName("quick_add_box")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.quick_add_box)
        self.verticalLayout_4.setSizeConstraint(
            QtWidgets.QLayout.SetDefaultConstraint)
        self.verticalLayout_4.setSpacing(1)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setSpacing(10)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.gridLayout.setHorizontalSpacing(4)
        self.gridLayout.setVerticalSpacing(0)
        self.gridLayout.setObjectName("gridLayout")
        self.product_list = QtWidgets.QComboBox(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.product_list.sizePolicy().hasHeightForWidth())
        self.product_list.setSizePolicy(sizePolicy)
        self.product_list.setObjectName("product_list")
        self.gridLayout.addWidget(self.product_list, 1, 0, 1, 1)
        self.product_label = QtWidgets.QLabel(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.product_label.sizePolicy().hasHeightForWidth())
        self.product_label.setSizePolicy(sizePolicy)
        self.product_label.setObjectName("product_label")
        self.gridLayout.addWidget(self.product_label, 0, 0, 1, 1)
        self.buyer_list = QtWidgets.QComboBox(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.buyer_list.sizePolicy().hasHeightForWidth())
        self.buyer_list.setSizePolicy(sizePolicy)
        self.buyer_list.setObjectName("buyer_list")
        self.gridLayout.addWidget(self.buyer_list, 1, 1, 1, 1)
        self.buyer_label = QtWidgets.QLabel(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.buyer_label.sizePolicy().hasHeightForWidth())
        self.buyer_label.setSizePolicy(sizePolicy)
        self.buyer_label.setObjectName("buyer_label")
        self.gridLayout.addWidget(self.buyer_label, 0, 1, 1, 1)
        self.add_button = QtWidgets.QPushButton(self.quick_add_box)
        self.add_button.setObjectName("add_button")
        self.gridLayout.addWidget(self.add_button, 1, 3, 1, 1)
        self.quantity_number = QtWidgets.QSpinBox(self.quick_add_box)
        self.quantity_number.setObjectName("quantity_number")
        self.gridLayout.addWidget(self.quantity_number, 1, 2, 1, 1)
        self.horizontalLayout_3.addLayout(self.gridLayout)
        self.verticalLayout_3.addLayout(self.horizontalLayout_3)
        self.line = QtWidgets.QFrame(self.quick_add_box)
        self.line.setFrameShape(QtWidgets.QFrame.HLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.verticalLayout_3.addWidget(self.line)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.total_label = QtWidgets.QLabel(self.quick_add_box)
        self.total_label.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.total_label.setObjectName("total_label")
        self.horizontalLayout_4.addWidget(self.total_label)
        spacerItem = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem)
        self.start_button = QtWidgets.QPushButton(self.quick_add_box)
        self.start_button.setText("")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(
            ":/start/ic_play_arrow_black_18dp_2x.png"), QtGui.QIcon.Normal,
            QtGui.QIcon.Off)
        self.start_button.setIcon(icon)
        self.start_button.setObjectName("start_button")
        self.horizontalLayout_4.addWidget(self.start_button)
        self.stop_button = QtWidgets.QPushButton(self.quick_add_box)
        self.stop_button.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap(
            ":/stop/ic_stop_black_18dp_2x.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.stop_button.setIcon(icon1)
        self.stop_button.setObjectName("stop_button")
        self.horizontalLayout_4.addWidget(self.stop_button)
        self.verticalLayout_3.addLayout(self.horizontalLayout_4)
        self.verticalLayout_4.addLayout(self.verticalLayout_3)
        self.verticalLayout.addWidget(self.quick_add_box)
        self.verticalLayout_2.addLayout(self.verticalLayout)
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setScaledContents(True)
        self.label_5.setObjectName("label_5")
        self.verticalLayout_2.addWidget(self.label_5)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.bill_box = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.bill_box.sizePolicy().hasHeightForWidth())
        self.bill_box.setSizePolicy(sizePolicy)
        self.bill_box.setObjectName("bill_box")
        self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.bill_box)
        self.verticalLayout_8.setObjectName("verticalLayout_8")
        self.verticalLayout_7 = QtWidgets.QVBoxLayout()
        self.verticalLayout_7.setObjectName("verticalLayout_7")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.bill_name_label = QtWidgets.QLabel(self.bill_box)
        self.bill_name_label.setObjectName("bill_name_label")
        self.gridLayout_2.addWidget(self.bill_name_label, 0, 0, 1, 1)
        self.bill_product_list = QtWidgets.QComboBox(self.bill_box)
        self.bill_product_list.setObjectName("bill_product_list")
        self.gridLayout_2.addWidget(self.bill_product_list, 2, 1, 1, 1)
        self.bill_buyer_type_label = QtWidgets.QLabel(self.bill_box)
        self.bill_buyer_type_label.setObjectName("bill_buyer_type_label")
        self.gridLayout_2.addWidget(self.bill_buyer_type_label, 1, 0, 1, 1)
        self.bill_buyer_list = QtWidgets.QComboBox(self.bill_box)
        self.bill_buyer_list.setObjectName("bill_buyer_list")
        self.gridLayout_2.addWidget(self.bill_buyer_list, 1, 1, 1, 1)
        self.bill_product_label = QtWidgets.QLabel(self.bill_box)
        self.bill_product_label.setObjectName("bill_product_label")
        self.gridLayout_2.addWidget(self.bill_product_label, 2, 0, 1, 1)
        self.bill_name_line = QtWidgets.QLineEdit(self.bill_box)
        self.bill_name_line.setObjectName("bill_name_line")
        self.gridLayout_2.addWidget(self.bill_name_line, 0, 1, 1, 1)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem1 = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.bill_quantity_no = QtWidgets.QSpinBox(self.bill_box)
        self.bill_quantity_no.setObjectName("bill_quantity_no")
        self.horizontalLayout_2.addWidget(self.bill_quantity_no)
        self.bill_add_button = QtWidgets.QPushButton(self.bill_box)
        self.bill_add_button.setObjectName("bill_add_button")
        self.horizontalLayout_2.addWidget(self.bill_add_button)
        self.gridLayout_2.addLayout(self.horizontalLayout_2, 3, 1, 1, 1)
        self.verticalLayout_7.addLayout(self.gridLayout_2)
        self.tableView = QtWidgets.QTableView(self.bill_box)
        self.tableView.setObjectName("tableView")
        self.verticalLayout_7.addWidget(self.tableView)
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.delete_button = QtWidgets.QPushButton(self.bill_box)
        self.delete_button.setObjectName("delete_button")
        self.horizontalLayout_6.addWidget(self.delete_button)
        spacerItem2 = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_6.addItem(spacerItem2)
        self.bill_total_label = QtWidgets.QLabel(self.bill_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.bill_total_label.sizePolicy().hasHeightForWidth())
        self.bill_total_label.setSizePolicy(sizePolicy)
        self.bill_total_label.setObjectName("bill_total_label")
        self.horizontalLayout_6.addWidget(self.bill_total_label)
        self.verticalLayout_7.addLayout(self.horizontalLayout_6)
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setSizeConstraint(
            QtWidgets.QLayout.SetDefaultConstraint)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.print_check = QtWidgets.QCheckBox(self.bill_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.print_check.sizePolicy().hasHeightForWidth())
        self.print_check.setSizePolicy(sizePolicy)
        self.print_check.setLayoutDirection(QtCore.Qt.RightToLeft)
        self.print_check.setObjectName("print_check")
        self.horizontalLayout_5.addWidget(self.print_check)
        spacerItem3 = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem3)
        self.submit_button = QtWidgets.QPushButton(self.bill_box)
        self.submit_button.setObjectName("submit_button")
        self.horizontalLayout_5.addWidget(self.submit_button)
        self.verticalLayout_7.addLayout(self.horizontalLayout_5)
        self.verticalLayout_8.addLayout(self.verticalLayout_7)
        self.horizontalLayout.addWidget(self.bill_box)
        self.stock_box = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.stock_box.sizePolicy().hasHeightForWidth())
        self.stock_box.setSizePolicy(sizePolicy)
        self.stock_box.setObjectName("stock_box")
        self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.stock_box)
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.verticalLayout_5 = QtWidgets.QVBoxLayout()
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.verticalLayout_6.addLayout(self.verticalLayout_5)
        self.horizontalLayout.addWidget(self.stock_box)
        self.stock_layout = QtWidgets.QHBoxLayout()
        self.verticalLayout_6.addWidget(self.stock_list)
        self.verticalLayout_2.addLayout(self.horizontalLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 31))
        self.menubar.setObjectName("menubar")
        self.menuFile = QtWidgets.QMenu(self.menubar)
        self.menuFile.setObjectName("menuFile")
        self.menuEdit = QtWidgets.QMenu(self.menubar)
        self.menuEdit.setObjectName("menuEdit")
        self.menuReports = QtWidgets.QMenu(self.menubar)
        self.menuReports.setObjectName("menuReports")
        self.menuOptionis = QtWidgets.QMenu(self.menubar)
        self.menuOptionis.setObjectName("menuOptionis")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionExit = QtWidgets.QAction(MainWindow)
        self.actionExit.setObjectName("actionExit")
        self.actionAbout = QtWidgets.QAction(MainWindow)
        self.actionAbout.setObjectName("actionAbout")
        self.actionUndo = QtWidgets.QAction(MainWindow)
        self.actionUndo.setObjectName("actionUndo")
        self.actionEdit_Products_Stock = QtWidgets.QAction(MainWindow)
        self.actionEdit_Products_Stock.setObjectName(
            "actionEdit_Products_Stock")
        self.actionEdit_Sales = QtWidgets.QAction(MainWindow)
        self.actionEdit_Sales.setObjectName("actionEdit_Sales")
        self.actionEdit_Buyer = QtWidgets.QAction(MainWindow)
        self.actionEdit_Buyer.setObjectName("actionEdit_Buyer")
        self.actionMonthly_Report = QtWidgets.QAction(MainWindow)
        self.actionMonthly_Report.setObjectName("actionMonthly_Report")
        self.actionWeekly_Report = QtWidgets.QAction(MainWindow)
        self.actionWeekly_Report.setObjectName("actionWeekly_Report")
        self.actionDaily_Report = QtWidgets.QAction(MainWindow)
        self.actionDaily_Report.setObjectName("actionDaily_Report")
        self.actionInventory = QtWidgets.QAction(MainWindow)
        self.actionInventory.setObjectName("actionInventory")
        self.actionClear_Old_Records = QtWidgets.QAction(MainWindow)
        self.actionClear_Old_Records.setObjectName("actionClear_Old_Records")
        # self.actionSettings = QtWidgets.QAction(MainWindow)
        # self.actionSettings.setObjectName("actionSettings")
        self.menuFile.addAction(self.actionExit)
        self.menuFile.addAction(self.actionAbout)
        self.menuEdit.addAction(self.actionUndo)
        self.menuEdit.addSeparator()
        self.menuEdit.addAction(self.actionEdit_Products_Stock)

        self.menuEdit.addAction(self.actionEdit_Sales)
        self.menuEdit.addAction(self.actionEdit_Buyer)

        self.menuReports.addAction(self.actionMonthly_Report)

        self.menuReports.addAction(self.actionWeekly_Report)
        self.menuReports.addAction(self.actionDaily_Report)
        self.menuReports.addAction(self.actionInventory)
        self.menuOptionis.addAction(self.actionClear_Old_Records)
        # self.menuOptionis.addAction(self.actionSettings)
        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuEdit.menuAction())
        self.menubar.addAction(self.menuReports.menuAction())
        self.menubar.addAction(self.menuOptionis.menuAction())
        self.product_list.setEditable(1)
        self.buyer_list.setEditable(1)
        self.bill_buyer_list.setEditable(1)
        self.bill_product_list.setEditable(1)

        self.dbman.products_model.select()
        self.proxy_product_model = QSortFilterProxyModel()
        self.proxy_product_model.setSourceModel(self.dbman.products_model)
        self.proxy_product_model.insertRow(0)
        self.proxy_product_model.setFilterKeyColumn(1)
        self.product_list.setModel(self.proxy_product_model)
        self.product_list.setModelColumn(
            self.proxy_product_model.filterKeyColumn())

        self.dbman.buyer_model.select()
        self.proxy_buyer_model = QSortFilterProxyModel()
        self.proxy_buyer_model.setSourceModel(self.dbman.buyer_model)
        self.proxy_buyer_model.insertRow(0)
        self.proxy_buyer_model.setFilterKeyColumn(0)
        self.buyer_list.setModel(self.proxy_buyer_model)
        self.buyer_list.setModelColumn(
            self.proxy_buyer_model.filterKeyColumn())

        self.bill_product_list.setModel(self.proxy_product_model)
        self.bill_product_list.setModelColumn(
            self.proxy_product_model.filterKeyColumn())

        self.bill_buyer_list.setModel(self.proxy_buyer_model)
        self.bill_buyer_list.setModelColumn(
            self.proxy_buyer_model.filterKeyColumn())
        self.bill_quantity_no.setValue(1)
        self.start_button.clicked.connect(self.bill_start)
        self.stop_button.clicked.connect(self.bill_stop)
        self.add_button.clicked.connect(self.tally)
        self.bill_add_button.clicked.connect(self.bill_item)
        self.product_list.currentIndexChanged.connect(self.reset_tally)
        self.setWindowIcon(QtGui.QIcon('icon.png'))
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
Example #44
0
class Ui_MainWindow(object):

    dbman = DBMan()
    dbman.load_tables()
    dbman.clear_undo()

    def setupUi(self, MainWindow):
        self.bill_bool = 2
        self.totalbill = 0
        self.item_price = 0
        self.stock_list = QtWidgets.QTextEdit()
        self.stock_list.setReadOnly(1)
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 688)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setSizeConstraint(
            QtWidgets.QLayout.SetDefaultConstraint)
        self.verticalLayout.setObjectName("verticalLayout")
        self.quick_add_box = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.quick_add_box.sizePolicy().hasHeightForWidth())
        self.quick_add_box.setSizePolicy(sizePolicy)
        self.quick_add_box.setObjectName("quick_add_box")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.quick_add_box)
        self.verticalLayout_4.setSizeConstraint(
            QtWidgets.QLayout.SetDefaultConstraint)
        self.verticalLayout_4.setSpacing(1)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setSpacing(10)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
        self.gridLayout.setHorizontalSpacing(4)
        self.gridLayout.setVerticalSpacing(0)
        self.gridLayout.setObjectName("gridLayout")
        self.product_list = QtWidgets.QComboBox(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.product_list.sizePolicy().hasHeightForWidth())
        self.product_list.setSizePolicy(sizePolicy)
        self.product_list.setObjectName("product_list")
        self.gridLayout.addWidget(self.product_list, 1, 0, 1, 1)
        self.product_label = QtWidgets.QLabel(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.product_label.sizePolicy().hasHeightForWidth())
        self.product_label.setSizePolicy(sizePolicy)
        self.product_label.setObjectName("product_label")
        self.gridLayout.addWidget(self.product_label, 0, 0, 1, 1)
        self.buyer_list = QtWidgets.QComboBox(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.buyer_list.sizePolicy().hasHeightForWidth())
        self.buyer_list.setSizePolicy(sizePolicy)
        self.buyer_list.setObjectName("buyer_list")
        self.gridLayout.addWidget(self.buyer_list, 1, 1, 1, 1)
        self.buyer_label = QtWidgets.QLabel(self.quick_add_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.buyer_label.sizePolicy().hasHeightForWidth())
        self.buyer_label.setSizePolicy(sizePolicy)
        self.buyer_label.setObjectName("buyer_label")
        self.gridLayout.addWidget(self.buyer_label, 0, 1, 1, 1)
        self.add_button = QtWidgets.QPushButton(self.quick_add_box)
        self.add_button.setObjectName("add_button")
        self.gridLayout.addWidget(self.add_button, 1, 3, 1, 1)
        self.quantity_number = QtWidgets.QSpinBox(self.quick_add_box)
        self.quantity_number.setObjectName("quantity_number")
        self.gridLayout.addWidget(self.quantity_number, 1, 2, 1, 1)
        self.horizontalLayout_3.addLayout(self.gridLayout)
        self.verticalLayout_3.addLayout(self.horizontalLayout_3)
        self.line = QtWidgets.QFrame(self.quick_add_box)
        self.line.setFrameShape(QtWidgets.QFrame.HLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.verticalLayout_3.addWidget(self.line)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.total_label = QtWidgets.QLabel(self.quick_add_box)
        self.total_label.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.total_label.setObjectName("total_label")
        self.horizontalLayout_4.addWidget(self.total_label)
        spacerItem = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem)
        self.start_button = QtWidgets.QPushButton(self.quick_add_box)
        self.start_button.setText("")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(
            ":/start/ic_play_arrow_black_18dp_2x.png"), QtGui.QIcon.Normal,
            QtGui.QIcon.Off)
        self.start_button.setIcon(icon)
        self.start_button.setObjectName("start_button")
        self.horizontalLayout_4.addWidget(self.start_button)
        self.stop_button = QtWidgets.QPushButton(self.quick_add_box)
        self.stop_button.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap(
            ":/stop/ic_stop_black_18dp_2x.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.stop_button.setIcon(icon1)
        self.stop_button.setObjectName("stop_button")
        self.horizontalLayout_4.addWidget(self.stop_button)
        self.verticalLayout_3.addLayout(self.horizontalLayout_4)
        self.verticalLayout_4.addLayout(self.verticalLayout_3)
        self.verticalLayout.addWidget(self.quick_add_box)
        self.verticalLayout_2.addLayout(self.verticalLayout)
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setScaledContents(True)
        self.label_5.setObjectName("label_5")
        self.verticalLayout_2.addWidget(self.label_5)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.bill_box = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.bill_box.sizePolicy().hasHeightForWidth())
        self.bill_box.setSizePolicy(sizePolicy)
        self.bill_box.setObjectName("bill_box")
        self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.bill_box)
        self.verticalLayout_8.setObjectName("verticalLayout_8")
        self.verticalLayout_7 = QtWidgets.QVBoxLayout()
        self.verticalLayout_7.setObjectName("verticalLayout_7")
        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.bill_name_label = QtWidgets.QLabel(self.bill_box)
        self.bill_name_label.setObjectName("bill_name_label")
        self.gridLayout_2.addWidget(self.bill_name_label, 0, 0, 1, 1)
        self.bill_product_list = QtWidgets.QComboBox(self.bill_box)
        self.bill_product_list.setObjectName("bill_product_list")
        self.gridLayout_2.addWidget(self.bill_product_list, 2, 1, 1, 1)
        self.bill_buyer_type_label = QtWidgets.QLabel(self.bill_box)
        self.bill_buyer_type_label.setObjectName("bill_buyer_type_label")
        self.gridLayout_2.addWidget(self.bill_buyer_type_label, 1, 0, 1, 1)
        self.bill_buyer_list = QtWidgets.QComboBox(self.bill_box)
        self.bill_buyer_list.setObjectName("bill_buyer_list")
        self.gridLayout_2.addWidget(self.bill_buyer_list, 1, 1, 1, 1)
        self.bill_product_label = QtWidgets.QLabel(self.bill_box)
        self.bill_product_label.setObjectName("bill_product_label")
        self.gridLayout_2.addWidget(self.bill_product_label, 2, 0, 1, 1)
        self.bill_name_line = QtWidgets.QLineEdit(self.bill_box)
        self.bill_name_line.setObjectName("bill_name_line")
        self.gridLayout_2.addWidget(self.bill_name_line, 0, 1, 1, 1)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem1 = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem1)
        self.bill_quantity_no = QtWidgets.QSpinBox(self.bill_box)
        self.bill_quantity_no.setObjectName("bill_quantity_no")
        self.horizontalLayout_2.addWidget(self.bill_quantity_no)
        self.bill_add_button = QtWidgets.QPushButton(self.bill_box)
        self.bill_add_button.setObjectName("bill_add_button")
        self.horizontalLayout_2.addWidget(self.bill_add_button)
        self.gridLayout_2.addLayout(self.horizontalLayout_2, 3, 1, 1, 1)
        self.verticalLayout_7.addLayout(self.gridLayout_2)
        self.tableView = QtWidgets.QTableView(self.bill_box)
        self.tableView.setObjectName("tableView")
        self.verticalLayout_7.addWidget(self.tableView)
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.delete_button = QtWidgets.QPushButton(self.bill_box)
        self.delete_button.setObjectName("delete_button")
        self.horizontalLayout_6.addWidget(self.delete_button)
        spacerItem2 = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_6.addItem(spacerItem2)
        self.bill_total_label = QtWidgets.QLabel(self.bill_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.bill_total_label.sizePolicy().hasHeightForWidth())
        self.bill_total_label.setSizePolicy(sizePolicy)
        self.bill_total_label.setObjectName("bill_total_label")
        self.horizontalLayout_6.addWidget(self.bill_total_label)
        self.verticalLayout_7.addLayout(self.horizontalLayout_6)
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setSizeConstraint(
            QtWidgets.QLayout.SetDefaultConstraint)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.print_check = QtWidgets.QCheckBox(self.bill_box)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.print_check.sizePolicy().hasHeightForWidth())
        self.print_check.setSizePolicy(sizePolicy)
        self.print_check.setLayoutDirection(QtCore.Qt.RightToLeft)
        self.print_check.setObjectName("print_check")
        self.horizontalLayout_5.addWidget(self.print_check)
        spacerItem3 = QtWidgets.QSpacerItem(
            40, 20, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem3)
        self.submit_button = QtWidgets.QPushButton(self.bill_box)
        self.submit_button.setObjectName("submit_button")
        self.horizontalLayout_5.addWidget(self.submit_button)
        self.verticalLayout_7.addLayout(self.horizontalLayout_5)
        self.verticalLayout_8.addLayout(self.verticalLayout_7)
        self.horizontalLayout.addWidget(self.bill_box)
        self.stock_box = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.stock_box.sizePolicy().hasHeightForWidth())
        self.stock_box.setSizePolicy(sizePolicy)
        self.stock_box.setObjectName("stock_box")
        self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.stock_box)
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.verticalLayout_5 = QtWidgets.QVBoxLayout()
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.verticalLayout_6.addLayout(self.verticalLayout_5)
        self.horizontalLayout.addWidget(self.stock_box)
        self.stock_layout = QtWidgets.QHBoxLayout()
        self.verticalLayout_6.addWidget(self.stock_list)
        self.verticalLayout_2.addLayout(self.horizontalLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 31))
        self.menubar.setObjectName("menubar")
        self.menuFile = QtWidgets.QMenu(self.menubar)
        self.menuFile.setObjectName("menuFile")
        self.menuEdit = QtWidgets.QMenu(self.menubar)
        self.menuEdit.setObjectName("menuEdit")
        self.menuReports = QtWidgets.QMenu(self.menubar)
        self.menuReports.setObjectName("menuReports")
        self.menuOptionis = QtWidgets.QMenu(self.menubar)
        self.menuOptionis.setObjectName("menuOptionis")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionExit = QtWidgets.QAction(MainWindow)
        self.actionExit.setObjectName("actionExit")
        self.actionAbout = QtWidgets.QAction(MainWindow)
        self.actionAbout.setObjectName("actionAbout")
        self.actionUndo = QtWidgets.QAction(MainWindow)
        self.actionUndo.setObjectName("actionUndo")
        self.actionEdit_Products_Stock = QtWidgets.QAction(MainWindow)
        self.actionEdit_Products_Stock.setObjectName(
            "actionEdit_Products_Stock")
        self.actionEdit_Sales = QtWidgets.QAction(MainWindow)
        self.actionEdit_Sales.setObjectName("actionEdit_Sales")
        self.actionEdit_Buyer = QtWidgets.QAction(MainWindow)
        self.actionEdit_Buyer.setObjectName("actionEdit_Buyer")
        self.actionMonthly_Report = QtWidgets.QAction(MainWindow)
        self.actionMonthly_Report.setObjectName("actionMonthly_Report")
        self.actionWeekly_Report = QtWidgets.QAction(MainWindow)
        self.actionWeekly_Report.setObjectName("actionWeekly_Report")
        self.actionDaily_Report = QtWidgets.QAction(MainWindow)
        self.actionDaily_Report.setObjectName("actionDaily_Report")
        self.actionInventory = QtWidgets.QAction(MainWindow)
        self.actionInventory.setObjectName("actionInventory")
        self.actionClear_Old_Records = QtWidgets.QAction(MainWindow)
        self.actionClear_Old_Records.setObjectName("actionClear_Old_Records")
        # self.actionSettings = QtWidgets.QAction(MainWindow)
        # self.actionSettings.setObjectName("actionSettings")
        self.menuFile.addAction(self.actionExit)
        self.menuFile.addAction(self.actionAbout)
        self.menuEdit.addAction(self.actionUndo)
        self.menuEdit.addSeparator()
        self.menuEdit.addAction(self.actionEdit_Products_Stock)

        self.menuEdit.addAction(self.actionEdit_Sales)
        self.menuEdit.addAction(self.actionEdit_Buyer)

        self.menuReports.addAction(self.actionMonthly_Report)

        self.menuReports.addAction(self.actionWeekly_Report)
        self.menuReports.addAction(self.actionDaily_Report)
        self.menuReports.addAction(self.actionInventory)
        self.menuOptionis.addAction(self.actionClear_Old_Records)
        # self.menuOptionis.addAction(self.actionSettings)
        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuEdit.menuAction())
        self.menubar.addAction(self.menuReports.menuAction())
        self.menubar.addAction(self.menuOptionis.menuAction())
        self.product_list.setEditable(1)
        self.buyer_list.setEditable(1)
        self.bill_buyer_list.setEditable(1)
        self.bill_product_list.setEditable(1)

        self.dbman.products_model.select()
        self.proxy_product_model = QSortFilterProxyModel()
        self.proxy_product_model.setSourceModel(self.dbman.products_model)
        self.proxy_product_model.insertRow(0)
        self.proxy_product_model.setFilterKeyColumn(1)
        self.product_list.setModel(self.proxy_product_model)
        self.product_list.setModelColumn(
            self.proxy_product_model.filterKeyColumn())

        self.dbman.buyer_model.select()
        self.proxy_buyer_model = QSortFilterProxyModel()
        self.proxy_buyer_model.setSourceModel(self.dbman.buyer_model)
        self.proxy_buyer_model.insertRow(0)
        self.proxy_buyer_model.setFilterKeyColumn(0)
        self.buyer_list.setModel(self.proxy_buyer_model)
        self.buyer_list.setModelColumn(
            self.proxy_buyer_model.filterKeyColumn())

        self.bill_product_list.setModel(self.proxy_product_model)
        self.bill_product_list.setModelColumn(
            self.proxy_product_model.filterKeyColumn())

        self.bill_buyer_list.setModel(self.proxy_buyer_model)
        self.bill_buyer_list.setModelColumn(
            self.proxy_buyer_model.filterKeyColumn())
        self.bill_quantity_no.setValue(1)
        self.start_button.clicked.connect(self.bill_start)
        self.stop_button.clicked.connect(self.bill_stop)
        self.add_button.clicked.connect(self.tally)
        self.bill_add_button.clicked.connect(self.bill_item)
        self.product_list.currentIndexChanged.connect(self.reset_tally)
        self.setWindowIcon(QtGui.QIcon('icon.png'))
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "IET Store Log"))
        self.quick_add_box.setTitle(_translate("MainWindow", "Quick Add"))
        self.product_label.setText(_translate("MainWindow", "Product"))
        self.buyer_label.setText(_translate("MainWindow", "Customer  Type"))
        self.add_button.setText(_translate("MainWindow", "Submit"))
        self.total_label.setText(_translate("MainWindow", "Total : 0"))
        self.label_5.setText(_translate(
            "MainWindow", "<b> Last Added : None </b>"))
        self.label_5.setAlignment(QtCore.Qt.AlignCenter)
        self.bill_box.setTitle(_translate("MainWindow", "Bill"))
        self.bill_name_label.setText(_translate("MainWindow", "Customer Name"))
        self.bill_buyer_type_label.setText(
            _translate("MainWindow", "Customer Type"))
        self.bill_product_label.setText(_translate("MainWindow", "Product"))
        self.bill_add_button.setText(_translate("MainWindow", "Add"))
        self.delete_button.setText(_translate("MainWindow", "Delete"))
        self.bill_total_label.setText(_translate("MainWindow", "Total : 0"))
        self.print_check.setText(_translate("MainWindow", "Print"))
        self.submit_button.setText(_translate("MainWindow", "Submit"))
        self.stock_box.setTitle(_translate("MainWindow", "Lowest Stock"))
        self.menuFile.setTitle(_translate("MainWindow", "&File"))
        self.menuEdit.setTitle(_translate("MainWindow", "&Edit"))
        self.menuReports.setTitle(_translate("MainWindow", "&Reports"))
        self.menuOptionis.setTitle(_translate("MainWindow", "Opt&ions"))
        self.actionExit.setText(_translate("MainWindow", "Exit"))
        self.actionAbout.setText(_translate("MainWindow", "About"))
        self.actionUndo.setText(_translate("MainWindow", "Undo"))
        self.actionEdit_Products_Stock.setText(
            _translate("MainWindow", "Edit Products & Stock"))
        self.actionEdit_Sales.setText(_translate("MainWindow", "Edit Sales"))
        self.actionEdit_Buyer.setText(
            _translate("MainWindow", "Edit Customer Type"))
        self.actionMonthly_Report.setText(
            _translate("MainWindow", "Monthly Report"))
        self.actionWeekly_Report.setText(
            _translate("MainWindow", "Weekly Report"))
        self.actionDaily_Report.setText(
            _translate("MainWindow", "Daily Report"))
        self.actionInventory.setText(_translate("MainWindow", "Inventory"))
        self.actionClear_Old_Records.setText(
            _translate("MainWindow", "Clear Old Records"))
        # self.actionSettings.setText(_translate("MainWindow", "Settings"))
        self.actionExit.triggered.connect(self.close_window)
        self.actionAbout.triggered.connect(self.about_dialog)
        self.actionUndo.triggered.connect(self.undo)
        self.actionEdit_Products_Stock.triggered.connect(
            self.dialog_edit_products)
        self.actionEdit_Sales.triggered.connect(self.dialog_edit_sales)
        self.actionEdit_Buyer.triggered.connect(self.dialog_edit_buyer)
        self.actionMonthly_Report.triggered.connect(self.gen_month_report)
        self.actionWeekly_Report.triggered.connect(self.gen_weekly_report)
        self.actionDaily_Report.triggered.connect(self.gen_daily_report)
        self.actionInventory.triggered.connect(self.inventory)
        self.actionClear_Old_Records.triggered.connect(self.cleaner)
        self.delete_button.clicked.connect(self.delete)
        self.submit_button.clicked.connect(self.billmaker)
        self.stock_list.setText(self.dbman.load_low_stock())

    def close_window(self):
        self.close()
        pass

    def bill_start(self):
        self.bill_bool = 0
        self.totalbill = 0
        self.total_label.setText("Total : " + str(self.totalbill))

    def bill(self):
        stock = int(self.dbman.return_stock(self.product_list.currentText()))
        price = int(self.dbman.return_price(self.product_list.currentText()))
        tally = int(self.quantity_number.value())
        if stock >= tally:
            if self.bill_bool == 0:
                self.totalbill = self.totalbill + (tally * price)
                print(self.totalbill)
                self.total_label.setText("Total : " + str(self.totalbill))

    def bill_stop(self):
        self.bill_bool = 1

    def reset_tally(self):
        self.quantity_number.setValue(1)

    def tally(self):
        if self.product_list.currentIndex() != 0:
            tally = self.quantity_number.value()
            pname = str(self.product_list.currentText())
            print(pname)
            self.buyer_type = str(self.buyer_list.currentText())
            sale = self.dbman.update_sales(pname, tally, self.buyer_type)
            self.bill()
            if sale:
                self.label_5.setText("<b>" + "Last Added : " + sale + "</b>")

    def dialog_edit_products(self):
        products_dialog = TableEditor('products')
        products_dialog.exec_()
        self.stock_list.setText(self.dbman.load_low_stock())
        self.dbman.products_model.select()

    def about_dialog(self):

        about = """
                <h2 style="text-align: center;">Created By,</h2>
                <h4 style="text-align: center;">Javed Hussain</h4>
                <h4 style="text-align: center;">Neethu KT</h4>
                <h4 style="text-align: center;">Shahma P</h4>
                <h4 style="text-align: center;">Anu Krishna</h4>
                <h3 style="text-align: center;">&nbsp;</h3>
                <h3 style="text-align: center;">IT 2015 - 2019</h3>
                <h3 style="text-align: center;"><a href="https://github.com/trailblazer42">Github</a></h3>
                """
        dial = warning(1, about)
        dial.exec_()

    def dialog_edit_sales(self):
        sales_dialog = TableEditor('salesview')
        sales_dialog.exec_()

    def dialog_edit_buyer(self):
        sales_dialog = TableEditor('buyer_type')
        sales_dialog.exec_()

    def gen_month_report(self):
        sdate = date.today().replace(day=1)
        edate = date.today()
        rep_dialog = Report(sdate, edate)
        rep_dialog.exec_()

    def gen_weekly_report(self):
        edate = date.today()
        sdate = edate - timedelta(7)
        rep_dialog = Report(sdate, edate)
        rep_dialog.exec_()

    def gen_daily_report(self):
        edate = date.today()
        rep_dialog = Report(edate, edate)
        rep_dialog.exec_()

    def cleaner(self):
        self.dbman.clean()

    def undo(self):
        self.dbman.undo_sale()

    def inventory(self):
        inv = Inventory()
        inv.filepick()

    def billmaker(self):
        cname = self.bill_name_line.text()
        buyer = self.bill_buyer_list.currentText()
        to_print = self.print_check.isChecked()
        if to_print:
            bill_generate = Bill(cname, buyer)
            self.dbman.update_bill_sales(buyer)
            self.dbman.bill_model.select()

        else:
            self.dbman.update_bill_sales(buyer)
            self.dbman.bill_model.select()
        self.bill_product_list.setCurrentIndex(-1)
        self.label_5.setText("<b>" + "Last Added: Bill for " + cname + "</b>")
        self.bill_name_line.clear()

    def bill_item(self):
        self.tableView.setModel(self.dbman.bill_model)
        self.tableView.setColumnHidden(0, True)
        pname = self.bill_product_list.currentText()
        buyer = self.bill_buyer_list.currentText()
        quantity = self.bill_quantity_no.value()
        total = self.dbman.update_bill(pname, quantity, buyer)
        self.bill_total_label.setText("Total : " + str(total))
        self.dbman.bill_model.select()

    def delete(self):
        self.rowindexes = self.tableView.selectionModel().selectedRows(0)
        for rindex in (self.rowindexes):
            row = (rindex.data())
            self.dbman.bill_delete(row)
            self.dbman.bill_model.select()
Example #45
0
def edit_contact_dialog(wallet_api, contact_key=None):
    editing = contact_key is not None
    if editing:
        title = _("Edit Contact")
    else:
        title = _("New Contact")

    d = WindowModalDialog(wallet_api.wallet_window.reference(), title)
    vbox = QVBoxLayout(d)
    vbox.addWidget(QLabel(title + ':'))

    def _contact_insert_completion(text):
        if text:
            index = combo1.findText(text)
            combo1.setCurrentIndex(index)

    identity_line = QLineEdit()
    name_line = QLineEdit()
    combo1 = QComboBox()
    combo1.setFixedWidth(280)
    combo1.setEditable(True)

    # add a filter model to filter matching items
    contact_filter_model = QSortFilterProxyModel(combo1)
    contact_filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
    contact_filter_model.setSourceModel(combo1.model())

    contact_completer = QCompleter(contact_filter_model, combo1)
    contact_completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
    combo1.setCompleter(contact_completer)

    ok_button = OkButton(d)
    ok_button.setEnabled(False)

    def _validate_form() -> None:
        def _set_validation_state(element, is_valid) -> None:
            if not is_valid:
                element.setStyleSheet("border: 1px solid red")
            else:
                element.setStyleSheet("")

        can_submit = True

        system_name = combo1.currentText().lower().strip()
        is_valid = True
        try:
            system_id = get_system_id(system_name)
        except ContactDataError:
            system_id = None
            is_valid = False
        _set_validation_state(combo1, is_valid)
        can_submit = can_submit and is_valid

        identity_text = identity_line.text().strip()
        if system_id is None:
            identity_result = IdentityCheckResult.Invalid
        else:
            identity_result = wallet_api.check_identity_valid(
                system_id, identity_text, skip_exists=editing)
        is_valid = identity_result == IdentityCheckResult.Ok
        _set_validation_state(identity_line, is_valid)
        if is_valid:
            identity_line.setToolTip("")
        elif identity_result == IdentityCheckResult.Invalid:
            if system_id == IdentitySystem.OnChain:
                identity_line.setToolTip(_("Not a valid Bitcoin address"))
            else:
                identity_line.setToolTip(_("Incorrect format"))
        elif identity_result == IdentityCheckResult.InUse:
            identity_line.setToolTip(_("Already in use"))
        can_submit = can_submit and is_valid

        name_text = name_line.text().strip()
        name_result = wallet_api.check_label(name_text)
        is_valid = (name_result == IdentityCheckResult.Ok
                    or editing and name_result == IdentityCheckResult.InUse)
        _set_validation_state(name_line, is_valid)
        if is_valid:
            name_line.setToolTip("")
        elif name_result == IdentityCheckResult.Invalid:
            name_line.setToolTip(_("Name too short"))
        elif name_result == IdentityCheckResult.InUse:
            name_line.setToolTip(_("Name already in use"))
        can_submit = can_submit and is_valid

        ok_button.setEnabled(can_submit)

    def _contact_text_changed(text: str) -> None:
        _validate_form()

    combo1.lineEdit().textEdited.connect(
        contact_filter_model.setFilterFixedString)
    combo1.editTextChanged.connect(_contact_text_changed)
    identity_line.textChanged.connect(_contact_text_changed)
    name_line.textChanged.connect(_contact_text_changed)
    contact_completer.activated.connect(_contact_insert_completion)

    combo1.addItems(list(IDENTITY_SYSTEM_NAMES.values()))

    grid = QGridLayout()
    identity_line.setFixedWidth(280)
    name_line.setFixedWidth(280)
    grid.addWidget(QLabel(_("Identity Type")), 1, 0)
    grid.addWidget(combo1, 1, 1)
    grid.addWidget(QLabel(_("Identity")), 2, 0)
    grid.addWidget(identity_line, 2, 1)
    grid.addWidget(QLabel(_("Name")), 3, 0)
    grid.addWidget(name_line, 3, 1)

    vbox.addLayout(grid)
    vbox.addLayout(Buttons(CancelButton(d), ok_button))

    if contact_key is None:
        combo1.lineEdit().setText(
            IDENTITY_SYSTEM_NAMES[IdentitySystem.OnChain])
        identity_line.setFocus()
    else:
        entry = wallet_api.get_contact(contact_key[0])
        identity = [
            ci for ci in entry.identities if ci.identity_id == contact_key[1]
        ][0]
        combo1.lineEdit().setText(IDENTITY_SYSTEM_NAMES[identity.system_id])
        identity_line.setText(identity.system_data)
        name_line.setText(entry.label)
        name_line.setFocus()

    if d.exec_():
        name_text = name_line.text().strip()
        identity_text = identity_line.text().strip()
        system_id = get_system_id(combo1.currentText())
        if contact_key is not None:
            contact = wallet_api.get_contact(contact_key[0])
            identity = [
                ci for ci in contact.identities
                if ci.identity_id == contact_key[1]
            ][0]
            if contact_key[1] != identity.identity_id:
                wallet_api.remove_identity(contact_key[0], contact_key[1])
                wallet_api.add_identity(contact_key[0], system_id,
                                        identity_text)
            if contact.label != name_text:
                wallet_api.set_label(contact_key[0], name_text)
        else:
            wallet_api.add_contact(system_id, name_text, identity_text)
Example #46
0
class SearchFileWidget(QWidget):

    language_filter_change = pyqtSignal(list)

    def __init__(self):
        QWidget.__init__(self)

        self._refreshing = False

        self.fileModel = None
        self.proxyFileModel = None
        self.videoModel = None

        self._state = None

        self.timeLastSearch = QTime.currentTime()

        self.ui = Ui_SearchFileWidget()
        self.setup_ui()

    def set_state(self, state):
        self._state = state
        self._state.login_status_changed.connect(self.on_login_state_changed)
        self._state.interface_language_changed.connect(
            self.on_interface_language_changed)

    def get_state(self):
        return self._state

    def setup_ui(self):
        self.ui.setupUi(self)
        settings = QSettings()

        self.ui.splitter.setSizes([600, 1000])
        self.ui.splitter.setChildrenCollapsible(False)

        # Set up folder view

        lastDir = settings.value("mainwindow/workingDirectory",
                                 QDir.homePath())
        log.debug('Current directory: {currentDir}'.format(currentDir=lastDir))

        self.fileModel = QFileSystemModel(self)
        self.fileModel.setFilter(QDir.AllDirs | QDir.Dirs | QDir.Drives
                                 | QDir.NoDotAndDotDot | QDir.Readable
                                 | QDir.Executable | QDir.Writable)
        self.fileModel.iconProvider().setOptions(
            QFileIconProvider.DontUseCustomDirectoryIcons)
        self.fileModel.setRootPath(QDir.rootPath())
        self.fileModel.directoryLoaded.connect(self.onFileModelDirectoryLoaded)

        self.proxyFileModel = QSortFilterProxyModel(self)
        self.proxyFileModel.setSortRole(Qt.DisplayRole)
        self.proxyFileModel.setSourceModel(self.fileModel)
        self.proxyFileModel.sort(0, Qt.AscendingOrder)
        self.proxyFileModel.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.ui.folderView.setModel(self.proxyFileModel)

        self.ui.folderView.setHeaderHidden(True)
        self.ui.folderView.hideColumn(3)
        self.ui.folderView.hideColumn(2)
        self.ui.folderView.hideColumn(1)

        index = self.fileModel.index(str(lastDir))
        proxyIndex = self.proxyFileModel.mapFromSource(index)
        self.ui.folderView.scrollTo(proxyIndex)

        self.ui.folderView.expanded.connect(self.onFolderViewExpanded)
        self.ui.folderView.clicked.connect(self.onFolderTreeClicked)
        self.ui.buttonFind.clicked.connect(self.onButtonFind)
        self.ui.buttonRefresh.clicked.connect(self.onButtonRefresh)

        # Set up introduction
        self.showInstructions()

        # Set up video view
        self.ui.filterLanguageForVideo.set_unknown_text(_('All languages'))
        self.ui.filterLanguageForVideo.set_selected_language(
            UnknownLanguage.create_generic())
        self.ui.filterLanguageForVideo.selected_language_changed.connect(
            self.on_language_combobox_filter_change)

        self.videoModel = VideoModel(self)
        self.videoModel.connect_treeview(self.ui.videoView)
        self.ui.videoView.setHeaderHidden(True)
        self.ui.videoView.activated.connect(self.onClickVideoTreeView)
        self.ui.videoView.clicked.connect(self.onClickVideoTreeView)
        self.ui.videoView.customContextMenuRequested.connect(self.onContext)
        self.videoModel.dataChanged.connect(self.subtitlesCheckedChanged)
        self.language_filter_change.connect(
            self.videoModel.on_filter_languages_change)

        self.ui.buttonSearchSelectVideos.clicked.connect(
            self.onButtonSearchSelectVideos)
        self.ui.buttonSearchSelectFolder.clicked.connect(
            self.onButtonSearchSelectFolder)
        self.ui.buttonDownload.clicked.connect(self.onButtonDownload)
        self.ui.buttonPlay.clicked.connect(self.onButtonPlay)
        self.ui.buttonIMDB.clicked.connect(self.onViewOnlineInfo)
        self.ui.videoView.setContextMenuPolicy(Qt.CustomContextMenu)

        # Drag and Drop files to the videoView enabled
        self.ui.videoView.__class__.dragEnterEvent = self.dragEnterEvent
        self.ui.videoView.__class__.dragMoveEvent = self.dragEnterEvent
        self.ui.videoView.__class__.dropEvent = self.dropEvent
        self.ui.videoView.setAcceptDrops(1)

        # FIXME: ok to drop this connect?
        # self.ui.videoView.clicked.connect(self.onClickMovieTreeView)

        self.retranslate()

    def retranslate(self):
        introduction = '<p align="center"><h2>{title}</h2></p>' \
            '<p><b>{tab1header}</b><br/>{tab1content}</p>' \
            '<p><b>{tab2header}</b><br/>{tab2content}</p>'\
            '<p><b>{tab3header}</b><br/>{tab3content}</p>'.format(
                title=_('How To Use {title}').format(title=PROJECT_TITLE),
                tab1header=_('1st Tab:'),
                tab2header=_('2nd Tab:'),
                tab3header=_('3rd Tab:'),
                tab1content=_('Select, from the Folder Tree on the left, the folder which contains the videos '
                              'that need subtitles. {project} will then try to automatically find available '
                              'subtitles.').format(project=PROJECT_TITLE),
                tab2content=_('If you don\'t have the videos in your machine, you can search subtitles by '
                              'introducing the title/name of the video.').format(project=PROJECT_TITLE),
                tab3content=_('If you have found some subtitle somewhere else that is not in {project}\'s database, '
                              'please upload those subtitles so next users will be able to '
                              'find them more easily.').format(project=PROJECT_TITLE))
        self.ui.introductionHelp.setHtml(introduction)

    @pyqtSlot(Language)
    def on_interface_language_changed(self, language):
        self.ui.retranslateUi(self)
        self.retranslate()

    @pyqtSlot(str)
    def onFileModelDirectoryLoaded(self, path):
        settings = QSettings()
        lastDir = settings.value('mainwindow/workingDirectory',
                                 QDir.homePath())
        qDirLastDir = QDir(lastDir)
        qDirLastDir.cdUp()
        if qDirLastDir.path() == path:
            index = self.fileModel.index(lastDir)
            proxyIndex = self.proxyFileModel.mapFromSource(index)
            self.ui.folderView.scrollTo(proxyIndex)
            self.ui.folderView.setCurrentIndex(proxyIndex)

    @pyqtSlot(int, str)
    def on_login_state_changed(self, state, message):
        log.debug(
            'on_login_state_changed(state={state}, message={message}'.format(
                state=state, message=message))
        if state in (State.LOGIN_STATUS_LOGGED_OUT, State.LOGIN_STATUS_BUSY):
            self.ui.buttonSearchSelectFolder.setEnabled(False)
            self.ui.buttonSearchSelectVideos.setEnabled(False)
            self.ui.buttonFind.setEnabled(False)
        elif state == State.LOGIN_STATUS_LOGGED_IN:
            self.ui.buttonSearchSelectFolder.setEnabled(True)
            self.ui.buttonSearchSelectVideos.setEnabled(True)
            self.ui.buttonFind.setEnabled(
                self.get_current_selected_folder() is not None)
        else:
            log.warning('unknown state')

    @pyqtSlot(Language)
    def on_language_combobox_filter_change(self, language):
        if language.is_generic():
            self.language_filter_change.emit(
                self.get_state().get_permanent_language_filter())
        else:
            self.language_filter_change.emit([language])

    def on_permanent_language_filter_change(self, languages):
        selected_language = self.ui.filterLanguageForVideo.get_selected_language(
        )
        if selected_language.is_generic():
            self.language_filter_change.emit(languages)

    @pyqtSlot()
    def subtitlesCheckedChanged(self):
        subs = self.videoModel.get_checked_subtitles()
        if subs:
            self.ui.buttonDownload.setEnabled(True)
        else:
            self.ui.buttonDownload.setEnabled(False)

    def showInstructions(self):
        self.ui.stackedSearchResult.setCurrentWidget(self.ui.pageIntroduction)

    def hideInstructions(self):
        self.ui.stackedSearchResult.setCurrentWidget(self.ui.pageSearchResult)

    @pyqtSlot(QModelIndex)
    def onFolderTreeClicked(self, proxyIndex):
        """What to do when a Folder in the tree is clicked"""
        if not proxyIndex.isValid():
            return

        index = self.proxyFileModel.mapToSource(proxyIndex)
        settings = QSettings()
        folder_path = self.fileModel.filePath(index)
        settings.setValue('mainwindow/workingDirectory', folder_path)
        # self.ui.buttonFind.setEnabled(self.get_state().)

    def get_current_selected_folder(self):
        proxyIndex = self.ui.folderView.currentIndex()
        index = self.proxyFileModel.mapToSource(proxyIndex)
        folder_path = Path(self.fileModel.filePath(index))
        if not folder_path:
            return None
        return folder_path

    def get_current_selected_item_videomodel(self):
        current_index = self.ui.videoView.currentIndex()
        return self.videoModel.getSelectedItem(current_index)

    @pyqtSlot()
    def onButtonFind(self):
        now = QTime.currentTime()
        if now < self.timeLastSearch.addMSecs(500):
            return
        folder_path = self.get_current_selected_folder()

        settings = QSettings()
        settings.setValue('mainwindow/workingDirectory', str(folder_path))
        self.search_videos([folder_path])

        self.timeLastSearch = QTime.currentTime()

    @pyqtSlot()
    def onButtonRefresh(self):
        currentPath = self.get_current_selected_folder()
        if not currentPath:
            settings = QSettings()
            currentPath = settings.value('mainwindow/workingDirectory',
                                         QDir.homePath())

        self._refreshing = True

        self.ui.folderView.collapseAll()

        currentPath = self.get_current_selected_folder()
        if not currentPath:
            settings = QSettings()
            currentPath = settings.value('mainwindow/workingDirectory',
                                         QDir.homePath())

        index = self.fileModel.index(str(currentPath))

        self.ui.folderView.scrollTo(self.proxyFileModel.mapFromSource(index))

    @pyqtSlot(QModelIndex)
    def onFolderViewExpanded(self, proxyIndex):
        if self._refreshing:
            expandedPath = self.fileModel.filePath(
                self.proxyFileModel.mapToSource(proxyIndex))
            if expandedPath == QDir.rootPath():
                currentPath = self.get_current_selected_folder()
                if not currentPath:
                    settings = QSettings()
                    currentPath = settings.value('mainwindow/workingDirectory',
                                                 QDir.homePath())

                index = self.fileModel.index(str(currentPath))

                self.ui.folderView.scrollTo(
                    self.proxyFileModel.mapFromSource(index))
                self._refreshing = False

    @pyqtSlot()
    def onButtonSearchSelectFolder(self):
        settings = QSettings()
        path = settings.value('mainwindow/workingDirectory', QDir.homePath())
        folder_path = QFileDialog.getExistingDirectory(
            self, _('Select the directory that contains your videos'), path)
        if folder_path:
            settings.setValue('mainwindow/workingDirectory', folder_path)
            self.search_videos([Path(folder_path)])

    @pyqtSlot()
    def onButtonSearchSelectVideos(self):
        settings = QSettings()
        currentDir = settings.value('mainwindow/workingDirectory',
                                    QDir.homePath())
        fileNames, t = QFileDialog.getOpenFileNames(
            self, _('Select the video(s) that need subtitles'), currentDir,
            get_select_videos())
        if fileNames:
            settings.setValue('mainwindow/workingDirectory',
                              QFileInfo(fileNames[0]).absolutePath())
            self.search_videos([Path(filename) for filename in fileNames])

    def search_videos(self, paths):
        if not self.get_state().connected():
            QMessageBox.about(
                self, _("Error"),
                _('You are not connected to the server. Please reconnect first.'
                  ))
            return
        self.ui.buttonFind.setEnabled(False)
        self._search_videos_raw(paths)
        self.ui.buttonFind.setEnabled(True)

    def _search_videos_raw(self, paths):
        # FIXME: must pass mainwindow as argument to ProgressCallbackWidget
        callback = ProgressCallbackWidget(self)
        callback.set_title_text(_("Scanning..."))
        callback.set_label_text(_("Scanning files"))
        callback.set_finished_text(_("Scanning finished"))
        callback.set_block(True)
        callback.show()

        try:
            local_videos, local_subs = scan_videopaths(paths,
                                                       callback=callback,
                                                       recursive=True)
        except OSError:
            callback.cancel()
            QMessageBox.warning(self, _('Error'),
                                _('Some directories are not accessible.'))

        if callback.canceled():
            return

        callback.finish()

        log.debug("Videos found: %s" % local_videos)
        log.debug("Subtitles found: %s" % local_subs)
        self.hideInstructions()

        QCoreApplication.processEvents()

        if not local_videos:
            QMessageBox.about(self, _("Scan Results"),
                              _("No video has been found."))
            return

        total = len(local_videos)

        # FIXME: must pass mainwindow as argument to ProgressCallbackWidget
        # callback = ProgressCallbackWidget(self)
        # callback.set_title_text(_("Asking Server..."))
        # callback.set_label_text(_("Searching subtitles..."))
        # callback.set_updated_text(_("Searching subtitles ( %d / %d )"))
        # callback.set_finished_text(_("Search finished"))
        callback.set_block(True)
        callback.set_range(0, total)

        callback.show()

        callback.set_range(0, 2)

        download_callback = callback.get_child_progress(0, 1)
        # videoSearchResults = self.get_state().get_OSDBServer().SearchSubtitles("", videos_piece)
        remote_subs = self.get_state().get_OSDBServer().search_videos(
            videos=local_videos, callback=download_callback)

        self.videoModel.set_videos(local_videos)
        # self.onFilterLanguageVideo(self.ui.filterLanguageForVideo.get_selected_language())

        if remote_subs is None:
            QMessageBox.about(
                self, _("Error"),
                _("Error contacting the server. Please try again later"))
        callback.finish()

        # TODO: CHECK if our local subtitles are already in the server, otherwise suggest to upload
        # self.OSDBServer.CheckSubHash(sub_hashes)

    @pyqtSlot()
    def onButtonPlay(self):
        settings = QSettings()
        programPath = settings.value('options/VideoPlayerPath', '')
        parameters = settings.value('options/VideoPlayerParameters', '')
        if programPath == '':
            QMessageBox.about(
                self, _('Error'),
                _('No default video player has been defined in Settings.'))
            return

        selected_subtitle = self.get_current_selected_item_videomodel()
        if isinstance(selected_subtitle, SubtitleFileNetwork):
            selected_subtitle = selected_subtitle.get_subtitles()[0]

        if isinstance(selected_subtitle, LocalSubtitleFile):
            subtitle_file_path = selected_subtitle.get_filepath()
        elif isinstance(selected_subtitle, RemoteSubtitleFile):
            subtitle_file_path = QDir.temp().absoluteFilePath(
                'subdownloader.tmp.srt')
            log.debug(
                'Temporary subtitle will be downloaded into: {temp_path}'.
                format(temp_path=subtitle_file_path))
            # FIXME: must pass mainwindow as argument to ProgressCallbackWidget
            callback = ProgressCallbackWidget(self)
            callback.set_title_text(_('Playing video + sub'))
            callback.set_label_text(_('Downloading files...'))
            callback.set_finished_text(_('Downloading finished'))
            callback.set_block(True)
            callback.set_range(0, 100)
            callback.show()
            try:
                subtitle_stream = selected_subtitle.download(
                    self.get_state().get_OSDBServer(), callback=callback)
            except ProviderConnectionError:
                log.debug('Unable to download subtitle "{}"'.format(
                    selected_subtitle.get_filename()),
                          exc_info=sys.exc_info())
                QMessageBox.about(
                    self, _('Error'),
                    _('Unable to download subtitle "{subtitle}"').format(
                        subtitle=selected_subtitle.get_filename()))
                callback.finish()
                return
            callback.finish()
            write_stream(subtitle_stream, subtitle_file_path)

        video = selected_subtitle.get_parent().get_parent().get_parent()

        def windows_escape(text):
            return '"{text}"'.format(text=text.replace('"', '\\"'))

        params = [windows_escape(programPath)]

        for param in parameters.split(' '):
            param = param.format(video.get_filepath(), subtitle_file_path)
            if platform.system() in ('Windows', 'Microsoft'):
                param = windows_escape(param)
            params.append(param)

        pid = None
        log.info('Running this command: {params}'.format(params=params))
        try:
            log.debug('Trying os.spawnvpe ...')
            pid = os.spawnvpe(os.P_NOWAIT, programPath, params, os.environ)
            log.debug('... SUCCESS. pid={pid}'.format(pid=pid))
        except AttributeError:
            log.debug('... FAILED', exc_info=sys.exc_info())
        except Exception as e:
            log.debug('... FAILED', exc_info=sys.exc_info())
        if pid is None:
            try:
                log.debug('Trying os.fork ...')
                pid = os.fork()
                if not pid:
                    log.debug('... SUCCESS. pid={pid}'.format(pid=pid))
                    os.execvpe(os.P_NOWAIT, programPath, params, os.environ)
            except:
                log.debug('... FAIL', exc_info=sys.exc_info())
        if pid is None:
            QMessageBox.about(self, _('Error'),
                              _('Unable to launch videoplayer'))

    @pyqtSlot(QModelIndex)
    def onClickVideoTreeView(self, index):
        data_item = self.videoModel.getSelectedItem(index)

        if isinstance(data_item, SubtitleFile):
            self.ui.buttonPlay.setEnabled(True)
        else:
            self.ui.buttonPlay.setEnabled(False)

        if isinstance(data_item, VideoFile):
            video = data_item
            if True:  # video.getMovieInfo():
                self.ui.buttonIMDB.setEnabled(True)
                self.ui.buttonIMDB.setIcon(QIcon(':/images/info.png'))
                self.ui.buttonIMDB.setText(_('Movie Info'))
        elif isinstance(data_item, RemoteSubtitleFile):
            self.ui.buttonIMDB.setEnabled(True)
            self.ui.buttonIMDB.setIcon(
                QIcon(':/images/sites/opensubtitles.png'))
            self.ui.buttonIMDB.setText(_('Subtitle Info'))
        else:
            self.ui.buttonIMDB.setEnabled(False)

    def onContext(self, point):
        # FIXME: code duplication with Main.onContext and/or SearchNameWidget and/or SearchFileWidget
        menu = QMenu('Menu', self)

        listview = self.ui.videoView

        index = listview.currentIndex()
        data_item = listview.model().getSelectedItem(index)
        if data_item is not None:
            if isinstance(data_item, VideoFile):
                video = data_item
                video_identities = video.get_identities()
                if any(video_identities.iter_imdb_identity()):
                    online_action = QAction(QIcon(":/images/info.png"),
                                            _("View IMDb info"), self)
                    online_action.triggered.connect(self.onViewOnlineInfo)
                else:
                    online_action = QAction(QIcon(":/images/info.png"),
                                            _("Set IMDb info..."), self)
                    online_action.triggered.connect(self.on_set_imdb_info)
                menu.addAction(online_action)
            elif isinstance(data_item, SubtitleFile):
                play_action = QAction(QIcon(":/images/play.png"),
                                      _("Play video + subtitle"), self)
                play_action.triggered.connect(self.onButtonPlay)
                menu.addAction(play_action)

                if isinstance(data_item, RemoteSubtitleFile):
                    download_action = QAction(QIcon(":/images/download.png"),
                                              _("Download"), self)
                    download_action.triggered.connect(self.onButtonDownload)
                    menu.addAction(download_action)

                    online_action = QAction(
                        QIcon(":/images/sites/opensubtitles.png"),
                        _("View online info"), self)
                    online_action.triggered.connect(self.onViewOnlineInfo)
                    menu.addAction(online_action)

        # Show the context menu.
        menu.exec_(listview.mapToGlobal(point))

    def onButtonDownload(self):
        # We download the subtitle in the same folder than the video
        subs = self.videoModel.get_checked_subtitles()
        replace_all = False
        skip_all = False
        if not subs:
            QMessageBox.about(self, _("Error"),
                              _("No subtitles selected to be downloaded"))
            return
        total_subs = len(subs)
        answer = None
        success_downloaded = 0

        # FIXME: must pass mainwindow as argument to ProgressCallbackWidget
        callback = ProgressCallbackWidget(self)
        callback.set_title_text(_("Downloading..."))
        callback.set_label_text(_("Downloading files..."))
        callback.set_updated_text(_("Downloading subtitle {0} ({1}/{2})"))
        callback.set_finished_text(
            _("{0} from {1} subtitles downloaded successfully"))
        callback.set_block(True)
        callback.set_range(0, total_subs)

        callback.show()

        for i, sub in enumerate(subs):
            if callback.canceled():
                break
            destinationPath = self.get_state().getDownloadPath(self, sub)
            if not destinationPath:
                break
            log.debug("Trying to download subtitle '%s'" % destinationPath)
            callback.update(i,
                            QFileInfo(destinationPath).fileName(), i + 1,
                            total_subs)

            # Check if we have write permissions, otherwise show warning window
            while True:
                # If the file and the folder don't have write access.
                if not QFileInfo(
                        destinationPath).isWritable() and not QFileInfo(
                            QFileInfo(destinationPath).absoluteDir().path()
                        ).isWritable():
                    warningBox = QMessageBox(
                        _("Error write permission"),
                        _("%s cannot be saved.\nCheck that the folder exists and you have write-access permissions."
                          ) % destinationPath, QMessageBox.Warning,
                        QMessageBox.Retry | QMessageBox.Default,
                        QMessageBox.Discard | QMessageBox.Escape,
                        QMessageBox.NoButton, self)

                    saveAsButton = warningBox.addButton(
                        _("Save as..."), QMessageBox.ActionRole)
                    answer = warningBox.exec_()
                    if answer == QMessageBox.Retry:
                        continue
                    elif answer == QMessageBox.Discard:
                        break  # Let's get out from the While true
                    # If we choose the SAVE AS
                    elif answer == QMessageBox.NoButton:
                        fileName, t = QFileDialog.getSaveFileName(
                            self, _("Save subtitle as..."), destinationPath,
                            'All (*.*)')
                        if fileName:
                            destinationPath = fileName
                else:  # If we have write access we leave the while loop.
                    break

            # If we have chosen Discard subtitle button.
            if answer == QMessageBox.Discard:
                continue  # Continue the next subtitle

            optionWhereToDownload = QSettings().value(
                "options/whereToDownload", "SAME_FOLDER")
            # Check if doesn't exists already, otherwise show fileExistsBox
            # dialog
            if QFileInfo(destinationPath).exists(
            ) and not replace_all and not skip_all and optionWhereToDownload != "ASK_FOLDER":
                # The "remote filename" below is actually not the real filename. Real name could be confusing
                # since we always rename downloaded sub to match movie
                # filename.
                fileExistsBox = QMessageBox(
                    QMessageBox.Warning, _("File already exists"),
                    _("Local: {local}\n\nRemote: {remote}\n\nHow would you like to proceed?"
                      ).format(local=destinationPath,
                               remote=QFileInfo(destinationPath).fileName()),
                    QMessageBox.NoButton, self)
                skipButton = fileExistsBox.addButton(_("Skip"),
                                                     QMessageBox.ActionRole)
                #                    skipAllButton = fileExistsBox.addButton(_("Skip all"), QMessageBox.ActionRole)
                replaceButton = fileExistsBox.addButton(
                    _("Replace"), QMessageBox.ActionRole)
                replaceAllButton = fileExistsBox.addButton(
                    _("Replace all"), QMessageBox.ActionRole)
                saveAsButton = fileExistsBox.addButton(_("Save as..."),
                                                       QMessageBox.ActionRole)
                cancelButton = fileExistsBox.addButton(_("Cancel"),
                                                       QMessageBox.ActionRole)
                fileExistsBox.exec_()
                answer = fileExistsBox.clickedButton()
                if answer == replaceAllButton:
                    # Don't ask us again (for this batch of files)
                    replace_all = True
                elif answer == saveAsButton:
                    # We will find a uniqiue filename and suggest this to user.
                    # add .<lang> to (inside) the filename. If that is not enough, start adding numbers.
                    # There should also be a preferences setting "Autorename
                    # files" or similar ( =never ask) FIXME
                    suggBaseName, suggFileExt = os.path.splitext(
                        destinationPath)
                    fNameCtr = 0  # Counter used to generate a unique filename
                    suggestedFileName = suggBaseName + '.' + \
                        sub.get_language().xxx() + suggFileExt
                    while (os.path.exists(suggestedFileName)):
                        fNameCtr += 1
                        suggestedFileName = suggBaseName + '.' + \
                            sub.get_language().xxx() + '-' + \
                            str(fNameCtr) + suggFileExt
                    fileName, t = QFileDialog.getSaveFileName(
                        None, _("Save subtitle as..."), suggestedFileName,
                        'All (*.*)')
                    if fileName:
                        destinationPath = fileName
                    else:
                        # Skip this particular file if no filename chosen
                        continue
                elif answer == skipButton:
                    continue  # Skip this particular file
#                    elif answer == skipAllButton:
#                        count += percentage
#                        skip_all = True # Skip all files already downloaded
#                        continue
                elif answer == cancelButton:
                    break  # Break out of DL loop - cancel was pushed
            QCoreApplication.processEvents()
            # FIXME: redundant update?
            callback.update(i,
                            QFileInfo(destinationPath).fileName(), i + 1,
                            total_subs)
            try:
                if not skip_all:
                    log.debug("Downloading subtitle '%s'" % destinationPath)
                    download_callback = ProgressCallback()  # FIXME
                    data_stream = sub.download(
                        provider_instance=self.get_state().get_OSDBServer(),
                        callback=download_callback,
                    )
                    write_stream(data_stream, destinationPath)
            except Exception as e:
                log.exception('Unable to Download subtitle {}'.format(
                    sub.get_filename()))
                QMessageBox.about(
                    self, _("Error"),
                    _("Unable to download subtitle %s") % sub.get_filename())
        callback.finish(success_downloaded, total_subs)

    def onViewOnlineInfo(self):
        # FIXME: code duplication with Main.onContext and/or SearchNameWidget and/or SearchFileWidget
        # Tab for SearchByHash TODO:replace this 0 by an ENUM value
        listview = self.ui.videoView
        index = listview.currentIndex()
        data_item = self.videoModel.getSelectedItem(index)

        if isinstance(data_item, VideoFile):
            video = data_item
            video_identities = video.get_identities()
            if any(video_identities.iter_imdb_identity()):
                imdb_identity = next(video_identities.iter_imdb_identity())
                webbrowser.open(imdb_identity.get_imdb_url(),
                                new=2,
                                autoraise=1)

        elif isinstance(data_item, RemoteSubtitleFile):
            sub = data_item
            webbrowser.open(sub.get_link(), new=2, autoraise=1)

    @pyqtSlot()
    def on_set_imdb_info(self):
        #FIXME: DUPLICATED WITH SEARCHNAMEWIDGET
        QMessageBox.about(self, _("Info"), "Not implemented yet. Sorry...")
Example #47
0
    def setup_ui(self):
        self.ui.setupUi(self)
        settings = QSettings()

        self.ui.splitter.setSizes([600, 1000])
        self.ui.splitter.setChildrenCollapsible(False)

        # Set up folder view

        lastDir = settings.value("mainwindow/workingDirectory",
                                 QDir.homePath())
        log.debug('Current directory: {currentDir}'.format(currentDir=lastDir))

        self.fileModel = QFileSystemModel(self)
        self.fileModel.setFilter(QDir.AllDirs | QDir.Dirs | QDir.Drives
                                 | QDir.NoDotAndDotDot | QDir.Readable
                                 | QDir.Executable | QDir.Writable)
        self.fileModel.iconProvider().setOptions(
            QFileIconProvider.DontUseCustomDirectoryIcons)
        self.fileModel.setRootPath(QDir.rootPath())
        self.fileModel.directoryLoaded.connect(self.onFileModelDirectoryLoaded)

        self.proxyFileModel = QSortFilterProxyModel(self)
        self.proxyFileModel.setSortRole(Qt.DisplayRole)
        self.proxyFileModel.setSourceModel(self.fileModel)
        self.proxyFileModel.sort(0, Qt.AscendingOrder)
        self.proxyFileModel.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.ui.folderView.setModel(self.proxyFileModel)

        self.ui.folderView.setHeaderHidden(True)
        self.ui.folderView.hideColumn(3)
        self.ui.folderView.hideColumn(2)
        self.ui.folderView.hideColumn(1)

        index = self.fileModel.index(str(lastDir))
        proxyIndex = self.proxyFileModel.mapFromSource(index)
        self.ui.folderView.scrollTo(proxyIndex)

        self.ui.folderView.expanded.connect(self.onFolderViewExpanded)
        self.ui.folderView.clicked.connect(self.onFolderTreeClicked)
        self.ui.buttonFind.clicked.connect(self.onButtonFind)
        self.ui.buttonRefresh.clicked.connect(self.onButtonRefresh)

        # Set up introduction
        self.showInstructions()

        # Set up video view
        self.ui.filterLanguageForVideo.set_unknown_text(_('All languages'))
        self.ui.filterLanguageForVideo.set_selected_language(
            UnknownLanguage.create_generic())
        self.ui.filterLanguageForVideo.selected_language_changed.connect(
            self.on_language_combobox_filter_change)

        self.videoModel = VideoModel(self)
        self.videoModel.connect_treeview(self.ui.videoView)
        self.ui.videoView.setHeaderHidden(True)
        self.ui.videoView.activated.connect(self.onClickVideoTreeView)
        self.ui.videoView.clicked.connect(self.onClickVideoTreeView)
        self.ui.videoView.customContextMenuRequested.connect(self.onContext)
        self.videoModel.dataChanged.connect(self.subtitlesCheckedChanged)
        self.language_filter_change.connect(
            self.videoModel.on_filter_languages_change)

        self.ui.buttonSearchSelectVideos.clicked.connect(
            self.onButtonSearchSelectVideos)
        self.ui.buttonSearchSelectFolder.clicked.connect(
            self.onButtonSearchSelectFolder)
        self.ui.buttonDownload.clicked.connect(self.onButtonDownload)
        self.ui.buttonPlay.clicked.connect(self.onButtonPlay)
        self.ui.buttonIMDB.clicked.connect(self.onViewOnlineInfo)
        self.ui.videoView.setContextMenuPolicy(Qt.CustomContextMenu)

        # Drag and Drop files to the videoView enabled
        self.ui.videoView.__class__.dragEnterEvent = self.dragEnterEvent
        self.ui.videoView.__class__.dragMoveEvent = self.dragEnterEvent
        self.ui.videoView.__class__.dropEvent = self.dropEvent
        self.ui.videoView.setAcceptDrops(1)

        # FIXME: ok to drop this connect?
        # self.ui.videoView.clicked.connect(self.onClickMovieTreeView)

        self.retranslate()
Example #48
0
 def __init__(self, username):
     QSortFilterProxyModel.__init__(self)
     self.username = username
     self.tFilt = ""
     self.uFilt = ""
     self.setDynamicSortFilter(True)
Example #49
0
class RBACRuleQueryTab(AnalysisTab):
    """A RBAC rule query."""
    def __init__(self, parent, policy, perm_map):
        super(RBACRuleQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = RBACRuleQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)
        logging.getLogger("setools.rbacrulequery").removeHandler(self.handler)

    def setupUi(self):
        self.load_ui("apol/rbacrulequery.ui")

        # set up role autocompletion (source, default)
        role_completion_list = [str(r) for r in self.policy.roles()]
        role_completer_model = QStringListModel(self)
        role_completer_model.setStringList(sorted(role_completion_list))
        self.role_completion = QCompleter()
        self.role_completion.setModel(role_completer_model)
        self.source.setCompleter(self.role_completion)
        self.default_role.setCompleter(self.role_completion)

        # set up role/type autocompletion (target)
        roletype_completion_list = [str(r) for r in self.policy.roles()]
        # roletype_completion_list.extend(str(a) for a in self.policy.roleattributes())
        roletype_completion_list.extend(str(t) for t in self.policy.types())
        roletype_completion_list.extend(
            str(a) for a in self.policy.typeattributes())
        roletype_completer_model = QStringListModel(self)
        roletype_completer_model.setStringList(
            sorted(roletype_completion_list))
        self.roletype_completion = QCompleter()
        self.roletype_completion.setModel(roletype_completer_model)
        self.target.setCompleter(self.roletype_completion)

        # setup indications of errors on source/target/default
        self.errors = set()
        self.orig_palette = self.source.palette()
        self.error_palette = self.source.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_source_error()
        self.clear_target_error()
        self.clear_default_error()

        # populate class list
        self.class_model = SEToolsListModel(self)
        self.class_model.item_list = sorted(self.policy.classes())
        self.tclass.setModel(self.class_model)

        # set up results
        self.table_results_model = RBACRuleTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.rbacrulequery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_source_regex(self.source_regex.isChecked())
        self.set_target_regex(self.target_regex.isChecked())
        self.set_default_regex(self.default_regex.isChecked())
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes)
        self.all_ruletypes.clicked.connect(self.set_all_ruletypes)
        self.source.textEdited.connect(self.clear_source_error)
        self.source.editingFinished.connect(self.set_source)
        self.source_regex.toggled.connect(self.set_source_regex)
        self.target.textEdited.connect(self.clear_target_error)
        self.target.editingFinished.connect(self.set_target)
        self.target_regex.toggled.connect(self.set_target_regex)
        self.tclass.selectionModel().selectionChanged.connect(self.set_tclass)
        self.invert_class.clicked.connect(self.invert_tclass_selection)
        self.default_role.textEdited.connect(self.clear_default_error)
        self.default_role.editingFinished.connect(self.set_default_role)
        self.default_regex.toggled.connect(self.set_default_regex)

    #
    # Ruletype criteria
    #

    def _set_ruletypes(self, value):
        self.allow.setChecked(value)
        self.role_transition.setChecked(value)

    def set_all_ruletypes(self):
        self._set_ruletypes(True)

    def clear_all_ruletypes(self):
        self._set_ruletypes(False)

    #
    # Source criteria
    #

    def clear_source_error(self):
        self.clear_criteria_error(self.source,
                                  "Match the source role of the rule.")

    def set_source(self):
        try:
            self.query.source = self.source.text()
        except Exception as ex:
            self.log.error("Source role error: {0}".format(ex))
            self.set_criteria_error(self.source, ex)

    def set_source_regex(self, state):
        self.log.debug("Setting source_regex {0}".format(state))
        self.query.source_regex = state
        self.clear_source_error()
        self.set_source()

    #
    # Target criteria
    #

    def clear_target_error(self):
        self.clear_criteria_error(self.target,
                                  "Match the target role/type of the rule.")

    def set_target(self):
        try:
            self.query.target = self.target.text()
        except Exception as ex:
            self.log.error("Target type/role error: {0}".format(ex))
            self.set_criteria_error(self.target, ex)

    def set_target_regex(self, state):
        self.log.debug("Setting target_regex {0}".format(state))
        self.query.target_regex = state
        self.clear_target_error()
        self.set_target()

    #
    # Class criteria
    #

    def set_tclass(self):
        selected_classes = []
        for index in self.tclass.selectionModel().selectedIndexes():
            selected_classes.append(self.class_model.data(index, Qt.UserRole))

        self.query.tclass = selected_classes

    def invert_tclass_selection(self):
        invert_list_selection(self.tclass.selectionModel())

    #
    # Default criteria
    #

    def clear_default_error(self):
        self.clear_criteria_error(self.default_role,
                                  "Match the default role the rule.")

    def set_default_role(self):
        self.query.default_regex = self.default_regex.isChecked()

        try:
            self.query.default = self.default_role.text()
        except Exception as ex:
            self.log.error("Default role error: {0}".format(ex))
            self.set_criteria_error(self.default_role, ex)

    def set_default_regex(self, state):
        self.log.debug("Setting default_regex {0}".format(state))
        self.query.default_regex = state
        self.clear_default_error()
        self.set_default_role()

    #
    # Save/Load tab
    #
    def save(self):
        """Return a dictionary of settings."""
        if self.errors:
            raise TabFieldError("Field(s) are in error: {0}".format(" ".join(
                o.objectName() for o in self.errors)))

        settings = {}
        save_checkboxes(self, settings, [
            "criteria_expander", "notes_expander", "allow", "role_transition",
            "source_indirect", "source_regex", "target_indirect",
            "target_regex", "default_regex"
        ])
        save_lineedits(self, settings, ["source", "target", "default_role"])
        save_listviews(self, settings, ["tclass"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings, [
            "criteria_expander", "notes_expander", "allow", "role_transition",
            "source_indirect", "source_regex", "target_indirect",
            "target_regex", "default_regex"
        ])
        load_lineedits(self, settings, ["source", "target", "default_role"])
        load_listviews(self, settings, ["tclass"])
        load_textedits(self, settings, ["notes"])

    #
    # Results runner
    #

    def run(self, button):
        # right now there is only one button.
        rule_types = []

        for mode in [self.allow, self.role_transition]:
            if mode.isChecked():
                rule_types.append(mode.objectName())

        self.query.ruletype = rule_types
        self.query.source_indirect = self.source_indirect.isChecked()
        self.query.target_indirect = self.target_indirect.isChecked()

        # start processing
        self.busy.setLabelText("Processing query...")
        self.busy.show()
        self.raw_results.clear()
        self.thread.start()

    def update_complete(self, count):
        self.log.info("{0} RBAC rule(s) found.".format(count))

        # update sizes/location of result displays
        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's columns; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeColumnsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's rows; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeRowsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Moving the raw result to top; GUI may be unresponsive")
            self.busy.repaint()
            self.raw_results.moveCursor(QTextCursor.Start)

        self.busy.reset()
Example #50
0
 def populate_table(self, table: QTableView, data=[]):
     model = TableModel(data)
     sortable_model = QSortFilterProxyModel(model)
     sortable_model.setSourceModel(model)
     table.setModel(sortable_model)
Example #51
0
    def setupUi(self):
        self.load_ui("netifconquery.ui")

        # set up user autocompletion
        user_completion_list = [str(u) for u in self.policy.users()]
        user_completer_model = QStringListModel(self)
        user_completer_model.setStringList(sorted(user_completion_list))
        self.user_completion = QCompleter()
        self.user_completion.setModel(user_completer_model)
        self.user.setCompleter(self.user_completion)

        # set up role autocompletion
        role_completion_list = [str(r) for r in self.policy.roles()]
        role_completer_model = QStringListModel(self)
        role_completer_model.setStringList(sorted(role_completion_list))
        self.role_completion = QCompleter()
        self.role_completion.setModel(role_completer_model)
        self.role.setCompleter(self.role_completion)

        # set up type autocompletion
        type_completion_list = [str(t) for t in self.policy.types()]
        type_completer_model = QStringListModel(self)
        type_completer_model.setStringList(sorted(type_completion_list))
        self.type_completion = QCompleter()
        self.type_completion.setModel(type_completer_model)
        self.type_.setCompleter(self.type_completion)

        # setup indications of errors on source/target/default
        self.orig_palette = self.type_.palette()
        self.error_palette = self.type_.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_name_error()
        self.clear_user_error()
        self.clear_type_error()
        self.clear_role_error()
        self.clear_range_error()

        # set up results
        self.table_results_model = NetifconTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.netifconquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_name_regex(self.name_regex.isChecked())
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # Range criteria is available only if policy is MLS
        if not self.policy.mls:
            self.range_criteria.setEnabled(False)
            self.range_criteria.setToolTip("MLS is disabled in this policy.")
            self.range_.setToolTip("MLS is disabled in this policy.")
            self.range_exact.setToolTip("MLS is disabled in this policy.")
            self.range_overlap.setToolTip("MLS is disabled in this policy.")
            self.range_subset.setToolTip("MLS is disabled in this policy.")
            self.range_superset.setToolTip("MLS is disabled in this policy.")

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.name.textEdited.connect(self.clear_name_error)
        self.name.editingFinished.connect(self.set_name)
        self.name_regex.toggled.connect(self.set_name_regex)
        self.user.textEdited.connect(self.clear_user_error)
        self.user.editingFinished.connect(self.set_user)
        self.user_regex.toggled.connect(self.set_user_regex)
        self.role.textEdited.connect(self.clear_role_error)
        self.role.editingFinished.connect(self.set_role)
        self.role_regex.toggled.connect(self.set_role_regex)
        self.type_.textEdited.connect(self.clear_type_error)
        self.type_.editingFinished.connect(self.set_type)
        self.type_regex.toggled.connect(self.set_type_regex)
        self.range_.textEdited.connect(self.clear_range_error)
        self.range_.editingFinished.connect(self.set_range)
Example #52
0
class DwarfListView(QTreeView):
    """ Using QTreeView as ListView because it allows ListView+QHeaderView
    """
    def __init__(self, parent=None, search_enabled=True):
        super(DwarfListView, self).__init__(parent=parent)

        self._search_enabled = search_enabled
        self._current_search = ''

        self._uppercase_hex = True

        _prefs = Prefs()
        self.rows_dualcolor = _prefs.get('dwarf_ui_alternaterowcolors', False)
        self.uppercase_hex = _prefs.get('dwarf_ui_hexstyle',
                                        'upper').lower() == 'upper'

        self.setEditTriggers(self.NoEditTriggers)
        self.setHeaderHidden(False)
        self.setAutoFillBackground(True)
        self.setRootIsDecorated(False)
        # TODO: use filter
        self._proxy_model = QSortFilterProxyModel(self)
        self._proxy_model.setSourceModel(self.model())
        # self.setSortingEnabled(True)

    def keyPressEvent(self, event):
        """ onkeydown
        """
        key = event.key()
        mod = event.modifiers()
        if key == Qt.Key_F and mod & Qt.ControlModifier and self.search_enabled:  # CTRL + F
            self._on_cm_search()
        else:
            super(DwarfListView, self).keyPressEvent(event)

    # ************************************************************************
    # **************************** Properties ********************************
    # ************************************************************************
    @property
    def rows_dualcolor(self):
        """ AlternatingRowColors
        """
        return self.alternatingRowColors()

    @rows_dualcolor.setter
    def rows_dualcolor(self, value):
        """ AlternatingRowColors
        """
        if isinstance(value, bool):
            self.setAlternatingRowColors(value)
        elif isinstance(value, str):
            self.setAlternatingRowColors(value.lower() == 'true')

    @property
    def uppercase_hex(self):
        """ Addresses displayed lower/upper-case
        """
        return self._uppercase_hex

    @uppercase_hex.setter
    def uppercase_hex(self, value):
        """ Addresses displayed lower/upper-case
            value - bool or str
                    'upper', 'lower'
        """
        if isinstance(value, bool):
            self._uppercase_hex = value
        elif isinstance(value, str):
            self._uppercase_hex = (value == 'upper')

    @property
    def search_enabled(self):
        return self._search_enabled

    @search_enabled.setter
    def search_enabled(self, value):
        if isinstance(value, bool):
            self._search_enabled = value

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def clear(self):
        """ Delete Entries but not Headerdata
        """
        model = self.model()
        if model is not None:
            model.removeRows(0, model.rowCount())

    def get_item(self, index):
        """ Returns [] with col_texts
        """
        if self.model() is not None:
            item_data = []
            if index < self.model().rowCount():
                for i in range(self.model().columnCount()):
                    item_text = self.model().item(index, i).text()
                    if item_text:
                        item_data.append(item_text)
                    else:
                        item_data.append('')

                return item_data

        return None

    def get_item_text(self, index, col):
        """ returns text in index, col
        """
        if self.model() is not None:
            if index < self.model().rowCount():
                if col < self.model().columnCount():
                    item = self.model().item(index, col)
                    if isinstance(item, QStandardItem):
                        return self.model().item(index, col).text()

        return None

    def contains_text(self,
                      text,
                      case_sensitive=False,
                      stop_at_match=True,
                      match_exactly=False):
        """ looks in all fields for text
            returns true, [[row, col]] if text exists
        """
        if not text:
            return

        ret_val = False
        ret_res = []
        if self.model() is not None:
            for i in range(self.model().rowCount()):
                for j in range(self.model().columnCount()):
                    item_text = self.get_item_text(i, j)
                    if item_text is None:
                        continue

                    if match_exactly:
                        if not case_sensitive:
                            _eval = item_text.lower() == text.lower()
                        else:
                            _eval = item_text == text
                    else:
                        if not case_sensitive:
                            _eval = text.lower() in item_text.lower()
                        else:
                            _eval = item_text in text

                    if _eval:
                        ret_res.append([i, j])
                        if stop_at_match:
                            break
        if ret_res:
            ret_val = True

        if ret_val:
            return ret_val, ret_res
        else:
            return ret_val, []

    def number_of_items(self):
        """ returns number of rows
        """
        if self.model() is not None:
            return self.model().rowCount()

        return None

    def number_of_rows(self):
        """ returns number of rows
        """
        if self.model() is not None:
            return self.number_of_items()

        return None

    def number_of_total(self):
        """ returns number of all fields rows+cols
        """
        if self.model() is not None:
            return self.model().rowCount() + self.model().columnCount()

        return None

    def number_of_cols(self):
        """ returns number of cols
        """
        if self.model() is not None:
            return self.model().columnCount()

        return None

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def mouseDoubleClickEvent(self, event):  # pylint: disable=invalid-name
        """ override doubleclickevent to prevent doublerightclicks
        """
        if event.button() == Qt.LeftButton:
            super().mouseDoubleClickEvent(event)

    def resizeEvent(self, event):  # pylint: disable=invalid-name
        """ override to give user control over header back
        """
        super(DwarfListView, self).resizeEvent(event)
        header = self.header()
        resize_mode = (QHeaderView.ResizeToContents | QHeaderView.Interactive)
        if header:
            for col in range(header.count()):
                if header.sectionResizeMode(col) == resize_mode:
                    header.setSectionResizeMode(col,
                                                QHeaderView.ResizeToContents)
                    width = header.sectionSize(col)
                    header.setSectionResizeMode(col, QHeaderView.Interactive)
                    header.resizeSection(col, width)

    def _on_cm_search(self):
        from dwarf_debugger.ui.dialogs.dialog_input import InputDialog
        accept, input_ = InputDialog.input(
            self,
            hint='Search something in this list',
            placeholder='search...',
            input_content=self._current_search)

        if accept and not input_:
            # reset search
            self._current_search = ''
            for row in range(self.model().rowCount()):
                self.setRowHidden(row,
                                  self.model().invisibleRootItem().index(),
                                  False)
        elif accept and input_:
            # search for input
            self._current_search = input_

            have_result, search_results = self.contains_text(
                input_, stop_at_match=False)

            if not have_result:
                return

            # hide non matching
            for row in range(self.model().rowCount()):
                item = self.model().item(row, 0)
                hide = True
                for sr in search_results:
                    if sr[0] == row:
                        hide = False
                        break

                self.setRowHidden(row,
                                  self.model().invisibleRootItem().index(),
                                  hide)
Example #53
0
class NetifconQueryTab(SEToolsWidget, QScrollArea):
    """A netifcon query."""
    def __init__(self, parent, policy, perm_map):
        super(NetifconQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = NetifconQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)
        logging.getLogger("setools.netifconquery").removeHandler(self.handler)

    def setupUi(self):
        self.load_ui("netifconquery.ui")

        # set up user autocompletion
        user_completion_list = [str(u) for u in self.policy.users()]
        user_completer_model = QStringListModel(self)
        user_completer_model.setStringList(sorted(user_completion_list))
        self.user_completion = QCompleter()
        self.user_completion.setModel(user_completer_model)
        self.user.setCompleter(self.user_completion)

        # set up role autocompletion
        role_completion_list = [str(r) for r in self.policy.roles()]
        role_completer_model = QStringListModel(self)
        role_completer_model.setStringList(sorted(role_completion_list))
        self.role_completion = QCompleter()
        self.role_completion.setModel(role_completer_model)
        self.role.setCompleter(self.role_completion)

        # set up type autocompletion
        type_completion_list = [str(t) for t in self.policy.types()]
        type_completer_model = QStringListModel(self)
        type_completer_model.setStringList(sorted(type_completion_list))
        self.type_completion = QCompleter()
        self.type_completion.setModel(type_completer_model)
        self.type_.setCompleter(self.type_completion)

        # setup indications of errors on source/target/default
        self.orig_palette = self.type_.palette()
        self.error_palette = self.type_.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_name_error()
        self.clear_user_error()
        self.clear_type_error()
        self.clear_role_error()
        self.clear_range_error()

        # set up results
        self.table_results_model = NetifconTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.netifconquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_name_regex(self.name_regex.isChecked())
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # Range criteria is available only if policy is MLS
        if not self.policy.mls:
            self.range_criteria.setEnabled(False)
            self.range_criteria.setToolTip("MLS is disabled in this policy.")
            self.range_.setToolTip("MLS is disabled in this policy.")
            self.range_exact.setToolTip("MLS is disabled in this policy.")
            self.range_overlap.setToolTip("MLS is disabled in this policy.")
            self.range_subset.setToolTip("MLS is disabled in this policy.")
            self.range_superset.setToolTip("MLS is disabled in this policy.")

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.name.textEdited.connect(self.clear_name_error)
        self.name.editingFinished.connect(self.set_name)
        self.name_regex.toggled.connect(self.set_name_regex)
        self.user.textEdited.connect(self.clear_user_error)
        self.user.editingFinished.connect(self.set_user)
        self.user_regex.toggled.connect(self.set_user_regex)
        self.role.textEdited.connect(self.clear_role_error)
        self.role.editingFinished.connect(self.set_role)
        self.role_regex.toggled.connect(self.set_role_regex)
        self.type_.textEdited.connect(self.clear_type_error)
        self.type_.editingFinished.connect(self.set_type)
        self.type_regex.toggled.connect(self.set_type_regex)
        self.range_.textEdited.connect(self.clear_range_error)
        self.range_.editingFinished.connect(self.set_range)

    #
    # Name criteria
    #
    def clear_name_error(self):
        self.name.setToolTip("Match the device name.")
        self.name.setPalette(self.orig_palette)

    def set_name(self):
        try:
            self.query.name = self.name.text()
        except Exception as ex:
            self.log.error("Device name error: {0}".format(ex))
            self.name.setToolTip("Error: " + str(ex))
            self.name.setPalette(self.error_palette)

    def set_name_regex(self, state):
        self.log.debug("Setting name_regex {0}".format(state))
        self.query.name_regex = state
        self.clear_name_error()
        self.set_name()

    #
    # User criteria
    #
    def clear_user_error(self):
        self.user.setToolTip("Match the user of the context.")
        self.user.setPalette(self.orig_palette)

    def set_user(self):
        try:
            self.query.user = self.user.text()
        except Exception as ex:
            self.log.error("Context user error: {0}".format(ex))
            self.user.setToolTip("Error: " + str(ex))
            self.user.setPalette(self.error_palette)

    def set_user_regex(self, state):
        self.log.debug("Setting user_regex {0}".format(state))
        self.query.user_regex = state
        self.clear_user_error()
        self.set_user()

    #
    # Role criteria
    #
    def clear_role_error(self):
        self.role.setToolTip("Match the role of the context.")
        self.role.setPalette(self.orig_palette)

    def set_role(self):
        try:
            self.query.role = self.role.text()
        except Exception as ex:
            self.log.error("Context role error: {0}".format(ex))
            self.role.setToolTip("Error: " + str(ex))
            self.role.setPalette(self.error_palette)

    def set_role_regex(self, state):
        self.log.debug("Setting role_regex {0}".format(state))
        self.query.role_regex = state
        self.clear_role_error()
        self.set_role()

    #
    # Type criteria
    #
    def clear_type_error(self):
        self.type_.setToolTip("Match the type of the context.")
        self.type_.setPalette(self.orig_palette)

    def set_type(self):
        try:
            self.query.type_ = self.type_.text()
        except Exception as ex:
            self.log.error("Context type error: {0}".format(ex))
            self.type_.setToolTip("Error: " + str(ex))
            self.type_.setPalette(self.error_palette)

    def set_type_regex(self, state):
        self.log.debug("Setting type_regex {0}".format(state))
        self.query.type_regex = state
        self.clear_type_error()
        self.set_type()

    #
    # Range criteria
    #
    def clear_range_error(self):
        self.range_.setToolTip("Match the range of the context.")
        self.range_.setPalette(self.orig_palette)

    def set_range(self):
        try:
            self.query.range_ = self.range_.text()
        except Exception as ex:
            self.log.info("Context range error: " + str(ex))
            self.range_.setToolTip("Error: " + str(ex))
            self.range_.setPalette(self.error_palette)

    #
    # Results runner
    #
    def run(self, button):
        # right now there is only one button.
        self.query.range_overlap = self.range_overlap.isChecked()
        self.query.range_subset = self.range_subset.isChecked()
        self.query.range_superset = self.range_superset.isChecked()

        # start processing
        self.busy.setLabelText("Processing query...")
        self.busy.show()
        self.raw_results.clear()
        self.thread.start()

    def update_complete(self, count):
        self.log.info("{0} netifcon statment(s) found.".format(count))

        # update sizes/location of result displays
        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's columns; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeColumnsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's rows; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeRowsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Moving the raw result to top; GUI may be unresponsive")
            self.busy.repaint()
            self.raw_results.moveCursor(QTextCursor.Start)

        self.busy.reset()
Example #54
0
class MLSRuleQueryTab(SEToolsWidget, QScrollArea):
    """An MLS rule query."""
    def __init__(self, parent, policy, perm_map):
        super(MLSRuleQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = MLSRuleQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)
        logging.getLogger("setools.mlsrulequery").removeHandler(self.handler)

    def setupUi(self):
        self.load_ui("mlsrulequery.ui")

        # set up source/target autocompletion
        typeattr_completion_list = [str(t) for t in self.policy.types()]
        typeattr_completion_list.extend(
            str(a) for a in self.policy.typeattributes())
        typeattr_completer_model = QStringListModel(self)
        typeattr_completer_model.setStringList(
            sorted(typeattr_completion_list))
        self.typeattr_completion = QCompleter()
        self.typeattr_completion.setModel(typeattr_completer_model)
        self.source.setCompleter(self.typeattr_completion)
        self.target.setCompleter(self.typeattr_completion)

        # setup indications of errors on source/target/default
        self.orig_palette = self.source.palette()
        self.error_palette = self.source.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_source_error()
        self.clear_target_error()
        self.clear_default_error()

        # populate class list
        self.class_model = SEToolsListModel(self)
        self.class_model.item_list = sorted(self.policy.classes())
        self.tclass.setModel(self.class_model)

        # set up results
        self.table_results_model = MLSRuleTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(1, Qt.AscendingOrder)

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.mlsrulequery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_source_regex(self.source_regex.isChecked())
        self.set_target_regex(self.target_regex.isChecked())
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.buttonBox.clicked.connect(self.run)
        self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes)
        self.all_ruletypes.clicked.connect(self.set_all_ruletypes)
        self.source.textEdited.connect(self.clear_source_error)
        self.source.editingFinished.connect(self.set_source)
        self.source_regex.toggled.connect(self.set_source_regex)
        self.target.textEdited.connect(self.clear_target_error)
        self.target.editingFinished.connect(self.set_target)
        self.target_regex.toggled.connect(self.set_target_regex)
        self.tclass.selectionModel().selectionChanged.connect(self.set_tclass)
        self.invert_class.clicked.connect(self.invert_tclass_selection)
        self.default_range.textEdited.connect(self.clear_default_error)
        self.default_range.editingFinished.connect(self.set_default_range)

    #
    # Ruletype criteria
    #

    def _set_ruletypes(self, value):
        self.range_transition.setChecked(value)

    def set_all_ruletypes(self):
        self._set_ruletypes(True)

    def clear_all_ruletypes(self):
        self._set_ruletypes(False)

    #
    # Source criteria
    #

    def clear_source_error(self):
        self.source.setToolTip("Match the source type/attribute of the rule.")
        self.source.setPalette(self.orig_palette)

    def set_source(self):
        try:
            self.query.source = self.source.text()
        except Exception as ex:
            self.log.error("Source type/attribute error: {0}".format(ex))
            self.source.setToolTip("Error: {0}".format(ex))
            self.source.setPalette(self.error_palette)

    def set_source_regex(self, state):
        self.log.debug("Setting source_regex {0}".format(state))
        self.query.source_regex = state
        self.clear_source_error()
        self.set_source()

    #
    # Target criteria
    #

    def clear_target_error(self):
        self.target.setToolTip("Match the target type/attribute of the rule.")
        self.target.setPalette(self.orig_palette)

    def set_target(self):
        try:
            self.query.target = self.target.text()
        except Exception as ex:
            self.log.error("Target type/attribute error: {0}".format(ex))
            self.target.setToolTip("Error: {0}".format(ex))
            self.target.setPalette(self.error_palette)

    def set_target_regex(self, state):
        self.log.debug("Setting target_regex {0}".format(state))
        self.query.target_regex = state
        self.clear_target_error()
        self.set_target()

    #
    # Class criteria
    #

    def set_tclass(self):
        selected_classes = []
        for index in self.tclass.selectionModel().selectedIndexes():
            selected_classes.append(self.class_model.data(index, Qt.UserRole))

        self.query.tclass = selected_classes

    def invert_tclass_selection(self):
        invert_list_selection(self.tclass.selectionModel())

    #
    # Default criteria
    #

    def clear_default_error(self):
        self.default_range.setToolTip("Match the default type the rule.")
        self.default_range.setPalette(self.orig_palette)

    def set_default_range(self):
        try:
            self.query.default = self.default_range.text()
        except Exception as ex:
            self.log.error("Default range error: {0}".format(ex))
            self.default_range.setToolTip("Error: {0}".format(ex))
            self.default_range.setPalette(self.error_palette)

    #
    # Results runner
    #

    def run(self, button):
        # right now there is only one button.

        self.query.ruletype = ['range_transition']
        self.query.source_indirect = self.source_indirect.isChecked()
        self.query.target_indirect = self.target_indirect.isChecked()

        # start processing
        self.busy.setLabelText("Processing query...")
        self.busy.show()
        self.raw_results.clear()
        self.thread.start()

    def update_complete(self, count):
        self.log.info("{0} MLS rule(s) found.".format(count))

        # update sizes/location of result displays
        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's columns; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeColumnsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's rows; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeRowsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Moving the raw result to top; GUI may be unresponsive")
            self.busy.repaint()
            self.raw_results.moveCursor(QTextCursor.Start)

        self.busy.reset()
Example #55
0
class CategoryQueryTab(AnalysisTab):
    """Category browser and query tab."""

    section = AnalysisSection.Components
    tab_title = "MLS Categories"
    mlsonly = True

    def __init__(self, parent, policy, perm_map):
        super(CategoryQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = CategoryQuery(policy)
        self.setupUi()

    def __del__(self):
        with suppress(RuntimeError):
            self.thread.quit()
            self.thread.wait(5000)

        logging.getLogger("setools.categoryquery").removeHandler(self.handler)

    def setupUi(self):
        self.load_ui("apol/categoryquery.ui")

        # populate category list
        self.category_model = SEToolsListModel(self)
        self.category_model.item_list = sorted(self.policy.categories())
        self.cats.setModel(self.category_model)

        # set up results
        self.table_results_model = MLSComponentTableModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)
        self.table_results.sortByColumn(0, Qt.AscendingOrder)

        # setup indications of errors on level/range
        self.errors = set()
        self.orig_palette = self.name.palette()
        self.error_palette = self.name.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_name_error()

        # set up processing thread
        self.thread = QThread()
        self.worker = QueryResultsUpdater(self.query, self.table_results_model)
        self.worker.moveToThread(self.thread)
        self.worker.raw_line.connect(self.raw_results.appendPlainText)
        self.worker.finished.connect(self.update_complete)
        self.worker.finished.connect(self.thread.quit)
        self.thread.started.connect(self.worker.update)

        # create a "busy, please wait" dialog
        self.busy = QProgressDialog(self)
        self.busy.setModal(True)
        self.busy.setRange(0, 0)
        self.busy.setMinimumDuration(0)
        self.busy.canceled.connect(self.thread.requestInterruption)
        self.busy.reset()

        # update busy dialog from query INFO logs
        self.handler = LogHandlerToSignal()
        self.handler.message.connect(self.busy.setLabelText)
        logging.getLogger("setools.categoryquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.notes.setHidden(not self.notes_expander.isChecked())

        # connect signals
        self.cats.doubleClicked.connect(self.get_detail)
        self.cats.get_detail.triggered.connect(self.get_detail)
        self.name.textEdited.connect(self.clear_name_error)
        self.name.editingFinished.connect(self.set_name)
        self.name_regex.toggled.connect(self.set_name_regex)
        self.buttonBox.clicked.connect(self.run)

    #
    # Category browser
    #
    def get_detail(self):
        # .ui is set for single item selection.
        index = self.cats.selectedIndexes()[0]
        item = self.category_model.data(index, Qt.UserRole)

        self.log.debug("Generating detail window for {0}".format(item))
        category_detail(self, item)

    #
    # Name criteria
    #
    def clear_name_error(self):
        self.clear_criteria_error(self.name, "Match the category name.")

    def set_name(self):
        try:
            self.query.name = self.name.text()
        except Exception as ex:
            self.log.error("Category name error: {0}".format(ex))
            self.set_criteria_error(self.name, ex)

    def set_name_regex(self, state):
        self.log.debug("Setting name_regex {0}".format(state))
        self.query.name_regex = state
        self.clear_name_error()
        self.set_name()

    #
    # Save/Load tab
    #
    def save(self):
        """Return a dictionary of settings."""
        if self.errors:
            raise TabFieldError("Field(s) are in error: {0}".format(" ".join(
                o.objectName() for o in self.errors)))

        settings = {}
        save_checkboxes(self, settings,
                        ["criteria_expander", "notes_expander", "name_regex"])
        save_lineedits(self, settings, ["name"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings,
                        ["criteria_expander", "notes_expander", "name_regex"])
        load_lineedits(self, settings, ["name"])
        load_textedits(self, settings, ["notes"])

    #
    # Results runner
    #

    def run(self, button):
        # right now there is only one button.

        # start processing
        self.busy.setLabelText("Processing query...")
        self.busy.show()
        self.raw_results.clear()
        self.thread.start()

    def update_complete(self, count):
        self.log.info("{0} categories found.".format(count))

        # update sizes/location of result displays
        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's columns; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeColumnsToContents()
            # If the attrs or alias column widths are too long, pull back
            # to a reasonable size
            header = self.table_results.horizontalHeader()
            if header.sectionSize(1) > 400:
                header.resizeSection(1, 400)
            if header.sectionSize(2) > 400:
                header.resizeSection(2, 400)

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Resizing the result table's rows; GUI may be unresponsive")
            self.busy.repaint()
            self.table_results.resizeRowsToContents()

        if not self.busy.wasCanceled():
            self.busy.setLabelText(
                "Moving the raw result to top; GUI may be unresponsive")
            self.busy.repaint()
            self.raw_results.moveCursor(QTextCursor.Start)

        self.busy.reset()
Example #56
0
class ComboBoxAutocomplete(QComboBox):
    """UI dropdown element with autocomplete.

    Attributes:
        completer (QtWidgets.QCompleter): Autocomplete instance tied to the dropdown items.
        proxy_model (QtWidgets.QSortFilterProxyModel): Configurations of the autocomplete.
    """
    def __init__(self, parent=None):
        """Creates default configurations (case insensitive) and constructs the UI element.

        Args:
            parent (App(QDialog), optional): Object corresponding to the parent UI element.
        """
        super(ComboBoxAutocomplete, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # Setup proxy model to sort and filter data passed between model and view
        self.proxy_model = QSortFilterProxyModel(self)
        self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxy_model.setSourceModel(self.model())

        # Setup completer
        self.completer = QCompleter(self.proxy_model, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # Connect autocompletion signals
        self.lineEdit().textEdited.connect(
            self.proxy_model.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)

    # Override
    def on_completer_activated(self, text):
        """Callback event handler for a query in the autocomplete.

        Args:
            text (str): Query text.
        """
        if not text:
            return
        index = self.findText(text)
        self.setCurrentIndex(index)
        self.activated[str].emit(self.itemText(index))

    # Override
    def setModel(self, model):
        """Updates the configuration model.

        Args:
            model (QtWidgets.QSortFilterProxyModel): New configuration to update to.
        """
        super(ComboBoxAutocomplete, self).setModel(model)
        self.proxy_model.setSourceModel(model)
        self.completer.setModel(self.proxy_model)

    # Override
    def setModelColumn(self, column):
        """Updates the column being autocompleted.

        Args:
            column (int): Column from the data used for checking suggestions.
        """
        self.completer.setCompletionColumn(column)
        self.proxy_model.setFilterKeyColumn(column)
        super(ComboBoxAutocomplete, self).setModelColumn(column)
Example #57
0
    def __init__(self, parent, *args, **kwargs):
        super(ListWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle("Devices list")
        self.setWindowState(Qt.WindowMaximized)
        self.setLayout(VLayout(margin=0, spacing=0))

        self.mqtt = parent.mqtt
        self.env = parent.env

        self.device = None
        self.idx = None

        self.nam = QNetworkAccessManager()
        self.backup = bytes()

        self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()), QSettings.IniFormat)
        views_order = self.settings.value("views_order", [])

        self.views = {}
        self.settings.beginGroup("Views")
        views = self.settings.childKeys()
        if views and views_order:
            for view in views_order.split(";"):
                view_list = self.settings.value(view).split(";")
                self.views[view] = base_view + view_list
        else:
            self.views = default_views
        self.settings.endGroup()

        self.tb = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonTextBesideIcon)
        self.tb_relays = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonIconOnly)
        # self.tb_filter = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonTextBesideIcon)
        self.tb_views = Toolbar(Qt.Horizontal, 24, Qt.ToolButtonTextBesideIcon)

        self.pwm_sliders = []

        self.layout().addWidget(self.tb)
        self.layout().addWidget(self.tb_relays)
        # self.layout().addWidget(self.tb_filter)

        self.device_list = TableView()
        self.device_list.setIconSize(QSize(24, 24))
        self.model = parent.device_model
        self.model.setupColumns(self.views["Home"])

        self.sorted_device_model = QSortFilterProxyModel()
        self.sorted_device_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.sorted_device_model.setSourceModel(parent.device_model)
        self.sorted_device_model.setSortRole(Qt.InitialSortOrderRole)
        self.sorted_device_model.setSortLocaleAware(True)
        self.sorted_device_model.setFilterKeyColumn(-1)

        self.device_list.setModel(self.sorted_device_model)
        self.device_list.setupView(self.views["Home"])
        self.device_list.setSortingEnabled(True)
        self.device_list.setWordWrap(True)
        self.device_list.setItemDelegate(DeviceDelegate())
        self.device_list.sortByColumn(self.model.columnIndex("FriendlyName"), Qt.AscendingOrder)
        self.device_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.device_list.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.layout().addWidget(self.device_list)

        self.layout().addWidget(self.tb_views)

        self.device_list.clicked.connect(self.select_device)
        self.device_list.customContextMenuRequested.connect(self.show_list_ctx_menu)

        self.ctx_menu = QMenu()

        self.create_actions()
        self.create_view_buttons()
        # self.create_view_filter()

        self.device_list.doubleClicked.connect(lambda: self.openConsole.emit())
class E5NetworkMonitor(QDialog, Ui_E5NetworkMonitor):
    """
    Class implementing a network monitor dialog.
    """
    _monitor = None

    @classmethod
    def instance(cls, networkAccessManager):
        """
        Class method to get a reference to our singleton.
        
        @param networkAccessManager reference to the network access manager
            (QNetworkAccessManager)
        @return reference to the network monitor singleton (E5NetworkMonitor)
        """
        if cls._monitor is None:
            cls._monitor = E5NetworkMonitor(networkAccessManager)

        return cls._monitor

    @classmethod
    def closeMonitor(cls):
        """
        Class method to close the monitor dialog.
        """
        if cls._monitor is not None:
            cls._monitor.close()

    def __init__(self, networkAccessManager, parent=None):
        """
        Constructor
        
        @param networkAccessManager reference to the network access manager
            (QNetworkAccessManager)
        @param parent reference to the parent widget (QWidget)
        """
        super(E5NetworkMonitor, self).__init__(parent)
        self.setupUi(self)
        self.setWindowFlags(Qt.Window)

        self.__requestHeaders = QStandardItemModel(self)
        self.__requestHeaders.setHorizontalHeaderLabels(
            [self.tr("Name"), self.tr("Value")])
        self.requestHeadersList.setModel(self.__requestHeaders)
        self.requestHeadersList.horizontalHeader().setStretchLastSection(True)
        self.requestHeadersList.doubleClicked.connect(self.__showHeaderDetails)

        self.__replyHeaders = QStandardItemModel(self)
        self.__replyHeaders.setHorizontalHeaderLabels(
            [self.tr("Name"), self.tr("Value")])
        self.responseHeadersList.setModel(self.__replyHeaders)
        self.responseHeadersList.horizontalHeader().setStretchLastSection(True)
        self.responseHeadersList.doubleClicked.connect(
            self.__showHeaderDetails)

        self.requestsList.horizontalHeader().setStretchLastSection(True)
        self.requestsList.verticalHeader().setMinimumSectionSize(-1)

        self.__proxyModel = QSortFilterProxyModel(self)
        self.__proxyModel.setFilterKeyColumn(-1)
        self.searchEdit.textChanged.connect(
            self.__proxyModel.setFilterFixedString)

        self.removeButton.clicked.connect(self.requestsList.removeSelected)
        self.removeAllButton.clicked.connect(self.requestsList.removeAll)

        self.__model = E5RequestModel(networkAccessManager, self)
        self.__proxyModel.setSourceModel(self.__model)
        self.requestsList.setModel(self.__proxyModel)
        self.__proxyModel.rowsInserted.connect(
            self.requestsList.scrollToBottom)
        self.requestsList.selectionModel()\
            .currentChanged[QModelIndex, QModelIndex]\
            .connect(self.__currentChanged)

        fm = self.fontMetrics()
        em = fm.width("m")
        self.requestsList.horizontalHeader().resizeSection(0, em * 5)
        self.requestsList.horizontalHeader().resizeSection(1, em * 20)
        self.requestsList.horizontalHeader().resizeSection(3, em * 5)
        self.requestsList.horizontalHeader().resizeSection(4, em * 15)

        self.__headersDlg = None

    def closeEvent(self, evt):
        """
        Protected method called upon closing the dialog.
        
        @param evt reference to the close event object (QCloseEvent)
        """
        self.__class__._monitor = None
        super(E5NetworkMonitor, self).closeEvent(evt)

    def reject(self):
        """
        Public slot to close the dialog with a Reject status.
        """
        self.__class__._monitor = None
        super(E5NetworkMonitor, self).reject()

    def __currentChanged(self, current, previous):
        """
        Private slot to handle a change of the current index.
        
        @param current new current index (QModelIndex)
        @param previous old current index (QModelIndex)
        """
        self.__requestHeaders.setRowCount(0)
        self.__replyHeaders.setRowCount(0)

        if not current.isValid():
            return

        row = self.__proxyModel.mapToSource(current).row()

        req = self.__model.requests[row].request

        for header in req.rawHeaderList():
            self.__requestHeaders.insertRows(0, 1, QModelIndex())
            self.__requestHeaders.setData(self.__requestHeaders.index(0, 0),
                                          str(header, "utf-8"))
            self.__requestHeaders.setData(self.__requestHeaders.index(0, 1),
                                          str(req.rawHeader(header), "utf-8"))
            self.__requestHeaders.item(0, 0).setFlags(Qt.ItemIsSelectable
                                                      | Qt.ItemIsEnabled)
            self.__requestHeaders.item(0, 1).setFlags(Qt.ItemIsSelectable
                                                      | Qt.ItemIsEnabled)

        for header in self.__model.requests[row].replyHeaders:
            self.__replyHeaders.insertRows(0, 1, QModelIndex())
            self.__replyHeaders.setData(self.__replyHeaders.index(0, 0),
                                        header[0])
            self.__replyHeaders.setData(self.__replyHeaders.index(0, 1),
                                        header[1])
            self.__replyHeaders.item(0, 0).setFlags(Qt.ItemIsSelectable
                                                    | Qt.ItemIsEnabled)
            self.__replyHeaders.item(0, 1).setFlags(Qt.ItemIsSelectable
                                                    | Qt.ItemIsEnabled)

    def __showHeaderDetails(self, index):
        """
        Private slot to show a dialog with the header details.
        
        @param index index of the entry to show (QModelIndex)
        """
        if not index.isValid():
            return

        headerList = self.sender()
        if headerList is None:
            return

        row = index.row()
        name = headerList.model().data(headerList.model().index(row, 0))
        value = headerList.model().data(headerList.model().index(row, 1))
        if self.__headersDlg is None:
            from .E5NetworkHeaderDetailsDialog import \
                E5NetworkHeaderDetailsDialog
            self.__headersDlg = E5NetworkHeaderDetailsDialog(self)
        self.__headersDlg.setData(name, value)
        self.__headersDlg.show()
Example #59
0
class MinibufferInput(QLineEdit):
    completion_activated = Signal(QModelIndex)

    FuzzyMatch = Prompt.FuzzyMatch
    SimpleMatch = Prompt.SimpleMatch

    def __init__(self, parent, window):
        QLineEdit.__init__(self, parent)
        self._completer_model = None
        self._popup = Popup(window, self)
        self.textEdited.connect(self._show_completions)
        self._popup.installEventFilter(self)
        self.installEventFilter(self)
        self._eat_focusout = False
        self._proxy_model = QSortFilterProxyModel(self)
        self._proxy_model.setFilterKeyColumn(-1)
        self._popup.setModel(self._proxy_model)
        self._popup.activated.connect(self._on_completion_activated)
        self._popup.selectionModel().currentRowChanged.connect(
            self._on_row_changed)
        self._right_italic_text = ""
        self._mark = False
        self.configure_completer({})

    def configure_completer(self, opts):
        self._popup._max_visible_items = opts.get("max-visible-items", 10)
        self._match = opts.get("match", self.SimpleMatch)
        self._autocomplete_single = opts.get("autocomplete-single", True)
        self._autocomplete = opts.get("autocomplete", False)
        if self._autocomplete:
            self._autocomplete_single = False
        self._complete_empty = opts.get("complete-empty", False)

    def keymap(self):
        prompt = self.parent()._prompt
        if prompt and prompt.keymap:
            return prompt.keymap
        return KEYMAP

    def eventFilter(self, obj, event):
        etype = event.type()
        if etype == QEvent.FocusOut and obj == self and self._eat_focusout \
           and self._popup.isVisible():
            # keep the focus on the line edit
            return True
        elif etype == QEvent.MouseButtonPress:
            # if we've clicked in the widget (or its descendant), let it handle
            # the click
            pos = obj.mapToGlobal(event.pos())
            target = QApplication.widgetAt(pos)
            if target and (self.isAncestorOf(target) or target == self):
                if not self._popup.underMouse():
                    self._popup.hide()
                target.event(event)
                return True

            if not self._popup.underMouse():
                self._popup.hide()
                return True
        elif etype in (QEvent.KeyPress, QEvent.KeyRelease):
            # send event to the line edit
            self._eat_focusout = True
            self.event(event)
            self._eat_focusout = False
            return True

        return QLineEdit.eventFilter(self, obj, event)

    def event(self, evt):
        t = evt.type()
        if t == QEvent.KeyPress:
            if KEY_EATER.event_filter(self, evt):
                return True
        elif t == QEvent.Show:
            LOCAL_KEYMAP_SETTER.minibuffer_input_focus_changed(self, True)
        elif t == QEvent.Hide:
            LOCAL_KEYMAP_SETTER.minibuffer_input_focus_changed(self, False)
        return QLineEdit.event(self, evt)

    def set_completer_model(self, completer_model):
        self._proxy_model.setSourceModel(completer_model)

    def completer_model(self):
        return self._proxy_model.sourceModel()

    def set_match(self, type):
        self._match = type
        if self._popup.isVisible():
            self._show_completions(self.text())

    def _on_row_changed(self, current, old):
        if self._autocomplete:
            self.complete(hide_popup=False)

    def _show_completions(self, txt, force=False):
        force = force or self._complete_empty
        if self._match is not None:
            if self._match == self.SimpleMatch:
                pattern = "^" + QRegExp.escape(txt)
            elif self._match == self.FuzzyMatch:
                pattern = ".*".join(QRegExp.escape(t) for t in txt.split())
            self._proxy_model.setFilterRegExp(
                QRegExp(pattern, Qt.CaseInsensitive))
        else:
            self._proxy_model.setFilterRegExp(None)

        if self._proxy_model.rowCount() == 0:
            self._popup.hide()
        elif not txt and not force:
            self._popup.hide()
        else:
            self._popup.popup()

    def show_completions(self, filter_text=None):
        self._show_completions(
            filter_text if filter_text is not None else self.text(), True)

    def _on_completion_activated(self, index, hide_popup=True):
        if hide_popup:
            self._popup.hide()
        model = index.model()
        if index.column() != 0:
            index = model.index(index.row(), 0)

        self.setText(model.data(index))
        self.completion_activated.emit(model.mapToSource(index))

    def popup(self):
        return self._popup

    def complete(self, hide_popup=True):
        if not self._popup.isVisible():
            return

        index = self._popup.selectionModel().currentIndex()
        if index.isValid():
            self._on_completion_activated(index, hide_popup=hide_popup)
        elif self._autocomplete_single and self._proxy_model.rowCount() == 1:
            self._on_completion_activated(self._proxy_model.index(0, 0),
                                          hide_popup=hide_popup)

    def select_next_completion(self, forward=True):
        model = self._proxy_model
        entries = model.rowCount()
        if entries == 0:
            return

        selection = self._popup.selectionModel().currentIndex()
        if not selection.isValid():
            row = 0 if forward else (entries - 1)
        else:
            row = selection.row()
            if forward:
                row = row + 1
                if row >= entries:
                    row = 0
            else:
                row = row - 1
                if row < 0:
                    row = (entries - 1)

        self._popup.selectRow(row)

    def mark(self):
        return self._mark

    def set_mark(self, value=None):
        if value is None:
            value = not self._mark
        self._mark = value
        return self._mark

    def reinit(self):
        self.setText("")
        self.setEchoMode(self.Normal)
        self.setValidator(None)
        self._right_italic_text = ""

    def set_right_italic_text(self, text):
        self._right_italic_text = text
        self.update()

    def paintEvent(self, event):
        QLineEdit.paintEvent(self, event)
        if not self._right_italic_text:
            return
        painter = QPainter(self)
        font = painter.font()
        font.setItalic(True)
        painter.setFont(font)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.drawText(self.rect().adjusted(0, 0, -10, 0), Qt.AlignRight,
                         self._right_italic_text)
 def __init__(self, *args, **kwargs):
     QSortFilterProxyModel.__init__(self, *args, **kwargs)
     self.filters = {}
     self.multi_filter_mode = MultiFilterMode.AND