class CustomQCompleter(QCompleter): def __init__(self, *args): super(CustomQCompleter, self).__init__(*args) self.local_completion_prefix = "" self.source_model = None self.filterProxyModel = QSortFilterProxyModel(self) self.usingOriginalModel = False def setModel(self, model): self.source_model = model self.filterProxyModel = QSortFilterProxyModel(self) self.filterProxyModel.setSourceModel(self.source_model) super(CustomQCompleter, self).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] return []
class JoinChannelDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.app = QApplication.instance() self.chans = ChatChannels() self.ui = ui_chatchannelslist.Ui_ChannelsListDialog() self.ui.setupUi(self) self.ui.joinButton.clicked.connect(self.onJoinClicked) self.ui.cancelButton.clicked.connect(functools.partial(self.done, 1)) self.channelsModel = QStandardItemModel() self.channelsModel.setHorizontalHeaderLabels(['Channel', 'Connected']) self.channelsProxyModel = QSortFilterProxyModel(self) self.channelsProxyModel.setSourceModel(self.channelsModel) self.channelsProxyModel.setFilterKeyColumn(0) self.channelsProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.ui.channelsView.setModel(self.channelsProxyModel) self.ui.channelsView.doubleClicked.connect( lambda idx: self.onJoinClicked()) self.ui.channelsView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ui.searchLine.textChanged.connect(self.onApplySearch) @ipfsOp async def initDialog(self, ipfsop): dagChannels = ipfsop.ctx.currentProfile.dagChatChannels for channel in dagChannels.channels: self.channelsModel.appendRow([ UneditableItem(channel), UneditableItem(str(await self.chans.cnCountByChannel(channel))) ]) await ipfsop.sleep() def onApplySearch(self): self.channelsProxyModel.setFilterRegExp(self.ui.searchLine.text()) def onJoinClicked(self): try: idx = self.ui.channelsView.selectionModel().selectedRows(0).pop() except Exception: return chan = self.channelsProxyModel.data(idx, Qt.DisplayRole) if chan: ensure(self.onJoinChannel(chan)) self.done(1) @ipfsOp async def onJoinChannel(self, ipfsop, channel): log.info(f'Joining channel: {channel}') widget = await self.chans.joinChannel(channel) self.app.mainWindow.registerTab(widget, name=channel, icon=getIcon('chat.png'), current=True, workspace=WS_PEERS)
def txt_dictFind_textChange(self, text): if len(text) == 0: self.tbl_dictList.setModel(self.dict_list_model) return filter_model = QSortFilterProxyModel() filter_model.setSourceModel(self.dict_list_model) filter_model.setFilterKeyColumn(0) regex = "^{}".format(text) filter_model.setFilterRegExp( QtCore.QRegExp(regex, QtCore.Qt.CaseInsensitive)) self.tbl_dictList.setModel(filter_model) pass
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 ''))
class PostSelectionWidget(QDialog): def __init__(self, app, parent=None): super(PostSelectionWidget, self).__init__(parent=parent) self.app = app self.model = PostsListModel(app) self.filtermodel = QSortFilterProxyModel() self.filtermodel.setSourceModel(self.model) self.resize(450, 250) self.layout = QVBoxLayout() self.setLayout(self.layout) view = QListView(self) self.completer = QCompleter(parent=self) self.completer.setCompletionMode(QCompleter.InlineCompletion) self.completer.setCompletionColumn(0) self.completer.setCompletionRole(Qt.DisplayRole) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setModelSorting(QCompleter.CaseInsensitivelySortedModel) self.completer.setModel(self.model) self._edit = QLineEdit('') self._edit.setCompleter(self.completer) self._edit.textEdited.connect(self.setfilter) self.layout.addWidget(self._edit) self.layout.addWidget(view) view.setModel(self.filtermodel) view.clicked.connect(self.select) view.doubleClicked.connect(self.select_and_edit) self._button = QPushButton('Edit') self._button.clicked.connect(self.edit) self.layout.addWidget(self._button) def setfilter(self, text): regexp = QRegExp("%s*" % text, Qt.CaseInsensitive, QRegExp.Wildcard) self.filtermodel.setFilterRegExp(regexp) def select(self, index): text = self.filtermodel.data(index) self._edit.setText(text) def select_and_edit(self, index): text = self.filtermodel.data(index) self._edit.setText(text) self.app.edit_post(text) def edit(self): self.app.edit_post(self._edit.text())
class JoinChannelDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.app = QApplication.instance() self.chans = ChatChannels() self.ui = ui_chatchannelslist.Ui_ChannelsListDialog() self.ui.setupUi(self) self.ui.joinButton.clicked.connect(self.onJoinClicked) self.ui.cancelButton.clicked.connect(functools.partial(self.done, 1)) self.channelsModel = UneditableStringListModel(self) self.channelsProxyModel = QSortFilterProxyModel(self) self.channelsProxyModel.setSourceModel(self.channelsModel) self.ui.channelsView.setModel(self.channelsProxyModel) self.ui.channelsView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ui.searchLine.textChanged.connect(self.onApplySearch) @ipfsOp async def initDialog(self, ipfsop): dagChannels = ipfsop.ctx.currentProfile.dagChatChannels self.channelsModel.setStringList(dagChannels.channels) def onApplySearch(self): self.channelsProxyModel.setFilterRegExp(self.ui.searchLine.text()) def onJoinClicked(self): idx = self.ui.channelsView.currentIndex() chan = self.channelsProxyModel.data(idx, Qt.DisplayRole) if chan: ensure(self.onJoinChannel(chan)) self.done(1) @ipfsOp async def onJoinChannel(self, ipfsop, channel): log.info(f'Joining channel: {channel}') widget = await self.chans.joinChannel(channel) self.app.mainWindow.registerTab(widget, name=channel, icon=getIcon('qta:mdi.chat-outline'), current=True)
class Window(QWidget): def __init__(self): super().__init__() # Make widgets ################# self.edit = QLineEdit() self.table_view = QTableView() self.edit.setPlaceholderText("Filter text (on col. 1)") # Set the layout ############################ vbox = QVBoxLayout() vbox.addWidget(self.edit) vbox.addWidget(self.table_view) self.setLayout(vbox) # Set Model and ProxyModel ################## my_model = MyModel(None) self.proxy_model = QSortFilterProxyModel() # <-- self.proxy_model.setSourceModel(my_model) # <-- self.table_view.setModel(self.proxy_model) # <-- #self.table_view.setModel(my_model) #self.proxy_model.setFilterRegExp(QRegExp("1", Qt.CaseInsensitive, QRegExp.FixedString)) # <-- self.proxy_model.setFilterKeyColumn(0) # <-- #self.table_view.setSortingEnabled(True) # Set LineEdit slot ######################### self.edit.textChanged.connect(self.foo) def foo(self): filter_str = self.edit.text() self.proxy_model.setFilterRegExp( QRegExp(filter_str, Qt.CaseInsensitive, QRegExp.FixedString)) # <--
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 []
def run_gui(): # Get some mutations #mutations = generate_mutation_sequence(50) reader = ABNAMROReader() path = r"C:\Users\z428172\Documents\financien\2019\transacties\TXT190210094911.TAB" mutations = reader.read(path) app = QApplication(sys.argv) window = MainAnotatorWindow() model = MutationsTableModel(mutations) proxy = QSortFilterProxyModel() proxy.setSourceModel(model) #proxy.sortByColumn(MutationsTableModel.column_numbers['description'], Qt.AscendingOrder) regExp = QRegExp("", Qt.CaseInsensitive, QRegExp.RegExp) proxy.setFilterRegExp(regExp) window.mutationsListView.setModel(proxy) window.show() sys.exit(app.exec_())
class reportUI(QWidget): def __init__(self, parent=None): super().__init__(parent) self.index = 0 self.selectActiveOnly = False self.model = None self.reportChooser = QComboBox() self.reportChooser.addItems(["Active Folios", "All Folios"]) self.reportChooser.currentTextChanged.connect(self.filterChanged) self.reportTableView = QTableView() self.reportTableView.setSortingEnabled(True) layout = QVBoxLayout() layout.addWidget(self.reportChooser) layout.addWidget(self.reportTableView) groupbox = QGroupBox("Account Summary") groupbox.setLayout(layout) boxLayout = QVBoxLayout(self) boxLayout.addWidget(groupbox) def setModel(self, model): self.model = model self.proxyModel = QSortFilterProxyModel() self.proxyModel.setSourceModel(self.model) self.reportTableView.setModel(self.proxyModel) self.filterChanged(self.reportChooser.currentText()) @pyqtSlot(str) def filterChanged(self, filter): if filter == "Active Folios": self.proxyModel.setFilterRegExp("^[1-9].*") self.proxyModel.setFilterKeyColumn(9) else: self.proxyModel.setFilterRegExp("")
class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): """ Class implementing a dialog to generate code for a Qt4/Qt5 dialog. """ DialogClasses = { "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", "QTabWidget", "QToolBox", "QStackedWidget" } Separator = 25 * "=" def __init__(self, formName, project, parent=None): """ Constructor @param formName name of the file containing the form (string) @param project reference to the project object @param parent parent widget if the dialog (QWidget) """ super(CreateDialogCodeDialog, self).__init__(parent) self.setupUi(self) self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.slotsView.header().hide() self.project = project self.formFile = formName filename, ext = os.path.splitext(self.formFile) self.srcFile = '{0}{1}'.format( filename, self.project.getDefaultSourceExtension()) self.slotsModel = QStandardItemModel() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.proxyModel.setSourceModel(self.slotsModel) self.slotsView.setModel(self.proxyModel) # initialize some member variables self.__initError = False self.__module = None if os.path.exists(self.srcFile): vm = e5App().getObject("ViewManager") ed = vm.getOpenEditor(self.srcFile) if ed and not vm.checkDirty(ed): self.__initError = True return try: splitExt = os.path.splitext(self.srcFile) if len(splitExt) == 2: exts = [splitExt[1]] else: exts = None from Utilities import ModuleParser self.__module = ModuleParser.readModule(self.srcFile, extensions=exts, caching=False) except ImportError: pass if self.__module is not None: self.filenameEdit.setText(self.srcFile) classesList = [] vagueClassesList = [] for cls in list(self.__module.classes.values()): if not set(cls.super).isdisjoint( CreateDialogCodeDialog.DialogClasses): classesList.append(cls.name) else: vagueClassesList.append(cls.name) classesList.sort() self.classNameCombo.addItems(classesList) if vagueClassesList: if classesList: self.classNameCombo.addItem( CreateDialogCodeDialog.Separator) self.classNameCombo.addItems(sorted(vagueClassesList)) if os.path.exists(self.srcFile) and \ self.__module is not None and \ self.classNameCombo.count() == 0: self.__initError = True E5MessageBox.critical( self, self.tr("Create Dialog Code"), self.tr("""The file <b>{0}</b> exists but does not contain""" """ any classes.""").format(self.srcFile)) self.okButton.setEnabled(self.classNameCombo.count() > 0) self.__updateSlotsModel() def initError(self): """ Public method to determine, if there was an initialzation error. @return flag indicating an initialzation error (boolean) """ return self.__initError def __objectName(self): """ Private method to get the object name of the dialog. @return object name (string) """ try: dlg = uic.loadUi(self.formFile, package=self.project.getProjectPath()) return dlg.objectName() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr("""<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __className(self): """ Private method to get the class name of the dialog. @return class name (sting) """ try: dlg = uic.loadUi(self.formFile, package=self.project.getProjectPath()) return dlg.metaObject().className() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr("""<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __signatures(self): """ Private slot to get the signatures. @return list of signatures (list of strings) """ if self.__module is None: return [] signatures = [] clsName = self.classNameCombo.currentText() if clsName: cls = self.__module.classes[clsName] for meth in list(cls.methods.values()): if meth.name.startswith("on_"): if meth.pyqtSignature is not None: sig = ", ".join([ bytes(QMetaObject.normalizedType(t)).decode() for t in meth.pyqtSignature.split(",") ]) signatures.append("{0}({1})".format(meth.name, sig)) else: signatures.append(meth.name) return signatures def __mapType(self, type_): """ Private method to map a type as reported by Qt's meta object to the correct Python type. @param type_ type as reported by Qt (QByteArray) @return mapped Python type (string) """ mapped = bytes(type_).decode() if self.project.getProjectLanguage() != "Python2" or \ self.project.getProjectType == "PySide": # 1. check for const mapped = mapped.replace("const ", "") # 2. check fpr * mapped = mapped.replace("*", "") # 3. replace QString and QStringList mapped = mapped.replace("QStringList", "list")\ .replace("QString", "str") # 4. replace double by float mapped = mapped.replace("double", "float") return mapped def __updateSlotsModel(self): """ Private slot to update the slots tree display. """ self.filterEdit.clear() try: dlg = uic.loadUi(self.formFile, package=self.project.getProjectPath()) objects = dlg.findChildren(QWidget) + dlg.findChildren(QAction) signatureList = self.__signatures() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) for obj in objects: name = obj.objectName() if not name or name.startswith("qt_"): # ignore un-named or internal objects continue metaObject = obj.metaObject() className = metaObject.className() itm = QStandardItem("{0} ({1})".format(name, className)) self.slotsModel.appendRow(itm) for index in range(metaObject.methodCount()): metaMethod = metaObject.method(index) if metaMethod.methodType() == QMetaMethod.Signal: if qVersion() >= "5.0.0": itm2 = QStandardItem("on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()).decode())) else: itm2 = QStandardItem("on_{0}_{1}".format( name, metaMethod.signature())) itm.appendRow(itm2) if self.__module is not None: if qVersion() >= "5.0.0": method = "on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()).decode( ).split("(")[0]) else: method = "on_{0}_{1}".format( name, metaMethod.signature().split("(")[0]) method2 = "{0}({1})".format( method, ", ".join([ self.__mapType(t) for t in metaMethod.parameterTypes() ])) if method2 in signatureList or \ method in signatureList: itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) itm2.setCheckState(Qt.Checked) itm2.setForeground(QBrush(Qt.blue)) continue pyqtSignature = \ ", ".join([self.__mapType(t) for t in metaMethod.parameterTypes()]) parameterNames = metaMethod.parameterNames() if parameterNames: for index in range(len(parameterNames)): if not parameterNames[index]: parameterNames[index] = \ QByteArray("p{0:d}".format(index) .encode("utf-8")) methNamesSig = \ ", ".join( [bytes(n).decode() for n in parameterNames]) if methNamesSig: if qVersion() >= "5.0.0": pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0], methNamesSig) else: pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, metaMethod.signature().split("(")[0], methNamesSig) else: if qVersion() >= "5.0.0": pythonSignature = "on_{0}_{1}(self)".format( name, bytes(metaMethod.methodSignature()).decode( ).split("(")[0]) else: pythonSignature = "on_{0}_{1}(self)".format( name, metaMethod.signature().split("(")[0]) itm2.setData(pyqtSignature, pyqtSignatureRole) itm2.setData(pythonSignature, pythonSignatureRole) itm2.setFlags( Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)) itm2.setCheckState(Qt.Unchecked) self.slotsView.sortByColumn(0, Qt.AscendingOrder) except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr("""<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) def __generateCode(self): """ Private slot to generate the code as requested by the user. """ # first decide on extension if self.filenameEdit.text().endswith(".py") or \ self.filenameEdit.text().endswith(".pyw"): self.__generatePythonCode() elif self.filenameEdit.text().endswith(".rb"): pass # second decide on project language elif self.project.getProjectLanguage() in ["Python2", "Python3"]: self.__generatePythonCode() elif self.project.getProjectLanguage() == "Ruby": pass else: # assume Python (our global default) self.__generatePythonCode() def __generatePythonCode(self): """ Private slot to generate Python code as requested by the user. """ # init some variables sourceImpl = [] appendAtIndex = -1 indentStr = " " slotsCode = [] if self.__module is None: # new file try: if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py2.tmpl") elif self.project.getProjectType() == "PyQt5": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py2.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py2.tmpl") else: if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py.tmpl") elif self.project.getProjectType() in [ "PyQt5", "E6Plugin" ]: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py.tmpl") tmplFile = open(tmplName, 'r', encoding="utf-8") template = tmplFile.read() tmplFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the code template file""" """ "{0}".</p><p>Reason: {1}</p>""").format( tmplName, str(why))) return objName = self.__objectName() if objName: template = template\ .replace( "$FORMFILE$", os.path.splitext(os.path.basename(self.formFile))[0])\ .replace("$FORMCLASS$", objName)\ .replace("$CLASSNAME$", self.classNameCombo.currentText())\ .replace("$SUPERCLASS$", self.__className()) sourceImpl = template.splitlines(True) appendAtIndex = -1 # determine indent string for line in sourceImpl: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break else: # extend existing file try: srcFile = open(self.srcFile, 'r', encoding="utf-8") sourceImpl = srcFile.readlines() srcFile.close() if not sourceImpl[-1].endswith("\n"): sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.srcFile, str(why))) return cls = self.__module.classes[self.classNameCombo.currentText()] if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: appendAtIndex = -1 # delete empty lines at end while not sourceImpl[-1].strip(): del sourceImpl[-1] else: appendAtIndex = cls.endlineno - 1 while not sourceImpl[appendAtIndex].strip(): appendAtIndex -= 1 appendAtIndex += 1 # determine indent string for line in sourceImpl[cls.lineno:cls.endlineno + 1]: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break # do the coding stuff if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' elif self.project.getProjectType() == "PyQt5": pyqtSignatureFormat = '@pyqtSlot({0})' else: pyqtSignatureFormat = '@pyqtSignature("{0}")' else: if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' else: pyqtSignatureFormat = '@pyqtSlot({0})' for row in range(self.slotsModel.rowCount()): topItem = self.slotsModel.item(row) for childRow in range(topItem.rowCount()): child = topItem.child(childRow) if child.checkState() and \ child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable): slotsCode.append('{0}\n'.format(indentStr)) slotsCode.append('{0}{1}\n'.format( indentStr, pyqtSignatureFormat.format( child.data(pyqtSignatureRole)))) slotsCode.append('{0}def {1}:\n'.format( indentStr, child.data(pythonSignatureRole))) slotsCode.append('{0}"""\n'.format(indentStr * 2)) slotsCode.append( '{0}Slot documentation goes here.\n'.format(indentStr * 2)) slotsCode.append('{0}"""\n'.format(indentStr * 2)) slotsCode.append('{0}# {1}: not implemented yet\n'.format( indentStr * 2, "TODO")) slotsCode.append('{0}raise NotImplementedError\n'.format( indentStr * 2)) if appendAtIndex == -1: sourceImpl.extend(slotsCode) else: sourceImpl[appendAtIndex:appendAtIndex] = slotsCode # write the new code try: if self.project.useSystemEol(): newline = None else: newline = self.project.getEolString() srcFile = open(self.filenameEdit.text(), 'w', encoding="utf-8", newline=newline) srcFile.write("".join(sourceImpl)) srcFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not write the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.filenameEdit.text(), str(why))) return self.project.appendFile(self.filenameEdit.text()) @pyqtSlot(int) def on_classNameCombo_activated(self, index): """ Private slot to handle the activated signal of the classname combo. @param index index of the activated item (integer) """ if (self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator): self.okButton.setEnabled(False) self.filterEdit.clear() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) else: self.okButton.setEnabled(True) self.__updateSlotsModel() def on_filterEdit_textChanged(self, text): """ Private slot called, when thext of the filter edit has changed. @param text changed text (string) """ re = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(re) @pyqtSlot() def on_newButton_clicked(self): """ Private slot called to enter the data for a new dialog class. """ path, file = os.path.split(self.srcFile) objName = self.__objectName() if objName: dlg = NewDialogClassDialog(objName, file, path, self) if dlg.exec_() == QDialog.Accepted: className, fileName = dlg.getData() self.classNameCombo.clear() self.classNameCombo.addItem(className) self.srcFile = fileName self.filenameEdit.setText(self.srcFile) self.__module = None self.okButton.setEnabled(self.classNameCombo.count() > 0) def on_buttonBox_clicked(self, button): """ Private slot to handle the buttonBox clicked signal. @param button reference to the button that was clicked (QAbstractButton) """ if button == self.okButton: self.__generateCode() self.accept()
class HistoryManagerWidget(QWidget): def __init__(self): super().__init__() self.listHistory = [] self.nam = QtNetwork.QNetworkAccessManager() self.setting = QSettings() self.searchLineEdit = QLineEdit() self.tableView = QTableView() self.columnComboBox = QComboBox() self.searchLabel = QLabel() self.searchLabel.setText("Filter") self.model = QStandardItemModel(self) searchHbox = QHBoxLayout() searchHbox.addWidget(self.searchLabel) searchHbox.addWidget(self.searchLineEdit) searchHbox.addWidget(self.columnComboBox) self.header = "Order ID;Order Status;Card ID;Menu ID;Menu Name;Price;Qty;" \ "Item Status;Table Number;Order Time;Modified Time".split(";") self.model.setHorizontalHeaderLabels(self.header) self.tableView.horizontalHeader().setStretchLastSection(True) hboxLayout = QHBoxLayout() self.backButton = QPushButton() self.backButton.setText("Back") self.refreshButton = QPushButton() self.refreshButton.setText("Refresh") self.refreshButton.clicked.connect(self.refresh) self.saveCSVButton = QPushButton() self.saveCSVButton.setText("Save as CSV") self.saveCSVButton.clicked.connect(self.saveCSV) hboxLayout.addWidget(self.backButton) hboxLayout.addWidget(self.refreshButton) hboxLayout.addWidget(self.saveCSVButton) widgetTitleLabel = QLabel() widgetTitleLabel.setAlignment(Qt.AlignCenter) widgetTitleLabel.setText("History Manager") mainLayout = QVBoxLayout() mainLayout.addWidget(widgetTitleLabel) mainLayout.addLayout(searchHbox) mainLayout.addWidget(self.tableView) mainLayout.addLayout(hboxLayout) self.proxy = QSortFilterProxyModel(self) self.proxy.setSourceModel(self.model) self.tableView.setModel(self.proxy) self.columnComboBox.addItems(self.header) self.searchLineEdit.textChanged.connect(self.on_lineEdit_textChanged) self.columnComboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged) self.horizontalHeader = self.tableView.horizontalHeader() self.setLayout(mainLayout) def saveCSV(self): data = "" rows = self.model.rowCount() columns = self.model.columnCount() if rows>0: for title in self.header: data += title data += "," data += "\n" for i in range(rows): for j in range(columns): index = self.model.index(i,j) # print(str(self.model.data(index))) data += str(self.model.data(index)) data += "," data += "\n" name, _ = QFileDialog.getSaveFileName(self, 'Save File', "History SELFO.csv", "csv(*.csv)") if name: file = open(name, 'w') file.write(data) file.close() else: QMessageBox.critical(self, "Error", "No Data") def clear(self): self.listHistory.clear() self.model.clear() self.model.setHorizontalHeaderLabels(self.header) def refresh(self): self.clear() self.doRequestOrderDetail() def populateList(self): for rowName in range(len(self.listHistory)): self.model.invisibleRootItem().appendRow( [QStandardItem("{}".format(self.listHistory[rowName][column])) for column in range(len(self.header)) ] ) self.tableView.resizeColumnsToContents() def closeHistoryManager(self): self.mainWindow.stackedWidget.removeWidget(self) def doRequestOrderDetail(self): url = self.setting.value("baseURL", "") url += "/orderdetail/?sellerID=" + str(self.setting.value("sellerID", "")) \ # + "&itemStatus=" + "placed" req = QtNetwork.QNetworkRequest(QUrl(url)) reply = self.nam.get(req) reply.finished.connect(self.handleResponseOrderDetail) def handleResponseOrderDetail(self): reply = self.sender() er = reply.error() if er == QtNetwork.QNetworkReply.NoError: bytes_string = reply.readAll() data = json.loads(str(bytes_string, 'utf-8')) # print(data) for history in data: # id = history['id'] orderID = history['orderID'] orderStatus = history['orderStatus'] cardID = history['cardID'] # sellerID = history['sellerID'] menuID = history['menuID'] menuName = history['menuName'] itemStatus = history['itemStatus'] price = formatRupiah(history['price']) qty = history['qty'] tableNumber = history['tableNumber'] rawOrderTime = history['orderTime'] orderTime = datetime.datetime.strptime( rawOrderTime, "%Y-%m-%dT%H:%M:%S.%f+07:00").strftime("%d %b %Y %H:%M:%S") rawModifiedTime = history['modifiedTime'] if rawModifiedTime is not None: modifiedTime = datetime.datetime.strptime( rawModifiedTime, "%Y-%m-%dT%H:%M:%S.%f+07:00").strftime("%d %b %Y %H:%M:%S") else: modifiedTime = "null" historyItem = [orderID, orderStatus, cardID, menuID, menuName, price, qty, itemStatus, tableNumber, orderTime, modifiedTime] self.listHistory.append(historyItem) self.populateList() else: errorMessage = "Error occured: " + str(er) + "\n" + str(reply.errorString()) QMessageBox.critical(self, "Error Order Detail", errorMessage) reply.deleteLater() def on_view_horizontalHeader_sectionClicked(self, logicalIndex): self.logicalIndex = logicalIndex self.menuValues = QMenu(self) self.signalMapper = QSignalMapper(self) self.columnComboBox.blockSignals(True) self.columnComboBox.setCurrentIndex(self.logicalIndex) self.columnComboBox.blockSignals(True) valuesUnique = [ self.model.item(row, self.logicalIndex).text() for row in range(self.model.rowCount()) ] actionAll = QAction("All", self) actionAll.triggered.connect(self.on_actionAll_triggered) self.menuValues.addAction(actionAll) self.menuValues.addSeparator() for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))): action = QAction(actionName, self) self.signalMapper.setMapping(action, actionNumber) action.triggered.connect(self.signalMapper.map) self.menuValues.addAction(action) self.signalMapper.mapped.connect(self.on_signalMapper_mapped) headerPos = self.tableView.mapToGlobal(self.horizontalHeader.pos()) posY = headerPos.y() + self.horizontalHeader.height() posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex) self.menuValues.exec_(QPoint(posX, posY)) def on_actionAll_triggered(self): filterColumn = self.logicalIndex filterString = QRegExp( "", Qt.CaseInsensitive, QRegExp.RegExp ) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) def on_signalMapper_mapped(self, i): stringAction = self.signalMapper.mapping(i).text() filterColumn = self.logicalIndex filterString = QRegExp( stringAction, Qt.CaseSensitive, QRegExp.FixedString ) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) def on_lineEdit_textChanged(self, text): search = QRegExp( text, Qt.CaseInsensitive, QRegExp.RegExp ) self.proxy.setFilterRegExp(search) def on_comboBox_currentIndexChanged(self, index): self.proxy.setFilterKeyColumn(index)
class NormaOdk(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) self.skrot = QShortcut(QKeySequence(Qt.Key_Return), self) self.naglowki = { 'iddetale': 'ID', 'nr_detalu': 'Detal', 'maszyna': 'Maszyna', "ilosc_m": 'Ilość maszyn', 'ilosc_szt': 'Ilość sztuk na operację', 'nazwa_op': 'Nazwa operacji', 'nr_op': 'Nr operacji', 'tm': 'Czas Tm [s]', 'tp': 'Czas Tp [s]', 'tj': 'Czas Tj [h]', 'norma': 'Norma [szt.]', 'uwagi': 'Uwagi', 'id_uzytkownika': 'Użytkownik' } self.proxy = QSortFilterProxyModel(self) self.parent = parent self.formularz = QGroupBox("Normy") self.lbl_w = QLabel("Wyszukaj") self.edit_w = QLineEdit(self) self.table = QTableView(self) self.btn_odswiez = QPushButton("Odśwież bazę") sciezka = czy_istnieje() self.db = QSqlDatabase.addDatabase('QSQLITE') self.db.setDatabaseName(sciezka) if self.db.open(): print('Otworzono bazę danych') self.model = QSqlRelationalTableModel(self, self.db) self.initUI() def initUI(self): # Zainicjowanie tabeli zawsze przed wszystkim self.tabela() # lista wybieralna with open('./resources/Maszyny i operacje.json', 'r', encoding='utf-8') as file: plik_json = json.load(file) masz = plik_json['Maszyny'] operacje = plik_json['Operacje'] self.table.setItemDelegateForColumn(2, ComboDelegate(self, masz)) self.table.setItemDelegateForColumn(6, ComboDelegate(self, operacje)) for row in range(0, self.model.rowCount()): self.table.openPersistentEditor(self.model.index(row, 2)) self.table.openPersistentEditor(self.model.index(row, 6)) # Zatwierdzenie ok_button = QPushButton("Dodaj") cancel_button = QPushButton("Cofnij") hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(self.btn_odswiez) hbox.addWidget(ok_button) hbox.addWidget(cancel_button) # Layouty layout_v = QVBoxLayout() layout_h = QHBoxLayout() # Tabela self.proxy.setSourceModel(self.model) self.table.setModel(self.proxy) # przyporządkowanie layout_h.addWidget(self.lbl_w) layout_h.addWidget(self.edit_w) layout_v.addLayout(layout_h) layout_v.addWidget(self.table) self.formularz.setLayout(layout_v) main_layout = QVBoxLayout() main_layout.addWidget(self.formularz) main_layout.addLayout(hbox) self.setLayout(main_layout) # export # self.export() # Funkcje cancel_button.clicked.connect(self.anulowanie) ok_button.clicked.connect(self.dodaj) self.edit_w.textChanged.connect(self.wyszukiwanie) self.btn_odswiez.clicked.connect(self.refresh_db) self.skrot.activated.connect(self.refresh_db) # Menu kontekstowe własne self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.prawoklik) def prawoklik(self): menu = QMenu(self) if self.model.rowCount(): akcja = QAction('Usuń wiersz', self) akcja.triggered.connect(self.usun_wiersz) menu.addAction(akcja) menu.exec_(QCursor.pos()) def usun_wiersz(self): ok = QMessageBox.question(self, 'Potwierdzenie', 'Czy na pewno chcesz usunąć pozycję?', QMessageBox.Ok, QMessageBox.Cancel) if ok == QMessageBox.Ok: selected = self.table.currentIndex() self.model.removeRow(selected.row()) self.model.submitAll() self.model.select() @pyqtSlot(str) def wyszukiwanie(self, text): search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(search) # Odpowiedzialne za kolumnę, po której filtruje self.proxy.setFilterKeyColumn(-1) @pyqtSlot() def uzupelniene(self): # Pobranie tp, tm z bazy query = 'SELECT iddetale, tm, tp, ilosc_m, ilosc_szt FROM detale' dane_db = multipolaczenie(query) for i in range(len(dane_db)): # if dane_db[i][1] and dane_db[i][2]: tm = dane_db[i][1] tp1 = dane_db[i][2] ilosc_m = dane_db[i][3] ilosc_szt = dane_db[i][4] if not ilosc_m: ilosc_m = 1 zm = 1 else: zm = 0.95 if not ilosc_szt: ilosc_szt = 1 if isinstance(tm, int) and isinstance(tp1, int): tw = tm + tp1 else: tw = 0 tp2 = tw * 0.05 tj = (tw + tp2) * 1.1 tjh = tj / 3600 if tj != 0: norma = 8 / tj * 3600 * ilosc_m * zm * ilosc_szt else: norma = 0 print(round(norma)) # update bazy query = 'UPDATE "detale" SET "tj" = ' + str(round( tjh, 5)) + ', "norma" = ' + str( round(norma)) + ' WHERE "iddetale" = ' + str(dane_db[i][0]) update_bazy(query) # query = 'UPDATE "detale" SET "norma" = ' + str(round(norma)) + # ' WHERE "iddetale" = ' + str(dane_db[i][0]) update_bazy(query) @pyqtSlot() def refresh_db(self): try: self.uzupelniene() except: pass # Odświeżenie tabeli self.model.select() def tabela(self): self.model.setTable('detale') self.model.setRelation( 12, QSqlRelation('uzytkownicy', 'iduzytkownicy', 'nazwa_uz')) # Za zmianę w bazie odpowiada OnFieldChange self.model.setEditStrategy(QSqlTableModel.OnFieldChange) # 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, self.naglowki[nazwa_kolumn]) self.model.select() # Odpowiada za edycję pojednynczym kliknieciem ''' Constant Value Description QAbstractItemView::NoEditTriggers 0 No editing possible. QAbstractItemView::CurrentChanged 1 Editing start whenever current item changes. QAbstractItemView::DoubleClicked 2 Editing starts when an item is double clicked. QAbstractItemView::SelectedClicked 4 Editing starts when clicking on an already selected item. QAbstractItemView::EditKeyPressed 8 Editing starts when the platform edit key has been pressed over an item. QAbstractItemView::AnyKeyPressed 16 Editing starts when any key is pressed over an item. QAbstractItemView::AllEditTriggers 31 Editing starts for all above actions. ''' if self.odczyt(): self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) else: self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.resizeColumnsToContents() self.table.setModel(self.model) self.table.setAlternatingRowColors(True) self.table.resizeColumnsToContents() # self.table.doubleClicked.connect(self.klikniecie) def anulowanie(self): self.parent.statusBar().clearMessage() from opcje_qt import Wewnatrz menu_gl = Wewnatrz(self.parent) self.parent.setCentralWidget(menu_gl) def odczyt(self): id = str(self.parent.id_user[0]) query = 'SELECT odczyt FROM uzytkownicy WHERE iduzytkownicy=' + id return polaczenie(query)[0] def dodaj(self): poz, masz, op, tm, tp, ok = MultiDialog().getMultidialog(self) print(poz, masz, op, tm, tp, ok) id = self.parent.id_user[0] if ok and poz: query = "INSERT INTO detale(nr_detalu,maszyna,nazwa_op,tm,tp," \ "id_uzytkownika) VALUES ('" + poz + "','" + masz + "','" + op + "','" + tm + "','" + tp + "','" + str( id) + "');" print(query) polaczenie(query) if tm and tp: try: self.uzupelniene() except: pass self.model.select() self.parent.statusBar().showMessage("Dodano nową pozycję", 10000) else: print("Nie wpisano pozycji")
class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): """ Class implementing a dialog to generate code for a Qt5 dialog. """ DialogClasses = { "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", "QTabWidget", "QToolBox", "QStackedWidget" } Separator = 25 * "=" def __init__(self, formName, project, parent=None): """ Constructor @param formName name of the file containing the form (string) @param project reference to the project object @param parent parent widget if the dialog (QWidget) """ super(CreateDialogCodeDialog, self).__init__(parent) self.setupUi(self) self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.slotsView.header().hide() self.project = project self.formFile = formName filename, ext = os.path.splitext(self.formFile) self.srcFile = '{0}{1}'.format( filename, self.project.getDefaultSourceExtension()) self.slotsModel = QStandardItemModel() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.proxyModel.setSourceModel(self.slotsModel) self.slotsView.setModel(self.proxyModel) # initialize some member variables self.__initError = False self.__module = None packagesRoot = self.project.getUicParameter("PackagesRoot") if packagesRoot: self.packagesPath = os.path.join(self.project.getProjectPath(), packagesRoot) else: self.packagesPath = self.project.getProjectPath() if os.path.exists(self.srcFile): vm = e5App().getObject("ViewManager") ed = vm.getOpenEditor(self.srcFile) if ed and not vm.checkDirty(ed): self.__initError = True return try: splitExt = os.path.splitext(self.srcFile) if len(splitExt) == 2: exts = [splitExt[1]] else: exts = None from Utilities import ModuleParser self.__module = ModuleParser.readModule(self.srcFile, extensions=exts, caching=False) except ImportError: pass if self.__module is not None: self.filenameEdit.setText(self.srcFile) classesList = [] vagueClassesList = [] for cls in list(self.__module.classes.values()): if not set(cls.super).isdisjoint( CreateDialogCodeDialog.DialogClasses): classesList.append(cls.name) else: vagueClassesList.append(cls.name) classesList.sort() self.classNameCombo.addItems(classesList) if vagueClassesList: if classesList: self.classNameCombo.addItem( CreateDialogCodeDialog.Separator) self.classNameCombo.addItems(sorted(vagueClassesList)) if (os.path.exists(self.srcFile) and self.__module is not None and self.classNameCombo.count() == 0): self.__initError = True E5MessageBox.critical( self, self.tr("Create Dialog Code"), self.tr("""The file <b>{0}</b> exists but does not contain""" """ any classes.""").format(self.srcFile)) self.okButton.setEnabled(self.classNameCombo.count() > 0) self.__updateSlotsModel() def initError(self): """ Public method to determine, if there was an initialzation error. @return flag indicating an initialzation error (boolean) """ return self.__initError def __runUicLoadUi(self, command): """ Private method to run the UicLoadUi.py script with the given command and return the output. @param command uic command to be run @type str @return tuple of process output and error flag @rtype tuple of (str, bool) """ venvName = self.project.getDebugProperty("VIRTUALENV") venvManager = e5App().getObject("VirtualEnvManager") interpreter = venvManager.getVirtualenvInterpreter(venvName) execPath = venvManager.getVirtualenvExecPath(venvName) if not interpreter: interpreter = sys.executable env = QProcessEnvironment.systemEnvironment() if execPath: if env.contains("PATH"): env.insert("PATH", os.pathsep.join([execPath, env.value("PATH")])) else: env.insert("PATH", execPath) loadUi = os.path.join(os.path.dirname(__file__), "UicLoadUi.py") args = [ loadUi, command, self.formFile, self.packagesPath, ] uicText = "" ok = False proc = QProcess() proc.setWorkingDirectory(self.packagesPath) proc.setProcessEnvironment(env) proc.start(interpreter, args) started = proc.waitForStarted(5000) finished = proc.waitForFinished(30000) if started and finished: output = proc.readAllStandardOutput() outText = str(output, "utf-8", "replace") if proc.exitCode() == 0: ok = True uicText = outText.strip() else: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, outText)) else: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>The project specific Python interpreter <b>{0}</b>""" """ could not be started or did not finish within 30""" """ seconds.</p>""").format(interpreter)) return uicText, ok def __objectName(self): """ Private method to get the object name of a form. @return object name @rtype str """ objectName = "" output, ok = self.__runUicLoadUi("object_name") if ok and output: objectName = output return objectName def __className(self): """ Private method to get the class name of a form. @return class name @rtype str """ className = "" output, ok = self.__runUicLoadUi("class_name") if ok and output: className = output return className def __signatures(self): """ Private slot to get the signatures. @return list of signatures (list of strings) """ if self.__module is None: return [] signatures = [] clsName = self.classNameCombo.currentText() if clsName: cls = self.__module.classes[clsName] for meth in list(cls.methods.values()): if meth.name.startswith("on_"): if meth.pyqtSignature is not None: sig = ", ".join([ bytes(QMetaObject.normalizedType(t)).decode() for t in meth.pyqtSignature.split(",") ]) signatures.append("{0}({1})".format(meth.name, sig)) else: signatures.append(meth.name) return signatures def __mapType(self, type_): """ Private method to map a type as reported by Qt's meta object to the correct Python type. @param type_ type as reported by Qt (QByteArray) @return mapped Python type (string) """ mapped = bytes(type_).decode() # I. always check for * mapped = mapped.replace("*", "") if (self.project.getProjectLanguage() != "Python2" or self.project.getProjectType in ("PySide", "PySide2")): # 1. check for const mapped = mapped.replace("const ", "") # 2. replace QString and QStringList mapped = (mapped.replace("QStringList", "list").replace("QString", "str")) # 3. replace double by float mapped = mapped.replace("double", "float") return mapped def __updateSlotsModel(self): """ Private slot to update the slots tree display. """ self.filterEdit.clear() output, ok = self.__runUicLoadUi("signatures") if ok and output: objectsList = json.loads(output.strip()) signatureList = self.__signatures() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) for objectDict in objectsList: itm = QStandardItem("{0} ({1})".format( objectDict["name"], objectDict["class_name"])) self.slotsModel.appendRow(itm) for methodDict in objectDict["methods"]: itm2 = QStandardItem(methodDict["signature"]) itm.appendRow(itm2) if self.__module is not None: if (methodDict["methods"][0] in signatureList or methodDict["methods"][1] in signatureList): itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) itm2.setCheckState(Qt.Checked) itm2.setForeground(QBrush(Qt.blue)) continue itm2.setData(methodDict["pyqt_signature"], pyqtSignatureRole) itm2.setData(methodDict["python_signature"], pythonSignatureRole) itm2.setData(methodDict["return_type"], returnTypeRole) itm2.setData(methodDict["parameter_types"], parameterTypesListRole) itm2.setData(methodDict["parameter_names"], parameterNamesListRole) itm2.setFlags( Qt.ItemFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)) itm2.setCheckState(Qt.Unchecked) self.slotsView.sortByColumn(0, Qt.AscendingOrder) def __generateCode(self): """ Private slot to generate the code as requested by the user. """ # first decide on extension if (self.filenameEdit.text().endswith(".py") or self.filenameEdit.text().endswith(".pyw")): self.__generatePythonCode() elif self.filenameEdit.text().endswith(".rb"): pass # second decide on project language elif self.project.getProjectLanguage() in ["Python2", "Python3"]: self.__generatePythonCode() elif self.project.getProjectLanguage() == "Ruby": pass else: # assume Python (our global default) self.__generatePythonCode() def __generatePythonCode(self): """ Private slot to generate Python code as requested by the user. """ # init some variables sourceImpl = [] appendAtIndex = -1 indentStr = " " slotsCode = [] if self.__module is None: # new file try: if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py2.tmpl") elif self.project.getProjectType() == "PySide2": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside2.py2.tmpl") elif self.project.getProjectType() == "PyQt5": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py2.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py2.tmpl") else: if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py.tmpl") elif self.project.getProjectType() == "PySide2": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside2.py.tmpl") elif self.project.getProjectType() in [ "PyQt5", "E6Plugin" ]: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py.tmpl") tmplFile = open(tmplName, 'r', encoding="utf-8") template = tmplFile.read() tmplFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the code template file""" """ "{0}".</p><p>Reason: {1}</p>""").format( tmplName, str(why))) return objName = self.__objectName() if objName: template = (template.replace( "$FORMFILE$", os.path.splitext( os.path.basename(self.formFile))[0]).replace( "$FORMCLASS$", objName).replace( "$CLASSNAME$", self.classNameCombo.currentText()).replace( "$SUPERCLASS$", self.__className())) sourceImpl = template.splitlines(True) appendAtIndex = -1 # determine indent string for line in sourceImpl: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break else: # extend existing file try: srcFile = open(self.srcFile, 'r', encoding="utf-8") sourceImpl = srcFile.readlines() srcFile.close() if not sourceImpl[-1].endswith("\n"): sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not open the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.srcFile, str(why))) return cls = self.__module.classes[self.classNameCombo.currentText()] if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: appendAtIndex = -1 # delete empty lines at end while not sourceImpl[-1].strip(): del sourceImpl[-1] else: appendAtIndex = cls.endlineno - 1 while not sourceImpl[appendAtIndex].strip(): appendAtIndex -= 1 appendAtIndex += 1 # determine indent string for line in sourceImpl[cls.lineno:cls.endlineno + 1]: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break # do the coding stuff if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() in ("PySide", "PySide2"): pyqtSignatureFormat = '@Slot({0})' elif self.project.getProjectType() == "PyQt5": pyqtSignatureFormat = '@pyqtSlot({0})' else: pyqtSignatureFormat = '@pyqtSignature("{0}")' else: if self.project.getProjectType() in ("PySide", "PySide2"): pyqtSignatureFormat = '@Slot({0})' else: pyqtSignatureFormat = '@pyqtSlot({0})' for row in range(self.slotsModel.rowCount()): topItem = self.slotsModel.item(row) for childRow in range(topItem.rowCount()): child = topItem.child(childRow) if (child.checkState() and child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable)): slotsCode.append('{0}\n'.format(indentStr)) slotsCode.append('{0}{1}\n'.format( indentStr, pyqtSignatureFormat.format( child.data(pyqtSignatureRole)))) slotsCode.append('{0}def {1}:\n'.format( indentStr, child.data(pythonSignatureRole))) indentStr2 = indentStr * 2 slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append( '{0}Slot documentation goes here.\n'.format( indentStr2)) if (child.data(returnTypeRole) or child.data(parameterTypesListRole)): slotsCode.append('{0}\n'.format(indentStr2)) if child.data(parameterTypesListRole): for name, type_ in zip( child.data(parameterNamesListRole), child.data(parameterTypesListRole)): slotsCode.append( '{0}@param {1} DESCRIPTION\n'.format( indentStr2, name)) slotsCode.append('{0}@type {1}\n'.format( indentStr2, type_)) if child.data(returnTypeRole): slotsCode.append( '{0}@returns DESCRIPTION\n'.format(indentStr2)) slotsCode.append('{0}@rtype {1}\n'.format( indentStr2, child.data(returnTypeRole))) slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append('{0}# {1}: not implemented yet\n'.format( indentStr2, "TODO")) slotsCode.append( '{0}raise NotImplementedError\n'.format(indentStr2)) if appendAtIndex == -1: sourceImpl.extend(slotsCode) else: sourceImpl[appendAtIndex:appendAtIndex] = slotsCode # write the new code try: if self.project.useSystemEol(): newline = None else: newline = self.project.getEolString() srcFile = open(self.filenameEdit.text(), 'w', encoding="utf-8", newline=newline) srcFile.write("".join(sourceImpl)) srcFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not write the source file "{0}".</p>""" """<p>Reason: {1}</p>""").format( self.filenameEdit.text(), str(why))) return self.project.appendFile(self.filenameEdit.text()) @pyqtSlot(int) def on_classNameCombo_activated(self, index): """ Private slot to handle the activated signal of the classname combo. @param index index of the activated item (integer) """ if (self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator): self.okButton.setEnabled(False) self.filterEdit.clear() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) else: self.okButton.setEnabled(True) self.__updateSlotsModel() def on_filterEdit_textChanged(self, text): """ Private slot called, when thext of the filter edit has changed. @param text changed text (string) """ re = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(re) @pyqtSlot() def on_newButton_clicked(self): """ Private slot called to enter the data for a new dialog class. """ path, file = os.path.split(self.srcFile) objName = self.__objectName() if objName: dlg = NewDialogClassDialog(objName, file, path, self) if dlg.exec_() == QDialog.Accepted: className, fileName = dlg.getData() self.classNameCombo.clear() self.classNameCombo.addItem(className) self.srcFile = fileName self.filenameEdit.setText(self.srcFile) self.__module = None self.okButton.setEnabled(self.classNameCombo.count() > 0) def on_buttonBox_clicked(self, button): """ Private slot to handle the buttonBox clicked signal. @param button reference to the button that was clicked (QAbstractButton) """ if button == self.okButton: self.__generateCode() self.accept()
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. # The environment will be informed, how the application ended. sys.exit(exit_code)
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 Customer(QWidget): """ Klasa odpowiedzialna za widget klienci """ def __init__(self, parent, db): super(QWidget, self).__init__(parent) self.parent = parent self.btn_usun = QPushButton('Usuń') self.btn_mod = QPushButton('Modyfikuj') self.txt_imie = QLineEdit() self.txt_nazwisko = QLineEdit() self.txt_email = QLineEdit() self.txt_tel = QLineEdit() self.txt_ulica = QLineEdit() self.txt_nr_dom = QLineEdit() self.txt_kod = QLineEdit() self.txt_miasto = QLineEdit() self.proxy = QSortFilterProxyModel(self) self.view = QTableView() # Parametry połączenia z bazą self.model = QSqlTableModel(self, db) self.id_modify = -1 self.initUI() def initUI(self): """ Inicjuje UI """ self.table_init() self.btn_usun.setDisabled(True) self.btn_mod.setDisabled(True) # Walidacja self.txt_kod.setInputMask('99-999') # Tworzenie kontrolek lbl_wyszukaj = QLabel('Wyszukaj klienta:') txt_wysz = QLineEdit(self) btn_dodaj = QPushButton('Dodaj') lbl_1 = QLabel('Imię:') lbl_2 = QLabel('Nazwisko:') lbl_3 = QLabel('Email:') lbl_4 = QLabel('Telefon:') lbl_5 = QLabel('Ulica:') lbl_6 = QLabel('Numer domu:') lbl_7 = QLabel('Kod pocztowy:') lbl_8 = QLabel('Miejscowość:') # Tworzenie widoków centralbox = QVBoxLayout() hbox_wysz = QHBoxLayout() gropubox = QGroupBox('Edycja danych klienta') grop_layout = QGridLayout() hbox_btn = QHBoxLayout() form_left = QFormLayout() form_right = QFormLayout() # Metody self.view.clicked.connect(self.change) btn_dodaj.clicked.connect(self.add) self.btn_mod.clicked.connect(self.modify) self.btn_usun.clicked.connect(self.remove) txt_wysz.textChanged.connect(self.searching) # Ustawianie widoków hbox_wysz.addWidget(lbl_wyszukaj) hbox_wysz.addWidget(txt_wysz) hbox_btn.addWidget(self.btn_usun) hbox_btn.addWidget(self.btn_mod) hbox_btn.addWidget(btn_dodaj) form_left.setSpacing(9) form_right.setSpacing(9) form_left.setContentsMargins(0, 0, 10, 0) form_right.setContentsMargins(10, 0, 0, 0) form_left.addRow(lbl_1, self.txt_imie) form_left.addRow(lbl_2, self.txt_nazwisko) form_left.addRow(lbl_3, self.txt_email) form_left.addRow(lbl_4, self.txt_tel) form_right.addRow(lbl_5, self.txt_ulica) form_right.addRow(lbl_6, self.txt_nr_dom) form_right.addRow(lbl_7, self.txt_kod) form_right.addRow(lbl_8, self.txt_miasto) grop_layout.addItem(form_left, 0, 0) grop_layout.addItem(form_right, 0, 1) gropubox.setLayout(grop_layout) centralbox.addLayout(hbox_wysz) centralbox.addWidget(self.view) centralbox.addWidget(gropubox) centralbox.addLayout(hbox_btn) self.setLayout(centralbox) self.show() def change(self): """ Metoda edytująca zaznaczone wiersze - Wstawia wartości z wierszy w odpowiednie pola """ index = (self.view.selectionModel().currentIndex()) value = index.sibling(index.row(), index.column()).data() self.id_modify = index.sibling(index.row(), 0).data() self.txt_imie.setText(index.sibling(index.row(), 1).data()) self.txt_nazwisko.setText(str(index.sibling(index.row(), 2).data())) self.txt_email.setText(index.sibling(index.row(), 3).data()) self.txt_tel.setText(index.sibling(index.row(), 4).data()) self.txt_ulica.setText(index.sibling(index.row(), 5).data()) self.txt_nr_dom.setText(index.sibling(index.row(), 6).data()) self.txt_miasto.setText(index.sibling(index.row(), 7).data()) self.txt_kod.setText(index.sibling(index.row(), 8).data()) if self.id_modify >= 0 and self.txt_imie.text( ) and self.txt_nazwisko.text(): self.btn_mod.setEnabled(True) self.btn_usun.setEnabled(True) else: self.btn_usun.setDisabled(True) self.btn_mod.setDisabled(True) value.setText('') def table_init(self): """ Inicjuje wygląd tabeli """ self.model.setTable('klienci') query = QSqlQuery( 'SELECT klienci_id, imie, nazwisko, email, telefon, ulica, numer_mieszkania, miejscowosc, poczta FROM ' 'klienci;') self.model.setQuery(query) self.proxy.setSourceModel(self.model) 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.columnCount() for i in range(ilosc_kolumn): nazwa_kolumn = self.model.headerData(i, Qt.Horizontal) self.model.setHeaderData(i, Qt.Horizontal, naglowki[nazwa_kolumn]) self.view.setSizeAdjustPolicy( QAbstractScrollArea.AdjustToContentsOnFirstShow) self.view.setSortingEnabled(True) self.view.setAlternatingRowColors(True) # Wczytanie danych self.view.setModel(self.proxy) self.view.hideColumn(0) self.view.sortByColumn(1, Qt.AscendingOrder) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) def if_checked(self, txt, q, val=None): """ Sprawdza poprawność wprowadzonych damych. :param val: wartości do zapytania :param q: zapytanie query MySql :param txt: komunikat """ if len(self.txt_imie.text()) < 3 or len(self.txt_nazwisko.text()) < 1: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(txt) msg.setWindowTitle("Popraw dane") msg.exec_() return False else: print('Trwa zmiana w bazie danych') if val: print('Połączenie') query_to_db(q, val) else: print('Transakcja') return transaction_to_db(q) return True def add(self): """ Dodaje nowego klienta do bazy danych i odświeża widok. """ tekst = 'Nie wprowadzono wszystkich danych' # Dodanie nowego użytkownika query = 'INSERT INTO klienci (imie, nazwisko, email, telefon, ulica, numer_mieszkania, miejscowosc, ' \ 'poczta) VALUES (%s, %s, %s, %s, %s, %s, %s, %s);' val = (self.txt_imie.text(), self.txt_nazwisko.text(), self.txt_email.text(), self.txt_tel.text(), self.txt_ulica.text(), self.txt_nr_dom.text(), self.txt_miasto.text(), self.txt_kod.text()) if self.if_checked(tekst, query, val): msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setText('Klient został dodany do bazy danych') msg.setWindowTitle("Dodano nowego klienta") msg.exec_() # Odświeżanie widoku tabeli self.model.select() self.view.reset() def modify(self): """ Modyfikuje bazę danych """ tekst = 'Nie wprowadzono wszystkich danych' # Dodanie nowego użytkownika query = 'UPDATE klienci SET imie = %s, nazwisko = %s, email = %s, telefon = %s, ulica = %s, ' \ 'numer_mieszkania = %s, miejscowosc = %s, poczta = %s WHERE klienci_id = %s;' val = (self.txt_imie.text(), self.txt_nazwisko.text(), self.txt_email.text(), self.txt_tel.text(), self.txt_ulica.text(), self.txt_nr_dom.text(), self.txt_miasto.text(), self.txt_kod.text(), self.id_modify) if self.if_checked(tekst, query, val): msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setText('Dane klienta zostały pomyślnie zmodyfikowane') msg.setWindowTitle("Dane klienta zostały zmodyfikowane") msg.exec_() # Odświeżanie widoku tabeli self.model.select() self.view.reset() def remove(self): """ Usuwa klientów z bazy danych """ test = 'Błąd! Nie można usunąć danej usługi!' query = 'DELETE FROM klienci WHERE klienci_id = %s' query1 = 'DELETE FROM wizyty WHERE klienci_id = %s' val = (self.id_modify, ) ret = QMessageBox.question( self, 'Usuwanie klienta', "Czy na pewno chcesz usunąć danego klienta?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if ret == QMessageBox.Yes: if self.if_checked(test, [(query1, val), (query, val)]): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText('Klient został usunięty') msg.setWindowTitle("Usunięto") msg.exec_() self.txt_imie.setText('') self.txt_nazwisko.setText(''), self.txt_email.setText(''), self.txt_tel.setText(''), self.txt_ulica.setText(''), self.txt_nr_dom.setText(''), self.txt_miasto.setText(''), self.txt_kod.setText('') # Odświeżanie widoku tabeli self.model.select() self.view.reset() @pyqtSlot(str) def searching(self, text): """ Wyszukuje po wszystkich kolumnach tabeli :param text: """ search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(search) # Odpowiedzialne za kolumnę, po której filtruje self.proxy.setFilterKeyColumn(-1)
class ViewDataWindow(QDialog): formSubmitted = pyqtSignal() closeSignal = pyqtSignal() def __init__(self, LOGIN, parent=None): #super(ViewDataWindow, self).__init__(parent) super().__init__(parent) self.LOGIN = LOGIN self.db = db(self.LOGIN, "Brewing") self.displayNo = 0 self.displayedBrewsH = [] self.displayedBrewsVMash = [] self.displayedBrewsVBoil = [] self.displayedBrewsVFerment = [] self.create_layout_viewData() self.setWindowTitle('Past Brew Viewer') self.activeColours = [] self.colours = ["red", "green", "blue", "black",\ "cyan", "magenta", "yellow", "gray"] # Function to create layout of New Brew window def create_layout_viewData(self): # Create scroll boxes for filtering data filterGroupBox = QGroupBox("Filter by:") # Date edit box lab_date = QLabel("Date:") self.dateEdit = QDateEdit() # Set range of possible dates, current date is max date self.maxDate = QDate().currentDate() self.minDate = QDate(2019, 1, 1) self.dateEdit.setDate(self.maxDate) self.dateEdit.setDateRange(self.minDate, self.maxDate) self.dateEdit.setCalendarPopup(1) self.dateEdit.setDisplayFormat("dd/MM/yy") #self.dateEdit2 = QLineEdit() self.dateEdit.dateChanged.connect(self.filter_date) dateHLayout = QHBoxLayout() dateHLayout.addWidget(lab_date) dateHLayout.addWidget(self.dateEdit) ### Text edit filters ### # Batch ID search lab_batch = QLabel("Batch ID:") self.edit_batchID = QLineEdit() self.edit_batchID.setPlaceholderText("Enter Batch ID") self.but_IDsearch = QPushButton("Go") self.but_IDsearch.setAutoDefault(0) self.but_IDsearch.clicked.connect(self.filter_batchID) self.edit_batchID.returnPressed.connect(self.filter_batchID) batchHLayout = QHBoxLayout() batchHLayout.addWidget(lab_batch) batchHLayout.addWidget(self.edit_batchID) batchHLayout.addWidget(self.but_IDsearch) # Recipe search lab_recipe = QLabel("Recipe:") self.lineEdit_recipe = QLineEdit() self.lineEdit_recipe.setPlaceholderText("Enter Recipe") self.lineEdit_recipe.textChanged.connect(self.filter_recipe) self.lineEdit_recipe.returnPressed.connect(self.filter_recipe) recipeHLayout = QHBoxLayout() recipeHLayout.addWidget(lab_recipe) recipeHLayout.addWidget(self.lineEdit_recipe) # Clear filters button self.but_clearFilter = QPushButton("Clear Filters") self.but_clearFilter.setAutoDefault(0) clearHLayout = QHBoxLayout() clearHLayout.addStretch(1) clearHLayout.addWidget(self.but_clearFilter) clearHLayout.addStretch(0) self.but_clearFilter.clicked.connect(self.clearFilters) # Filter groupbox layout #recipeHLayout.addWidget(self.recipeEdit) #recipeVLayout = QVBoxLayout() #recipeVLayout.addLayout(recipeHLayout) #recipeVLayout.addWidget(self.lineEdit_recipe) filterHLayout = QHBoxLayout() filterHLayout.addStretch(1) filterHLayout.addWidget(lab_date) filterHLayout.addWidget(self.dateEdit) filterHLayout.addStretch(1) #filterHLayout.addLayout(recipeVLayout) filterHLayout.addStretch(1) filterHLayout.addWidget(self.edit_batchID) filterHLayout.addWidget(self.but_IDsearch) filterHLayout.addStretch(1) #filterGroupBox.setLayout(filterHLayout) # Alternate - Filter vertical layout filterVLayout = QVBoxLayout() filterVLayout.addLayout(batchHLayout) filterVLayout.addLayout(recipeHLayout) filterVLayout.addLayout(dateHLayout) filterVLayout.addLayout(clearHLayout) filterGroupBox.setLayout(filterVLayout) # scrollHLayout = QHBoxLayout() # scrollHLayout.addWidget(filterGroupBox) # scrollHLayout.addStretch(1) # Create QTableView of brew data header = ['Brew ID', 'Recipe', 'Date'] self.model = MyTableModel( self.db.readFromTable("Brews", "id, Recipe, Date"), header, self) self.proxyModel = QSortFilterProxyModel(self) self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setSourceModel(self.model) self.dataTable = QTableView() self.dataTable.setModel(self.proxyModel) self.dataTable.setSortingEnabled(True) self.dataTable.setSelectionBehavior(1) # Create bottom buttons self.but_quit = QPushButton("Close") self.but_quit.setAutoDefault(0) self.but_view = QPushButton("Display Brew") self.but_view.setAutoDefault(0) quitHLayout = QHBoxLayout() quitHLayout.addStretch(0) quitHLayout.addWidget(self.but_quit) quitHLayout.addStretch(3) quitHLayout.addWidget(self.but_view) quitHLayout.addStretch(0) # Main vertical layout for left area lWidget = QWidget() vLayoutL = QVBoxLayout(lWidget) vLayoutL.addWidget(filterGroupBox) vLayoutL.addWidget(self.dataTable) vLayoutL.addLayout(quitHLayout) # Widget for displayed brews - Widget allows fixed height to be set displayedWidget = QWidget() #displayedWidget.setFixedHeight(180) # h Layout to add groupboxes of displayed brews - added to in viewButtonClicked slot self.hLayoutDisplayed = QHBoxLayout() self.hLayoutDisplayed.addStretch(1) self.hLayoutDisplayed.setSizeConstraint(5) displayedWidget.setLayout(self.hLayoutDisplayed) # Scroll area for horizontal displayed brews hScrollArea = QScrollArea() hScrollArea.setWidget(displayedWidget) hScrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) hScrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) #hScrollArea.setFixedHeight(120) hScrollArea.setMinimumHeight(20) # Main v layout for displayed brews widget displayTitle = QLabel("Displayed Brews:") displayTitle.setMaximumHeight(20) hDisplayedWidget = QWidget() self.vLayoutDisplayed = QVBoxLayout(hDisplayedWidget) self.vLayoutDisplayed.addWidget(displayTitle) self.vLayoutDisplayed.addWidget(hScrollArea) # Main vertical layout for right area rWidget = QWidget() rSplitter = QSplitter() rSplitter.setOrientation(Qt.Orientation(2)) #vLayoutR = QVBoxLayout(rWidget) self.tabs = QTabWidget() self.tabMash = MashTab() self.tabBoil = BoilTab() self.tabFerment = FermentTab() self.tabs.resize(100, 1000) self.tabs.setMinimumSize(400, 100) self.tabs.addTab(self.tabMash, "Mash") self.tabs.addTab(self.tabBoil, "Boil") self.tabs.addTab(self.tabFerment, "Ferment") #vLayoutR.addLayout(self.vLayoutDisplayed) #vLayoutR.addWidget(self.tabs) rSplitter.addWidget(hDisplayedWidget) rSplitter.addWidget(self.tabs) # Main layout for whole window - splitter so widget sizes are adjustable mainLayout = QHBoxLayout() mainSplitter = QSplitter() mainSplitter.addWidget(lWidget) mainSplitter.addWidget(rSplitter) mainLayout.addWidget(mainSplitter) mainSplitter.setSizes([260, 740]) self.setLayout(mainLayout) #self.showFullScreen() self.setGeometry(0, 0, 1500, 1000) self.but_view.clicked.connect(self.viewButtonClicked) self.but_view.clicked.connect(self.viewButtonClickedTabs) self.but_quit.clicked.connect(self.quitButtonClicked) def quitButtonClicked(self): self.close() self.closeSignal.emit() # Slot for adding selected brew to widget def viewButtonClicked(self): self.brewInfo = [] # array to place brew info: ID, Recipe, Date self.displayNo = self.displayNo + 1 # Add brew info to array based on selected row index = (self.dataTable.selectionModel().currentIndex()) for i in range(3): self.brewInfo.append( QLabel(str(index.sibling(index.row(), i).data()))) # Choose colour to use for this displayed brew self.colourToUse = self.chooseColour() # Create group box with all brew info displayed and Remove button brewGroupBox = QGroupBox(str(self.displayNo)) brewGroupBox.setObjectName("ColouredGroupBox") brewGroupBox.setStyleSheet( "QGroupBox#ColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) brewForm = QFormLayout() brewForm.addRow(QLabel('Brew ID:'), self.brewInfo[0]) brewForm.addRow(QLabel('Recipe:'), self.brewInfo[1]) brewForm.addRow(QLabel('Date:'), self.brewInfo[2]) removeButHLayout = QHBoxLayout() removeButHLayout.addStretch(1) self.but_Remove = QPushButton("Remove") removeButHLayout.addWidget(self.but_Remove) brewForm.addRow(removeButHLayout) brewGroupBox.setLayout(brewForm) # Add group box to layout - use insert so that stretch stays on right side self.hLayoutDisplayed.insertWidget(self.displayNo - 1, brewGroupBox) self.displayedBrewsH.append( brewGroupBox) # Add groupbox to array of displayed brews # Signal to connect remove brew button. Lambda function used to pass argument of specific # brew to be removed self.but_Remove.clicked.connect( lambda: self.removeBrewClickedMash(brewGroupBox)) self.but_Remove.clicked.connect( lambda: self.removeBrewClickedBoil(brewGroupBox)) self.but_Remove.clicked.connect( lambda: self.removeBrewClickedFerment(brewGroupBox)) self.but_Remove.clicked.connect( lambda: self.removeBrewClicked(brewGroupBox)) # Slot for adding brew info to each of the process tabs def viewButtonClickedTabs(self): batchID = self.brewInfo[0].text() # Query database to get recipe data for the brew selected to view # brewInfo[0].text() gives brew ID for selected brew from table sql = f"SELECT * FROM Brews WHERE id = '{self.brewInfo[0].text()}'" query = self.db.custom(sql) self.recipedata = {} self.recipedata['batchID'] = query[0][0] self.recipedata['recipeName'] = query[0][1] self.recipedata['recipeDate'] = query[0][2] self.recipedata['mashTemp'] = query[0][3] self.recipedata['mashTime'] = query[0][4] self.recipedata['boilTemp'] = query[0][5] self.recipedata['boilTime'] = query[0][6] self.recipedata['hop1'] = (query[0][7], query[0][8]) self.recipedata['hop2'] = (query[0][9], query[0][10]) self.recipedata['hop3'] = (query[0][11], query[0][12]) self.recipedata['hop4'] = (query[0][13], query[0][14]) self.recipedata['fermenttemp'] = query[0][15] # Create groupboxes for each of the process tabs to fill with brew info mashGroupBox = QGroupBox(str(self.displayNo)) mashGroupBox.setObjectName("MashColouredGroupBox") mashGroupBox.setStyleSheet( "QGroupBox#MashColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) mashFormLayout = QFormLayout() mashFormLayout.addRow( QLabel(f"Temp ({DEGREES}C): {self.recipedata['mashTemp']}")) mashFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['mashTime']}")) mashGroupBox.setLayout(mashFormLayout) self.tabMash.mashVLayout.insertWidget(self.displayNo - 1, mashGroupBox) self.displayedBrewsVMash.append(mashGroupBox) boilGroupBox = QGroupBox(str(self.displayNo)) boilGroupBox.setObjectName("BoilColouredGroupBox") boilGroupBox.setStyleSheet( "QGroupBox#BoilColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) boilFormLayout = QFormLayout() boilFormLayout.addRow( QLabel(f"Temp ({DEGREES}C):{self.recipedata['boilTemp']}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['boilTime']}")) boilFormLayout.addRow(QLabel(f"Hop 1: {self.recipedata['hop1'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop1'][1]}")) boilFormLayout.addRow(QLabel(f"Hop 2: {self.recipedata['hop2'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop2'][1]}")) boilFormLayout.addRow(QLabel(f"Hop 3: {self.recipedata['hop3'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop3'][1]}")) boilFormLayout.addRow(QLabel(f"Hop 4: {self.recipedata['hop4'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop4'][1]}")) boilGroupBox.setLayout(boilFormLayout) self.tabBoil.boilVLayout.insertWidget(self.displayNo - 1, boilGroupBox) self.displayedBrewsVBoil.append(boilGroupBox) fermentGroupBox = QGroupBox(str(self.displayNo)) fermentGroupBox.setObjectName("FermentColouredGroupBox") fermentGroupBox.setStyleSheet( "QGroupBox#FermentColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) fermentFormLayout = QFormLayout() fermentFormLayout.addRow( QLabel(f"Temp ({DEGREES}C): {self.recipedata['fermenttemp']}")) #fermentFormLayout.addRow(QLabel('Time (mins):')) fermentGroupBox.setLayout(fermentFormLayout) self.tabFerment.fermentVLayout.insertWidget(self.displayNo - 1, fermentGroupBox) self.displayedBrewsVFerment.append(fermentGroupBox) ### PUTTING DATA ONTO GRAPHS ### # Query database to get data to plot on graphs sqlMash = f"SELECT TimeStamp, Temp FROM Mash WHERE BatchID = '{batchID}'" sqlBoil = f"SELECT TimeStamp, Temp FROM BoilMonitor WHERE BatchID = '{batchID}'" sqlFermentTemp = f"SELECT TimeStamp, Temp FROM Ferment WHERE BatchID = '{batchID}'" sqlFermentSG = f"SELECT TimeStamp, Sg FROM Ferment WHERE BatchID = '{batchID}'" mashDataX, mashDataY = self.createData(sqlMash) boilDataX, boilDataY = self.createData(sqlBoil) fermentTempDataX, fermentTempDataY = self.createData(sqlFermentTemp) fermentSGDataX, fermentSGDataY = self.createData(sqlFermentSG) # Create and add curves to each of the plots self.tabMash.graph.createCurve(mashDataX, mashDataY, self.colourToUse) self.tabBoil.graph.createCurve(boilDataX, boilDataY, self.colourToUse) self.tabFerment.tempGraph.createCurve(fermentTempDataX[1:], fermentTempDataY[1:], self.colourToUse) self.tabFerment.gravGraph.createCurve(fermentSGDataX[1:], fermentSGDataY[1:], self.colourToUse) # Function to choose first available colour def chooseColour(self): # Loop through dictionary, checking if self.colours[j] appear for colours in self.colours: # If it does appear, continue to next colour if colours not in self.activeColours: # If it doesn't appear, add colour to dictionary and return colour self.activeColours.append(colours) return colours # Get data from database using sql query def createData(self, sql): timestamps = [] tempdat = [] try: for data in self.db.custom(sql): timestamps.append(data[0]) tempdat.append(data[1]) startTime = timestamps[0] for i in range(len(timestamps)): timestamps[i] = (timestamps[i] - startTime).seconds except IndexError: return [0], [0] return timestamps, tempdat # Slot for removing group boxes from horizontal tab def removeBrewClicked(self, brewToRemove): brewArrayPos = self.displayedBrewsH.index(brewToRemove) self.hLayoutDisplayed.removeWidget( brewToRemove) # remove widget from layout brewToRemove.setParent(None) # remove parent so widget dissappears self.displayNo = self.displayNo - 1 self.displayedBrewsH.remove( brewToRemove) # remove brew from array of displayed brews i = 0 # Loop to renumber the remaining displayed groupboxes using the array for i in range(len(self.displayedBrewsH)): self.displayedBrewsH[i].setTitle(str(i + 1)) del self.activeColours[brewArrayPos] # Slot for removing group boxes of brew info in mash tab def removeBrewClickedMash(self, brewToRemove): # Obtain position in array of displayed brews of brew to remove brewArrayPos = self.displayedBrewsH.index(brewToRemove) # Use position to remove widget from layout self.tabMash.mashVLayout.takeAt(brewArrayPos) # Use position to remove parent self.displayedBrewsVMash[brewArrayPos].setParent(None) # Use position to delete from vertical array del self.displayedBrewsVMash[brewArrayPos] # Renumber groupboxes in vertical display for i in range(len(self.displayedBrewsVMash)): self.displayedBrewsVMash[i].setTitle(str(i + 1)) # Remove curve from graph self.tabMash.graph.removeCurve(brewArrayPos) # Slot for removing group boxes of brew info in boil tab def removeBrewClickedBoil(self, brewToRemove): # Obtain position in array of displayed brews of brew to remove brewArrayPos = self.displayedBrewsH.index(brewToRemove) # Use position to remove widget from layout self.tabBoil.boilVLayout.takeAt(brewArrayPos) # Use position to remove parent self.displayedBrewsVBoil[brewArrayPos].setParent(None) # Use position to delete from vertical array del self.displayedBrewsVBoil[brewArrayPos] # Renumber groupboxes in vertical display for i in range(len(self.displayedBrewsVBoil)): self.displayedBrewsVBoil[i].setTitle(str(i + 1)) self.tabBoil.graph.removeCurve(brewArrayPos) # Slot for removing group boxes of brew info in ferment tab def removeBrewClickedFerment(self, brewToRemove): # Obtain position in array of displayed brews of brew to remove brewArrayPos = self.displayedBrewsH.index(brewToRemove) # Use position to remove widget from layout self.tabFerment.fermentVLayout.takeAt(brewArrayPos) # Use position to remove parent self.displayedBrewsVFerment[brewArrayPos].setParent(None) # Use position to delete from vertical array del self.displayedBrewsVFerment[brewArrayPos] # Renumber groupboxes in vertical display for i in range(len(self.displayedBrewsVFerment)): self.displayedBrewsVFerment[i].setTitle(str(i + 1)) self.tabFerment.tempGraph.removeCurve(brewArrayPos) self.tabFerment.gravGraph.removeCurve(brewArrayPos) # Slot for filtering by Batch IDdisplayed def filter_batchID(self): self.lineEdit_recipe.clear() self.proxyModel.setFilterRegExp(self.edit_batchID.text()) self.proxyModel.setFilterKeyColumn(0) # Slot for filtering by Recipe def filter_recipe(self): self.edit_batchID.clear() self.proxyModel.setFilterRegExp(self.lineEdit_recipe.text()) self.proxyModel.setFilterKeyColumn(1) # Slot for filtering by date def filter_date(self): self.lineEdit_recipe.clear() self.edit_batchID.clear() self.proxyModel.setFilterRegExp( self.dateEdit.date().toString("dd/MM/yy")) self.proxyModel.setFilterKeyColumn(2) # Slot for clearing all filters def clearFilters(self): self.dateEdit.setDate(self.maxDate) self.proxyModel.setFilterRegExp('') self.proxyModel.setFilterKeyColumn(0) self.proxyModel.setFilterKeyColumn(1) self.proxyModel.setFilterKeyColumn(2) self.lineEdit_recipe.clear() self.edit_batchID.clear()
class BrowseWidget(QWidget): def __init__(self, parent=None): super(BrowseWidget, self).__init__(parent) self.parent = parent self.horizontalLayout = QtWidgets.QHBoxLayout(self.parent) self.usersFrame = QtWidgets.QFrame(self.parent) self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.usersFrame) self.browseUsersFrame = QtWidgets.QFrame(self.usersFrame) self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.browseUsersFrame) self.browseUsersLabel = QtWidgets.QLabel(self.browseUsersFrame) self.browseUsersLineEdit = QtWidgets.QLineEdit(self.browseUsersFrame) self.usersList = QtWidgets.QListView(self.usersFrame) self.buttonsFrame = QtWidgets.QFrame(self.parent) self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.buttonsFrame) self.downloadButton = QtWidgets.QPushButton(self.buttonsFrame) self.treeFrame = QtWidgets.QFrame(self.parent) self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.treeFrame) self.browseFileFrame = QtWidgets.QFrame(self.treeFrame) self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.browseFileFrame) self.browseFileLabel = QtWidgets.QLabel(self.browseFileFrame) self.browseFileLineEdit = QtWidgets.QLineEdit(self.browseFileFrame) self.fileTreeView = QtWidgets.QTreeView(self.treeFrame) self.foldIcon = QtGui.QIcon() self.fileIcon = QtGui.QIcon() self.filterType = 0 self.lastSearchedTreeFilter = None self.chosenUserTreeFile = None self.usersModel = None self.fileTreeModel = None self.worker = None self.thread = None self.fileProxyModel = QSortFilterProxyModel() self.setupUi() def disableButtons(self): self.downloadButton.setEnabled(False) def enableButtons(self): self.downloadButton.setEnabled(True) def fillUsersList(self, users_input): self.usersModel = QStandardItemModel() with open(users_input, "r") as inp: for line in inp.readlines(): item = UserItem(name=line.strip(), structFile=abspath('./files/user_tree.json')) self.usersModel.appendRow(item) self.usersList.setModel(self.usersModel) self.verticalLayout_3.addWidget(self.usersList) def filterUsersList(self, text): # search = QtCore.QRegExp(text, # QtCore.Qt.CaseInsensitive, # QtCore.QRegExp.RegExp # ) # self.usersProxyModel.setFilterRegExp(search) searchedText = text.lower() for row in range(self.usersModel.rowCount()): if searchedText in str(self.usersModel.item(row).text()).lower(): self.usersList.setRowHidden(row, False) else: self.usersList.setRowHidden(row, True) def renderTree(self, treeFile: str): self.fileTreeModel = TreeModelFile(treeInput=treeFile, foldIcon=self.foldIcon, fileIcon=self.fileIcon) # Allows for scrolling optimizations. self.fileTreeView.setAlternatingRowColors(True) self.fileTreeView.setUniformRowHeights(True) self.fileProxyModel.setSourceModel(self.fileTreeModel) # self.fileProxyModel.sort() self.fileTreeView.setModel(self.fileProxyModel) self.enableButtons() def fillStructTree(self, index): self.chosenUserTreeFile = self.usersList.model().itemData(index)[ UserItem.StructFileRole] self.renderTree(self.chosenUserTreeFile) def simpleTreeFilter(self, searchText): if self.fileTreeModel is not None and self.filterType == 0: search = QtCore.QRegExp(searchText, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp) self.fileProxyModel.setFilterRegExp(search) def complexTreeFilter(self): searchText = self.browseFileLineEdit.text() if searchText == "": self.renderTree(self.chosenUserTreeFile) if self.fileTreeModel is not None and self.filterType == 1: if self.lastSearchedTreeFilter is not None and searchText not in self.lastSearchedTreeFilter: self.fileTreeModel = TreeModelFile( treeInput=self.chosenUserTreeFile, foldIcon=self.foldIcon, fileIcon=self.fileIcon) newTreeDict = self.fileTreeModel.filterTree(searchText) if newTreeDict["#_size"] != 0: with open(abspath("./files/temp/treeFilterTemp.json"), "w") as filteredTree: json.dump(newTreeDict, filteredTree) self.chosenUserTreeFile = self.fileTreeModel.treeInput self.lastSearchedTreeFilter = searchText self.renderTree(filteredTree.name) def prepareDownloadItemsAction(self): self.disableButtons() try: self.thread = QtCore.QThread() self.worker = DownLoadWorker(self.chosenUserTreeFile, self.fileTreeModel) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.thread.start() self.thread.finished.connect( lambda: {self.renderTree(self.chosenUserTreeFile)}) except Exception as e: print(e) self.enableButtons() def setupUi(self): self.horizontalLayout.setObjectName("horizontalLayout") self.usersFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.usersFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.usersFrame.setObjectName("usersFrame") self.verticalLayout_3.setObjectName("verticalLayout_3") self.browseUsersFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.browseUsersFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.browseUsersFrame.setObjectName("browseUsersFrame") self.horizontalLayout_2.setObjectName("horizontalLayout_2") font = QtGui.QFont() font.setFamily("Verdana") font.setPointSize(9) self.browseUsersLabel.setFont(font) self.browseUsersLabel.setObjectName("browseUsersLabel") self.horizontalLayout_2.addWidget(self.browseUsersLabel) self.browseUsersLineEdit.setObjectName("browseUsersLineEdit") self.horizontalLayout_2.addWidget(self.browseUsersLineEdit) self.verticalLayout_3.addWidget(self.browseUsersFrame) self.usersList.viewport().setProperty( "cursor", QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.usersList.setObjectName("usersList") self.horizontalLayout.addWidget(self.usersFrame) self.buttonsFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.buttonsFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.buttonsFrame.setObjectName("buttonsFrame") self.verticalLayout_4.setObjectName("verticalLayout_4") spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout_4.addItem(spacerItem) self.downloadButton.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.downloadButton.setLayoutDirection(QtCore.Qt.RightToLeft) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/buttonIcons/downloadIcon"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.downloadButton.setIcon(icon) self.downloadButton.setIconSize(QtCore.QSize(15, 15)) self.downloadButton.setObjectName("downloadButton") self.verticalLayout_4.addWidget(self.downloadButton) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout_4.addItem(spacerItem1) self.horizontalLayout.addWidget(self.buttonsFrame) self.treeFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.treeFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.treeFrame.setObjectName("treeFrame") self.verticalLayout_5.setObjectName("verticalLayout_5") self.browseFileFrame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.browseFileFrame.setFrameShadow(QtWidgets.QFrame.Raised) self.browseFileFrame.setObjectName("browseFileFrame") self.horizontalLayout_4.setObjectName("horizontalLayout_4") font = QtGui.QFont() font.setFamily("Verdana") font.setPointSize(9) self.browseFileLabel.setFont(font) self.browseFileLabel.setObjectName("browseFileLabel") self.horizontalLayout_4.addWidget(self.browseFileLabel) self.browseFileLineEdit.setObjectName("browseFileLineEdit") self.horizontalLayout_4.addWidget(self.browseFileLineEdit) self.verticalLayout_5.addWidget(self.browseFileFrame) self.fileTreeView.viewport().setProperty( "cursor", QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.fileTreeView.setObjectName("fileTreeView") self.verticalLayout_5.addWidget(self.fileTreeView) self.horizontalLayout.addWidget(self.treeFrame) self.browseUsersLabel.setBuddy(self.browseUsersLineEdit) self.browseFileLabel.setBuddy(self.browseFileLineEdit) self.browseFileLineEdit.setStyleSheet( 'background-color: rgb(255, 255, 255);') self.browseUsersLineEdit.setStyleSheet( 'background-color: rgb(255, 255, 255);') self.usersList.setStyleSheet('background-color: rgb(255, 255, 255);') self.fileTreeView.setStyleSheet( 'background-color: rgb(255, 255, 255);') QtCore.QMetaObject.connectSlotsByName(self) self.browseUsersLabel.setText("Browse Users:") self.downloadButton.setText("DownLoad") self.browseFileLabel.setText("Browse Files:") self.fileIcon.addPixmap(QtGui.QPixmap(":/windowIcons/fileIcon"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.foldIcon.addPixmap(QtGui.QPixmap(":/windowIcons/foldIcon"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.disableButtons() self.fillUsersList(abspath('./files/users_list.txt')) self.usersList.clicked['QModelIndex'].connect(self.fillStructTree) self.browseUsersLineEdit.textChanged.connect(self.filterUsersList) self.browseFileLineEdit.textChanged.connect(self.simpleTreeFilter) self.downloadButton.clicked.connect(self.prepareDownloadItemsAction)
class Employee(QWidget): """ Klasa odpowiedzialna za widget Zmiany hasła """ def __init__(self, parent, db): super(QWidget, self).__init__(parent) self.btn_usun = QPushButton('Usuń') self.btn_modyfikuj = QPushButton('Modyfikuj') self.id_modify = -1 self.view = QTableView() self.cb_pracownik = QCheckBox('Pracownik') self.txt_login = QLineEdit() self.txt_nazwisko = QLineEdit() self.txt_imie = QLineEdit() self.parent = parent self.layout = QHBoxLayout() self.lbl_wysz = QLabel("Wyszukaj:") self.txt_wysz = QLineEdit(self) self.proxy = QSortFilterProxyModel(self) # Parametry połączenia z bazą self.model = QSqlTableModel(self, db) self.initUI() def initUI(self): """ Inicjuje UI """ fbox = QFormLayout() fbox.addRow(self.lbl_wysz, self.txt_wysz) self.txt_wysz.textChanged.connect(self.searching) self.table_init() # Pokazuje wszystko # self.model.select() group_box = QGroupBox("Edycja danych użytkownika") fbox2 = QFormLayout() lbl_imie = QLabel('Imię:') lbl_nazwisko = QLabel('Nazwisko:') lbl_login = QLabel('Login:'******'Dodaj') self.btn_modyfikuj.setDisabled(True) self.btn_usun.setDisabled(True) fbox2.addRow(lbl_imie, self.txt_imie) fbox2.addRow(lbl_nazwisko, self.txt_nazwisko) fbox2.addRow(lbl_login, self.txt_login) fbox2.addRow(self.cb_pracownik) lhbox = QHBoxLayout() lhbox.addWidget(self.btn_usun) lhbox.addSpacing(35) lhbox.addWidget(self.btn_modyfikuj) lhbox.addSpacing(35) lhbox.addWidget(btn_dodaj) fbox2.addRow(lhbox) group_box.setLayout(fbox2) fbox.addRow(group_box) # Formatka dni self.group_box_dni = QGroupBox('Godziny pracy') fbox_dni = QFormLayout() lhbox_pon = QHBoxLayout() lhbox_wt = QHBoxLayout() lhbox_sr = QHBoxLayout() lhbox_czw = QHBoxLayout() lhbox_pt = QHBoxLayout() lhbox_sob = QHBoxLayout() lbl_pon = QLabel('Poniedziałek') lbl_wt = QLabel('Wtorek') lbl_sr = QLabel('Środa') lbl_czw = QLabel('Czwartek') lbl_pt = QLabel('Piątek') lbl_sob = QLabel('Sobota') self.txt_pon_od = QLineEdit() self.txt_pon_do = QLineEdit() self.txt_wt_od = QLineEdit() self.txt_wt_do = QLineEdit() self.txt_sr_od = QLineEdit() self.txt_sr_do = QLineEdit() self.txt_czw_od = QLineEdit() self.txt_czw_do = QLineEdit() self.txt_pt_od = QLineEdit() self.txt_pt_do = QLineEdit() self.txt_sob_od = QLineEdit() self.txt_sob_do = QLineEdit() self.pola = (self.txt_pon_od, self.txt_pon_do, self.txt_wt_od, self.txt_wt_do, self.txt_sr_od, self.txt_sr_do, self.txt_czw_od, self.txt_czw_do, self.txt_pt_od, self.txt_pt_do, self.txt_sob_od, self.txt_sob_do) lhbox_pon.addWidget(self.txt_pon_od) lhbox_pon.addSpacing(30) lhbox_pon.addWidget(self.txt_pon_do) lhbox_wt.addWidget(self.txt_wt_od) lhbox_wt.addSpacing(30) lhbox_wt.addWidget(self.txt_wt_do) lhbox_sr.addWidget(self.txt_sr_od) lhbox_sr.addSpacing(30) lhbox_sr.addWidget(self.txt_sr_do) lhbox_czw.addWidget(self.txt_czw_od) lhbox_czw.addSpacing(30) lhbox_czw.addWidget(self.txt_czw_do) lhbox_pt.addWidget(self.txt_pt_od) lhbox_pt.addSpacing(30) lhbox_pt.addWidget(self.txt_pt_do) lhbox_sob.addWidget(self.txt_sob_od) lhbox_sob.addSpacing(30) lhbox_sob.addWidget(self.txt_sob_do) fbox_dni.addRow(lbl_pon, lhbox_pon) fbox_dni.addRow(lbl_wt, lhbox_wt) fbox_dni.addRow(lbl_sr, lhbox_sr) fbox_dni.addRow(lbl_czw, lhbox_czw) fbox_dni.addRow(lbl_pt, lhbox_pt) fbox_dni.addRow(lbl_sob, lhbox_sob) group_box_szablon = QGroupBox('Szablony') btn1 = QPushButton('7-15') btn2 = QPushButton('8-16') btn3 = QPushButton('9-17') btn4 = QPushButton('10-18') vbox = QVBoxLayout() vbox.addWidget(btn1) vbox.addWidget(btn2) vbox.addWidget(btn3) vbox.addWidget(btn4) group_box_szablon.setLayout(vbox) hbox_dni = QHBoxLayout() hbox_dni.addLayout(fbox_dni) hbox_dni.addWidget(group_box_szablon) self.group_box_dni.setLayout(hbox_dni) fbox.addRow(self.group_box_dni) self.group_box_dni.setVisible(False) self.view.clicked.connect(self.change) btn_dodaj.clicked.connect(self.add) self.btn_modyfikuj.clicked.connect(self.modify) self.btn_usun.clicked.connect(self.remove) self.cb_pracownik.stateChanged.connect(self.changeGroupBox) btn1.clicked.connect(lambda: self.hour(7)) btn2.clicked.connect(lambda: self.hour(8)) btn3.clicked.connect(lambda: self.hour(9)) btn4.clicked.connect(lambda: self.hour(10)) self.layout.addLayout(fbox) self.layout.addWidget(self.view) self.setLayout(self.layout) self.show() def hour(self, godz): """ Wypełnia godzinami odpowiednie pola :param godz: int godzina rozpoczęcia """ for i, value in enumerate(self.pola): if i % 2 == 0: value.setText(str(timedelta(hours=godz))) else: value.setText(str(timedelta(hours=godz + 8))) def changeGroupBox(self, state): """ Sprawdza, czy zaznaczono checkbox pracownik :param state: status pola pracownik """ if state == Qt.Checked: self.group_box_dni.setVisible(True) else: self.group_box_dni.setVisible(False) def table_init(self): """ Inicjuje wygląd tabeli """ self.model.setTable('uzytkownik') query = QSqlQuery( 'SELECT uzytkownik_id, uzytkownik_nazwa, imie, nazwisko, pracownik FROM uzytkownik;' ) self.model.setQuery(query) self.proxy.setSourceModel(self.model) naglowki = { 'uzytkownik_id': 'ID', 'uzytkownik_nazwa': 'Login', 'imie': 'Imię', "nazwisko": 'Nazwisko', 'pracownik': 'Pracownik', } # 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]) # TODO Poprawić wiywietlanie kolumny Pracownik self.view.setSizeAdjustPolicy( QAbstractScrollArea.AdjustToContentsOnFirstShow) self.view.setSortingEnabled(True) self.view.setAlternatingRowColors(True) # Wczytanie danych self.view.setModel(self.proxy) self.view.hideColumn(0) self.view.sortByColumn(1, Qt.AscendingOrder) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) def if_checked(self, txt, q, val=None): """ Sprawdza poprawność wprowadzonych damych. :param val: wartości do zapytania :param q: zapytanie query MySql :param txt: komunikat """ if len(self.txt_imie.text()) < 2 or len( self.txt_nazwisko.text()) < 2 or len( self.txt_login.text()) < 5: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setText(txt) msg.setWindowTitle("Popraw dane") msg.exec_() return False else: print('Trwa zmiana w bazie danych') if val: print('Połączenie') query_to_db(q, val) else: print('Transakcja') return transaction_to_db(q) # Odświeżanie widoku tabeli self.model.select() self.view.reset() return True def employee_type(self): """ Sprawdza, czy dana osoba jest pracownikiem, czy nie. :return: int Pracownik """ return 1 if self.cb_pracownik.checkState() else 0 def add(self): """ Dodaje nową osobę do bazy danych i odświeża widok. """ tekst = "Dane zostały błędnie wprowadzone.\nLogin musi mieć minimum 5 znaków." # Dodanie nowego użytkownika query1 = 'INSERT INTO uzytkownik (imie, nazwisko, uzytkownik_nazwa, haslo, pracownik) VALUES (%s, %s, %s, ' \ 'sha(%s), %s)' val1 = (self.txt_imie.text(), self.txt_nazwisko.text(), self.txt_login.text(), self.txt_login.text(), self.employee_type()) # Dodanie godzin do pracownika if self.cb_pracownik.checkState(): query2 = 'INSERT INTO godziny (uzytkownik_id, pon_od, pon_do, wt_od, wt_do, sr_od, sr_do, czw_od, czw_do, pt_od, pt_do, sob_od, sob_do) VALUES (LAST_INSERT_ID(),"' + self.txt_pon_od.text( ) + '","' + self.txt_pon_do.text() + '","' + self.txt_wt_od.text( ) + '","' + self.txt_wt_do.text() + '","' + self.txt_sr_od.text( ) + '","' + self.txt_sr_do.text() + '","' + self.txt_czw_od.text( ) + '","' + self.txt_czw_do.text() + '","' + self.txt_pt_od.text( ) + '","' + self.txt_pt_do.text() + '","' + self.txt_sob_od.text( ) + '","' + self.txt_sob_do.text() + '");' val2 = None else: query2 = None val2 = None if self.if_checked(tekst, [(query1, val1), (query2, val2)]): msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setText('Dodano nowego użytkownika') msg.setWindowTitle("Dodano użytkownika") msg.exec_() else: msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setText('Dany użytkownik istnieje już w bazie') msg.setWindowTitle("Błąd!") msg.exec_() # Odświeżanie widoku tabeli self.model.select() self.view.reset() def modify(self): """ Modyfikuje bazę danych """ query = 'SELECT * FROM godziny WHERE uzytkownik_id = %s' val = (self.id_modify, ) wynik = query_to_db(query, val) test = 'Dane zostały błędnie zmodyfikowane.' query = 'UPDATE uzytkownik SET imie = %s, nazwisko = %s, uzytkownik_nazwa = %s, ' \ 'pracownik = %s WHERE uzytkownik_id = %s' val = (self.txt_imie.text(), self.txt_nazwisko.text(), self.txt_login.text(), self.employee_type(), self.id_modify) self.if_checked(test, query, val) if wynik and self.cb_pracownik.checkState(): query = 'UPDATE godziny SET pon_od = %s, pon_do = %s, wt_od = %s, wt_do = %s, sr_od = %s, sr_do = %s, ' \ 'czw_od = %s, czw_do = %s, pt_od = %s, pt_do = %s, sob_od = %s, sob_do = %s WHERE uzytkownik_id = %s;' val = (self.txt_pon_od.text(), self.txt_pon_do.text(), self.txt_wt_od.text(), self.txt_wt_do.text(), self.txt_sr_od.text(), self.txt_sr_do.text(), self.txt_czw_od.text(), self.txt_czw_do.text(), self.txt_pt_od.text(), self.txt_pt_do.text(), self.txt_sob_od.text(), self.txt_sob_do.text(), self.id_modify) query_to_db(query, val) elif self.cb_pracownik.checkState(): query = 'INSERT INTO godziny SET uzytkownik_id = %s, pon_od = %s, pon_do = %s, wt_od = %s, wt_do = %s, ' \ 'sr_od = %s, ' \ 'sr_do = %s, ' \ 'czw_od = %s, czw_do = %s, pt_od = %s, pt_do = %s, sob_od = %s, sob_do = %s; ' val = (self.id_modify, self.txt_pon_od.text(), self.txt_pon_do.text(), self.txt_wt_od.text(), self.txt_wt_do.text(), self.txt_sr_od.text(), self.txt_sr_do.text(), self.txt_czw_od.text(), self.txt_czw_do.text(), self.txt_pt_od.text(), self.txt_pt_do.text(), self.txt_sob_od.text(), self.txt_sob_do.text()) query_to_db(query, val) msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setText('Zmodyfikowano dane użytkownika') msg.setWindowTitle("Zmodyfikowano użytkownika") msg.exec_() # Odświeżanie widoku tabeli self.model.select() self.view.reset() def remove(self): """ Usuwa dane z bazy danych """ test = 'Błąd! Nie można usunąć danego użytkownika!' query1 = 'DELETE FROM uzytkownik WHERE uzytkownik_id = %s' val = (self.id_modify, ) query2 = 'DELETE FROM godziny WHERE uzytkownik_id = %s' query3 = 'DELETE FROM uzytkownik_usluga WHERE uzytkownik_id = %s' query4 = 'DELETE FROM wizyty WHERE uzytkownik_id = %s' if self.id_modify == 1: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText('Błąd! Nie można usunąć domyślnego użytkownika') msg.setWindowTitle("Popraw dane") msg.exec_() else: ret = QMessageBox.question( self, 'Usuwanie użytkownika', "Czy na pewno chcesz usunąć danego użytkownika?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if ret == QMessageBox.Yes: if self.if_checked(test, [(query4, val), (query3, val), (query2, val), (query1, val)]): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText('Użytkownik został usunięty') msg.setWindowTitle("Usunięto") msg.exec_() self.txt_imie.setText('') self.txt_login.setText('') self.txt_nazwisko.setText('') if self.cb_pracownik.checkState(): self.cb_pracownik.toggle() # Odświeżanie widoku tabeli self.model.select() self.view.reset() def change(self): """ Metoda edytująca zaznaczone wiersze - Wstawia wartości z wierszy w odpowiednie pola """ index = (self.view.selectionModel().currentIndex()) value = index.sibling(index.row(), index.column()).data() self.id_modify = index.sibling(index.row(), 0).data() self.txt_imie.setText(index.sibling(index.row(), 2).data()) self.txt_nazwisko.setText(index.sibling(index.row(), 3).data()) self.txt_login.setText(index.sibling(index.row(), 1).data()) if self.id_modify >= 0 and self.txt_imie.text( ) and self.txt_login.text() and self.txt_nazwisko.text(): self.btn_modyfikuj.setEnabled(True) self.btn_usun.setEnabled(True) else: self.btn_usun.setDisabled(True) self.btn_modyfikuj.setDisabled(True) if index.sibling(index.row(), 4).data() == 1: if not self.cb_pracownik.checkState(): self.cb_pracownik.toggle() else: if self.cb_pracownik.checkState(): for value in self.pola: value.setText('') self.cb_pracownik.toggle() if self.cb_pracownik.checkState(): query = 'SELECT * FROM godziny WHERE uzytkownik_id = %s' val = (self.id_modify, ) wynik = query_to_db(query, val) for i, value in enumerate(self.pola, 2): if wynik: value.setText(str(wynik[i])) else: value.setText('') @pyqtSlot(str) def searching(self, text): """ Wyszukuje po wszystkich kolumnach tabeli :param text: """ search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(search) # Odpowiedzialne za kolumnę, po której filtruje self.proxy.setFilterKeyColumn(-1)
class IPTagsSelectDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.app = QApplication.instance() self.destTags = [] self.allTagsModel = UneditableStringListModel(self) self.destTagsModel = UneditableStringListModel(self) self.allTagsProxyModel = QSortFilterProxyModel(self) self.allTagsProxyModel.setSourceModel(self.allTagsModel) self.ui = ui_iptagsmanager.Ui_IPTagsDialog() self.ui.setupUi(self) self.ui.destTagsView.setModel(self.destTagsModel) self.ui.destTagsView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.ui.destTagsView.doubleClicked.connect(self.onTagDoubleClicked) self.ui.addTagButton.clicked.connect(lambda: ensure(self.addTag())) self.ui.lineEditTag.textChanged.connect(self.onTagEditChanged) self.ui.lineEditTag.setValidator( QRegExpValidator(QRegExp(r'[A-Za-z0-9-_@#]+'))) self.ui.lineEditTag.setMaxLength(128) self.ui.tagItButton.clicked.connect(self.onTagObject) self.ui.untagItButton.clicked.connect(self.untagObject) self.ui.okButton.clicked.connect(lambda: ensure(self.validate())) self.ui.noTagsButton.clicked.connect(self.reject) self.setMinimumSize(self.app.desktopGeometry.width() / 2, (2 * self.app.desktopGeometry.height()) / 3) def onTagEditChanged(self, text): self.allTagsProxyModel.setFilterRegExp(text) self.ui.allTagsView.clearSelection() def onTagDoubleClicked(self, idx): ensure(self.tagObject([idx])) def onTagObject(self): ensure(self.tagObject()) def untagObject(self): try: for idx in self.ui.destTagsView.selectedIndexes(): tag = self.destTagsModel.data(idx, Qt.DisplayRole) if tag: tagList = self.destTagsModel.stringList() tagList.remove(tag) self.destTagsModel.setStringList(tagList) except Exception: pass async def tagObject(self, indexes=None): if indexes is None: indexes = self.ui.allTagsView.selectedIndexes() for idx in indexes: tag = self.allTagsProxyModel.data(idx, Qt.DisplayRole) if tag and tag not in self.destTagsModel.stringList(): self.destTagsModel.setStringList( self.destTagsModel.stringList() + [tag]) async def initDialog(self): await self.updateAllTags() async def addTag(self): tagname = self.ui.lineEditTag.text() if not tagname: return await database.ipTagAdd(ipTagsFormat(tagname)) self.ui.lineEditTag.clear() await self.updateAllTags() async def updateAllTags(self): tags = [t.name for t in await database.ipTagsAll()] self.allTagsModel.setStringList(tags) self.ui.allTagsView.setModel(self.allTagsProxyModel) self.allTagsProxyModel.sort(0) async def validate(self): self.destTags = self.destTagsModel.stringList() self.done(1)
class Wyswietl(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) self.parent = parent self.proxy = QSortFilterProxyModel(self) self.edit_wysz = QLineEdit(self) self.combo_typ = QComboBox(self) self.lbl_wysz = QLabel("Wyszukaj") self.lbl_typ = QLabel("Wybierz typ narzędzia:") self.table = QTableView(self) sciezka = czy_istnieje() db = QSqlDatabase.addDatabase('QSQLITE') db.setDatabaseName(sciezka) if db.open(): print('Otworzono bazę danych') self.model = QSqlTableModel(self, db) self.formularz = QGroupBox("Wyświetl narzędzia") self.initUI() def initUI(self): typy_narzedzi = [ 'Brak', 'Frez palcowy', 'Frez płytkowy (głowica)', 'Gwintownik', 'Nóż tokarski', # 'Oprawka', 'Piła', 'Pozostałe', 'Rozwiertak', 'Wiertło', 'Wiertło składane', 'Wygniatak' ] self.widok() self.combo_typ.addItems(typy_narzedzi) cancel_button = QPushButton("Cofnij") hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(cancel_button) l_h = QHBoxLayout() l_h.addWidget(self.lbl_typ) l_h.addWidget(self.combo_typ) l_h2 = QHBoxLayout() l_h2.addWidget(self.lbl_wysz) l_h2.addWidget(self.edit_wysz) layout_v = QVBoxLayout() layout_v.addLayout(l_h) layout_v.addLayout(l_h2) layout_v.addWidget(self.table) self.proxy.setSourceModel(self.model) self.table.setModel(self.proxy) main_layout = QVBoxLayout() self.formularz.setLayout(layout_v) main_layout.addWidget(self.formularz) main_layout.addLayout(hbox) self.setLayout(main_layout) cancel_button.clicked.connect(self.anulowanie) self.edit_wysz.textChanged.connect(self.wyszukiwanie) self.combo_typ.activated[str].connect(self.onActiveNarz) # Menu kontekstowe własne self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.prawoklik) def prawoklik(self): menu = QMenu(self) if self.model.rowCount(): akcja = QAction('Usuń narzędzie', self) akcja.triggered.connect(self.usun_wiersz) menu.addAction(akcja) menu.exec_(QCursor.pos()) def usun_wiersz(self): ok = QMessageBox.question(self, 'Potwierdzenie', 'Czy na pewno chcesz usunąć narzędzie?', QMessageBox.Ok, QMessageBox.Cancel) if ok == QMessageBox.Ok: selected = self.table.currentIndex() self.model.removeRow(selected.row()) self.model.submitAll() self.model.select() self.parent.statusBar().showMessage("Usunięto narzędzie", 10000) def onActiveNarz(self, tekst): slownik = { 'Frez palcowy': 'frezy_palcowe', 'Frez płytkowy (głowica)': 'frezy_plytkowe', 'Gwintownik': 'gwintowniki', 'Nóż tokarski': 'noze_tokarskie', 'Oprawka': 'oprawki', 'Piła': 'pily', 'Pozostałe': 'pozostale', 'Rozwiertak': 'rozwiertaki', 'Wiertło': 'wiertla', 'Wiertło składane': 'wiertla_skladane', 'Wygniatak': 'wygniataki', 'Brak': '' } naglowki = { 'idfrezy_palcowe': 'ID', 'symbol_freza': 'Symbol', 'producent_fr': 'Producent', 'srednica_fr': 'Średnica', 'dl_fr': 'Długość całkowita', 'dl_rob_fr': 'Długość robocza', 'idfrezy_plytkowe': 'ID', 'symbol_frez_pl': 'Symbol', 'producent_fp': 'Producent', 'srednica_fr_pl': 'Średnica', 'ilosc_plytek': 'Ilość płytek', 'symbol_pl': 'Symbol płytek', 'ilosc_krawedzi_pl': 'Ilość krawędzi płytki', 'idgwintowniki': 'ID', 'symbol_g': 'Symbol', 'producent_gw': 'Producent', 'rozmiar_gwintu': 'Rozmiar gwintu i skok', 'typ_gwintownika': 'Typ gwintownika', 'idnoze_tokarskie': 'ID', 'symbol_n': 'Symbol', 'producent_n': 'Producent', 'plytki_n': 'Symbol płytek', 'ilosc_krawedzi_pl_n': 'Ilość krawędzi', 'idpily': 'ID', 'symbol_p': 'Symbol', 'producent_pil': 'Producent', 'srednica_p': 'Średnica', 'grubosc_p': 'Grubość', 'rodzaj_pl_p': 'Symbol płytek', 'ilosc_pl_p': 'Ilość płytek', 'ilosc_kraw_p': 'Ilość krawędzi płytki', 'idpozostale': 'ID', 'symbol_poz': 'Symbol', 'producent_poz': 'Producent', 'srednica_poz': 'Średnica', 'ilosc_pl_poz': 'Ilość płytek', 'plytki_poz': 'Symbol płytek', 'idrozwiertaki': 'ID', 'symbol_r': 'Symbol', 'producent_roz': 'Producent', 'rozmiar_r': 'Rozmiar', 'idwiertla': 'ID', 'symbol_w': 'Symbol', 'producent_w': 'Producent', 'srednica_w': 'Średnica', 'dlugosc_w': 'Długość [mm]', 'idwiertla_skladane': 'ID', 'symbol_w_skl': 'Symbol', 'producent_ws': 'Producent', 'srednica_w_skl': 'Średnica', 'plytki_w_skl': 'Symbol płytek', 'idwygniataki': 'ID', 'symbol_wyg': 'Symbol', 'producent_wyg': 'Producent', 'rozmiar_gw': 'Rozmiar gwintu' } self.model.setTable(slownik[tekst]) self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.model.select() # 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]) @pyqtSlot(str) def wyszukiwanie(self, text): search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp ) self.proxy.setFilterRegExp(search) # Odpowiedzialne za kolumnę, po której filtruje self.proxy.setFilterKeyColumn(-1) def widok(self): # Ustawianie własciwości widoku self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.setModel(self.model) def anulowanie(self): self.parent.statusBar().clearMessage() from opcje_qt import Wewnatrz menu_gl = Wewnatrz(self.parent) self.parent.setCentralWidget(menu_gl)
class FontViewWidget(QWidget): def __init__(self, statusBar, config, *args, **kwargs): super(FontViewWidget, self).__init__(*args, **kwargs) self.statusBar = statusBar layout = QVBoxLayout(self) self.retButton = QToolButton(self) self.retButton.setIconSize(QSize(60, 60)) self.retButton.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.retButton.setMinimumSize(200, 100) self.retButton.setMaximumSize(200, 100) layout.addWidget(self.retButton) # 过滤输入框 layout.addWidget( QLineEdit(self, textChanged=self.doFilter, placeholderText='过滤...')) # Material Font self.listView = QListView(self) self.listView.setMouseTracking(True) self.listView.setViewMode(QListView.IconMode) self.listView.setMovement(QListView.Static) self.listView.setFlow(QListView.LeftToRight) self.listView.setWrapping(True) self.listView.setEditTriggers(QListView.NoEditTriggers) self.listView.setResizeMode(QListView.Adjust) self.listView.doubleClicked.connect(self.onDoubleClicked) self.listView.entered.connect(self.onEntered) self.dmodel = QStandardItemModel(self.listView) self.fmodel = QSortFilterProxyModel(self.listView) self.fmodel.setSourceModel(self.dmodel) self.fmodel.setFilterRole(Qt.ToolTipRole) self.listView.setModel(self.fmodel) layout.addWidget(self.listView) # 字体加载器 loader = config[0] # 添加Item fontMap = json.loads(open(config[1], 'rb').read().decode(encoding='utf_8', errors='ignore'), encoding='utf_8') for name, _ in fontMap.items(): item = QStandardItem(loader.icon(name), '') item.setData(name, Qt.ToolTipRole) item.setData(name, Qt.StatusTipRole) item.setTextAlignment(Qt.AlignCenter) item.setFlags(item.flags()) self.dmodel.appendRow(item) def doFilter(self, _): self.fmodel.setFilterRegExp(self.sender().text()) def onEntered(self, index): index = self.fmodel.mapToSource(index) text = index.data(Qt.ToolTipRole) if text: self.retButton.setText(text) self.retButton.setIcon(self.dmodel.itemFromIndex(index).icon()) def onDoubleClicked(self, index): index = self.fmodel.mapToSource(index) text = index.data(Qt.ToolTipRole) if text: QApplication.clipboard().setText(text) self.statusBar.showMessage('已复制: %s' % text)
class CreateDialogCodeDialog(QDialog, Ui_CreateDialogCodeDialog): """ Class implementing a dialog to generate code for a Qt4/Qt5 dialog. """ DialogClasses = { "QDialog", "QWidget", "QMainWindow", "QWizard", "QWizardPage", "QDockWidget", "QFrame", "QGroupBox", "QScrollArea", "QMdiArea", "QTabWidget", "QToolBox", "QStackedWidget" } Separator = 25 * "=" def __init__(self, formName, project, parent=None): """ Constructor @param formName name of the file containing the form (string) @param project reference to the project object @param parent parent widget if the dialog (QWidget) """ super(CreateDialogCodeDialog, self).__init__(parent) self.setupUi(self) self.okButton = self.buttonBox.button(QDialogButtonBox.Ok) self.slotsView.header().hide() self.project = project self.formFile = formName filename, ext = os.path.splitext(self.formFile) self.srcFile = '{0}{1}'.format( filename, self.project.getDefaultSourceExtension()) self.slotsModel = QStandardItemModel() self.proxyModel = QSortFilterProxyModel() self.proxyModel.setDynamicSortFilter(True) self.proxyModel.setSourceModel(self.slotsModel) self.slotsView.setModel(self.proxyModel) # initialize some member variables self.__initError = False self.__module = None if os.path.exists(self.srcFile): vm = e5App().getObject("ViewManager") ed = vm.getOpenEditor(self.srcFile) if ed and not vm.checkDirty(ed): self.__initError = True return try: splitExt = os.path.splitext(self.srcFile) if len(splitExt) == 2: exts = [splitExt[1]] else: exts = None from Utilities import ModuleParser self.__module = ModuleParser.readModule( self.srcFile, extensions=exts, caching=False) except ImportError: pass if self.__module is not None: self.filenameEdit.setText(self.srcFile) classesList = [] vagueClassesList = [] for cls in list(self.__module.classes.values()): if not set(cls.super).isdisjoint( CreateDialogCodeDialog.DialogClasses): classesList.append(cls.name) else: vagueClassesList.append(cls.name) classesList.sort() self.classNameCombo.addItems(classesList) if vagueClassesList: if classesList: self.classNameCombo.addItem( CreateDialogCodeDialog.Separator) self.classNameCombo.addItems(sorted(vagueClassesList)) if os.path.exists(self.srcFile) and \ self.__module is not None and \ self.classNameCombo.count() == 0: self.__initError = True E5MessageBox.critical( self, self.tr("Create Dialog Code"), self.tr( """The file <b>{0}</b> exists but does not contain""" """ any classes.""").format(self.srcFile)) self.okButton.setEnabled(self.classNameCombo.count() > 0) self.__updateSlotsModel() def initError(self): """ Public method to determine, if there was an initialzation error. @return flag indicating an initialzation error (boolean) """ return self.__initError def __objectName(self): """ Private method to get the object name of the dialog. @return object name (string) """ try: dlg = uic.loadUi( self.formFile, package=self.project.getProjectPath()) return dlg.objectName() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __className(self): """ Private method to get the class name of the dialog. @return class name (sting) """ try: dlg = uic.loadUi( self.formFile, package=self.project.getProjectPath()) return dlg.metaObject().className() except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) return "" def __signatures(self): """ Private slot to get the signatures. @return list of signatures (list of strings) """ if self.__module is None: return [] signatures = [] clsName = self.classNameCombo.currentText() if clsName: cls = self.__module.classes[clsName] for meth in list(cls.methods.values()): if meth.name.startswith("on_"): if meth.pyqtSignature is not None: sig = ", ".join( [bytes(QMetaObject.normalizedType(t)).decode() for t in meth.pyqtSignature.split(",")]) signatures.append("{0}({1})".format(meth.name, sig)) else: signatures.append(meth.name) return signatures def __mapType(self, type_): """ Private method to map a type as reported by Qt's meta object to the correct Python type. @param type_ type as reported by Qt (QByteArray) @return mapped Python type (string) """ mapped = bytes(type_).decode() if self.project.getProjectLanguage() != "Python2" or \ self.project.getProjectType == "PySide": # 1. check for const mapped = mapped.replace("const ", "") # 2. check for * mapped = mapped.replace("*", "") # 3. replace QString and QStringList mapped = mapped.replace("QStringList", "list")\ .replace("QString", "str") # 4. replace double by float mapped = mapped.replace("double", "float") return mapped def __updateSlotsModel(self): """ Private slot to update the slots tree display. """ self.filterEdit.clear() try: dlg = uic.loadUi( self.formFile, package=self.project.getProjectPath()) objects = dlg.findChildren(QWidget) + dlg.findChildren(QAction) signatureList = self.__signatures() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) for obj in objects: name = obj.objectName() if not name or name.startswith("qt_"): # ignore un-named or internal objects continue metaObject = obj.metaObject() className = metaObject.className() itm = QStandardItem("{0} ({1})".format(name, className)) self.slotsModel.appendRow(itm) for index in range(metaObject.methodCount()): metaMethod = metaObject.method(index) if metaMethod.methodType() == QMetaMethod.Signal: if qVersion() >= "5.0.0": itm2 = QStandardItem("on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()).decode())) else: itm2 = QStandardItem("on_{0}_{1}".format( name, metaMethod.signature())) itm.appendRow(itm2) if self.__module is not None: if qVersion() >= "5.0.0": method = "on_{0}_{1}".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0]) else: method = "on_{0}_{1}".format( name, metaMethod.signature().split("(")[0]) method2 = "{0}({1})".format( method, ", ".join( [self.__mapType(t) for t in metaMethod.parameterTypes()])) if method2 in signatureList or \ method in signatureList: itm2.setFlags(Qt.ItemFlags(Qt.ItemIsEnabled)) itm2.setCheckState(Qt.Checked) itm2.setForeground(QBrush(Qt.blue)) continue returnType = self.__mapType( metaMethod.typeName().encode()) if returnType == 'void': returnType = "" parameterTypesList = [ self.__mapType(t) for t in metaMethod.parameterTypes()] pyqtSignature = ", ".join(parameterTypesList) parameterNames = metaMethod.parameterNames() if parameterNames: for index in range(len(parameterNames)): if not parameterNames[index]: parameterNames[index] = \ QByteArray("p{0:d}".format(index) .encode("utf-8")) parameterNamesList = [bytes(n).decode() for n in parameterNames] methNamesSig = ", ".join(parameterNamesList) if methNamesSig: if qVersion() >= "5.0.0": pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0], methNamesSig) else: pythonSignature = \ "on_{0}_{1}(self, {2})".format( name, metaMethod.signature().split("(")[0], methNamesSig) else: if qVersion() >= "5.0.0": pythonSignature = "on_{0}_{1}(self)".format( name, bytes(metaMethod.methodSignature()) .decode().split("(")[0]) else: pythonSignature = "on_{0}_{1}(self)".format( name, metaMethod.signature().split("(")[0]) itm2.setData(pyqtSignature, pyqtSignatureRole) itm2.setData(pythonSignature, pythonSignatureRole) itm2.setData(returnType, returnTypeRole) itm2.setData(parameterTypesList, parameterTypesListRole) itm2.setData(parameterNamesList, parameterNamesListRole) itm2.setFlags(Qt.ItemFlags( Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable) ) itm2.setCheckState(Qt.Unchecked) self.slotsView.sortByColumn(0, Qt.AscendingOrder) except (AttributeError, ImportError, xml.etree.ElementTree.ParseError) as err: E5MessageBox.critical( self, self.tr("uic error"), self.tr( """<p>There was an error loading the form <b>{0}</b>""" """.</p><p>{1}</p>""").format(self.formFile, str(err))) def __generateCode(self): """ Private slot to generate the code as requested by the user. """ # first decide on extension if self.filenameEdit.text().endswith(".py") or \ self.filenameEdit.text().endswith(".pyw"): self.__generatePythonCode() elif self.filenameEdit.text().endswith(".rb"): pass # second decide on project language elif self.project.getProjectLanguage() in ["Python2", "Python3"]: self.__generatePythonCode() elif self.project.getProjectLanguage() == "Ruby": pass else: # assume Python (our global default) self.__generatePythonCode() def __generatePythonCode(self): """ Private slot to generate Python code as requested by the user. """ # init some variables sourceImpl = [] appendAtIndex = -1 indentStr = " " slotsCode = [] if self.__module is None: # new file try: if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py2.tmpl") elif self.project.getProjectType() == "PyQt5": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py2.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py2.tmpl") else: if self.project.getProjectType() == "PySide": tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyside.py.tmpl") elif self.project.getProjectType() in [ "PyQt5", "E6Plugin"]: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt5.py.tmpl") else: tmplName = os.path.join( getConfig('ericCodeTemplatesDir'), "impl_pyqt.py.tmpl") tmplFile = open(tmplName, 'r', encoding="utf-8") template = tmplFile.read() tmplFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr( """<p>Could not open the code template file""" """ "{0}".</p><p>Reason: {1}</p>""") .format(tmplName, str(why))) return objName = self.__objectName() if objName: template = template\ .replace( "$FORMFILE$", os.path.splitext(os.path.basename(self.formFile))[0])\ .replace("$FORMCLASS$", objName)\ .replace("$CLASSNAME$", self.classNameCombo.currentText())\ .replace("$SUPERCLASS$", self.__className()) sourceImpl = template.splitlines(True) appendAtIndex = -1 # determine indent string for line in sourceImpl: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break else: # extend existing file try: srcFile = open(self.srcFile, 'r', encoding="utf-8") sourceImpl = srcFile.readlines() srcFile.close() if not sourceImpl[-1].endswith("\n"): sourceImpl[-1] = "{0}{1}".format(sourceImpl[-1], "\n") except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr( """<p>Could not open the source file "{0}".</p>""" """<p>Reason: {1}</p>""") .format(self.srcFile, str(why))) return cls = self.__module.classes[self.classNameCombo.currentText()] if cls.endlineno == len(sourceImpl) or cls.endlineno == -1: appendAtIndex = -1 # delete empty lines at end while not sourceImpl[-1].strip(): del sourceImpl[-1] else: appendAtIndex = cls.endlineno - 1 while not sourceImpl[appendAtIndex].strip(): appendAtIndex -= 1 appendAtIndex += 1 # determine indent string for line in sourceImpl[cls.lineno:cls.endlineno + 1]: if line.lstrip().startswith("def __init__"): indentStr = line.replace(line.lstrip(), "") break # do the coding stuff if self.project.getProjectLanguage() == "Python2": if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' elif self.project.getProjectType() == "PyQt5": pyqtSignatureFormat = '@pyqtSlot({0})' else: pyqtSignatureFormat = '@pyqtSignature("{0}")' else: if self.project.getProjectType() == "PySide": pyqtSignatureFormat = '@Slot({0})' else: pyqtSignatureFormat = '@pyqtSlot({0})' for row in range(self.slotsModel.rowCount()): topItem = self.slotsModel.item(row) for childRow in range(topItem.rowCount()): child = topItem.child(childRow) if child.checkState() and \ child.flags() & Qt.ItemFlags(Qt.ItemIsUserCheckable): slotsCode.append('{0}\n'.format(indentStr)) slotsCode.append('{0}{1}\n'.format( indentStr, pyqtSignatureFormat.format( child.data(pyqtSignatureRole)))) slotsCode.append('{0}def {1}:\n'.format( indentStr, child.data(pythonSignatureRole))) indentStr2 = indentStr * 2 slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append( '{0}Slot documentation goes here.\n'.format( indentStr2)) if child.data(returnTypeRole) or \ child.data(parameterTypesListRole): slotsCode.append('{0}\n'.format(indentStr2)) if child.data(parameterTypesListRole): for name, type_ in zip( child.data(parameterNamesListRole), child.data(parameterTypesListRole)): slotsCode.append( '{0}@param {1} DESCRIPTION\n'.format( indentStr2, name)) slotsCode.append('{0}@type {1}\n'.format( indentStr2, type_)) if child.data(returnTypeRole): slotsCode.append( '{0}@returns DESCRIPTION\n'.format( indentStr2)) slotsCode.append('{0}@rtype {1}\n'.format( indentStr2, child.data(returnTypeRole))) slotsCode.append('{0}"""\n'.format(indentStr2)) slotsCode.append('{0}# {1}: not implemented yet\n'.format( indentStr2, "TODO")) slotsCode.append('{0}raise NotImplementedError\n'.format( indentStr2)) if appendAtIndex == -1: sourceImpl.extend(slotsCode) else: sourceImpl[appendAtIndex:appendAtIndex] = slotsCode # write the new code try: if self.project.useSystemEol(): newline = None else: newline = self.project.getEolString() srcFile = open(self.filenameEdit.text(), 'w', encoding="utf-8", newline=newline) srcFile.write("".join(sourceImpl)) srcFile.close() except IOError as why: E5MessageBox.critical( self, self.tr("Code Generation"), self.tr("""<p>Could not write the source file "{0}".</p>""" """<p>Reason: {1}</p>""") .format(self.filenameEdit.text(), str(why))) return self.project.appendFile(self.filenameEdit.text()) @pyqtSlot(int) def on_classNameCombo_activated(self, index): """ Private slot to handle the activated signal of the classname combo. @param index index of the activated item (integer) """ if (self.classNameCombo.currentText() == CreateDialogCodeDialog.Separator): self.okButton.setEnabled(False) self.filterEdit.clear() self.slotsModel.clear() self.slotsModel.setHorizontalHeaderLabels([""]) else: self.okButton.setEnabled(True) self.__updateSlotsModel() def on_filterEdit_textChanged(self, text): """ Private slot called, when thext of the filter edit has changed. @param text changed text (string) """ re = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp2) self.proxyModel.setFilterRegExp(re) @pyqtSlot() def on_newButton_clicked(self): """ Private slot called to enter the data for a new dialog class. """ path, file = os.path.split(self.srcFile) objName = self.__objectName() if objName: dlg = NewDialogClassDialog(objName, file, path, self) if dlg.exec_() == QDialog.Accepted: className, fileName = dlg.getData() self.classNameCombo.clear() self.classNameCombo.addItem(className) self.srcFile = fileName self.filenameEdit.setText(self.srcFile) self.__module = None self.okButton.setEnabled(self.classNameCombo.count() > 0) def on_buttonBox_clicked(self, button): """ Private slot to handle the buttonBox clicked signal. @param button reference to the button that was clicked (QAbstractButton) """ if button == self.okButton: self.__generateCode() self.accept()
class FileChooser(BaseFileChooser): def __init__(self, **kwargs): super(FileChooser, self).__init__(**kwargs) self.options = PropDict() self.edit.textEdited.connect(self._onTextEdited) self.view.activated.connect(self._onActivated) # models self.rootChanger = RootChangerProxy() fsModel = QFileSystemModel(self) self.setModel(fsModel) self.filter = QSortFilterProxyModel() self.filter.setSourceModel(self.rootChanger) self.view.setModel(self.filter) def setModel(self, model): self.baseModel = model self.rootChanger.setSourceModel(self.baseModel) @Slot(str) def setRoot(self, path): self.root = path srcIdx = self.baseModel.setRootPath(path) self.rootChanger.setRootSource(srcIdx) self.view.setRootIndex(QModelIndex()) @Slot(str) def _onTextEdited(self, txt): elems = txt.rsplit('/', 1) if len(elems) == 2: dir, base = elems else: dir, base = '', elems[0] path = os.path.join(self.root, dir) self.rootChanger.setRootSource(self.baseModel.index(path)) self.filter.setFilterRegExp(QRegExp(base, Qt.CaseInsensitive, QRegExp.Wildcard)) if self.options.get('autosuggest'): names = [self.filter.data(self.filter.index(i, 0)).toString() for i in range(self.filter.rowCount(QModelIndex()))] names = [n[len(base):] for n in names] add = commonPrefix(names) cursor = self.edit.cursorPosition() self.edit.setText(self.edit.text()[:cursor] + add) self.edit.setSelection(cursor, len(self.edit.text())) @Slot(QModelIndex) def _onActivated(self, idx): idx = self.filter.mapToSource(idx) idx = self.rootChanger.mapToSource(idx) info = self.baseModel.fileInfo(idx) if info.isDir(): return path = info.absoluteFilePath() self.openFile(path)
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)
class UiRenters(QtWidgets.QDialog): def __init__(self): super().__init__() uic.loadUi('Ui/UiRenters.ui', self) self.add_renter_window = None self.edit_renter_window = None self.data_proxy = DataProxy() self.populate_model() self.search_comboBox.addItems(self.renters_model.headers) self.renters_count.setText(str(self.renters_model.rowCount(self))) self.add_new_renter_button.clicked.connect(self.add_new_renter_button_clicked) self.search_comboBox.currentIndexChanged.connect(self.change_search_column) self.search_input.textChanged.connect(self.search) self.renters_model.dataChanged.connect(self.update_renters_count) self.close_button.clicked.connect(self.close) self.renters_QTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.renters_QTableView.customContextMenuRequested.connect(self.show_context_menu) self.renters_QTableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.setModal(True) self.renters_QTableView.resizeColumnsToContents() # self.renters_QTableView.setSortingEnabled(True) # Shouldn't be enabled, screws indexes badly, and needs # tons of boiler plate code to work. self.show() def populate_model(self): self.renters_model = RenterModel(self.renters_QTableView) self.renters_proxy_model = QSortFilterProxyModel(self) self.renters_proxy_model.setSourceModel(self.renters_model) self.renters_QTableView.setModel(self.renters_proxy_model) def add_new_renter_button_clicked(self): self.add_renter_window = UiAddRenter(self) def change_search_column(self, index): self.renters_proxy_model.setFilterKeyColumn(index) def search(self, text): search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp) self.renters_proxy_model.setFilterRegExp(search) def update_renters_count(self): self.renters_count.setText(str(self.renters_model.rowCount(self))) def show_context_menu(self, event): index = self.renters_QTableView.indexAt(event) if index.isValid(): menu = QMenu(self) menu.addAction('Edit Renter', lambda: self.edit_renter(index)) menu.addAction('Remove Renter', lambda: self.remove_renter(index)) menu.popup(QCursor.pos()) def edit_renter(self, index): self.edit_renter_window = UiEditRenter(self, index, self.renters_model.get_data(index)) def remove_renter(self, index): renter_id = self.renters_model.get_data(index)['id'] if self.data_proxy.delete_renter(renter_id): self.populate_model() self.update_renters_count()
class MyWidget(QWidget): def __init__(self, parent=None): super().__init__(parent) horizontalLayout = QHBoxLayout() self.dayView = QTableView() self.dayView.setFrameShape(QFrame.Box) self.dayView.horizontalHeader().setStretchLastSection(True) self.dayView.verticalHeader().setVisible(False) horizontalLayout.addWidget(self.dayView) verticalLayout = QVBoxLayout() self.calendarWidget = QCalendarWidget() self.calendarWidget.setMinimumSize(QSize(250, 200)) self.calendarWidget.setMaximumSize(QSize(250, 200)) self.calendarWidget.setMinimumDate(QDate(2017, 1, 1)) self.calendarWidget.setMaximumDate(QDate(2030, 1, 1)) self.calendarWidget.selectionChanged.connect(self.dataChange) self.calendarWidget.setSelectedDate(QDate.currentDate()) verticalLayout.addWidget(self.calendarWidget) titleFV = QLabel('Food View') verticalLayout.addWidget(titleFV) self.filterLine = QLineEdit() self.filterLine.setMaximumSize(QSize(200, 25)) self.filterLine.textChanged.connect(self.filterChange) buttonAdd = QPushButton(QIcon("images/add.png"), '', None) buttonAdd.setMaximumSize(QSize(20, 30)) buttonAdd.clicked.connect(self.addFood) buttonDell = QPushButton(QIcon("images/del.png"), '', None) buttonDell.setMaximumSize(QSize(20, 30)) buttonDell.clicked.connect(self.delFood) lineEditLayout = QHBoxLayout() lineEditLayout.addWidget(self.filterLine) lineEditLayout.addWidget(buttonAdd) lineEditLayout.addWidget(buttonDell) verticalLayout.addLayout(lineEditLayout) self.foodView = QTableView() self.foodView.setMinimumSize(QSize(0, 0)) self.foodView.setMaximumSize(QSize(250, 1000)) self.foodView.verticalHeader().setVisible(False) self.foodView.horizontalHeader().setStretchLastSection(True) verticalLayout.addWidget(self.foodView) horizontalLayout.addLayout(verticalLayout) self.setLayout(horizontalLayout) model_in = QSqlRelationalTableModel() model_in.setEditStrategy(QSqlTableModel.OnFieldChange) model_in.setTable("intake_food") id_food = model_in.fieldIndex("id_food") date = model_in.fieldIndex("food_date") mass = model_in.fieldIndex("mass") # Set model, hide ID column model_in.setRelation(id_food, QSqlRelation("food", "id", "name")) model_in.setHeaderData(id_food, Qt.Horizontal, "Food") model_in.setHeaderData(date, Qt.Horizontal, "Date") model_in.setHeaderData(mass, Qt.Horizontal, "Mass") if not model_in.select(): self.showError(model_in.lastError()) return self.proxyModel_in = QSortFilterProxyModel() self.proxyModel_in.setSourceModel(model_in) self.proxyModel_in.setFilterKeyColumn(2) self.dayView.setItemDelegate(FlipProxyDelegate()) self.dayView.setModel(self.proxyModel_in) self.dayView.setColumnHidden(0, True) self.dayView.setColumnHidden(2, True) self.dayView.setSelectionMode(QAbstractItemView.SingleSelection) self.dayView.setContextMenuPolicy(Qt.CustomContextMenu) self.dayView.customContextMenuRequested.connect(self.ShowContextMenu) # filter day food by calendar widget self.dataChange() self.model_f = QSqlRelationalTableModel() self.model_f.setEditStrategy(QSqlTableModel.OnFieldChange) self.model_f.setTable("food") self.model_f.setHeaderData(1, Qt.Horizontal, "Food") self.model_f.setHeaderData(2, Qt.Horizontal, "Rate") if not self.model_f.select(): self.showError(self.model_f.lastError()) return self.proxyModel_f = QSortFilterProxyModel() self.proxyModel_f.setSourceModel(self.model_f) self.proxyModel_f.setFilterKeyColumn(1) self.foodView.setModel(self.proxyModel_f) self.foodView.setColumnHidden(0, True) self.foodView.setSelectionMode(QAbstractItemView.SingleSelection) self.foodView.setColumnWidth(1, 150) self.foodView.setColumnWidth(2, 90) def showError(self, err): QMessageBox.critical(self, "Unable to initialize Database", "Error initializing database: " + err.text()) def filterChange(self): regExp = QRegExp(self.filterLine.text(), Qt.CaseInsensitive, QRegExp.FixedString) self.proxyModel_f.setFilterRegExp(regExp) def dataChange(self): date = self.calendarWidget.selectedDate().toString('dd.MM.yyyy') regExp = QRegExp(date, Qt.CaseInsensitive, QRegExp.FixedString) self.proxyModel_in.setFilterRegExp(regExp) def addFood(self): self.model_f.insertRow(self.model_f.rowCount()) def delFood(self): self.model_f.removeRow(self.foodView.currentIndex().row()) self.model_f.select() def resizeEvent(self, event): self.dayView.setColumnWidth(1, self.dayView.width() * 0.7) self.dayView.setColumnWidth(3, self.dayView.width() * 0.2) QWidget.resizeEvent(self, event) def ShowContextMenu(self, pos): contextMenu = QMenu("Context menu", self) action1 = QAction("Add food eaten", self) contextMenu.addAction(action1) contextMenu.exec(self.mapToGlobal(pos))
class UiMainWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() uic.loadUi('Ui/UiMainWindow.ui', self) self.books_window = None self.renters_window = None self.add_book_window = None self.add_new_book_rent_window = None self.data_proxy = DataProxy() self.populate_model() self.search_comboBox.addItems(self.rented_books_model.headers) self.update_counters() self.btn_show_books.clicked.connect(self.show_books_clicked) self.btn_show_renters.clicked.connect(self.show_renters_clicked) self.add_new_book_rent_button.clicked.connect(self.add_new_book_rent_button_clicked) self.search_comboBox.currentIndexChanged.connect(self.change_search_column) self.search_input.textChanged.connect(self.search) self.rented_books_model.dataChanged.connect(self.update_counters) self.rented_books_QTableView.resizeColumnsToContents() # self.rented_books_QTableView.setSortingEnabled(True) self.rented_books_QTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.rented_books_QTableView.customContextMenuRequested.connect(self.show_context_menu) self.rented_books_QTableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.show() def populate_model(self): self.rented_books_model = RentedBookModel(self.rented_books_QTableView) self.rented_books_proxy_model = QSortFilterProxyModel(self) self.rented_books_proxy_model.setSourceModel(self.rented_books_model) self.rented_books_QTableView.setModel(self.rented_books_proxy_model) def show_books_clicked(self): self.books_window = UiBooks() def show_renters_clicked(self): self.renters_window = UiRenters() def add_new_book_rent_button_clicked(self): self.add_new_book_rent_window = UiAddBookRent(self) def change_search_column(self, index): self.rented_books_proxy_model.setFilterKeyColumn(index) def search(self, text): search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp) self.rented_books_proxy_model.setFilterRegExp(search) def show_context_menu(self, event): index = self.rented_books_QTableView.indexAt(event) if index.isValid(): menu = QMenu(self) menu.addAction('Remove Rent', lambda: self.remove_rent(index)) menu.popup(QCursor.pos()) def remove_rent(self, index): rent_id = self.rented_books_model.get_data(index)['id'] if self.data_proxy.delete_rented_book(rent_id): self.populate_model() self.update_counters() def update_rented_books_count(self): self.rented_books_count.setText(str(self.rented_books_model.rowCount(self))) def update_overdue_counter(self): self.overdue_books_count.setText(str(self.rented_books_model.overdue_counter())) def update_counters(self): self.update_rented_books_count() self.update_overdue_counter()
class NarzPoz(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) self.pozycja = 'Brak' self.proxy = QSortFilterProxyModel(self) self.proxy_poz = QSortFilterProxyModel(self) self.edit_wysz = QLineEdit(self) self.combo_typ = QComboBox(self) self.lbl_wysz = QLabel("Wyszukaj") self.lbl_typ = QLabel("Wybierz typ narzędzia:") self.combo_poz = QComboBox(self) self.lbl_poz = QLabel("Wybierz pozycję:") self.listaPozycji = [] self.table = QTableView(self) self.table_narz = QTableView(self) sciezka = czy_istnieje() db = QSqlDatabase.addDatabase('QSQLITE') db.setDatabaseName(sciezka) if db.open(): print('Otworzono bazę danych') self.model = QSqlTableModel(self, db) self.model_poz = QSqlTableModel(self, db) self.parent = parent self.formularz = QGroupBox("Przypisz narzędzia") self.initUI() def initUI(self): self.naglowki_kolumn() # todo dodać okno z wyborem oprawki po wyborze narzędzia typy_narzedzi = [ 'Brak', 'Frez palcowy', 'Frez płytkowy (głowica)', 'Gwintownik', 'Nóż tokarski', # 'Oprawka', 'Piła', 'Pozostałe', 'Rozwiertak', 'Wiertło', 'Wiertło składane', 'Wygniatak' ] self.widok() # Zatwierdzenie ok_button = QPushButton("Dodaj do pozycji") cancel_button = QPushButton("Cofnij") wydrukuj_btn = QPushButton("Wyeksportuj") usun_btn = QPushButton("Usuń pozycję") dodaj_btn = QPushButton("Dodaj pozycję") hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(ok_button) hbox.addWidget(cancel_button) # Layouty layout_v = QVBoxLayout() l_1 = QHBoxLayout() l_2 = QHBoxLayout() l_3 = QHBoxLayout() layout_h = QHBoxLayout() # Funkcje self.combo_typ.addItems(typy_narzedzi) self.combo_poz.addItems(self.listaPozycji) self.proxy_poz.setSourceModel(self.model_poz) self.table.setModel(self.proxy_poz) self.proxy.setSourceModel(self.model) self.table_narz.setModel(self.proxy) # Przyporzadkowanie l_1.addWidget(self.lbl_typ) l_1.addWidget(self.combo_typ) l_2.addWidget(self.lbl_wysz) l_2.addWidget(self.edit_wysz) l_3.addWidget(wydrukuj_btn) l_3.addWidget(usun_btn) l_3.addWidget(dodaj_btn) layout_h.addWidget(self.lbl_poz) layout_h.addWidget(self.combo_poz) layout_v.addLayout(layout_h, 1) layout_v.addLayout(l_1) layout_v.addLayout(l_2) layout_v.addLayout(l_3) layout_v.addWidget(self.table) layout_v.addWidget(self.table_narz) self.formularz.setLayout(layout_v) main_layout = QVBoxLayout() main_layout.addWidget(self.formularz) main_layout.addLayout(hbox) self.setLayout(main_layout) # connecty # ok_button.clicked.connect(self.dodaj) cancel_button.clicked.connect(self.anulowanie) dodaj_btn.clicked.connect(self.dodaj_poz) ok_button.clicked.connect(self.klikniecie) usun_btn.clicked.connect(self.usun_pozycje) wydrukuj_btn.clicked.connect(self.wydrukuj) self.edit_wysz.textChanged.connect(self.wyszukiwanie) self.combo_typ.activated[str].connect(self.onActiveNarz) self.combo_poz.activated[str].connect(self.onActivePoz) # Menu kontekstowe własne self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.prawoklik) def wydrukuj(self): poz_lista = [ 'Wykaz narzędzi ' + self.pozycja, "SELECT * FROM '" + self.pozycja + "'", 'Baza nie zawiera żadnych pozycji. Plik nie zostanie zapisany.', ] from gui import Window if self.pozycja != 'Brak': Window.export(self, poz_lista) self.parent.statusBar().showMessage("Wyeksportowano do pliku", 10000) else: QMessageBox.critical(self, 'Wybierz pozycję', 'Nie wybrano żadnej pozycji!', QMessageBox.Ok, QMessageBox.Ok) def naglowki_kolumn(self): # Nagłówki kolumn self.listaPozycji.append('Brak') for i in naglowki(): if "/" in i[0]: self.listaPozycji.append(i[0]) def usun_pozycje(self): text, ok = QInputDialog.getItem(self, 'Usuń pozycje', 'Wybierz pozycję do usunięcia', self.listaPozycji[1:], editable=False) if ok: if text != 'Brak': print(text) query = 'DROP TABLE "main"."' + text + '";' polaczenie(query) self.listaPozycji.clear() self.naglowki_kolumn() indeks = self.combo_poz.findText(text) self.combo_poz.removeItem(indeks) self.parent.statusBar().showMessage("Usunięto pozycję", 10000) else: msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowIcon(QIcon('icons/cow.png')) msg.setText("Wybierz poprawną pozycję") msg.setWindowTitle("Niewłaściwa pozycja") msg.exec_() self.usun_pozycje() def prawoklik(self): menu = QMenu(self) akcja = QAction('Usuń narzędzie', self) akcja.triggered.connect(self.usun_wiersz) menu.addAction(akcja) menu.exec_(QCursor.pos()) def usun_wiersz(self): selected = self.table.currentIndex() self.model_poz.removeRow(selected.row()) self.model_poz.submitAll() self.model_poz.select() self.parent.statusBar().showMessage("Usunięto narzędzie", 10000) def dodaj_poz(self): text, ok = QInputDialog.getText(self, 'Wprowadź pozycje', 'Pozycja:') if ok and text: query = 'CREATE TABLE IF NOT EXISTS "' + text + '" ("id_poz" INTEGER PRIMARY ' \ 'KEY AUTOINCREMENT, ' \ '"symbol_narz" TEXT, ' \ '"vc" INTEGER, "obroty" ' \ 'INTEGER, "fz" REAL, "posuw" ' \ 'INTEGER); ' print(query) polaczenie(query) self.listaPozycji.clear() self.combo_poz.addItem(text) self.naglowki_kolumn() self.parent.statusBar().showMessage("Dodano pozycję " + text, 10000) else: print("Nie wpisano pozycji") def onActivePoz(self, tekst): self.pozycja = tekst naglowki = { 'id_poz': 'ID', 'symbol_narz': 'Symbol narzędzia', 'vc': 'Prędkość skrawania Vc [m/min]', 'obroty': 'Obroty n [obr/min]', 'fz': 'Posuw na ząb fz [mm/ostrze]', 'posuw': 'Posuw liniowy f [mm/min]' } self.model_poz.setTable(tekst) self.model_poz.setEditStrategy(QSqlTableModel.OnFieldChange) self.model_poz.select() # Ustawianie nagłówków ilosc_kolumn = self.model_poz.columnCount() for i in range(ilosc_kolumn): nazwa_kolumn = self.model_poz.headerData(i, Qt.Horizontal) self.model_poz.setHeaderData(i, Qt.Horizontal, naglowki[nazwa_kolumn]) def onActiveNarz(self, tekst): slownik = { 'Frez palcowy': 'frezy_palcowe', 'Frez płytkowy (głowica)': 'frezy_plytkowe', 'Gwintownik': 'gwintowniki', 'Nóż tokarski': 'noze_tokarskie', 'Oprawka': 'oprawki', 'Piła': 'pily', 'Pozostałe': 'pozostale', 'Rozwiertak': 'rozwiertaki', 'Wiertło': 'wiertla', 'Wiertło składane': 'wiertla_skladane', 'Wygniatak': 'wygniataki', 'Brak': '' } naglowki = { 'idfrezy_palcowe': 'ID', 'symbol_freza': 'Symbol', 'producent_fr': 'Producent', 'srednica_fr': 'Średnica', 'dl_fr': 'Długość całkowita', 'dl_rob_fr': 'Długość robocza', 'idfrezy_plytkowe': 'ID', 'symbol_frez_pl': 'Symbol', 'producent_fp': 'Producent', 'srednica_fr_pl': 'Średnica', 'ilosc_plytek': 'Ilość płytek', 'symbol_pl': 'Symbol płytek', 'ilosc_krawedzi_pl': 'Ilość krawędzi płytki', 'idgwintowniki': 'ID', 'symbol_g': 'Symbol', 'producent_gw': 'Producent', 'rozmiar_gwintu': 'Rozmiar gwintu i skok', 'typ_gwintownika': 'Typ gwintownika', 'idnoze_tokarskie': 'ID', 'symbol_n': 'Symbol', 'producent_n': 'Producent', 'plytki_n': 'Symbol płytek', 'ilosc_krawedzi_pl_n': 'Ilość krawędzi', 'idpily': 'ID', 'symbol_p': 'Symbol', 'producent_pil': 'Producent', 'srednica_p': 'Średnica', 'grubosc_p': 'Grubość', 'rodzaj_pl_p': 'Symbol płytek', 'ilosc_pl_p': 'Ilość płytek', 'ilosc_kraw_p': 'Ilość krawędzi płytki', 'idpozostale': 'ID', 'symbol_poz': 'Symbol', 'producent_poz': 'Producent', 'srednica_poz': 'Średnica', 'ilosc_pl_poz': 'Ilość płytek', 'plytki_poz': 'Symbol płytek', 'idrozwiertaki': 'ID', 'symbol_r': 'Symbol', 'producent_roz': 'Producent', 'rozmiar_r': 'Rozmiar', 'idwiertla': 'ID', 'symbol_w': 'Symbol', 'producent_w': 'Producent', 'srednica_w': 'Średnica', 'dlugosc_w': 'Długość [mm]', 'idwiertla_skladane': 'ID', 'symbol_w_skl': 'Symbol', 'producent_ws': 'Producent', 'srednica_w_skl': 'Średnica', 'plytki_w_skl': 'Symbol płytek', 'idwygniataki': 'ID', 'symbol_wyg': 'Symbol', 'producent_wyg': 'Producent', 'rozmiar_gw': 'Rozmiar gwintu' } self.model.setTable(slownik[tekst]) self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.model.select() # 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]) @pyqtSlot(str) def wyszukiwanie(self, text): search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(search) # Odpowiedzialne za kolumnę, po której filtruje self.proxy.setFilterKeyColumn(-1) # opcja z wyszukiwaniem def widok(self): # Ustawianie własciwości widoku self.table_narz.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_narz.setSelectionMode(QAbstractItemView.SingleSelection) self.table_narz.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_narz.verticalHeader().setVisible(False) self.table_narz.setSortingEnabled(True) self.table_narz.setModel(self.model) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.setAlternatingRowColors(True) self.table.setModel(self.model_poz) # self.table.hideColumn(0) self.table_narz.doubleClicked.connect(self.klikniecie) @pyqtSlot() def klikniecie(self): x = self.table_narz.currentIndex().row() y = self.table_narz.currentIndex().column() nazwa = self.table_narz.currentIndex().sibling(x, 1).data() print(nazwa) # Dodanie narzędzia do pozycji if nazwa: print(nazwa) query = "INSERT INTO '" + self.model_poz.tableName( ) + "'(symbol_narz) VALUES ('" + nazwa + "') " polaczenie(query) # Odświeża tabelę self.model_poz.select() self.parent.statusBar().showMessage( "Dodano narzędzie " + nazwa + " do pozycji " + self.model_poz.tableName(), 10000) else: print(self.model_poz.tableName()) print("Brak wybranego narzędzia") def anulowanie(self): self.parent.statusBar().clearMessage() from opcje_qt import Wewnatrz menu_gl = Wewnatrz(self.parent) self.parent.setCentralWidget(menu_gl)
class Shtat(QMainWindow): """ Класс, реализующий окно для работы со штатным расписанием в виде таблицы """ con = QSqlDatabase.addDatabase('QSQLITE') con.setDatabaseName(settings.db_name) def __init__(self, parent: any = None) -> None: """ Функция инициализации окна штатного расписания :param parent: Родительский виджет (окно) """ super().__init__(parent) self.filters = ['Номер', 'Подразделение', 'Должность', 'Количество', 'Тариф', 'Оклад', 'ФИО', 'Декрет', 'История', 'Оклад замещающего работника', 'Вид позиции', ] self.setObjectName("ShtatWindow") self.resize(1380, 886) self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setObjectName("centralwidget") self.view = QTableView(self.centralwidget) self.view.setGeometry(QRect(0, 0, 1381, 821)) self.view.setObjectName("shtat_table_view") self.view.setSortingEnabled(True) self.filter_combo_box = QtWidgets.QComboBox(self.centralwidget) self.filter_combo_box.setGeometry(QRect(250, 840, 231, 31)) self.filter_combo_box.setObjectName("filter_combo_box") self.filter_input = QtWidgets.QLineEdit(self.centralwidget) self.filter_input.setGeometry(QRect(500, 840, 281, 31)) self.filter_input.setObjectName("filter_input") self.filter_label = QtWidgets.QLabel(self.centralwidget) self.filter_label.setGeometry(QRect(10, 840, 221, 31)) font = QFont() font.setFamily("Times New Roman") font.setPointSize(12) self.filter_label.setFont(font) self.filter_label.setObjectName("filter_label") self.filter_button = QtWidgets.QPushButton(self.centralwidget) self.filter_button.setGeometry(QRect(800, 840, 171, 31)) self.save_shtat_button = QtWidgets.QPushButton(self.centralwidget) self.save_shtat_button.setGeometry(QRect(1000, 840, 225, 31)) self.filter_button.setFont(font) self.save_shtat_button.setFont(font) self.filter_button.setObjectName("filter_button") self.setCentralWidget(self.centralwidget) _translate = QCoreApplication.translate self.setWindowTitle(_translate("ShtatWindow", "Работа со штатным расписанием")) self.filter_label.setText(_translate("ShtatWindow", "Фильтровать по столбцу:")) self.filter_button.setText(_translate("ShtatWindow", "Поиск")) self.save_shtat_button.setText(_translate("ShtatWindow", "Выгрузить штатное расписание")) self.model = QSqlRelationalTableModel(self.view) self.model.setTable('salaries') self.model.setEditStrategy(QSqlRelationalTableModel.OnFieldChange) self.model.setRelation(1, QSqlRelation("departments", "code", "department")) self.model.setRelation(10, QSqlRelation("positions", "position_code", "position_name")) for i in range(0, len(self.filters)): self.model.setHeaderData(i, Qt.Horizontal, self.filters[i]) self.model.select() self.proxyModelContact = QSortFilterProxyModel(self) self.proxyModelContact.setSourceModel(self.model) self.view.setModel(self.proxyModelContact) self.view.resizeColumnsToContents() self.view.setItemDelegate(QSqlRelationalDelegate(self.view)) self.filter_combo_box.addItems(self.filters) self.filter_button.clicked.connect(self.use_filter_button) self.save_shtat_button.clicked.connect(self.use_save_shtat_button) self.view.setItemDelegate(QSqlRelationalDelegate(self.view)) def use_filter_button(self) -> None: """ Функция кнопки "Поиск". Считывает паттерн из поля фильтра и применяет его к столбцу, выбранного в комбо-боксе фильтра :return: None """ self.proxyModelContact.setFilterKeyColumn(self.filters.index(self.filter_combo_box.currentText())) self.proxyModelContact.setFilterRegExp(self.filter_input.text()) @staticmethod def use_save_shtat_button() -> None: """ Функция кнопки "Выгрузить штатное расписание". Выгружает все штатное расписание в файл формата Excel :return: None """ file = QtWidgets.QFileDialog.getSaveFileName()[0] saver = FullShtatToExcel(file if file.endswith(".xlsx") else f"{file}.xlsx") saver.full_shtat_to_excel()
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({}) from ..keyboardhandler import LOCAL_KEYMAP_SETTER LOCAL_KEYMAP_SETTER.register_minibuffer_input(self) 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 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 == self.SimpleMatch: pattern = "^" + QRegExp.escape(txt) else: pattern = ".*".join(QRegExp.escape(t) for t in txt.split()) self._proxy_model.setFilterRegExp(QRegExp(pattern, Qt.CaseInsensitive)) 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): self._show_completions(self.text(), True) def _on_completion_activated(self, index, hide_popup=True): if hide_popup: self._popup.hide() model = index.model() if index.column() != 0: index = model.index(index.row(), 0) self.setText(model.data(index)) self.completion_activated.emit(model.mapToSource(index)) def popup(self): return self._popup def complete(self, hide_popup=True): if not self._popup.isVisible(): return index = self._popup.selectionModel().currentIndex() if index.isValid(): self._on_completion_activated(index, hide_popup=hide_popup) elif self._autocomplete_single and self._proxy_model.rowCount() == 1: self._on_completion_activated(self._proxy_model.index(0, 0), hide_popup=hide_popup) def select_next_completion(self, forward=True): model = self._proxy_model entries = model.rowCount() if entries == 0: return selection = self._popup.selectionModel().currentIndex() if not selection.isValid(): row = 0 if forward else (entries - 1) else: row = selection.row() if forward: row = row + 1 if row >= entries: row = 0 else: row = row - 1 if row < 0: row = (entries - 1) self._popup.selectRow(row) def mark(self): return self._mark def set_mark(self, value=None): if value is None: value = not self._mark self._mark = value return self._mark def reinit(self): self.setText("") self.setEchoMode(self.Normal) self.setValidator(None) self._right_italic_text = "" def set_right_italic_text(self, text): self._right_italic_text = text self.update() def paintEvent(self, event): QLineEdit.paintEvent(self, event) if not self._right_italic_text: return painter = QPainter(self) font = painter.font() font.setItalic(True) painter.setFont(font) painter.setRenderHint(QPainter.Antialiasing, True) painter.drawText(self.rect().adjusted(0, 0, -10, 0), Qt.AlignRight, self._right_italic_text)
class QtComparePanel(QWidget): filterChanged = pyqtSignal(str) def __init__(self, parent=None): super(QtComparePanel, self).__init__(parent) self.visibility_flags = [] self.visibility_buttons = [] self.labels_projects = [] self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.setMinimumWidth(400) self.setMinimumHeight(100) self.data_table = QTableView() self.data_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.data_table.setSelectionMode(QAbstractItemView.MultiSelection) self.data_table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.data_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.model = None self.data = None self.combodelegate1 = ComboBoxItemDelegate(self.data_table) self.combodelegate2 = ComboBoxItemDelegate(self.data_table) lblFilter = QLabel("Filter: ") self.comboboxFilter = QComboBox() self.comboboxFilter.setMinimumWidth(80) self.comboboxFilter.addItem("All") self.comboboxFilter.addItem("Same") self.comboboxFilter.addItem("Born") self.comboboxFilter.addItem("Dead") self.comboboxFilter.addItem("Grow") self.comboboxFilter.addItem("Shrink") filter_layout = QHBoxLayout() filter_layout.addWidget(lblFilter) filter_layout.addWidget(self.comboboxFilter) filter_layout.addStretch() layout = QVBoxLayout() layout.addLayout(filter_layout) layout.addWidget(self.data_table) self.setLayout(layout) self.correspondences = None self.data = None self.comboboxFilter.currentTextChanged.connect(self.changeFilter) def setTable(self, project, img1idx, img2idx): self.correspondences = project.getImagePairCorrespondences( img1idx, img2idx) self.data = self.correspondences.data self.model = TableModel(self.data) self.sortfilter = QSortFilterProxyModel(self) self.sortfilter.setSourceModel(self.model) self.data_table.setModel(self.sortfilter) self.data_table.setVisible(False) self.data_table.verticalHeader().hide() self.data_table.resizeColumnsToContents() self.data_table.setVisible(True) self.data_table.setItemDelegateForColumn(5, self.combodelegate1) self.data_table.setItemDelegateForColumn(6, self.combodelegate2) self.data_table.setEditTriggers(QAbstractItemView.DoubleClicked) self.data_table.update() self.data_table.setStyleSheet( "QHeaderView::section { background-color: rgb(40,40,40) }") def updateData(self, corr): if corr is None: return self.correspondences = corr self.sortfilter.beginResetModel() self.model.beginResetModel() self.model._data = corr.data self.sortfilter.endResetModel() self.model.endResetModel() self.data_table.update() def selectRows(self, rows): self.data_table.clearSelection() indexes = [self.model.index(r, 0) for r in rows] mode = QItemSelectionModel.Select | QItemSelectionModel.Rows [ self.data_table.selectionModel().select(index, mode) for index in indexes ] if len(rows) > 0: value = self.data_table.horizontalScrollBar().value() column = self.data_table.columnAt(value) self.data_table.scrollTo(self.data_table.model().index( rows[0], column)) @pyqtSlot(QModelIndex) def getData(self, index): pass #column = index.column() #row = index.row() #self.data_table.model().index(row, column).data() @pyqtSlot(str) def changeFilter(self, txt): if self.data is None: return if txt == 'All': self.sortfilter.setFilterRegExp(QRegExp()) else: self.sortfilter.setFilterKeyColumn(5) self.sortfilter.setFilterRegExp(txt.lower()) self.sortfilter.setFilterRole(Qt.DisplayRole) self.filterChanged.emit(txt.lower())
class ScanTableWidget(QWidget): """ Used for displaying information in a table. =============================== ========================================= **Signals:** sigScanClicked Emitted when the user has clicked on a row of the table and returns the current index. This index contains information about the current rows column data. =============================== ========================================= """ sigScanClicked = pyqtSignal(QModelIndex, name="scanClicked") header = [ "MS level", "Index", "RT (min)", "precursor m/z", "charge", "ID", "PeptideSeq", "PeptideIons", ] def __init__(self, ms_experiment, *args): QWidget.__init__(self, *args) self.ms_experiment = ms_experiment self.table_model = ScanTableModel(self, self.ms_experiment, self.header) self.table_view = QTableView() # register a proxy class for filering and sorting the scan table self.proxy = QSortFilterProxyModel(self) self.proxy.setSourceModel(self.table_model) self.table_view.sortByColumn(1, Qt.AscendingOrder) # setup selection model self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_view.setModel(self.proxy) self.table_view.setSelectionModel(QItemSelectionModel(self.proxy)) # header self.horizontalHeader = self.table_view.horizontalHeader() self.horizontalHeader.sectionClicked.connect(self.onHeaderClicked) # enable sorting self.table_view.setSortingEnabled(True) # connect signals to slots self.table_view.selectionModel().currentChanged.connect( self.onCurrentChanged) # keyboard moves to new row self.horizontalHeader.sectionClicked.connect(self.onHeaderClicked) layout = QVBoxLayout(self) layout.addWidget(self.table_view) self.setLayout(layout) # hide column 7 with the PepIon data, intern information usage self.table_view.setColumnHidden(7, True) # Add rt in minutes for better TIC interaction self.table_view.setItemDelegateForColumn(2, RTUnitDelegate(self)) self.table_view.setColumnWidth(2, 160) # default : first row selected. in OpenMSWidgets def onRowSelected(self, index): """se_comment: hard-refactoring to comply to pep8""" if index.siblingAtColumn(1).data() is None: return # prevents crash if row gets filtered out self.curr_spec = self.ms_experiment.getSpectrum( index.siblingAtColumn(1).data()) self.scanClicked.emit(index) def onCurrentChanged(self, new_index, old_index): self.onRowSelected(new_index) def onHeaderClicked(self, logicalIndex): if logicalIndex != 0: return # allow filter on first column only for now self.logicalIndex = logicalIndex self.menuValues = QMenu(self) self.signalMapper = QSignalMapper(self) # get unique values from (unfiltered) model valuesUnique = set([ self.table_model.index(row, self.logicalIndex).data() for row in range( self.table_model.rowCount( self.table_model.index(-1, self.logicalIndex))) ]) if len(valuesUnique) == 1: return # no need to select anything actionAll = QAction("Show All", self) actionAll.triggered.connect(self.onShowAllRows) self.menuValues.addAction(actionAll) self.menuValues.addSeparator() """se_comment: hard-refactoring to comply to pep8""" l: enumerate = enumerate(sorted(list(set(valuesUnique)))) for actionNumber, actionName in l: action = QAction(actionName, self) self.signalMapper.setMapping(action, actionNumber) action.triggered.connect(self.signalMapper.map) self.menuValues.addAction(action) self.signalMapper.mapped.connect(self.onSignalMapper) # get screen position of table header and open menu headerPos = self.table_view.mapToGlobal(self.horizontalHeader.pos()) posY = headerPos.y() + self.horizontalHeader.height() posX = headerPos.x() + \ self.horizontalHeader.sectionPosition(self.logicalIndex) self.menuValues.exec_(QPoint(posX, posY)) def onShowAllRows(self): filterColumn = self.logicalIndex filterString = QRegExp("", Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn) def onSignalMapper(self, i): stringAction = self.signalMapper.mapping(i).text() filterColumn = self.logicalIndex filterString = QRegExp(stringAction, Qt.CaseSensitive, QRegExp.FixedString) self.proxy.setFilterRegExp(filterString) self.proxy.setFilterKeyColumn(filterColumn)
class FilterableTable(SQLTable): """a filterable Table Widget that displays content of an SQLite table; for individual widgets, subclass and overwrite the create_model method; add_color_proxy should be an (INT allele_status-column, INT lab_status-column) tuple """ def __init__(self, log, mydb = ": memory :", add_color_proxy = False, header_dic = None): super().__init__(log, mydb) self.add_color_proxy = add_color_proxy self.header_dic = header_dic self.create_model() self.fill_UI() self.create_filter_model() self.update_filterbox() def fill_UI(self): """sets up the layout """ self.log.debug("\t- Setting up the table...") self.table = QTableView() self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.header = self.table.horizontalHeader() # table header self.header.setSectionResizeMode(QHeaderView.ResizeToContents) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setAlternatingRowColors(True) # self.header.sectionClicked.connect(self.on_header_sectionClicked) mode = QAbstractItemView.SingleSelection self.table.setSelectionMode(mode) self.grid.addWidget(self.table, 2, 0, 10, 10) self.filter_lbl = QLabel("Filter:", self) self.grid.addWidget(self.filter_lbl, 1, 2) self.filter_entry = QLineEdit(self) self.grid.addWidget(self.filter_entry, 1, 3) self.filter_entry.textChanged.connect(self.on_filter_entry_textChanged) self.filter_text = "" self.filter_cb = QComboBox(self) self.grid.addWidget(self.filter_cb, 1, 4) self.filter_cb.currentIndexChanged.connect(self.on_filter_cb_IndexChanged) self.filter_btn = QPushButton("Filter!", self) self.grid.addWidget(self.filter_btn, 1, 5) self.filter_btn.clicked.connect(self.on_filter_btn_clicked) self.unfilter_btn = QPushButton("Remove Filter", self) self.grid.addWidget(self.unfilter_btn, 1, 6) self.unfilter_btn.clicked.connect(self.on_actionAll_triggered) self.log.debug("\t=> Done!") def update_filterbox(self): """fills the filter-combobox with the header values after the model has been created and set """ column_num = self.model.columnCount() if self.header_dic: columns = [self.header_dic[i] for i in self.header_dic] else: columns = [self.proxy.headerData(i, Qt.Horizontal) for i in range(column_num)] self.filter_cb.addItems(columns) def create_filter_model(self): """creates the filter-proxy-model on top of self.model """ self.log.debug("Creating filter model...") self.proxy = QSortFilterProxyModel(self) if self.add_color_proxy: (allele_status_column, lab_status_column) = self.add_color_proxy self.log.debug("adding color filter to columns {} and {}".format(allele_status_column, lab_status_column)) self.color_proxy = ColorProxyModel(self, allele_status_column, lab_status_column) self.color_proxy.setSourceModel(self.model) self.proxy.setSourceModel(self.color_proxy) else: self.proxy.setSourceModel(self.model) self.table.setSortingEnabled(True) self.table.setModel(self.proxy) def on_filter_cb_IndexChanged(self, index): """restricts RegEx filter to selected column """ self.log.debug("Combobox: colum {} selected".format(index)) self.proxy.setFilterKeyColumn(index) def on_filter_entry_textChanged(self, text): """stores content of filter_entry as self.text """ self.log.debug("filter text: '{}'".format(text)) self.filter_text = text def on_filter_btn_clicked(self): """activates RegEx filter to current content of filter_entry and filter_cb """ column = self.filter_cb.currentIndex() self.log.debug("Filtering column {} for '{}'".format(column, self.filter_text)) self.proxy.setFilterKeyColumn(column) search = QRegExp(self.filter_text, Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(search) def on_header_sectionClicked(self, logicalIndex): """opens a dialog to choose between all unique values for this column, or revert to 'All' """ self.log.debug("Header clicked: column {}".format(logicalIndex)) self.logicalIndex = logicalIndex menuValues = QMenu(self) self.signalMapper = QSignalMapper(self) self.filter_cb.setCurrentIndex(self.logicalIndex) self.filter_cb.blockSignals(True) self.proxy.setFilterKeyColumn(self.logicalIndex) valuesUnique = [str(self.model.index(row, self.logicalIndex).data()) for row in range(self.model.rowCount()) ] actionAll = QAction("All", self) actionAll.triggered.connect(self.on_actionAll_triggered) menuValues.addAction(actionAll) menuValues.addSeparator() for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))): action = QAction(actionName, self) self.signalMapper.setMapping(action, actionNumber) action.triggered.connect(self.signalMapper.map) menuValues.addAction(action) self.signalMapper.mapped.connect(self.on_signalMapper_mapped) headerPos = self.table.mapToGlobal(self.header.pos()) posY = headerPos.y() + self.header.height() posX = headerPos.x() + self.header.sectionViewportPosition(self.logicalIndex) menuValues.exec_(QPoint(posX, posY)) def on_actionAll_triggered(self): """reverts table to unfiltered state """ self.log.debug("Unfiltering...") filterString = QRegExp("", Qt.CaseInsensitive, QRegExp.RegExp) self.proxy.setFilterRegExp(filterString) self.filter_entry.setText("") def on_signalMapper_mapped(self, i): """filters current column to mapping text """ text = self.signalMapper.mapping(i).text() self.log.debug("Filtering column {} to '{}'".format(self.logicalIndex, text)) filterString = QRegExp(text, Qt.CaseSensitive, QRegExp.FixedString) self.proxy.setFilterRegExp(filterString)