class ButtonBar(QFrame): buttonClicked = pyqtSignal( str, int ) # Indicates the iteration number and iteration name of the button that was clicked def __init__(self, items: t_.Sequence[str], parent=None): super().__init__(parent=parent) # self.setFrameStyle(QFrame.Panel) self._bGroup = QButtonGroup(self) l = QHBoxLayout(self) for i, itemName in enumerate(items): b = QPushButton(itemName, parent=self) b.setCheckable(True) # Toggleable self._bGroup.addButton(b, id=i) l.addWidget(b) self._selectedButtonId = self._bGroup.id(self._bGroup.buttons()[0]) self._bGroup.buttons()[0].click( ) # Make sure at least one button is selected. self._bGroup.buttonClicked.connect(self._buttonSelected) l.setSpacing(1) # Move buttons close together l.setContentsMargins(0, 0, 0, 0) w = QFrame(self) w.setFrameStyle(QFrame.Box) w.setLayout(l) scrollArea = QScrollArea(parent=self) scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) scrollArea.setStyleSheet("""QScrollBar:horizontal { height:10px; }""") scrollArea.setWidget(w) scrollArea.setFixedHeight(10 + w.height()) ll = QHBoxLayout() ll.setContentsMargins(0, 0, 0, 0) ll.addWidget(scrollArea) self.setLayout(ll) def _buttonSelected(self, btn): self._selectedButtonId = self._bGroup.id(btn) self.buttonClicked.emit(btn.text(), self._bGroup.id(btn)) def getSelectedButtonId(self): return self._selectedButtonId def selectNextButton(self): id = self._selectedButtonId + 1 if id >= len(self._bGroup.buttons()): id = 0 self.setButtonSelected(id) def setButtonSelected(self, ID: int): btn = self._bGroup.button(ID) btn.click()
class GSideToolbar(QWidget): selectionChanged = pyqtSignal(str) def __init__(self, buttons): super().__init__() self.selectedId = None self.mainLayout = QVBoxLayout(self) self.buttonGroup = QButtonGroup() self.buttons = {} for button in buttons: b = QPushButton(button.name) self.buttonGroup.addButton(b) self.buttonGroup.setId(b, button.id) self.buttons[button.id] = b self.mainLayout.addWidget(b) self.buttonGroup.buttonClicked.connect(self.buttonClicked) self.mainLayout.addStretch() def buttonState(self, state): pass def buttonClicked(self, button : QPushButton): buttonId = self.buttonGroup.id(button) buttonName = self.buttons[buttonId].text() self.selectionChanged.emit(buttonName) @staticmethod def createButton(text, icon): pass
class GSideToolbar(QWidget): selectionChanged = pyqtSignal(str) def __init__(self, buttons): super().__init__() self.selectedId = None self.mainLayout = QVBoxLayout(self) self.buttonGroup = QButtonGroup() self.buttons = {} for button in buttons: b = QPushButton(button.name) self.buttonGroup.addButton(b) self.buttonGroup.setId(b, button.id) self.buttons[button.id] = b self.mainLayout.addWidget(b) self.buttonGroup.buttonClicked.connect(self.buttonClicked) self.mainLayout.addStretch() def buttonState(self, state): pass def buttonClicked(self, button: QPushButton): buttonId = self.buttonGroup.id(button) buttonName = self.buttons[buttonId].text() self.selectionChanged.emit(buttonName) @staticmethod def createButton(text, icon): pass
class PstnSettingsWidget(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.layout = QVBoxLayout() self.form_layout = QFormLayout() self.setup_heading() self.button_group = QGroupBox("Mandatory Fields are Marked with *") self.layout.addWidget(self.button_group) self.v_box = QVBoxLayout() self.button_group.setLayout(self.v_box) self.setup_pstn_settings_form() self.v_box.addLayout(self.form_layout) self.setup_ip_form() self.v_box.addLayout(self.ip_form_layout) self.init_settings() self.setup_buttons() self.v_box.addWidget(QLabel()) self.v_box.addLayout(self.button_layout) self.setLayout(self.layout) def setup_buttons(self): self.button_layout = QHBoxLayout() back_button_creator = BackButton() self.back_button = back_button_creator.create_back_button() self.button_layout.addWidget(self.back_button) self.add_ip_address_button = QPushButton("Add IP Address", self) self.add_ip_address_button.setToolTip("Add another contact IP address") self.button_layout.addWidget(self.add_ip_address_button) self.apply_settings_button = QPushButton("Apply") self.apply_settings_button.setToolTip( "Update Sip Trunk settings for contact between your IVR and telephone provider") self.button_layout.addWidget(self.apply_settings_button) def setup_ip_form(self): self.ip_form_layout = QFormLayout() self.ip_addresses = [] self.delete_button_group = QButtonGroup(self) self.delete_layouts = [] self.settings = QSettings("gp_ivr_settings", "GP_IVR_Settings") def setup_pstn_settings_form(self): self.form_layout.addRow("", QLabel()) self.pjsip_port = QLineEdit() self.pjsip_port.setToolTip("The port that your telephone provider will connect to the IVR with") self.provider_address = QLineEdit() self.provider_address.setToolTip("The SIP address that the IVR can contact the telephone provider through") self.provider_port = QLineEdit() self.provider_port.setToolTip("The port through which the telephone provider uses in communications") self.form_layout.addRow("Asterisk PJSIP Port (default is 5160):", self.pjsip_port) self.form_layout.addRow("*Provider Contact Address:", self.provider_address) self.form_layout.addRow("Provider Contact Port:", self.provider_port) grow_label = QLabel() self.form_layout.addRow("Provider Contact IP Addresses:", grow_label) grow_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) def setup_heading(self): heading_font = QFont('Arial', 12) heading_font.setBold(True) heading = QLabel("SIP Trunk Settings:") heading.setFont(heading_font) self.layout.addWidget(QLabel()) self.layout.addWidget(heading) page_info = QLabel( "You can change your telephone service provider SIP trunk settings here.\nThese settings must be updated from the default before running an IVR.\nMake sure that you have created a SIP trunk with your telephone provider.") self.layout.addWidget(page_info) self.layout.addWidget(QLabel()) def init_settings(self): self.pjsip_port.setText(self.settings.value("pjsip port")) self.provider_address.setText(self.settings.value("provider contact address")) self.provider_port.setText(self.settings.value("provider contact port")) saved_ip_addresses = self.settings.value("provider ip addresses") if saved_ip_addresses is not None: new_ip_addresses = list(saved_ip_addresses.split(",")) del new_ip_addresses[-1] for ip_address in new_ip_addresses: self.add_ip_address(value=ip_address) def add_ip_address(self, value=None): layout = QHBoxLayout() delete_ip_address_button = QPushButton("Delete", self) delete_ip_address_button.setToolTip("Remove this contact IP address") new_ip_address = QLineEdit() new_ip_address.setToolTip("IP address that the telephone provider will contact the IVR with") layout.addWidget(new_ip_address) layout.addWidget(delete_ip_address_button) if value is not None: new_ip_address.setText(value) self.ip_form_layout.addRow("IP Address " + str(len(self.ip_addresses)), layout) self.ip_addresses.append(new_ip_address) self.delete_button_group.addButton(delete_ip_address_button) def apply_settings(self): self.save_settings() ip_addresses = [] if not self.pjsip_port.text(): pjsip_port_text = "5160" else: pjsip_port_text = self.pjsip_port.text() if not self.provider_port.text(): provider_port_text = "5060" else: provider_port_text = self.provider_port.text() for ip_address in self.ip_addresses: ip_addresses.append(ip_address.text()) create_pjsip = SettingsToPjsip(asterisk_constants.PJSIP_CONF_PATH, pjsip_port_text, self.provider_address.text(), provider_port_text, ip_addresses) create_pjsip.create_config() def save_settings(self): self.settings.setValue("pjsip port", self.pjsip_port.text()) self.settings.setValue("provider contact address", self.provider_address.text()) self.settings.setValue("provider contact port", self.provider_port.text()) ip_address_list = "" for ip_address in self.ip_addresses: ip_address_list += ip_address.text() + "," if ip_address_list is not None: self.settings.setValue("provider ip addresses", ip_address_list) def delete_ip_address(self, button): ip_index = - 2 - self.delete_button_group.id(button) self.ip_form_layout.removeRow(ip_index) del self.ip_addresses[ip_index] for button in self.delete_button_group.buttons(): button_id = self.delete_button_group.id(button) if(button_id < - 2 - ip_index): self.delete_button_group.setId(button, button_id + 1)
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText( app.settings.get("account", "username")) self.lineEdit_loginPassword.setText( app.settings.get("account", "password")) self.checkBox_autoLogin.setChecked( app.settings.getbool("account", "autologin")) self.checkBox_autoStartFrontend.setChecked( self.doesAutoStartFileExists()) self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked( app.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect( self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked( app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled( self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText( app.settings.get("frontend", "watchpattern")) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) try: startEtmWhen = callXwaredInterface("getStartEtmWhen") self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) except SocketDoesntExist: self.group_etmStartWhen.setEnabled(False) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) self.btn_refreshMount.clicked.connect(self.setupMounts) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @staticmethod def doesAutoStartFileExists(): return os.path.lexists(constants.FRONTEND_AUTOSTART_FILE) @pyqtSlot(int) def slotWatchClipboardToggled(self, state): # disable pattern settings, before # 1. complete patterns # 2. test glib key file compatibility self.plaintext_watchPattern.setReadOnly(True) self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() permissionCheckResult = app.mountsFaker.permissionCheck() permissionCheckFailed = [ "无法获得检测权限。运行{}查看原因。".format(constants.PERMISSIONCHECK) ] mountsMapping = app.mountsFaker.getMountsMapping() for i, mount in enumerate(app.mountsFaker.mounts): # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.insertRow(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(mount)) # drive1: the drive letter it should map to, by alphabetical order drive1 = chr(ord('C') + i) + ":" self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") # check 1: permission errors = permissionCheckResult.get(mount, permissionCheckFailed) # check 2: mapping if drive1 != drive2: errors.append( "警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format( actual=drive2, should=drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem(row, 0, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加")) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("account", "username", self.lineEdit_loginUsername.text()) app.settings.set("account", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) doesAutoStartFileExists = self.doesAutoStartFileExists() if self.checkBox_autoStartFrontend.isChecked( ) and not doesAutoStartFileExists: # mkdir if autostart dir doesn't exist try: os.mkdir(os.path.dirname(constants.FRONTEND_AUTOSTART_FILE)) except OSError: pass # already exists os.symlink(constants.DESKTOP_FILE_LOCATION, constants.FRONTEND_AUTOSTART_FILE) elif (not self.checkBox_autoStartFrontend.isChecked() ) and doesAutoStartFileExists: os.remove(constants.FRONTEND_AUTOSTART_FILE) app.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) # app.settings.set("frontend", "watchpattern", # self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id( self.btngrp_etmStartWhen.checkedButton()) try: callXwaredInterface("setStartEtmWhen", startEtmWhen) except SocketDoesntExist: QMessageBox.warning( None, "Xware Desktop", "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()), QMessageBox.Ok, QMessageBox.Ok) app.settings.save() app.mountsFaker.mounts = self.newMounts app.settings.applySettings.emit() super().accept() @property def newMounts(self): return list( map(lambda row: self.table_mounts.item(row, 0).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values lcPort = app.xwaredpy.lcPort self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用") etmSettings = app.etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue( etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): newsettings = EtmSetting( dLimit=self.spinBox_dSpeedLimit.value(), uLimit=self.spinBox_uSpeedLimit.value(), maxRunningTasksNum=self.spinBox_maxRunningTasksNum.value()) app.etmpy.saveSettings(newsettings)
class MainWindow(QMainWindow): sizeButtonGroup = None OtherSize = QStyle.PM_CustomBase otherSpinBox = None def createImagesGroupBox(self): imagesGroupBox = QGroupBox("Images") labels = ("Images", "Mode", "State") self.imagesTable = QTableWidget() self.imagesTable.setSelectionMode(QAbstractItemView.NoSelection) self.imagesTable.setItemDelegate(ImageDelegate(self)) self.imagesTable.horizontalHeader().setDefaultSectionSize(90) self.imagesTable.setColumnCount(3) self.imagesTable.setHorizontalHeaderLabels(labels) self.imagesTable.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.imagesTable.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.imagesTable.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Fixed) self.imagesTable.verticalHeader().hide() self.imagesTable.itemChanged.connect(self.changeIcon) layout = QVBoxLayout(imagesGroupBox) layout.addWidget(self.imagesTable) return imagesGroupBox def createIconSizeGroupBox(self): iconSizeGroupBox = QGroupBox("Icon Size") self.sizeButtonGroup = QButtonGroup(iconSizeGroupBox) self.sizeButtonGroup.setExclusive(True) self.sizeButtonGroup.buttonToggled.connect(self.triggerChangeSize) smallRadioButton = QRadioButton() smallRadioButton.setChecked(True) self.sizeButtonGroup.addButton(smallRadioButton, QStyle.PM_SmallIconSize) largeRadioButton = QRadioButton() self.sizeButtonGroup.addButton(largeRadioButton, QStyle.PM_LargeIconSize) toolBarRadioButton = QRadioButton() self.sizeButtonGroup.addButton(toolBarRadioButton, QStyle.PM_ToolBarIconSize) iconViewRadioButton = QRadioButton() self.sizeButtonGroup.addButton(iconViewRadioButton, QStyle.PM_IconViewIconSize) listViewRadioButton = QRadioButton() self.sizeButtonGroup.addButton(listViewRadioButton, QStyle.PM_ListViewIconSize) tabBarRadioButton = QRadioButton() self.sizeButtonGroup.addButton(tabBarRadioButton, QStyle.PM_TabBarIconSize) otherRadioButton = QRadioButton("Other:") self.sizeButtonGroup.addButton(otherRadioButton, self.OtherSize) self.otherSpinBox = IconSizeSpinBox() self.otherSpinBox.setRange(8, 256) spinBoxToolTip = "Enter a custom size within {}..{}".format( self.otherSpinBox.minimum(), self.otherSpinBox.maximum()) self.otherSpinBox.setValue(64) self.otherSpinBox.setToolTip(spinBoxToolTip) otherRadioButton.setToolTip(spinBoxToolTip) self.otherSpinBox.valueChanged.connect(self.triggerChangeSize) otherSizeLayout = QHBoxLayout() otherSizeLayout.addWidget(otherRadioButton) otherSizeLayout.addWidget(self.otherSpinBox) otherSizeLayout.addStretch() layout = QGridLayout(iconSizeGroupBox) layout.addWidget(smallRadioButton, 0, 0) layout.addWidget(largeRadioButton, 1, 0) layout.addWidget(toolBarRadioButton, 2, 0) layout.addWidget(listViewRadioButton, 0, 1) layout.addWidget(iconViewRadioButton, 1, 1) layout.addWidget(tabBarRadioButton, 2, 1) layout.addLayout(otherSizeLayout, 3, 0, 1, 2) layout.setRowStretch(4, 1) return iconSizeGroupBox def loadImages(self, fileNames): for fileName in fileNames: row = self.imagesTable.rowCount() self.imagesTable.setRowCount(row + 1) fileInfo = QFileInfo(fileName) imageName = fileInfo.baseName() fileImage2x = fileInfo.absolutePath( ) + '/' + imageName + "@2x." + fileInfo.suffix() fileInfo2x = QFileInfo(fileImage2x) image = QImage(fileName) toolTip = "Directory: {}\nFile: {}\nFile@2x: {}\nSize: {}x{}".format( QDir.toNativeSeparators(fileInfo.absolutePath()), fileInfo.fileName(), fileInfo2x.fileName() if fileInfo2x.exists else "<None>", image.width(), image.height()) fileItem = QTableWidgetItem(imageName) fileItem.setData(Qt.UserRole, fileName) fileItem.setIcon(QIcon(QPixmap.fromImage(image))) fileItem.setFlags((fileItem.flags() | Qt.ItemIsUserCheckable) & ~Qt.ItemIsEditable) fileItem.setToolTip(toolTip) self.imagesTable.setItem(row, 0, fileItem) mode = QIcon.Normal state = QIcon.Off if self.guessModeStateAct.isChecked(): if "_act" in imageName: mode = QIcon.Active elif "_dis" in imageName: mode = QIcon.Disabled elif "_sel" in imageName: mode = QIcon.Selected if "_on" in imageName: mode = QIcon.On modeItem = QTableWidgetItem(IconPreviewArea.iconModeNames()[ IconPreviewArea.iconModes().index(mode)]) modeItem.setToolTip(toolTip) self.imagesTable.setItem(row, 1, modeItem) stateItem = QTableWidgetItem(IconPreviewArea.iconStateNames()[ IconPreviewArea.iconStates().index(state)]) stateItem.setToolTip(toolTip) self.imagesTable.setItem(row, 2, stateItem) self.imagesTable.openPersistentEditor(modeItem) self.imagesTable.openPersistentEditor(stateItem) fileItem.setCheckState(Qt.Checked) def addImages(self, directory): fileDialog = QFileDialog(self, "Open Images", directory) mimeTypeFilters = [] for mimeTypeName in QImageReader.supportedMimeTypes(): mimeTypeFilters.append(str(mimeTypeName)) mimeTypeFilters.sort() fileDialog.setMimeTypeFilters(mimeTypeFilters) fileDialog.selectMimeTypeFilter('image/png') fileDialog.setAcceptMode(QFileDialog.AcceptOpen) fileDialog.setFileMode(QFileDialog.ExistingFiles) if not self.nativeFileDialogAct.isChecked(): fileDialog.setOption(QFileDialog.DontUseNativeDialog) if fileDialog.exec_() == QDialog.Accepted: self.loadImages(fileDialog.selectedFiles()) def addSampleImages(self): self.addImages("C:/Users/hungbn/Pictures") def addOtherImages(self): pass def removeAllImages(self): self.imagesTable.setRowCount(0) self.changeIcon() def createActions(self): fileMenu = self.menuBar().addMenu("&File") addSampleImagesAct = QAction("Add &Sample Images...", self) addSampleImagesAct.triggered.connect(self.addSampleImages) fileMenu.addAction(addSampleImagesAct) addOtherImagesAct = QAction("&Add Images...", self) addOtherImagesAct.setShortcut(QKeySequence.Open) addOtherImagesAct.triggered.connect(self.addOtherImages) fileMenu.addAction(addOtherImagesAct) removeAllImagesAct = QAction("&Remove All Images", self) removeAllImagesAct.setShortcut("CTRL+R") removeAllImagesAct.triggered.connect(self.removeAllImages) fileMenu.addAction(removeAllImagesAct) fileMenu.addSeparator() exitAct = QAction("&Quit", self) exitAct.triggered.connect(QWidget.close) exitAct.setShortcuts(QKeySequence.Quit) fileMenu.addAction(exitAct) viewMenu = self.menuBar().addMenu("&View") self.styleActionGroup = QActionGroup(self) for styleName in QStyleFactory.keys(): action = QAction("{} Style".format(styleName), self.styleActionGroup) action.setData(styleName) action.setCheckable(True) action.triggered.connect(self.changeStyle) viewMenu.addAction(action) settingsMenu = self.menuBar().addMenu("&Settings") self.guessModeStateAct = QAction("&Guess Image Mode/State", self) self.guessModeStateAct.setCheckable(True) self.guessModeStateAct.setChecked(True) settingsMenu.addAction(self.guessModeStateAct) self.nativeFileDialogAct = QAction("&Use Native File Dialog", self) self.nativeFileDialogAct.setCheckable(True) self.nativeFileDialogAct.setChecked(True) settingsMenu.addAction(self.nativeFileDialogAct) def __init__(self, *args): super(QMainWindow, self).__init__(*args) centerWidget = QWidget(self) self.setCentralWidget(centerWidget) mainLayout = QGridLayout(centerWidget) previewGroupBox = QGroupBox("Preview") self.previewArea = IconPreviewArea(previewGroupBox) previewLayout = QVBoxLayout(previewGroupBox) previewLayout.addWidget(self.previewArea) mainLayout.addWidget(previewGroupBox, 0, 0, 1, 2) mainLayout.addWidget(self.createImagesGroupBox(), 1, 0) vbox = QVBoxLayout() vbox.addWidget(self.createIconSizeGroupBox()) #vbox.addWidget(self.createHighDpiIconSizeGroupBox()) vbox.addItem( QSpacerItem(0, 0, QSizePolicy.Ignored, QSizePolicy.MinimumExpanding)) mainLayout.addLayout(vbox, 1, 1) self.createActions() self.setWindowTitle("Icons") self.checkCurrentStyle() def about(self): QMessageBox.about( self, "About Icons" "The <b>Icons</b> example illustrates how Qt renders an icon in " + "different modes (active, normal, disabled, and selected) and " + "states (on and off) based on a set of images.") def checkCurrentStyle(self): for action in self.styleActionGroup.actions(): styleName = action.data() candidate = QStyleFactory.create(styleName) if candidate.metaObject().className() == QApplication.style( ).metaObject().className(): action.trigger() return def changeStyle(self, checked): if (not checked): return action = self.sender() style = QStyleFactory.create(action.data()) QApplication.setStyle(style) for button in self.sizeButtonGroup.buttons(): metric = self.sizeButtonGroup.id(button) value = style.pixelMetric(metric) { QStyle.PM_SmallIconSize: lambda: button.setText("Small ({} x {})".format(value, value)), QStyle.PM_LargeIconSize: lambda: button.setText("Large ({} x {})".format(value, value)), QStyle.PM_ToolBarIconSize: lambda: button.setText("Toolbars ({} x {})".format( value, value)), QStyle.PM_ListViewIconSize: lambda: button.setText("List views ({} x {})".format( value, value)), QStyle.PM_IconViewIconSize: lambda: button.setText("Icon views ({} x {})".format( value, value)), QStyle.PM_TabBarIconSize: lambda: button.setText("Tab bars ({} x {})".format( value, value)), }.get(metric, lambda: "")() self.triggerChangeSize() def changeIcon(self): icon = QIcon() for row in range(self.imagesTable.rowCount()): fileItem = self.imagesTable.item(row, 0) modeItem = self.imagesTable.item(row, 1) stateItem = self.imagesTable.item(row, 2) if fileItem.checkState() == Qt.Checked: modeIndex = IconPreviewArea.iconModeNames().index( modeItem.text()) stateIndex = IconPreviewArea.iconStateNames().index( stateItem.text()) mode = IconPreviewArea.iconModes()[modeIndex] state = IconPreviewArea.iconStates()[stateIndex] fileName = fileItem.data(Qt.UserRole) image = QImage(fileName) if not image.isNull(): icon.addPixmap(QPixmap.fromImage(image), mode, state) self.previewArea.setIcon(icon) def changeSize(self, id, checked): if (not checked): return other = (id == self.OtherSize) extend = self.otherSpinBox.value() if other else QApplication.style( ).pixelMetric(id) self.previewArea.setSize(QSize(extend, extend)) self.otherSpinBox.setEnabled(other) def triggerChangeSize(self): self.changeSize(self.sizeButtonGroup.checkedId(), True)
class VistaListaDipendenti( QWidget): # Apre la vista che visualizza la lista dei dipendenti. def __init__(self): super(VistaListaDipendenti, self).__init__() self.controller = ControllerListaDipendenti() # Inserisce in 'lista_dipendenti' le informazioni della 'lista-dipendenti.json'. # Se la lista è vuota l'utente è notificato con un messaggio di errore. self.stylesheet_label = """ QLabel{ background-color: #99cbff; border: 1px solid #dfdfdf; } """ self.stylesheet_window = """ QWidget{ background-color: #dfdfdf } """ self.stylesheet_button_back = """ QPushButton{ border-radius: 15px; background-color: transparent; } QPushButton::Pressed{ background-color: transparent; } """ self.stylesheet_button = """ QPushButton{ background-color: #cc3234; color: white; border-radius: 15px; } QPushButton::Pressed{ background-color: grey } """ self.stylesheet_table = """ QTableWidget{ background-color: white; } """ self.stylesheet_pagamento = """ QPushButton{ background-color: transparent; border-color: transparent; } QPushButton::Pressed{ background-color: grey; } """ # Inserimento e impostazioni grafiche dell'immagine dello sfondo della finestra. self.imagePath = "Image/foto.png" self.image = QImage(self.imagePath) self.label = QLabel(self) self.label.setPixmap(QPixmap.fromImage(self.image)) self.label.setScaledContents(True) self.label.setGeometry(0, 0, 1400, 750) # Inserimento della tabella e intestazione delle colonne. self.table = QTableWidget(self) self.table.setColumnCount(6) self.table.setRowCount(1) self.table.setItem(0, 0, QTableWidgetItem("Apri")) self.table.setItem(0, 1, QTableWidgetItem("ID")) self.table.setItem(0, 2, QTableWidgetItem("Nome")) self.table.setItem(0, 3, QTableWidgetItem("Cognome")) self.table.setItem(0, 4, QTableWidgetItem("Mansione")) self.table.setItem(0, 5, QTableWidgetItem("Elimina")) self.set_data( ) # Inserisce nella tabella i dati contenuti nella lista_dipendenti. # Impostazioni grafiche della tabella. self.table.setGeometry(25, 30, 1200, 550) self.table.setColumnWidth(0, 90) self.table.setColumnWidth(1, 100) self.table.setColumnWidth(2, 300) self.table.setColumnWidth(3, 300) self.table.setColumnWidth(4, 300) self.table.setColumnWidth(5, 90) self.table.setStyleSheet(self.stylesheet_table) self.table.horizontalHeader().setStretchLastSection(True) self.table.horizontalHeader().hide() self.table.horizontalScrollBar().setDisabled(True) self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table.verticalHeader().hide() self.table.setEditTriggers(self.table.NoEditTriggers) self.table.setSelectionMode(self.table.NoSelection) self.table.setFocusPolicy(Qt.NoFocus) # Inserimento e impostazioni grafiche del bottone per tornare alla vista precedente. self.button_back = QPushButton(self) self.button_back.setIcon(QIcon('Image/back.png')) self.button_back.setIconSize(QSize(90, 90)) self.button_back.setGeometry(70, 600, 90, 90) self.button_back.setStyleSheet(self.stylesheet_button_back) self.button_back.clicked.connect(self.go_back) # Inserimento e impostazioni grafiche del bottone per inserire un nuovo dipendente nella lista. self.button_new_dipendente = QPushButton(self) self.button_new_dipendente.setText("Nuovo Dipendente") self.font_button = QFont("Times", 11) self.button_new_dipendente.setFont(self.font_button) self.button_new_dipendente.setGeometry(1000, 620, 190, 50) self.button_new_dipendente.setStyleSheet(self.stylesheet_button) self.button_new_dipendente.clicked.connect(self.go_new_dipendente) # Impostazioni grafiche generali della finestra del programma. self.setWindowTitle("Lista Dipendenti") self.resize(1250, 700) self.setFixedSize(self.size()) self.setStyleSheet(self.stylesheet_window) # == set_data == # La funzione si occupa di salvare le informazioni relative al dipendente e contenute nel file # 'lista_dipendenti.pickle' nella tabella della VistaListaDipendenti. def set_data(self): self.button_group_apri = QButtonGroup() self.button_group_elimina = QButtonGroup() self.apri_icon = QIcon("Image/apri_icon.png") self.cancella_icon = QIcon("Image/delete.png") i = 1 self.lista_dipendenti = self.controller.get_lista_dipendenti() n_righe = len(self.controller.get_lista_dipendenti()) self.table.setRowCount(n_righe + 1) self.button_group_apri.buttonClicked.connect(self.on_selection_apri) self.button_group_elimina.buttonClicked.connect( self.on_selection_elimina) for dipendente in self.controller.get_lista_dipendenti(): self.controller_dipendente = ControllerDipendente(dipendente) self.apri = QPushButton() self.apri.setIcon(self.apri_icon) self.apri.setIconSize(QSize(30, 30)) self.apri.setStyleSheet(self.stylesheet_pagamento) self.button_group_apri.addButton(self.apri, i) self.table.setCellWidget(i, 0, self.apri) self.table.setItem( i, 1, QTableWidgetItem(self.controller_dipendente.get_id())) self.table.setItem( i, 2, QTableWidgetItem(self.controller_dipendente.get_nome())) self.table.setItem( i, 3, QTableWidgetItem(self.controller_dipendente.get_cognome())) self.table.setItem( i, 4, QTableWidgetItem(self.controller_dipendente.get_mansione())) self.delete = QPushButton() self.delete.setIcon(self.cancella_icon) self.delete.setIconSize(QSize(35, 35)) self.delete.setStyleSheet(self.stylesheet_pagamento) self.button_group_elimina.addButton(self.delete, i) self.table.setCellWidget(i, 5, self.delete) i = i + 1 # == go_new_dipendente == # La funzione si occupa di aprire la VistaNuovoDipendente. def go_new_dipendente(self): self.vista_nuovo_dipendente = VistaNuovoDipendente() self.vista_nuovo_dipendente.show() self.close() # == go_back == # La funzione si occupa di aprire la finestra precedente. def go_back(self): self.go_home = VistaHomeSegretario.VistaHomeSegretario() self.go_home.show() self.close() # == go_apri == # La funzione si occupa di aprire la VistaCliente corrispondente al cliente scelto. def go_apri(self, i): dipendente = self.lista_dipendenti[i - 1] self.go_dipendente = VistaDipendente(dipendente, False) self.go_dipendente.show() self.close() # == go_elimina == # La funzione, dopo aver chiesto conferma all'utente, cancella le informazioni relative al # cliente scelto. def go_elimina(self, i): conferma = QMessageBox.question( self, "Attenzione", "Sei sicuro di voler eliminare questo dipendente?", QMessageBox.No, QMessageBox.Yes) if conferma == QMessageBox.Yes: self.controller.rimuovi_dipendente_by_index(i - 1) self.refresh() else: return def refresh(self): self.go_lista = VistaListaDipendenti() self.go_lista.show() self.close() def on_selection_apri(self, selected): self.go_apri(self.button_group_apri.id(selected)) def on_selection_elimina(self, selected): self.go_elimina(self.button_group_elimina.id(selected))
class DependenciesDialog(QDialog): """Dependencies dialog for python dependencies""" column = AttrDict( zip(("button", "status", "name", "version", "required_version", "description"), range(6))) column_headers = ("", "Status", "Package", "Version", "Required", "Description") def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Installer") # Button group for install buttons self.buttGroup = QButtonGroup() self.buttGroup.buttonClicked.connect(self.on_butt_install) self.mainLayout = QVBoxLayout() self.mainLayout.setContentsMargins(10, 10, 10, 10) self.setLayout(self.mainLayout) self.tree = QTreeWidget() self.mainLayout.addWidget(self.tree, 4) self.tree.setHeaderLabels(self.column_headers) self.tree.setRootIsDecorated(False) self.tree.setSelectionMode(QTreeWidget.NoSelection) self.update_load() def sizeHint(self): """Overloaded method""" return QSize(700, 200) def update_load(self): self.tree.clear() for idx, module in enumerate(OPTIONAL_DEPENDENCIES): item = QTreeWidgetItem() item.setText(self.column.name, module.name) version = module.version if module.version else "Not installed" item.setText(self.column.version, str(version)) item.setText(self.column.required_version, str(module.required_version)) item.setText(self.column.description, module.description) self.tree.addTopLevelItem(item) if module.is_installed(): color = "#DBFEAC" status = "Installed" else: status = "Not installed" color = "#F3FFBB" butt = QToolButton() butt.setText("Install") butt.setEnabled(PIP_MODULE.is_installed()) self.tree.setItemWidget(item, self.column.button, butt) self.buttGroup.addButton(butt, idx) item.setText(self.column.status, status) item.setBackground(self.column.status, QColor(color)) def on_butt_install(self, butt): """One of install buttons pressed""" butt.setDisabled(True) idx = self.buttGroup.id(butt) dial = InstallPackageDialog(self, module=OPTIONAL_DEPENDENCIES[idx]) dial.exec_() self.update_load()
class SendConfigDialog(QDialog): def __init__(self): super().__init__() self.setMinimumWidth(640) self.setWindowTitle('Send configuration to device') self.settings = QSettings('tasmotizer.cfg', QSettings.IniFormat) self.commands = None self.module_mode = 0 self.createUI() self.loadSettings() def createUI(self): vl = VLayout() self.setLayout(vl) # Wifi groupbox self.gbWifi = QGroupBox('WiFi') self.gbWifi.setCheckable(True) self.gbWifi.setChecked(False) flWifi = QFormLayout() self.leAP = QLineEdit() self.leAPPwd = QLineEdit() self.leAPPwd.setEchoMode(QLineEdit.Password) flWifi.addRow('SSID', self.leAP) flWifi.addRow('Password', self.leAPPwd) self.gbWifi.setLayout(flWifi) # Recovery Wifi groupbox self.gbRecWifi = QGroupBox('Recovery WiFi') self.gbRecWifi.setCheckable(True) self.gbRecWifi.setChecked(False) flRecWifi = QFormLayout() lbRecAP = QLabel('Recovery') lbRecAP.setAlignment(Qt.AlignVCenter | Qt.AlignRight) lbRecAPPwd = QLabel('a1b2c3d4') lbRecAPPwd.setAlignment(Qt.AlignVCenter | Qt.AlignRight) flRecWifi.addRow('SSID', lbRecAP) flRecWifi.addRow('Password', lbRecAPPwd) self.gbRecWifi.setLayout(flRecWifi) vl_wifis = VLayout(0) vl_wifis.addWidgets([self.gbWifi, self.gbRecWifi]) # MQTT groupbox self.gbMQTT = QGroupBox('MQTT') self.gbMQTT.setCheckable(True) self.gbMQTT.setChecked(False) flMQTT = QFormLayout() self.leBroker = QLineEdit() self.sbPort = SpinBox() self.sbPort.setValue(1883) self.leTopic = QLineEdit() self.leTopic.setText('tasmota') self.leFullTopic = QLineEdit() self.leFullTopic.setText('%prefix%/%topic%/') self.leFriendlyName = QLineEdit() self.leMQTTUser = QLineEdit() self.leMQTTPass = QLineEdit() self.leMQTTPass.setEchoMode(QLineEdit.Password) flMQTT.addRow('Host', self.leBroker) flMQTT.addRow('Port', self.sbPort) flMQTT.addRow('Topic', self.leTopic) flMQTT.addRow('FullTopic', self.leFullTopic) flMQTT.addRow('FriendlyName', self.leFriendlyName) flMQTT.addRow('User [optional]', self.leMQTTUser) flMQTT.addRow('Password [optional]', self.leMQTTPass) self.gbMQTT.setLayout(flMQTT) # Module/template groupbox self.gbModule = GroupBoxV('Module/template') self.gbModule.setCheckable(True) self.gbModule.setChecked(False) hl_m_rb = HLayout() self.rbModule = QRadioButton('Module') self.rbModule.setChecked(True) self.rbTemplate = QRadioButton('Template') hl_m_rb.addWidgets([self.rbModule, self.rbTemplate]) self.rbgModule = QButtonGroup(self.gbModule) self.rbgModule.addButton(self.rbModule, 0) self.rbgModule.addButton(self.rbTemplate, 1) self.cbModule = QComboBox() for mod_id, mod_name in MODULES.items(): self.cbModule.addItem(mod_name, mod_id) self.leTemplate = QLineEdit() self.leTemplate.setPlaceholderText('Paste template string here') self.leTemplate.setVisible(False) self.gbModule.addLayout(hl_m_rb) self.gbModule.addWidgets([self.cbModule, self.leTemplate]) self.rbgModule.buttonClicked[int].connect(self.setModuleMode) # layout all widgets hl_wifis_mqtt = HLayout(0) hl_wifis_mqtt.addLayout(vl_wifis) hl_wifis_mqtt.addWidget(self.gbMQTT) vl.addLayout(hl_wifis_mqtt) vl.addWidget(self.gbModule) btns = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close) btns.accepted.connect(self.accept) btns.rejected.connect(self.reject) vl.addWidget(btns) def loadSettings(self): self.gbWifi.setChecked(self.settings.value('gbWifi', False, bool)) self.leAP.setText(self.settings.value('AP')) self.gbRecWifi.setChecked(self.settings.value('gbRecWifi', False, bool)) self.gbMQTT.setChecked(self.settings.value('gbMQTT', False, bool)) self.leBroker.setText(self.settings.value('Broker')) self.sbPort.setValue(self.settings.value('Port', 1883, int)) self.leTopic.setText(self.settings.value('Topic', 'tasmota')) self.leFullTopic.setText( self.settings.value('FullTopic', '%prefix%/%topic%/')) self.leFriendlyName.setText(self.settings.value('FriendlyName')) self.leMQTTUser.setText(self.settings.value('MQTTUser')) self.gbModule.setChecked(self.settings.value('gbModule', False, bool)) module_mode = self.settings.value('ModuleMode', 0, int) for b in self.rbgModule.buttons(): if self.rbgModule.id(b) == module_mode: b.setChecked(True) self.setModuleMode(module_mode) self.cbModule.setCurrentText(self.settings.value('Module', 'Generic')) self.leTemplate.setText(self.settings.value('Template')) def setModuleMode(self, radio): self.module_mode = radio self.cbModule.setVisible(not radio) self.leTemplate.setVisible(radio) def accept(self): ok = True if self.gbWifi.isChecked() and (len(self.leAP.text()) == 0 or len(self.leAPPwd.text()) == 0): ok = False QMessageBox.warning(self, 'WiFi details incomplete', 'Input WiFi AP and Password') if self.gbMQTT.isChecked() and not self.leBroker.text(): ok = False QMessageBox.warning(self, 'MQTT details incomplete', 'Input broker hostname') if self.module_mode == 1 and len(self.leTemplate.text()) == 0: ok = False QMessageBox.warning(self, 'Template string missing', 'Input template string') if ok: backlog = [] if self.gbWifi.isChecked(): backlog.extend([ 'ssid1 {}'.format(self.leAP.text()), 'password1 {}'.format(self.leAPPwd.text()) ]) if self.gbRecWifi.isChecked(): backlog.extend(['ssid2 Recovery', 'password2 a1b2c3d4']) if self.gbMQTT.isChecked(): backlog.extend([ 'mqtthost {}'.format(self.leBroker.text()), 'mqttport {}'.format(self.sbPort.value()) ]) topic = self.leTopic.text() if topic and topic != 'tasmota': backlog.append('topic {}'.format(topic)) fulltopic = self.leFullTopic.text() if fulltopic and fulltopic != '%prefix%/%topic%/': backlog.append('fulltopic {}'.format(fulltopic)) fname = self.leFriendlyName.text() if fname: backlog.append('friendlyname {}'.format(fname)) mqttuser = self.leMQTTUser.text() if mqttuser: backlog.append('mqttuser {}'.format(mqttuser)) mqttpassword = self.leMQTTPass.text() if mqttpassword: backlog.append('mqttpassword {}'.format(mqttpassword)) if self.gbModule.isChecked(): if self.module_mode == 0: backlog.append('module {}'.format( self.cbModule.currentData())) elif self.module_mode == 1: backlog.extend([ 'template {}'.format(self.leTemplate.text()), 'module 0' ]) self.commands = 'backlog {}\n'.format(';'.join(backlog)) self.done(QDialog.Accepted)
class VistaListaDocumenti( QWidget): # Apre la vista che visualizza la lista dei documenti. def __init__(self): super(VistaListaDocumenti, self).__init__() self.controller = ControllerListaDocumenti() self.lista_documenti = [] # Inserisce in 'lista_documenti' le informazioni della 'lista_documenti.json' # Se la lista è vuota l'utente è notificato con un messaggio di errore. self.lista_documenti = self.controller.get_lista_documenti() if not self.lista_documenti: QMessageBox.critical(self, "Attenzione", "Nessun documento trovato", QMessageBox.Ok) self.stylesheet_window = """ QWidget{ background-color: #dfdfdf } """ self.stylesheet_button = """ QPushButton{ background-color: #cc3234; color: white; border-radius: 15px; } QPushButton::Pressed{ background-color: grey } """ self.stylesheet_table = """ QTableWidget{ background-color: white; } """ self.stylesheet_button_back = """ QPushButton{ border-radius: 15px; background-color: transparent; } QPushButton::Pressed{ background-color: transparent; } """ self.stylesheet_pagamento = """ QPushButton{ background-color: transparent; border-color: transparent; } QPushButton::Pressed{ background-color: grey; } """ # Inserimento e impostazioni grafiche dell'immagine dello sfondo della finestra. self.imagePath = "Image/foto.png" self.image = QImage(self.imagePath) self.label = QLabel(self) self.label.setPixmap(QPixmap.fromImage(self.image)) self.label.setScaledContents(True) self.label.setGeometry(0, 0, 1000, 600) # Impostazioni grafiche generali della finestra del programma. self.setWindowTitle("Lista Documenti") self.resize(1000, 600) self.setFixedSize(self.size()) self.setStyleSheet(self.stylesheet_window) # Inserimento della tabella e intestazione delle colonne. self.table = QTableWidget(self) self.table.setColumnCount(3) self.table.setRowCount(1) self.table.setItem(0, 0, QTableWidgetItem("Apri")) self.table.setItem(0, 1, QTableWidgetItem("Nome")) self.table.setItem(0, 2, QTableWidgetItem("Elimina")) self.set_data( ) # Inserisce nella tabella i dati contenuti nella lista_documenti. # Impostazioni grafiche della tabella. self.table.setGeometry(70, 50, 850, 400) self.table.setColumnWidth(0, 75) self.table.setColumnWidth(1, 700) self.table.setColumnWidth(2, 75) self.table.setStyleSheet(self.stylesheet_table) self.table.horizontalHeader().setStretchLastSection(True) self.table.horizontalHeader().hide() self.table.horizontalScrollBar().setDisabled(True) self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table.verticalHeader().hide() self.table.setSelectionMode(self.table.NoSelection) self.table.setEditTriggers(self.table.NoEditTriggers) self.table.setFocusPolicy(Qt.NoFocus) # Inserimento e impostazioni grafiche del bottone che consente di caricare un nuovo documento # nel sistema. self.button_upload_document = QPushButton(self) self.button_upload_document.setText("Carica") self.font_button = QFont("Times", 11) self.button_upload_document.setFont(self.font_button) self.button_upload_document.setGeometry(800, 500, 140, 50) self.button_upload_document.setStyleSheet(self.stylesheet_button) self.button_upload_document.clicked.connect(self.upload_document) # Inserimento e impostazioni grafiche del bottone per tornare alla vista precedente. self.button_back = QPushButton(self) self.button_back.setIcon(QIcon('Image/back.png')) self.button_back.setIconSize(QSize(90, 90)) self.button_back.setGeometry(60, 490, 90, 90) self.button_back.setStyleSheet(self.stylesheet_button_back) self.button_back.clicked.connect(self.go_back) # == set_data == # La funzione si occupa di salvare le informazioni relative al documento e contenute nel file # 'lista_documenti.json' nella tabella della VistaListaDocumenti. def set_data(self): self.button_group_apri = QButtonGroup() self.button_group_elimina = QButtonGroup() self.apri_icon = QIcon("Image/Visualizza.png") self.cancella_icon = QIcon("Image/delete.png") i = 1 self.lista_documenti = self.controller.get_lista_documenti() n_righe = len(self.lista_documenti) self.table.setRowCount(n_righe + 1) self.button_group_apri.buttonClicked.connect(self.on_selection_apri) self.button_group_elimina.buttonClicked.connect( self.on_selection_elimina) for documento in self.lista_documenti: self.apri = QPushButton() self.apri.setIcon(self.apri_icon) self.apri.setIconSize(QSize(25, 25)) self.apri.setStyleSheet(self.stylesheet_pagamento) self.button_group_apri.addButton(self.apri, i) self.table.setCellWidget(i, 0, self.apri) self.table.setItem(i, 1, QTableWidgetItem(documento)) self.delete = QPushButton() self.delete.setIcon(self.cancella_icon) self.delete.setIconSize(QSize(35, 35)) self.delete.setStyleSheet(self.stylesheet_pagamento) self.button_group_elimina.addButton(self.delete, i) self.table.setCellWidget(i, 2, self.delete) self.table.currentRow() i = i + 1 # == open_document == # La funzione, dopo che è stato selezionato un documento dalla lista, # apre la VistaDocumento. def open_document(self, i): documento = self.controller.get_lista_documenti()[i - 1] self.vista_documento = VistaDocumento(documento) self.vista_documento.show() self.close() # == go_back == # La funzione si occupa di aprire la finestra precedente. def go_back(self): self.go_lista_documenti = VistaHomeSegretario.VistaHomeSegretario() self.go_lista_documenti.show() self.close() # == upload_document == # La funzione permette di caricare nel sistema un file .pdf scelto dai file # contenuti nel computer del dipendente. def upload_document(self): filename = QFileDialog.getOpenFileName(self, 'open file', '/home', 'Images(*.pdf)') if filename[0]: f = open(filename[0], 'r') src = f.name des = 'Documents/' shutil.copy2(src, des) self.refresh() else: return # == remove_document == # La funzione, dopo aver inviato un messaggio di conferma all'utente, effettua # l'eliminazione del documento dalla lista. La finestra viene poi refreshata per aggiornare # la lista. def remove_document(self, i): conferma = QMessageBox.question( self, "Attenzione", "Sei sicuro di voler eliminare questo documento?", QMessageBox.No, QMessageBox.Yes) if conferma == QMessageBox.Yes: documento = self.controller.get_lista_documenti()[i - 1] self.controller.rimuovi_documento(documento) self.refresh() else: return # == refresh == # La funzione si occupa di riaprire la VistaListaDocumenti per aggiornarla dopo # che sono state effettuate modifiche. def refresh(self): self.go_vista_documenti = VistaListaDocumenti() self.go_vista_documenti.show() self.close() def on_selection_apri(self, selected): self.open_document(self.button_group_apri.id(selected)) def on_selection_elimina(self, selected): self.remove_document(self.button_group_elimina.id(selected))
class AppScreenQ(QMainWindow): def __init__(self): super(AppScreenQ, self).__init__() self.setWindowTitle("Mistrz szachownicy QT") self.timeCounter = TIME_LIMIT self.gameFlag = False self.bar = None self.engine = AppModel() self.mainLayout = QVBoxLayout() self.setMinimumSize(800, 800) self._menuSetUp() self._boardSetUp() self._progressSetUp() self._controlSetUp() self._statsSetUp() widget = QWidget() widget.setLayout(self.mainLayout) self.setCentralWidget(widget) self.show() def _menuSetUp(self): fileMenu = self.menuBar().addMenu("&Menu") newAct = QAction('Opis gry', self) newAct.triggered.connect(self._overviewDisplay) fileMenu.addAction(newAct) def _overviewDisplay(self): dlg = QDialog(self) dlg.setWindowTitle("Opis gry!") overviewLayout = QVBoxLayout() overview = QLabel(OVERVIEW_TEXT) overview.setWordWrap(True) overviewLayout.addWidget(overview) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok) buttonBox.setCenterButtons(True) buttonBox.accepted.connect(dlg.accept) overviewLayout.addWidget(buttonBox) dlg.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) dlg.setLayout(overviewLayout) dlg.show() def _statsSetUp(self): style = """ border: 2px solid gray; border-radius: 10px; padding: 8px; selection-background-color: darkgray;""" self.stats = QHBoxLayout() self.scoreStatic = QLabel("Aktualny wynik:") self.scoreStatic.setMinimumHeight(40) self.scoreStatic.setMaximumHeight(40) self.scoreStatic.setStyleSheet(style) self.scoreStatic.setAlignment(QtCore.Qt.AlignCenter) self.score = QLabel("0") self.score.setMinimumHeight(40) self.score.setMaximumHeight(40) self.score.setStyleSheet(style) self.score.setAlignment(QtCore.Qt.AlignCenter) self.coordStatic = QLabel("Znajdź:") self.coordStatic.setMinimumHeight(40) self.coordStatic.setMaximumHeight(40) self.coordStatic.setStyleSheet(style) self.coordStatic.setAlignment(QtCore.Qt.AlignCenter) self.coord = QLabel("") self.coord.setMinimumHeight(40) self.coord.setMaximumHeight(40) self.coord.setStyleSheet(style) self.coord.setAlignment(QtCore.Qt.AlignCenter) self.stats.addWidget(self.scoreStatic) self.stats.addWidget(self.score) self.stats.addWidget(self.coordStatic) self.stats.addWidget(self.coord) self.mainLayout.addLayout(self.stats) def _controlSetUp(self): style = """ border-style: solid; border-color: gray; border-width: 2px; border-radius: 10px;""" self.menu = QHBoxLayout() self.startButton = QPushButton('Start', self) self.startButton.setStyleSheet(style) self.startButton.setMinimumHeight(40) self.startButton.clicked.connect(self._onButtonStart) self.stopButton = QPushButton('Stop', self) self.stopButton.setStyleSheet(style) self.stopButton.setMinimumHeight(40) self.stopButton.clicked.connect(self._onButtonStop) self.stopButton.setEnabled(False) self.menu.addWidget(self.startButton) self.menu.addWidget(self.stopButton) self.mainLayout.addLayout(self.menu) def _progressSetUp(self): self.progress = QProgressBar(self) self.progress.setTextVisible(False) self.progress.setStyleSheet("border: 2px solid grey;" "border-radius: 5px;" "text-align: center;" ) self.mainLayout.addWidget(self.progress) self.progress.setMaximum(TIME_LIMIT) def _boardSetUp(self): frameWidget = QWidget() frameLayout = QHBoxLayout() frameLayout.addStretch() frameWidget.setFixedSize(560, 560) frameLayout.addWidget(frameWidget) frameLayout.addStretch() self.mainLayout.addLayout(frameLayout) squareLayout = QGridLayout(frameWidget) squareLayout.setSpacing(0) self.squares = QButtonGroup() for i in range(8 * 8): newButton = QPushButton() policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) newButton.setSizePolicy(policy) x = getX(i) y = getY(i) if (x + y) % 2 == 0: newButton.setStyleSheet("background-color: linen") else: newButton.setStyleSheet("background-color: sienna") self.squares.addButton(newButton, i) squareLayout.addWidget(newButton, x, y) self.squares.setExclusive(True) self.squares.buttonPressed.connect(self._onSquareClick) self.squares.buttonReleased.connect(self._onSquareRelease) self.mainLayout.addLayout(squareLayout) def _onButtonStart(self): if self.gameFlag: return self.startButton.setEnabled(False) self.stopButton.setEnabled(True) self.gameFlag = True self.timeCounter = TIME_LIMIT self.bar = QTimer() self.bar.timeout.connect(self._onClockChanged) self.bar.start(TIME_INTERVAL) self.engine.counterReset() self.engine.getNextPosition() self.coord.setText(self.engine.getCurrentNotation()) self.score.setText("0") def _onButtonStop(self): if not self.gameFlag: return self.bar.stop() self.stopButton.setEnabled(False) self.startButton.setEnabled(True) self.gameFlag = False def _onClockChanged(self): if (self.timeCounter == 0) or (self.gameFlag is False): self.startButton.setEnabled(True) self.stopButton.setEnabled(False) self.gameFlag = False self.timeCounter -= 1 self.progress.setValue(self.timeCounter) def _onSquareClick(self, btn): if not self.gameFlag: return i = self.squares.id(btn) x = getX(i) y = getY(i) if self.engine.getCurrentPosition() == (x, y): btn.setStyleSheet("background-color: green") self.engine.counterAdd() self.engine.getNextPosition() self.coord.setText(self.engine.getCurrentNotation()) self.score.setText(str(self.engine.getCounter())) return btn.setStyleSheet("background-color: red") def _onSquareRelease(self, btn): i = self.squares.id(btn) x = getX(i) y = getY(i) if (x + y) % 2 == 0: btn.setStyleSheet("background-color: linen") else: btn.setStyleSheet("background-color: sienna")
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText(app.settings.get("account", "username")) self.lineEdit_loginPassword.setText(app.settings.get("account", "password")) self.checkBox_autoLogin.setChecked(app.settings.getbool("account", "autologin")) self.checkBox_autoStartFrontend.setChecked(self.doesAutoStartFileExists()) self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked(app.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked(app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText(app.settings.get("frontend", "watchpattern")) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) try: startEtmWhen = callXwaredInterface("getStartEtmWhen") self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) except SocketDoesntExist: self.group_etmStartWhen.setEnabled(False) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) self.btn_refreshMount.clicked.connect(self.setupMounts) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @staticmethod def doesAutoStartFileExists(): return os.path.lexists(constants.FRONTEND_AUTOSTART_FILE) @pyqtSlot(int) def slotWatchClipboardToggled(self, state): # disable pattern settings, before # 1. complete patterns # 2. test glib key file compatibility self.plaintext_watchPattern.setReadOnly(True) self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() permissionCheckResult = app.mountsFaker.permissionCheck() permissionCheckFailed = ["无法获得检测权限。运行{}查看原因。".format(constants.PERMISSIONCHECK)] mountsMapping = app.mountsFaker.getMountsMapping() for i, mount in enumerate(app.mountsFaker.mounts): # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.insertRow(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(mount)) # drive1: the drive letter it should map to, by alphabetical order drive1 = chr(ord('C') + i) + ":" self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") # check 1: permission errors = permissionCheckResult.get(mount, permissionCheckFailed) # check 2: mapping if drive1 != drive2: errors.append( "警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format( actual = drive2, should = drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem(row, 0, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加")) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("account", "username", self.lineEdit_loginUsername.text()) app.settings.set("account", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) doesAutoStartFileExists = self.doesAutoStartFileExists() if self.checkBox_autoStartFrontend.isChecked() and not doesAutoStartFileExists: # mkdir if autostart dir doesn't exist try: os.mkdir(os.path.dirname(constants.FRONTEND_AUTOSTART_FILE)) except OSError: pass # already exists os.symlink(constants.DESKTOP_FILE_LOCATION, constants.FRONTEND_AUTOSTART_FILE) elif (not self.checkBox_autoStartFrontend.isChecked()) and doesAutoStartFileExists: os.remove(constants.FRONTEND_AUTOSTART_FILE) app.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) # app.settings.set("frontend", "watchpattern", # self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton()) try: callXwaredInterface("setStartEtmWhen", startEtmWhen) except SocketDoesntExist: QMessageBox.warning(None, "Xware Desktop", "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()), QMessageBox.Ok, QMessageBox.Ok) app.settings.save() app.mountsFaker.mounts = self.newMounts app.settings.applySettings.emit() super().accept() @property def newMounts(self): return list(map(lambda row: self.table_mounts.item(row, 0).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values lcPort = app.xwaredpy.lcPort self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用") etmSettings = app.etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue(etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): newsettings = EtmSetting(dLimit = self.spinBox_dSpeedLimit.value(), uLimit = self.spinBox_uSpeedLimit.value(), maxRunningTasksNum = self.spinBox_maxRunningTasksNum.value()) app.etmpy.saveSettings(newsettings)
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setWindowModality(Qt.WindowModal) self.setAttribute(Qt.WA_DeleteOnClose) self.mainWin = parent self.setupUi(self) self.lineEdit_loginUsername.setText(self.settings.get("account", "username")) self.lineEdit_loginPassword.setText(self.settings.get("account", "password")) self.checkBox_autoLogin.setChecked(self.settings.getbool("account", "autologin")) self.checkBox_enableDevelopersTools.setChecked( self.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked(self.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked(self.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked(self.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked(self.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked(self.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked(self.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue(self.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked(self.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText(self.settings.get("frontend", "watchpattern")) from PyQt5.QtWidgets import QButtonGroup self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) self.btngrp_etmStartWhen.button(self.settings.getint("xwared", "startetmwhen")).setChecked(True) self.accepted.connect(self.writeSettings) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) self.btn_refreshMount.clicked.connect(self.setupMounts) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() # shorthand @property def settings(self): return self.mainWin.settings # shorthand ends @staticmethod def permissionCheck(): import re ansiEscape = re.compile(r'\x1b[^m]*m') import subprocess with subprocess.Popen([constants.PERMISSIONCHECK], stdout = subprocess.PIPE, stderr = subprocess.PIPE) as proc: output = proc.stdout.read().decode("utf-8") output = ansiEscape.sub('', output) lines = output.split("\n") prevLine = None currMount = None result = {} for line in lines: if len(line.strip()) == 0: continue if all(map(lambda c: c == '=', line)): if currMount: result[currMount] = result[currMount][:-1] result[prevLine] = [] currMount = prevLine continue if currMount: if line != "正常。": result[currMount].append(line) prevLine = line return result @pyqtSlot(int) def slotWatchClipboardToggled(self, state): # disable pattern settings, before # 1. complete patterns # 2. test glib key file compatibility self.plaintext_watchPattern.setReadOnly(True) self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() PermissionError = self.permissionCheck() mountsMapping = self.mainWin.mountsFaker.getMountsMapping() for i, mount in enumerate(self.mainWin.mountsFaker.mounts): # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.insertRow(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(mount)) drive1 = chr(ord('C') + i) + ":" # the drive letter it should map to, by alphabetical order self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1)) drive2 = mountsMapping.get(mount, "无") # the drive letter it actually is assigned to # check 1: permission errors = PermissionError.get(mount, ["无法获得检测权限。运行/opt/xware_desktop/permissioncheck查看原因。"]) # check 2: mapping if drive1 != drive2: errors.append("警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format(actual = drive2, should = drive1)) from PyQt5.Qt import Qt from PyQt5.QtGui import QBrush brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): import os from PyQt5.QtWidgets import QFileDialog from PyQt5.Qt import Qt fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if (fileDialog.exec()): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem(row, 0, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加")) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def writeSettings(self): self.settings.set("account", "username", self.lineEdit_loginUsername.text()) self.settings.set("account", "password", self.lineEdit_loginPassword.text()) self.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) self.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) self.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) self.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 self.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) self.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) self.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) self.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) self.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) self.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) # self.settings.set("frontend", "watchpattern", # self.plaintext_watchPattern.toPlainText()) self.settings.setint("xwared", "startetmwhen", self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton())) startETMWhen = self.settings.getint("xwared", "startetmwhen") if startETMWhen == 1: self.settings.setbool("xwared", "startetm", True) self.settings.save() self.mainWin.mountsFaker.setMounts(self.newMounts) self.settings.applySettings.emit() @property def newMounts(self): return list(map(lambda row: self.table_mounts.item(row, 0).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): etmpy = self.mainWin.etmpy # fill values self.lineEdit_lcport.setText(etmpy.cfg.get("local_control.listen_port", "不可用")) etmSettings = etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue(etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): import etmpy newsettings = etmpy.EtmSetting(dLimit = self.spinBox_dSpeedLimit.value(), uLimit = self.spinBox_uSpeedLimit.value(), maxRunningTasksNum = self.spinBox_maxRunningTasksNum.value()) self.mainWin.etmpy.saveSettings(newsettings)
class Test(QWidget): def __init__(self, topic_id, user_id): super().__init__() self.initUI() self.button_group = QButtonGroup() self.step = 0 self.user_answers = [] self.topic_id = topic_id self.user_id = user_id self.length = len(get_data(self.topic_id)) self.test(self.step) def initUI(self): self.setGeometry(100, 100, 650, 300) self.setWindowTitle('Тест') self.input_first = QLabel(self) self.input_first.setGeometry(QRect(50, -10, 250, 100)) self.input_first.setText('Вопрос') self.input_first.setFont(QtGui.QFont('Arial', 13)) self.own_result = QLabel(self) self.question = QLabel(self) self.question.move(50, 70) self.layout = QFrame(self) self.init_button() def test(self, step): a = 0 j = 0 data = get_data(self.topic_id) correct = data[step] self.question.setText(correct[2]) self.question.setGeometry(QRect(50, 52, 600, 80)) font = QtGui.QFont() font.setPointSize(13) self.question.setFont(font) self.question.setWordWrap(True) numbers = (self.length - 1 if self.length < 4 else 3) failed = random.sample(get_unique_data(self.topic_id, correct[1]), numbers) for i in random.sample(failed + [correct], numbers + 1): a += 30 j += 1 button_name = "radioButton" + str(j) button_name = QRadioButton(self.layout) if correct[0] != i[0]: self.button_group.addButton(button_name, correct[0]) else: self.button_group.addButton(button_name, 0) button_name.setGeometry(QRect(50, 100 + a, 255, 17)) button_name.setObjectName("radioButton" + str(j)) button_name.setText(i[1]) button_name.toggled.connect(self.get_answer) button_name.show() self.input_first.setText('Вопрос № ' + str(self.step + 1) + ' из ' + str(self.length)) def get_answer(self): self.btn.setEnabled(True) def init_button(self): self.btn = QPushButton('Перейти к следующему вопросу.', self) self.btn.setEnabled(False) self.btn.resize(200, 40) self.btn.move(50, 250) self.btn.clicked.connect(self.validate) def validate(self): for children in self.button_group.buttons(): if children.isChecked() and self.button_group.id(children) > 0: self.user_answers.append(self.button_group.id(children)) children.hide() self.btn.setEnabled(False) self.step += 1 if self.step < self.length: self.test(self.step) else: if self.user_answers: self.input_first.setText('Ошибки:') self.conclusion() else: self.input_first.setText('Ошибок нет. Молодец!') self.conclusion() def conclusion(self): con = sqlite3.connect('quiz_db.db') cur = con.cursor() query = cur.execute("SELECT * FROM qa WHERE id in (%s)" % (', '.join(str(i) for i in self.user_answers))).fetchall() con.commit() con.close() result = 99 + ((self.length - len(self.user_answers) * 100) // self.length) save_score(self.user_id, self.topic_id, result) text = '' for i in query: text += i[1] + ' — ' + i[2] + '\n' self.own_result.setGeometry(QRect(50, 175, 275, 100)) self.own_result.setText('Ваш результат составляет: ' + str(result) + '%') self.own_result.setFont(QtGui.QFont('Arial', 13)) self.question.setText(text) self.question.move(50, 75) self.btn.setText('Вернуться на главную страницу.') self.btn.setEnabled(True) self.btn.clicked.connect(self.restart) def restart(self): self.cl = SelectQuiz(self.user_id) self.cl.show() self.close()
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText(app.settings.get("adapter-legacy", "username")) self.lineEdit_loginPassword.setText(app.settings.get("adapter-legacy", "password")) self.checkBox_autoLogin.setChecked(app.settings.getbool("legacy", "autologin")) self.checkBox_autoStartFrontend.setChecked(app.autoStart) if sys.platform == "linux": self.checkBox_autoStartFrontend.setEnabled(True) adapter = app.adapterManager[0] # Xwared Management managedBySystemd = adapter.daemonManagedBySystemd managedByUpstart = adapter.daemonManagedByUpstart managedByAutostart = adapter.daemonManagedByAutostart self.radio_managedBySystemd.setChecked(managedBySystemd) self.radio_managedByUpstart.setChecked(managedByUpstart) self.radio_managedByAutostart.setChecked(managedByAutostart) self.radio_managedByNothing.setChecked( not (managedBySystemd or managedByUpstart or managedByAutostart)) initType = getInitType() self.radio_managedBySystemd.setEnabled(initType == InitType.SYSTEMD) self.radio_managedByUpstart.setEnabled(initType == InitType.UPSTART) if not adapter.useXwared: self.group_etmStartWhen.setEnabled(False) self.group_initManaged.setEnabled(False) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) if adapter.useXwared: startEtmWhen = adapter.startEtmWhen self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) # frontend self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("legacy", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked(app.settings.getbool("legacy", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked(app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText(app.settings.get("frontend", "watchpattern")) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @pyqtSlot(int) def slotWatchClipboardToggled(self, state): self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): adapter = app.adapterManager[0] if not adapter.useXwared: self.tab_mount.setEnabled(False) return self.table_mounts.setRowCount(0) self.table_mounts.clearContents() mountsMapping = app.adapterManager[0].mountsFaker.getMountsMapping() for i, mount in enumerate(app.adapterManager[0].mountsFaker.mounts): self.table_mounts.insertRow(i) # drive1: the drive letter it should map to, by alphabetical order drive1 = app.adapterManager[0].mountsFaker.driveIndexToLetter(i) self.table_mounts.setItem(i, 0, QTableWidgetItem(drive1 + "\\TDDOWNLOAD")) # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.setItem(i, 1, QTableWidgetItem(mount)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") errors = [] # check: mapping if drive1 != drive2: errors.append( "错误:盘符映射在'{actual}',而不是'{should}'。\n" "如果这是个新挂载的文件夹,请尝试稍等,或重启后端,可能会修复此问题。" .format(actual = drive2, should = drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem( row, 0, QTableWidgetItem(app.adapterManager[0].mountsFaker.driveIndexToLetter(row) + "\\TDDOWNLOAD")) self.table_mounts.setItem(row, 1, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("adapter-legacy", "username", self.lineEdit_loginUsername.text()) app.settings.set("adapter-legacy", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("legacy", "autologin", self.checkBox_autoLogin.isChecked()) app.autoStart = self.checkBox_autoStartFrontend.isChecked() app.adapterManager[0].daemonManagedBySystemd = self.radio_managedBySystemd.isChecked() app.adapterManager[0].daemonManagedByUpstart = self.radio_managedByUpstart.isChecked() app.adapterManager[0].daemonManagedByAutostart = self.radio_managedByAutostart.isChecked() app.settings.setbool("legacy", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("legacy", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) app.settings.set("frontend", "watchpattern", self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton()) app.adapterManager[0].startEtmWhen = startEtmWhen app.settings.save() if self.tab_mount.isEnabled(): app.adapterManager[0].mountsFaker.mounts = self.newMounts app.applySettings.emit() super().accept() @property def newMounts(self): return list(map(lambda row: self.table_mounts.item(row, 1).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values adapter = app.adapterManager[0] settings = adapter.backendSettings etmRunning = adapter.etmPid != 0 if etmRunning and settings.initialized: self.spinBox_dSpeedLimit.setValue(settings.downloadSpeedLimit) self.spinBox_uSpeedLimit.setValue(settings.uploadSpeedLimit) self.spinBox_maxRunningTasksNum.setValue(settings.maxRunTaskNumber) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): adapter = app.adapterManager[0] adapter.do_applySettings({ "downloadSpeedLimit": self.spinBox_dSpeedLimit.value(), "uploadSpeedLimit": self.spinBox_uSpeedLimit.value(), "maxRunTaskNumber": self.spinBox_maxRunningTasksNum.value(), })
def create_rows(self, layout, sarea): u"""Build the rows of the dialog box""" play_button_group = QButtonGroup(sarea) old_play_button_group = QButtonGroup(sarea) for num, entry in enumerate(self.entries_list, 2): tt_text = self.build_text_help_label(entry) ico_label = QLabel('', sarea) ico_label.setToolTip(tt_text) if entry.icon: ico_label.setPixmap(QPixmap.fromImage(entry.icon)) layout.addWidget(ico_label, num, 0) tt_label = QLabel(entry.display_word, sarea) tt_label.setToolTip(tt_text) layout.addWidget(tt_label, num, 1) if self.hide_text: tt_label.hide() # Play button. t_play_button = QPushButton(sarea) play_button_group.addButton(t_play_button, num-2) t_play_button.setToolTip(self.play_help) t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png'))) layout.addWidget(t_play_button, num, self.play_column) if self.note[entry.audio_field_name]: t_play_old_button = QPushButton(sarea) old_play_button_group.addButton(t_play_old_button, num-2) t_play_old_button.setIcon( QIcon(os.path.join(icons_dir, 'play.png'))) if not self.hide_text: t_play_old_button.setToolTip( self.note[entry.audio_field_name]) else: t_play_old_button.setToolTip(self.play_old_help_short) layout.addWidget(t_play_old_button, num, self.play_old_column) else: dummy_label = QLabel('', sarea) dummy_label.setToolTip(self.play_old_empty_line_help) layout.addWidget(dummy_label, num, self.play_old_column) # The group where we later look what to do: t_button_group = QButtonGroup(sarea) t_button_group.setExclusive(True) # Now the four buttons t_add_button = QPushButton(sarea) t_add_button.setCheckable(True) t_add_button.setFlat(True) t_add_button.setToolTip(self.add_help_text_short) t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png'))) layout.addWidget(t_add_button, num, self.add_column) t_button_group.addButton(t_add_button, Action.Add) t_keep_button = QPushButton(sarea) t_keep_button.setCheckable(True) t_keep_button.setFlat(True) t_keep_button.setToolTip(self.keep_help_text_short) t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png'))) layout.addWidget(t_keep_button, num, self.keep_column) t_button_group.addButton(t_keep_button, Action.Keep) t_delete_button = QPushButton(sarea) t_delete_button.setCheckable(True) t_delete_button.setFlat(True) t_delete_button.setToolTip(self.delete_help_text_short) t_delete_button.setIcon( QIcon(os.path.join(icons_dir, 'delete.png'))) layout.addWidget(t_delete_button, num, self.delete_column) t_button_group.addButton(t_delete_button, Action.Delete) t_blacklist_button = QPushButton(sarea) t_blacklist_button.setCheckable(True) t_blacklist_button.setFlat(True) t_blacklist_button.setToolTip(self.blacklist_help_text_short) t_blacklist_button.setIcon( QIcon(os.path.join(icons_dir, 'blacklist.png'))) if entry.entry_hash: layout.addWidget( t_blacklist_button, num, self.blacklist_column) else: t_blacklist_button.hide() dummy_label_bl = QLabel('', sarea) dummy_label_bl.setToolTip(self.blacklist_empty_line_help) layout.addWidget(dummy_label_bl, num, self.blacklist_column) t_button_group.button(entry.action).setChecked(True) # New: check a button based on how good the downloader is. t_button_group.addButton(t_blacklist_button, Action.Blacklist) self.buttons_groups.append(t_button_group) play_button_group.buttonClicked.connect( lambda button: play( self.entries_list[play_button_group.id(button)].file_path)) # N.B.: anki.sound.play() plays files from anywhere, not just # from the colection.media folder. We should be good, # here. (This behaviour may be a security risk, idk.) old_play_button_group.buttonClicked.connect( lambda button: playFromText( self.note[ self.entries_list[ old_play_button_group.id(button)].audio_field_name]))
class SettingsDialog(QDialog, Ui_Dialog): def __init__(self, parent): super().__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self.lineEdit_loginUsername.setText( app.settings.get("account", "username")) self.lineEdit_loginPassword.setText( app.settings.get("account", "password")) self.checkBox_autoLogin.setChecked( app.settings.getbool("account", "autologin")) self.checkBox_autoStartFrontend.setChecked(app.autoStart) # Xwared Management managedBySystemd = app.xwaredpy.managedBySystemd managedByUpstart = app.xwaredpy.managedByUpstart managedByAutostart = app.xwaredpy.managedByAutostart self.radio_managedBySystemd.setChecked(managedBySystemd) self.radio_managedByUpstart.setChecked(managedByUpstart) self.radio_managedByAutostart.setChecked(managedByAutostart) self.radio_managedByNothing.setChecked(not ( managedBySystemd or managedByUpstart or managedByAutostart)) initType = getInitType() self.radio_managedBySystemd.setEnabled(initType == InitType.SYSTEMD) self.radio_managedByUpstart.setEnabled(initType == InitType.UPSTART) # frontend self.checkBox_enableDevelopersTools.setChecked( app.settings.getbool("frontend", "enabledeveloperstools")) self.checkBox_allowFlash.setChecked( app.settings.getbool("frontend", "allowflash")) self.checkBox_minimizeToSystray.setChecked( app.settings.getbool("frontend", "minimizetosystray")) self.checkBox_closeToMinimize.setChecked( app.settings.getbool("frontend", "closetominimize")) self.checkBox_popNotifications.setChecked( app.settings.getbool("frontend", "popnotifications")) self.checkBox_notifyBySound.setChecked( app.settings.getbool("frontend", "notifybysound")) self.checkBox_showMonitorWindow.setChecked( app.settings.getbool("frontend", "showmonitorwindow")) self.spinBox_monitorFullSpeed.setValue( app.settings.getint("frontend", "monitorfullspeed")) # clipboard related self.checkBox_watchClipboard.stateChanged.connect( self.slotWatchClipboardToggled) self.checkBox_watchClipboard.setChecked( app.settings.getbool("frontend", "watchclipboard")) self.slotWatchClipboardToggled( self.checkBox_watchClipboard.checkState()) self.plaintext_watchPattern.setPlainText( app.settings.get("frontend", "watchpattern")) self.btngrp_etmStartWhen = QButtonGroup() self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2) self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3) startEtmWhen = app.xwaredpy.startEtmWhen if startEtmWhen: self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True) else: self.group_etmStartWhen.setEnabled(False) self.btn_addMount.clicked.connect(self.slotAddMount) self.btn_removeMount.clicked.connect(self.slotRemoveMount) # Mounts self.setupMounts() # backend setting is a different thing! self.setupETM() @pyqtSlot(int) def slotWatchClipboardToggled(self, state): self.plaintext_watchPattern.setEnabled(state) @pyqtSlot() def setupMounts(self): self.table_mounts.setRowCount(0) self.table_mounts.clearContents() mountsMapping = app.mountsFaker.getMountsMapping() for i, mount in enumerate(app.mountsFaker.mounts): self.table_mounts.insertRow(i) # drive1: the drive letter it should map to, by alphabetical order drive1 = app.mountsFaker.driveIndexToLetter(i) self.table_mounts.setItem( i, 0, QTableWidgetItem(drive1 + "\\TDDOWNLOAD")) # mounts = ['/path/to/1', 'path/to/2', ...] self.table_mounts.setItem(i, 1, QTableWidgetItem(mount)) # drive2: the drive letter it actually is assigned to drive2 = mountsMapping.get(mount, "无") errors = [] # check: mapping if drive1 != drive2: errors.append("错误:盘符映射在'{actual}',而不是'{should}'。\n" "如果这是个新挂载的文件夹,请尝试稍等,或重启后端,可能会修复此问题。".format( actual=drive2, should=drive1)) brush = QBrush() if errors: brush.setColor(Qt.red) errString = "\n".join(errors) else: brush.setColor(Qt.darkGreen) errString = "正常" errWidget = QTableWidgetItem(errString) errWidget.setForeground(brush) self.table_mounts.setItem(i, 2, errWidget) del brush, errWidget self.table_mounts.resizeColumnsToContents() @pyqtSlot() def slotAddMount(self): fileDialog = QFileDialog(self, Qt.Dialog) fileDialog.setFileMode(QFileDialog.Directory) fileDialog.setOption(QFileDialog.ShowDirsOnly, True) fileDialog.setViewMode(QFileDialog.List) fileDialog.setDirectory(os.environ["HOME"]) if fileDialog.exec(): selected = fileDialog.selectedFiles()[0] if selected in self.newMounts: return row = self.table_mounts.rowCount() self.table_mounts.insertRow(row) self.table_mounts.setItem( row, 0, QTableWidgetItem( app.mountsFaker.driveIndexToLetter(row) + "\\TDDOWNLOAD")) self.table_mounts.setItem(row, 1, QTableWidgetItem(selected)) self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加")) @pyqtSlot() def slotRemoveMount(self): row = self.table_mounts.currentRow() self.table_mounts.removeRow(row) @pyqtSlot() def accept(self): app.settings.set("account", "username", self.lineEdit_loginUsername.text()) app.settings.set("account", "password", self.lineEdit_loginPassword.text()) app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked()) app.autoStart = self.checkBox_autoStartFrontend.isChecked() app.xwaredpy.managedBySystemd = self.radio_managedBySystemd.isChecked() app.xwaredpy.managedByUpstart = self.radio_managedByUpstart.isChecked() app.xwaredpy.managedByAutostart = self.radio_managedByAutostart.isChecked( ) app.settings.setbool("frontend", "enabledeveloperstools", self.checkBox_enableDevelopersTools.isChecked()) app.settings.setbool("frontend", "allowflash", self.checkBox_allowFlash.isChecked()) app.settings.setbool("frontend", "minimizetosystray", self.checkBox_minimizeToSystray.isChecked()) # A possible Qt bug # https://bugreports.qt-project.org/browse/QTBUG-37695 app.settings.setbool("frontend", "closetominimize", self.checkBox_closeToMinimize.isChecked()) app.settings.setbool("frontend", "popnotifications", self.checkBox_popNotifications.isChecked()) app.settings.setbool("frontend", "notifybysound", self.checkBox_notifyBySound.isChecked()) app.settings.setbool("frontend", "showmonitorwindow", self.checkBox_showMonitorWindow.isChecked()) app.settings.setint("frontend", "monitorfullspeed", self.spinBox_monitorFullSpeed.value()) app.settings.setbool("frontend", "watchclipboard", self.checkBox_watchClipboard.isChecked()) app.settings.set("frontend", "watchpattern", self.plaintext_watchPattern.toPlainText()) if self.group_etmStartWhen.isEnabled(): startEtmWhen = self.btngrp_etmStartWhen.id( self.btngrp_etmStartWhen.checkedButton()) try: app.xwaredpy.startEtmWhen = startEtmWhen except InvalidSocket: QMessageBox.warning( None, "Xware Desktop", "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()), QMessageBox.Ok, QMessageBox.Ok) app.settings.save() app.mountsFaker.mounts = self.newMounts app.settings.applySettings.emit() super().accept() @property def newMounts(self): return list( map(lambda row: self.table_mounts.item(row, 1).text(), range(self.table_mounts.rowCount()))) @pyqtSlot() def setupETM(self): # fill values lcPort = app.xwaredpy.lcPort self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用") etmSettings = app.etmpy.getSettings() if etmSettings: self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit) self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit) self.spinBox_maxRunningTasksNum.setValue( etmSettings.maxRunningTasksNum) # connect signals self.accepted.connect(self.saveETM) else: self.spinBox_dSpeedLimit.setEnabled(False) self.spinBox_uSpeedLimit.setEnabled(False) self.spinBox_maxRunningTasksNum.setEnabled(False) @pyqtSlot() def saveETM(self): newsettings = EtmSetting( dLimit=self.spinBox_dSpeedLimit.value(), uLimit=self.spinBox_uSpeedLimit.value(), maxRunningTasksNum=self.spinBox_maxRunningTasksNum.value()) app.etmpy.saveSettings(newsettings)
class WeatherInput(QWidget): """ Weather parameter input for GUI. Contains selector on whether to scrape, import, or ignore with corresponding windows for each based on current selection e.g. parameter input fields if scraping. """ def __init__(self): super().__init__() self.__init_weather() self.__init_design() def __init_weather(self): self.layout = QVBoxLayout() self.__scrape() self.__import() self.__none() self.__revolver() self.__selector() self.layout.addWidget(self.selector) self.layout.addWidget(self.revolver) self.layout.addWidget(QLabel("Powered by the <a href=\"https://www.weatherbit.io/\">Weatherbit API</a>")) self.setLayout(self.layout) def __scrape(self): input_fields = [("City", "text"), ("State", "text"), ("Country", "text"), ("Days", "text"), ("weatherbit.io Key", "text")] input_defaults = {"City": "Cambridge", "State": "MA", "Country": "US", "Days": "14"} self.scrape_layout, self.scrape_fields = basic_form_creator(input_fields, input_defaults) # adding "Imperial Units" and "Save Weather" options as checkboxes in same row. imperial = QCheckBox("Imperial Units") imperial.setChecked(True) # default is checked save = QCheckBox("Save") self.scrape_fields["Imperial Units"] = imperial self.scrape_fields["Save Weather"] = save self.checkbox_layout = QHBoxLayout() self.checkbox_layout.addWidget(imperial) self.checkbox_layout.addWidget(save) self.checkbox_layout.addStretch() checkbox = QWidget() checkbox.setLayout(self.checkbox_layout) self.scrape_layout.addWidget(checkbox) self.scrape = QWidget(self) self.scrape.setLayout(self.scrape_layout) def __import(self): self.import_layout = QVBoxLayout() button = QPushButton("Browse") self.import_path = QPlainTextEdit() font_height = self.import_path.fontMetrics().height() num_rows = 5 # size of browse window, plenty of space to display full path self.import_path.setFixedHeight(int(num_rows * font_height)) self.import_layout.addWidget(button, 0, Qt.AlignTop | Qt.AlignLeft) # align top-left corner self.import_layout.addWidget(self.import_path, 0, Qt.AlignTop | Qt.AlignLeft) button.clicked.connect(lambda: self.import_path.setPlainText(QFileDialog.getOpenFileName()[0])) self.import_ = QWidget(self) self.import_.setLayout(self.import_layout) def __selector(self): self.selector_layout = QHBoxLayout() self.selector_button_group = QButtonGroup() self.selector_button_group.setExclusive(True) self.none_button = QRadioButton("None") self.scrape_button = QRadioButton("Scrape") self.import_button = QRadioButton("Import") self.selector_button_group.addButton(self.none_button, 1) self.selector_button_group.addButton(self.scrape_button, 2) # need 1-index because 0 means not found self.selector_button_group.addButton(self.import_button, 3) self.selector_layout.addWidget(self.none_button) self.selector_layout.addWidget(self.scrape_button) self.selector_layout.addWidget(self.import_button) self.selector_layout.addStretch() self.scrape_button.setChecked(True) self.selector = QWidget(self) self.selector.setLayout(self.selector_layout) def __none(self): self.none_ = QWidget() def __revolver(self): self.revolver = QStackedWidget() self.revolver.addWidget(self.none_) self.revolver.addWidget(self.scrape) self.revolver.addWidget(self.import_) self.revolver.setCurrentIndex(1) # default setting is scrape def switch_window(self, button): """ Switch input fields based on current selection. :param button: radio button of current selection :return: nothing, mutates object """ self.revolver.setCurrentIndex(self.selector_button_group.id(button) - 1) # make up for 1-index def __init_design(self): self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.scrape_layout.setContentsMargins(0, 3, 11, 0) # effort to line up to TwilightInput self.scrape_layout.setSpacing(5) self.import_layout.setSpacing(10) self.import_layout.addStretch(1) self.selector_layout.setContentsMargins(0, 0, 0, 11) self.checkbox_layout.setContentsMargins(0, 0, 0, 0) self.scrape_layout.addStretch(25) # stretch large enough to move checkboxes close to other fields self.default_border = self.scrape_fields["City"].styleSheet() # just get from any existing line edit self.error_border = "border: 1px solid red;"
class AddVoiceFilesWidget(QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.layout = QVBoxLayout() self.settings = QSettings("voice_file_settings", "GP_IVR_Settings") self.error = False self.browse_button_group = QButtonGroup(self) self.setup_heading() self.voiceflow_settings = QSettings("simplified_voiceflow", "GP_IVR_Settings") self.voice_files = {} self.node_ids = [] self.setup_voice_files_form() self.init_settings() self.setup_buttons() self.setLayout(self.layout) def setup_heading(self): heading_font = QFont('Arial', 12) heading_font.setBold(True) rules_font = QFont('Arial', 10) rules_font.setItalic(True) self.layout.addWidget(QLabel()) heading = QLabel("Add Recorded Voice Files to IVR:") heading.setFont(heading_font) page_info = QLabel( "You can add personal recorded voice files in place of the automatically\n generated voice files for each " "question in the IVR.") file_type_rule = QLabel("* WAV Files Only") file_type_rule.setFont(rules_font) self.layout.addWidget(heading) self.layout.addWidget(page_info) self.layout.addWidget(file_type_rule) def setup_buttons(self): button_layout = QHBoxLayout() back_button_creator = BackButton() self.back_button = back_button_creator.create_back_button() button_layout.addWidget(self.back_button) self.apply_settings_button = QPushButton("Apply") self.apply_settings_button.setToolTip( "Replace IVR voice files with updated files") button_layout.addWidget(self.apply_settings_button) self.layout.addWidget(QLabel()) self.layout.addLayout(button_layout) def init_settings(self): for node in self.voice_files: node_value = self.settings.value(node) if node_value: self.voice_files[node].setText(node_value) def setup_voice_files_form(self): voiceflow_settings = GetVoiceflowSettings( self.voiceflow_settings.value("simplified json")) ivr_texts = voiceflow_settings.get_ivr_texts() if ivr_texts == -1: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Error\n\nYou have not set up an IVR") msg.setWindowTitle("Error") msg.exec_() return for node in ivr_texts: self.add_voice_file_input(ivr_texts[node], node) def add_voice_file_input(self, ivr_text, ivr_node): ivr_text = QLabel(ivr_text) ivr_text.setWordWrap(True) voice_file = WavFileEdit(self) self.button_group = QGroupBox() self.layout.addWidget(self.button_group) self.v_box = QHBoxLayout() self.button_group.setLayout(self.v_box) browse_files_button = QPushButton("Browse", self) browse_files_button.setToolTip("Browse file manager for WAV file") self.v_box.addWidget(ivr_text) grow_label = QLabel() self.v_box.addWidget(grow_label) grow_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.v_box.addWidget(voice_file) self.v_box.addWidget(browse_files_button) self.voice_files[ivr_node] = voice_file self.browse_button_group.addButton(browse_files_button) self.node_ids.append(ivr_node) def get_files(self, voice_file_edit): filepath = QFileDialog.getOpenFileName(self, 'Single File', "~", '*.wav') voice_file_edit.setText(filepath[0]) def apply_settings(self): self.save_settings() voice_file_paths = [] node_ids = [] for node in self.voice_files: voice_file_path_text = self.voice_files[node].text() voice_file_path = Path(voice_file_path_text) if not voice_file_path.is_file(): if not voice_file_path_text: continue msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Error\n\nThe Path Specified is not a File") msg.setWindowTitle("Error") msg.exec_() self.error = True return node_ids.append(node) voice_file_paths.append(self.voice_files[node].text()) if voice_file_paths: modify_voice_files = ModifyVoiceFiles( asterisk_constants.VOICE_FILE_PATH, node_ids, voice_file_paths) modify_voice_files.replace_asterisk_voice_files() def save_settings(self): self.settings.clear() for node in self.voice_files: if self.voice_files[node].text(): self.settings.setValue(node, self.voice_files[node].text()) def browse_files(self, button): voice_file_index = -2 - self.browse_button_group.id(button) self.get_files(self.voice_files[self.node_ids[voice_file_index]])
class ToolBar(QWidget): mouseEntered = pyqtSignal() mouseLeft = pyqtSignal() toolChanged = pyqtSignal(str) primaryInkChanged = pyqtSignal(str) secondaryInkChanged = pyqtSignal(str) def __init__(self): super(ToolBar, self).__init__() self.setAttribute(Qt.WA_StaticContents) self.setAttribute(Qt.WA_NoSystemBackground) self.setFont(ResourcesCache.get("BigFont")) self._registeredTools = {} self._registeredInks = {} self._toolSlots = [] self._inkSlots = [] self._currentActiveToolSlot = None self._previousActiveToolSlot = None self._currentEditedInkSlot = None self._previousEditedInkSlot = None self._editMode = False self._backgroundColor = QColor(40, 40, 40) self._toolLabelColor = QColor(112, 231, 255) self._layout = QVBoxLayout() self._layout.setAlignment(Qt.AlignTop) self._layout.setContentsMargins(4, 4, 4, 4) top_layout = QHBoxLayout() self._layout.addLayout(top_layout) self._toolsLayout = QHBoxLayout() self._inksLayout = QHBoxLayout() self._toolsLayout.setContentsMargins(0, 0, 0, 0) self._toolsLayout.setAlignment(Qt.AlignLeft) self._inksLayout.setContentsMargins(0, 0, 0, 0) self._inksLayout.setAlignment(Qt.AlignRight) top_layout.addLayout(self._toolsLayout) top_layout.addLayout(self._inksLayout) self._toolsButtonGroup = QButtonGroup() self._toolsButtonGroup.buttonClicked.connect( self._on_tool_slot_triggered) self._inksButtonGroup = QButtonGroup() self._inksButtonGroup.setExclusive(False) self._inksButtonGroup.buttonClicked.connect( self._on_ink_slot_triggered) self.setLayout(self._layout) self._toolbarSubPanel = None self._toolsListWidget = None self._toolsOptionsPanel = None self._init_edit_panel() self._add_ink_slot(0) self._add_ink_slot(1) self.resize(0, 50) # ------------------------------------------------------------------------- def get_tool_by_name(self, name): return self._registeredTools[name] def register_tool(self, tool, is_default=None): if tool.name not in self._registeredTools: self._registeredTools[tool.name] = tool self._toolsListWidget.addItem(tool.name) if is_default is True: self._toolsListWidget.setCurrentRow(0) self._build_tool_options_pane(tool) if len(self._toolSlots) < 4: slot_index = self._add_tool_slot(is_default) self._assign_tool_to_slot(tool, slot_index) def register_ink(self, ink, slot): if not ink.name in self._registeredInks: self._registeredInks[ink.name] = ink self._inksListWidget.addItem(ink.name) self._build_ink_options_pane(ink) if self._inkSlots[slot]['id'] is None: self._assign_ink_to_slot(ink, slot) def switch_tool_slot(self, slot): self._previousActiveToolSlot = self._currentActiveToolSlot self._currentActiveToolSlot = slot if self._currentActiveToolSlot == self._previousActiveToolSlot: return tool_name = self._toolSlots[slot]['id'] self._toolSlots[slot]['button'].setChecked(True) self.toolChanged.emit(tool_name) self._select_tool_on_list(tool_name) # ------------------------------------------------------------------------- def _go_back_to_last_tool(self): self.switch_tool_slot(self._previousActiveToolSlot) def _add_tool_slot(self, selected=None): slot_button = QPushButton() slot_button.setCheckable(True) index = len(self._toolSlots) if selected is not None and selected is True: slot_button.setChecked(True) slot = {'id': None, 'button': slot_button} if selected: self._currentActiveToolSlot = index self._toolSlots.append(slot) self._toolsButtonGroup.addButton(slot_button, index) self._toolsLayout.addWidget(slot_button) return index def _add_ink_slot(self, slot_number): slot_button = QPushButton() slot_button.setFont(self.font()) slot_button.setStyleSheet( "border-color: rgb(56,56,56); background-color: rgb(17,17," "17); font-size: 12pt;") index = len(self._inkSlots) if slot_number == 0: icon = QIcon() icon.addPixmap(QPixmap(":/icons/ico_mouse_button1"), QIcon.Normal, QIcon.Off) slot_button.setIcon(icon) slot_button.setIconSize(QSize(18, 23)) elif slot_number == 1: icon = QIcon() icon.addPixmap(QPixmap(":/icons/ico_mouse_button2"), QIcon.Normal, QIcon.Off) slot_button.setIcon(icon) slot_button.setIconSize(QSize(18, 23)) slot = {'id': None, 'button': slot_button} self._inkSlots.append(slot) self._inksButtonGroup.addButton(slot_button) self._inksButtonGroup.setId(slot_button, index) self._inksLayout.addWidget(slot_button) return index def _assign_tool_to_slot(self, tool, slot): if slot < 0 or slot > len(self._toolSlots) - 1: raise Exception( '[ToolBar] > _assignToolToSlot : invalid slot parameter') self._toolSlots[slot]['id'] = tool.name icon = tool.icon if icon is not None: tool_button = self._toolSlots[slot]['button'] tool_button.setIcon(tool.icon) tool_button.setIconSize(QSize(24, 24)) def _assign_ink_to_slot(self, ink, slot): if slot != 0 and slot != 1: raise Exception( '[ToolBar] > _assignInkToSlot : invalid slot parameter') ink_name = ink.name self._inkSlots[slot]['id'] = ink_name self._inkSlots[slot]['button'].setText(ink_name) if slot == 0: self.primaryInkChanged.emit(ink_name) elif slot == 1: self.secondaryInkChanged.emit(ink_name) def _init_edit_panel(self): self._toolbarSubPanel = QStackedWidget() # 1. Initialize Tools Control Panel ----------------------------------- self._toolsListWidget = QListWidget() self._toolsListWidget.currentRowChanged.connect( lambda v: self._toolsOptionsPanel.setCurrentIndex(v)) self._toolsListWidget.setMaximumSize(QSize(150, 200)) self._toolsListWidget.itemClicked.connect( self._on_tool_list_item_clicked) # Tools Subpanel ------------------------------------------------------ tools_control_panel = QWidget() tools_control_panel_layout = QHBoxLayout() tools_control_panel.setLayout(tools_control_panel_layout) tools_control_panel_layout.setAlignment(Qt.AlignLeft) # Tools List ---------------------------------------------------------- tools_list_sublayout = QVBoxLayout() tools_list_sublayout.setAlignment(Qt.AlignTop) tools_list_sublayout.setContentsMargins(0, 0, 0, 0) tools_list_sublayout.addWidget(QLabel("Tools")) tools_list_sublayout.addWidget(self._toolsListWidget) tools_control_panel_layout.addLayout(tools_list_sublayout) # Tools Options ------------------------------------------------------- tools_options_sublayout = QVBoxLayout() tools_options_sublayout.setAlignment(Qt.AlignTop) tools_control_panel_layout.addLayout(tools_options_sublayout) self._toolsOptionsPanel = QStackedWidget() tools_options_sublayout.addWidget(QLabel("Tools Options")) tools_options_sublayout.addWidget(self._toolsOptionsPanel) self._toolbarSubPanel.addWidget(tools_control_panel) # 2. Initialize Inks Control Panel ------------------------------------ self._inksListWidget = QListWidget() self._inksListWidget.currentRowChanged.connect( lambda v: self._inksOptionsPanel.setCurrentIndex(v)) self._inksListWidget.setMaximumSize(QSize(150, 200)) self._inksListWidget.itemClicked.connect( self._on_ink_list_item_clicked) # Inks Subpanel ------------------------------------------------------- inks_control_panel = QWidget() inks_control_panel_layout = QHBoxLayout() inks_control_panel.setLayout(inks_control_panel_layout) inks_control_panel_layout.setAlignment(Qt.AlignLeft) # Inks List ----------------------------------------------------------- inks_list_sublayout = QVBoxLayout() inks_list_sublayout.setAlignment(Qt.AlignTop) inks_list_sublayout.setContentsMargins(0, 0, 0, 0) inks_list_sublayout.addWidget(QLabel("Inks")) inks_list_sublayout.addWidget(self._inksListWidget) inks_control_panel_layout.addLayout(inks_list_sublayout) # Inks Options -------------------------------------------------------- inks_options_sublayout = QVBoxLayout() inks_options_sublayout.setAlignment(Qt.AlignTop) inks_control_panel_layout.addLayout(inks_options_sublayout) self._inksOptionsPanel = QStackedWidget() inks_options_sublayout.addWidget(QLabel("Ink Options")) inks_options_sublayout.addWidget(self._inksOptionsPanel) self._toolbarSubPanel.addWidget(inks_control_panel) # --------------------------------------------------------------------- self._layout.addWidget(self._toolbarSubPanel) self._toolbarSubPanel.setVisible(False) def _build_tool_options_pane(self, tool): pane = QWidget() pane_layout = QVBoxLayout() pane_layout.setAlignment(Qt.AlignTop) pane.setLayout(pane_layout) for prop in tool.properties.values(): field_layout = QHBoxLayout() field_layout.addWidget(QLabel(prop.description)) prop_widget = prop.build_property_widget() field_layout.addWidget(prop_widget) pane_layout.addLayout(field_layout) self._toolsOptionsPanel.addWidget(pane) def _build_ink_options_pane(self, ink): pane = QWidget() pane_layout = QVBoxLayout() pane_layout.setAlignment(Qt.AlignTop) pane.setLayout(pane_layout) for prop in ink.properties.values(): field_layout = QHBoxLayout() field_layout.addWidget(QLabel(prop.description)) prop_widget = prop.build_property_widget() field_layout.addWidget(prop_widget) pane_layout.addLayout(field_layout) self._inksOptionsPanel.addWidget(pane) def _select_tool_on_list(self, tool_name): tool_list_item = \ self._toolsListWidget.findItems(tool_name, Qt.MatchExactly)[0] if tool_list_item is not None: self._toolsListWidget.setCurrentItem(tool_list_item) def _select_ink_on_list(self, ink_name): ink_list_item = \ self._inksListWidget.findItems(ink_name, Qt.MatchExactly)[0] if ink_list_item is not None: self._inksListWidget.setCurrentItem(ink_list_item) def _toggle_edit_mode(self): if not self._editMode: self._show_sub_panel() else: self._hide_sub_panel() self.update() def _show_sub_panel(self): self._editMode = True self.resize(self.width(), 300) self._toolbarSubPanel.setVisible(True) def _hide_sub_panel(self): self._editMode = False self.resize(self.width(), 50) self._toolbarSubPanel.setVisible(False) self._finish_ink_edit_mode() def _finish_ink_edit_mode(self): if self._currentEditedInkSlot is not None: self._inksButtonGroup.button(self._currentEditedInkSlot). \ setStyleSheet("border-color: rgb(56,56,56);") self._currentEditedInkSlot = None self._previousEditedInkSlot = None self._inksListWidget.setCurrentRow(0) self._toolbarSubPanel.setCurrentIndex(0) # ------------------------------------------------------------------------- def mousePressEvent(self, e): self._toggle_edit_mode() e.accept() def wheelEvent(self, e): e.accept() def enterEvent(self, e): self.mouseEntered.emit() self.setCursor(Qt.PointingHandCursor) def leaveEvent(self, e): self.mouseLeft.emit() def _on_tool_slot_triggered(self): self._toolbarSubPanel.setCurrentIndex(0) triggered_slot = self._toolsButtonGroup.checkedId() if self._currentEditedInkSlot is not None: self._finish_ink_edit_mode() self.switch_tool_slot(triggered_slot) self.update() def _on_ink_slot_triggered(self, slot_button): if not self._editMode: self._show_sub_panel() triggered_slot_id = self._inksButtonGroup.id(slot_button) if triggered_slot_id != self._currentEditedInkSlot: self._previousEditedInkSlot = self._currentEditedInkSlot self._currentEditedInkSlot = triggered_slot_id if self._previousEditedInkSlot is not None: self._inksButtonGroup. \ button(self._previousEditedInkSlot). \ setStyleSheet("border-color: rgb(56,56,56);") slot_button.setStyleSheet("border-color: rgb(255,0,0);") self._toolbarSubPanel.setCurrentIndex(1) ink_name = self._inkSlots[triggered_slot_id]['id'] self._select_ink_on_list(ink_name) if triggered_slot_id == 0: self.primaryInkChanged.emit(ink_name) elif triggered_slot_id == 1: self.secondaryInkChanged.emit(ink_name) else: self._hide_sub_panel() def _on_tool_list_item_clicked(self, new_item): new_item_name = new_item.text() self._assign_tool_to_slot(self.get_tool_by_name(new_item_name), self._currentActiveToolSlot) self.toolChanged.emit(new_item_name) self._toolbarSubPanel.update() def _on_ink_list_item_clicked(self, item): item_name = item.text() ink = self._registeredInks[item_name] if ink is not None: self._assign_ink_to_slot(ink, self._currentEditedInkSlot)
class VistaListaPrenotazioni( QWidget): # Apre la vista che visualizza la lista delle prenotazioni. def __init__(self, tipo): super(VistaListaPrenotazioni, self).__init__() self.tipo = tipo self.controller = ControllerListaPrenotazioni() # Inserisce in 'lista_prenotazioni' le informazioni della 'lista_prenotazioni.pickle'. # Se la lista è vuota l'utente è notificato con un messaggio di errore self.stylesheet_label = """ QLabel{ background-color: grey; border: 1px solid #dfdfdf; } """ self.stylesheet_window = """ QWidget{ background-color: #dfdfdf } """ self.stylesheet_button_back = """ QPushButton{ border-radius: 15px; background-color: transparent; } QPushButton::Pressed{ background-color: transparent; } """ self.stylesheet_button = """ QPushButton{ background-color: #cc3234; color: white; border-radius: 15px; } QPushButton::Pressed{ background-color: grey; } """ self.stylesheet_table = """ QTableWidget{ background-color: white; } """ self.stylesheet_pagamento = """ QPushButton{ background-color: transparent; border-color: transparent; } QPushButton::Pressed{ background-color: grey; } """ # Inserimento e impostazioni grafiche dell'immagine dello sfondo della finestra. self.imagePath = "Image/foto.png" self.image = QImage(self.imagePath) self.label = QLabel(self) self.label.setPixmap(QPixmap.fromImage(self.image)) self.label.setScaledContents(True) self.label.setGeometry(0, 0, 970, 750) # Inserimento della tabella e intestazione delle colonne. self.table = QTableWidget(self) self.table.setColumnCount(4) self.table.setRowCount(1) self.table.setItem(0, 0, QTableWidgetItem("ID")) self.table.setItem(0, 1, QTableWidgetItem("Tipo")) self.table.setItem(0, 2, QTableWidgetItem("Data")) self.table.setItem(0, 3, QTableWidgetItem("Elimina")) self.set_data( ) # Inserisce nella tabella i dati contenuti nella lista_prenotazioni. # Impostazioni grafiche della tabella. self.table.setGeometry(50, 30, 870, 550) self.table.setColumnWidth(0, 100) self.table.setColumnWidth(1, 350) self.table.setColumnWidth(2, 350) self.table.setColumnWidth(3, 70) self.table.setStyleSheet(self.stylesheet_table) self.table.horizontalHeader().setStretchLastSection(True) self.table.horizontalHeader().hide() self.table.horizontalScrollBar().setDisabled(True) self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table.verticalHeader().hide() self.table.setEditTriggers(self.table.NoEditTriggers) self.table.setSelectionMode(self.table.NoSelection) self.table.setFocusPolicy(Qt.NoFocus) # Inserimento e impostazioni grafiche del bottone per tornare alla vista precedente. self.button_back = QPushButton(self) self.button_back.setIcon(QIcon('Image/back.png')) self.button_back.setIconSize(QSize(90, 90)) self.button_back.setGeometry(50, 600, 90, 90) self.button_back.setStyleSheet(self.stylesheet_button_back) self.button_back.clicked.connect(self.go_back) # Inserimento e impostazioni grafiche del bottone che consente di aggiungere un orario per # le prenotazioni. self.button_new_prenotazione = QPushButton(self) self.button_new_prenotazione.setText("Aggiungi orari") self.font_button = QFont("Times", 11) self.button_new_prenotazione.setFont(self.font_button) self.button_new_prenotazione.setGeometry(780, 620, 140, 50) self.button_new_prenotazione.setStyleSheet(self.stylesheet_button) self.button_new_prenotazione.clicked.connect(self.go_aggiungi_orari) # Impostazioni grafiche generali della finestra del programma. self.setWindowTitle("Lista Prenotazioni") self.resize(970, 700) self.setFixedSize(self.size()) self.setStyleSheet(self.stylesheet_window) # == set_data == # La funzione si occupa di salvare le informazioni relative alla prenotazione e contenute nel file # 'lista_prenotazioni.pickle' nella tabella della VistaListaPrenotazioni. def set_data(self): self.button_group_elimina = QButtonGroup() self.cancella_icon = QIcon("Image/delete.png") i = 1 n_righe = len(self.controller.get_lista_prenotazioni()) self.table.setRowCount(n_righe + 1) self.button_group_elimina.buttonClicked.connect( self.on_selection_elimina) for prenotazione in self.controller.get_lista_prenotazioni(): self.controller_prenotazione = ControllerPrenotazione(prenotazione) self.table.setItem( i, 0, QTableWidgetItem(self.controller_prenotazione.get_id())) self.table.setItem( i, 1, QTableWidgetItem(self.controller_prenotazione.get_tipo())) self.table.setItem( i, 2, QTableWidgetItem(self.controller_prenotazione.get_data())) if i % 2 != 0: for j in range(0, 3): self.table.item(i, j).setBackground(QColor(224, 224, 224)) self.delete = QPushButton() self.delete.setIcon(self.cancella_icon) self.delete.setIconSize(QSize(35, 35)) self.delete.setStyleSheet(self.stylesheet_pagamento) self.button_group_elimina.addButton(self.delete, i) self.table.setCellWidget(i, 3, self.delete) i = i + 1 # == go_back == # La funzione si occupa di aprire la finestra precedente. def go_back(self): self.go_prenotazioni = VistaHomeIstruttore.VistaHomeIstruttore( self.tipo) self.go_prenotazioni.show() self.close() # == go_aggiungi_orari == # La funzione si occupa di aprire la VistaAggiungiOrari. def go_aggiungi_orari(self): self.aggiungi_orari = VistaAggiungiOrari(self.tipo) self.aggiungi_orari.show() self.close() def go_elimina(self, i): conferma = QMessageBox.question( self, "Attenzione", "Sei sicuro di voler eliminare questo orario?", QMessageBox.No, QMessageBox.Yes) if conferma == QMessageBox.Yes: self.controller.rimuovi_prenotazione_by_index(i - 1) self.refresh() else: return def refresh(self): self.go_lista = VistaListaPrenotazioni(self.tipo) self.go_lista.show() self.close() def on_selection_elimina(self, selected): self.go_elimina(self.button_group_elimina.id(selected))
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.path = os.path.join(os.getcwd(), "Projects") # Путь к папке с проектами self.projects = os.listdir(self.path) # Проекты self.current_project = "" # Имя проекта self.current_test = "" # Имя испытания self.data = pd.DataFrame() # Data from excel self.x = [] # Data for x self.x_name = "" # Имя столбца по оси X self.y = [] # Chosen columns self.type_flag = False # Необходимо для проверки данных на соответствие типу данных (число) self.table_ready = False self.file_path = "" # Отвечает за путь к .xlsx файлу self.additional_data_flag = False # Флаг, обозначающий, что данные нужно дополнить self.x_min = 0 # Нижняя граница дополнения self.x_max = 0 # Верхняя граница дополнения self.changed_flag = False self.y_filtered = {} # Фильтрованные данные (y) self.incorrect_data = {} # Данные с ошибками self.many_cells = False # Флаг для метода изменения значений в нескольких ячейках self.is_loading = False # Флаг текущей загрузки self.setWindowTitle("Excel to data") self.central_widget = QWidget(self) # Создаём центральный виджет self.setCentralWidget(self.central_widget) # Создаём все расположения main_layout = QHBoxLayout() # Главное left_layout = QVBoxLayout( ) # Для проектов, испытаний и вывода данных и .data self.project_layout = QVBoxLayout() # Для проектов self.tests_layout = QVBoxLayout() # Для испытаний data_layout = QHBoxLayout() # Для представления данных graph_layout = QVBoxLayout() # Для графиков # Часть для окна с данными self.table = QTableWidget(self) # Пустая таблица self.table.setMinimumWidth( int(QApplication.desktop().availableGeometry().width() * 0.3)) self.table.cellChanged.connect( self.change_cell) # Возможность редактирования данных # Часть для графиков pg.setConfigOption('foreground', pg.mkColor("000000")) # Создаём поле для графика self.originalGraphWidget = pg.PlotWidget() self.originalGraphWidget.setBackground('w') self.originalGraphWidget.setTitle("Исходные данные") self.originalGraphWidget.setLabel('left', 'Values') self.originalGraphWidget.setLabel('bottom', 'X') self.originalGraphWidget.showGrid(x=True, y=True) self.originalGraphWidget.addLegend() # Описание: цвет - график # Создаём поле для изменённого графика self.changedGraphWidget = pg.PlotWidget() self.changedGraphWidget.setBackground('w') self.changedGraphWidget.setTitle("Изменённые данные") self.changedGraphWidget.setLabel('left', 'Values') self.changedGraphWidget.setLabel('bottom', 'X') self.changedGraphWidget.showGrid(x=True, y=True) self.changedGraphWidget.addLegend() self.original_plt = [] self.changed_plt = [] # Часть для вывода self.out_text = QTextEdit() self.out_text.setMaximumHeight( int(QApplication.desktop().availableGeometry().height() * 0.3)) self.out_text.setReadOnly(True) # Второй поток self.threadclass = thread.ThreadClass(self) self.threadclass.finishSignal.connect(self.finishSignal_process) data_layout.addLayout(self.project_layout) data_layout.addLayout(self.tests_layout) data_layout.addWidget(self.table) left_layout.addLayout(data_layout) left_layout.addWidget(self.out_text) graph_layout.addWidget(self.originalGraphWidget) graph_layout.addWidget(self.changedGraphWidget) main_layout.addLayout(left_layout) main_layout.addLayout(graph_layout) self.central_widget.setLayout(main_layout) self.create_menuBar() self.update_project_layout() self.update_tests_layout() def create_menuBar(self): menuBar = self.menuBar() file_menu = menuBar.addMenu("Файл") create_menu = file_menu.addMenu("Создать") self.project_action = QAction("Проект", self) self.project_action.triggered.connect(self.create_project) self.test_action = QAction("Данные испытаний", self) self.test_action.setEnabled(False) self.test_action.triggered.connect(self.add_test) create_menu.addAction(self.project_action) create_menu.addAction(self.test_action) delete_menu = file_menu.addMenu("Удалить") self.delete_prj_action = QAction("Проект", self) self.delete_prj_action.triggered.connect(self.delete_prj_folder) self.delete_test_action = QAction("Данные испытаний", self) self.delete_test_action.triggered.connect(self.delete_test_folder) delete_menu.addAction(self.delete_prj_action) delete_menu.addAction(self.delete_test_action) data_menu = menuBar.addMenu("Данные") self.conversion_action = QAction("Конвертировать в .data", self) self.conversion_action.setEnabled(False) self.conversion_action.triggered.connect(self.convert_data) self.set_x_action = QAction("Назначить ось абсцисс", self) self.set_x_action.setEnabled(False) self.set_x_action.triggered.connect(self.set_x) self.graph_action = QAction("Построить график", self) self.graph_action.setEnabled(False) self.graph_action.triggered.connect(self.get_graph) self.copy_action = QAction("Копировать данные", self) self.copy_action.setEnabled(False) self.copy_action.triggered.connect(self.copy_test) data_menu.addAction(self.graph_action) data_menu.addAction(self.conversion_action) data_menu.addAction(self.set_x_action) data_menu.addAction(self.copy_action) change_menu = data_menu.addMenu("Изменить") self.data_action = QAction("Данные в выбранных ячейках", self) self.data_action.setEnabled(False) self.data_action.triggered.connect(self.change_data_in_chosen_cells) self.column_action = QAction("Порядок столбцов", self) self.column_action.setEnabled(False) self.column_action.triggered.connect(self.enumerate_col) change_menu.addAction(self.data_action) change_menu.addAction(self.column_action) self.delete_action = QAction("Удалить столбцы", self) self.delete_action.setEnabled(False) self.delete_action.triggered.connect(self.delete_column) data_menu.addAction(self.delete_action) graph_menu = menuBar.addMenu("График") self.filter_action = QAction("Фильтровать", self) self.filter_action.setEnabled(False) self.filter_action.triggered.connect(self.filter_data) self.add_action = QAction("Изменить диапозон Х", self) self.add_action.setEnabled(False) self.add_action.triggered.connect(self.add_data) graph_menu.addAction(self.filter_action) graph_menu.addAction(self.add_action) save_menu = graph_menu.addMenu("Сохранить") self.original_action = QAction("Исходное изображение", self) self.original_action.setEnabled(False) self.original_action.triggered.connect( lambda state, graphWidget=self.originalGraphWidget: self. save_graph(graphWidget)) self.changed_action = QAction("Изменённое изображение", self) self.changed_action.setEnabled(False) self.changed_action.triggered.connect( lambda state, graphWidget=self.changedGraphWidget: self.save_graph( graphWidget)) save_menu.addAction(self.original_action) save_menu.addAction(self.changed_action) def init_prj_context_menu(self, name): self.current_project = name context_menu = QMenu(self) add_data = QAction("Добавить данные испытаний", self) add_data.triggered.connect(self.add_test) delete_project = QAction("Удалить проект", self) delete_project.triggered.connect( lambda state: self.delete_prj_folder(name)) context_menu.addAction(add_data) context_menu.addAction(delete_project) context_menu.exec_(QCursor.pos()) def init_header_context_menu(self, name): context_menu = QMenu(self) set = QAction("Сделать осью абсцисс", self) #set.triggered.connect(lambda state: self.set_x(name)) context_menu.addAction(set) context_menu.exec_(QCursor.pos()) def set_x(self): items = self.data.columns.to_list() item, ok = QInputDialog().getItem(self, "Назначение оси абсцисс", "Выберите:", items, 0, False) if ok and item != '': self.x_name = item def loading_data(self): self.out_text.clear() self.out_text.setText("Подождите. Идёт загрузка данных...") def update_project_layout(self): clear_layout(self.project_layout) self.projects = os.listdir(self.path) if len(self.projects) == 0: empty_lbl = QLabel("Нет созданных проектов") empty_lbl.setStyleSheet('font-size: 11pt') self.project_layout.addWidget(empty_lbl) else: box = QGroupBox() inner_layout = QVBoxLayout() project_lbl = QLabel("Проекты:") project_lbl.setStyleSheet('font-size: 11pt') self.project_layout.addWidget(project_lbl) self.buttons = QButtonGroup() self.buttons.buttonClicked[int].connect(self.choose_project) for folder in range(len(self.projects)): button = QPushButton(self.projects[folder], self) button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: 11pt; ' 'font-weight: 100') button.setContextMenuPolicy(Qt.CustomContextMenu) button.customContextMenuRequested.connect( lambda state, name=self.projects[ folder]: self.init_prj_context_menu(name)) self.buttons.addButton(button, folder) inner_layout.addWidget(button) inner_layout.addStretch(1) box.setLayout(inner_layout) scroll = QScrollArea() scroll.setWidget(box) scroll.setWidgetResizable(True) self.project_layout.addWidget(scroll) def update_tests_layout(self): clear_layout(self.tests_layout) if self.current_project != '': folder_path = os.path.join(self.path, self.current_project) tests = os.listdir(folder_path) # Добавляем кнопки для всех файлов, лежащих в папке # Добавляем ScrollArea, чтобы можно было прокручивать вниз, если файлов очень много if len(tests) == 0: empty_lbl = QLabel("Нет созданных испытаний") empty_lbl.setStyleSheet('font-size: 11pt') self.tests_layout.addWidget(empty_lbl) else: test_lbl = QLabel(self.current_project + ':') test_lbl.setStyleSheet('font-size: 11pt') self.tests_layout.addWidget(test_lbl) self.test_buttons = QButtonGroup() self.test_buttons.buttonClicked[int].connect(self.test_pushed) box = QGroupBox() # Необходимо для ScrollArea inner_layout = QVBoxLayout() for test in range( len(tests)): # Добавляем каждую внутреннюю директорию button = QPushButton(tests[test], self) button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: 11pt; ' 'font-weight: 100') # В обработчик нажатия передаём путь, чтобы определять, что нужно открыть self.test_buttons.addButton(button, test) inner_layout.addWidget(button) inner_files = os.listdir( os.path.join(folder_path, tests[test])) for file in inner_files: # Добавляем каждый файл из внутренних директорий button = QPushButton('- ' + file) button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: ' '9pt; font-weight: 100; margin-left: 20px') # В обработчик нажатия передаём путь, чтобы определять, что нужно открыть button.clicked.connect( lambda state, file_path=os.path.join( folder_path, tests[test], file ): self.file_pushed(file_path)) inner_layout.addWidget(button) if os.path.isdir( os.path.join(folder_path, tests[test], file)): data_files = os.listdir( os.path.join(folder_path, tests[test], file)) for df in data_files: button = QPushButton('> ' + df) button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: ' '7pt; font-weight: 100; margin-left: 40px') button.clicked.connect( lambda state, file_path=os.path.join( folder_path, tests[test], file, df ): self.file_pushed(file_path)) inner_layout.addWidget(button) box.setLayout(inner_layout) scroll = QScrollArea() scroll.setWidget(box) scroll.setWidgetResizable(True) self.tests_layout.addWidget(scroll) def choose_project(self, id): for button in self.buttons.buttons(): if self.buttons.id(button) == id: self.current_project = button.text() button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: 11pt; font-weight: 700; ' 'color: yellow') else: button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: 11pt; font-weight: 100;' ) self.test_action.setEnabled(True) self.copy_action.setEnabled(False) self.update_tests_layout() def test_pushed(self, id): self.incorrect_data = dict.fromkeys(self.data.columns, 0) for button in self.test_buttons.buttons(): if self.test_buttons.id(button) == id: self.current_test = button.text() button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: 11pt; font-weight: 700; ' 'color: yellow') else: button.setStyleSheet( 'background: transparent; text-align: left; border: none; font-size: 11pt; font-weight: 100;' ) self.conversion_action.setEnabled(True) self.data_action.setEnabled(True) self.column_action.setEnabled(True) self.copy_action.setEnabled(True) self.delete_action.setEnabled(True) self.set_x_action.setEnabled(True) # Находим файл с таблицей xlsx = os.listdir( os.path.join(self.path, self.current_project, self.current_test)) xlsx = [i for i in xlsx if ('.xlsx' in i) and i != 'out.xlsx'] self.file_path = os.path.join(self.path, self.current_project, self.current_test, xlsx[0]) self.loading_data() self.threadclass.start() def finishSignal_process(self): self.create_table() if '.data' in self.file_path: self.draw_data_graph() def copy_test(self): item, ok = QInputDialog.getItem(self, "Выбор проекта", "Проект", tuple(self.projects), 0, False) if ok and item: cur_path = os.path.join(self.path, self.current_project, self.current_test) new_path = os.path.join(self.path, item, self.current_test + "-copy") try: os.mkdir(new_path) paths = [ i for i in os.listdir( os.path.join(self.path, self.current_project, self.current_test)) if ('.xlsx' in i) or ('.data' in i) ] for p in paths: shutil.copy(os.path.join(cur_path, p), new_path) except FileExistsError: QMessageBox.about(self, "Предупреждение", "Копия уже была создана") def create_project(self): name, ok = QInputDialog.getText(self, 'Создание проекта', 'Введите название нового проекта:') if ok: if name in self.projects: QMessageBox.about(self, 'Ошибка', 'Проект с таким именем уже существует.') else: pat = "[\w-]+" # Шаблон для названия if re.sub(pat, "", name, 1) == "": os.mkdir(os.path.join(self.path, name)) self.projects.append(name) self.update_project_layout() else: QMessageBox.about( self, 'Ошибка', 'Название проекта может состоять из букв, цифр, а также знаков ' 'тире и нижнего подчёркивания.') def add_test(self): self.aw = aw.AddWindow(self) self.aw.show() def enumerate_col(self): self.cw = cw.ColumnsWindow(self) self.cw.show() def create_table(self): if self.file_path != "": self.x_name = self.data.columns[0] self.x = list(self.data[self.x_name]) self.type_flag = False self.table_ready = False headers = self.data.columns.to_list() self.clear_table() self.table.setColumnCount(len(headers)) self.table.setRowCount(len(self.data)) self.table.setHorizontalHeaderLabels(headers) self.incorrect_data = dict.fromkeys(headers, 0) for i in range(len(headers)): for j in range(len(self.data)): self.table.setItem( j, i, QTableWidgetItem(str(self.data.iloc[j, i]))) self.table_ready = True self.table.insertRow(0) # Добавляем ряд с checkbox for i in range(0, len(headers)): item = QTableWidgetItem() item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setCheckState(Qt.Unchecked) self.table.setItem(0, i, item) # делаем ресайз колонок по содержимому self.table.resizeColumnsToContents() incorrect_columns = [ key for key, value in self.incorrect_data.items() if value != 0 ] self.paint_headers(incorrect_columns) if len(incorrect_columns) != 0: self.conversion_action.setEnabled(False) self.graph_action.setEnabled(False) else: self.conversion_action.setEnabled(True) self.graph_action.setEnabled(True) def clear_table(self): while self.table.rowCount() > 0: self.table.removeRow(0) def paint_headers(self, columns): message = "Некорректные данные в столбцах: \n" for i in range(len(self.data.columns)): header = self.table.horizontalHeaderItem(i) header.setText(header.text().replace('*', '')) if self.data.columns[i] in columns: message += header.text() + "\n" header.setText('*' + header.text()) if message == "Некорректные данные в столбцах: \n": message = "Все данные в верном формате" else: message += "\nДанные могут быть представлены только в числовом формате.\n" \ "Для изменения значений выделите нужные ячейки и нажмите " \ "'Данные' - 'Изменить' - 'Данные в выбранных ячейках'." self.out_text.clear() self.out_text.setText(message) def convert_data(self): self.get_checked_columns() text, ok = QInputDialog.getText(self, 'Конвертация данных', 'Введите название файла:') files = os.listdir( os.path.join(self.path, self.current_project, self.current_test, "Изменённые_данные")) if ok: pat = "[\w-]+" # Шаблон для названия if re.sub(pat, "", text, 1) == "": if not ((text + '.data') in files): self.data.to_excel(os.path.join(self.path, self.current_project, self.current_test, "Изменённые_данные", text + '.xlsx'), columns=self.y, index=False) self.data.to_csv(os.path.join(self.path, self.current_project, self.current_test, "Изменённые_данные", text + '.data'), sep=' ', columns=self.y, header=True, index=False) QMessageBox.about(self, "Конвертация", "Конвертация завершена") self.update_tests_layout() else: QMessageBox.about( self, "Ошибка", "Файлы с такими названиями уже существуют") else: QMessageBox.about( self, 'Ошибка', 'Название проекта может состоять из букв, цифр, а также знаков ' 'тире и нижнего подчёркивания.') def get_checked_columns(self): self.y.clear() for i in range(0, self.table.columnCount()): if self.table.item(0, i).checkState() == Qt.Checked: self.y.append(self.data.columns[i]) # Add labels of columns def get_graph(self): self.data = self.data.sort_values( by=self.x_name) # Сортируем данные по возрастанию x self.x = list(self.data[self.x_name]) self.filter_action.setEnabled(True) self.add_action.setEnabled(True) self.original_action.setEnabled(True) self.get_checked_columns() self.draw_graph() def change_cell(self, row, column): if self.table_ready: if row != 0: t = str(type(self.data.iloc[row - 1, column])) self.data.iloc[row - 1, column] = self.table.item(row, column).text() try: value = float(self.table.item(row, column).text()) self.data.iloc[row - 1, column] = value if not ('float' in t) and not ('int' in t): self.incorrect_data[self.data.columns[column]] -= 1 except (TypeError, ValueError): if not self.many_cells: QMessageBox.about(self, "Ошибка", "Введены некорректные данные") self.conversion_action.setEnabled(False) self.graph_action.setEnabled(False) if 'float' in t or 'int' in t: self.incorrect_data[self.data.columns[column]] += 1 incorrect_columns = [ key for key, value in self.incorrect_data.items() if value != 0 ] self.paint_headers(incorrect_columns) if len(incorrect_columns) != 0: self.conversion_action.setEnabled(False) self.graph_action.setEnabled(False) else: self.conversion_action.setEnabled(True) self.graph_action.setEnabled(True) else: t = str(type(self.data.iloc[row - 1, column])) if not ('float' in t) and not ('int' in t): self.incorrect_data[self.data.columns[column]] += 1 def change_data_in_chosen_cells(self): cells = self.table.selectedIndexes() if len(cells) == 0: QMessageBox.about(self, "Ошибка", "Ни одна ячейка не была выбрана") else: text, ok = QInputDialog.getText(self, 'Изменение данных', 'Введите число:') if ok: try: value = float(text) except (TypeError, ValueError): QMessageBox.about(self, "Ошибка", "Введены некорректные данные") self.many_cells = True for cell in cells: row = cell.row() column = cell.column() item = QTableWidgetItem() item.setText(text) self.table.setItem(row, column, item) self.many_cells = False # Метод для сохранения картинок графиков def save_graph(self, graphWidget): exporter = pg.exporters.ImageExporter(graphWidget.plotItem) exporter.params.param('width').setValue( graphWidget.range.width(), blockSignal=exporter.widthChanged) exporter.params.param('height').setValue( graphWidget.range.height(), blockSignal=exporter.heightChanged) text, ok = QInputDialog.getText(self, 'Сохранение', 'Введите название файла:') if ok: # save to file exporter.export( os.path.join(self.path, self.current_project, self.current_test, text + '.png')) # Метод для отрисовки графиков в первый раз def draw_graph(self): self.originalGraphWidget.clear() self.changedGraphWidget.clear() self.changed_plt.clear() self.original_plt.clear() for col in self.y: if col != self.x_name: self.changed_plt.append( plot([0], [0], col, self.changedGraphWidget)) self.original_plt.append( plot(self.x, list(self.data[col]), col, self.originalGraphWidget)) # Метод для отрисовки данных по .data def draw_data_graph(self): self.originalGraphWidget.clear() self.changedGraphWidget.clear() self.changed_plt.clear() self.original_plt.clear() for col in self.data.columns: if col != self.x_name: self.original_plt.append( plot(self.x, list(self.data[col]), col, self.originalGraphWidget)) self.changed_plt.append( plot([0], [0], col, self.changedGraphWidget)) # Метод для обновления данных на графиках def update_graph(self): # plot data: x, y values self.changed_flag = False for col in range(len(self.y)): if self.y[col] != self.x_name: flag = False for fc in self.y_filtered.keys(): if fc == self.y[col]: flag = True break if flag: # Если эти данные были отфильтрованы values = list(self.y_filtered.get(self.y[col])) self.changed_flag = True else: values = list(self.data[self.y[col]]) if self.additional_data_flag: # Если есть дополнения к графику self.changed_flag = True x = list(enumerate(self.x, 0)) min_value = min(x, key=lambda j: j[1]) max_value = max(x, key=lambda j: j[1]) new_x = [] new_y = [] for i in range(len(self.x)): if self.x_min <= self.x[i] <= self.x_max: new_x.append(self.x[i]) new_y.append(values[i]) if min_value[1] > self.x_min: new_x.insert(0, self.x_min) new_y.insert(0, values[min_value[0]]) if max_value[1] < self.x_max: new_x.insert(len(new_x), self.x_max) new_y.insert(len(new_x), values[max_value[0]]) self.changed_plt[col].setData(new_x, new_y) elif self.changed_flag: self.changed_plt[col].setData(self.x, values) self.original_plt[col].setData(self.x, list(self.data[self.y[col]])) # Дополнения к графику def add_data(self): begin, ok = QInputDialog.getText(self, 'Начальное значение', 'Введите начальное значение:') if ok: try: self.x_min = int(begin) end, ok = QInputDialog.getText(self, 'Конечное значение', 'Введите конечное значение:') if ok: try: self.x_max = int(end) self.additional_data_flag = True self.changed_action.setEnabled(True) self.update_graph() except ValueError: QMessageBox.about(self, "Ошибка", "Введены некорректные данные") except ValueError: QMessageBox.about(self, "Ошибка", "Введены некорректные данные") def filter_data(self): self.filter_win = fw.FilterWindow(self) self.filter_win.show() def file_pushed(self, file_path): if '.txt' in file_path: f = open(file_path) self.out_text.setText(f.read()) elif '.data' in file_path: self.file_path = file_path self.conversion_action.setEnabled(True) self.data_action.setEnabled(True) self.column_action.setEnabled(True) self.copy_action.setEnabled(True) self.delete_action.setEnabled(True) self.set_x_action.setEnabled(True) f = open(file_path) self.out_text.setText(f.read()) self.loading_data() self.threadclass.start() elif '.' in file_path: subprocess.run(file_path, shell=True) def delete_column(self): self.get_checked_columns() self.data = self.data.drop(columns=self.y) self.create_table() def delete_prj_folder(self, name=""): self.current_project = "" if name == "": path = os.path.normpath(os.path.join(os.getcwd(), "Projects")) prj = QFileDialog.getExistingDirectory(self, "Выберите проект", path, QFileDialog.ShowDirsOnly) if prj != "" and (path in os.path.normpath(prj)): shutil.rmtree(prj, ignore_errors=True) self.update_project_layout() self.update_tests_layout() else: shutil.rmtree(os.path.join(self.path, name), ignore_errors=True) self.update_project_layout() self.update_tests_layout() def delete_test_folder(self): path = os.path.normpath(os.path.join(os.getcwd(), "Projects")) prj = QFileDialog.getExistingDirectory(self, "Выберите испытание", path, QFileDialog.ShowDirsOnly) if prj != "": h, t = os.path.split(os.path.normpath(prj)) h, t = os.path.split(h) if path == h: os.rmdir(prj)
class SendConfigDialog(QDialog): def __init__(self): super().__init__() self.setMinimumWidth(640) self.setWindowTitle("Send configuration to device") self.settings = QSettings("tasmotizer.cfg", QSettings.IniFormat) self.commands = None self.module_mode = 0 self.createUI() self.loadSettings() def createUI(self): vl = VLayout() self.setLayout(vl) # Wifi groupbox self.gbWifi = QGroupBox("WiFi") self.gbWifi.setCheckable(True) self.gbWifi.setChecked(False) flWifi = QFormLayout() self.leAP = QLineEdit() self.leAPPwd = QLineEdit() self.leAPPwd.setEchoMode(QLineEdit.Password) flWifi.addRow("SSID", self.leAP) flWifi.addRow("Password", self.leAPPwd) self.gbWifi.setLayout(flWifi) # Recovery Wifi groupbox self.gbRecWifi = QGroupBox("Recovery WiFi") self.gbRecWifi.setCheckable(True) self.gbRecWifi.setChecked(False) flRecWifi = QFormLayout() lbRecAP = QLabel("Recovery") lbRecAP.setAlignment(Qt.AlignVCenter | Qt.AlignRight) lbRecAPPwd = QLabel("a1b2c3d4") lbRecAPPwd.setAlignment(Qt.AlignVCenter | Qt.AlignRight) flRecWifi.addRow("SSID", lbRecAP) flRecWifi.addRow("Password", lbRecAPPwd) self.gbRecWifi.setLayout(flRecWifi) vl_wifis = VLayout(0) vl_wifis.addWidgets([self.gbWifi, self.gbRecWifi]) # MQTT groupbox self.gbMQTT = QGroupBox("MQTT") self.gbMQTT.setCheckable(True) self.gbMQTT.setChecked(False) flMQTT = QFormLayout() self.leBroker = QLineEdit() self.sbPort = SpinBox() self.sbPort.setValue(1883) self.leTopic = QLineEdit() self.leTopic.setText("tasmota") self.leFullTopic = QLineEdit() self.leFullTopic.setText("%prefix%/%topic%/") self.leFriendlyName = QLineEdit() self.leMQTTUser = QLineEdit() self.leMQTTPass = QLineEdit() self.leMQTTPass.setEchoMode(QLineEdit.Password) flMQTT.addRow("Host", self.leBroker) flMQTT.addRow("Port", self.sbPort) flMQTT.addRow("Topic", self.leTopic) flMQTT.addRow("FullTopic", self.leFullTopic) flMQTT.addRow("FriendlyName", self.leFriendlyName) flMQTT.addRow("User [optional]", self.leMQTTUser) flMQTT.addRow("Password [optional]", self.leMQTTPass) self.gbMQTT.setLayout(flMQTT) # Module/template groupbox self.gbModule = GroupBoxV("Module/template") self.gbModule.setCheckable(True) self.gbModule.setChecked(False) hl_m_rb = HLayout() self.rbModule = QRadioButton("Module") self.rbModule.setChecked(True) self.rbTemplate = QRadioButton("Template") hl_m_rb.addWidgets([self.rbModule, self.rbTemplate]) self.rbgModule = QButtonGroup(self.gbModule) self.rbgModule.addButton(self.rbModule, 0) self.rbgModule.addButton(self.rbTemplate, 1) self.cbModule = QComboBox() for mod_id, mod_name in modules.items(): self.cbModule.addItem(mod_name, mod_id) self.leTemplate = QLineEdit() self.leTemplate.setPlaceholderText("Paste template string here") self.leTemplate.setVisible(False) self.gbModule.addLayout(hl_m_rb) self.gbModule.addWidgets([self.cbModule, self.leTemplate]) self.rbgModule.buttonClicked[int].connect(self.setModuleMode) # layout all widgets hl_wifis_mqtt = HLayout(0) hl_wifis_mqtt.addLayout(vl_wifis) hl_wifis_mqtt.addWidget(self.gbMQTT) vl.addLayout(hl_wifis_mqtt) vl.addWidget(self.gbModule) btns = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close) btns.accepted.connect(self.accept) btns.rejected.connect(self.reject) vl.addWidget(btns) def loadSettings(self): self.gbWifi.setChecked(self.settings.value("gbWifi", False, bool)) self.leAP.setText(self.settings.value("AP")) self.gbRecWifi.setChecked(self.settings.value("gbRecWifi", False, bool)) self.gbMQTT.setChecked(self.settings.value("gbMQTT", False, bool)) self.leBroker.setText(self.settings.value("Broker")) self.sbPort.setValue(self.settings.value("Port", 1883, int)) self.leTopic.setText(self.settings.value("Topic", "tasmota")) self.leFullTopic.setText( self.settings.value("FullTopic", "%prefix%/%topic%/")) self.leFriendlyName.setText(self.settings.value("FriendlyName")) self.leMQTTUser.setText(self.settings.value("MQTTUser")) self.gbModule.setChecked(self.settings.value("gbModule", False, bool)) module_mode = self.settings.value("ModuleMode", 0, int) for b in self.rbgModule.buttons(): if self.rbgModule.id(b) == module_mode: b.setChecked(True) self.setModuleMode(module_mode) self.cbModule.setCurrentText(self.settings.value("Module", "Generic")) self.leTemplate.setText(self.settings.value("Template")) def setModuleMode(self, radio): self.module_mode = radio self.cbModule.setVisible(not radio) self.leTemplate.setVisible(radio) def accept(self): ok = True if self.gbWifi.isChecked() and (len(self.leAP.text()) == 0 or len(self.leAPPwd.text()) == 0): ok = False QMessageBox.warning(self, "WiFi details incomplete", "Input WiFi AP and Password") if self.gbMQTT.isChecked() and not self.leBroker.text(): ok = False QMessageBox.warning(self, "MQTT details incomplete", "Input broker hostname") if self.module_mode == 1 and len(self.leTemplate.text()) == 0: ok = False QMessageBox.warning(self, "Template string missing", "Input template string") if ok: backlog = [] if self.gbWifi.isChecked(): backlog.extend([ "ssid1 {}".format(self.leAP.text()), "password1 {}".format(self.leAPPwd.text()) ]) if self.gbRecWifi.isChecked(): backlog.extend(["ssid2 Recovery", "password2 a1b2c3d4"]) if self.gbMQTT.isChecked(): backlog.extend([ "mqtthost {}".format(self.leBroker.text()), "mqttport {}".format(self.sbPort.value()) ]) topic = self.leTopic.text() if topic and topic != "tasmota": backlog.append("topic {}".format(topic)) fulltopic = self.leFullTopic.text() if fulltopic and fulltopic != "%prefix%/%topic%/": backlog.append("fulltopic {}".format(fulltopic)) fname = self.leFriendlyName.text() if fname: backlog.append("friendlyname {}".format(fname)) mqttuser = self.leMQTTUser.text() if mqttuser: backlog.append("mqttuser {}".format(mqttuser)) mqttpassword = self.leMQTTPass.text() if mqttpassword: backlog.append("mqttpassword {}".format(mqttpassword)) if self.gbModule.isChecked(): if self.module_mode == 0: backlog.append("module {}".format( self.cbModule.currentData())) elif self.module_mode == 1: backlog.extend([ "template {}".format(self.leTemplate.text()), "module 0" ]) self.commands = "backlog {}\n".format(";".join(backlog)) self.done(QDialog.Accepted)
class VistaListaClienti(QWidget): # Apre la vista che contiene la lista dei clienti def __init__(self): super(VistaListaClienti, self).__init__() self.controller = ControllerListaClienti() # Inserisce in 'lista_clienti' i dati contenuti nel file 'lista_clienti.pickle'. # Se la lista è vuota l'utente è notificato con un messaggio di errore. self.stylesheet_label = """ QLabel{ background-color: white; border: 1px solid #dfdfdf; } """ self.stylesheet_window = """ QWidget{ background-color: #dfdfdf } """ self.stylesheet_button_back = """ QPushButton{ border-radius: 15px; background-color: transparent; } QPushButton::Pressed{ background-color: transparent; } """ self.stylesheet_button = """ QPushButton{ background-color: #cc3234; color: white; border-radius: 15px; } QPushButton::Pressed{ background-color: grey } """ self.stylesheet_table = """ QTableWidget{ background-color: white; } """ self.stylesheet_pagamento = """ QPushButton{ background-color: transparent; border-color: transparent; } QPushButton::Pressed{ background-color: grey; } """ # Inserimento e impostazioni grafiche dell'immagine dello sfondo della finestra. self.imagePath = "Image/foto.png" self.image = QImage(self.imagePath) self.label = QLabel(self) self.label.setPixmap(QPixmap.fromImage(self.image)) self.label.setScaledContents(True) self.label.setGeometry(0, 0, 1670, 750) # Inserimento della tabella e intestazione delle colonne. self.table = QTableWidget(self) self.table.setColumnCount(9) self.table.setRowCount(1) self.table.setItem(0, 0, QTableWidgetItem("Apri")) self.table.setItem(0, 1, QTableWidgetItem("ID")) self.table.setItem(0, 2, QTableWidgetItem("Nome")) self.table.setItem(0, 3, QTableWidgetItem("Cognome")) self.table.setItem(0, 4, QTableWidgetItem("Esame teorico")) self.table.setItem(0, 5, QTableWidgetItem("Esame pratico")) self.table.setItem(0, 6, QTableWidgetItem("Pagamenti")) self.table.setItem(0, 7, QTableWidgetItem("Prenotazione")) self.table.setItem(0, 8, QTableWidgetItem("Cancella")) self.set_data() # Inserisce nella tabella i dati contenuti nella lista_clienti. # Impostazioni grafiche della tabella. self.table.setGeometry(50, 50, 1300, 550) self.table.setColumnWidth(0, 90) self.table.setColumnWidth(1, 100) self.table.setColumnWidth(2, 280) self.table.setColumnWidth(3, 280) self.table.setColumnWidth(4, 110) self.table.setColumnWidth(5, 110) self.table.setColumnWidth(6, 110) self.table.setColumnWidth(7, 110) self.table.setColumnWidth(8, 90) self.table.setStyleSheet(self.stylesheet_table) self.table.horizontalHeader().setStretchLastSection(True) self.table.horizontalHeader().hide() self.table.horizontalScrollBar().setDisabled(True) self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table.verticalHeader().hide() self.table.setEditTriggers(self.table.NoEditTriggers) self.table.setSelectionMode(self.table.NoSelection) self.table.setFocusPolicy(Qt.NoFocus) # Inserimento e impostazioni grafiche del bottone per tornare alla vista precedente. self.button_back = QPushButton(self) self.button_back.setIcon(QIcon('Image/back.png')) self.button_back.setIconSize(QSize(90, 90)) self.button_back.setGeometry(60, 630, 90, 90) self.button_back.setStyleSheet(self.stylesheet_button_back) self.button_back.clicked.connect(self.go_back) # Inserimento e impostazioni grafiche del bottone per inserire un nuovo cliente nella lista. self.button_new_cliente = QPushButton(self) self.button_new_cliente.setText("Nuovo cliente") self.font_button = QFont("Times", 11) self.button_new_cliente.setFont(self.font_button) self.button_new_cliente.setGeometry(1210, 650, 140, 50) self.button_new_cliente.setStyleSheet(self.stylesheet_button) self.button_new_cliente.clicked.connect(self.go_new_cliente) # Impostazioni grafiche generali della finestra del programma. self.setWindowTitle("Lista Clienti") self.resize(1400, 750) self.setFixedSize(self.size()) self.setStyleSheet(self.stylesheet_window) # == set_data == # La funzione si occupa di salvare le informazioni relative al cliente e contenute nel file # 'lista_clienti.pickle' nella tabella della VistaListaClienti. Per ogni cliente è disponibile # aprire e visualizzare le sue informazioni attraverso un bottone 'Apri' ed è possibile cancellarle # attraverso un bottone 'Elimina'. def set_data(self): self.button_group_apri = QButtonGroup() self.button_group_elimina = QButtonGroup() self.button_group_pagamenti = QButtonGroup() self.icon_no = QIcon("Image/no.png") self.icon_si = QIcon("Image/si.png") self.icon_sino = QIcon("Image/sino.png") self.apri_icon = QIcon("Image/apri_icon.png") self.cancella_icon = QIcon("Image/delete.png") self.no = QTableWidgetItem() self.no.setIcon(self.icon_no) self.si = QTableWidgetItem() self.si.setIcon(self.icon_si) i = 1 n_righe = len(self.controller.get_lista_clienti()) self.table.setRowCount(n_righe + 1) self.button_group_apri.buttonClicked.connect(self.on_selection_apri) self.button_group_elimina.buttonClicked.connect(self.on_selection_elimina) self.button_group_pagamenti.buttonClicked.connect(self.on_selection_pagamenti) for cliente in self.controller.get_lista_clienti(): self.sino = QPushButton() self.sino.setIcon(self.icon_sino) self.sino.setStyleSheet(self.stylesheet_pagamento) self.button_group_pagamenti.addButton(self.sino, i) self.controller_cliente = ControllerCliente(cliente) self.apri = QPushButton() self.apri.setIcon(self.apri_icon) self.apri.setIconSize(QSize(30, 30)) self.apri.setStyleSheet(self.stylesheet_pagamento) self.button_group_apri.addButton(self.apri, i) self.table.setCellWidget(i, 0, self.apri) if self.controller_cliente.get_id() == "None": self.table.setItem(i, 1, QTableWidgetItem(self.no)) else: self.table.setItem(i, 1, QTableWidgetItem(self.controller_cliente.get_id())) self.table.setItem(i, 2, QTableWidgetItem(self.controller_cliente.get_nome())) self.table.setItem(i, 3, QTableWidgetItem(self.controller_cliente.get_cognome())) if self.controller_cliente.get_esame_teorico() == "None": self.table.setItem(i, 4, QTableWidgetItem(self.no)) else: self.table.setItem(i, 4, QTableWidgetItem(self.si)) if self.controller_cliente.get_esame_pratico() == "None": self.table.setItem(i, 5, QTableWidgetItem(self.no)) else: self.table.setItem(i, 5, QTableWidgetItem(self.si)) if self.controller_cliente.get_pagamento_iniziale() == "None" and \ self.controller_cliente.get_pagamento_esame_teorico() == "None" and \ self.controller_cliente.get_pagamento_lezioni_guida() == "None" and \ self.controller_cliente.get_pagamento_esame_pratico() == "None": self.table.setItem(i, 6, QTableWidgetItem(self.no)) else: if self.controller_cliente.get_pagamento_iniziale() != "None" and \ self.controller_cliente.get_pagamento_esame_teorico() != "None" and \ self.controller_cliente.get_pagamento_lezioni_guida() != "None" and \ self.controller_cliente.get_pagamento_esame_pratico() != "None": self.table.setItem(i, 6, QTableWidgetItem(self.si)) else: self.table.setCellWidget(i, 6, self.sino) if self.controller_cliente.get_prenotazione() == "None": if self.controller_cliente.get_esame_pratico() == "Effettuato" and \ self.controller_cliente.get_esame_teorico() == "Effettuato": self.table.setItem(i, 7, QTableWidgetItem(self.si)) else: self.table.setItem(i, 7, QTableWidgetItem(self.no)) else: self.table.setItem(i, 7, QTableWidgetItem(self.controller_cliente.get_prenotazione())) self.delete = QPushButton() self.delete.setIcon(self.cancella_icon) self.delete.setIconSize(QSize(35, 35)) self.delete.setStyleSheet(self.stylesheet_pagamento) self.button_group_elimina.addButton(self.delete, i) self.table.setCellWidget(i, 8, self.delete) i = i + 1 # == go_new_cliente == # La funzione si occupa di aprire la VistaNuovoCliente. def go_new_cliente(self): self.vista_nuovo_cliente = VistaNuovoCliente() self.vista_nuovo_cliente.show() self.close() # == go_back == # La funzione si occupa di aprire la finestra precedente. def go_back(self): self.go_lista_clienti = VistaHomeSegretario.VistaHomeSegretario() self.go_lista_clienti.show() self.close() # == go_pagamenti == # La funzione si occupa di aprire la VistaPagamentiEffettuati. def go_pagamenti(self, i): pagamento = self.controller.get_lista_clienti()[i-1] self.go_vedi_pagamenti = VistaPagamentiEffettuati(pagamento) self.go_vedi_pagamenti.show() # == go_apri == # La funzione si occupa di aprire la VistaCliente corrispondente al cliente scelto. def go_apri(self, i): cliente = self.controller.get_lista_clienti()[i - 1] self.go_cliente = VistaCliente(cliente, False) self.go_cliente.show() self.close() # == go_elimina == # La funzione, dopo aver chiesto conferma all'utente, cancella le informazioni relative al # cliente scelto. def go_elimina(self, i): conferma = QMessageBox.question(self, "Attenzione", "Sei sicuro di voler eliminare questo cliente?", QMessageBox.No, QMessageBox.Yes) if conferma == QMessageBox.Yes: self.controller_pagamenti = ControllerListaPagamenti() self.controller_pagamenti.elimina_pagamento_by_cliente(i-1) self.controller.rimuovi_cliente_by_index(i-1) self.refresh() else: return def refresh(self): self.go_lista = VistaListaClienti() self.go_lista.show() self.close() def on_selection_apri(self, selected): self.go_apri(self.button_group_apri.id(selected)) def on_selection_elimina(self, selected): self.go_elimina(self.button_group_elimina.id(selected)) def on_selection_pagamenti(self, selected): self.go_pagamenti(self.button_group_pagamenti.id(selected))