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)
Beispiel #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 __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)
    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()
Beispiel #5
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)
    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)
Beispiel #7
0
def createModel(parent,rows,cols,colNames):
    model=QStandardItemModel(rows, cols+1, parent)
    i=0
    for c in colNames:
        model.setHeaderData(i, Qt.Horizontal, c)
        i+=1
    proxyModel=QSortFilterProxyModel()
    proxyModel.setDynamicSortFilter(True)
    proxyModel.setSourceModel(model)
    proxyModel.setFilterKeyColumn(0)
    return proxyModel
Beispiel #8
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)
Beispiel #9
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()
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()[:]
Beispiel #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()
class SpellingDictionaryEditDialog(QDialog, Ui_SpellingDictionaryEditDialog):
    """
    Class implementing a dialog to edit the various spell checking
    dictionaries.
    """
    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)
    
    @pyqtSlot()
    def on_addButton_clicked(self):
        """
        Private slot to handle adding an entry.
        """
        self.__model.insertRow(self.__model.rowCount())
        self.wordList.edit(
            self.__proxyModel.index(self.__model.rowCount() - 1, 0))
    
    def getData(self):
        """
        Public method to get the data.
        
        @return data of the dialog (string)
        """
        return os.linesep.join(
            [line for line in self.__model.stringList() if line])
Beispiel #14
0
def filterOnFocus(window, focused):
	loclist = getattr(window, 'build_loclist', None)
	if not loclist:
		return

	model = loclist.model()
	if not getattr(model, 'isFilterOnFocus', False):
		orig = model

		model = QSortFilterProxyModel()
		model.isFilterOnFocus = True
		loclist.setModel(model)
		model.setSourceModel(orig)
		model.setFilterRole(AbsolutePathRole)

	model.setFilterRegExp(QRegExp.escape(focused.path or ''))
Beispiel #15
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()
Beispiel #16
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
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.setupUi(self)
        self.toolBox.setStyleSheet(style.toolBoxSS())

        self.mw = mainWindow()
        self.txtGeneralSplitScenes.setStyleSheet(style.lineEditSS())

        # TreeView to select parent
        # We use a proxy to display only folders
        proxy = QSortFilterProxyModel()
        proxy.setFilterKeyColumn(Outline.type)
        proxy.setFilterFixedString("folder")
        proxy.setSourceModel(self.mw.mdlOutline)
        self.treeGeneralParent.setModel(proxy)
        for i in range(1, self.mw.mdlOutline.columnCount()):
            self.treeGeneralParent.hideColumn(i)
        self.treeGeneralParent.setCurrentIndex(self.getParentIndex())
        self.chkGeneralParent.toggled.connect(self.treeGeneralParent.setVisible)
        self.treeGeneralParent.hide()
Beispiel #18
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_()
class CustomQCompleter(QCompleter):
    """
    adapted from: http://stackoverflow.com/a/7767999/2156909
    """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.local_completion_prefix = ""
        self.source_model = None
        self.filterProxyModel = QSortFilterProxyModel(self)
        self.usingOriginalModel = False

    def setModel(self, strList): 
        self.source_model = QStringListModel(strList)
        self.filterProxyModel = QSortFilterProxyModel(self)
        self.filterProxyModel.setSourceModel(self.source_model)
        super().setModel(self.filterProxyModel)
        self.usingOriginalModel = True


    def updateModel(self):
        if not self.usingOriginalModel:
            self.filterProxyModel.setSourceModel(self.source_model)

        pattern = QRegExp(self.local_completion_prefix,
                                Qt.CaseInsensitive,
                                QRegExp.FixedString)

        self.filterProxyModel.setFilterRegExp(pattern)

    def splitPath(self, path):
        self.local_completion_prefix = path
        self.updateModel()
        if self.filterProxyModel.rowCount() == 0:
            self.usingOriginalModel = False
            self.filterProxyModel.setSourceModel(QStringListModel([path]))
            return [path]

        self.usingOriginalModel = True
        return []
Beispiel #20
0
class VistaListaClienti(QWidget):
    def __init__(self, parent=None):
        super(VistaListaClienti, self).__init__(parent)
        self.setWindowIcon(QtGui.QIcon('logos/logo.png'))
        self.controller = ControlloreListaClienti()
        main_layout = QHBoxLayout()

        v_layout = QVBoxLayout()

        self.list_view = QListView()
        self.update_ui()

        #Crea un elenco fittizio sopra l'elenco reale per poter usare la barra di ricerca
        self.filter_proxy_model = QSortFilterProxyModel()
        self.filter_proxy_model.setSourceModel(self.listview_model)
        self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter_proxy_model.setFilterKeyColumn(0)

        search_field = QLineEdit()
        search_field.setStyleSheet('font-size: 15px; height: 30px;')
        search_field.textChanged.connect(
            self.filter_proxy_model.setFilterRegExp)
        v_layout.addWidget(search_field)

        self.list_view.setModel(self.filter_proxy_model)

        v_layout.addWidget(self.list_view)
        main_layout.addLayout(v_layout)

        #Bottone per aprire un cliente
        buttons_layout = QVBoxLayout()
        open_button = QPushButton("Apri")
        open_button.clicked.connect(self.show_selected_info)
        buttons_layout.addWidget(open_button)

        #Bottone per creare un nuovo cliente
        new_button = QPushButton("Nuovo")
        new_button.clicked.connect(self.show_new_cliente)
        buttons_layout.addWidget(new_button)
        buttons_layout.addStretch()
        main_layout.addLayout(buttons_layout)

        self.setLayout(main_layout)
        self.resize(600, 300)
        self.setWindowTitle("Lista Clienti")

    #Metodo che mostra a schermo le informazioni del cliente selezionato
    def show_selected_info(self):
        try:
            sourceindex = self.list_view.selectedIndexes()[0].row()
            cliente_selezionato = self.controller.get_cliente_by_index(
                sourceindex)
            self.vista_cliente = VistaCliente(
                cliente_selezionato, self.controller.rimuovi_cliente_by_id,
                self.update_ui)
            self.vista_cliente.show()
        except IndexError:
            QMessageBox.critical(self, 'Errore',
                                 'Per favore, seleziona un cliente',
                                 QMessageBox.Ok, QMessageBox.Ok)

    #Metodo aprire la vista di inserimento del nuovo cliente
    def show_new_cliente(self):
        self.vista_inserisci_cliente = VistaInserisciCliente(
            self.controller, self.update_ui)
        self.vista_inserisci_cliente.show()

    #Metodo che serve per generare e/o aggiornare la vista
    def update_ui(self):
        self.listview_model = QStandardItemModel(self.list_view)
        for cliente in self.controller.get_lista_dei_clienti():
            item = QStandardItem()
            item.setText(cliente.nome + " " + cliente.cognome)
            item.setEditable(False)
            font = item.font()
            font.setPointSize(18)
            item.setFont(font)
            self.listview_model.appendRow(item)
        self.list_view.setModel(self.listview_model)

    # salva i dati sul file pickle alla chiusura della view
    def closeEvent(self, event):
        self.controller.save_data()

    #Metodo per collegare l'indice selezionato all'elenco fittizio all'indice dell'elenco reale
    def toSourceIndex(self, index):
        return self.filter_proxy_model.mapToSource(index).row()
 def populate_table(self, table: QTableView, data=[]):
     model = TableModel(data)
     sortable_model = QSortFilterProxyModel(model)
     sortable_model.setSourceModel(model)
     table.setModel(sortable_model)
Beispiel #22
0
class DevicesListWidget(QWidget):
    def __init__(self, parent, *args, **kwargs):
        super(DevicesListWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle("Devices list")
        self.setWindowState(Qt.WindowMaximized)
        self.setLayout(VLayout(margin=0, spacing=0))

        self.mqtt = parent.mqtt
        self.mdi = parent.mdi
        self.idx = None

        self.settings = QSettings()
        self.hidden_columns = self.settings.value("hidden_columns", [1, 2])

        self.tb = Toolbar(Qt.Horizontal, 16, Qt.ToolButtonTextBesideIcon)
        self.tb.addAction(QIcon("GUI/icons/add.png"), "Add", self.device_add)

        self.layout().addWidget(self.tb)

        self.device_list = TableView()
        self.model = parent.device_model
        self.telemetry_model = parent.telemetry_model
        self.sorted_device_model = QSortFilterProxyModel()
        self.sorted_device_model.setSourceModel(parent.device_model)
        self.device_list.setModel(self.sorted_device_model)
        self.device_list.setupColumns(columns, self.hidden_columns)
        self.device_list.setSortingEnabled(True)
        self.device_list.setWordWrap(True)
        self.device_list.setItemDelegate(DeviceDelegate())
        self.device_list.sortByColumn(DevMdl.TOPIC, Qt.AscendingOrder)
        self.device_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.layout().addWidget(self.device_list)

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

        self.device_list.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
        self.device_list.horizontalHeader().customContextMenuRequested.connect(self.show_header_ctx_menu)

        self.ctx_menu = QMenu()
        self.ctx_menu_relays = None
        self.create_actions()

        self.build_header_ctx_menu()

    def create_actions(self):
        self.ctx_menu.addAction(QIcon("GUI/icons/configure.png"), "Configure", self.device_config)
        self.ctx_menu.addAction(QIcon("GUI/icons/delete.png"), "Remove", self.device_delete)
        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/on.png"), "Power ON", lambda: self.ctx_menu_power(state="ON"))
        self.ctx_menu.addAction(QIcon("GUI/icons/off.png"), "Power OFF", lambda: self.ctx_menu_power(state="OFF"))

        self.ctx_menu_relays = QMenu("Relays")
        self.ctx_menu_relays.setIcon(QIcon("GUI/icons/switch.png"))
        relays_btn = self.ctx_menu.addMenu(self.ctx_menu_relays)

        self.ctx_menu_relays.setEnabled(False)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/clear.png"), "Clear retained", self.ctx_menu_clean_retained)
        self.ctx_menu.addSeparator()

        self.ctx_menu_copy = QMenu("Copy")
        self.ctx_menu_copy.setIcon(QIcon("GUI/icons/copy.png"))
        copy_btn = self.ctx_menu.addMenu(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("GUI/icons/web.png"), "Open WebUI", self.ctx_menu_webui)

        self.ctx_menu_copy.addAction("IP", lambda: self.ctx_menu_copy_value(DevMdl.IP))
        self.ctx_menu_copy.addAction("MAC", lambda: self.ctx_menu_copy_value(DevMdl.MAC))
        self.ctx_menu_copy.addAction("BSSID", lambda: self.ctx_menu_copy_value(DevMdl.BSSID))
        self.ctx_menu_copy.addSeparator()
        self.ctx_menu_copy.addAction("Topic", lambda: self.ctx_menu_copy_value(DevMdl.TOPIC))
        self.ctx_menu_copy.addAction("FullTopic", lambda: self.ctx_menu_copy_value(DevMdl.FULL_TOPIC))
        self.ctx_menu_copy.addAction("STAT topic", lambda: self.ctx_menu_copy_prefix_topic("STAT"))
        self.ctx_menu_copy.addAction("CMND topic", lambda: self.ctx_menu_copy_prefix_topic("CMND"))
        self.ctx_menu_copy.addAction("TELE topic", lambda: self.ctx_menu_copy_prefix_topic("TELE"))

        self.tb.addActions(self.ctx_menu.actions())
        self.tb.widgetForAction(relays_btn).setPopupMode(QToolButton.InstantPopup)
        self.tb.widgetForAction(copy_btn).setPopupMode(QToolButton.InstantPopup)

    def ctx_menu_copy_value(self, column):
        if self.idx:
            row = self.idx.row()
            value = self.model.data(self.model.index(row, column))
            QApplication.clipboard().setText(value)

    def ctx_menu_copy_prefix_topic(self, prefix):
        if self.idx:
            if prefix == "STAT":
                topic = self.model.statTopic(self.idx)
            elif prefix == "CMND":
                topic = self.model.commandTopic(self.idx)
            elif prefix == "TELE":
                topic = self.model.teleTopic(self.idx)
            QApplication.clipboard().setText(topic)

    def ctx_menu_clean_retained(self):
        if self.idx:
            relays = self.model.data(self.model.index(self.idx.row(), DevMdl.POWER))
            if relays and len(relays.keys()>1):
                cmnd_topic = self.model.cmndTopic(self.idx)

                for r in relays.keys():
                    self.mqtt.publish(cmnd_topic + r, retain=True)
                QMessageBox.information(self, "Clear retained", "Cleared reatined messages.")

    def ctx_menu_power(self, relay=None, state=None):
        if self.idx:
            relays = self.model.data(self.model.index(self.idx.row(), DevMdl.POWER))
            cmnd_topic = self.model.commandTopic(self.idx)
            if relay:
                self.mqtt.publish(cmnd_topic+relay, payload=state)

            elif relays:
                for r in relays.keys():
                    self.mqtt.publish(cmnd_topic+r, payload=state)

    def ctx_menu_restart(self):
        if self.idx:
            self.mqtt.publish("{}/restart".format(self.model.commandTopic(self.idx)), payload="1")

    def ctx_menu_refresh(self):
        if self.idx:
            for q in initial_queries:
                self.mqtt.publish("{}/status".format(self.model.commandTopic(self.idx)), payload=q)

    def ctx_menu_telemetry(self):
        if self.idx:
            self.mqtt.publish("{}/status".format(self.model.commandTopic(self.idx)), payload=8)

    def ctx_menu_bssid(self):
        if self.idx:
            bssid = self.model.bssid(self.idx)
            current = self.settings.value("BSSID/{}".format(bssid), "")
            alias, ok = QInputDialog.getText(self, "BSSID alias", "Alias for {}. Clear to remove.".format(bssid), text=current)
            if ok:
                self.settings.setValue("BSSID/{}".format(bssid), alias)
                self.model.refreshBSSID()

    def ctx_menu_webui(self):
        if self.idx:
            QDesktopServices.openUrl(QUrl("http://{}".format(self.model.ip(self.idx))))

    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 build_header_ctx_menu(self):
        self.hdr_ctx_menu = QMenu()
        for c in columns.keys():
            a = self.hdr_ctx_menu.addAction(columns[c][0])
            a.setData(c)
            a.setCheckable(True)
            a.setChecked(not self.device_list.isColumnHidden(c))
            a.toggled.connect(self.header_ctx_menu_toggle_col)

    def show_header_ctx_menu(self, at):
        self.hdr_ctx_menu.popup(self.device_list.horizontalHeader().viewport().mapToGlobal(at))

    def header_ctx_menu_toggle_col(self, state):
        self.device_list.setColumnHidden(self.sender().data(), not state)
        hidden_columns = [int(c) for c in columns.keys() if self.device_list.isColumnHidden(c)]
        self.settings.setValue("hidden_columns", hidden_columns)
        self.settings.sync()

    def select_device(self, idx):
        self.idx = self.sorted_device_model.mapToSource(idx)
        self.device = self.model.data(self.model.index(idx.row(), DevMdl.TOPIC))

        relays = self.model.data(self.model.index(self.idx.row(), DevMdl.POWER))
        if relays and len(relays.keys()) > 1:
            self.ctx_menu_relays.setEnabled(True)
            self.ctx_menu_relays.setEnabled(True)
            self.ctx_menu_relays.clear()

            for r in relays.keys():
                actR = self.ctx_menu_relays.addAction("{} ON".format(r))
                actR.triggered.connect(lambda st, x=r: self.ctx_menu_power(x, "ON"))
                actR = self.ctx_menu_relays.addAction("{} OFF".format(r))
                actR.triggered.connect(lambda st, x=r: self.ctx_menu_power(x, "OFF"))
                self.ctx_menu_relays.addSeparator()
        else:
            self.ctx_menu_relays.setEnabled(False)
            self.ctx_menu_relays.clear()

    def device_config(self, idx=None):
        dev_cfg = DevicesConfigWidget(self, self.model.topic(self.idx))
        self.mdi.addSubWindow(dev_cfg)
        dev_cfg.setWindowState(Qt.WindowMaximized)

    def device_add(self):
        rc = self.model.rowCount()
        self.model.insertRow(rc)
        dlg = DeviceEditDialog(self.model, rc)
        dlg.full_topic.setText("%prefix%/%topic%/")

        if dlg.exec_() == QDialog.Accepted:
            self.model.setData(self.model.index(rc, DevMdl.FRIENDLY_NAME), self.model.data(self.model.index(rc, DevMdl.TOPIC)))
            topic = dlg.topic.text()
            tele_dev = self.telemetry_model.addDevice(TasmotaDevice, topic)
            self.telemetry_model.devices[topic] = tele_dev
        else:
            self.model.removeRow(rc)

    def device_delete(self):
        if self.idx:
            topic = self.model.topic(self.idx)
            if QMessageBox.question(self, "Confirm", "Do you want to remove '{}' from devices list?".format(topic)) == QMessageBox.Yes:
                self.model.removeRows(self.idx.row(),1)
                tele_idx = self.telemetry_model.devices.get(topic)
                if tele_idx:
                    self.telemetry_model.removeRows(tele_idx.row(),1)

    def closeEvent(self, event):
        event.ignore()
Beispiel #23
0
class UserQueryTab(SEToolsWidget, QScrollArea):

    """User browser and query tab."""

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

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

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

        # populate user list
        self.user_model = SEToolsListModel(self)
        self.user_model.item_list = sorted(self.policy.users())
        self.users.setModel(self.user_model)

        # populate role list
        self.role_model = SEToolsListModel(self)
        self.role_model.item_list = sorted(r for r in self.policy.roles() if r != "object_r")
        self.roles.setModel(self.role_model)

        # set up results
        self.table_results_model = UserTableModel(self, self.policy.mls)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)

        # 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()

        if self.policy.mls:
            self.clear_level_error()
            self.clear_range_error()
        else:
            # hide level and range criteria
            self.level_criteria.setHidden(True)
            self.range_criteria.setHidden(True)

        # set up processing thread
        self.thread = QThread()
        self.worker = ResultsUpdater(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.userquery").addHandler(self.handler)

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

        # connect signals
        self.users.doubleClicked.connect(self.get_detail)
        self.users.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.roles.selectionModel().selectionChanged.connect(self.set_roles)
        self.invert_roles.clicked.connect(self.invert_role_selection)
        self.level.textEdited.connect(self.clear_level_error)
        self.level.editingFinished.connect(self.set_level)
        self.range_.textEdited.connect(self.clear_range_error)
        self.range_.editingFinished.connect(self.set_range)
        self.buttonBox.clicked.connect(self.run)

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

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

    #
    # Name criteria
    #
    def clear_name_error(self):
        self.name.setToolTip("Match the user 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("User 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()

    #
    # Role criteria
    #
    def set_roles(self):
        selected_roles = []
        for index in self.roles.selectionModel().selectedIndexes():
            selected_roles.append(self.role_model.data(index, Qt.UserRole))

        self.query.roles = selected_roles

    def invert_role_selection(self):
        invert_list_selection(self.roles.selectionModel())

    #
    # Default level criteria
    #
    def clear_level_error(self):
        self.level.setToolTip("Match the default level of the user.")
        self.level.setPalette(self.orig_palette)

    def set_level(self):
        try:
            self.query.level = self.level.text()
        except Exception as ex:
            self.log.info("Level criterion error: " + str(ex))
            self.level.setToolTip("Error: " + str(ex))
            self.level.setPalette(self.error_palette)

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

    def set_range(self):
        try:
            self.query.range_ = self.range_.text()
        except Exception as ex:
            self.log.info("Range criterion 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.roles_equal = self.roles_equal.isChecked()
        self.query.level_dom = self.level_dom.isChecked()
        self.query.level_domby = self.level_domby.isChecked()
        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):
        # 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()
Beispiel #24
0
class DevicesListWidget(QWidget):
    def __init__(self, parent, *args, **kwargs):
        super(DevicesListWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle("Devices list")
        self.setWindowState(Qt.WindowMaximized)
        self.setLayout(VLayout(margin=0, spacing=0))

        self.mqtt = parent.mqtt
        self.mdi = parent.mdi
        self.idx = None

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

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

        self.tb = Toolbar(Qt.Horizontal, 16, Qt.ToolButtonTextBesideIcon)
        self.tb.addAction(QIcon("GUI/icons/add.png"), "Add", self.device_add)

        self.layout().addWidget(self.tb)

        self.device_list = TableView()
        self.model = parent.device_model
        self.telemetry_model = parent.telemetry_model
        self.sorted_device_model = QSortFilterProxyModel()
        self.sorted_device_model.setSourceModel(parent.device_model)
        self.device_list.setModel(self.sorted_device_model)
        self.device_list.setupColumns(columns, self.hidden_columns)
        self.device_list.setSortingEnabled(True)
        self.device_list.setWordWrap(True)
        self.device_list.setItemDelegate(DeviceDelegate())
        self.device_list.sortByColumn(DevMdl.TOPIC, Qt.AscendingOrder)
        self.device_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.layout().addWidget(self.device_list)

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

        self.device_list.horizontalHeader().setContextMenuPolicy(
            Qt.CustomContextMenu)
        self.device_list.horizontalHeader().customContextMenuRequested.connect(
            self.show_header_ctx_menu)

        self.ctx_menu = QMenu()
        self.ctx_menu_relays = None
        self.create_actions()

        self.build_header_ctx_menu()

    def create_actions(self):
        self.ctx_menu.addAction(QIcon("GUI/icons/configure.png"), "Configure",
                                self.device_config)
        self.ctx_menu.addAction(QIcon("GUI/icons/delete.png"), "Remove",
                                self.device_delete)
        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/on.png"), "Power ON",
                                lambda: self.ctx_menu_power(state="ON"))
        self.ctx_menu.addAction(QIcon("GUI/icons/off.png"), "Power OFF",
                                lambda: self.ctx_menu_power(state="OFF"))

        self.ctx_menu_relays = QMenu("Relays")
        self.ctx_menu_relays.setIcon(QIcon("GUI/icons/switch.png"))
        relays_btn = self.ctx_menu.addMenu(self.ctx_menu_relays)
        self.ctx_menu_relays.setEnabled(False)
        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction(QIcon("GUI/icons/clear.png"), "Clear retained",
                                self.ctx_menu_clean_retained)
        self.ctx_menu.addSeparator()

        self.ctx_menu_copy = QMenu("Copy")
        self.ctx_menu_copy.setIcon(QIcon("GUI/icons/copy.png"))
        copy_btn = self.ctx_menu.addMenu(self.ctx_menu_copy)

        self.ctx_menu.addSeparator()
        self.ctx_menu.addAction("Set teleperiod", self.ctx_menu_teleperiod)
        self.ctx_menu.addAction(QIcon("GUI/icons/restart.png"), "Restart",
                                self.ctx_menu_restart)
        self.ctx_menu.addAction(QIcon("GUI/icons/web.png"), "Open WebUI",
                                self.ctx_menu_webui)
        self.ctx_menu.addSeparator()

        self.ctx_menu_ota = QMenu("OTA upgrade")
        self.ctx_menu_ota.addAction("Set OTA URL", self.ctx_menu_ota_set_url)
        self.ctx_menu_ota.addAction("Upgrade", self.ctx_menu_ota_set_upgrade)
        ota_btn = self.ctx_menu.addMenu(self.ctx_menu_ota)

        self.ctx_menu.addAction("Config backup", self.ctx_menu_config_backup)

        self.ctx_menu_copy.addAction(
            "IP", lambda: self.ctx_menu_copy_value(DevMdl.IP))
        self.ctx_menu_copy.addAction(
            "MAC", lambda: self.ctx_menu_copy_value(DevMdl.MAC))
        self.ctx_menu_copy.addAction("BSSID", self.ctx_menu_copy_bssid)
        self.ctx_menu_copy.addSeparator()
        self.ctx_menu_copy.addAction(
            "Topic", lambda: self.ctx_menu_copy_value(DevMdl.TOPIC))
        self.ctx_menu_copy.addAction(
            "FullTopic", lambda: self.ctx_menu_copy_value(DevMdl.FULL_TOPIC))
        self.ctx_menu_copy.addAction(
            "STAT topic", lambda: self.ctx_menu_copy_prefix_topic("STAT"))
        self.ctx_menu_copy.addAction(
            "CMND topic", lambda: self.ctx_menu_copy_prefix_topic("CMND"))
        self.ctx_menu_copy.addAction(
            "TELE topic", lambda: self.ctx_menu_copy_prefix_topic("TELE"))

        self.tb.addActions(self.ctx_menu.actions())
        self.tb.widgetForAction(ota_btn).setPopupMode(QToolButton.InstantPopup)
        self.tb.widgetForAction(relays_btn).setPopupMode(
            QToolButton.InstantPopup)
        self.tb.widgetForAction(copy_btn).setPopupMode(
            QToolButton.InstantPopup)

    def ctx_menu_copy_value(self, column):
        if self.idx:
            row = self.idx.row()
            value = self.model.data(self.model.index(row, column))
            QApplication.clipboard().setText(value)

    def ctx_menu_copy_bssid(self):
        if self.idx:
            QApplication.clipboard().setText(self.model.bssid(self.idx))

    def ctx_menu_copy_prefix_topic(self, prefix):
        if self.idx:
            if prefix == "STAT":
                topic = self.model.statTopic(self.idx)
            elif prefix == "CMND":
                topic = self.model.commandTopic(self.idx)
            elif prefix == "TELE":
                topic = self.model.teleTopic(self.idx)
            QApplication.clipboard().setText(topic)

    def ctx_menu_clean_retained(self):
        if self.idx:
            relays = self.model.data(
                self.model.index(self.idx.row(), DevMdl.POWER))
            if relays and len(relays.keys()) > 0:
                cmnd_topic = self.model.commandTopic(self.idx)

                for r in relays.keys():
                    self.mqtt.publish(cmnd_topic + r, retain=True)
                QMessageBox.information(self, "Clear retained",
                                        "Cleared retained messages.")

    def ctx_menu_power(self, relay=None, state=None):
        if self.idx:
            relays = self.model.data(
                self.model.index(self.idx.row(), DevMdl.POWER))
            cmnd_topic = self.model.commandTopic(self.idx)
            if relay:
                self.mqtt.publish(cmnd_topic + relay, payload=state)

            elif relays:
                for r in relays.keys():
                    self.mqtt.publish(cmnd_topic + r, payload=state)

    def ctx_menu_restart(self):
        if self.idx:
            self.mqtt.publish("{}/restart".format(
                self.model.commandTopic(self.idx)),
                              payload="1")

    def ctx_menu_refresh(self):
        if self.idx:
            for q in initial_queries:
                self.mqtt.publish("{}/status".format(
                    self.model.commandTopic(self.idx)),
                                  payload=q)

    def ctx_menu_teleperiod(self):
        if self.idx:
            teleperiod, ok = QInputDialog.getInt(
                self, "Set telemetry period",
                "Input 1 to reset to default\n[Min: 10, Max: 3600]",
                int(
                    self.model.data(
                        self.model.index(self.idx.row(),
                                         DevMdl.TELEPERIOD))), 1, 3600)
            if ok:
                if teleperiod != 1 and teleperiod < 10:
                    teleperiod = 10
            self.mqtt.publish("{}/teleperiod".format(
                self.model.commandTopic(self.idx)),
                              payload=teleperiod)

    def ctx_menu_telemetry(self):
        if self.idx:
            self.mqtt.publish("{}/status".format(
                self.model.commandTopic(self.idx)),
                              payload=8)

    def ctx_menu_webui(self):
        if self.idx:
            QDesktopServices.openUrl(
                QUrl("http://{}".format(self.model.ip(self.idx))))

    def ctx_menu_config_backup(self):
        if self.idx:
            self.backup = bytes()
            ip = self.model.data(self.model.index(self.idx.row(), DevMdl.IP))
            self.dl = self.nam.get(
                QNetworkRequest(QUrl("http://{}/dl".format(ip))))
            self.dl.readyRead.connect(self.get_dump)
            self.dl.finished.connect(self.save_dump)

    def ctx_menu_ota_set_url(self):
        if self.idx:
            current_url = self.model.data(
                self.model.index(self.idx.row(), DevMdl.OTA_URL))
            url, ok = QInputDialog.getText(
                self,
                "Set OTA URL",
                '100 chars max. Set to "1" to reset to default.',
                text=current_url)
            if ok:
                self.mqtt.publish("{}/otaurl".format(
                    self.model.commandTopic(self.idx)),
                                  payload=url)

    def ctx_menu_ota_set_upgrade(self):
        if self.idx:
            current_url = self.model.data(
                self.model.index(self.idx.row(), DevMdl.OTA_URL))
            if QMessageBox.question(
                    self, "OTA Upgrade",
                    "Are you sure to OTA upgrade from\n{}".format(current_url),
                    QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
                self.model.setData(
                    self.model.index(self.idx.row(), DevMdl.FIRMWARE),
                    "Upgrade in progress")
                self.mqtt.publish("{}/upgrade".format(
                    self.model.commandTopic(self.idx)),
                                  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 build_header_ctx_menu(self):
        self.hdr_ctx_menu = QMenu()
        for c in columns.keys():
            a = self.hdr_ctx_menu.addAction(columns[c][0])
            a.setData(c)
            a.setCheckable(True)
            a.setChecked(not self.device_list.isColumnHidden(c))
            a.toggled.connect(self.header_ctx_menu_toggle_col)

    def show_header_ctx_menu(self, at):
        self.hdr_ctx_menu.popup(
            self.device_list.horizontalHeader().viewport().mapToGlobal(at))

    def header_ctx_menu_toggle_col(self, state):
        self.device_list.setColumnHidden(self.sender().data(), not state)
        hidden_columns = [
            int(c) for c in columns.keys()
            if self.device_list.isColumnHidden(c)
        ]
        self.settings.setValue("hidden_columns", hidden_columns)
        self.settings.sync()

    def select_device(self, idx):
        self.idx = self.sorted_device_model.mapToSource(idx)
        self.device = self.model.data(self.model.index(idx.row(),
                                                       DevMdl.TOPIC))

        relays = self.model.data(self.model.index(self.idx.row(),
                                                  DevMdl.POWER))
        if relays and len(relays.keys()) > 1:
            self.ctx_menu_relays.setEnabled(True)
            self.ctx_menu_relays.setEnabled(True)
            self.ctx_menu_relays.clear()

            for r in relays.keys():
                actR = self.ctx_menu_relays.addAction("{} ON".format(r))
                actR.triggered.connect(
                    lambda st, x=r: self.ctx_menu_power(x, "ON"))
                actR = self.ctx_menu_relays.addAction("{} OFF".format(r))
                actR.triggered.connect(
                    lambda st, x=r: self.ctx_menu_power(x, "OFF"))
                self.ctx_menu_relays.addSeparator()
        else:
            self.ctx_menu_relays.setEnabled(False)
            self.ctx_menu_relays.clear()

    def device_config(self, idx=None):
        if self.idx:
            dev_cfg = DevicesConfigWidget(self, self.model.topic(self.idx))
            self.mdi.addSubWindow(dev_cfg)
            dev_cfg.setWindowState(Qt.WindowMaximized)

    def device_add(self):
        rc = self.model.rowCount()
        self.model.insertRow(rc)
        dlg = DeviceEditDialog(self.model, rc)
        dlg.full_topic.setText("%prefix%/%topic%/")

        if dlg.exec_() == QDialog.Accepted:
            self.model.setData(
                self.model.index(rc, DevMdl.FRIENDLY_NAME),
                self.model.data(self.model.index(rc, DevMdl.TOPIC)))
            topic = dlg.topic.text()
            tele_dev = self.telemetry_model.addDevice(TasmotaDevice, topic)
            self.telemetry_model.devices[topic] = tele_dev
        else:
            self.model.removeRow(rc)

    def device_delete(self):
        if self.idx:
            topic = self.model.topic(self.idx)
            if QMessageBox.question(
                    self, "Confirm",
                    "Do you want to remove '{}' from devices list?".format(
                        topic)) == QMessageBox.Yes:
                self.model.removeRows(self.idx.row(), 1)
                tele_idx = self.telemetry_model.devices.get(topic)
                if tele_idx:
                    self.telemetry_model.removeRows(tele_idx.row(), 1)

    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 closeEvent(self, event):
        event.ignore()
Beispiel #25
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):
        xperms = []
        try:
            text = self.xperms.text()

            if text:
                for item in self.xperms.text().split(","):
                    rng = item.split("-")
                    if len(rng) == 2:
                        xperms.append((int(rng[0],
                                           base=16), int(rng[1], base=16)))
                    elif len(rng) == 1:
                        xperms.append((int(rng[0],
                                           base=16), int(rng[0], base=16)))
                    else:
                        raise ValueError(
                            "Enter an extended permission or extended permission "
                            "range, e.g. 0x5411 or 0x8800-0x88ff.")

                self.query.xperms = xperms
            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()
Beispiel #26
0
class OperacaoLogistica(QDialog):
    #TODO: Acertar formatação na listagem de items por SIMAFIC
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowFlags(Qt.WindowMinMaxButtonsHint
                            | Qt.WindowCloseButtonHint)
        self.setWindowTitle('Operação Logística')
        self.setMinimumSize(QSize(h_size, v_size))
        self.setWindowIcon(QIcon(main_icon))

        verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)

        #Pedido Input Field
        self.proxy_list_result_id = QSortFilterProxyModel()
        self.numero_pedido = QLineEdit(self)
        self.numero_pedido.setPlaceholderText("Insira o Número do Pedido")
        self.numero_pedido.textChanged.connect(
            lambda wildcard: self.proxy_list_result_id.setFilterWildcard(
                wildcard))

        #Voltar Btn
        self.voltar_btn = QPushButton(self)
        #self.voltar_btn.setStyleSheet('background-color: rgb(0,0,255); color: #fff')
        self.voltar_btn.setText('Voltar')
        self.voltar_btn.clicked.connect(self.goMainWindow)
        self.close()

        #Adicionar Cores no StyleSheet
        colors = ['##393318', '  ##fff']
        self.pedidos = services.get_all_pedidos()
        self.item_result = None
        self.item_escolhido = None

        self.id_pedido_list = QListView()
        self.simafics_do_id = QListWidget()
        #self.simafics_do_id.setHidden(True)
        self.createPedidoIdList()

        self.id_pedido_list.clicked.connect(
            lambda id_pedido: self.createListaSimafics(id_pedido))
        self.simafics_do_id.itemDoubleClicked.connect(
            lambda pedido: self.simaficSelecionado(pedido))

        self.pedidos_label = QLabel()
        self.pedidos_label.setBuddy(self.id_pedido_list)
        self.simafic_label = QLabel()
        self.simafic_label.setBuddy(self.simafics_do_id)

        self.itensTree = PedidoItensTree()
        self.treeItensTV = QTreeView()
        self.treeItensTV.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.treeItensTV.setAlternatingRowColors(True)
        self.treeItensTV.setRootIsDecorated(True)
        self.treeItensTV.doubleClicked.connect(self.simaficSelecionado)
        self.treeItensTV.setColumnHidden(8, True)

        if len(self.pedidos) <= 0:
            self.pedidos_label.setText(
                "É necessário adicionar um pedido na tela de cadastro.")
            self.pedidos_label.setStyleSheet("QLabel { color: red; }")
        else:
            self.pedidos_label.setText("Listagem de Pedidos:")
            self.pedidos_label.setStyleSheet("QLabel { color: black; }")
            self.simafic_label.setText(
                "Selecione um pedido para ver a listagem de Itens por SIMAFIC:"
            )
            self.simafic_label.setStyleSheet("QLabel { color: red; }")

        layout = QGridLayout()
        layout.setColumnStretch(0, 1)
        layout.setColumnStretch(1, 4)
        layout.addWidget(self.numero_pedido, 0, 0)
        layout.addWidget(self.voltar_btn, 0, 1)
        layout.addWidget(self.pedidos_label, 1, 0)
        layout.addWidget(self.simafic_label, 1, 1)
        layout.addWidget(self.id_pedido_list, 2, 0)
        layout.addWidget(self.treeItensTV, 2, 1)
        #layout.addWidget(self.simafics_do_id, 2,1)
        self.setLayout(layout)

    def createPedidoIdList(self):
        print('def createPedidoIdList(self):')
        onlyids = set()
        pedidosbyid = []
        pedidosCompletos = []
        self.proxy_list_result_id = QSortFilterProxyModel()
        for obj in self.pedidos:
            if obj.id_pedido not in onlyids:
                pedidosbyid.append(obj)
                onlyids.add(obj.id_pedido)

        self.pedidoId_model = QStringListModel(onlyids, self)
        self.proxy_list_result_id.setSourceModel(self.pedidoId_model)
        self.id_pedido_list.setModel(self.proxy_list_result_id)
        self.id_pedido_list.setAlternatingRowColors(True)
        self.id_pedido_list.setEditTriggers(QAbstractItemView.NoEditTriggers)

    def createListaSimafics(self, id_pedido):

        pedido = id_pedido.data()
        self.pedidosModel = self.itensTree.createPedidosModel(self.itensTree)
        self.treeItensTV.setModel(self.pedidosModel)
        print('def listaSimafics(self, id_pedido): {id_pedido}'.format(
            id_pedido=pedido))
        self.item_result = None
        self.item_result = [x for x in self.pedidos if x.id_pedido == pedido]
        self.simafics_do_id.clear()
        self.pedidosModel.beginResetModel
        self.pedidosModel.modelReset
        self.pedidosModel.endResetModel

        for idx, item in enumerate(self.item_result):
            print(item)
            self.itensTree.addItens(
                self.pedidosModel, item.cod_simafic, item.desc,
                item.qty_scanneada, item.qty_total, item.nome_responsavel,
                item.id_caixa, item.time_updated.strftime("%d/%m/%y %H:%M:%S"),
                item.id_pedido, item)

        self.simafic_label.setText(
            "Listagem de Itens do pedido {} por SIMAFIC:".format(pedido))
        self.simafic_label.setStyleSheet("QLabel { color: black; }")

        #self.simafics_do_id.setHidden(False)

    def simaficSelecionado(self, item):
        print(item.column(), item.row())
        simafic_escolhido = self.treeItensTV.model().index(item.row(),
                                                           0).data()
        id_pedido = self.treeItensTV.model().index(item.row(), 7).data()
        self.item_escolhido = [
            x for x in self.item_result
            if x.cod_simafic == simafic_escolhido and x.id_pedido == id_pedido
        ]
        self.cams = ItemScanner(self.item_escolhido[0])
        self.cams.show()
        self.close()

    def goMainWindow(self):
        self.cams = mainView
        self.cams.show()
        self.close()

    def goScan(self):
        self.cams = ItemScanner("Eu sou o Pedido", "Eu sou o Simafic",
                                "Eu sou a Descrição", "300")
        self.cams.show()
        self.close()
Beispiel #27
0
class FSUseQueryTab(AnalysisTab):

    """A fs_use_* rule query."""

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

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

    def setupUi(self):
        self.load_ui("fsusequery.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_fs_error()
        self.clear_user_error()
        self.clear_type_error()
        self.clear_role_error()
        self.clear_range_error()

        # set up results
        self.table_results_model = FSUseTableModel(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.fsusequery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_fs_regex(self.fs_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.clear_ruletypes.clicked.connect(self.clear_all_ruletypes)
        self.all_ruletypes.clicked.connect(self.set_all_ruletypes)
        self.fs.textEdited.connect(self.clear_fs_error)
        self.fs.editingFinished.connect(self.set_fs)
        self.fs_regex.toggled.connect(self.set_fs_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)

    #
    # Ruletype criteria
    #
    def _set_ruletypes(self, value):
        self.fs_use_xattr.setChecked(value)
        self.fs_use_trans.setChecked(value)
        self.fs_use_task.setChecked(value)

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

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

    #
    # FS criteria
    #
    def clear_fs_error(self):
        self.clear_criteria_error(self.fs, "Match the filesystem type.")

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

    def set_fs_regex(self, state):
        self.log.debug("Setting fs_regex {0}".format(state))
        self.query.fs_regex = state
        self.clear_fs_error()
        self.set_fs()

    #
    # 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",
                                         "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task",
                                         "user_regex", "role_regex", "type_regex", "range_exact",
                                         "range_overlap", "range_subset", "range_superset"])
        save_lineedits(self, settings, ["fs", "user", "role", "type_", "range_"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings, ["criteria_expander", "notes_expander",
                                         "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task",
                                         "user_regex", "role_regex", "type_regex", "range_exact",
                                         "range_overlap", "range_subset", "range_superset"])
        load_lineedits(self, settings, ["fs", "user", "role", "type_", "range_"])
        load_textedits(self, settings, ["notes"])

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

        for mode in [self.fs_use_xattr, self.fs_use_trans, self.fs_use_task]:
            if mode.isChecked():
                rule_types.append(mode.objectName())

        self.query.ruletype = rule_types
        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} fs_use_* 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()
Beispiel #28
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self._version = "0.1.20"
        self.setWindowIcon(QIcon("GUI/icons/logo.png"))
        self.setWindowTitle("Tasmota Device Manager {}".format(self._version))

        self.main_splitter = QSplitter()
        self.devices_splitter = QSplitter(Qt.Vertical)

        self.mqtt_queue = []
        self.devices = {}

        self.fulltopic_queue = []
        old_settings = QSettings()

        self.settings = QSettings("{}/TDM/tdm.cfg".format(QDir.homePath()),
                                  QSettings.IniFormat)
        self.setMinimumSize(QSize(1280, 800))

        for k in old_settings.allKeys():
            self.settings.setValue(k, old_settings.value(k))
            old_settings.remove(k)

        self.device_model = TasmotaDevicesModel()
        self.telemetry_model = TasmotaDevicesTree()
        self.console_model = ConsoleModel()

        self.sorted_console_model = QSortFilterProxyModel()
        self.sorted_console_model.setSourceModel(self.console_model)
        self.sorted_console_model.setFilterKeyColumn(CnsMdl.FRIENDLY_NAME)

        self.setup_mqtt()
        self.setup_telemetry_view()
        self.setup_main_layout()
        self.add_devices_tab()
        self.build_toolbars()
        self.setStatusBar(QStatusBar())

        self.queue_timer = QTimer()
        self.queue_timer.timeout.connect(self.mqtt_publish_queue)
        self.queue_timer.start(500)

        self.auto_timer = QTimer()
        self.auto_timer.timeout.connect(self.autoupdate)

        self.load_window_state()

        if self.settings.value("connect_on_startup", False, bool):
            self.actToggleConnect.trigger()

    def setup_main_layout(self):
        self.mdi = QMdiArea()
        self.mdi.setActivationOrder(QMdiArea.ActivationHistoryOrder)
        self.mdi.setViewMode(QMdiArea.TabbedView)
        self.mdi.setDocumentMode(True)

        mdi_widget = QWidget()
        mdi_widget.setLayout(VLayout())
        mdi_widget.layout().addWidget(self.mdi)

        self.devices_splitter.addWidget(mdi_widget)

        vl_console = VLayout()
        hl_filter = HLayout()
        self.cbFilter = QCheckBox("Console filtering")
        self.cbxFilterDevice = QComboBox()
        self.cbxFilterDevice.setEnabled(False)
        self.cbxFilterDevice.setFixedWidth(200)
        self.cbxFilterDevice.setModel(self.device_model)
        self.cbxFilterDevice.setModelColumn(DevMdl.FRIENDLY_NAME)
        hl_filter.addWidgets([self.cbFilter, self.cbxFilterDevice])
        hl_filter.addStretch(0)
        vl_console.addLayout(hl_filter)

        self.console_view = TableView()
        self.console_view.setModel(self.console_model)
        self.console_view.setupColumns(columns_console)
        self.console_view.setAlternatingRowColors(True)
        self.console_view.verticalHeader().setDefaultSectionSize(20)
        self.console_view.setMinimumHeight(200)

        vl_console.addWidget(self.console_view)

        console_widget = QWidget()
        console_widget.setLayout(vl_console)

        self.devices_splitter.addWidget(console_widget)
        self.main_splitter.insertWidget(0, self.devices_splitter)
        self.setCentralWidget(self.main_splitter)
        self.console_view.clicked.connect(self.select_cons_entry)
        self.console_view.doubleClicked.connect(self.view_payload)

        self.cbFilter.toggled.connect(self.toggle_console_filter)
        self.cbxFilterDevice.currentTextChanged.connect(
            self.select_console_filter)

    def setup_telemetry_view(self):
        tele_widget = QWidget()
        vl_tele = VLayout()
        self.tview = QTreeView()
        self.tview.setMinimumWidth(300)
        self.tview.setModel(self.telemetry_model)
        self.tview.setAlternatingRowColors(True)
        self.tview.setUniformRowHeights(True)
        self.tview.setIndentation(15)
        self.tview.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum))
        self.tview.expandAll()
        self.tview.resizeColumnToContents(0)
        vl_tele.addWidget(self.tview)
        tele_widget.setLayout(vl_tele)
        self.main_splitter.addWidget(tele_widget)

    def setup_mqtt(self):
        self.mqtt = MqttClient()
        self.mqtt.connecting.connect(self.mqtt_connecting)
        self.mqtt.connected.connect(self.mqtt_connected)
        self.mqtt.disconnected.connect(self.mqtt_disconnected)
        self.mqtt.connectError.connect(self.mqtt_connectError)
        self.mqtt.messageSignal.connect(self.mqtt_message)

    def add_devices_tab(self):
        tabDevicesList = DevicesListWidget(self)
        self.mdi.addSubWindow(tabDevicesList)
        tabDevicesList.setWindowState(Qt.WindowMaximized)

    def load_window_state(self):
        wndGeometry = self.settings.value('window_geometry')
        if wndGeometry:
            self.restoreGeometry(wndGeometry)
        spltState = self.settings.value('splitter_state')
        if spltState:
            self.main_splitter.restoreState(spltState)

    def build_toolbars(self):
        main_toolbar = Toolbar(orientation=Qt.Horizontal,
                               iconsize=16,
                               label_position=Qt.ToolButtonTextBesideIcon)
        main_toolbar.setObjectName("main_toolbar")
        self.addToolBar(main_toolbar)

        main_toolbar.addAction(QIcon("./GUI/icons/connections.png"), "Broker",
                               self.setup_broker)
        self.actToggleConnect = QAction(QIcon("./GUI/icons/disconnect.png"),
                                        "MQTT")
        self.actToggleConnect.setCheckable(True)
        self.actToggleConnect.toggled.connect(self.toggle_connect)
        main_toolbar.addAction(self.actToggleConnect)

        self.actToggleAutoUpdate = QAction(QIcon("./GUI/icons/automatic.png"),
                                           "Auto telemetry")
        self.actToggleAutoUpdate.setCheckable(True)
        self.actToggleAutoUpdate.toggled.connect(self.toggle_autoupdate)
        main_toolbar.addAction(self.actToggleAutoUpdate)

        main_toolbar.addSeparator()
        main_toolbar.addAction(QIcon("./GUI/icons/bssid.png"), "BSSId",
                               self.bssid)
        main_toolbar.addAction(QIcon("./GUI/icons/export.png"), "Export list",
                               self.export)

    def initial_query(self, idx, queued=False):
        for q in initial_queries:
            topic = "{}status".format(self.device_model.commandTopic(idx))
            if queued:
                self.mqtt_queue.append([topic, q])
            else:
                self.mqtt.publish(topic, q, 1)
            self.console_log(topic, "Asked for STATUS {}".format(q), q)

    def setup_broker(self):
        brokers_dlg = BrokerDialog()
        if brokers_dlg.exec_(
        ) == QDialog.Accepted and self.mqtt.state == self.mqtt.Connected:
            self.mqtt.disconnect()

    def toggle_autoupdate(self, state):
        if state:
            self.auto_timer.setInterval(5000)
            self.auto_timer.start()

    def toggle_connect(self, state):
        if state and self.mqtt.state == self.mqtt.Disconnected:
            self.broker_hostname = self.settings.value('hostname', 'localhost')
            self.broker_port = self.settings.value('port', 1883, int)
            self.broker_username = self.settings.value('username')
            self.broker_password = self.settings.value('password')

            self.mqtt.hostname = self.broker_hostname
            self.mqtt.port = self.broker_port

            if self.broker_username:
                self.mqtt.setAuth(self.broker_username, self.broker_password)
            self.mqtt.connectToHost()
        elif not state and self.mqtt.state == self.mqtt.Connected:
            self.mqtt_disconnect()

    def autoupdate(self):
        if self.mqtt.state == self.mqtt.Connected:
            for d in range(self.device_model.rowCount()):
                idx = self.device_model.index(d, 0)
                cmnd = self.device_model.commandTopic(idx)
                self.mqtt.publish(cmnd + "STATUS", payload=8)

    def mqtt_connect(self):
        self.broker_hostname = self.settings.value('hostname', 'localhost')
        self.broker_port = self.settings.value('port', 1883, int)
        self.broker_username = self.settings.value('username')
        self.broker_password = self.settings.value('password')

        self.mqtt.hostname = self.broker_hostname
        self.mqtt.port = self.broker_port

        if self.broker_username:
            self.mqtt.setAuth(self.broker_username, self.broker_password)

        if self.mqtt.state == self.mqtt.Disconnected:
            self.mqtt.connectToHost()

    def mqtt_disconnect(self):
        self.mqtt.disconnectFromHost()

    def mqtt_connecting(self):
        self.statusBar().showMessage("Connecting to broker")

    def mqtt_connected(self):
        self.actToggleConnect.setIcon(QIcon("./GUI/icons/connect.png"))
        self.statusBar().showMessage("Connected to {}:{} as {}".format(
            self.broker_hostname, self.broker_port,
            self.broker_username if self.broker_username else '[anonymous]'))

        self.mqtt_subscribe()

        for d in range(self.device_model.rowCount()):
            idx = self.device_model.index(d, 0)
            self.initial_query(idx)

    def mqtt_subscribe(self):
        main_topics = ["+/stat/+", "+/tele/+", "stat/#", "tele/#"]

        for d in range(self.device_model.rowCount()):
            idx = self.device_model.index(d, 0)
            if not self.device_model.isDefaultTemplate(idx):
                main_topics.append(self.device_model.commandTopic(idx))
                main_topics.append(self.device_model.statTopic(idx))

        for t in main_topics:
            self.mqtt.subscribe(t)

    def mqtt_publish_queue(self):
        for q in self.mqtt_queue:
            t, p = q
            self.mqtt.publish(t, p)
            self.mqtt_queue.pop(self.mqtt_queue.index(q))

    def mqtt_disconnected(self):
        self.actToggleConnect.setIcon(QIcon("./GUI/icons/disconnect.png"))
        self.statusBar().showMessage("Disconnected")

    def mqtt_connectError(self, rc):
        reason = {
            1: "Incorrect protocol version",
            2: "Invalid client identifier",
            3: "Server unavailable",
            4: "Bad username or password",
            5: "Not authorized",
        }
        self.statusBar().showMessage("Connection error: {}".format(reason[rc]))
        self.actToggleConnect.setChecked(False)

    def mqtt_message(self, topic, msg):
        found = self.device_model.findDevice(topic)
        if found.reply == 'LWT':
            if not msg:
                msg = "offline"

            if found.index.isValid():
                self.console_log(topic, "LWT update: {}".format(msg), msg)
                self.device_model.updateValue(found.index, DevMdl.LWT, msg)
                self.initial_query(found.index, queued=True)

            elif msg == "Online":
                self.console_log(
                    topic,
                    "LWT for unknown device '{}'. Asking for FullTopic.".
                    format(found.topic), msg, False)
                self.mqtt_queue.append(
                    ["cmnd/{}/fulltopic".format(found.topic), ""])
                self.mqtt_queue.append(
                    ["{}/cmnd/fulltopic".format(found.topic), ""])

        elif found.reply == 'RESULT':
            try:
                full_topic = loads(msg).get('FullTopic')
                new_topic = loads(msg).get('Topic')
                template_name = loads(msg).get('NAME')
                ota_url = loads(msg).get('OtaUrl')
                teleperiod = loads(msg).get('TelePeriod')

                if full_topic:
                    # TODO: update FullTopic for existing device AFTER the FullTopic changes externally (the message will arrive from new FullTopic)
                    if not found.index.isValid():
                        self.console_log(
                            topic, "FullTopic for {}".format(found.topic), msg,
                            False)

                        new_idx = self.device_model.addDevice(found.topic,
                                                              full_topic,
                                                              lwt='online')
                        tele_idx = self.telemetry_model.addDevice(
                            TasmotaDevice, found.topic)
                        self.telemetry_model.devices[found.topic] = tele_idx
                        #TODO: add QSortFilterProxyModel to telemetry treeview and sort devices after adding

                        self.initial_query(new_idx)
                        self.console_log(
                            topic,
                            "Added {} with fulltopic {}, querying for STATE".
                            format(found.topic, full_topic), msg)
                        self.tview.expand(tele_idx)
                        self.tview.resizeColumnToContents(0)

                elif new_topic:
                    if found.index.isValid() and found.topic != new_topic:
                        self.console_log(
                            topic, "New topic for {}".format(found.topic), msg)

                        self.device_model.updateValue(found.index,
                                                      DevMdl.TOPIC, new_topic)

                        tele_idx = self.telemetry_model.devices.get(
                            found.topic)

                        if tele_idx:
                            self.telemetry_model.setDeviceName(
                                tele_idx, new_topic)
                            self.telemetry_model.devices[
                                new_topic] = self.telemetry_model.devices.pop(
                                    found.topic)

                elif template_name:
                    self.device_model.updateValue(
                        found.index, DevMdl.MODULE,
                        "{} (0)".format(template_name))

                elif ota_url:
                    self.device_model.updateValue(found.index, DevMdl.OTA_URL,
                                                  ota_url)

                elif teleperiod:
                    self.device_model.updateValue(found.index,
                                                  DevMdl.TELEPERIOD,
                                                  teleperiod)

            except JSONDecodeError as e:
                self.console_log(
                    topic,
                    "JSON payload decode error. Check error.log for additional info."
                )
                with open("{}/TDM/error.log".format(QDir.homePath()),
                          "a+") as l:
                    l.write("{}\t{}\t{}\t{}\n".format(
                        QDateTime.currentDateTime().toString(
                            "yyyy-MM-dd hh:mm:ss"), topic, msg, e.msg))

        elif found.index.isValid():
            ok = False
            try:
                if msg.startswith("{"):
                    payload = loads(msg)
                else:
                    payload = msg
                ok = True
            except JSONDecodeError as e:
                self.console_log(
                    topic,
                    "JSON payload decode error. Check error.log for additional info."
                )
                with open("{}/TDM/error.log".format(QDir.homePath()),
                          "a+") as l:
                    l.write("{}\t{}\t{}\t{}\n".format(
                        QDateTime.currentDateTime().toString(
                            "yyyy-MM-dd hh:mm:ss"), topic, msg, e.msg))

            if ok:
                try:
                    if found.reply == 'STATUS':
                        self.console_log(topic, "Received device status", msg)
                        payload = payload['Status']
                        self.device_model.updateValue(
                            found.index, DevMdl.FRIENDLY_NAME,
                            payload['FriendlyName'][0])
                        self.telemetry_model.setDeviceFriendlyName(
                            self.telemetry_model.devices[found.topic],
                            payload['FriendlyName'][0])
                        module = payload['Module']
                        if module == 0:
                            self.mqtt.publish(
                                self.device_model.commandTopic(found.index) +
                                "template")
                        else:
                            self.device_model.updateValue(
                                found.index, DevMdl.MODULE,
                                modules.get(module, 'Unknown'))
                        self.device_model.updateValue(found.index,
                                                      DevMdl.MODULE_ID, module)

                    elif found.reply == 'STATUS1':
                        self.console_log(topic, "Received program information",
                                         msg)
                        payload = payload['StatusPRM']
                        self.device_model.updateValue(
                            found.index, DevMdl.RESTART_REASON,
                            payload.get('RestartReason'))
                        self.device_model.updateValue(found.index,
                                                      DevMdl.OTA_URL,
                                                      payload.get('OtaUrl'))

                    elif found.reply == 'STATUS2':
                        self.console_log(topic,
                                         "Received firmware information", msg)
                        payload = payload['StatusFWR']
                        self.device_model.updateValue(found.index,
                                                      DevMdl.FIRMWARE,
                                                      payload['Version'])
                        self.device_model.updateValue(found.index, DevMdl.CORE,
                                                      payload['Core'])

                    elif found.reply == 'STATUS3':
                        self.console_log(topic, "Received syslog information",
                                         msg)
                        payload = payload['StatusLOG']
                        self.device_model.updateValue(found.index,
                                                      DevMdl.TELEPERIOD,
                                                      payload['TelePeriod'])

                    elif found.reply == 'STATUS5':
                        self.console_log(topic, "Received network status", msg)
                        payload = payload['StatusNET']
                        self.device_model.updateValue(found.index, DevMdl.MAC,
                                                      payload['Mac'])
                        self.device_model.updateValue(found.index, DevMdl.IP,
                                                      payload['IPAddress'])

                    elif found.reply in ('STATE', 'STATUS11'):
                        self.console_log(topic, "Received device state", msg)
                        if found.reply == 'STATUS11':
                            payload = payload['StatusSTS']
                        self.parse_state(found.index, payload)

                    elif found.reply in ('SENSOR', 'STATUS8'):
                        self.console_log(topic, "Received telemetry", msg)
                        if found.reply == 'STATUS8':
                            payload = payload['StatusSNS']
                        self.parse_telemetry(found.index, payload)

                    elif found.reply.startswith('POWER'):
                        self.console_log(
                            topic, "Received {} state".format(found.reply),
                            msg)
                        payload = {found.reply: msg}
                        self.parse_power(found.index, payload)

                except KeyError as k:
                    self.console_log(
                        topic,
                        "JSON key error. Check error.log for additional info.")
                    with open("{}/TDM/error.log".format(QDir.homePath()),
                              "a+") as l:
                        l.write("{}\t{}\t{}\tKeyError: {}\n".format(
                            QDateTime.currentDateTime().toString(
                                "yyyy-MM-dd hh:mm:ss"), topic, payload,
                            k.args[0]))

    def parse_power(self, index, payload, from_state=False):
        old = self.device_model.power(index)
        power = {
            k: payload[k]
            for k in payload.keys() if k.startswith("POWER")
        }
        # TODO: fix so that number of relays get updated properly after module/no. of relays change
        needs_update = False
        if old:
            # if from_state and len(old) != len(power):
            #     needs_update = True
            #
            # else:
            for k in old.keys():
                needs_update |= old[k] != power.get(k, old[k])
                if needs_update:
                    break
        else:
            needs_update = True

        if needs_update:
            self.device_model.updateValue(index, DevMdl.POWER, power)

    def parse_state(self, index, payload):
        bssid = payload['Wifi'].get('BSSId')
        if not bssid:
            bssid = payload['Wifi'].get('APMac')
        self.device_model.updateValue(index, DevMdl.BSSID, bssid)
        self.device_model.updateValue(index, DevMdl.SSID,
                                      payload['Wifi']['SSId'])
        self.device_model.updateValue(index, DevMdl.CHANNEL,
                                      payload['Wifi'].get('Channel', "n/a"))
        self.device_model.updateValue(index, DevMdl.RSSI,
                                      payload['Wifi']['RSSI'])
        self.device_model.updateValue(index, DevMdl.UPTIME, payload['Uptime'])
        self.device_model.updateValue(index, DevMdl.LOADAVG,
                                      payload.get('LoadAvg'))
        self.device_model.updateValue(index, DevMdl.LINKCOUNT,
                                      payload['Wifi'].get('LinkCount', "n/a"))
        self.device_model.updateValue(index, DevMdl.DOWNTIME,
                                      payload['Wifi'].get('Downtime', "n/a"))

        self.parse_power(index, payload, True)

        tele_idx = self.telemetry_model.devices.get(
            self.device_model.topic(index))

        if tele_idx:
            tele_device = self.telemetry_model.getNode(tele_idx)
            self.telemetry_model.setDeviceFriendlyName(
                tele_idx, self.device_model.friendly_name(index))

            pr = tele_device.provides()
            for k in pr.keys():
                self.telemetry_model.setData(pr[k], payload.get(k))

    def parse_telemetry(self, index, payload):
        device = self.telemetry_model.devices.get(
            self.device_model.topic(index))
        if device:
            node = self.telemetry_model.getNode(device)
            time = node.provides()['Time']
            if 'Time' in payload:
                self.telemetry_model.setData(time, payload.pop('Time'))

            temp_unit = "C"
            pres_unit = "hPa"

            if 'TempUnit' in payload:
                temp_unit = payload.pop('TempUnit')

            if 'PressureUnit' in payload:
                pres_unit = payload.pop('PressureUnit')

            for sensor in sorted(payload.keys()):
                if sensor == 'DS18x20':
                    for sns_name in payload[sensor].keys():
                        d = node.devices().get(sensor)
                        if not d:
                            d = self.telemetry_model.addDevice(
                                DS18x20, payload[sensor][sns_name]['Type'],
                                device)
                        self.telemetry_model.getNode(d).setTempUnit(temp_unit)
                        payload[sensor][sns_name]['Id'] = payload[sensor][
                            sns_name].pop('Address')

                        pr = self.telemetry_model.getNode(d).provides()
                        for pk in pr.keys():
                            self.telemetry_model.setData(
                                pr[pk], payload[sensor][sns_name].get(pk))
                        self.tview.expand(d)

                elif sensor.startswith('DS18B20'):
                    d = node.devices().get(sensor)
                    if not d:
                        d = self.telemetry_model.addDevice(
                            DS18x20, sensor, device)
                    self.telemetry_model.getNode(d).setTempUnit(temp_unit)
                    pr = self.telemetry_model.getNode(d).provides()
                    for pk in pr.keys():
                        self.telemetry_model.setData(pr[pk],
                                                     payload[sensor].get(pk))
                    self.tview.expand(d)

                if sensor == 'COUNTER':
                    d = node.devices().get(sensor)
                    if not d:
                        d = self.telemetry_model.addDevice(
                            CounterSns, "Counter", device)
                    pr = self.telemetry_model.getNode(d).provides()
                    for pk in pr.keys():
                        self.telemetry_model.setData(pr[pk],
                                                     payload[sensor].get(pk))
                    self.tview.expand(d)

                else:
                    d = node.devices().get(sensor)
                    if not d:
                        d = self.telemetry_model.addDevice(
                            sensor_map.get(sensor, Node), sensor, device)
                    pr = self.telemetry_model.getNode(d).provides()
                    if 'Temperature' in pr:
                        self.telemetry_model.getNode(d).setTempUnit(temp_unit)
                    if 'Pressure' in pr or 'SeaPressure' in pr:
                        self.telemetry_model.getNode(d).setPresUnit(pres_unit)
                    for pk in pr.keys():
                        self.telemetry_model.setData(pr[pk],
                                                     payload[sensor].get(pk))
                    self.tview.expand(d)
        # self.tview.resizeColumnToContents(0)

    def console_log(self, topic, description, payload="", known=True):
        longest_tp = 0
        longest_fn = 0
        short_topic = "/".join(topic.split("/")[0:-1])
        fname = self.devices.get(short_topic, "")
        if not fname:
            device = self.device_model.findDevice(topic)
            fname = self.device_model.friendly_name(device.index)
            self.devices.update({short_topic: fname})
        self.console_model.addEntry(topic, fname, description, payload, known)

        if len(topic) > longest_tp:
            longest_tp = len(topic)
            self.console_view.resizeColumnToContents(1)

        if len(fname) > longest_fn:
            longest_fn = len(fname)
            self.console_view.resizeColumnToContents(1)

    def view_payload(self, idx):
        if self.cbFilter.isChecked():
            idx = self.sorted_console_model.mapToSource(idx)
        row = idx.row()
        timestamp = self.console_model.data(
            self.console_model.index(row, CnsMdl.TIMESTAMP))
        topic = self.console_model.data(
            self.console_model.index(row, CnsMdl.TOPIC))
        payload = self.console_model.data(
            self.console_model.index(row, CnsMdl.PAYLOAD))

        dlg = PayloadViewDialog(timestamp, topic, payload)
        dlg.exec_()

    def select_cons_entry(self, idx):
        self.cons_idx = idx

    def export(self):
        fname, _ = QFileDialog.getSaveFileName(self,
                                               "Export device list as...",
                                               directory=QDir.homePath(),
                                               filter="CSV files (*.csv)")
        if fname:
            if not fname.endswith(".csv"):
                fname += ".csv"

            with open(fname, "w", encoding='utf8') as f:
                column_titles = [
                    'mac', 'topic', 'friendly_name', 'full_topic',
                    'cmnd_topic', 'stat_topic', 'tele_topic', 'module',
                    'module_id', 'firmware', 'core'
                ]
                c = csv.writer(f)
                c.writerow(column_titles)

                for r in range(self.device_model.rowCount()):
                    d = self.device_model.index(r, 0)
                    c.writerow([
                        self.device_model.mac(d),
                        self.device_model.topic(d),
                        self.device_model.friendly_name(d),
                        self.device_model.fullTopic(d),
                        self.device_model.commandTopic(d),
                        self.device_model.statTopic(d),
                        self.device_model.teleTopic(d),
                        modules.get(self.device_model.module(d)),
                        self.device_model.module(d),
                        self.device_model.firmware(d),
                        self.device_model.core(d)
                    ])

    def bssid(self):
        BSSIdDialog().exec_()
        # if dlg.exec_() == QDialog.Accepted:

    def toggle_console_filter(self, state):
        self.cbxFilterDevice.setEnabled(state)
        if state:
            self.console_view.setModel(self.sorted_console_model)
        else:
            self.console_view.setModel(self.console_model)

    def select_console_filter(self, fname):
        self.sorted_console_model.setFilterFixedString(fname)

    def closeEvent(self, e):
        self.settings.setValue("window_geometry", self.saveGeometry())
        self.settings.setValue("splitter_state",
                               self.main_splitter.saveState())
        self.settings.sync()
        e.accept()
Beispiel #29
0
class CadastroPedidos(QDialog):
    def __init__(self, parent=None):
        super(CadastroPedidos, self).__init__(parent=None)
        self.setWindowFlags(Qt.WindowMinMaxButtonsHint
                            | Qt.WindowCloseButtonHint)

        self.setMinimumSize(QSize(h_size, v_size))
        self.originalPalette = QApplication.palette()
        self.setWindowIcon(QIcon(main_icon))
        self.setWindowTitle("Cadastro de Pedidos")
        self.setStyleSheet(style)

        self.pedidos_selecionados = []

        #Sempre que for iniciado criará um objeto data
        self.data = dict()

        voltar_btn = QPushButton(self)
        voltar_btn.setText('Voltar')
        voltar_btn.clicked.connect(self.goMainWindow)
        voltar_btn.setFocusPolicy(Qt.NoFocus)

        self.dadosDoPedido()
        self.resumoGeral()
        self.resumoDosItens()
        '''disableWidgetsCheckBox.toggled.connect(
            self.bottomLeftGroupBox.setHidden
        )
        '''

        topLayout = QHBoxLayout()
        topLayout.addWidget(voltar_btn)

        leftLayout = QVBoxLayout()
        leftLayout.addWidget(self.topLeftGroupBox, 100)
        #leftLayout.addWidget(self.bottomLeftGroupBox, 50)

        mainLayout = QGridLayout()
        mainLayout.addLayout(topLayout, 0, 0, 1, 2)
        mainLayout.addLayout(leftLayout, 1, 0)
        mainLayout.addWidget(self.topRightGroupBox, 1, 1)
        #mainLayout.addWidget(self.submitButtons, 3, 0, 1, 2)
        mainLayout.setRowStretch(1, 1)
        mainLayout.setColumnStretch(0, 1)
        mainLayout.setColumnStretch(1, 3)

        self.setLayout(mainLayout)

    def dadosDoPedido(self):
        self.topLeftGroupBox = QGroupBox("Dados do Pedido")

        verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)

        formLayout = QFormLayout()
        self.pedido = QLineEdit(self)
        self.pedido.setPlaceholderText("ex: 123.456")
        pedido_label = QLabel("Pedido:")

        self.n_simafic = QLineEdit(self)
        self.n_simafic.setPlaceholderText("ex: 08.04.02.507-6")
        n_simafic_label = QLabel("COD. SIMAFIC:")

        self.qtd_items = QLineEdit(self)
        self.qtd_items.setPlaceholderText("ex: 100")
        qtd_items_label = QLabel("Quantidade de Items:")
        '''ADD PEDIDO'''
        add_item = QPushButton('Adicionar Item')
        add_item.setObjectName('Add')
        add_item.setIcon(QIcon('assets/check_icon_blue2.png'))
        add_item.clicked.connect(self.add_items)
        '''CLEAR BUTTON CONFIG '''
        clear_btn = QPushButton('Limpar Campos')
        clear_btn.setObjectName('Yellow')
        clear_btn.setIcon(QIcon('assets/eraser.png'))
        clear_btn.clicked.connect(self.limpar_pedidos)

        formLayout.addRow(pedido_label, self.pedido)
        formLayout.addRow(n_simafic_label, self.n_simafic)
        formLayout.addRow(qtd_items_label, self.qtd_items)
        formLayout.addItem(verticalSpacer)
        formLayout.addRow(add_item)
        formLayout.addRow(clear_btn)
        '''checkBox = QCheckBox("Tri-state check box")
        checkBox.setTristate(True)
        checkBox.setCheckState(Qt.PartiallyChecked)'''

        #layout.addWidget(checkBox)
        '''formLayout.addWidget(add_item)
        formLayout.addWidget(clear_btn)'''

        layout = QVBoxLayout()
        layout.addLayout(formLayout)
        layout.addStretch(2)

        self.topLeftGroupBox.setLayout(layout)

    def resumoGeral(self):
        self.topRightGroupBox = QTabWidget()
        self.topRightGroupBox.setSizePolicy(QSizePolicy.Preferred,
                                            QSizePolicy.Ignored)

        #[First Tab] Create first tab
        verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)
        tab1ListaPedidos = QWidget()
        layout = QVBoxLayout(self)

        #[First Tab] - TextFields
        searchPedido = QLineEdit(self)
        searchPedido.setPlaceholderText("Filtrar por pedido: ")
        searchProduto = QLineEdit(self)
        searchProduto.setPlaceholderText("Filtrar por produto: ")

        #[First Tab] - Set TableView
        self.tabv_pedidos = QTableView()
        tab2hbox = QHBoxLayout()
        self.modelAllPedidos = services.get_all_pedidos_pandas()

        #[First Tab] - Set Filters
        self.proxyPedidoFilter = QSortFilterProxyModel()
        self.proxyPedidoFilter.setSourceModel(self.modelAllPedidos)
        self.proxyPedidoFilter.setFilterKeyColumn(0)
        self.proxyPedidoFilter.setSortCaseSensitivity(Qt.CaseSensitive)
        self.proxyPedidoFilterSecondLayer = QSortFilterProxyModel()
        self.proxyPedidoFilterSecondLayer.setSourceModel(
            self.proxyPedidoFilter)
        self.proxyPedidoFilterSecondLayer.setFilterKeyColumn(1)
        self.proxyPedidoFilterSecondLayer.setSortCaseSensitivity(
            Qt.CaseSensitive)

        self.tabv_pedidos.resizeColumnsToContents()
        self.tabv_pedidos.doubleClicked.connect(self.abrirItensDoPedido)
        self.tabv_pedidos.setSelectionMode(QAbstractItemView.SingleSelection)
        self.tabv_pedidos.setSelectionBehavior(QTableView.SelectRows)

        self.tabv_pedidos.setColumnWidth(2, 100)
        self.tabv_pedidos.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        tab2hbox.addWidget(self.tabv_pedidos)

        #[Connect Fields]
        searchProduto.textChanged.connect(
            lambda wildcard: self.proxyPedidoFilterSecondLayer.
            setFilterWildcard(wildcard))
        searchPedido.textChanged.connect(
            lambda wildcard: self.proxyPedidoFilter.setFilterWildcard(wildcard
                                                                      ))
        self.tabv_pedidos.setModel(self.proxyPedidoFilterSecondLayer)

        #[First Tab] - Set Layout

        tabItensValidos = QWidget()
        tableItensValidos = QTableView()
        #tableItensValidos.horizontalHeader().sectionClicked.connect(your_callable)

        model = services.get_simafic_as_dataframe()

        tableItensValidos.setModel(model)

        tab1hbox = QHBoxLayout()
        #tab1hbox.setContentsMargins(5, 5, 5, 5)
        tableItensValidos.resizeColumnsToContents()
        tab1hbox.addWidget(tableItensValidos)

        tabItensValidos.setLayout(tab1hbox)

        layoutText = QHBoxLayout()
        layoutText.addWidget(searchPedido)
        layoutText.addWidget(searchProduto)

        layout.addLayout(layoutText)
        layout.addWidget(
            QLabel(
                "Para abrir mais opções sobre um pedido, clique duas vezes no item."
            ))

        self.tabv_pedidos.verticalHeader()
        self.tabv_pedidos.resizeColumnsToContents()
        layout.addWidget(self.tabv_pedidos)
        tab1ListaPedidos.setLayout(layout)

        #TODO: Agrupar items por pedido (Drop Down) | Auto-resize nas cells da TView
        #TODO: Adicionar

        self.topRightGroupBox.addTab(tab1ListaPedidos, "&Lista de Pedidos: ")
        self.topRightGroupBox.addTab(tabItensValidos, "&Lista de Itens:")

    def resumoDosItens(self):
        self.bottomLeftGroupBox = QGroupBox("Lista de Itens do Pedido nº")
        self.listDataItens = list()
        self.listaViewItens = QListWidget()

        verticalSpacer = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)

        self.resumoLayout = QGridLayout()
        self.resumoLayout.addItem(verticalSpacer)
        self.bottomLeftGroupBox.setLayout(self.resumoLayout)

    def abrirItensDoPedido(self, item):
        print(
            "[abrirIItensDoPedido] O Item foi selecionado através de um click na: {} x linha: {}"
            .format(item.column(), item.row()))
        pedido = self.tabv_pedidos.model().index(item.row(), 0).data()
        simafic = self.tabv_pedidos.model().index(item.row(), 1).data()
        print(pedido, simafic)
        self.pedidos_selecionados = pedido

        try:
            pedido_item = services.get_pedido_x_item(pedido, simafic)
            print(pedido_item)
        except (ValidationError, DBPedidosException) as error:
            error_dialog = QErrorMessage()
            error_dialog.setWindowTitle(error.errors)
            error_dialog.setWindowIcon(QIcon(main_icon))
            error_dialog.showMessage(error.message)
            error_dialog.exec_()

        box = QMessageBox()
        box.setWindowIcon(QIcon(main_icon))
        box.setWindowTitle("Pedido {} selecionado.".format(
            pedido_item.id_pedido))
        box.setText("O que deseja fazer com o item {}?".format(
            pedido_item.cod_simafic))
        box.setStandardButtons(QMessageBox.Open | QMessageBox.Discard
                               | QMessageBox.Cancel)
        buttonOpen = box.button(QMessageBox.Open)
        buttonOpen.setText('Alterar')
        buttonDiscard = box.button(QMessageBox.Discard)
        buttonDiscard.setText('Excluir')
        buttonCancel = box.button(QMessageBox.Cancel)
        buttonCancel.setText('Cancelar')
        box.exec_()
        if box.clickedButton() == buttonOpen:
            print("Alterar...")
            self.cams = UpdateScreen(pedido_item, parent=self)
            self.cams.show()
        elif box.clickedButton() == buttonDiscard:
            print("Excluir ")
            self.confirmarExclusao(pedido_item)

        elif box.clickedButton() == buttonCancel:
            print("Cancelar ")

    def confirmarExclusao(self, pedido):
        box = QMessageBox()
        box.setWindowIcon(QIcon(main_icon))
        box.setWindowTitle('Confirmação de Exclusão')
        box.setText(
            "Tem certeza que deseja excluir o item: {} do pedido {}?".format(
                pedido.cod_simafic, pedido.id_pedido))
        box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        buttonYes = box.button(QMessageBox.Yes)
        buttonYes.setText("Excluir")
        buttonNo = box.button(QMessageBox.No)
        buttonNo.setText("Cancelar")
        box.exec_()

        if box.clickedButton() == buttonYes:
            self.excluirPedido(pedido)
            print("Pedido excluido")

        else:
            print("Exclusão cancelada")
            return

    def excluirPedido(self, pedido):
        try:
            services.excluirPedidoItem(pedido)
            self.update_model_tableview()

        except (ValidationError, DBPedidosException) as error:
            error_dialog = QErrorMessage()
            error_dialog.setWindowTitle(error.errors)
            error_dialog.setWindowIcon(QIcon(main_icon))
            error_dialog.showMessage(error.message)
            error_dialog.exec_()

    def add_items(self):
        try:
            pedido, n_simafic, qtd_items = self.pedido.text(
            ), self.n_simafic.text(), self.qtd_items.text()
            print("Add Pedido: {} {} {}".format(pedido, n_simafic, qtd_items))
            if services.validateCadastro(pedido, n_simafic, qtd_items):
                print("Add Pedido: {} {} {}".format(pedido, n_simafic,
                                                    qtd_items))
                mb = QMessageBox()
                mb.setIconPixmap(QPixmap('assets/check_icon_blue2'))
                mb.setWindowTitle("Sucesso")
                mb.setText(
                    'O pedido: {} foi criado com sucesso!'.format(pedido))
                services.add_pedido(pedido, n_simafic, qtd_items)
                mb.exec_()
                self.update_model_tableview()
                self.limpar_pedidos()

        except (ValidationError, DBPedidosException) as error:
            error_dialog = QErrorMessage()
            error_dialog.setWindowTitle(error.errors)
            error_dialog.setWindowIcon(QIcon(main_icon))
            error_dialog.showMessage(error.message)
            error_dialog.exec_()

        pass

    def update_model_tableview(self):
        self.modelAllPedidos.setDataFrame(services.get_all_pedidos_df())
        self.topRightGroupBox.setCurrentIndex(0)

    def limpar_pedidos(self):
        self.n_simafic.clear()
        self.qtd_items.clear()
        self.pedido.clear()

    def goMainWindow(self):
        self.cams = mainView
        self.cams.show()
        self.close()
Beispiel #30
0
class Reservations(QWidget):
    """
    Klasa odpowiedzialna za widget klienci
    """
    def __init__(self, parent, db):
        super(QWidget, self).__init__(parent)
        self.parent = parent
        self.btn_mod = QPushButton('Zmiana statusu')
        self.btn_usun = QPushButton('Usuń')
        self.btn_dodaj = QPushButton('Dodaj')
        self.lbl_klient_ = QLabel('')
        self.lbl_usluga_ = QLabel('')
        self.lbl_termin_ = QDateTimeEdit()
        self.gb_layout = QVBoxLayout()
        self.kalendarz = QCalendarWidget()
        self.view_u = QTableView()
        self.view_k = QTableView()
        self.view_p = QTableView()
        self.view = QTableView()
        self.proxy_u = QSortFilterProxyModel(self)
        self.proxy_k = QSortFilterProxyModel(self)
        self.proxy_p = QSortFilterProxyModel(self)
        self.proxy = QSortFilterProxyModel(self)
        self.id_klient = -1
        self.id_usluga = -1
        self.id_pracownik = -1
        self.id_rezerwacje = -1
        self.data = None
        self.data_do = None
        self.dzien_tyg = 0
        self.czas = []

        # Lista składana przycisków godzin
        self.btn_godz = [QPushButton(str(i + 1)) for i in range(16)]

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

        self.initUI()

    def initUI(self):
        """
        Inicjuje UI
        """
        self.view_u.setObjectName('Usługi')
        self.view_k.setObjectName('Klienci')
        self.view_p.setObjectName('Pracownicy')
        self.view.setObjectName('Rezerwacje')
        self.table_init_u()
        self.table_init_k()
        self.table_init_p()
        self.table_init()
        self.btn_mod.setDisabled(True)
        self.btn_usun.setDisabled(True)
        self.btn_dodaj.setDisabled(True)

        # Tworzenie kontrolek
        lbl_wysz_u = QLabel('Wyszukaj usługę:')
        lbl_wysz_k = QLabel('Wyszukaj klienta:')
        lbl_wysz_p = QLabel('Wyszukaj pracownika:')
        txt_wysz_u = QLineEdit(self)
        txt_wysz_k = QLineEdit(self)
        txt_wysz_p = QLineEdit(self)
        lbl_klient = QLabel('Klient:')
        lbl_usluga = QLabel('Usługa:')
        lbl_termin = QLabel('Termin:')

        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.kalendarz.sizePolicy().hasHeightForWidth())
        self.kalendarz.setSizePolicy(sizePolicy)

        # Tworzenie widoków
        centralbox = QHBoxLayout()
        hbox_wysz_u = QHBoxLayout()
        hbox_wysz_k = QHBoxLayout()
        hbox_wysz_p = QHBoxLayout()
        vbox_u = QVBoxLayout()
        vbox_k = QVBoxLayout()
        vbox_p = QVBoxLayout()
        vbox_right = QVBoxLayout()
        hbox_btn = QHBoxLayout()
        hbox_k = QHBoxLayout()
        hbox_u = QHBoxLayout()
        hbox_t = QHBoxLayout()
        vbox_cal = QVBoxLayout()
        groupbox = QGroupBox('Godziny:')
        groupbox.setLayout(self.gb_layout)
        hbox_left = QHBoxLayout()

        # Metody
        self.lbl_termin_.setCalendarWidget(self.kalendarz)
        self.lbl_termin_.setDate(self.kalendarz.selectedDate())
        self.dzien_tyg = self.kalendarz.selectedDate().dayOfWeek()
        txt_wysz_u.textChanged.connect(self.searching_u)
        txt_wysz_k.textChanged.connect(self.searching_k)
        txt_wysz_p.textChanged.connect(self.searching_p)
        self.view_k.clicked.connect(lambda: self.clicked_table(self.view_k))
        self.view_p.clicked.connect(lambda: self.clicked_table(self.view_p))
        self.view_u.clicked.connect(lambda: self.clicked_table(self.view_u))
        self.view.clicked.connect(lambda: self.clicked_table(self.view))
        self.kalendarz.clicked.connect(self.show_data)
        self.btn_dodaj.clicked.connect(self.add)
        self.btn_mod.clicked.connect(self.modify)
        self.btn_usun.clicked.connect(self.remove)

        # Ustawianie widoków
        hbox_wysz_k.addWidget(lbl_wysz_k)
        hbox_wysz_k.addWidget(txt_wysz_k)
        hbox_wysz_p.addWidget(lbl_wysz_p)
        hbox_wysz_p.addWidget(txt_wysz_p)
        hbox_wysz_u.addWidget(lbl_wysz_u)
        hbox_wysz_u.addWidget(txt_wysz_u)
        vbox_u.addLayout(hbox_wysz_u)
        vbox_u.addWidget(self.view_u)
        vbox_k.addLayout(hbox_wysz_k)
        vbox_k.addWidget(self.view_k)
        vbox_p.addLayout(hbox_wysz_p)
        vbox_p.addWidget(self.view_p)
        vbox_right.addLayout(vbox_p)
        vbox_right.addLayout(vbox_u)
        vbox_right.addLayout(vbox_k)
        hbox_btn.addWidget(self.btn_usun)
        hbox_btn.addWidget(self.btn_mod)
        hbox_k.addWidget(lbl_klient)
        hbox_k.addWidget(self.lbl_klient_)
        hbox_u.addWidget(lbl_usluga)
        hbox_u.addWidget(self.lbl_usluga_)
        hbox_t.addWidget(lbl_termin)
        hbox_t.addWidget(self.lbl_termin_)
        vbox_cal.addWidget(self.kalendarz)
        vbox_cal.addLayout(hbox_u)
        vbox_cal.addLayout(hbox_t)
        vbox_cal.addLayout(hbox_k)
        self.view.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum))
        vbox_cal.addWidget(self.view)
        vbox_cal.addLayout(hbox_btn)
        vbox_cal.addWidget(self.btn_dodaj)
        hbox_left.addLayout(vbox_cal)
        hbox_left.addWidget(groupbox)
        centralbox.addLayout(hbox_left)
        centralbox.addLayout(vbox_right)

        self.setLayout(centralbox)
        self.show()

    def show_data(self):
        self.lbl_termin_.setDate(self.kalendarz.selectedDate())
        self.dzien_tyg = self.kalendarz.selectedDate().dayOfWeek()
        self.clicked_table(self.view_p)

    def table_init_u(self):
        """
        Inicjuje wygląd tabeli usługi
        """
        # self.model_u.setTable('uslugi')
        query = QSqlQuery(
            'SELECT uslugi.uslugi_id, uslugi.nazwa, uslugi.cena, date_format(uslugi.czas, "%H:%i") AS czas FROM uslugi NATURAL JOIN uzytkownik_usluga WHERE uzytkownik_usluga.uzytkownik_id = '
            + str(self.id_pracownik) + ';')
        self.model_u.setQuery(query)
        # self.model_u.select()

        self.proxy_u.setSourceModel(self.model_u)

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

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

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

    def table_init_k(self):
        """
        Inicjuje wygląd tabeli klienta
        """
        self.model_k.setTable('klienci')
        query = QSqlQuery(
            'SELECT klienci_id, imie, nazwisko, email, telefon, ulica, numer_mieszkania, miejscowosc, poczta FROM '
            'klienci;')
        self.model_k.setQuery(query)
        # self.model_k.select()

        self.proxy_k.setSourceModel(self.model_k)

        naglowki = {
            'klienci_id': 'ID',
            'imie': 'Imię',
            'nazwisko': 'Nazwisko',
            "email": 'Email',
            'telefon': 'Telefon',
            'ulica': 'Ulica',
            'numer_mieszkania': 'Numer mieszkania',
            'miejscowosc': 'Miejscowosc',
            'poczta': 'Kod pocztowy',
        }
        # Ustawianie nagłówków
        ilosc_kolumn = self.model_k.columnCount()
        for i in range(ilosc_kolumn):
            nazwa_kolumn = self.model_k.headerData(i, Qt.Horizontal)
            self.model_k.setHeaderData(i, Qt.Horizontal,
                                       naglowki[nazwa_kolumn])

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

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

    def table_init_p(self):
        """
        Inicjuje wygląd tabeli pracownik
        """
        self.model_p.setTable('uzytkownik')
        query = QSqlQuery(
            'SELECT uzytkownik_id,  imie, nazwisko FROM uzytkownik WHERE '
            'pracownik = 1;')
        self.model_p.setQuery(query)
        # self.model_p.select()

        self.proxy_p.setSourceModel(self.model_p)

        naglowki = {
            'uzytkownik_id': 'ID',
            'imie': 'Imię',
            "nazwisko": 'Nazwisko',
        }
        # Ustawianie nagłówków
        ilosc_kolumn = self.model_p.columnCount()
        for i in range(ilosc_kolumn):
            nazwa_kolumn = self.model_p.headerData(i, Qt.Horizontal)
            self.model_p.setHeaderData(i, Qt.Horizontal,
                                       naglowki[nazwa_kolumn])

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

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

    def table_init(self):
        """
        Inicjuje wygląd tabeli
        """
        query = QSqlQuery(
            'SELECT wizyty.wizyty_id, CONCAT(klienci.imie, " ", klienci.nazwisko) AS klient, uslugi.nazwa, '
            'wizyty.rezerwacja_od, wizyty.rezerwacja_do, wizyty.status FROM klienci, uslugi NATURAL JOIN wizyty WHERE wizyty.rezerwacja_od > CURRENT_TIMESTAMP AND wizyty.uzytkownik_id = '
            + str(self.id_pracownik) + ';')
        self.model.setQuery(query)
        self.proxy.setSourceModel(self.model)

        naglowki = {
            'wizyty_id': 'ID',
            'klient': 'Klient',
            'nazwa': 'Usługa',
            'rezerwacja_od': 'Rezerwacja od',
            "rezerwacja_do": 'Rezerwacja do',
            'status': 'Status rezerwacji'
        }
        # 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(4, Qt.AscendingOrder)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)

    def clicked_table(self, view):
        """
        Metoda edytująca zaznaczone wiersze - Wstawia wartości z wierszy w odpowiednie pola
        """
        index = (view.selectionModel().currentIndex())
        if view.objectName() == 'Klienci':
            self.id_klient = index.sibling(index.row(), 0).data()
            self.lbl_klient_.setText('<b>' +
                                     index.sibling(index.row(), 1).data() +
                                     ' ' +
                                     index.sibling(index.row(), 2).data() +
                                     '</b>')
        elif view.objectName() == 'Usługi':
            self.id_usluga = index.sibling(index.row(), 0).data()
            self.lbl_usluga_.setText('<b>' +
                                     index.sibling(index.row(), 1).data() +
                                     '</b>')
            self.data_do = index.sibling(index.row(), 3).data()
        elif view.objectName() == 'Rezerwacje':
            self.id_rezerwacje = index.sibling(index.row(), 0).data()
            if self.id_rezerwacje > 0:
                self.btn_mod.setEnabled(True)
                self.btn_usun.setEnabled(True)
        elif view.objectName() == 'Pracownicy':
            self.id_pracownik = index.sibling(index.row(), 0).data()
            self.czas = []
            for i in reversed(range(self.gb_layout.count())):
                self.gb_layout.itemAt(i).widget().setParent(None)
            czas = datetime.datetime(2000, 1, 1, 8, 0)
            dzien = {
                1: ('pon_od', 'pon_do'),
                2: ('wt_od', 'wt_do'),
                3: ('sr_od', 'sr_do'),
                4: ('czw_od', 'czw_do'),
                5: ('pt_od', 'pt_do'),
                6: ('sob_od', 'sob_do'),
                7: ('', '')
            }
            query = 'SELECT date_format({}, "%H") AS g_start, date_format({}, "%H") AS g_stop FROM godziny WHERE ' \
                    'uzytkownik_id = {};'.format(dzien[self.dzien_tyg][0], dzien[self.dzien_tyg][1], self.id_pracownik)
            wynik = query_to_db(query)
            if wynik:
                godzina_stop = (int(wynik[1]) - int(wynik[0])) * 2
                godzina = int(wynik[0])
                for btn in self.btn_godz:
                    btn.setEnabled(True)
            else:
                godzina_stop = 0
                godzina = 1
                for btn in self.btn_godz:
                    btn.setDisabled(True)
            minuta = 0
            czas = datetime.time(godzina, minuta)
            for i in range(godzina_stop):
                self.btn_godz[i].setText(czas.strftime("%H:%M"))
                self.czas.append(czas)
                self.btn_godz[i].setObjectName(str(i))
                self.gb_layout.addWidget(self.btn_godz[i])
                if i % 2 != 0:
                    godzina += 1
                    minuta = 0
                else:
                    minuta = 30
                czas = datetime.time(godzina, minuta)
            QMetaObject.connectSlotsByName(self)

            # Czyszczenie, odświeżanie
            self.refresh()
            query = QSqlQuery(
                'SELECT uslugi.uslugi_id, uslugi.nazwa, uslugi.cena, date_format(uslugi.czas, "%H:%i") AS czas FROM uslugi NATURAL JOIN uzytkownik_usluga WHERE uzytkownik_usluga.uzytkownik_id = '
                + str(self.id_pracownik) + ';')
            self.model_u.setQuery(query)
            self.lbl_klient_.setText('')
            self.lbl_usluga_.setText('')

        if self.id_klient > 0 and self.id_pracownik > 0 and self.id_usluga > 0:
            self.btn_dodaj.setEnabled(True)

    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 self.id_klient < 0 and self.id_pracownik < 0 and self.id_usluga < 0 and self.data is None:
            msg = QMessageBox(self)
            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')
                query_to_db(q, val)
            else:
                print('Transakcja')
                return transaction_to_db(q)

            return True

    def refresh(self):
        """
        Odświeża widok tabeli rezerwacji
        """
        # Odświeżanie widoku tabeli
        query = QSqlQuery(
            'SELECT wizyty.wizyty_id, CONCAT(klienci.imie, " ", klienci.nazwisko) AS klient, uslugi.nazwa, '
            'wizyty.rezerwacja_od, wizyty.rezerwacja_do, wizyty.status FROM wizyty,klienci,uslugi WHERE wizyty.klienci_id= klienci.klienci_id AND wizyty.uslugi_id = uslugi.uslugi_id AND wizyty.rezerwacja_od > CURRENT_TIMESTAMP AND wizyty.uzytkownik_id = '
            + str(self.id_pracownik) + ';')
        self.model.setQuery(query)
        self.view.reset()

    def add(self):
        """
        Dodaje rezerwację do bazy danych i odświeża widok.
        """
        tekst = 'Nie wprowadzono wszystkich danych'
        self.data = self.lbl_termin_.dateTime().toString(Qt.ISODate)
        self.data_do = datetime.datetime.fromisoformat(
            self.data) + datetime.timedelta(
                hours=datetime.time.fromisoformat(self.data_do).hour,
                minutes=datetime.time.fromisoformat(self.data_do).minute)
        # Dodanie nowego użytkownika
        query = 'INSERT INTO wizyty (klienci_id, uslugi_id, uzytkownik_id, rezerwacja_od, rezerwacja_do, ' \
                'status) VALUES (%s, %s, %s, %s, %s, %s);'
        val = (self.id_klient, self.id_usluga, self.id_pracownik, self.data,
               str(self.data_do.isoformat()), 'oczekuje')
        print(val)

        if self.if_checked(tekst, query, val):
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Information)
            msg.setText('Rezerwacja została dodana do bazy danych')
            msg.setWindowTitle("Dodano nową rezerwację")
            msg.exec_()
            self.refresh()

    def modify(self):
        """
        Zmienia status rezerwacji i odświeża widok.
        """
        tekst = 'Nie wprowadzono wszystkich danych'

        items = ('Oczekuje', 'Wykonana', 'Rezygnacja')
        item, ok = QInputDialog.getItem(self, "Wybierz status",
                                        "Wybierz nowy status rezerwacji",
                                        items, 0, False)

        if ok and item:
            # Zmodyfikowanie statusu
            query = 'UPDATE wizyty SET status = %s WHERE wizyty_id = %s;'
            val = (item.lower(), self.id_rezerwacje)

            if self.if_checked(tekst, query, val):
                msg = QMessageBox(self)
                msg.setIcon(QMessageBox.Information)
                msg.setText('Status rezerwacji został zmodyfikowany')
                msg.setWindowTitle("Zmodyfikowano status")
                msg.exec_()
                self.refresh()

    def remove(self):
        """
        Usuwa rezerwację z bazy danych
        """
        test = 'Błąd! Nie można usunąć danej rezerwacji!'
        query = 'DELETE FROM wizyty WHERE wizyty_id = %s'
        val = (self.id_rezerwacje, )
        ret = QMessageBox.question(
            self, 'Usuwanie rezerwacji',
            "Czy na pewno chcesz usunąć daną rezerwację klienta?",
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if ret == QMessageBox.Yes:
            if self.if_checked(test, query, val):
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Information)
                msg.setText('Rezerwacja została usunięta')
                msg.setWindowTitle("Usunięto")
                msg.exec_()

                self.refresh()

    @pyqtSlot()
    def on_0_clicked(self):
        self.lbl_termin_.setTime(self.czas[0])

    @pyqtSlot()
    def on_1_clicked(self):
        self.lbl_termin_.setTime(self.czas[1])

    @pyqtSlot()
    def on_2_clicked(self):
        self.lbl_termin_.setTime(self.czas[2])

    @pyqtSlot()
    def on_3_clicked(self):
        self.lbl_termin_.setTime(self.czas[3])

    @pyqtSlot()
    def on_4_clicked(self):
        self.lbl_termin_.setTime(self.czas[4])

    @pyqtSlot()
    def on_5_clicked(self):
        self.lbl_termin_.setTime(self.czas[5])

    @pyqtSlot()
    def on_6_clicked(self):
        self.lbl_termin_.setTime(self.czas[6])

    @pyqtSlot()
    def on_7_clicked(self):
        self.lbl_termin_.setTime(self.czas[7])

    @pyqtSlot()
    def on_8_clicked(self):
        self.lbl_termin_.setTime(self.czas[8])

    @pyqtSlot()
    def on_9_clicked(self):
        self.lbl_termin_.setTime(self.czas[9])

    @pyqtSlot()
    def on_10_clicked(self):
        self.lbl_termin_.setTime(self.czas[10])

    @pyqtSlot()
    def on_11_clicked(self):
        self.lbl_termin_.setTime(self.czas[11])

    @pyqtSlot()
    def on_12_clicked(self):
        self.lbl_termin_.setTime(self.czas[12])

    @pyqtSlot()
    def on_13_clicked(self):
        self.lbl_termin_.setTime(self.czas[13])

    @pyqtSlot()
    def on_14_clicked(self):
        self.lbl_termin_.setTime(self.czas[14])

    @pyqtSlot()
    def on_15_clicked(self):
        self.lbl_termin_.setTime(self.czas[15])

    @pyqtSlot(str)
    def searching_u(self, text):
        """
        Wyszukuje po wszystkich kolumnach tabeli
        :param text:
        """
        search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
        self.proxy_u.setFilterRegExp(search)
        # Odpowiedzialne za kolumnę, po której filtruje
        self.proxy_u.setFilterKeyColumn(-1)

    @pyqtSlot(str)
    def searching_k(self, text):
        """
        Wyszukuje po wszystkich kolumnach tabeli
        :param text:
        """
        search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
        self.proxy_k.setFilterRegExp(search)
        # Odpowiedzialne za kolumnę, po której filtruje
        self.proxy_k.setFilterKeyColumn(-1)

    @pyqtSlot(str)
    def searching_p(self, text):
        """
        Wyszukuje po wszystkich kolumnach tabeli
        :param text:
        """
        search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
        self.proxy_p.setFilterRegExp(search)
        # Odpowiedzialne za kolumnę, po której filtruje
        self.proxy_p.setFilterKeyColumn(-1)
Beispiel #31
0
    def insertRows(self, position, rows, parent=QModelIndex()):

        self.beginInsertRows(parent, position, position + rows - 1)
        self.endInsertRows()
        return True


if __name__ == '__main__':
    app = QApplication(sys.argv)

    # How to apply sorting in a QTableView

    # Step 1: create the model for the QTableView
    tablemodel = SortingTableModel()
    tablemodel.insertRows(len(DATA), 1)

    # Step 2: create the sorter model
    sortermodel = QSortFilterProxyModel()
    sortermodel.setSourceModel(tablemodel)
    sortermodel.setFilterKeyColumn(3)

    # Step 3: setup the QTableView to enable sorting
    tableview = QTableView()
    tableview.setWindowTitle('Sorting QTableView')
    tableview.setModel(sortermodel)
    tableview.setSortingEnabled(True)
    tableview.sortByColumn(1, Qt.AscendingOrder)  # sorting via 'Fruit' header
    tableview.show()

    sys.exit(app.exec())
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('')

        self.__loadRecent()

    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)
        header.setSectionsClickable(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.__saveRecent()

            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.__saveRecent()

                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")

    def __loadRecent(self):
        """
        Private method to load the recently used file names.
        """
        Preferences.Prefs.rsettings.sync()

        # load recently used file names
        self.fnHistory = []
        self.fnHistory.append('')
        rs = Preferences.Prefs.rsettings.value(recentNameBreakpointFiles)
        if rs is not None:
            recent = [
                f for f in Preferences.toList(rs) if QFileInfo(f).exists()
            ]
            self.fnHistory.extend(
                recent[:Preferences.getDebugger("RecentNumber")])

        # load recently entered condition expressions
        self.condHistory = []
        rs = Preferences.Prefs.rsettings.value(recentNameBreakpointConditions)
        if rs is not None:
            self.condHistory = Preferences.toList(
                rs)[:Preferences.getDebugger("RecentNumber")]

    def __saveRecent(self):
        """
        Private method to save the list of recently used file names.
        """
        recent = [f for f in self.fnHistory if f]
        Preferences.Prefs.rsettings.setValue(recentNameBreakpointFiles, recent)
        Preferences.Prefs.rsettings.setValue(recentNameBreakpointConditions,
                                             self.condHistory)
        Preferences.Prefs.rsettings.sync()
Beispiel #33
0
class OWGeneSets(OWWidget):
    name = "Gene Sets"
    description = ""
    icon = "icons/OWGeneSets.svg"
    priority = 9
    want_main_area = True

    # settings
    selected_organism = Setting(0)
    auto_commit = Setting(True)
    auto_apply = Setting(True)

    gene_col_index = ContextSetting(0)
    use_attr_names = ContextSetting(False)

    class Inputs:
        genes = Input("Genes", Table)

    class Outputs:
        matched_genes = Output("Matched Genes", Table)

    class Information(OWWidget.Information):
        pass

    class Error(OWWidget.Error):
        cant_reach_host = Msg("Host orange.biolab.si is unreachable.")
        cant_load_organisms = Msg(
            "No available organisms, please check your connection.")

    def __init__(self):
        super().__init__()

        # commit
        self.commit_button = None

        # progress bar
        self.progress_bar = None
        self.progress_bar_iterations = None

        # data
        self.input_data = None
        self.tax_id = None
        self.input_genes = None
        self.mapped_genes = None
        self.organisms = list()
        self.input_info = None

        self.column_candidates = []

        # filter
        self.lineEdit_filter = None
        self.search_pattern = ''
        self.organism_select_combobox = None

        # data model view
        self.data_view = None
        self.data_model = None

        # gene matcher NCBI
        self.gene_matcher = None

        # filter proxy model
        self.filter_proxy_model = None

        # hierarchy widget
        self.hierarchy_widget = None
        self.hierarchy_state = None

        # input options
        self.gene_columns = None
        self.gene_column_combobox = None
        self.attr_names_checkbox = None

        # threads
        self.threadpool = QThreadPool(self)
        self.workers = None

        # gui
        self.setup_gui()
        self._get_available_organisms()

        # self.handle_input(self.input_genes)
        # self.on_organism_change()

    def _progress_advance(self):
        # GUI should be updated in main thread. That's why we are calling advance method here
        if self.progress_bar:
            self.progress_bar.advance()

    def _get_selected_organism(self):
        return self.organisms[self.selected_organism]

    def _get_available_organisms(self):
        available_organism = sorted([(tax_id, taxonomy.name(tax_id))
                                     for tax_id in taxonomy.common_taxids()],
                                    key=lambda x: x[1])

        self.organisms = [tax_id[0] for tax_id in available_organism]

        self.organism_select_combobox.addItems(
            [tax_id[1] for tax_id in available_organism])

    def _gene_names_from_table(self):
        """ Extract and return gene names from `Orange.data.Table`.
        """
        self.input_genes = []
        if self.input_data:
            if self.use_attr_names:
                self.input_genes = [
                    str(attr.name).strip()
                    for attr in self.input_data.domain.attributes
                ]
            elif self.gene_columns:
                column = self.gene_columns[self.gene_col_index]
                self.input_genes = [
                    str(e[column]) for e in self.input_data
                    if not np.isnan(e[column])
                ]

    def _update_gene_matcher(self):
        self._gene_names_from_table()
        if self.gene_matcher:
            self.gene_matcher.genes = self.input_genes
            self.gene_matcher.organism = self._get_selected_organism()

    def on_input_option_change(self):
        self._update_gene_matcher()
        self.match_genes()

    @Inputs.genes
    def handle_input(self, data):
        if data:
            self.input_data = data
            self.gene_matcher = gene.GeneMatcher(self._get_selected_organism())

            self.gene_column_combobox.clear()
            self.column_candidates = [
                attr for attr in data.domain.variables + data.domain.metas
                if isinstance(attr, (StringVariable, DiscreteVariable))
            ]

            for var in self.column_candidates:
                self.gene_column_combobox.addItem(*attributeItem(var))

            self.tax_id = str(data_hints.get_hint(self.input_data, TAX_ID))
            self.use_attr_names = data_hints.get_hint(
                self.input_data, GENE_NAME, default=self.use_attr_names)
            self.gene_col_index = min(self.gene_col_index,
                                      len(self.column_candidates) - 1)

            if self.tax_id in self.organisms:
                self.selected_organism = self.organisms.index(self.tax_id)

        self.on_input_option_change()

    def update_info_box(self):
        info_string = ''
        if self.input_genes:
            info_string += '{} unique gene names on input.\n'.format(
                len(self.input_genes))
            mapped = self.gene_matcher.get_known_genes()
            if mapped:
                ratio = (len(mapped) / len(self.input_genes)) * 100
                info_string += '{} ({:.2f}%) gene names matched.\n'.format(
                    len(mapped), ratio)
        else:
            info_string += 'No genes on input.\n'

        self.input_info.setText(info_string)

    def match_genes(self):
        if self.gene_matcher:
            # init progress bar
            self.progress_bar = ProgressBar(self,
                                            iterations=len(
                                                self.gene_matcher.genes))
            # status message
            self.setStatusMessage('gene matcher running')

            worker = Worker(self.gene_matcher.run_matcher,
                            progress_callback=True)
            worker.signals.progress.connect(self._progress_advance)
            worker.signals.finished.connect(self.handle_matcher_results)

            # move download process to worker thread
            self.threadpool.start(worker)

    def handle_matcher_results(self):
        assert threading.current_thread() == threading.main_thread()
        if self.progress_bar:
            self.progress_bar.finish()
            self.setStatusMessage('')

        if self.gene_matcher.map_input_to_ncbi():
            self.download_gene_sets()
            self.update_info_box()
        else:
            # reset gene sets
            self.init_item_model()
            self.update_info_box()

    def on_gene_sets_download(self, result):
        # make sure this happens in the main thread.
        # Qt insists that widgets be created within the GUI(main) thread.
        assert threading.current_thread() == threading.main_thread()
        self.progress_bar.finish()
        self.setStatusMessage('')

        tax_id, sets = result
        self.set_hierarchy_model(self.hierarchy_widget,
                                 *hierarchy_tree(tax_id, sets))

        self.organism_select_combobox.setEnabled(True)  # re-enable combobox

        self.update_info_box()
        self.mapped_genes = self.gene_matcher.map_input_to_ncbi()
        self.workers = defaultdict(list)
        self.progress_bar_iterations = dict()

        for selected_hierarchy in [*self.get_hierarchies()]:
            gene_sets = geneset.load_gene_sets(selected_hierarchy)
            worker = Worker(get_collections,
                            gene_sets,
                            self.mapped_genes,
                            progress_callback=True,
                            partial_result=True)
            worker.signals.error.connect(self.handle_error)
            worker.signals.finished.connect(self.handle_worker_finished)
            worker.signals.progress.connect(self._progress_advance)
            worker.signals.partial_result.connect(self.populate_data_model)
            worker.setAutoDelete(False)

            self.workers[selected_hierarchy] = worker
            self.progress_bar_iterations[selected_hierarchy] = len(gene_sets)

    def handle_worker_finished(self):
        # We check if all workers have completed. If not, continue
        # dirty hax, is this ok?
        if self.progress_bar and self.progress_bar.widget.progressBarValue == 100:
            self.progress_bar.finish()
            self.setStatusMessage('')
            self.hierarchy_widget.setDisabled(False)

            # adjust column width
            for i in range(len(DATA_HEADER_LABELS) - 1):

                self.data_view.resizeColumnToContents(i)

            self.filter_proxy_model.setSourceModel(self.data_model)

    def populate_data_model(self, partial_result):
        assert threading.current_thread() == threading.main_thread()

        if partial_result:
            self.data_model.appendRow(partial_result)

    def set_hierarchy_model(self, model, tax_id, sets):
        # TODO: maybe optimize this code?
        for key, value in sets.items():
            item = QTreeWidgetItem(model, [key])
            item.setFlags(item.flags()
                          & (Qt.ItemIsUserCheckable | ~Qt.ItemIsSelectable
                             | Qt.ItemIsEnabled))
            # item.setDisabled(True)
            item.setData(0, Qt.CheckStateRole, Qt.Unchecked)
            item.setExpanded(True)
            item.tax_id = tax_id
            item.hierarchy = key

            if value:
                item.setFlags(item.flags() | Qt.ItemIsTristate)
                self.set_hierarchy_model(item, tax_id, value)
            else:
                if item.parent():
                    item.hierarchy = ((item.parent().hierarchy, key), tax_id)

            if not item.childCount() and not item.parent():
                item.hierarchy = ((key, ), tax_id)

    def download_gene_sets(self):
        tax_id = self._get_selected_organism()

        self.Error.clear()
        # do not allow user to change organism when download task is running
        self.organism_select_combobox.setEnabled(False)
        # reset hierarchy widget state
        self.hierarchy_widget.clear()
        # clear data view
        self.init_item_model()

        # get all gene sets for selected organism
        gene_sets = geneset.list_all(organism=tax_id)
        # init progress bar
        self.progress_bar = ProgressBar(self, iterations=len(gene_sets) * 100)
        # status message
        self.setStatusMessage('downloading sets')

        worker = Worker(download_gene_sets, gene_sets, progress_callback=True)
        worker.signals.progress.connect(self._progress_advance)
        worker.signals.result.connect(self.on_gene_sets_download)
        worker.signals.error.connect(self.handle_error)

        # move download process to worker thread
        self.threadpool.start(worker)

    def display_gene_sets(self):
        self.init_item_model()
        self.hierarchy_widget.setDisabled(True)

        only_selected_hier = [*self.get_hierarchies(only_selected=True)]

        # init progress bar
        iterations = sum([
            self.progress_bar_iterations[hier] for hier in only_selected_hier
        ])
        self.progress_bar = ProgressBar(self, iterations=iterations)
        self.setStatusMessage('displaying gene sets')

        if not only_selected_hier:
            self.progress_bar.finish()
            self.setStatusMessage('')
            self.hierarchy_widget.setDisabled(False)
            return

        for selected_hierarchy in only_selected_hier:
            self.threadpool.start(self.workers[selected_hierarchy])

    def handle_error(self, ex):
        self.progress_bar.finish()
        self.setStatusMessage('')

        if isinstance(ex, ConnectionError):
            self.organism_select_combobox.setEnabled(
                True)  # re-enable combobox
            self.Error.cant_reach_host()

        print(ex)

    def get_hierarchies(self, **kwargs):
        """ return selected hierarchy
        """
        only_selected = kwargs.get('only_selected', None)

        sets_to_display = list()

        if only_selected:
            iterator = QTreeWidgetItemIterator(self.hierarchy_widget,
                                               QTreeWidgetItemIterator.Checked)
        else:
            iterator = QTreeWidgetItemIterator(self.hierarchy_widget)

        while iterator.value():
            # note: if hierarchy value is not a tuple, then this is just top level qTreeWidgetItem that
            #       holds subcategories. We don't want to display all sets from category
            if type(iterator.value().hierarchy) is not str:

                if not only_selected:
                    sets_to_display.append(iterator.value().hierarchy)
                else:
                    if not iterator.value().isDisabled():
                        sets_to_display.append(iterator.value().hierarchy)

            iterator += 1

        return sets_to_display

    def commit(self):
        selection_model = self.data_view.selectionModel()

        if selection_model:
            # genes_from_set = selection_model.selectedRows(GENES)
            matched_genes = selection_model.selectedRows(MATCHED)

            if matched_genes and self.input_genes:
                genes = [
                    model_index.data(Qt.UserRole)
                    for model_index in matched_genes
                ]
                output_genes = [
                    gene_name for gene_name in list(set.union(*genes))
                ]
                input_to_ncbi = self.gene_matcher.map_input_to_ncbi()
                ncbi_to_input = {
                    ncbi_id: input_name
                    for input_name, ncbi_id in
                    self.gene_matcher.map_input_to_ncbi().items()
                }

                if self.use_attr_names:
                    selected = [
                        self.input_data.domain[ncbi_to_input[output_gene]]
                        for output_gene in output_genes
                    ]
                    domain = Domain(selected,
                                    self.input_data.domain.class_vars,
                                    self.input_data.domain.metas)
                    new_data = self.input_data.from_table(
                        domain, self.input_data)
                    self.Outputs.matched_genes.send(new_data)

                elif self.column_candidates:
                    column = self.column_candidates[self.gene_col_index]
                    selected_rows = []

                    for row_index, row in enumerate(self.input_data):
                        if str(row[column]) in input_to_ncbi.keys(
                        ) and input_to_ncbi[str(row[column])] in output_genes:
                            selected_rows.append(row_index)
                    if selected_rows:
                        selected = self.input_data[selected_rows]
                    else:
                        selected = None
                    self.Outputs.matched_genes.send(selected)

    def setup_gui(self):
        # control area
        info_box = vBox(self.controlArea, 'Input info')
        self.input_info = widgetLabel(info_box)

        organism_box = vBox(self.controlArea, 'Organisms')
        self.organism_select_combobox = comboBox(
            organism_box,
            self,
            'selected_organism',
            callback=self.on_input_option_change)

        # Selection of genes attribute
        box = widgetBox(self.controlArea, 'Gene attribute')
        self.gene_columns = itemmodels.VariableListModel(parent=self)
        self.gene_column_combobox = comboBox(
            box, self, 'gene_col_index', callback=self.on_input_option_change)
        self.gene_column_combobox.setModel(self.gene_columns)

        self.attr_names_checkbox = checkBox(
            box,
            self,
            'use_attr_names',
            'Use attribute names',
            disables=[(-1, self.gene_column_combobox)],
            callback=self.on_input_option_change)

        self.gene_column_combobox.setDisabled(bool(self.use_attr_names))

        hierarchy_box = widgetBox(self.controlArea, "Entity Sets")
        self.hierarchy_widget = QTreeWidget(self)
        self.hierarchy_widget.setEditTriggers(QTreeView.NoEditTriggers)
        self.hierarchy_widget.setHeaderLabels(HIERARCHY_HEADER_LABELS)
        self.hierarchy_widget.itemClicked.connect(self.display_gene_sets)
        hierarchy_box.layout().addWidget(self.hierarchy_widget)

        self.commit_button = auto_commit(self.controlArea,
                                         self,
                                         "auto_commit",
                                         "&Commit",
                                         box=False)

        # rubber(self.controlArea)

        # main area
        self.filter_proxy_model = QSortFilterProxyModel(self.data_view)
        self.filter_proxy_model.setFilterKeyColumn(3)

        self.data_view = QTreeView()
        self.data_view.setModel(self.filter_proxy_model)
        self.data_view.setAlternatingRowColors(True)
        self.data_view.setSortingEnabled(True)
        self.data_view.setSelectionMode(QTreeView.ExtendedSelection)
        self.data_view.setEditTriggers(QTreeView.NoEditTriggers)
        self.data_view.viewport().setMouseTracking(True)
        self.data_view.setItemDelegateForColumn(
            TERM, LinkStyledItemDelegate(self.data_view))

        self.data_view.selectionModel().selectionChanged.connect(self.commit)

        self.lineEdit_filter = lineEdit(self.mainArea, self, 'search_pattern',
                                        'Filter gene sets:')
        self.lineEdit_filter.setPlaceholderText('search pattern ...')
        self.lineEdit_filter.textChanged.connect(
            self.filter_proxy_model.setFilterRegExp)

        self.mainArea.layout().addWidget(self.data_view)

    def init_item_model(self):
        if self.data_model:
            self.data_model.clear()
            self.filter_proxy_model.setSourceModel(None)
        else:
            self.data_model = QStandardItemModel()

        self.data_model.setSortRole(Qt.UserRole)
        self.data_model.setHorizontalHeaderLabels(DATA_HEADER_LABELS)

    def sizeHint(self):
        return QSize(1280, 960)
Beispiel #34
0
class TERuleQueryTab(SEToolsWidget, QScrollArea):

    """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("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.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.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: " + str(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: " + str(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
        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.xperms.setToolTip("Match the extended permissions of the rule. Comma-separated "
                               "permissions or ranges of permissions.")
        self.xperms.setPalette(self.orig_palette)

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

            if text:
                for item in self.xperms.text().split(","):
                    rng = item.split("-")
                    if len(rng) == 2:
                        xperms.append((int(rng[0], base=16), int(rng[1], base=16)))
                    elif len(rng) == 1:
                        xperms.append((int(rng[0], base=16), int(rng[0], base=16)))
                    else:
                        raise ValueError("Enter an extended permission or extended permission "
                                         "range, e.g. 0x5411 or 0x8800-0x88ff.")

                self.query.xperms = xperms
            else:
                self.query.xperms = None

        except Exception as ex:
            self.log.error("Extended permissions error: {0}".format(ex))
            self.xperms.setToolTip("Error: " + str(ex))
            self.xperms.setPalette(self.error_palette)

    #
    # Default criteria
    #

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

    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.default_type.setToolTip("Error: " + str(ex))
            self.default_type.setPalette(self.error_palette)

    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."""
        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()
Beispiel #35
0
class MLSRuleQueryTab(AnalysisTab):

    """An MLS rule query."""

    section = AnalysisSection.Rules
    tab_title = "MLS Rules"
    mlsonly = True

    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):
        with suppress(RuntimeError):
            self.thread.quit()
            self.thread.wait(5000)

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

    def setupUi(self):
        self.load_ui("apol/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.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 = 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.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

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

    #
    # Default criteria
    #

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

    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.set_criteria_error(self.default_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",
                                         "range_transition",
                                         "source_indirect", "source_regex",
                                         "target_indirect", "target_regex"])
        save_lineedits(self, settings, ["source", "target", "default_range"])
        save_listviews(self, settings, ["tclass"])
        save_textedits(self, settings, ["notes"])
        return settings

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

    #
    # 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()
Beispiel #36
0
class InitialSIDQueryTab(SEToolsWidget, QScrollArea):

    """An initial SID query."""

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

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

    def setupUi(self):
        self.load_ui("initsidquery.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 = InitialSIDTableModel(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.initsidquery").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 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("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} initial SID 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()
class Mcar(QMainWindow, Ui_MainWindow):
    """
    汽车参数数据管理
    """
    sqlModel = QSqlQueryModel()

    def __init__(self, db, parent=None):
        """
        设置表格样式
        """
        super(Mcar, self).__init__(parent)
        self.setupUi(self)
        self.db = db
        self.initUi()

    def initUi(self):
        # 左右分栏布局五五开
        self.splitter.setStretchFactor(0, 5)
        self.splitter.setStretchFactor(1, 5)

        query = QSqlQuery()

        # 系列复选框关键字(遍历)
        series_key = [
            "",
        ]
        query.exec_("SELECT 系列 from CarData group by 系列;")
        while (query.next()):
            series_key.append(query.value(0))
        self.comboBox.addItems(series_key)

        # 级别复选框关键字
        level_key = [
            "",
        ]
        query.exec_("SELECT 级别 from CarData group by 级别;")
        while (query.next()):
            level_key.append(query.value(0))
        self.comboBox_3.addItems(level_key)

        # 价格复选框关键字
        price_key = ["", "厂商指导价", "补贴售后价", "经销商参考价"]
        self.comboBox_2.addItems(price_key)

        # 能源类型关键字
        energytype_key = [
            "",
        ]
        query.exec_("SELECT 能源类型 from CarData group by 能源类型;")
        while (query.next()):
            energytype_key.append(query.value(0))
        self.comboBox_4.addItems(energytype_key)

        # 厂商关键字
        vendertype_key = [
            "",
        ]
        query.exec_("SELECT 厂商 from CarData group by 厂商;")
        while (query.next()):
            vendertype_key.append(query.value(0))
        self.comboBox_5.addItems(vendertype_key)

        # 环保标准关键字
        envstandard_key = [
            "",
        ]
        query.exec_("SELECT 环保标准 from CarData group by 环保标准;")
        while (query.next()):
            envstandard_key.append(query.value(0))
        self.comboBox_6.addItems(envstandard_key)

        self.tableView.setIconSize(QSize(55, 25))
        # 水平布局填充
        self.tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

        self.setTableModel()

    def loading(self):
        while self.sqlModel.canFetchMore():
            self.sqlModel.fetchMore()

    def setTableModel(self):
        """
        表格数据显示
        """
        # self.sqlModel = QSqlQueryModel()
        # self.sqlModel.setQuery("SELECT * FROM CarData;")
        self.sqlModel.setQuery(
            "SELECT id,系列,车型,厂商指导价,补贴后售价,经销商参考价,厂商,级别,能源类型,环保标准,上市时间,\"最大功率(kW)\",\"最大扭矩(N·m)\",发动机,变速箱,\"长*宽*高(mm)\",车身结构,\"最高车速(km/h)\",\"官方0-100km/h加速(s)\",\"实测0-100km/h加速(s)\",\"实测100-0km/h制动(m)\",\"工信部综合油耗(L/100km)\",\"实测油耗(L/100km)\",整车质保,\"长度(mm)\",\"宽度(mm)\",\"高度(mm)\",\"轴距(mm)\",\"前轮距(mm)\",\"后轮距(mm)\",\"最小离地间隙(mm)\",\"车门数(个)\",\"座位数(个)\",\"油箱容积(L)\",\"行李厢容积(L)\",\"整备质量(kg)\",发动机型号,\"排量(mL)\",\"排量(L)\",进气形式 FROM CarData;"
        )
        print("数据库读取中.....")
        # while self.sqlModel.canFetchMore():
        #     self.sqlModel.fetchMore()
        self.proxyModel = QSortFilterProxyModel()
        # self.proxyModel.sort(0, Qt.AscendingOrder) 会有bug
        self.proxyModel.setSourceModel(self.sqlModel)
        # 大小写不敏感
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.tableView.setModel(self.proxyModel)
        # 开启排序
        # self.tableView.setSortingEnabled(True)
        self.tableView.hideColumn(0)
        # hidden
        for i in range(8, 1371):
            self.tableView.hideColumn(i)
        # self.tableView.show()

    @pyqtSlot(QModelIndex)
    def on_tableView_clicked(self, index):
        """
        单击显示车辆详细信息
        """
        row = index.row()
        self.label_12.setText(self.sqlModel.record(row).value("系列"))
        self.label_14.setText(self.sqlModel.record(row).value("车型"))
        strp1 = str(self.sqlModel.record(row).value("厂商指导价"))
        if strp1 != "暂无报价":
            self.label_16.setText(strp1 + "万元")
        else:
            self.label_16.setText("暂无报价")
        strp2 = str(self.sqlModel.record(row).value("补贴后售价"))
        if strp2 != "暂无报价":
            self.label_18.setText(strp2 + "万元")
        else:
            self.label_18.setText("暂无报价")
        strp3 = str(self.sqlModel.record(row).value("经销商参考价"))
        if strp3 != "暂无报价":
            self.label_20.setText(strp3 + "万元")
        else:
            self.label_20.setText("暂无报价")
        self.label_22.setText(self.sqlModel.record(row).value("厂商"))
        self.label_24.setText(self.sqlModel.record(row).value("级别"))
        self.label_26.setText(self.sqlModel.record(row).value("能源类型"))
        self.label_28.setText(self.sqlModel.record(row).value("环保标准"))
        self.label_30.setText(str(self.sqlModel.record(row).value("上市时间")))
        self.label_32.setText(str(self.sqlModel.record(row).value("最大功率(kW)")))
        self.label_34.setText(str(
            self.sqlModel.record(row).value("最大扭矩(N·m)")))
        self.label_36.setText(self.sqlModel.record(row).value("发动机"))
        self.label_38.setText(self.sqlModel.record(row).value("变速箱"))
        self.label_40.setText(self.sqlModel.record(row).value("长*宽*高(mm)"))
        self.label_42.setText(self.sqlModel.record(row).value("车身结构"))
        self.label_44.setText(
            str(self.sqlModel.record(row).value("最高车速(km/h)")))
        self.label_46.setText(
            str(self.sqlModel.record(row).value("官方0-100km/h加速(s)")))
        self.label_48.setText(
            str(self.sqlModel.record(row).value("实测0-100km/h加速(s)")))
        self.label_50.setText(
            str(self.sqlModel.record(row).value("实测100-0km/h制动(m)")))
        self.label_52.setText(
            str(self.sqlModel.record(row).value("工信部综合油耗(L/100km)")))
        self.label_54.setText(
            str(self.sqlModel.record(row).value("实测油耗(L/100km)")))
        self.label_56.setText(self.sqlModel.record(row).value("整车质保"))
        self.label_58.setText(self.sqlModel.record(row).value("进气形式"))
        self.label_60.setText(str(self.sqlModel.record(row).value("车门数(个)")))
        self.label_70.setText(str(self.sqlModel.record(row).value("排量(L)")))
        self.label_62.setText(str(self.sqlModel.record(row).value("座位数(个)")))
        self.label_64.setText(str(self.sqlModel.record(row).value("油箱容积(L)")))
        self.label_66.setText(str(self.sqlModel.record(row).value("行李厢容积(L)")))
        self.label_68.setText(self.sqlModel.record(row).value("发动机型号"))

    @pyqtSlot()
    def on_pushButton_search_clicked(self):
        # 系列
        self.seriesFilter = self.comboBox.currentText()
        # 级别
        self.levelFilter = self.comboBox_3.currentText()
        # 价格
        self.priceFilter = self.comboBox_2.currentText()
        # 能源类型
        self.energyFilter = self.comboBox_4.currentText()
        # 厂商
        self.vendorFilter = self.comboBox_5.currentText()
        # 环保标准
        self.envFilter = self.comboBox_6.currentText()
        # 价格下限
        self.bottomFilter = self.lineEdit_bottomPrice.text()
        # 价格上限
        self.topFilter = self.lineEdit_topPrice.text()
        self.Filter(self.seriesFilter, self.levelFilter, self.priceFilter,
                    self.energyFilter, self.vendorFilter, self.envFilter,
                    self.bottomFilter, self.topFilter)

    def Filter(self, sf, lf, pf, enef, vf, envf, bf, tf):
        for i in range(8, 1371):
            self.tableView.hideColumn(i)
        if sf == lf == pf == enef == vf == envf == bf == tf == self.lineEdit.text(
        ) == self.lineEdit_2.text() == self.lineEdit_topPrice.text(
        ) == self.lineEdit_bottomPrice.text() == "":
            self.sqlModel.setQuery(
                "SELECT id,系列,车型,厂商指导价,补贴后售价,经销商参考价,厂商,级别,能源类型,环保标准,上市时间,\"最大功率(kW)\",\"最大扭矩(N·m)\",发动机,变速箱,\"长*宽*高(mm)\",车身结构,\"最高车速(km/h)\",\"官方0-100km/h加速(s)\",\"实测0-100km/h加速(s)\",\"实测100-0km/h制动(m)\",\"工信部综合油耗(L/100km)\",\"实测油耗(L/100km)\",整车质保,\"长度(mm)\",\"宽度(mm)\",\"高度(mm)\",\"轴距(mm)\",\"前轮距(mm)\",\"后轮距(mm)\",\"最小离地间隙(mm)\",\"车门数(个)\",\"座位数(个)\",\"油箱容积(L)\",\"行李厢容积(L)\",\"整备质量(kg)\",发动机型号,\"排量(mL)\",\"排量(L)\",进气形式 FROM CarData;"
            )
        elif pf == "" and (self.lineEdit_topPrice.text() != ""
                           or self.lineEdit_bottomPrice.text() != ""):
            msg_box = QMessageBox()
            msg_box.setWindowTitle("提示")
            msg_box.setText("请选择价格")
            if msg_box.exec_() == QMessageBox.Yes:
                return
        else:
            arr = {'系列': sf, '级别': lf, '能源类型': enef, '厂商': vf, '环保标准': envf}
            base_query = "SELECT id,系列,车型,厂商指导价,补贴后售价,经销商参考价,厂商,级别,能源类型,环保标准,上市时间,\"最大功率(kW)\",\"最大扭矩(N·m)\",发动机,变速箱,\"长*宽*高(mm)\",车身结构,\"最高车速(km/h)\",\"官方0-100km/h加速(s)\",\"实测0-100km/h加速(s)\",\"实测100-0km/h制动(m)\",\"工信部综合油耗(L/100km)\",\"实测油耗(L/100km)\",整车质保,\"长度(mm)\",\"宽度(mm)\",\"高度(mm)\",\"轴距(mm)\",\"前轮距(mm)\",\"后轮距(mm)\",\"最小离地间隙(mm)\",\"车门数(个)\",\"座位数(个)\",\"油箱容积(L)\",\"行李厢容积(L)\",\"整备质量(kg)\",发动机型号,\"排量(mL)\",\"排量(L)\",进气形式 FROM CarData WHERE "
            # base_query = "SELECT * FROM CarData WHERE "
            flag = True
            for key in arr.keys():
                if arr[key] != "" and flag:
                    flag = False
                    base_query = base_query + key + "=" + '\"' + arr[key] + '\"'
                elif not flag and arr[key] != "":
                    base_query = base_query + " AND " + key + "=" + '\"' + arr[
                        key] + '\"'

            # 上市时间筛选
            if self.lineEdit.text() != "" and self.lineEdit_2.text(
            ) != "" and flag:
                flag = False
                base_query = base_query + "\"上市时间\" BETWEEN " + self.lineEdit.text(
                ) + " AND " + self.lineEdit_2.text()
            elif self.lineEdit.text() != "" and self.lineEdit_2.text(
            ) != "" and (not flag):
                base_query = base_query + " AND " + "\"上市时间\" BETWEEN " + self.lineEdit.text(
                ) + " AND " + self.lineEdit_2.text()
            # 价格筛选
            if self.lineEdit_bottomPrice.text(
            ) != "" and self.lineEdit_topPrice.text(
            ) != "" and pf != "" and flag:
                flag = False
                base_query = base_query + "\"" + pf + "\"" + " BETWEEN " + self.lineEdit_bottomPrice.text(
                ) + " AND " + self.lineEdit_topPrice.text()
            elif self.lineEdit_bottomPrice.text(
            ) != "" and self.lineEdit_topPrice.text() != "" and pf != "" and (
                    not flag):
                base_query = base_query + " AND " + "\"" + pf + "\"" + " BETWEEN " + self.lineEdit_bottomPrice.text(
                ) + " AND " + self.lineEdit_topPrice.text()
            base_query = base_query + " ORDER BY " + "id" + ';'
            self.sqlModel.setQuery(base_query)
Beispiel #38
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')
Beispiel #39
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(self.__class__.__name__)
        self.policy = policy
        self.query = MLSRuleQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)

    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 = MLSRuleListModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)

        # set up processing thread
        self.thread = QThread()
        self.worker = ResultsUpdater(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)

        # 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.results_frame.setHidden(not self.results_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.source.setToolTip("Error: " + str(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.target.setToolTip("Error: " + str(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.default_range.setToolTip("Error: " + str(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):
        # 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()
Beispiel #40
0
class TileStampsDock(QDockWidget):
    setStamp = pyqtSignal(TileStamp)

    def __init__(self, stampManager, parent=None):
        super().__init__(parent)

        self.mTileStampManager = stampManager
        self.mTileStampModel = stampManager.tileStampModel()
        self.mProxyModel = QSortFilterProxyModel(self.mTileStampModel)
        self.mFilterEdit = QLineEdit(self)
        self.mNewStamp = QAction(self)
        self.mAddVariation = QAction(self)
        self.mDuplicate = QAction(self)
        self.mDelete = QAction(self)
        self.mChooseFolder = QAction(self)

        self.setObjectName("TileStampsDock")
        self.mProxyModel.setSortLocaleAware(True)
        self.mProxyModel.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.mProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.mProxyModel.setSourceModel(self.mTileStampModel)
        self.mProxyModel.sort(0)
        self.mTileStampView = TileStampView(self)
        self.mTileStampView.setModel(self.mProxyModel)
        self.mTileStampView.setVerticalScrollMode(
            QAbstractItemView.ScrollPerPixel)
        self.mTileStampView.header().setStretchLastSection(False)
        self.mTileStampView.header().setSectionResizeMode(
            0, QHeaderView.Stretch)
        self.mTileStampView.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self.mTileStampView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.mTileStampView.customContextMenuRequested.connect(
            self.showContextMenu)
        self.mNewStamp.setIcon(QIcon(":images/16x16/document-new.png"))
        self.mAddVariation.setIcon(QIcon(":/images/16x16/add.png"))
        self.mDuplicate.setIcon(QIcon(":/images/16x16/stock-duplicate-16.png"))
        self.mDelete.setIcon(QIcon(":images/16x16/edit-delete.png"))
        self.mChooseFolder.setIcon(QIcon(":images/16x16/document-open.png"))
        Utils.setThemeIcon(self.mNewStamp, "document-new")
        Utils.setThemeIcon(self.mAddVariation, "add")
        Utils.setThemeIcon(self.mDelete, "edit-delete")
        Utils.setThemeIcon(self.mChooseFolder, "document-open")

        self.mFilterEdit.setClearButtonEnabled(True)
        self.mFilterEdit.textChanged.connect(
            self.mProxyModel.setFilterFixedString)
        self.mTileStampModel.stampRenamed.connect(self.ensureStampVisible)
        self.mNewStamp.triggered.connect(self.newStamp)
        self.mAddVariation.triggered.connect(self.addVariation)
        self.mDuplicate.triggered.connect(self.duplicate)
        self.mDelete.triggered.connect(self.delete_)
        self.mChooseFolder.triggered.connect(self.chooseFolder)
        self.mDuplicate.setEnabled(False)
        self.mDelete.setEnabled(False)
        self.mAddVariation.setEnabled(False)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)

        buttonContainer = QToolBar()
        buttonContainer.setFloatable(False)
        buttonContainer.setMovable(False)
        buttonContainer.setIconSize(QSize(16, 16))
        buttonContainer.addAction(self.mNewStamp)
        buttonContainer.addAction(self.mAddVariation)
        buttonContainer.addAction(self.mDuplicate)
        buttonContainer.addAction(self.mDelete)
        stretch = QWidget()
        stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        buttonContainer.addWidget(stretch)
        buttonContainer.addAction(self.mChooseFolder)
        listAndToolBar = QVBoxLayout()
        listAndToolBar.setSpacing(0)
        listAndToolBar.addWidget(self.mFilterEdit)
        listAndToolBar.addWidget(self.mTileStampView)
        listAndToolBar.addWidget(buttonContainer)
        layout.addLayout(listAndToolBar)
        selectionModel = self.mTileStampView.selectionModel()
        selectionModel.currentRowChanged.connect(self.currentRowChanged)
        self.setWidget(widget)
        self.retranslateUi()

    def changeEvent(self, e):
        super().changeEvent(e)
        x = e.type()
        if x == QEvent.LanguageChange:
            self.retranslateUi()
        else:
            pass

    def keyPressEvent(self, event):
        x = event.key()
        if x == Qt.Key_Delete or x == Qt.Key_Backspace:
            self.delete_()
            return

        super().keyPressEvent(event)

    def currentRowChanged(self, index):
        sourceIndex = self.mProxyModel.mapToSource(index)
        isStamp = self.mTileStampModel.isStamp(sourceIndex)
        self.mDuplicate.setEnabled(isStamp)
        self.mDelete.setEnabled(sourceIndex.isValid())
        self.mAddVariation.setEnabled(isStamp)
        if (isStamp):
            self.setStamp.emit(self.mTileStampModel.stampAt(sourceIndex))
        else:
            variation = self.mTileStampModel.variationAt(sourceIndex)
            if variation:
                # single variation clicked, use it specifically
                self.setStamp.emit(TileStamp(Map(variation.map)))

    def showContextMenu(self, pos):
        index = self.mTileStampView.indexAt(pos)
        if (not index.isValid()):
            return
        menu = QMenu()
        sourceIndex = self.mProxyModel.mapToSource(index)
        if (self.mTileStampModel.isStamp(sourceIndex)):
            addStampVariation = QAction(self.mAddVariation.icon(),
                                        self.mAddVariation.text(), menu)
            deleteStamp = QAction(self.mDelete.icon(), self.tr("Delete Stamp"),
                                  menu)
            deleteStamp.triggered.connect(self.delete_)
            addStampVariation.triggered.connect(self.addVariation)
            menu.addAction(addStampVariation)
            menu.addSeparator()
            menu.addAction(deleteStamp)
        else:
            removeVariation = QAction(QIcon(":/images/16x16/remove.png"),
                                      self.tr("Remove Variation"), menu)
            Utils.setThemeIcon(removeVariation, "remove")
            removeVariation.triggered.connect(self.delete_)
            menu.addAction(removeVariation)

        menu.exec(self.mTileStampView.viewport().mapToGlobal(pos))

    def newStamp(self):
        stamp = self.mTileStampManager.createStamp()
        if (self.isVisible() and not stamp.isEmpty()):
            stampIndex = self.mTileStampModel.index(stamp)
            if (stampIndex.isValid()):
                viewIndex = self.mProxyModel.mapFromSource(stampIndex)
                self.mTileStampView.setCurrentIndex(viewIndex)
                self.mTileStampView.edit(viewIndex)

    def delete_(self):
        index = self.mTileStampView.currentIndex()
        if (not index.isValid()):
            return
        sourceIndex = self.mProxyModel.mapToSource(index)
        self.mTileStampModel.removeRow(sourceIndex.row(), sourceIndex.parent())

    def duplicate(self):
        index = self.mTileStampView.currentIndex()
        if (not index.isValid()):
            return
        sourceIndex = self.mProxyModel.mapToSource(index)
        if (not self.mTileStampModel.isStamp(sourceIndex)):
            return
        stamp = self.mTileStampModel.stampAt = TileStamp(sourceIndex)
        self.mTileStampModel.addStamp(stamp.clone())

    def addVariation(self):
        index = self.mTileStampView.currentIndex()
        if (not index.isValid()):
            return
        sourceIndex = self.mProxyModel.mapToSource(index)
        if (not self.mTileStampModel.isStamp(sourceIndex)):
            return
        stamp = self.mTileStampModel.stampAt(sourceIndex)
        self.mTileStampManager.addVariation(stamp)

    def chooseFolder(self):
        prefs = Preferences.instance()
        stampsDirectory = prefs.stampsDirectory()
        stampsDirectory = QFileDialog.getExistingDirectory(
            self.window(), self.tr("Choose the Stamps Folder"),
            stampsDirectory)
        if (not stampsDirectory.isEmpty()):
            prefs.setStampsDirectory(stampsDirectory)

    def ensureStampVisible(self, stamp):
        stampIndex = self.mTileStampModel.index(stamp)
        if (stampIndex.isValid()):
            self.mTileStampView.scrollTo(
                self.mProxyModel.mapFromSource(stampIndex))

    def retranslateUi(self):
        self.setWindowTitle(self.tr("Tile Stamps"))
        self.mNewStamp.setText(self.tr("Add New Stamp"))
        self.mAddVariation.setText(self.tr("Add Variation"))
        self.mDuplicate.setText(self.tr("Duplicate Stamp"))
        self.mDelete.setText(self.tr("Delete Selected"))
        self.mChooseFolder.setText(self.tr("Set Stamps Folder"))
        self.mFilterEdit.setPlaceholderText(self.tr("Filter"))
Beispiel #41
0
class BackAnnotateMainWindow(QMainWindow):
    def __init__(self):
        super(BackAnnotateMainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.ui.loadBoardButton.clicked.connect(self.loadBoard)
        self.ui.prepareSchematicButton.clicked.connect(self.prepareSchematic)

        self.settings = QSettings("kicad_backannotate", "kicad_backannotate")

        self.ui.prepareSchematicButton.setEnabled(False)
        self.ui.writeSchematicButton.setEnabled(False)
        self.show()

        self.ui.schGroup.hide()

        self.ui.commitboardbutton.setEnabled(False)
        self.ui.writeSchematicButton.setEnabled(False)
        self.ui.commitboardbutton.pressed.connect(self.commitBoard)
        self.ui.writeSchematicButton.pressed.connect(self.commitSchematic)

        self.ui.inchRadio.toggled.connect(self.unitsChanged)
        self.ui.mmRadio.toggled.connect(self.unitsChanged)

        units = self.get_lastunits()
        if not units:
            self.ui.mmRadio.setChecked(True)
        else:
            self.ui.inchRadio.setChecked(True)

    def loadBoard(self, checked, filename=None):
        print(filename)
        lastdir = self.get_lastdir()
        if filename is None:
            filename, _ = QFileDialog.getOpenFileName(self,
                                                      "select board file",
                                                      lastdir,
                                                      _KICAD_BOARD_FILTER)

        if len(filename) == 0:
            return

        self._model = RemapTable(filename, self.ui.sortOrder.currentIndex(),
                                 self.style())

        self._filterproxy = QSortFilterProxyModel()
        self._filterproxy.setSourceModel(self._model)
        self.ui.remapView.setModel(self._filterproxy)
        self.ui.remapView.selectionModel().currentChanged.connect(
            self.componentSelected)
        self.ui.remapView.setSortingEnabled(True)

        self.settings.setValue("lastVisitedDir", os.path.dirname(filename))
        self.ui.sortOrder.currentIndexChanged.connect(self._model.resortdata)
        self.ui.prepareSchematicButton.setEnabled(True)
        self.statusBar().showMessage("Board loaded OK")
        self.ui.remapView.resizeColumnsToContents()
        self.ui.commitboardbutton.setEnabled(True)

    def prepareSchematic(self, checked, filename=None):
        lastdir = self.get_lastdir()

        if filename is None:
            filename, _ = QFileDialog.getOpenFileName(self,
                                                      "select schematic file",
                                                      lastdir,
                                                      _KICAD_SCHEM_FILTER)

        if len(filename) == 0:
            return

        self._updater = SchematicUpdater(filename)
        stremap = string_remapping(self._model.remap)
        done = self._updater.recursive_remap(stremap)

        if len(done) != len(stremap):
            self.statusBar().showMessage("WARNING: some symbols not found!")
            self._allsymsfound = False
        else:
            self.statusBar().showMessage(
                "Schematic loaded OK, all symbols found")
            self._allsymsfound = True
            self.ui.writeSchematicButton.setEnabled(True)

        self.ui.loadBoardButton.setEnabled(False)
        self.ui.sortOrder.setEnabled(False)
        self._model.showSchematicStatus(stremap, done)
        self.ui.remapView.resizeColumnsToContents()
        self.ui.schGroup.show()

        self.ui.commitboardbutton.setEnabled(True)

    def get_lastdir(self):
        lastdir_variant = self.settings.value("lastVisitedDir")
        if not lastdir_variant:
            lastdir = ""
        else:
            lastdir = str(lastdir_variant)

        return lastdir

    def get_lastunits(self):
        units_variant = self.settings.value("lastUnits")
        units = 0 if not units_variant else int(units_variant)
        return units

    def componentSelected(self, index, previous):
        if not hasattr(self, "_model"):
            return

        props = self._model.getProperties(index)

        #mm
        self.x_mm = props["x"] / 1E6
        self.y_mm = props["y"] / 1E6

        self.x_inch = self.x_mm * INCH_TO_MM
        self.y_inch = self.y_mm * INCH_TO_MM

        self.unitsChanged(None)
        self.ui.timestampvalue.setNum(props["tstamp"])
        self.ui.footprintvalue.setText(str(props["libid"]))

        desig = self._model._oldvals[index.row()]
        if hasattr(self, "_updater"):
            if desig in self._updater.found_in_schematic_file:
                fname = os.path.basename(
                    self._updater.found_in_schematic_file[desig])
                self.ui.schfilevalue.setText(fname)
            else:
                self.ui.schfilevalue.setText("")

    def unitsChanged(self, toggleval):
        if not hasattr(self, "x_mm"):
            return

        if self.ui.mmRadio.isChecked():
            self.ui.xvalue.setNum(self.x_mm)
            self.ui.yvalue.setNum(self.y_mm)
            self.settings.setValue("lastUnits", 0)
        else:
            self.ui.xvalue.setNum(self.x_inch)
            self.ui.yvalue.setNum(self.y_inch)
            self.settings.setValue("lastUnits", 1)

    def commitBoard(self):
        lastdir = self.get_lastdir()
        self._model._remapper.change_board_references(self._model.remap)

        savename, _ = QFileDialog.getSaveFileName(self,
                                                  "select output board file",
                                                  lastdir, _KICAD_BOARD_FILTER)

        self._model._remapper.save_board(savename)
        self.statusBar().showMessage("saved output board %s" % savename)

    def commitSchematic(self):
        lastdir = self.get_lastdir()
        ext, ok = QInputDialog.getText(self, "extension",
                                       "select updated schematic name append",
                                       0, "_remapped")
        if not ok:
            return
        self._updater.save_changes(ext)

        self.statusBar().showMessage("saved output schematic")
Beispiel #42
0
class SensitivityQueryTab(SEToolsWidget, QScrollArea):

    """Sensitivity browser and query tab."""

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

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

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

        # populate sensitivity list
        self.sensitivity_model = SEToolsListModel(self)
        self.sensitivity_model.item_list = sorted(self.policy.sensitivities())
        self.sens.setModel(self.sensitivity_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.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.sensitivityquery").addHandler(self.handler)

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

        # connect signals
        self.sens.doubleClicked.connect(self.get_detail)
        self.sens.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)

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

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

    #
    # Name criteria
    #
    def clear_name_error(self):
        self.name.setToolTip("Match the sensitivity 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("Sensitivity 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()

    #
    # 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()
Beispiel #43
0
class MainWindow(QMainWindow):
    """ The main GUI window. """
    def __init__(self, application):
        super().__init__()

        self.application = application
        self.tabulator_dialog = None
        self.sound = QSound('laser.wav')

        self.window = Ui_MainWindow()
        self.window.setupUi(self)

        self.setWindowIcon(QIcon('aswan-icon.png'))

        # Data binding
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.application.REPORT)
        self.window.treeView.setModel(self.proxy_model)

        # Command binding
        self.window.actionQuit.triggered.connect(qApp.quit)

        self.window.actionColumns.triggered.connect(self.cmd_view_columns)
        self.window.actionClear.triggered.connect(self.cmd_view_clear)
        self.window.actionFit_Columns_To_Contents.triggered.connect(
            self.cmd_view_fit_columns_to_contents)

        self.window.actionDocumentation.triggered.connect(
            self.cmd_help_documentation)

        # Start the report updates
        self.update()

    def cmd_view_columns(self):
        """ Configure the columns produced by the tabulator. """
        self.tabulator_dialog = TabulatorDialog(self.application)
        self.tabulator_dialog.show()

    def cmd_view_clear(self):
        """ Clear the report. """
        self.application.REPORT.clear()

    def cmd_view_fit_columns_to_contents(self):
        """ Fit report columns to visible rows. """
        self.window.treeView.header().resizeSections(
            QHeaderView.ResizeToContents)

    def cmd_help_documentation(self):
        """ Show documentation. """
        webbrowser.open_new('https://www.intrepiduniverse.com/')

    def update(self):
        """ Timer method to update the report in real time. """
        try:
            if self.window.actionRealtime.isChecked():
                table = self.application.REPORT.update()
                if table['rows']:
                    if self.window.actionAudible_Blink.isChecked():
                        self.sound.play()
        finally:
            QTimer.singleShot(100, self.update)
Beispiel #44
0
class RBACRuleQueryTab(SEToolsWidget, QScrollArea):

    """A RBAC rule query."""

    def __init__(self, parent, policy, perm_map):
        super(RBACRuleQueryTab, self).__init__(parent)
        self.log = logging.getLogger(self.__class__.__name__)
        self.policy = policy
        self.query = RBACRuleQuery(policy)
        self.setupUi()

    def __del__(self):
        self.thread.quit()
        self.thread.wait(5000)

    def setupUi(self):
        self.load_ui("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.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 = RBACRuleListModel(self)
        self.sort_proxy = QSortFilterProxyModel(self)
        self.sort_proxy.setSourceModel(self.table_results_model)
        self.table_results.setModel(self.sort_proxy)

        # set up processing thread
        self.thread = QThread()
        self.worker = ResultsUpdater(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)

        # 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.results_frame.setHidden(not self.results_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.source.setToolTip("Match the source role 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.source.setToolTip("Error: " + str(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 role/type 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.target.setToolTip("Error: " + str(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_role.setToolTip("Match the default role the rule.")
        self.default_role.setPalette(self.orig_palette)

    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.default_role.setToolTip("Error: " + str(ex))
            self.default_role.setPalette(self.error_palette)

    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()

    #
    # 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):
        # 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()
Beispiel #45
0
class BoolQueryTab(AnalysisTab):
    """Bool browser and query tab."""
    def __init__(self, parent, policy, perm_map):
        super(BoolQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = BoolQuery(policy)
        self.setupUi()

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

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

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

        # set up results
        self.table_results_model = BooleanTableModel(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.boolquery").addHandler(self.handler)

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

        # connect signals
        self.bools.doubleClicked.connect(self.get_detail)
        self.bools.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)

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

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

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

    def set_name(self):
        try:
            self.query.name = self.name.text()
        except Exception as ex:
            self.log.error("Boolean 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", "default_any",
            "default_true", "default_false", "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", "default_any",
            "default_true", "default_false", "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.
        if self.default_any.isChecked():
            self.query.default = None
        else:
            self.query.default = self.default_true.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} Boolean(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()
Beispiel #46
0
class BoundsQueryTab(AnalysisTab):
    """Bounds browser and query tab."""
    def __init__(self, parent, policy, perm_map):
        super(BoundsQueryTab, self).__init__(parent)
        self.log = logging.getLogger(__name__)
        self.policy = policy
        self.query = BoundsQuery(policy)
        self.setupUi()

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

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

        # set up results
        self.table_results_model = BoundsTableModel(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)

        # setup indications of errors on level/range
        self.errors = set()
        self.orig_palette = self.parent.palette()
        self.error_palette = self.parent.palette()
        self.error_palette.setColor(QPalette.Base, Qt.red)
        self.clear_parent_error()
        self.clear_child_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.boundsquery").addHandler(self.handler)

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

        # connect signals
        self.parent.textEdited.connect(self.clear_parent_error)
        self.parent.editingFinished.connect(self.set_parent)
        self.parent_regex.toggled.connect(self.set_parent_regex)
        self.child.textEdited.connect(self.clear_child_error)
        self.child.editingFinished.connect(self.set_child)
        self.child_regex.toggled.connect(self.set_child_regex)
        self.buttonBox.clicked.connect(self.run)

    #
    # Parent criteria
    #
    def clear_parent_error(self):
        self.clear_criteria_error(self.parent, "Match the parent type.")

    def set_parent(self):
        try:
            self.query.parent = self.parent.text()
        except Exception as ex:
            self.log.error("Type parent error: {0}".format(ex))
            self.set_criteria_error(self.parent, ex)

    def set_parent_regex(self, state):
        self.log.debug("Setting parent_regex {0}".format(state))
        self.query.parent_regex = state
        self.clear_parent_error()
        self.set_parent()

    #
    # Child criteria
    #
    def clear_child_error(self):
        self.clear_criteria_error(self.child, "Match the child type.")

    def set_child(self):
        try:
            self.query.child = self.child.text()
        except Exception as ex:
            self.log.error("Type child error: {0}".format(ex))
            self.set_criteria_error(self.child, ex)

    def set_child_regex(self, state):
        self.log.debug("Setting child_regex {0}".format(state))
        self.query.child_regex = state
        self.clear_child_error()
        self.set_child()

    #
    # 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", "typebounds",
            "parent_regex", "child_regex"
        ])
        save_lineedits(self, settings, ["parent", "child"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings, [
            "criteria_expander", "notes_expander", "typebounds",
            "parent_regex", "child_regex"
        ])
        load_lineedits(self, settings, ["parent", "child"])
        load_textedits(self, settings, ["notes"])

    #
    # Results runner
    #
    def run(self, button):
        # right now there is only one button.
        self.query.parent_regex = self.parent_regex.isChecked()
        self.query.child_regex = self.child_regex.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} bound(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()
Beispiel #47
0
class TypeQueryTab(SEToolsWidget, QScrollArea):

    """Type browser and query tab."""

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

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

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

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

        # populate attribute list
        self.attr_model = SEToolsListModel(self)
        self.attr_model.item_list = sorted(self.policy.typeattributes())
        self.attrs.setModel(self.attr_model)

        # set up results
        self.table_results_model = TypeTableModel(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.typequery").addHandler(self.handler)

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

        # connect signals
        self.types.doubleClicked.connect(self.get_detail)
        self.types.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.attrs.selectionModel().selectionChanged.connect(self.set_attrs)
        self.invert_attrs.clicked.connect(self.invert_attr_selection)
        self.buttonBox.clicked.connect(self.run)

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

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

    #
    # Name criteria
    #
    def clear_name_error(self):
        self.name.setToolTip("Match the type 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("Type 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()

    #
    # Attribute criteria
    #
    def set_attrs(self):
        selected_attrs = []
        for index in self.attrs.selectionModel().selectedIndexes():
            selected_attrs.append(self.attr_model.data(index, Qt.UserRole))

        self.query.attrs = selected_attrs

    def invert_attr_selection(self):
        invert_list_selection(self.attrs.selectionModel())

    #
    # Results runner
    #

    def run(self, button):
        # right now there is only one button.
        self.query.name_regex = self.name_regex.isChecked()
        self.query.attrs_equal = self.attrs_equal.isChecked()
        self.query.permissive = self.permissive.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} type(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 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()
class IncidentView(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(IncidentView, self).__init__(parent)
        self.view = QtWidgets.QTreeView()
        self.view.setAllColumnsShowFocus(True)
        self.view.setUniformRowHeights(True)
        box = QtWidgets.QVBoxLayout()
        box.addWidget(self.view)
        self.load_trace = QtWidgets.QPushButton('&Trace')
        self.load_trace.setToolTip('Load into the Trace Window')
        self.load_trace.setEnabled(False)
        for activation_signal in [
                self.view.activated,
                self.view.entered,
                self.view.pressed]:
            activation_signal.connect(lambda _: self.update_controls_state())
        self.load_trace.clicked.connect(self.load_current_trace)
        self.view.doubleClicked.connect(self.jump_to_index)
        hbox = QtWidgets.QHBoxLayout()
        self.filter = QtWidgets.QLineEdit()
        self.filter.textChanged.connect(self.filter_model)
        filter_label = QtWidgets.QLabel('&Search')
        filter_label.setBuddy(self.filter)
        hbox.addWidget(filter_label)
        hbox.addWidget(self.filter)
        hbox.addWidget(self.load_trace)
        box.addLayout(hbox)
        self.setLayout(box)
        self.model = None
        self.proxy = None

    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)

    def filter_model(self, txt):
        if self.proxy:
            self.proxy.setFilterRegExp(QRegExp(txt))

    def update_controls_state(self):
        curr = self.view.currentIndex()
        self.load_trace.setEnabled(curr.isValid() and
                                   curr.parent().isValid())

    def load_current_trace(self):
        idx = self.proxy.mapToSource(self.view.currentIndex())
        if not idx.isValid() or index_level(idx) not in (1, 2):
            raise ValueError('load_current_trace: invalid index')

        if index_level(idx) == 2:
            idx = idx.parent()

        incident = self.model.incidents[idx.parent().row()]
        location = incident.locations[idx.row()]
        backtrace = self.model.locations[location]

        for p in reversed(backtrace):
            self.load_trace_point(p)

    def jump_to_index(self, idx):
        idx = self.proxy.mapToSource(idx)
        if index_level(idx) != 2:
            # don't mess with parents, they are used to create children
            return
        grandpa = idx.parent().parent()
        incident = self.model.incidents[grandpa.row()]
        location = incident.locations[idx.parent().row()]
        trace = self.model.locations[location]
        point = trace[idx.row()]
        self.show_trace_point(point)

    def load_trace_point(self, p):
        add_insn_to_trace_view(p.addr)

    def show_trace_point(self, p):
        idaapi.jumpto(p.addr)
class ConstraintQueryTab(AnalysisTab):

    """A constraint query."""

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

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

    def setupUi(self):
        self.load_ui("apol/constraintquery.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)

        # 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)

        # setup indications of errors
        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_user_error()
        self.clear_type_error()
        self.clear_role_error()

        # set up results
        self.table_results_model = ConstraintTableModel(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.constraintquery").addHandler(self.handler)

        # Ensure settings are consistent with the initial .ui state
        self.set_user_regex(self.user_regex.isChecked())
        self.set_role_regex(self.role_regex.isChecked())
        self.set_type_regex(self.type_regex.isChecked())
        self.criteria_frame.setHidden(not self.criteria_expander.isChecked())
        self.notes.setHidden(not self.notes_expander.isChecked())

        # MLS constraints available only if policy is MLS
        if not self.policy.mls:
            self.mlsconstrain.setEnabled(False)
            self.mlsvalidatetrans.setEnabled(False)
            self.mlsconstrain.setToolTip("MLS is disabled in this policy.")
            self.mlsvalidatetrans.setToolTip("MLS is disabled in this policy.")

        # 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.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.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)

    #
    # Ruletype criteria
    #
    def _set_ruletypes(self, value):
        self.constrain.setChecked(value)
        self.validatetrans.setChecked(value)

        if self.policy.mls:
            self.mlsconstrain.setChecked(value)
            self.mlsvalidatetrans.setChecked(value)

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

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

    #
    # 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())

    #
    # User criteria
    #
    def clear_user_error(self):
        self.clear_criteria_error(self.user,
                                  "Match constraints that have a user in the expression.")

    def set_user(self):
        try:
            self.query.user = self.user.text()
        except Exception as ex:
            self.log.error("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 constraints that have a role in the expression.")

    def set_role(self):
        try:
            self.query.role = self.role.text()
        except Exception as ex:
            self.log.error("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 constraints that have a type in the expression.")

    def set_type(self):
        try:
            self.query.type_ = self.type_.text()
        except Exception as ex:
            self.log.error("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()

    #
    # 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", "constrain",
                                         "mlsconstrain", "validatetrans", "mlsvalidatetrans",
                                         "user_regex", "role_regex", "type_regex", "perms_subset"])
        save_lineedits(self, settings, ["user", "role", "type_"])
        save_listviews(self, settings, ["tclass", "perms"])
        save_textedits(self, settings, ["notes"])
        return settings

    def load(self, settings):
        load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "constrain",
                                         "mlsconstrain", "validatetrans", "mlsvalidatetrans",
                                         "user_regex", "role_regex", "type_regex", "perms_subset"])
        load_lineedits(self, settings, ["user", "role", "type_"])
        load_listviews(self, settings, ["tclass", "perms"])
        load_textedits(self, settings, ["notes"])

    #
    # Results runner
    #
    def run(self, button):
        # right now there is only one button.
        rule_types = []
        for mode in [self.constrain, self.mlsconstrain, self.validatetrans, self.mlsvalidatetrans]:
            if mode.isChecked():
                rule_types.append(mode.objectName())

        self.query.ruletype = rule_types
        self.query.perms_subset = self.perms_subset.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} constraint(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 or expression column widths are too long, pull back
            # to a reasonable size
            header = self.table_results.horizontalHeader()
            if header.sectionSize(2) > 400:
                header.resizeSection(2, 400)
            if header.sectionSize(3) > 400:
                header.resizeSection(3, 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()
Beispiel #50
0
 def _init_proxy_model(self):
     filter_proxy_model = QSortFilterProxyModel()
     filter_proxy_model.setSourceModel(self.model())
     filter_proxy_model.setFilterKeyColumn(1)
     filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
     self.setModel(filter_proxy_model)
Beispiel #51
0
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.__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()
Beispiel #52
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.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, steps=1):
        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 + steps
                if row >= entries:
                    row = 0
            else:
                row = row - steps
                if row < 0:
                    row = (entries - 1)

        self._popup.selectRow(row)

    def select_first_completion(self):
        self._popup.selectRow(0)

    def select_last_completion(self):
        entries = self._proxy_model.rowCount()
        self._popup.selectRow(entries - 1)

    def select_next_page_completion(self, forward=True):
        self.select_next_completion(forward=forward,
                                    steps=self._popup._max_visible_items - 1)

    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)

    @pyqtProperty("QColor")
    def background_color(self):
        return self.palette().color(self.backgroundRole())

    @background_color.setter
    def background_color(self, color):
        palette = self.palette()
        palette.setColor(self.backgroundRole(), color)
        self.setPalette(palette)
        return self._data.shape[1]

    def data(self, index, role):
        if role == Qt.DisplayRole:
            return "{}".format(self._data[index.row(), index.column()])

        return QVariant()

if __name__ == '__main__':
    app = QApplication(sys.argv)

    table_view = QTableView()
    my_model = MyModel(None)

    proxy_model = QSortFilterProxyModel()   # <--
    proxy_model.setSourceModel(my_model)    # <--
    table_view.setModel(proxy_model)        # <--
    #table_view.setModel(my_model)

    proxy_model.setFilterRegExp(QRegExp("1", Qt.CaseInsensitive, QRegExp.FixedString))     # <--
    proxy_model.setFilterKeyColumn(0)                                                      # <--
    #table_view.setSortingEnabled(True)

    table_view.show()


    # The mainloop of the application. The event handling starts from this point.
    # The exec_() method has an underscore. It is because the exec is a Python keyword. And thus, exec_() was used instead.
    exit_code = app.exec_()

    # The sys.exit() method ensures a clean exit.
Beispiel #54
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")
class MLSRuleQueryTab(AnalysisTab):

    """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("apol/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.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 = 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.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

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

    #
    # Default criteria
    #

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

    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.set_criteria_error(self.default_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",
                                         "range_transition",
                                         "source_indirect", "source_regex",
                                         "target_indirect", "target_regex"])
        save_lineedits(self, settings, ["source", "target", "default_range"])
        save_listviews(self, settings, ["tclass"])
        save_textedits(self, settings, ["notes"])
        return settings

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

    #
    # 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()
class MasternodesWidget(QWidget):
    """Widget that displays masternodes."""
    def __init__(self, manager, parent=None):
        super(MasternodesWidget, self).__init__(parent)
        self.manager = manager
        self.model = MasternodesModel(self.manager)
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.model)
        self.view = QTableView()
        self.view.setModel(self.proxy_model)
        for header in [self.view.horizontalHeader(), self.view.verticalHeader()]:
            header.setHighlightSections(False)

        header = self.view.horizontalHeader()
        header.setSectionResizeMode(MasternodesModel.ALIAS, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(MasternodesModel.VIN, QHeaderView.Stretch)
        header.setSectionResizeMode(MasternodesModel.COLLATERAL, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(MasternodesModel.DELEGATE, QHeaderView.ResizeToContents)
        self.view.verticalHeader().setVisible(False)

        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.view.setSortingEnabled(True)
        self.view.sortByColumn(self.model.ALIAS, Qt.AscendingOrder)

        vbox = QVBoxLayout()
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.addWidget(self.view)
        self.setLayout(vbox)

    def select_masternode(self, alias):
        """Select the row that represents alias."""
        self.view.clearSelection()
        for i in range(self.proxy_model.rowCount()):
            idx = self.proxy_model.index(i, 0)
            mn_alias = str(self.proxy_model.data(idx))
            if mn_alias == alias:
                self.view.selectRow(i)
                break

    def populate_collateral_key(self, row):
        """Fill in the collateral key for a masternode based on its collateral output.

        row refers to the desired row in the proxy model, not the actual model.
        """
        mn = self.masternode_for_row(row)
        self.manager.populate_masternode_output(mn.alias)
        # Emit dataChanged for the collateral key.
        index = self.model.index(row, self.model.COLLATERAL)
        self.model.dataChanged.emit(index, index)

    def refresh_items(self):
        self.model.dataChanged.emit(QModelIndex(), QModelIndex())

    def add_masternode(self, masternode, save = True):
        self.model.add_masternode(masternode, save=save)

    def remove_masternode(self, alias, save = True):
        self.model.remove_masternode(alias, save=save)

    def masternode_for_row(self, row):
        idx = self.proxy_model.mapToSource(self.proxy_model.index(row, 0))
        return self.model.masternode_for_row(idx.row())

    def import_masternode_conf_lines(self, conf_lines, pw):
        return self.model.import_masternode_conf_lines(conf_lines, pw)
class GuiPropertyDock():

    '''
    GuiPropertyDock
    '''
    dock_name = "properties-dock"
    dock_displayed_name = _("Properties")

    def __init__(self):
        '''
        Constructor
        '''
        super(GuiPropertyDock, self).__init__()
        self.widget = None
        self.core_part = None  # CorePropertyDock
        self._sheet_id = None
        self.tree_sheet = None

    @property
    def sheet_id(self):
        return self._sheet_id

    @sheet_id.setter
    def sheet_id(self, sheet_id):
        if self._sheet_id == sheet_id:
            pass
        self._sheet_id = sheet_id
        if self.sheet_id is not None:
            self.tree_sheet = gui_cfg.core.tree_sheet_manager.get_tree_sheet_from_sheet_id(
                self.sheet_id)
            self.core_part = self.tree_sheet.get_instance_of(self.dock_name)
            self.core_part.sheet_id = sheet_id

    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

    @pyqtSlot()
    def add_property_row(self):
        index = self.filter.mapToSource(self.ui.tableView.currentIndex())
        self.core_part.add_property_row(index)

    @pyqtSlot()
    def remove_property_row(self):
        index = self.filter.mapToSource(self.ui.tableView.currentIndex())
        self.core_part.remove_property_row(index)

    @pyqtSlot('QModelIndex')
    def set_current_row(self, model_index):
        self.ui.tableView.setCurrentIndex(model_index)
Beispiel #58
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, 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)
Beispiel #59
0
class CommonQueryTab(AnalysisTab):

    """Common browser and query tab."""

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

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

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

        # populate commons list
        self.common_model = SEToolsListModel(self)
        self.common_model.item_list = sorted(c for c in self.policy.commons())
        self.commons.setModel(self.common_model)

        # populate perm list
        self.perms_model = SEToolsListModel(self)
        perms = set()
        for com in self.policy.commons():
            perms.update(com.perms)
        self.perms_model.item_list = sorted(perms)
        self.perms.setModel(self.perms_model)

        # set up results
        self.table_results_model = CommonTableModel(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
        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.commonquery").addHandler(self.handler)

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

        # connect signals
        self.commons.doubleClicked.connect(self.get_detail)
        self.commons.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.perms.selectionModel().selectionChanged.connect(self.set_perms)
        self.invert_perms.clicked.connect(self.invert_perms_selection)
        self.buttonBox.clicked.connect(self.run)

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

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

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

    def set_name(self):
        try:
            self.query.name = self.name.text()
        except Exception as ex:
            self.log.error("Common 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()

    #
    # 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())

    #
    # 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",
                                         "perms_equal"])
        save_lineedits(self, settings, ["name"])
        save_listviews(self, settings, ["perms"])
        save_textedits(self, settings, ["notes"])
        return settings

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

    #
    # Results runner
    #
    def run(self, button):
        # right now there is only one button.
        self.query.perms_equal = self.perms_equal.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} common(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(1) > 400:
                header.resizeSection(1, 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()
class Example(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.setGeometry(300, 300, 400, 240)
        self.setWindowTitle("Filtering data")
       
        self.initData()
        self.initUI()
        
        
    def initData(self):
    
        words = ["radar", "robert", "Rome", "rodeo",
            "rust", "ready", "robot", "rampart", "RAM", "ROM"]

        self.model = QStringListModel(words)
        self.filterModel = QSortFilterProxyModel(self)
        self.filterModel.setSourceModel(self.model)
        self.filterModel.setDynamicSortFilter(True)
        
    
    def initUI(self):
    
        grid = QGridLayout()
        grid.setSpacing(10)
        
        self.lv = QListView(self)
        self.lv.setModel(self.filterModel)
        grid.addWidget(self.lv, 0, 0, 2, 2)             
    
        self.filText = QLineEdit(self)
        grid.addWidget(self.filText, 0, 3, Qt.AlignTop)
    
        self.case = QCheckBox("Case sensitive", self)
        grid.addWidget(self.case, 1, 3, Qt.AlignTop)
    
        self.filterCombo = QComboBox(self)
        self.filterCombo.addItem("Regular expression",
            QVariant(QRegExp.RegExp))
        self.filterCombo.addItem("Wildcard", 
            QVariant(QRegExp.Wildcard))
        self.filterCombo.addItem("Fixed string",
            QVariant(QRegExp.FixedString))
        grid.addWidget(self.filterCombo, 2, 0)
        
        self.filterCombo.activated[str].connect(self.filterItems)
        self.filText.textChanged[str].connect(self.filterItems)
        self.case.toggled[bool].connect(self.filterItems)
               
        self.setLayout(grid)       
        
        
    def filterItems(self, value):
        
        idx = self.filterCombo.currentIndex()
        
        syntaxType = self.filterCombo.itemData(idx)
        syntax = QRegExp.PatternSyntax(syntaxType)
        
        if self.case.isChecked():
            case = Qt.CaseSensitive
            
        else: