def createTable(self, type_table, rows, list_of_komp): """ Создание и заполнение таблицы :param type_table: :param row: :param list_komp: :param list_desc: :return: """ if type_table == 'out': model = QStandardItemModel(rows, 2) list_horizontal = ['Код компетенции', 'Описание компетенции'] model.setHorizontalHeaderLabels(list_horizontal) self.tableOut.setModel(model) self.tableOut.setColumnWidth(0, 110) self.tableOut.setColumnWidth(1, self.tableOut.width() - 130) for row in range(rows): for column in range(2): index = model.index(row, column, QModelIndex()) model.setData(index, str(list_of_komp[row][column]).strip()) else: model = QStandardItemModel(rows, 2) list_horizontal = ['Код компетенции', 'Описание компетенции'] model.setHorizontalHeaderLabels(list_horizontal) self.tableIn.setModel(model) self.tableIn.setColumnWidth(0, 110) self.tableIn.setColumnWidth(1, self.tableIn.width() - 130) for row in range(rows): for column in range(2): index = model.index(row, column, QModelIndex()) model.setData(index, str(list_of_komp[row][column]).strip())
def showSchema(self, table): """ Public slot to show the schema of a table. @param table name of the table to be shown (string) """ rec = self.connections.currentDatabase().record(table) model = QStandardItemModel(self.table) model.insertRows(0, rec.count()) model.insertColumns(0, 7) model.setHeaderData(0, Qt.Horizontal, "Fieldname") model.setHeaderData(1, Qt.Horizontal, "Type") model.setHeaderData(2, Qt.Horizontal, "Length") model.setHeaderData(3, Qt.Horizontal, "Precision") model.setHeaderData(4, Qt.Horizontal, "Required") model.setHeaderData(5, Qt.Horizontal, "Auto Value") model.setHeaderData(6, Qt.Horizontal, "Default Value") for i in range(rec.count()): fld = rec.field(i) model.setData(model.index(i, 0), fld.name()) if fld.typeID() == -1: model.setData(model.index(i, 1), QVariant.typeToName(fld.type())) else: model.setData( model.index(i, 1), "{0} ({1})".format( QVariant.typeToName(fld.type()), fld.typeID())) if fld.length() < 0: model.setData(model.index(i, 2), "?") else: model.setData(model.index(i, 2), fld.length()) if fld.precision() < 0: model.setData(model.index(i, 3), "?") else: model.setData(model.index(i, 3), fld.precision()) if fld.requiredStatus() == -1: model.setData(model.index(i, 4), "?") else: model.setData(model.index(i, 4), bool(fld.requiredStatus())) model.setData(model.index(i, 5), fld.isAutoValue()) model.setData(model.index(i, 6), fld.defaultValue()) self.table.setModel(model) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.resizeColumnsToContents() self.updateActions()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() fileMenu = QMenu("&File", self) openAction = fileMenu.addAction("&Open...") openAction.setShortcut("Ctrl+O") saveAction = fileMenu.addAction("&Save As...") saveAction.setShortcut("Ctrl+S") quitAction = fileMenu.addAction("E&xit") quitAction.setShortcut("Ctrl+Q") self.setupModel() self.setupViews() openAction.triggered.connect(self.openFile) saveAction.triggered.connect(self.saveFile) quitAction.triggered.connect(QApplication.instance().quit) self.menuBar().addMenu(fileMenu) self.statusBar() self.openFile(':/Charts/qtdata.cht') self.setWindowTitle("Chart") self.resize(870, 550) def setupModel(self): self.model = QStandardItemModel(8, 2, self) self.model.setHeaderData(0, Qt.Horizontal, "Label") self.model.setHeaderData(1, Qt.Horizontal, "Quantity") def setupViews(self): splitter = QSplitter() table = QTableView() self.pieChart = PieView() splitter.addWidget(table) splitter.addWidget(self.pieChart) splitter.setStretchFactor(0, 0) splitter.setStretchFactor(1, 1) table.setModel(self.model) self.pieChart.setModel(self.model) self.selectionModel = QItemSelectionModel(self.model) table.setSelectionModel(self.selectionModel) self.pieChart.setSelectionModel(self.selectionModel) table.horizontalHeader().setStretchLastSection(True) self.setCentralWidget(splitter) def openFile(self, path=None): if not path: path, _ = QFileDialog.getOpenFileName(self, "Choose a data file", '', '*.cht') if path: f = QFile(path) if f.open(QFile.ReadOnly | QFile.Text): stream = QTextStream(f) self.model.removeRows(0, self.model.rowCount(QModelIndex()), QModelIndex()) row = 0 line = stream.readLine() while line: self.model.insertRows(row, 1, QModelIndex()) pieces = line.split(',') self.model.setData(self.model.index(row, 0, QModelIndex()), pieces[0]) self.model.setData(self.model.index(row, 1, QModelIndex()), float(pieces[1])) self.model.setData(self.model.index(row, 0, QModelIndex()), QColor(pieces[2]), Qt.DecorationRole) row += 1 line = stream.readLine() f.close() self.statusBar().showMessage("Loaded %s" % path, 2000) def saveFile(self): fileName, _ = QFileDialog.getSaveFileName(self, "Save file as", '', '*.cht') if fileName: f = QFile(fileName) if f.open(QFile.WriteOnly | QFile.Text): for row in range(self.model.rowCount(QModelIndex())): pieces = [] pieces.append(self.model.data(self.model.index(row, 0, QModelIndex()), Qt.DisplayRole)) pieces.append(str(self.model.data(self.model.index(row, 1, QModelIndex()), Qt.DisplayRole))) pieces.append(self.model.data(self.model.index(row, 0, QModelIndex()), Qt.DecorationRole).name()) f.write(QByteArray(','.join(pieces))) f.write('\n') f.close() self.statusBar().showMessage("Saved %s" % fileName, 2000)
class IsosViewer(QMainWindow, mageiaSyncUI.Ui_mainWindow): # Display the main window def __init__(self, parent=None): super(IsosViewer, self).__init__(parent) self.setupUi(self) self.connectActions() self.IprogressBar.setMinimum(0) self.IprogressBar.setMaximum(100) self.IprogressBar.setValue(0) self.IprogressBar.setEnabled(False) self.selectAllState=True self.stop.setEnabled(False) self.destination='' self.rsyncThread = mageiaSyncExt.syncThread(self) # create a thread to launch rsync self.rsyncThread.progressSignal.connect(self.setProgress) self.rsyncThread.speedSignal.connect(self.setSpeed) self.rsyncThread.sizeSignal.connect(self.setSize) self.rsyncThread.remainSignal.connect(self.setRemain) self.rsyncThread.endSignal.connect(self.syncEnd) self.rsyncThread.lvM.connect(self.lvMessage) self.rsyncThread.checkSignal.connect(self.checks) self.checkThreads=[] # A list of thread for each iso # Model for list view in a table self.model = QStandardItemModel(0, 6, self) headers=[self.tr("Directory"),self.tr("Name"),self.tr("Size"),self.tr("Date"),"SHA1","MD5"] i=0 for label in headers: self.model.setHeaderData(i, QtCore.Qt.Horizontal,label ) i+=1 # settings for the list view self.localList.setModel(self.model) self.localList.setColumnWidth(0,220) self.localList.setColumnWidth(1,220) self.localList.horizontalHeader().setStretchLastSection(True) # settings for local iso names management self.localListNames=[] def multiSelect(self): # allows to select multiple lines in remote ISOs list self.listIsos.setSelectionMode(2) def add(self, iso): # Add an remote ISO in list self.listIsos.addItem(iso) def localAdd(self, path,iso,isoSize): # Add an entry in local ISOs list, with indications about checking itemPath=QStandardItem(path) itemIso=QStandardItem(iso) if isoSize==0: itemSize=QStandardItem('--') else: formatedSize='{:n}'.format(isoSize).replace(","," ") itemSize=QStandardItem(formatedSize) itemSize.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter) itemDate=QStandardItem("--/--/--") itemDate.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter) itemCheck1=QStandardItem("--") itemCheck1.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter) itemCheck5=QStandardItem("--") itemCheck5.setTextAlignment(QtCore.Qt.AlignVCenter|QtCore.Qt.AlignHCenter) self.model.appendRow([itemPath,itemIso,itemSize,itemDate, itemCheck1, itemCheck5,]) self.localListNames.append([path,iso]) def setProgress(self, value): # Update the progress bar self.IprogressBar.setValue(value) def setSpeed(self, value): # Update the speed field self.speedLCD.display(value) def setSize(self, size): # Update the size field self.Lsize.setText(size+self.tr(" bytes")) def setRemain(self,remainTime): content=QtCore.QTime.fromString(remainTime,"h:mm:ss") self.timeRemaining.setTime(content) def manualChecks(self): for iso in self.listIsos.selectedItems(): path,name=iso.text().split('/') try: # Look for ISO in local list item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0] except: # Remote ISO is not yet in local directory. We add it in localList and create the directory self.localAdd(path,name,0) basedir=QtCore.QDir(self.destination) basedir.mkdir(path) item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0] row=self.model.indexFromItem(item).row() self.checks(row) def checks(self,isoIndex): # processes a checking for each iso # launches a thread for each iso newThread=mageiaSyncExt.checkThread(self) self.checkThreads.append(newThread) self.checkThreads[-1].setup(self.destination, self.model.data(self.model.index(isoIndex,0)) , self.model.data(self.model.index(isoIndex,1)), isoIndex) self.checkThreads[-1].md5Signal.connect(self.md5Check) self.checkThreads[-1].sha1Signal.connect(self.sha1Check) self.checkThreads[-1].dateSignal.connect(self.dateCheck) self.checkThreads[-1].sizeFinalSignal.connect(self.sizeUpdate) self.checkThreads[-1].checkStartSignal.connect(self.checkStart) self.checkThreads[-1].start() def checkStart(self,isoIndex): # the function indicates that checking is in progress # the hundred contains index of the value to check, the minor value contains the row col=(int)(isoIndex/100) row=isoIndex-col*100 self.model.setData(self.model.index(row, col, QtCore.QModelIndex()), self.tr("Checking")) def md5Check(self,check): if check>=128: val=self.tr("OK") row=check-128 else: val=self.tr("Failed") row=check self.model.setData(self.model.index(row, 5, QtCore.QModelIndex()), val) def sha1Check(self,check): if check>=128: val=self.tr("OK") row=check-128 else: val=self.tr("Failed") row=check self.model.setData(self.model.index(row, 4, QtCore.QModelIndex()), val) def dateCheck(self,check): if check>=128: val=self.tr("OK") row=check-128 else: val=self.tr("Failed") row=check self.model.setData(self.model.index(row, 3, QtCore.QModelIndex()), val) def sizeUpdate(self,signal,isoSize): col=(int)(signal/100) row=signal-col*100 self.model.setData(self.model.index(row, col, QtCore.QModelIndex()), isoSize) def syncEnd(self, rc): if rc==1: self.lvMessage(self.tr("Command rsync not found")) elif rc==2: self.lvMessage(self.tr("Error in rsync parameters")) elif rc==3: self.lvMessage(self.tr("Unknown error in rsync")) self.IprogressBar.setEnabled(False) self.syncGo.setEnabled(True) self.listIsos.setEnabled(True) self.selectAll.setEnabled(True) self.stop.setEnabled(False) def prefsInit(self): # Load the parameters at first params=QtCore.QSettings("Mageia","mageiaSync") paramRelease="" try: paramRelease=params.value("release", type="QString") # the parameters already initialised? except: pass if paramRelease =="": # Values are not yet set self.pd0=prefsDialog0() self.pd0.user.setFocus() answer=self.pd0.exec_() if answer: # Update params self.user=self.pd0.user.text() self.password=self.pd0.password.text() self.location=self.pd0.location.text() params=QtCore.QSettings("Mageia","mageiaSync") params.setValue("user",self.user) params.setValue("password",self.password) params.setValue("location",self.location) else: pass # answer=QDialogButtonBox(QDialogButtonBox.Ok) # the user must set values or default values self.pd0.close() self.pd=prefsDialog() if self.password !="": code,list=mageiaSyncExt.findRelease('rsync://'+self.user+'@bcd.mageia.org/isos/',self.password) if code==0: for item in list: self.pd.release.addItem(item) self.pd.password.setText(self.password) self.pd.user.setText(self.user) self.pd.location.setText(self.location) self.pd.selectDest.setText(QtCore.QDir.currentPath()) self.pd.release.setFocus() answer=self.pd.exec_() if answer: # Update params self.user=self.pd.user.text() self.password=self.pd.password.text() self.location=self.pd.location.text() params=QtCore.QSettings("Mageia","mageiaSync") self.release= self.pd.release.currentText() self.destination=self.pd.selectDest.text() self.bwl=self.pd.bwl.value() params.setValue("release", self.release) params.setValue("user",self.user) params.setValue("password",self.password) params.setValue("location",self.location) params.setValue("destination",self.destination) params.setValue("bwl",str(self.bwl)) else: pass # answer=QDialogButtonBox(QDialogButtonBox.Ok) print(self.tr("the user must set values or default values")) self.pd.close() else: self.release=params.value("release", type="QString") self.user=params.value("user", type="QString") self.location=params.value("location", type="QString") self.password=params.value("password", type="QString") self.destination=params.value("destination", type="QString") self.bwl=params.value("bwl",type=int) self.localDirLabel.setText(self.tr("Local directory: ")+self.destination) if self.location !="": self.remoteDirLabel.setText(self.tr("Remote directory: ")+self.location) def selectDestination(self): # dialog box to select the destination (local directory) directory = QFileDialog.getExistingDirectory(self, self.tr('Select a directory'),'~/') isosSync.destination = directory self.pd.selectDest.setText(isosSync.destination) def selectAllIsos(self): # Select or unselect the ISOs in remote list if self.selectAllState : for i in range(self.listIsos.count()): self.listIsos.item(i).setSelected(True) self.selectAll.setText(self.tr("Unselect &All")) else: for i in range(self.listIsos.count()): self.listIsos.item(i).setSelected(False) self.selectAll.setText(self.tr("Select &All")) self.selectAllState=not self.selectAllState def connectActions(self): self.actionQuit.triggered.connect(app.quit) self.quit.clicked.connect(app.quit) self.actionRename.triggered.connect(self.rename) self.actionUpdate.triggered.connect(self.updateList) self.actionCheck.triggered.connect(self.manualChecks) self.actionPreferences.triggered.connect(self.prefs) self.syncGo.clicked.connect(self.launchSync) self.selectAll.clicked.connect(self.selectAllIsos) def updateList(self): # From the menu entry self.lw = LogWindow() self.lw.show() self.listIsos.clear() self.model.removeRows(0,self.model.rowCount()) if self.location == "" : self.nameWithPath='rsync://'+self.user+'@bcd.mageia.org/isos/'+self.release+'/' # print self.nameWithPath else: self.nameWithPath=self.location+'/' self.lvMessage(self.tr("Source: ")+self.nameWithPath) self.fillList = mageiaSyncExt.findIsos() self.fillList.setup(self.nameWithPath, self.password,self.destination) self.fillList.endSignal.connect(self.closeFill) self.fillList.start() # Reset the button self.selectAll.setText(self.tr("Select &All")) self.selectAllState=True def lvMessage( self,message): # Add a line in the logview self.lvText.append(message) def renameDir(self): # Choose the directory where isos are stored directory = QFileDialog.getExistingDirectory(self, self.tr('Select a directory'),self.destination) self.rd.chooseDir.setText(directory) def rename(self): # rename old isos and directories to a new release self.rd=renameDialog() loc=[] loc=self.location.split('/') self.rd.oldRelease.setText(loc[-1]) self.rd.chooseDir.setText(self.destination) answer=self.rd.exec_() if answer: returnMsg=mageiaSyncExt.rename(self.rd.chooseDir.text(),self.rd.oldRelease.text(),str(self.rd.newRelease.text())) self.lvMessage(returnMsg) self.rd.close() def prefs(self): # From the menu entry self.pd=prefsDialog() self.pd.release.addItem(self.release) self.pd.password.setText(self.password) self.pd.user.setText(self.user) self.pd.location.setText(self.location) self.pd.selectDest.setText(self.destination) self.pd.bwl.setValue(self.bwl) params=QtCore.QSettings("Mageia","mageiaSync") answer=self.pd.exec_() if answer: params.setValue("release", self.pd.release.currentText()) params.setValue("user",self.pd.user.text()) params.setValue("password",self.pd.password.text()) params.setValue("location",self.pd.location.text()) params.setValue("destination",self.pd.selectDest.text()) params.setValue("bwl",str(self.pd.bwl.value())) self.prefsInit() self.pd.close() def launchSync(self): self.IprogressBar.setEnabled(True) self.stop.setEnabled(True) self.syncGo.setEnabled(False) self.listIsos.setEnabled(False) self.selectAll.setEnabled(False) # Connect the button Stop self.stop.clicked.connect(self.stopSync) self.rsyncThread.params(self.password, self.bwl) for iso in self.listIsos.selectedItems(): path,name=iso.text().split('/') try: # Look for ISO in local list item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0] except: # Remote ISO is not yet in local directory. We add it in localList and create the directory self.localAdd(path,name,0) basedir=QtCore.QDir(self.destination) basedir.mkdir(path) item=self.model.findItems(name,QtCore.Qt.MatchExactly,1)[0] row=self.model.indexFromItem(item).row() if self.location == "" : self.nameWithPath='rsync://'+self.user+'@bcd.mageia.org/isos/'+self.release+'/'+path else: self.nameWithPath=self.location+path if (not str(path).endswith('/')): self.nameWithPath+='/' self.rsyncThread.setup(self.nameWithPath, self.destination+'/'+path+'/',row) self.rsyncThread.start() # start the thread # Pour les tests uniquement #rsync://[email protected]/isos/$release/ #self.nameWithPath='rsync://ftp5.gwdg.de/pub/linux/mageia/iso/4.1/Mageia-4.1-LiveCD-GNOME-en-i586-CD/' def closeFill(self,code): if code==0: # list returned list=self.fillList.getList() for iso in list: self.add(iso) elif code==1: self.lvMessage(self.tr("Command rsync not found")) elif code==2: self.lvMessage(self.tr("Error in rsync parameters")) elif code==3: self.lvMessage(self.tr("Unknown error in rsync")) list=self.fillList.getList() list=self.fillList.getLocal() for path,iso,isoSize in list: self.localAdd(path,iso, isoSize) self.fillList.quit() self.lw.hide() def stopSync(self): self.rsyncThread.stop() self.IprogressBar.setEnabled(False) self.stop.setEnabled(False) self.syncGo.setEnabled(True) self.listIsos.setEnabled(True) self.selectAll.setEnabled(True) def main(self): self.show() # Load or look for intitial parameters self.prefsInit() # look for Isos list and add it to the isoSync list. Update preferences self.updateList() self.multiSelect() def close(self): self.rsyncThread.stop() exit(0)
class MDIHistory(QWidget, _HalWidgetBase): def __init__(self, parent=None): super(MDIHistory, self).__init__(parent) self.setMinimumSize(QSize(200, 150)) self.setWindowTitle("PyQt5 editor test example") lay = QVBoxLayout() lay.setContentsMargins(0,0,0,0) self.setLayout(lay) self.list = QListView() self.list.setEditTriggers(QListView.NoEditTriggers) self.list.activated.connect(self.activated) self.list.setAlternatingRowColors(True) self.list.selectionChanged = self.selectionChanged self.model = QStandardItemModel(self.list) self.MDILine = MDILine() self.MDILine.soft_keyboard = False self.MDILine.line_up = self.line_up self.MDILine.line_down = self.line_down STATUS.connect('reload-mdi-history', self.reload) # add widgets lay.addWidget(self.list) lay.addWidget(self.MDILine) self.fp = os.path.expanduser(INFO.MDI_HISTORY_PATH) try: open(self.fp, 'r') except: open(self.fp, 'a+') LOG.debug('MDI History file created: {}'.format(self.fp)) self.reload() self.select_row('last') def _hal_init(self): STATUS.connect('state-off', lambda w: self.setEnabled(False)) STATUS.connect('state-estop', lambda w: self.setEnabled(False)) STATUS.connect('interp-idle', lambda w: self.setEnabled(STATUS.machine_is_on() and (STATUS.is_all_homed() or INFO.NO_HOME_REQUIRED))) STATUS.connect('interp-run', lambda w: self.setEnabled(not STATUS.is_auto_mode())) STATUS.connect('all-homed', lambda w: self.setEnabled(STATUS.machine_is_on())) def reload(self, w=None ): self.model.clear() try: with open(self.fp,'r') as inputfile: for line in inputfile: line = line.rstrip('\n') item = QStandardItem(line) self.model.appendRow(item) self.list.setModel(self.model) self.list.scrollToBottom() if self.MDILine.hasFocus(): self.select_row('last') except: LOG.debug('File path is not valid: {}'.format(fp)) def selectionChanged(self,old, new): cmd = self.getSelected() self.MDILine.setText(cmd) selectionModel = self.list.selectionModel() if selectionModel.hasSelection(): self.row = selectionModel.currentIndex().row() def getSelected(self): selected_indexes = self.list.selectedIndexes() selected_rows = [item.row() for item in selected_indexes] # iterates each selected row in descending order for selected_row in sorted(selected_rows, reverse=True): text = self.model.item(selected_row).text() return text def activated(self): cmd = self.getSelected() self.MDILine.setText(cmd) self.MDILine.submit() self.select_row('down') def select_row(self, style): selectionModel = self.list.selectionModel() parent = QModelIndex() self.rows = self.model.rowCount(parent) - 1 if style == 'last': self.row = self.rows elif style == 'up': if self.row > 0: self.row -= 1 else: self.row = self.rows elif style == 'down': if self.row < self.rows: self.row += 1 else: self.row = 0 else: return top = self.model.index(self.row, 0, parent) bottom = self.model.index(self.row, 0, parent) selectionModel.setCurrentIndex(top, QItemSelectionModel.Select | QItemSelectionModel.Rows) selection = QItemSelection(top, top) selectionModel.clearSelection() selectionModel.select(selection, QItemSelectionModel.Select) def line_up(self): self.select_row('up') def line_down(self): self.select_row('down') ######################################################################### # This is how designer can interact with our widget properties. # designer will show the pyqtProperty properties in the editor # it will use the get set and reset calls to do those actions ######################################################################### def set_soft_keyboard(self, data): self.MDILine.soft_keyboard = data def get_soft_keyboard(self): return self.MDILine.soft_keyboard def reset_soft_keyboard(self): self.MDILine.soft_keyboard = False # designer will show these properties in this order: soft_keyboard_option = pyqtProperty(bool, get_soft_keyboard, set_soft_keyboard, reset_soft_keyboard)
class MassTabSelectorGUI(QDockWidget): """ classdocs """ masstabViewRaisedSignal = pyqtSignal(object) """ constructor """ def __init__(self, parent=None): super(MassTabSelectorGUI, self).__init__(parent) self.ui = Ui_DockWidget_MassTabSelector() self.ui.setupUi(self) def setup(self, analysis): self.ana = analysis self.__connect_events() def __connect_events(self): self.model = QStandardItemModel() self.mass_list = [] for i in range(10): mass = 184 + i self.mass_list.append(str(mass)) for i in range(10): mass = 209 + i self.mass_list.append(str(mass)) for i in range(10): mass = 273.3 + i self.mass_list.append(str(mass)) for i in range(10): mass = 294 + i self.mass_list.append(str(mass)) for mass in self.mass_list: item = QStandardItem(mass) item.setCheckable(True) item.setEditable(True) self.model.appendRow(item) self.view = self.ui.listView_Mass self.view.setModel(self.model) # changes in one item, don't know which one self.model.itemChanged.connect(self.change_list) # changes in button self.ui.pushButton_ChangeList.clicked.connect(self.emit_list_signal) # get peaks found and update automatically the mass list self.ana.masstabSelectorRaisedSignal.connect(self.update_list_view) def update_list_view(self, xind): self.mass_list = [] for i in range(len(xind)): m = "{:.1f}".format(float(xind[i])) self.mass_list.append(str(m)) self.model.clear() self.model = QStandardItemModel() for mass in self.mass_list: item = QStandardItem(mass) item.setCheckable(True) item.setEditable(True) item.setCheckState(Qt.Checked) self.model.appendRow(item) self.view = self.ui.listView_Mass self.view.setModel(self.model) # changes in one item, don't know which one self.model.itemChanged.connect(self.change_list) def change_list(self): log.debug("event from %s", self.sender()) self.oneIsChecked = False self.mass_list = [] count = self.model.rowCount() for i in range(count): checked = self.model.item(i).checkState() if checked: mass_name = self.model.data(self.model.index(i, 0)) self.mass_list.append(mass_name) self.oneIsChecked = True def emit_list_signal(self): log.debug("event from %s", self.sender()) self.change_list() if self.oneIsChecked: self.masstabViewRaisedSignal.emit(self.mass_list)
class RefsWidget(QObject): error = pyqtSignal(Exception) reference_changed = pyqtSignal(Node) def __init__(self, view): self.view = view QObject.__init__(self, view) self.model = QStandardItemModel() delegate = MyDelegate(self.view, self) delegate.error.connect(self.error.emit) delegate.reference_changed.connect(self.reference_changed.emit) self.view.setEditTriggers(QAbstractItemView.DoubleClicked) self.view.setModel(self.model) self.view.setItemDelegate(delegate) self.settings = QSettings() self.model.setHorizontalHeaderLabels(['ReferenceType', 'NodeId', "BrowseName", "TypeDefinition"]) state = self.settings.value("WindowState/refs_widget_state", None) if state is not None: self.view.horizontalHeader().restoreState(state) self.view.horizontalHeader().setSectionResizeMode(0) self.view.horizontalHeader().setStretchLastSection(True) self.node = None self.reloadAction = QAction("Reload", self.model) self.reloadAction.triggered.connect(self.reload) self.addRefAction = QAction("Add Reference", self.model) self.addRefAction.triggered.connect(self.add_ref) self.removeRefAction = QAction("Remove Reference", self.model) self.removeRefAction.triggered.connect(self.remove_ref) self.view.setContextMenuPolicy(Qt.CustomContextMenu) self.view.customContextMenuRequested.connect(self.showContextMenu) self._contextMenu = QMenu() self._contextMenu.addAction(self.reloadAction) self._contextMenu.addSeparator() self._contextMenu.addAction(self.addRefAction) self._contextMenu.addAction(self.removeRefAction) def showContextMenu(self, position): if not self.node: return self.removeRefAction.setEnabled(False) idx = self.view.currentIndex() if idx.isValid(): self.removeRefAction.setEnabled(True) self._contextMenu.exec_(self.view.viewport().mapToGlobal(position)) def clear(self): # remove all rows but not header!! self.model.removeRows(0, self.model.rowCount()) self.node = None def _make_default_ref(self): #FIXME: remeber last choosen values or use values that make sense ref = ua.ReferenceDescription() return ref @trycatchslot def add_ref(self): ref = self._make_default_ref() logger.info("Adding ref: %s", ref) self._add_ref_row(ref) idx = self.model.index(self.model.rowCount() - 1, 0) self.view.setCurrentIndex(idx) #self.view.edit(idx) @trycatchslot def reload(self): node = self.node self.clear() self.show_refs(node) @trycatchslot def remove_ref(self): idx = self.view.currentIndex() if not idx.isValid(): logger.warning("No valid reference selected to remove") idx = idx.sibling(idx.row(), 0) item = self.model.itemFromIndex(idx) ref = item.data(Qt.UserRole) self.do_remove_ref(ref) self.reload() def do_remove_ref(self, ref, check=True): logger.info("Removing: %s", ref) it = ua.DeleteReferencesItem() it.SourceNodeId = self.node.nodeid it.ReferenceTypeId = ref.ReferenceTypeId it.IsForward = ref.IsForward it.TargetNodeId = ref.NodeId it.DeleteBidirectional = False #param = ua.DeleteReferencesParameters() #param.ReferencesToDelete.append(it) results = self.node.server.delete_references([it]) logger.info("Remove result: %s", results[0]) if check: results[0].check() def save_state(self): self.settings.setValue("WindowState/refs_widget_state", self.view.horizontalHeader().saveState()) def show_refs(self, node): self.clear() self.node = node self._show_refs(node) def _show_refs(self, node): try: refs = node.get_children_descriptions(refs=ua.ObjectIds.References) except Exception as ex: self.error.emit(ex) raise for ref in refs: self._add_ref_row(ref) def _add_ref_row(self, ref): if ref.ReferenceTypeId.Identifier in ua.ObjectIdNames: typename = ua.ObjectIdNames[ref.ReferenceTypeId.Identifier] else: typename = str(ref.ReferenceTypeId) if ref.NodeId.NamespaceIndex == 0 and ref.NodeId.Identifier in ua.ObjectIdNames: nodeid = ua.ObjectIdNames[ref.NodeId.Identifier] else: nodeid = ref.NodeId.to_string() if ref.TypeDefinition.Identifier in ua.ObjectIdNames: typedef = ua.ObjectIdNames[ref.TypeDefinition.Identifier] else: typedef = ref.TypeDefinition.to_string() titem = QStandardItem(typename) titem.setData(ref, Qt.UserRole) self.model.appendRow([ titem, QStandardItem(nodeid), QStandardItem(ref.BrowseName.to_string()), QStandardItem(typedef) ])
class SubtitleEditor(SubTab): def __init__(self, filePath, subtitleData, parent = None): name = os.path.split(filePath)[1] super(SubtitleEditor, self).__init__(name, parent) self.__initWidgets() self.__initContextMenu() self._settings = SubSettings() self._filePath = filePath self._movieFilePath = None self._subtitleData = subtitleData self.refreshSubtitles() # Some signals self._subtitleData.fileChanged.connect(self.fileChanged) self._subtitleData.subtitlesAdded.connect(self._subtitlesAdded) self._subtitleData.subtitlesRemoved.connect(self._subtitlesRemoved) self._subtitleData.subtitlesChanged.connect(self._subtitlesChanged) self._model.itemChanged.connect(self._subtitleEdited) self.customContextMenuRequested.connect(self.showContextMenu) def __initWidgets(self): minimalSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) # List of subtitles subListDelegate = SubListItemDelegate() self._model = QStandardItemModel(0, 3, self) self._model.setHorizontalHeaderLabels([_("Begin"), _("End"), _("Subtitle")]) self._subList = QTableView(self) self._subList.setModel(self._model) self._subList.setItemDelegateForColumn(0, subListDelegate) self._subList.setItemDelegateForColumn(1, subListDelegate) self._subList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) self._searchBar = SearchBar(self) self._searchBar.hide() # Top toolbar toolbar = QHBoxLayout() toolbar.setAlignment(Qt.AlignLeft) #toolbar.addWidget(someWidget....) toolbar.addStretch(1) # Main layout grid = QGridLayout() grid.setSpacing(10) grid.setContentsMargins(0, 3, 0, 0) grid.addLayout(toolbar, 0, 0, 1, 1) # stretch to the right grid.addWidget(self._subList, 1, 0) grid.addWidget(self._searchBar, 2, 0) self.setLayout(grid) def __initContextMenu(self): self._contextMenu = QMenu(self) self.setContextMenuPolicy(Qt.CustomContextMenu) af = ActionFactory(self) insertSub = af.create(title = _("&Insert subtitle"), icon = "list-add", connection = self.insertNewSubtitle) self._contextMenu.addAction(insertSub) insertSub = af.create(title = _("&Add subtitle"), icon = "list-add", connection = self.addNewSubtitle) self._contextMenu.addAction(insertSub) removeSub = af.create(title = _("&Remove subtitles"), icon = "list-remove", connection = self.removeSelectedSubtitles) self._contextMenu.addAction(removeSub) def _changeRowBackground(self, rowNo, bg): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): for columnNo in range(self._model.columnCount()): item = self._model.item(rowNo, columnNo) item.setBackground(bg) def _changeItemData(self, item, val, role): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): item.setData(val, role) def _handleIncorrectItem(self, item): with DisableSignalling(self._model.itemChanged, self._subtitleEdited): item.setData(False, CustomDataRoles.ErrorFlagRole) bg = item.background() rowNo = item.row() self._changeRowBackground(rowNo, Qt.red) QTimer.singleShot(600, lambda rowNo=rowNo, bg=bg: self._changeRowBackground(rowNo, bg)) def _subtitleEdited(self, item): modelIndex = item.index() column = modelIndex.column() subNo = modelIndex.row() errorFlag = item.data(CustomDataRoles.ErrorFlagRole) if errorFlag is True: self._handleIncorrectItem(item) else: # TODO: timeStart and timeEnd might be displayed in a frame format in a bright future. # Check it and create FrameTime properly in that case. # TODO: Maybe add column numbers to some kind of enum to avoid magic numbers? oldSubtitle = self.subtitles[subNo] newSubtitle = oldSubtitle.clone() if 0 == column: timeStart = item.data(CustomDataRoles.FrameTimeRole) newSubtitle.change(start = timeStart) elif 1 == column: timeEnd = item.data(CustomDataRoles.FrameTimeRole) newSubtitle.change(end = timeEnd) elif 2 == column: newSubtitle.change(text = item.text()) command = ChangeSubtitle(self.filePath, oldSubtitle, newSubtitle, subNo) self._subtitleData.execute(command) def _subtitlesAdded(self, path, subNos): if path != self.filePath: return subtitles = self.subtitles for subNo in subNos: row = createRow(subtitles[subNo]) self._model.insertRow(subNo, row) def _subtitlesRemoved(self, path, subNos): if path != self.filePath: return for subNo in subNos: self._model.removeRow(subNo) def _subtitlesChanged(self, path, subNos): if path != self.filePath: return for subNo in subNos: self.refreshSubtitle(subNo) def _createNewSubtitle(self, data, subNo): fps = data.fps # data is passed to avoid unnecessary copies minFrameTime = FrameTime(fps, frames = 1) # calculate correct minimum subtitle start time if subNo > 0: timeStart = data.subtitles[subNo - 1].end + minFrameTime else: timeStart = FrameTime(fps, frames = 0) # calculate correct maximum subtitle end time if subNo < data.subtitles.size(): try: timeEnd = data.subtitles[subNo].start - minFrameTime except SubException: timeEnd = FrameTime(fps, frames = 0) else: timeEnd = timeStart + FrameTime(fps, frames = 50) # add subtitle to DataModel sub = Subtitle(timeStart, timeEnd, "") command = AddSubtitle(self.filePath, subNo, sub) with DisableSignalling(self._subtitleData.subtitlesAdded, self._subtitlesAdded): self._subtitleData.execute(command) # create subtitle graphical representation in editor sub list row = createRow(sub) self._model.insertRow(subNo, row) index = self._model.index(subNo, 2) self._subList.clearSelection() self._subList.setCurrentIndex(index) self._subList.edit(index) def addNewSubtitle(self): data = self.data subNo = data.subtitles.size() indices = self._subList.selectedIndexes() if len(indices) > 0: rows = [index.row() for index in indices] subNo = max(rows) + 1 self._createNewSubtitle(data, subNo) def insertNewSubtitle(self): data = self.data subNo = 0 indices = self._subList.selectedIndexes() if len(indices) > 0: rows = [index.row() for index in indices] subNo = max(rows) self._createNewSubtitle(data, subNo) def removeSelectedSubtitles(self): indices = self._subList.selectedIndexes() if len(indices) > 0: rows = list(set([index.row() for index in indices])) command = RemoveSubtitles(self.filePath, rows) self._subtitleData.execute(command) if self._model.rowCount() > rows[-1]: self._subList.selectRow(rows[-1]) else: self._subList.selectRow(self._model.rowCount() - 1) def highlight(self): self._searchBar.show() self._searchBar.highlight() def showContextMenu(self): self._contextMenu.exec(QCursor.pos()) def changeInputEncoding(self, encoding): data = self._subtitleData.data(self.filePath) if encoding != data.inputEncoding: try: data.encode(encoding) except UnicodeDecodeError: message = QMessageBox( QMessageBox.Warning, _("Decoding error"), _("Cannot decode subtitles to '%s' encoding.\nPlease try different encoding.") % encoding, QMessageBox.Ok, self ) message.exec() except LookupError: message = QMessageBox(QMessageBox.Warning, _("Unknown encoding"), _("Unknown encoding: '%s'") % encoding, QMessageBox.Ok, self ) message.exec() else: # TODO: outputEncoding command = ChangeData(self.filePath, data, _("Input encoding: %s") % encoding) self._subtitleData.execute(command) def changeOutputEncoding(self, encoding): data = self._subtitleData.data(self.filePath) if encoding != data.outputEncoding: data.outputEncoding = encoding command = ChangeData(self.filePath, data, _("Output encoding: %s") % encoding) self._subtitleData.execute(command) def changeSubFormat(self, fmt): data = self._subtitleData.data(self.filePath) if data.outputFormat != fmt: data.outputFormat = fmt command = ChangeData(self.filePath, data) self._subtitleData.execute(command) def changeFps(self, fps): data = self.data if data.fps != fps: data.subtitles.changeFps(fps) data.fps = fps command = ChangeData(self.filePath, data, _("FPS: %s") % fps) self._subtitleData.execute(command) def changeVideoPath(self, path): data = self.data if data.videoPath != path: data.videoPath = path command = ChangeData(self.filePath, data, _("Video path: %s") % path) self._subtitleData.execute(command) def offset(self, seconds): data = self.data fps = data.subtitles.fps if fps is None: log.error(_("No FPS for '%s' (empty subtitles)." % self.filePath)) return ft = FrameTime(data.subtitles.fps, seconds=seconds) data.subtitles.offset(ft) command = ChangeData(self.filePath, data, _("Offset by: %s") % ft.toStr()) self._subtitleData.execute(command) def detectFps(self): data = self.data if data.videoPath is not None: fpsInfo = File.detectFpsFromMovie(data.videoPath) if data.videoPath != fpsInfo.videoPath or data.fps != fpsInfo.fps: data.videoPath = fpsInfo.videoPath data.subtitles.changeFps(fpsInfo.fps) data.fps = fpsInfo.fps command = ChangeData(self.filePath, data, _("Detected FPS: %s") % data.fps) self._subtitleData.execute(command) def fileChanged(self, filePath): if filePath == self._filePath: self.refreshSubtitles() def refreshSubtitle(self, subNo): sub = self.subtitles[subNo] self._model.removeRow(subNo) self._model.insertRow(subNo, createRow(sub)) def refreshSubtitles(self): self._model.removeRows(0, self._model.rowCount()) for sub in self.subtitles: self._model.appendRow(createRow(sub)) def updateTab(self): self.refreshSubtitles() def selectedSubtitles(self): rows = self.selectedRows() subtitleList = [self.subtitles[row] for row in rows] return subtitleList def selectedRows(self): indices = self._subList.selectedIndexes() # unique list rows = list(set([index.row() for index in indices])) rows.sort() return rows def selectRow(self, row): self._subList.selectRow(row) @property def filePath(self): return self._filePath @property def movieFilePath(self): return self._movieFilePath @property def data(self): return self._subtitleData.data(self.filePath) @property def subtitles(self): return self.data.subtitles @property def history(self): return self._subtitleData.history(self.filePath) @property def inputEncoding(self): return self.data.inputEncoding @property def outputEncoding(self): return self.data.outputEncoding @property def outputFormat(self): return self.data.outputFormat
class AddressList(MyTreeView): class Columns(IntEnum): TYPE = 0 ADDRESS = 1 LABEL = 2 COIN_BALANCE = 3 FIAT_BALANCE = 4 NUM_TXS = 5 filter_columns = [ Columns.TYPE, Columns.ADDRESS, Columns.LABEL, Columns.COIN_BALANCE ] ROLE_SORT_ORDER = Qt.UserRole + 1000 def __init__(self, parent): super().__init__(parent, self.create_menu, stretch_column=self.Columns.LABEL) self.wallet = self.parent.wallet self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.change_button = QComboBox(self) self.change_button.currentIndexChanged.connect(self.toggle_change) for addr_type in AddressTypeFilter.__members__.values( ): # type: AddressTypeFilter self.change_button.addItem(addr_type.ui_text()) self.used_button = QComboBox(self) self.used_button.currentIndexChanged.connect(self.toggle_used) for addr_usage_state in AddressUsageStateFilter.__members__.values( ): # type: AddressUsageStateFilter self.used_button.addItem(addr_usage_state.ui_text()) self.std_model = QStandardItemModel(self) self.proxy = MySortModel(self, sort_role=self.ROLE_SORT_ORDER) self.proxy.setSourceModel(self.std_model) self.setModel(self.proxy) self.update() self.sortByColumn(self.Columns.TYPE, Qt.AscendingOrder) def get_toolbar_buttons(self): return QLabel(_("Filter:")), self.change_button, self.used_button def on_hide_toolbar(self): self.show_change = AddressTypeFilter.ALL # type: AddressTypeFilter self.show_used = AddressUsageStateFilter.ALL # type: AddressUsageStateFilter self.update() def save_toolbar_state(self, state, config): config.set_key('show_toolbar_addresses', state) def refresh_headers(self): fx = self.parent.fx if fx and fx.get_fiat_address_config(): ccy = fx.get_currency() else: ccy = _('Fiat') headers = { self.Columns.TYPE: _('Type'), self.Columns.ADDRESS: _('Address'), self.Columns.LABEL: _('Label'), self.Columns.COIN_BALANCE: _('Balance'), self.Columns.FIAT_BALANCE: ccy + ' ' + _('Balance'), self.Columns.NUM_TXS: _('Tx'), } self.update_headers(headers) def toggle_change(self, state: int): if state == self.show_change: return self.show_change = AddressTypeFilter(state) self.update() def toggle_used(self, state: int): if state == self.show_used: return self.show_used = AddressUsageStateFilter(state) self.update() @profiler def update(self): if self.maybe_defer_update(): return current_address = self.current_item_user_role(col=self.Columns.LABEL) if self.show_change == AddressTypeFilter.RECEIVING: addr_list = self.wallet.get_receiving_addresses() elif self.show_change == AddressTypeFilter.CHANGE: addr_list = self.wallet.get_change_addresses() else: addr_list = self.wallet.get_addresses() self.proxy.setDynamicSortFilter( False) # temp. disable re-sorting after every change self.std_model.clear() self.refresh_headers() fx = self.parent.fx set_address = None addresses_beyond_gap_limit = self.wallet.get_all_known_addresses_beyond_gap_limit( ) for address in addr_list: num = self.wallet.get_address_history_len(address) label = self.wallet.labels.get(address, '') c, u, x = self.wallet.get_addr_balance(address) balance = c + u + x is_used_and_empty = self.wallet.is_used(address) and balance == 0 if self.show_used == AddressUsageStateFilter.UNUSED and ( balance or is_used_and_empty): continue if self.show_used == AddressUsageStateFilter.FUNDED and balance == 0: continue if self.show_used == AddressUsageStateFilter.USED_AND_EMPTY and not is_used_and_empty: continue balance_text = self.parent.format_amount(balance, whitespaces=True) # create item if fx and fx.get_fiat_address_config(): rate = fx.exchange_rate() fiat_balance = fx.value_str(balance, rate) else: fiat_balance = '' labels = [ '', address, label, balance_text, fiat_balance, "%d" % num ] address_item = [QStandardItem(e) for e in labels] # align text and set fonts for i, item in enumerate(address_item): item.setTextAlignment(Qt.AlignVCenter) if i not in (self.Columns.TYPE, self.Columns.LABEL): item.setFont(QFont(MONOSPACE_FONT)) self.set_editability(address_item) address_item[self.Columns.FIAT_BALANCE].setTextAlignment( Qt.AlignRight | Qt.AlignVCenter) # setup column 0 if self.wallet.is_change(address): address_item[self.Columns.TYPE].setText(_('change')) address_item[self.Columns.TYPE].setBackground( ColorScheme.YELLOW.as_color(True)) else: address_item[self.Columns.TYPE].setText(_('receiving')) address_item[self.Columns.TYPE].setBackground( ColorScheme.GREEN.as_color(True)) address_item[self.Columns.LABEL].setData(address, Qt.UserRole) address_path = self.wallet.get_address_index(address) address_item[self.Columns.TYPE].setData(address_path, self.ROLE_SORT_ORDER) address_path_str = self.wallet.get_address_path_str(address) if address_path_str is not None: address_item[self.Columns.TYPE].setToolTip(address_path_str) address_item[self.Columns.FIAT_BALANCE].setData( balance, self.ROLE_SORT_ORDER) # setup column 1 if self.wallet.is_frozen_address(address): address_item[self.Columns.ADDRESS].setBackground( ColorScheme.BLUE.as_color(True)) if address in addresses_beyond_gap_limit: address_item[self.Columns.ADDRESS].setBackground( ColorScheme.RED.as_color(True)) # add item count = self.std_model.rowCount() self.std_model.insertRow(count, address_item) address_idx = self.std_model.index(count, self.Columns.LABEL) if address == current_address: set_address = QPersistentModelIndex(address_idx) self.set_current_idx(set_address) # show/hide columns if fx and fx.get_fiat_address_config(): self.showColumn(self.Columns.FIAT_BALANCE) else: self.hideColumn(self.Columns.FIAT_BALANCE) self.filter() self.proxy.setDynamicSortFilter(True) def create_menu(self, position): from electrum_mona.wallet import Multisig_Wallet is_multisig = isinstance(self.wallet, Multisig_Wallet) can_delete = self.wallet.can_delete_address() selected = self.selected_in_column(self.Columns.ADDRESS) if not selected: return multi_select = len(selected) > 1 addrs = [self.item_from_index(item).text() for item in selected] menu = QMenu() if not multi_select: idx = self.indexAt(position) if not idx.isValid(): return item = self.item_from_index(idx) if not item: return addr = addrs[0] addr_column_title = self.std_model.horizontalHeaderItem( self.Columns.LABEL).text() addr_idx = idx.sibling(idx.row(), self.Columns.LABEL) self.add_copy_menu(menu, idx) menu.addAction(_('Details'), lambda: self.parent.show_address(addr)) persistent = QPersistentModelIndex(addr_idx) menu.addAction(_("Edit {}").format(addr_column_title), lambda p=persistent: self.edit(QModelIndex(p))) #menu.addAction(_("Request payment"), lambda: self.parent.receive_at(addr)) if self.wallet.can_export(): menu.addAction(_("Private key"), lambda: self.parent.show_private_key(addr)) if not is_multisig and not self.wallet.is_watching_only(): menu.addAction(_("Sign/verify message"), lambda: self.parent.sign_verify_message(addr)) menu.addAction(_("Encrypt/decrypt message"), lambda: self.parent.encrypt_message(addr)) if can_delete: menu.addAction(_("Remove from wallet"), lambda: self.parent.remove_address(addr)) addr_URL = block_explorer_URL(self.config, 'addr', addr) if addr_URL: menu.addAction(_("View on block explorer"), lambda: webopen(addr_URL)) if not self.wallet.is_frozen_address(addr): menu.addAction( _("Freeze"), lambda: self.parent. set_frozen_state_of_addresses([addr], True)) else: menu.addAction( _("Unfreeze"), lambda: self.parent. set_frozen_state_of_addresses([addr], False)) coins = self.wallet.get_spendable_coins(addrs) if coins: menu.addAction(_("Spend from"), lambda: self.parent.utxo_list.set_spend_list(coins)) run_hook('receive_menu', menu, addrs, self.wallet) menu.exec_(self.viewport().mapToGlobal(position)) def place_text_on_clipboard(self, text: str, *, title: str = None) -> None: if is_address(text): try: self.wallet.check_address_for_corruption(text) except InternalAddressCorruption as e: self.parent.show_error(str(e)) raise super().place_text_on_clipboard(text, title=title)
spinBox.interpretText() value = spinBox.value() model.setData(index, value, Qt.EditRole) def updateEditorGeometry(self, editor, option, index): editor.setGeometry(option.rect) if __name__ == '__main__': import sys app = QApplication(sys.argv) model = QStandardItemModel(4, 2) tableView = QTableView() tableView.setModel(model) delegate = SpinBoxDelegate() tableView.setItemDelegate(delegate) for row in range(4): for column in range(2): index = model.index(row, column, QModelIndex()) model.setData(index, (row + 1) * (column + 1)) tableView.setWindowTitle("Spin Box Delegate") tableView.show() sys.exit(app.exec_())
class YoutubeDLGui(QMainWindow): def __init__(self): super(YoutubeDLGui, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) Center(self) self.download_model = QStandardItemModel(0, 5, self) self.download_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Name') self.download_model.setHeaderData(1, QtCore.Qt.Horizontal, 'Progress') self.download_model.setHeaderData(2, QtCore.Qt.Horizontal, 'Size') self.download_model.setHeaderData(3, QtCore.Qt.Horizontal, 'ETA') self.download_model.setHeaderData(4, QtCore.Qt.Horizontal, 'Speed') self.ui.downloadView.setModel(self.download_model) self.pending_model = QStandardItemModel(0, 2, self) self.pending_model.setHeaderData(0, QtCore.Qt.Horizontal, 'Name') self.pending_model.setHeaderData(1, QtCore.Qt.Horizontal, 'Quality') self.ui.pendingView.setModel(self.pending_model) self.ui.pendingView.setItemDelegate(CustomToolTipDelegate(self.ui.pendingView)) self.init_status_bar() self.parsing_worker = WorkerBuilder.build(bool) self.pending_list = [] def init_status_bar(self): self.pending_progressbar = QProgressBar() self.pending_progressbar.setFixedHeight(20) self.pending_progressbar.setFixedWidth(150) self.pending_progressbar.setMaximum(0) self.pending_progressbar.setMinimum(0) self.pending_label = QLabel("") self.pending_label.setAlignment(QtCore.Qt.AlignLeading) self.pending_label.setFixedWidth(220) font = self.pending_label.font() font.setPointSize(10) self.pending_label.setFont(font) self.pending_label.setStyleSheet("padding-left: 5px") self.pending_progressbar.setVisible(False) self.statusBar().addPermanentWidget(self.pending_progressbar) self.statusBar().addWidget(self.pending_label) @pyqtSlot() def on_addBtn_clicked(self): url = CustomInputDialog.get_text("Url", "Enter Url") if not url[1]: return if not validators.url(url[0]): QMessageBox.information(self, "Invalid Url", "Please enter a valid url") self.on_addBtn_clicked() ydl_logger = YDLLogger() ydl_logger.debug_message.connect(self.on_debug_message_emitted) ydl_opt = { 'logger': ydl_logger } self.ui.addBtn.setEnabled(False) self.parser = InfoParser(url[0], ydl_opt) self.parsing_worker.set_up(self.parser.generate_info, self.on_parsing_done) self.parsing_worker.start() self.pending_progressbar.setVisible(True) @pyqtSlot(int) def on_combobox_currentIndexChanged(self, index): list_index = self.ui.pendingView.currentIndex().row() self.pending_list[list_index].current_format = self.pending_list[list_index].format_info[index] @pyqtSlot(str) def on_debug_message_emitted(self, msg): self.pending_label.setText(msg) def add_to_pending(self, ydl_obj): if ydl_obj in self.pending_list: return index = len(self.pending_list) self.pending_list.append(ydl_obj) self.pending_model.insertRow(index) self.pending_model.setData(self.pending_model.index(index, 0), ydl_obj.title) model_index = self.pending_model.index(index, 0) self.ui.pendingView.setCurrentIndex(model_index) self.ui.pendingView.selectionModel().select(model_index, QItemSelectionModel.ClearAndSelect) combobox = QComboBox() combobox.currentIndexChanged[int].connect(self.on_combobox_currentIndexChanged) for ydl_format in ydl_obj.info: format_text = "%s, %s, %s" % (ydl_format['extension'], ydl_format['resolution'], ydl_format['filesize']) combobox.addItem(format_text) self.ui.pendingView.setIndexWidget(self.pending_model.index(index, 1), combobox) self.ui.tabWidget.setCurrentIndex(1) def on_parsing_done(self, success): self.pending_progressbar.setVisible(False) self.pending_label.setText("") self.ui.addBtn.setEnabled(True) if success: self.add_to_pending(self.parser.ydl_object) else: self.parsing_worker.quit() self.ui.addBtn.setEnabled(True) QMessageBox.information(self, "Invalid Url", "Unable to parse url")
class Ui_MainWindow(QMainWindow): def __init__(self): super().__init__() self.select_checkbox_num = 0 self.all_widgets = [] self.game_sub_menus = [] self.face_sub_menus = [] self.setupUi(self) self.updateMenu(self) self.retranslateUi(self) def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(775, 532) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 775, 23)) self.menubar.setObjectName("menubar") self.menu = QtWidgets.QMenu(self.menubar) self.menu.setObjectName("menu") self.menu_team = QtWidgets.QMenu(self.menubar) #参赛队组建菜单 self.menu_team.setObjectName("menu_team") self.menu_face = QtWidgets.QMenu(self.menubar) #对阵组建 self.menu_face.setObjectName("menu_face") MainWindow.setMenuBar(self.menubar) mgr_player = QAction(QIcon(), '运动员管理', self) mgr_player.triggered.connect( functools.partial(self.edit_player, *self.get_player_parmas())) mgr_playground = QAction(QIcon(), '场地管理', self) mgr_playground.triggered.connect( functools.partial(self.edit_player, *self.get_playground_parmas())) mgr_game = QAction(QIcon(), '竞赛项目', self) mgr_game.triggered.connect( functools.partial(self.edit_player, *self.get_game_parmas())) mgr_team = QAction(QIcon(), '参赛团队', self) mgr_team.triggered.connect(self.edit_team) mgr_group = QAction(QIcon(), '分组管理', self) mgr_group.triggered.connect(self.edit_group) mgr_test = QAction(QIcon(), '我的测试', self) mgr_test.triggered.connect(self.test) # mgr_face = QAction(QIcon(),'对阵设定',self) # mgr_face.triggered.connect(self.edit_face) self.toolbar = self.addToolBar('Mytool') self.toolbar.addAction(mgr_player) self.toolbar.addAction(mgr_playground) self.toolbar.addAction(mgr_game) self.toolbar.addAction(mgr_team) self.toolbar.addAction(mgr_group) self.toolbar.addAction(mgr_test) # self.toolbar.addAction(mgr_face) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.action_init = QtWidgets.QAction(MainWindow) self.action_init.setObjectName("action_init") self.action_import_data = QtWidgets.QAction(MainWindow) self.action_import_data.setObjectName("action_import_data") self.action_gamemgr = QtWidgets.QAction(MainWindow) self.action_gamemgr.setObjectName("action_gamemgr") self.menu.addAction(self.action_init) self.menu.addAction(self.action_import_data) self.menu.addSeparator() self.menubar.addAction(self.menu.menuAction()) self.menubar.addAction(self.menu_team.menuAction()) self.menubar.addAction(self.menu_face.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.action_init.triggered.connect(self.clear_data_firm) self.action_import_data.triggered.connect(self.get_data_file) self.add_first_ui() # if has_data(): # self.add_team_ui() # time.sleep(2) # self.centralwidget.hide() # def pr(self): # print('prrrrr') def updateMenu(self, MainWindow): """添加或更新为每个竞赛项目组队的‘参赛队组建’菜单""" self.games = get_games() # 清除‘参赛队组建’原子菜单 for game_sub_menu in self.game_sub_menus: self.menu_team.removeAction(game_sub_menu) for game in self.games: self.game_sub_menus.append(QtWidgets.QAction(MainWindow)) for game_sub_menu, game in zip(self.game_sub_menus, self.games): game_sub_menu.setObjectName(game.name) game_sub_menu.triggered.connect( functools.partial(self.select_player, game.id, game.name, game.team_num, game.sex)) game_sub_menu.setText( QtCore.QCoreApplication.translate("MainWindow", "&{}".format(game.name))) for game_sub_menu in self.game_sub_menus: self.menu_team.addAction(game_sub_menu) """添加或更新为每个竞赛项目组队的‘对阵组建’菜单""" for face_sub_menu in self.face_sub_menus: self.menu_face.removeAction(face_sub_menu) for game in self.games: self.face_sub_menus.append(QtWidgets.QAction(MainWindow)) for game_sub_menu, game in zip(self.face_sub_menus, self.games): game_sub_menu.setObjectName(game.name + '_') game_sub_menu.triggered.connect( functools.partial(self.new_face, game.id)) game_sub_menu.setText( QtCore.QCoreApplication.translate("MainWindow", "&{}".format(game.name))) for game_sub_menu in self.face_sub_menus: self.menu_face.addAction(game_sub_menu) def add_first_ui(self, info="Welcome!"): self.takeCentralWidget() self.main_frame = QScrollArea(self) self.main_frame.setStyleSheet( 'QWidget{background-color:rgb(255,255,255)}') self.wel = QLabel(info) boxlayout = QHBoxLayout() boxlayout.addStretch() boxlayout.addWidget(self.wel) boxlayout.addStretch() self.main_frame.setLayout(boxlayout) self.setCentralWidget(self.main_frame) # def add_team_ui(self): # self.centralwidget = QWidget() # self.form_layout = QHBoxLayout(self.centralwidget) # self.left_layout = MyQVBoxLayout() # self.right_layout = QVBoxLayout() # # qbtn = QPushButton('1') # # qbtn.resize(qbtn.minimumSize()) # self.left_widgts = self.get_left_widgts() # # self.left_layout.addWidget(qbtn) # # self.left_layout.addWidget(QLabel('def')) # for widgt in self.left_widgts: # self.left_layout.addWidget(widgt) # self.left_layout.addStretch() # # self.right_layout.addWidget(QLabel('aaaa'),0,0) # # self.right_layout.addWidget(QLabel('bbbb'),1,0) # self.right_widgts = self.get_right_widgets() # for widgt in self.right_widgts: # self.right_layout.addWidget(widgt) # self.right_layout.addStretch() # self.form_layout.addLayout(self.left_layout) # self.form_layout.addLayout(self.right_layout) # self.setCentralWidget(self.centralwidget) # qbtn.clicked.connect(self.test) # def test(self): # centralwidget = QWidget() # test_layout = QHBoxLayout(centralwidget) # test_layout.addWidget(QLabel('kkkkkkkkkkkkkkkkkkk')) # # self.removeWidget(self.centralwidget) # self.takeCentralWidget() # self.setCentralWidget(centralwidget) # # self.show() # # self.update() # # self.repaint() # def test_tool(self): # print('abccc') # self.wel.setText('akkkkkkkkkkkk!') # self.takeCentralWidget() # self.setCentralWidget(QLabel('kkkdkddaaaaaaaaaaaaaa')) # main_form = QFormLayout() # left_widgt = QWidget(None) # left_widgt_layout = QVBoxLayout() # left_widgt.setLayout(left_widgt_layout) # for i in range(5): # left_widgt_layout.addWidget(QLabel('标签%i' % i)) # for w in self.get_left_widgts(): # left_widgt_layout.addWidget(w) # scroll_area = QScrollArea() # right_widgt = QWidget(None) # self.right_widgt_layout = QVBoxLayout() # right_widgt.setLayout(self.right_widgt_layout) # self.right_widgt_layout.addWidget(QLabel('标签%i' % 5)) # self.right_widgt_layout.addWidget(QLabel('标签%i' % 7)) # scroll_area.setWidget(right_widgt) # main_form.addRow(left_widgt,scroll_area) # main_widgt = QWidget(None) # main_widgt.setLayout(main_form) # self.setCentralWidget(main_widgt) # def get_left_widgts(self): # widgts = [] # self.game_data = get_games() # mylbl = QLabel('运动项目:') # mylbl.setMaximumHeight(20) # widgts.append(mylbl) # self.game_combo = QComboBox(None) # self.game_combo.setMaximumWidth(80) # self.game_combo.setMaximumHeight(20) # for item in self.game_data.keys(): # self.game_combo.addItem(item) # widgts.append(self.game_combo) # self.game_combo.setCurrentIndex(-1) # self.game_combo.activated[str].connect(self.set_cur_game) # return widgts # def set_cur_game(self,game): # self.game = game # print(game,self.game_data[game]) # if self.game_data[game] == 1: # self.show_players(game) # def get_right_widgets(self): # players = get_players() # widgts = [] # for p in players: # data = [p.name,p.idcode,p.sex,p.age,p.work_place,p.tel] # data = ['' if d is None else d for d in data] # info = '{: <8} {: <8} {: <2} {: <2} {: <10} {: <12}'.format(*data) # widgts.append(QLabel(info)) # return widgts # def show_players(self,game): # self.test() # game_sex = get_games_sex() # sex = game_sex[game] # self.players = get_players(sex) # self.p_checkboxes = [QCheckBox(' '.join((p.name,p.idcode))) for p in self.players] # for w in self.right_widgts: # w.hide() # for cb in self.p_checkboxes: # cb.toggle() # print('abc') # self.right_layout.addWidget(cb) # self.right_layout.addStretch() def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "易用竞赛管理系统")) self.menu.setTitle(_translate("MainWindow", "&管理数据")) self.action_init.setText(_translate("MainWindow", "&清理数据")) self.action_import_data.setText(_translate("MainWindow", "&导入数据")) self.menu_team.setTitle(_translate("MainWindow", "&参赛队组建")) self.menu_face.setTitle(_translate("MainWindow", "&对阵组建")) def get_data_file(self): fname = QFileDialog.getOpenFileName(self, '打开文件', '.\\') if fname[0]: info = load_data(fname[0]) if info: QMessageBox.information(self, "数据错误,请修改后重新导入!", info) else: QMessageBox.information(self, "提示:", '数据导入成功!') self.add_first_ui('数据已导入!') # self.add_team_ui() self.updateMenu(self) def clear_data_firm(self): reply = QMessageBox.question(self, '确认', '确定删除数据?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) self.takeCentralWidget() if reply == QMessageBox.Yes: clear_data() self.add_first_ui('数据已全部清空!') def get_player_parmas(self): head_lst = ['索引号', '姓名', '身份证号', '性别', '年龄', '工作单位', '电话'] keys = ['id', 'name', 'idcode', 'sex', 'age', 'work_place', 'tel'] return get_players, keys, head_lst, Player def get_playground_parmas(self): head_lst = ['索引号', '场地名', '使用状态', '备注'] keys = ['id', 'name', 'using', 'memo'] return get_playgrounds, keys, head_lst, PlayGround def get_game_parmas(self): head_lst = ['索引号', '竞赛项目', '队员人数', '队员性别', '备注'] keys = ['id', 'name', 'team_num', 'sex', 'memo'] return get_games, keys, head_lst, Games def edit_player(self, getfunc, keys, head_lst, obj): model_objs = getfunc() datas = [] for model_obj in model_objs: # data = [p.id,p.name,p.idcode,p.sex,p.age,p.work_place,p.tel] data = [getattr(model_obj, key) for key in keys] data = ['' if d is None else d for d in data] datas.append(data) # head_lst = ['索引号','姓名','身份证号','性别','年龄','工作单位','电话'] if datas: self.takeCentralWidget() main_frame = QScrollArea(self) main_frame.setStyleSheet( 'QWidget{background-color:rgb(255,255,255)}') self.player_tabview = QTableView() r, c = len(datas), len(datas[0]) self.player_model = QStandardItemModel(r, c) self.player_model.setHorizontalHeaderLabels(head_lst) for r, rdata in enumerate(datas): for c, cell in enumerate(rdata): it = QStandardItem(str(cell)) if c == 0: it.setEditable(False) self.player_model.setItem(r, c, it) # keys = ['id','name','idcode','sex','age','work_place','tel'] edit_cell = functools.partial(self.edit_cell, obj, keys) self.player_model.itemChanged.connect(edit_cell) self.player_tabview.setModel(self.player_model) boxlayout = QVBoxLayout() # boxlayout.addStretch(1) boxlayout.addWidget(self.player_tabview, 18) # boxlayout.addStretch(1) del_btn = QPushButton('删除') del_btn.clicked.connect(functools.partial(self.del_row, obj)) boxlayout.addWidget(del_btn) main_frame.setLayout(boxlayout) self.setCentralWidget(main_frame) def edit_cell(self, obj, keys): r = self.player_tabview.currentIndex().row() c = self.player_tabview.currentIndex().column() curr_data = self.player_tabview.currentIndex().data() item = self.player_model.index(r, 0) param = dict() param[keys[c]] = curr_data save_cell(obj, int(item.data()), param) if obj == Games and 'name' in param: self.updateMenu(self) def del_row(self, obj): reply = QMessageBox.question(self, '确认', '确定删除数据?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: r = self.player_tabview.currentIndex().row() item = self.player_model.index(r, 0) # print(int(item.data())) del_rowdb(obj, int(item.data())) self.player_model.removeRow(r) if obj == Games: self.updateMenu(self) def edit_team(self): datas = get_team_datas() head_lst = ['索引号', '队名', '项目', '分组'] if datas: self.takeCentralWidget() main_frame = QScrollArea(self) main_frame.setStyleSheet( 'QWidget{background-color:rgb(255,255,255)}') self.player_tabview = QTableView() r, c = len(datas), len(datas[0]) self.player_model = QStandardItemModel(r, c) self.player_model.setHorizontalHeaderLabels(head_lst) for r, rdata in enumerate(datas): for c, cell in enumerate(rdata): it = QStandardItem(str(cell)) if c == 0: it.setEditable(False) self.player_model.setItem(r, c, it) # keys = ['id','name','idcode','sex','age','work_place','tel'] # edit_cell = functools.partial(self.edit_cell,obj,keys) # self.player_model.itemChanged.connect(edit_cell) self.player_tabview.setModel(self.player_model) boxlayout = QVBoxLayout() # boxlayout.addStretch(1) boxlayout.addWidget(self.player_tabview, 18) # boxlayout.addStretch(1) del_btn = QPushButton('删除') del_btn.clicked.connect(self.del_team) boxlayout.addWidget(del_btn) main_frame.setLayout(boxlayout) self.setCentralWidget(main_frame) def del_team(self): # v = MyDialog() # if v.exec_(): # name,game = v.get_data() # print(name,game) reply = QMessageBox.question(self, '确认', '确定删除数据?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: r = self.player_tabview.currentIndex().row() item = self.player_model.index(r, 0) # print(int(item.data())) del_rowdb(Team, int(item.data())) self.player_model.removeRow(r) def select_player(self, gid, gname, gteam_num, gsex): # 新建团队UI players = get_players(gsex) head_lst = ['索引号', '姓名', '身份证号', '性别', '年龄', '工作单位', '电话'] keys = ['id', 'name', 'idcode', 'sex', 'age', 'work_place', 'tel'] datas = [] for player in players: data = [getattr(player, key) for key in keys] data = ['' if d is None else d for d in data] datas.append(data) if datas: self.takeCentralWidget() main_frame = QScrollArea(self) main_frame.setStyleSheet( 'QWidget{background-color:rgb(255,255,255)}') self.player_tabview = QTableView() r, c = len(datas), len(datas[0]) self.player_model = QStandardItemModel(r, c) print(self.player_tabview.itemDelegate()) self.player_model.setHorizontalHeaderLabels(head_lst) for r, rdata in enumerate(datas): for c, cell in enumerate(rdata): it = QStandardItem(str(cell)) if c == 0: it.setEditable(False) self.player_model.setItem(r, c, it) self.player_tabview.setModel(self.player_model) boxlayout = QVBoxLayout() # boxlayout.addStretch(1) boxlayout.addWidget(self.player_tabview, 18) # boxlayout.addStretch(1) new_btn = QPushButton('新建团队({})'.format(gname)) new_btn.clicked.connect( functools.partial(self.add_team, gid, gteam_num, gsex)) boxlayout.addWidget(new_btn) main_frame.setLayout(boxlayout) self.setCentralWidget(main_frame) def add_team(self, gid, gteam_num, gsex): # 新建团队方法 rows = set() pids = [] for selected_model_index in self.player_tabview.selectedIndexes(): rows.add(selected_model_index.row()) for r in rows: item = self.player_model.index(r, 0) pids.append(item.data()) if gteam_num == 1: info = new_team(gid, pids, flag=1) if info: QMessageBox.warning(self, '完成', info, QMessageBox.Ok) else: QMessageBox.information(self, '完成', '成功建立!', QMessageBox.Ok) if gteam_num > 1: if len(rows) == gteam_num: info = new_team(gid, pids) if info: QMessageBox.warning(self, '完成', info, QMessageBox.Ok) else: QMessageBox.information(self, '完成', '成功建立!', QMessageBox.Ok) else: QMessageBox.warning(self, '错误', '请选中指定的运动员数:{}'.format(gteam_num), QMessageBox.Ok) self.player_tabview.clearSelection() def test(self): from .modeltt import TObjModel, MyDelegate md = MyDelegate() self.takeCentralWidget() main_frame = QScrollArea(self) main_frame.setStyleSheet('QWidget{background-color:rgb(255,255,255)}') self.player_tabview = QTableView() self.player_model = TObjModel() self.player_tabview.setModel(self.player_model) boxlayout = QVBoxLayout() # boxlayout.addStretch(1) boxlayout.addWidget(self.player_tabview, 18) self.player_tabview.setItemDelegateForColumn(2, md) self.player_tabview.hideColumn(0) main_frame.setLayout(boxlayout) self.setCentralWidget(main_frame) def edit_group(self): datas = get_group_datas() head_lst = ['索引号', '组名', '项目', '所含队名', 'gameid'] self.takeCentralWidget() main_frame = QScrollArea(self) main_frame.setStyleSheet('QWidget{background-color:rgb(255,255,255)}') self.player_tabview = QTableView() self.player_model = QStandardItemModel() self.player_model.setHorizontalHeaderLabels(head_lst) if datas: r, c = len(datas), len(datas[0]) # self.player_model = QStandardItemModel(r,c) self.player_model.setHorizontalHeaderLabels(head_lst) for r, rdata in enumerate(datas): for c, cell in enumerate(rdata): it = QStandardItem(str(cell)) # if c == 0: it.setEditable(False) self.player_model.setItem(r, c, it) # keys = ['id','name','idcode','sex','age','work_place','tel'] # edit_cell = functools.partial(self.edit_cell,obj,keys) # self.player_model.itemChanged.connect(edit_cell) self.player_tabview.setModel(self.player_model) boxlayout = QVBoxLayout() # boxlayout.addStretch(1) boxlayout.addWidget(self.player_tabview, 18) # boxlayout.addStretch(1) self.player_tabview.hideColumn(4) add_btn = QPushButton('添加分组') add_btn.clicked.connect(self.add_group) boxlayout.addWidget(add_btn) del_btn = QPushButton('删除分组') del_btn.clicked.connect(functools.partial(self.del_row, Group)) boxlayout.addWidget(del_btn) add_team_btn = QPushButton('分配参赛团队') add_team_btn.clicked.connect(self.add_team2group) boxlayout.addWidget(add_team_btn) main_frame.setLayout(boxlayout) self.setCentralWidget(main_frame) def add_group(self): v = MyDialog() if v.exec_(): name, game = v.get_data() if name and game: info = add_groupdb(name, int(game)) if info: QMessageBox.warning(self, '错误', info, QMessageBox.Ok) else: QMessageBox.information(self, '完成', '成功建立!', QMessageBox.Ok) self.edit_group() def add_team2group(self): rows = set() for selected_model_index in self.player_tabview.selectedIndexes(): rows.add(selected_model_index.row()) if len(rows) != 1: QMessageBox.warning(self, '错误', '请仅选择其中一个小组', QMessageBox.Ok) return row = rows.pop() groupid = self.player_model.index(row, 0).data() gameid = self.player_model.index(row, 4).data() print(groupid, gameid) if get_team_datas(gameid): v = GroupDialog(gameid, "添加团队到小组", get_team_datas) if v.exec_(): tids = v.get_data() print(tids) if tids: add_team2group_db(groupid, tids) QMessageBox.information(self, '提示', '操作完成!', QMessageBox.Ok) else: QMessageBox.information(self, '提示', '无参赛团队可以分组!', QMessageBox.Ok) def get_grp_combo(self, gid): groups = get_group_for_game(gid) cur_index = -1 grp_combo = QComboBox() for index, (ggid, gname, ggname) in enumerate(groups): grp_combo.addItem('-'.join((ggname, gname)), ggid) grp_combo.setCurrentIndex(cur_index) grp_combo.currentIndexChanged.connect( functools.partial(self.disp_face, gid)) grp_combo.setToolTip('请选择一个分组,并为其建立对阵。') return grp_combo def new_face(self, gid): # print(gid) self.takeCentralWidget() main_frame = QScrollArea(self) main_frame.setStyleSheet('QWidget{background-color:rgb(255,255,255)}') boxlayout = QVBoxLayout() self.grp_combo = self.get_grp_combo(gid) boxlayout.addWidget(self.grp_combo) # boxlayout.addStretch(1) self.face_view = QTableView() self.face_model = QStandardItemModel() self.face_model.setHorizontalHeaderLabels(['id', '队A', '队B']) self.face_view.setModel(self.face_model) boxlayout.addWidget(self.face_view) add_btn = QPushButton('添加对阵') add_btn.clicked.connect(functools.partial(self.add_face, gid)) boxlayout.addWidget(add_btn) main_frame.setLayout(boxlayout) self.setCentralWidget(main_frame) def disp_face(self, gid): # print(self.grp_combo.currentIndex(),self.grp_combo.currentText()) self.ggid = int(self.grp_combo.itemData(self.grp_combo.currentIndex())) if self.ggid >= 1: self.face_model.beginResetModel() self.face_model.clear() self.face_model.setHorizontalHeaderLabels(['id', '队A', '队B']) faces = get_faces(gid, self.ggid) for r, rd in enumerate(faces): for c, cd in enumerate(rd): item = QStandardItem(str(cd)) item.setEditable(False) self.face_model.setItem(r, c, item) self.face_model.endResetModel() def add_face(self, gid): v = GroupDialog(self.ggid, "添加对阵团队", get_teams_for_group) if v.exec_(): tids = v.get_data() print(tids) tids = [int(tid) for tid in tids] if len(tids) != 2: QMessageBox.warning(self, '错误', '请仅选择对阵的双方小组', QMessageBox.Ok) else: tids.sort() if add_face2db(*tids): self.disp_face(gid) QMessageBox.information(self, '提示', '操作完成!', QMessageBox.Ok) else: QMessageBox.warning(self, '错误', '对阵不能重复!', QMessageBox.Ok)
class mainView(QtWidgets.QMainWindow, mainWin.Ui_MainWindow): """ 主窗口类 """ def __init__(self): super(mainView, self).__init__() self.setupUi(self) # 主要变量初始化 self.isShow_flag = False self.account = "admin" self.password = "******" self.loadTimeStr = "" self.isAdmin = False self.curPage = 1 self.totalPage = 1 # 日志相关变量和类的初始化 # self.log = logout.TimedRotatingFileLog("win_log",".\\log\\", "win.log",logging.DEBUG) self.log = logout.RotatingFileLog("win_log", ".\\log\\", "win.log", logging.DEBUG) self.msg_list = [] self.msg_list2 = [] self.DEBUG = 1 self.INFO = 2 self.WARNING = 3 self.ERROR = 4 self.CRITICAL = 5 # 线程锁及线程信号量初始化 self.mutex1 = QMutex() self.mutex2 = QMutex() self.signal = threading.Event() self.signal.clear() # 初始化数据库相关信息 my_cof = config.config() # my_cof.cofig_update() my_cof.get_config() self.msg_level = my_cof.level["msg_level"] self.ip1 = my_cof.scanner["s1_ip"] # "172.24.24.222" self.port1 = my_cof.scanner["s1_port"] # 51236 self.ip2 = my_cof.scanner["s2_ip"] # "172.24.24.222" self.port2 = my_cof.scanner["s2_port"] # 51236 self.db = pymysql.Connect(my_cof.mysql["host"], my_cof.mysql["user"], my_cof.mysql["passwd"], my_cof.mysql["dbName"]) self.cursor = self.db.cursor() # self.db = pymysql.Connect(mysql["host"], mysql["user"], mysql["passwd"], mysql["dbName"]) # self.cursor = self.db.cursor() # 系统时间显示相关类初始化 self.updateTime = QTimer() self.updateTime.start(1000) self.updateTime.timeout.connect(self.updateTimeShow) # 自动刷新显示列表定时器初始化 self.Refresh_timer = QTimer() self.Refresh_timer.timeout.connect(self.refreshSelf) # 扫码枪未连接提示 self.scanner_statue_timer = QTimer() self.scanner_statue_timer.timeout.connect(self.scanner_statu_change) self.scanner_statue_flag = False # PLC未连接提示 self.plc_statue_timer = QTimer() self.plc_statue_timer.timeout.connect(self.plc_statue_change) self.plc_statue_flag = False # 初始化状态栏及时间栏相关类及变量初始化 # self.setWhatsThis("123456789") self.statuLable = QtWidgets.QLabel() # self.errLable = QtWidgets.QLabel() self.nowTimeLable = QtWidgets.QLabel() self.statuLable.setAlignment(Qt.AlignLeft) # self.errLable.setAlignment(Qt.AlignCenter) self.nowTimeLable.setAlignment(Qt.AlignRight) self.statusbar.addWidget(self.statuLable) # self.statusbar.addWidget(self.errLable) self.statusbar.addWidget(self.nowTimeLable) self.statusbar.setStyleSheet("QStatusBar::item{border: 0px}") self.statuLable.setText("就绪") # self.errLable.setStyleSheet("color:red;font:bold;font-size:12px") # self.errLable.setText("异常显示") nowtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) self.nowTimeLable.setText(str(nowtime)) self.nowTimeLable.setStyleSheet("color:blue;font-size:12px") self.statuLable.setStyleSheet("color:red;font-size:12px") # 用户及登陆信息栏初始化 self.textLable.setStyleSheet("color:blue;font:bold;font-size:14px") self.userLable.setStyleSheet("color:red;font:bold;font-size:14px") self.loadTimeLable2.setStyleSheet("color:red;font:bold;font-size:14px") # 设置设置信息为只读 self.machineID.setReadOnly(True) self.plantID.setReadOnly(True) self.processNo.setReadOnly(True) self.localityNo.setReadOnly(True) self.type.setReadOnly(True) self.loadTime.setReadOnly(True) self.classBox.setEnabled(False) # 初始化页码显示控件 self.curPageNoEdit.setMaximumSize(QSize(40, 20)) self.curPageNoEdit.setStyleSheet("color:blue;font:bold;font-size:14px") validator = QRegExpValidator(QRegExp("\d+")) self.curPageNoEdit.setValidator(validator) # 设置只能输入数字 self.curPageNoEdit.setText(str(self.curPage)) self.curPageNoEdit.setAlignment(Qt.AlignCenter) self.totalPageLable.setStyleSheet("color:blue;font:bold;font-size:14px") # 设置PLC和扫码枪连接状态 self.PlcConStatu.setText("PLC等待连接") self.ScanConStatu.setText("扫码枪等待连接") self.PlcConStatu.setStyleSheet("background:none;border:none;font:bold;font-size:12px;color:#FF8800") self.ScanConStatu.setStyleSheet("background:none;border:none;font:bold;font-size:12px;color:#FF8800") # 设置各类信号与槽 self.prevPageBtn.clicked.connect(self.onClickedPrevPageBtn) self.nextPageBtn.clicked.connect(self.onClickedNextPageBtn) self.curPageNoEdit.returnPressed.connect(self.onPressedCurPageNoEdit) self.setBtn.clicked.connect(self.onClickedSetBtn) self.changePwdBtn.clicked.connect(self.onClickedChangePwdBtn) self.refreshBtn.clicked.connect(self.onClickedRefreshBtn) self.refreshSelfBtn.clicked.connect(self.onClickedRefreshSelfBtn) # 设置显示列表 # self.showTable.setHorizontalHeaderLabels(["序号", "工字轮编号", "重量1", "称重时间1", "是否二次称重", "重量2", "称重时间2"]) self.mode = QStandardItemModel() self.mode.setRowCount(15) self.mode.setColumnCount(7) for i in range(0, 15): for j in range(0, 7): self.mode.setItem(i, j, QStandardItem("")) self.mode.setHorizontalHeaderLabels(["序号", "工字轮编号", "重量1", "称重时间1", "是否二次称重", "重量2", "称重时间2"]) self.showTable.setModel(self.mode) self.showTable.verticalHeader().setVisible(False) self.setTable() # 初始化登陆界面类 self.loginView = loginView() self.loginView.loginBtn.clicked.connect(self.onClickedLoginBtn) self.loginView.loginBtn.pressed.connect(self.onClickedLoginBtn) self.loginView.account.returnPressed.connect(self.onClickedLoginBtn) self.loginView.password.returnPressed.connect(self.onClickedLoginBtn) # 初始化修改密码界面类 self.changePwdView = changePwdView() self.changePwdView.changeBtn.clicked.connect(self.onClickedChangeBtn_c) self.changePwdView.changeBtn.pressed.connect(self.onClickedChangeBtn_c) self.changePwdView.oldPwd.returnPressed.connect(self.onClickedChangeBtn_c) self.changePwdView.newPwd1.returnPressed.connect(self.onClickedChangeBtn_c) self.changePwdView.newPwd2.returnPressed.connect(self.onClickedChangeBtn_c) self.logMsgView = logMsgView() def updateTimeShow(self): """ 系统时间显示程序 :return: """ nowtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) self.nowTimeLable.setText(str(nowtime)) def loginShow(self): """ 登陆界面显示 :return: """ self.log_msg(flag=self.INFO, msg_str="启动登陆程序") self.loginView.show() self.loginView.account.setText(self.account) self.loginView.password.setText(self.password) def changePwdShow(self): """ 修改密码界面显示 :return: """ self.changePwdView.show() if self.isAdmin == True: self.changePwdView.setWindowTitle("系统设置") else: self.changePwdView.setWindowTitle("修改密码") self.changePwdView.oldPwd.setText("") self.changePwdView.newPwd1.setText("") self.changePwdView.newPwd2.setText("") def mainWinShow(self): """ 主界面显示 :return: """ self.userLable.setText(self.account) nowtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) self.loadTimeLable2.setText(str(nowtime)) self.show() ret = self.getSpoolDate(pageNo=self.curPage) if ret == -1: return else: self.updateTable() ret = self.getTotalPage() if ret == -1: return else: self.totalPageLable.setText("/%d(共%d页)" % (self.totalPage, self.totalPage)) ret = self.updateOnlineDate() if ret == -1: return self.getMachineSetDate() if self.isAdmin == True: self.changePwdBtn.setText("系统设置") QMessageBox.information(self, "提示", "管理员账户验证成功! ", QMessageBox.Ok, QMessageBox.Ok) self.log_msg(flag=self.INFO, msg_str="管理员账户验证成功") self.T3.isStart = True self.T3.start() def verfiyAdmin(self): """ 确认登陆账号是否为管理员账号 :return: """ sqlStr = "SELECT * FROM adminuser WHERE uname = '%s'" % self.account try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_str="数据异常请重新再试", msg_tuple=e) return -1 result = self.cursor.fetchall() if len(result) > 0: self.isAdmin = True else: self.isAdmin = False return 0 def onClickedLoginBtn(self): """ 确认登陆处理 :return: """ self.account = self.loginView.account.text() self.password = self.loginView.password.text() if self.account == "" or self.password == "": QMessageBox.warning(self, "提示", "用户名或密码不能为空! ", QMessageBox.Ok, QMessageBox.Ok) return sqlstr = "SELECT * FROM login WHERE uname = '%s'" % self.account try: self.cursor.execute(sqlstr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) return result = self.cursor.fetchall() if len(result) == 0: QMessageBox.warning(self, "提示", "该用户名不存在! ", QMessageBox.Ok, QMessageBox.Ok) return s1 = sha1(self.password.encode("utf-8")) pwd = s1.hexdigest() if result[0][2] == pwd: self.loadTimeStr = str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) self.loginView.close() ret = self.verfiyAdmin() if ret == -1: return else: self.mainWinShow() self.log_msg(flag=self.INFO, msg_str="%s账号登陆成功" % self.account) else: QMessageBox.warning(self, "提示", "密码错误! ", QMessageBox.Ok, QMessageBox.Ok) def onClickedPrevPageBtn(self): """ 点击上一页处理 :return: """ self.log_msg(flag=self.INFO, msg_str="查看上一页") if self.curPage == 1: return elif self.curPage > 1: ret = self.getSpoolDate(pageNo=self.curPage - 1) if ret == 0: self.updateTable() self.curPage -= 1 self.curPageNoEdit.setText(str(self.curPage)) else: return def onClickedNextPageBtn(self): """ 点击下一页处理 :return: """ self.log_msg(flag=self.INFO, msg_str="查看下一页") self.getTotalPage() self.totalPageLable.setText("/%d(共%d页)" % (self.totalPage, self.totalPage)) if self.curPage == self.totalPage: return elif self.curPage < self.totalPage: ret = self.getSpoolDate(pageNo=self.curPage + 1) if ret == 0: self.updateTable() self.curPage += 1 self.curPageNoEdit.setText(str(self.curPage)) else: return def onPressedCurPageNoEdit(self): """ enter键当前页码框处理 :return: """ ret = self.getTotalPage() if ret == -1: return else: self.totalPageLable.setText("/%d(共%d页)" % (self.totalPage, self.totalPage)) pageNo = int(self.curPageNoEdit.text()) if pageNo == self.curPage: self.onClickedRefreshBtn() if pageNo < 1: pageNo = 1 elif pageNo <= self.totalPage: pageNo = pageNo else: pageNo = self.totalPage ret = self.getSpoolDate(pageNo=pageNo) if ret == 0: self.updateTable() self.curPage = pageNo self.curPageNoEdit.setText(str(self.curPage)) self.log_msg(flag=self.INFO, msg_str="查看第 %d 页" % self.curPage) def onClickedSetBtn(self): """ 处理点击设置按钮程序 :return: """ btnStr = self.setBtn.text() if btnStr == "编 辑": self.log_msg(flag=self.INFO, msg_str="编辑......") if self.isAdmin == True: self.machineID.setReadOnly(False) self.plantID.setReadOnly(False) self.processNo.setReadOnly(False) self.localityNo.setReadOnly(False) self.type.setReadOnly(False) self.classBox.setEnabled(True) else: self.classBox.setEnabled(True) self.setBtn.setText("保 存") self.changSetBoxColor("red") if btnStr == "保 存": if self.isAdmin == True: self.machineID.setReadOnly(True) self.plantID.setReadOnly(True) self.processNo.setReadOnly(True) self.localityNo.setReadOnly(True) self.type.setReadOnly(True) self.classBox.setEnabled(False) else: self.classBox.setEnabled(False) ret = self.updataMachineSetDate() if ret == 0: self.log_msg(flag=self.INFO, msg_str="保存成功") self.setBtn.setText("编 辑") self.changSetBoxColor("black") def onClickedChangePwdBtn(self): """ 点击系统设置按钮处理程序 :return: """ self.changePwdShow() self.hide() self.changePwdView.exec() self.show() def onClickedRefreshBtn(self): """ 点击刷新按钮处理程序 :return: """ ret = self.getSpoolDate(pageNo=self.curPage) if ret == -1: return self.updateTable() ret = self.getTotalPage() if ret == -1: return else: self.totalPageLable.setText("/%d(共%d页)" % (self.totalPage, self.totalPage)) self.setTable() self.log_msg(flag=self.INFO, msg_str="当前页刷新成功") def onClickedRefreshSelfBtn(self): """ 点击自动刷新按钮 :return: """ btnStr = self.refreshSelfBtn.text() if btnStr == "自动刷新": self.refreshSelfBtn.setText("停止刷新") self.Refresh_timer.start(1000) self.setBtn.setEnabled(False) self.refreshBtn.setEnabled(False) self.changePwdBtn.setEnabled(False) self.prevPageBtn.setEnabled(False) self.nextPageBtn.setEnabled(False) self.curPageNoEdit.setEnabled(False) if btnStr == "停止刷新": self.refreshSelfBtn.setText("自动刷新") self.Refresh_timer.stop() self.setBtn.setEnabled(True) self.refreshBtn.setEnabled(True) self.changePwdBtn.setEnabled(True) self.prevPageBtn.setEnabled(True) self.nextPageBtn.setEnabled(True) self.curPageNoEdit.setEnabled(True) self.log_msg(flag=self.INFO, msg_str="停止自动刷新") def onClickedChangeBtn_c(self): """ 点击确认修改程序 :return: """ oldPwd = self.changePwdView.oldPwd.text() newPwd1 = self.changePwdView.newPwd1.text() newPwd2 = self.changePwdView.newPwd2.text() if newPwd1 != newPwd2: if QMessageBox.warning(self, "提示", "两次输入的新密码不一致! ", QMessageBox.Ok, QMessageBox.Ok) == QMessageBox.Ok: self.changePwdView.oldPwd.setText("") self.changePwdView.newPwd1.setText("") self.changePwdView.newPwd2.setText("") return if len(newPwd1) < 6: if QMessageBox.warning(self, "提示", "密码不能少于6个字符! ", QMessageBox.Ok, QMessageBox.Ok) == QMessageBox.Ok: self.changePwdView.oldPwd.setText("") self.changePwdView.newPwd1.setText("") self.changePwdView.newPwd2.setText("") return if oldPwd != self.password: if QMessageBox.warning(self, "提示", "原始密码输入错误! ", QMessageBox.Ok, QMessageBox.Ok) == QMessageBox.Ok: self.changePwdView.oldPwd.setText("") self.changePwdView.newPwd1.setText("") self.changePwdView.newPwd2.setText("") return s1 = sha1(newPwd1.encode("utf-8")) newPwd1_s1 = s1.hexdigest() sqlStr1 = "UPDATE adminuser SET upwd = '%s' WHERE uname = '%s'" % (newPwd1_s1, self.account) sqlStr2 = "UPDATE login SET upwd = '%s' WHERE uname = '%s'" % (newPwd1_s1, self.account) sqlStr3 = "UPDATE lineuser SET upwd = '%s' WHERE uname = '%s'" % (newPwd1_s1, self.account) try: self.cursor.execute(sqlStr1) self.db.commit() except Exception as e1: self.log_msg(flag=self.ERROR, msg_str="修改密码异常(001)", msg_tuple=e1) self.db.rollback() return try: self.cursor.execute(sqlStr2) self.db.commit() except Exception as e2: self.log_msg(flag=self.ERROR, msg_str="修改密码异常(002)", msg_tuple=e2) self.db.rollback() return try: self.cursor.execute(sqlStr3) self.db.commit() except Exception as e3: self.log_msg(flag=self.ERROR, msg_str="修改密码异常(003)", msg_tuple=e3) self.db.rollback() return self.password = newPwd1 if QMessageBox.warning(self, "提示", "密码修改成功! ", QMessageBox.Ok, QMessageBox.Ok) == QMessageBox.Ok: self.log_msg(flag=self.INFO, msg_str="密码修改成功") self.changePwdView.close() def refreshSelf(self): """ 自动刷新显示列表 :return: """ ret = self.getSpoolDate(pageNo=self.curPage) if ret == -1: return self.updateTable() ret = self.getTotalPage() if ret == -1: return else: self.totalPageLable.setText("/%d(共%d页)" % (self.totalPage, self.totalPage)) self.log_msg(flag=self.INFO, msg_str="页面自动刷新中") def scanner_statu_change(self): """ 当扫码枪未连接是,闪烁来进行提醒 :return: """ if self.scanner_statue_flag: self.ScanConStatu.setText("扫描枪未连接") self.ScanConStatu.setStyleSheet("background:red;border:none;font:bold;font-size:12px") self.scanner_statue_flag = False else: self.ScanConStatu.setText("扫描枪未连接") self.ScanConStatu.setStyleSheet("background:none;border:none;font:bold;font-size:12px") self.scanner_statue_flag = True def plc_statue_change(self): if self.plc_statue_flag: self.PlcConStatu.setText("PLC未连接") self.PlcConStatu.setStyleSheet("background:red;border:none;font:bold;font-size:12px") self.plc_statue_flag = False else: self.PlcConStatu.setText("PLC未连接") self.PlcConStatu.setStyleSheet("background:none;border:none;font:bold;font-size:12px") self.plc_statue_flag = True def changSetBoxColor(self, color): """ 修改设置栏文字颜色 :param color: :return: """ if self.isAdmin == True: self.machineID.setStyleSheet("color:%s" % color) self.plantID.setStyleSheet("color:%s" % color) self.processNo.setStyleSheet("color:%s" % color) self.localityNo.setStyleSheet("color:%s" % color) self.type.setStyleSheet("color:%s" % color) self.classBox.setStyleSheet("color:%s" % color) def setTable(self): """ 设置列表 :return: """ size = self.showTable.size() self.showTable.setColumnWidth(0, size.width() / 12) self.showTable.setColumnWidth(1, size.width() / 6) self.showTable.setColumnWidth(2, size.width() / 6) self.showTable.setColumnWidth(3, size.width() / 6) self.showTable.setColumnWidth(4, size.width() / 12) self.showTable.setColumnWidth(5, size.width() / 6) self.showTable.setColumnWidth(6, size.width() / 6) height = self.showTable.horizontalHeader().height() for i in range(0, 15): self.showTable.setRowHeight(i, (size.height() - height) / 15) def updateTable(self): """ 更新列表 :return: """ for i in range(0, 15): for j in range(0, 7): self.mode.setData(self.mode.index(i, j), "") try: result = self.cursor.fetchall() for i in range(0, len(result)): for j in range(0, 7): if j == 0: self.mode.setData(self.mode.index(i, j), str(i + 1)) elif j == 4: if result[i][j] == 1: self.mode.setData(self.mode.index(i, j), "是") else: self.mode.setData(self.mode.index(i, j), "否") elif j == 2 or j == 5: self.mode.setData(self.mode.index(i, j), str(result[i][j])) else: self.mode.setData(self.mode.index(i, j), result[i][j]) self.setTable() except Exception as e: self.log_msg(flag=self.ERROR, msg_str="获取数据异常") gc.collect() def log_msg(self, flag, msg_str=None, msg_tuple=None): """ 打包日志信息 :param flag:信息级别 :param msg_str: 信息字符串 :param msg_tuple: 信息数组 :return: """ if flag == self.DEBUG: if msg_str: self.log.debug(msg_str) if msg_tuple: self.log.debug(msg_tuple) elif flag == self.INFO: if msg_str: self.log.info(msg_str) if msg_tuple: self.log.info(msg_tuple) elif flag == self.WARNING: if msg_str: self.log.warning(msg_str) if msg_tuple: self.log.warning(msg_tuple) elif flag == self.ERROR: if msg_str: self.log.error(msg_str) if msg_tuple: self.log.error(msg_tuple) elif flag == self.CRITICAL: if msg_str: self.log.critical(msg_str) if msg_tuple: self.log.critical(msg_tuple) msg = { "code": flag, "msgstr": msg_str, "msgtuple": msg_tuple } self.msg_append(msg) def msg_append(self, msg): """ 消息加入消息队列 :param msg:消息包 :return: """ # print(msg) self.mutex1.lock() self.msg_list.append(msg) self.mutex1.unlock() try: for i in self.msg_list: self.signal.set() time.sleep(0.01) except Exception as e: self.log_msg(flag=self.ERROR, msg_str="消息队列处理异常") def getSpoolDate(self, pageSize=15, pageNo=1): """ 获取工字轮数据,对应数据库gongzilun表 :param pageSize: :param pageNo: :return: """ minRow = (pageNo - 1) * pageSize count = pageSize sqlStr = "SELECT * FROM gongzilun ORDER BY id DESC LIMIT %d,%d" % (minRow, count) try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) return -1 return 0 def getTotalPage(self): """ 获取总页数 :return: """ sqlStr = "SELECT COUNT(*) FROM gongzilun" try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) return -1 else: result = self.cursor.fetchall() self.totalPage = math.ceil(result[0][0] / 15) return 0 def updateOnlineDate(self): """ 更新登录数据 :return: """ ret = self.clear_lineuser() if ret == -1: self.log_msg(flag=self.WARNING, msg_str="在线用户存在异常数据,未清理") s1 = sha1(self.password.encode("utf-8")) pwd = s1.hexdigest() sqlStr = "INSERT INTO lineuser (uname,upwd,denglushijian,runnormal)" \ " VALUES ('%s','%s','%s','%s')" % (self.account, pwd, self.loadTimeStr, "True") try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_str="更新在线账号信息异常", msg_tuple=e) self.db.rollback() return -1 return 0 def clear_lineuser(self): """ 用与清除在线用户表中的异常数据 :return: """ sqlStr = "DELETE FROM lineuser WHERE id > 0" # WHERE uname = 'admin' OR uname = 'user' try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) return -1 else: return 0 def getMachineSetDate(self): """ 获取设置信息 :return: """ sqlStr = "SELECT * FROM machine WHERE id = 1" try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) return result = self.cursor.fetchall() self.machineID.setText(result[0][1]) self.plantID.setText(result[0][2]) self.processNo.setText(result[0][3]) self.localityNo.setText(result[0][4]) self.type.setText(result[0][5]) classNo = result[0][6] self.classBox.setCurrentIndex(int(classNo)) self.loadTime.setText(self.loadTimeStr) def updataMachineSetDate(self): """ 更新设置信息 :return: """ classNo = self.classBox.currentIndex() if self.isAdmin == True: machineID = self.machineID.text() plantID = self.plantID.text() processNo = self.processNo.text() localityNo = self.localityNo.text() type = self.type.text() sqlStr = "UPDATE machine SET shebeiid = '%s',gongchangid = '%s',gongxuid= '%s', \ caijidianid = '%s',caijidiantype = '%s',banci = '%s' WHERE id = 1" \ % (machineID, plantID, processNo, localityNo, type, str(classNo)) if self.isAdmin == False: sqlStr = "UPDATE machine SET banci = '%s' WHERE id = 1" % str(classNo) try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) self.db.rollback() return -1 return 0 def mouseDoubleClickEvent(self, *args, **kwargs): """ 判断鼠标双击位置是窗口状态栏上 :param args: :param kwargs: :return: """ statu_lable_rect = self.statuLable.rect() statu_lable_width = statu_lable_rect.width() statu_lable_height = statu_lable_rect.height() statuLable_pos = self.statuLable.mapToGlobal(QPoint(0, 0)) mouse_pos = args[0].globalPos() if statuLable_pos.x() <= mouse_pos.x() < statuLable_pos.x() + statu_lable_width and statuLable_pos.y() < mouse_pos.y() < statuLable_pos.y() + statu_lable_height: print("双击状态栏") def resizeEvent(self, *args, **kwargs): """ 自动调整页面 :param args: :param kwargs: :return: """ try: oldSize = args[0].oldSize() nowSize = args[0].size() self.statuLable.setMinimumSize(nowSize.width() / 2 - 10, 12) self.nowTimeLable.setMinimumSize(nowSize.width() / 2 - 10, 12) except Exception as e: self.log_msg(flag=self.ERROR, msg_tuple=e) if oldSize != QSize(-1, -1): try: self.layoutWidget.setGeometry(QRect(0, 10, nowSize.width() - 12, nowSize.height() - 38)) self.setTable() except Exception as e2: self.log_msg(flag=self.ERROR, msg_str="窗口大小变动异常", msg_tuple=e2) def closeEvent(self, *args, **kwargs): """ 程序退出事件 :param args: :param kwargs: :return: """ if QMessageBox.warning(self, "提示", "确定要退出程序吗? ", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes: sqlStr = "DELETE FROM lineuser WHERE denglushijian = '%s'" % self.loadTimeStr try: self.cursor.execute(sqlStr) self.db.commit() except Exception as e: self.log_msg(flag=self.ERROR, msg_str="程序退出,清除用户信息异常", msg_tuple=e) return self.log_msg(flag=self.INFO, msg_str="程序退出") time.sleep(0.5) self.cursor.close() self.db.close() self.T1.isStart = False self.T1.quit() self.T1.wait() args[0].accept() else: args[0].ignore() def err_msg_work(self, msg): if msg["code"] == 10: # 连接扫码枪成功 # QMessageBox.warning(self, "提示", msg["msgstr"], QMessageBox.Yes, QMessageBox.Yes) self.ScanConStatu.setText("扫描枪已连接") self.ScanConStatu.setStyleSheet("background:#00DD00;border:none;font:bold;font-size:12px") self.scanner_statue_timer.stop() if msg["code"] == 11: # 扫码枪未连接 self.ScanConStatu.setText("扫描枪未连接") self.ScanConStatu.setStyleSheet("background:red;border:none;font:bold;font-size:12px") self.scanner_statue_timer.start(1000) if msg["code"] == 20: # PLC连接成功 self.PlcConStatu.setText("PLC已连接") self.PlcConStatu.setStyleSheet("background:#00DD00;border:none;font:bold;font-size:12px") self.plc_statue_timer.stop() if msg["code"] == 21: # PLC未连接 self.PlcConStatu.setText("PLC未连接") self.PlcConStatu.setStyleSheet("background:red;border:none;font:bold;font-size:12px") self.plc_statue_timer.start(1000) if msg["code"] == 22: # 与PLC连接异常断开 self.PlcConStatu.setText("PLC未连接") self.PlcConStatu.setStyleSheet("background:red;border:none;font:bold;font-size:12px") self.plc_statue_timer.start(1000) def run(self, *args, **kwargs): self.loginShow() self.q = args[0] self.q_err = args[1] self.T1 = get_msg_from_sys_thread(self) self.T2 = set_status_msg_thread(self) self.T3 = get_err_msg_from_sys_thread(self, self.q_err) self.T3.signal.connect(self.err_msg_work) self.T2.start() self.T1.isStart = True self.T1.start()
class ReservationSystem(QWidget): global currentYear, currentMonth, currentDay currentDay = datetime.now().day currentMonth = datetime.now().month currentYear = datetime.now().year dic = { 'teeth check up': ['Kaisa', 'Teemu', 'Inka'], 'teeth removal': ['Kaisa', 'Teemu', 'Inka'], 'teeth whitening': ['Kaisa', 'Teemu', 'Inka'], 'consultation': ['Kaisa', 'Inka'], 'implant': ['Inka'] } service_time = { 'teeth check up': 25, 'teeth removal': 25, 'teeth whitening': 25, 'consultation': 20, 'implant': 55 } def __init__(self): super().__init__() self.setWindowTitle('Reservation System') self.setGeometry(300, 200, 1000, 800) self.model = QStandardItemModel() # Calendar self.calendar = QtWidgets.QCalendarWidget(self) self.calendar.setGeometry(20, 250, 460, 330) self.init_calendar() # menu bar self.menubar = QtWidgets.QMenuBar(self) # self.menubar.setGeometry(0, 0, 600, 10) self.menuOther_services = QtWidgets.QMenu(self.menubar) self.statusbar = QtWidgets.QStatusBar(self) self.actionCheck_history = QtWidgets.QAction(self) self.actionCheck_history.setText("Get booking records") self.menuOther_services.addAction(self.actionCheck_history) self.actionCancellation = QtWidgets.QAction(self) self.actionCancellation.setText("Cancellation") self.menuOther_services.addAction(self.actionCancellation) self.menuOther_services.setTitle("Other services") self.menubar.addAction(self.menuOther_services.menuAction()) self.actionCheck_history.triggered.connect(self.history_window) self.actionCancellation.triggered.connect(self.cancellation_window) # Name self.label1 = QtWidgets.QLabel(self) self.label1.setText("Name") self.label1.setGeometry(20, 50, 200, 20) self.name = QtWidgets.QLineEdit(self) self.name.setGeometry(20, 70, 200, 20) self.name.setPlaceholderText("Enter Your Name") # Email self.label2 = QtWidgets.QLabel(self) self.label2.setText("Email") self.label2.setGeometry(260, 50, 200, 20) self.email = QtWidgets.QLineEdit(self) self.email.setGeometry(260, 70, 200, 20) self.email.setPlaceholderText("Enter your Email") # Phone self.label3 = QtWidgets.QLabel(self) self.label3.setText("Phone") self.label3.setGeometry(500, 50, 200, 20) self.phone = QtWidgets.QLineEdit(self) self.phone.setGeometry(500, 70, 200, 20) self.phone.setPlaceholderText("Phone number starting with 0") # Select Service self.label4 = QtWidgets.QLabel(self) self.label4.setText("Select Service") self.label4.setGeometry(20, 115, 200, 20) self.service = QtWidgets.QComboBox(self) self.service.setGeometry(20, 145, 200, 30) self.service.setModel(self.model) # label text 1 self.label5 = QtWidgets.QLabel(self) self.label5.setText( "Click on the date and available slots will shown on the right=>\nALWAYS click on the date to REFRESH the " "available slots!") self.label5.setGeometry(20, 200, 500, 40) # Select Doctor self.label5 = QtWidgets.QLabel(self) self.label5.setText("Select Doctor") self.label5.setGeometry(260, 115, 200, 20) self.doctor = QtWidgets.QComboBox(self) self.doctor.setGeometry(260, 145, 200, 30) self.doctor.setModel(self.model) # update combobox self.update_combobox() # time list self.listWidget = QtWidgets.QListWidget(self) self.listWidget.setGeometry(520, 180, 200, 400) # label text 2 self.label6 = QtWidgets.QLabel(self) self.label6.setText("Pick a time below") self.label6.setGeometry(515, 140, 180, 20) # Button and checkbox self.pushButton = QtWidgets.QPushButton(self) self.pushButton.setGeometry(240, 660, 80, 30) self.pushButton.setText("Reserve") self.checkBox = QtWidgets.QCheckBox(self) self.checkBox.setGeometry(50, 615, 600, 50) self.checkBox.setText( "I confirm all information are correct and I want to reserve this time" ) # Reserve time self.pushButton.clicked.connect(self.reserve) # reminder label in red color self.label7 = QtWidgets.QLabel(self) self.label7.setGeometry(100, 700, 500, 30) # New window after reservation self.window = QtWidgets.QMainWindow() self.window.resize(550, 300) self.window.setWindowTitle("Your booking is complete!") self.window.label = QtWidgets.QLabel(self.window) self.window.label.setGeometry(55, 30, 450, 200) self.show() # New window for history self.window2 = QtWidgets.QMainWindow() self.window2.resize(700, 600) self.window2.setWindowTitle("Get booking records") self.window2.label = QtWidgets.QLabel(self.window2) self.window2.label.setGeometry(20, 10, 650, 40) self.window2.label.setText( "Please enter your information to check booking records.\nRecords will be returned " "only if name and phone are matched with the records") # Name 2 self.window2.label1 = QtWidgets.QLabel(self.window2) self.window2.label1.setText("Name") self.window2.label1.setGeometry(20, 70, 150, 20) self.window2.name = QtWidgets.QLineEdit(self.window2) self.window2.name.setGeometry(20, 90, 150, 20) self.window2.name.setPlaceholderText("Enter Your Name") # Phone 2 self.window2.label3 = QtWidgets.QLabel(self.window2) self.window2.label3.setText("Phone") self.window2.label3.setGeometry(200, 70, 150, 20) self.window2.phone = QtWidgets.QLineEdit(self.window2) self.window2.phone.setGeometry(200, 90, 150, 20) self.window2.phone.setPlaceholderText("Phone number") # Button and checkbox self.window2.pushButton = QtWidgets.QPushButton(self.window2) self.window2.pushButton.setGeometry(380, 80, 150, 30) self.window2.pushButton.setText("Get records") # qtableview self.window2.tableWidget = QtWidgets.QTableWidget(self.window2) self.window2.tableWidget.setGeometry(10, 140, 500, 400) self.window2.labeln = QtWidgets.QLabel(self.window2) self.window2.pushButton.clicked.connect(self.display_history) # New window if want cancellation self.window3 = QtWidgets.QMainWindow() self.window3.resize(960, 600) self.window3.setWindowTitle("cancellation") self.window3.label = QtWidgets.QLabel(self.window3) self.window3.label.setGeometry(15, 10, 550, 20) self.window3.label.setText( "Please enter your information for cancellation.") self.window3.label2 = QtWidgets.QLabel(self.window3) self.window3.label2.setGeometry(15, 25, 550, 20) self.window3.label2.setStyleSheet("color: red") self.window3.label2.setText( "Please note for cancellation within 24 hours, you will be charged 40€!" ) self.window3.label3 = QtWidgets.QLabel(self.window3) self.window3.label3.setGeometry(600, 20, 550, 100) self.window3.label3.setText( "Select the time you would like\n to cancel by checking the 'Cancel' box.\nOnce the " "below button is clicked, \nyour cancellation request will be handled" ) # Name self.window3.label1 = QtWidgets.QLabel(self.window3) self.window3.label1.setText("Name") self.window3.label1.setGeometry(20, 70, 150, 20) self.window3.name = QtWidgets.QLineEdit(self.window3) self.window3.name.setGeometry(20, 90, 150, 20) self.window3.name.setPlaceholderText("Enter Your Name") # Phone self.window3.label3 = QtWidgets.QLabel(self.window3) self.window3.label3.setText("Phone") self.window3.label3.setGeometry(200, 70, 150, 20) self.window3.phone = QtWidgets.QLineEdit(self.window3) self.window3.phone.setGeometry(200, 90, 150, 20) self.window3.phone.setPlaceholderText("Phone number") # Button self.window3.pushButton = QtWidgets.QPushButton(self.window3) self.window3.pushButton.setGeometry(380, 80, 120, 30) self.window3.pushButton.setText("Search/Refresh") # qtableview self.window3.tableWidget = QtWidgets.QTableWidget(self.window3) self.window3.tableWidget.setGeometry(5, 140, 600, 400) self.window3.labeln = QtWidgets.QLabel(self.window3) # cancellation button self.window3.cancel = QtWidgets.QPushButton(self.window3) self.window3.cancel.setGeometry(640, 150, 150, 30) self.window3.cancel.setText("Confirm Cancel") # Cancelation confirmation text self.window3.label4 = QtWidgets.QLabel(self.window3) self.window3.label4.setGeometry(620, 190, 350, 60) self.window3.pushButton.clicked.connect(self.cancellation) self.window3.cancel.clicked.connect(self.cancellation_click) def history_window(self): self.window2.labeln.clear() self.window2.name.clear() self.window2.phone.clear() self.window2.tableWidget.clear() self.window2.show() def cancellation_window(self): self.window3.name.clear() self.window3.phone.clear() self.window3.labeln.clear() self.window3.label4.clear() self.window3.tableWidget.clear() self.window3.show() def cancellation_click(self): name = self.window3.name.text() phone = "'" + self.window3.phone.text() c = Customer(name, phone) for i in range(self.window3.tableWidget.rowCount()): item = self.window3.tableWidget.item( i, self.window3.tableWidget.columnCount() - 1) if item.checkState() != 0: date = self.window3.tableWidget.item(item.row(), 0) time = self.window3.tableWidget.item(item.row(), 1) doctor = self.window3.tableWidget.item(item.row(), 2) service = self.window3.tableWidget.item(item.row(), 3) txt = c.cancel(date.text(), time.text(), service.text(), doctor.text()) self.window3.label4.setText( txt + '\nhit search/refresh to refresh booking records!') def display_history(self): self.window2.tableWidget.clear() name = self.window2.name.text() phone = "'" + self.window2.phone.text() df = Customer.get_booked(name, phone) if isinstance(df, pd.DataFrame): self.window2.labeln.clear() df = df[[ 'Reserved date', 'Reserved time', 'Reserved doctor', 'Reserved service' ]].drop_duplicates() df = df.sort_values(['Reserved date', 'Reserved time'], ascending=[True, True]) self.window2.tableWidget.setRowCount(df.shape[0]) self.window2.tableWidget.setColumnCount(df.shape[1]) for i in range(df.shape[0]): for j in range(df.shape[1]): item = QtWidgets.QTableWidgetItem(str(df.iloc[i, j])) self.window2.tableWidget.setItem(i, j, item) self.window2.tableWidget.setHorizontalHeaderLabels( df.columns.tolist()) else: self.window2.labeln.setText( "Record not found! Please input valid name and phone!") self.window2.labeln.setStyleSheet("color: red") self.window2.labeln.setGeometry(40, 114, 400, 20) def cancellation(self): self.window3.labeln.clear() self.window3.tableWidget.clear() self.window3.label4.clear() name = self.window3.name.text() phone = "'" + self.window3.phone.text() df = Customer.get_future_events(name, phone) if isinstance(df, pd.DataFrame): self.window3.labeln.clear() df = df[[ 'Reserved date', 'Reserved time', 'Reserved doctor', 'Reserved service' ]].drop_duplicates() df = df.sort_values(['Reserved date', 'Reserved time'], ascending=[True, True]) self.window3.tableWidget.setRowCount(df.shape[0]) self.window3.tableWidget.setColumnCount(df.shape[1]) for i in range(df.shape[0]): for j in range(df.shape[1]): item = QtWidgets.QTableWidgetItem(str(df.iloc[i, j])) self.window3.tableWidget.setItem(i, j, item) # add one column for checkbox self.window3.tableWidget.insertColumn(df.shape[1]) for i in range(df.shape[0]): chkBoxItem = QtWidgets.QTableWidgetItem() chkBoxItem.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) chkBoxItem.setCheckState(QtCore.Qt.Unchecked) self.window3.tableWidget.setItem(i, df.shape[1], chkBoxItem) self.window3.tableWidget.setHorizontalHeaderLabels( df.columns.tolist() + ['Cancel']) else: self.window3.labeln.setText("There is no upcoming bookings!") self.window3.labeln.setStyleSheet("color: red") self.window3.labeln.setGeometry(40, 114, 400, 20) @staticmethod def input_checkup(name, email, phone): if all([substring in email for substring in ['.', '@']]) and any( x.isalpha() for x in name) and phone[1:].isnumeric(): return True def reserve(self): if self.checkBox.isChecked(): self.label7.clear() name = self.name.text() email = self.email.text() phone = "'" + self.phone.text() service = self.service.currentText() doctor = self.doctor.currentText() date = '{2}-{0}-{1}'.format(self.calendar.selectedDate().month(), self.calendar.selectedDate().day(), self.calendar.selectedDate().year()) item = self.listWidget.currentItem() if name is not None and email is not None and phone is not None and self.input_checkup( name, email, phone): if item is not None: time = item.text() c = Customer(name, phone, email) a = c.reserve(date, time, service, doctor) if a is None: # self.close() self.window.label.clear() self.window.label.setText( f"{service}:\n{time} on {date} \nwith doctor {doctor} is confirmed!\nThank you!:)" ) font = QFont() font.setPointSize(16) self.window.label.setFont(font) self.window.show() else: txt = a + ' Please choose a new time!' self.label7.setText(a) else: self.label7.setText( 'Please select a date and time for booking!') self.label7.setStyleSheet("color: red") else: self.label7.setText( 'Some information is not correct or missing!') self.label7.setStyleSheet("color: red") else: self.label7.setText( "Please confirm your booking by checking the checkbox!") self.label7.setStyleSheet("color: red") def update_combobox(self): for k, v in self.dic.items(): service = QStandardItem(k) self.model.appendRow(service) for value in v: doctor = QStandardItem(value) service.appendRow(doctor) self.service.currentIndexChanged.connect(self.update_service) self.update_service(0) def update_service(self, index): index = self.model.index(index, 0, self.service.rootModelIndex()) self.doctor.setRootModelIndex(index) self.doctor.setCurrentIndex(0) def init_calendar(self): self.calendar.setGridVisible(True) self.calendar.setMinimumDate( QDate(currentYear, currentMonth, currentDay)) self.calendar.setMaximumDate( QDate(currentYear, currentMonth + 1, calendar.monthrange(currentYear, currentMonth)[1])) self.calendar.setSelectedDate(QDate(currentYear, currentMonth, 1)) self.calendar.clicked.connect(self.get_time) def get_time(self, QDate): doctor_name = self.doctor.currentText() service_name = self.service.currentText() duration = self.service_time[service_name] a = Doctor(doctor_name) date = '{2}-{0}-{1}'.format(QDate.month(), QDate.day(), QDate.year()) self.listWidget.clear() if pd.to_datetime(date).weekday() < 5: if pd.to_datetime(date) > datetime.today(): for i in a.show_available_slots(date, service_name): time = (datetime.strptime(i, '%H:%M') + timedelta(minutes=duration)) end_time = datetime.strftime(time, '%H:%M') item = i + ' - ' + end_time self.listWidget.addItem(item) else: x = [ datetime.strptime(i, '%H:%M') for i in a.show_available_slots(date, service_name) ] x = [j for j in x if datetime.now().time() < j.time()] x = [datetime.strftime(i, '%H:%M') for i in x] for i in x: time = (datetime.strptime(i, '%H:%M') + timedelta(minutes=duration)) end_time = datetime.strftime(time, '%H:%M') item = i + ' - ' + end_time self.listWidget.addItem(item)
class MainWindow(QMainWindow): def __init__(self,system): super(MainWindow, self).__init__() self.system = system fileMenu = QMenu("&Menu", self) dbinitAction = fileMenu.addAction("사용자 정보 초기화") quitAction = fileMenu.addAction("E&xit") quitAction.setShortcut("Ctrl+Q") self.menuBar().addMenu(fileMenu) self.statusBar() dbinitAction.triggered.connect(self.ClickAction_dbinit) quitAction.triggered.connect(QApplication.instance().quit) self.setupModel() self.setupViews() self.readDB() self.setWindowTitle("PyStudy 학습진도창") self.resize(870, 550) def setupModel(self): self.model = QStandardItemModel(3, 2, self) self.model.setHeaderData(0, Qt.Horizontal, "목록") self.model.setHeaderData(1, Qt.Horizontal, "읽기여부") self.model2 = QStandardItemModel(3, 2, self) self.model2.setHeaderData(0, Qt.Horizontal, "학습여부") self.model2.setHeaderData(1, Qt.Horizontal, "개수") def setupViews(self): splitter = QSplitter() self.table = QTableView() self.pieChart = PieView() splitter.addWidget(self.pieChart) splitter.addWidget(self.table) splitter.setStretchFactor(0, 0) splitter.setStretchFactor(1, 0) self.table.setModel(self.model) self.pieChart.setModel(self.model2) self.selectionModel = QItemSelectionModel(self.model2) self.table.setSelectionModel(self.selectionModel) #self.pieChart.setSelectionModel(self.selectionModel) #table.setColumnWidth(0,100) self.setCentralWidget(splitter) self.table.doubleClicked.connect(self.ClickAction_table) def readDB(self): con = sqlite3.connect("mystudy.db") cur = con.cursor() cur.execute("select subject, readcheck from study;") self.model.removeRows(0, self.model.rowCount(QModelIndex()), QModelIndex()) self.model2.removeRows(0, self.model2.rowCount(QModelIndex()), QModelIndex()) row = 0 for line in cur: if line[1] ==1: result = "○" else: result = "X" self.model.insertRows(row, 1, QModelIndex()) self.model.setData(self.model.index(row, 0, QModelIndex()), line[0]) self.model.setData(self.model.index(row, 1, QModelIndex()),result) self.model.setData(self.model.index(row, 1, QModelIndex()), QVariant(Qt.AlignCenter),Qt.TextAlignmentRole) row += 1 cur.execute("select count() from study ;") for line in cur: self.studyTotal =line[0] cur.execute("select count() from study where readcheck=1;") for line in cur: self.studyRead =line[0] #print("총 개수 " ,self.studyTotal ," 학습한개수", self.studyRead ) con.close() row=0 self.model2.insertRows(row, 1, QModelIndex()) self.model2.setData(self.model2.index(row, 0, QModelIndex()),"학습") self.model2.setData(self.model2.index(row, 1, QModelIndex()), float(self.studyRead)) self.model2.setData(self.model2.index(row, 0, QModelIndex()), QColor("#99e600"), Qt.DecorationRole) row=1 self.model2.insertRows(row, 1, QModelIndex()) self.model2.setData(self.model2.index(row, 0, QModelIndex()),"미학습") self.model2.setData(self.model2.index(row, 1, QModelIndex()), float(self.studyTotal-self.studyRead)) self.model2.setData(self.model2.index(row, 0, QModelIndex()), QColor("#8080b3"), Qt.DecorationRole) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.table.setDragEnabled(False) self.table.horizontalHeader().setStretchLastSection(True) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.resizeRowsToContents() self.table.resizeColumnsToContents() self.table.setColumnWidth(0,350) #self.statusBar().showMessage("Loaded %s" % path, 2000) def ClickAction_table(self,index): #self.system #index.data() #self.table.selectedIndexes()[0].data() tempstr = self.table.selectedIndexes()[0].data().split() filepath = r"PyStudy_web\\example\\기본예제\\"+tempstr[0]+".html" selectedRowKey = self.table.selectedIndexes()[0].row()+1#mysql 테이블 줄수 차이 #print("click test ",selectedRowKey ) con = sqlite3.connect("mystudy.db") cur = con.cursor() cur.execute("update 'study' set 'readcheck'=1 where key="+str(selectedRowKey)+";") con.commit() con.close() self.setupViews() self.readDB() self.system.sendMessage("/학습창 열기 "+filepath) def ClickAction_dbinit(self,index): con = sqlite3.connect("mystudy.db") cur = con.cursor() cur.execute("update 'study' set 'readcheck'=0 ;") con.commit() con.close() self.setupViews() self.readDB()
class MainWindow(QMainWindow, Ui_MainWindow): dictChanged = pyqtSignal(str) # Tab indexes TabInfos = 0 TabSummary = 1 TabPersos = 2 TabPlots = 3 TabWorld = 4 TabOutline = 5 TabRedac = 6 def __init__(self): QMainWindow.__init__(self) self.setupUi(self) self.currentProject = None self.readSettings() # UI self.setupMoreUi() # Welcome self.welcome.updateValues() # self.welcome.btnCreate.clicked.connect self.stack.setCurrentIndex(0) # Word count self.mprWordCount = QSignalMapper(self) for t, i in [ (self.txtSummarySentence, 0), (self.txtSummaryPara, 1), (self.txtSummaryPage, 2), (self.txtSummaryFull, 3) ]: t.textChanged.connect(self.mprWordCount.map) self.mprWordCount.setMapping(t, i) self.mprWordCount.mapped.connect(self.wordCount) # Snowflake Method Cycle self.mapperCycle = QSignalMapper(self) for t, i in [ (self.btnStepTwo, 0), (self.btnStepThree, 1), (self.btnStepFour, 2), (self.btnStepFive, 3), (self.btnStepSix, 4), (self.btnStepSeven, 5), (self.btnStepEight, 6) ]: t.clicked.connect(self.mapperCycle.map) self.mapperCycle.setMapping(t, i) self.mapperCycle.mapped.connect(self.clickCycle) self.cmbSummary.currentIndexChanged.connect(self.summaryPageChanged) self.cmbSummary.setCurrentIndex(0) self.cmbSummary.currentIndexChanged.emit(0) # Main Menu for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuMode, self.menuView, self.menuTools, self.menuHelp]: i.setEnabled(False) self.actOpen.triggered.connect(self.welcome.openFile) self.actSave.triggered.connect(self.saveDatas) self.actSaveAs.triggered.connect(self.welcome.saveAsFile) self.actCompile.triggered.connect(self.doCompile) self.actLabels.triggered.connect(self.settingsLabel) self.actStatus.triggered.connect(self.settingsStatus) self.actSettings.triggered.connect(self.settingsWindow) self.actCloseProject.triggered.connect(self.closeProject) self.actQuit.triggered.connect(self.close) self.actToolFrequency.triggered.connect(self.frequencyAnalyzer) self.generateViewMenu() self.makeUIConnections() # self.loadProject(os.path.join(appPath(), "test_project.zip")) ############################################################################### # SUMMARY ############################################################################### def summaryPageChanged(self, index): fractalButtons = [ self.btnStepTwo, self.btnStepThree, self.btnStepFive, self.btnStepSeven, ] for b in fractalButtons: b.setVisible(fractalButtons.index(b) == index) ############################################################################### # OUTLINE ############################################################################### def outlineRemoveItemsRedac(self): self.treeRedacOutline.delete() def outlineRemoveItemsOutline(self): self.treeOutlineOutline.delete() ############################################################################### # PERSOS ############################################################################### def changeCurrentPerso(self, trash=None): index = self.lstPersos.currentPersoIndex() if not index.isValid(): self.tabPlot.setEnabled(False) return self.tabPersos.setEnabled(True) for w in [ self.txtPersoName, self.sldPersoImportance, self.txtPersoMotivation, self.txtPersoGoal, self.txtPersoConflict, self.txtPersoEpiphany, self.txtPersoSummarySentence, self.txtPersoSummaryPara, self.txtPersoSummaryFull, self.txtPersoNotes, ]: w.setCurrentModelIndex(index) # Button color self.mdlPersos.updatePersoColor(index) # Perso Infos self.tblPersoInfos.setRootIndex(index) if self.mdlPersos.rowCount(index): self.updatePersoInfoView() def updatePersoInfoView(self): # Hide columns for i in range(self.mdlPersos.columnCount()): self.tblPersoInfos.hideColumn(i) self.tblPersoInfos.showColumn(Perso.infoName.value) self.tblPersoInfos.showColumn(Perso.infoData.value) self.tblPersoInfos.horizontalHeader().setSectionResizeMode( Perso.infoName.value, QHeaderView.ResizeToContents) self.tblPersoInfos.horizontalHeader().setSectionResizeMode( Perso.infoData.value, QHeaderView.Stretch) self.tblPersoInfos.verticalHeader().hide() ############################################################################### # PLOTS ############################################################################### def changeCurrentPlot(self): index = self.lstPlots.currentPlotIndex() if not index.isValid(): self.tabPlot.setEnabled(False) return self.tabPlot.setEnabled(True) self.txtPlotName.setCurrentModelIndex(index) self.txtPlotDescription.setCurrentModelIndex(index) self.txtPlotResult.setCurrentModelIndex(index) self.sldPlotImportance.setCurrentModelIndex(index) self.lstPlotPerso.setRootIndex(index.sibling(index.row(), Plot.persos.value)) subplotindex = index.sibling(index.row(), Plot.subplots.value) self.lstSubPlots.setRootIndex(subplotindex) if self.mdlPlots.rowCount(subplotindex): self.updateSubPlotView() # self.txtSubPlotSummary.setCurrentModelIndex(QModelIndex()) self.txtSubPlotSummary.setEnabled(False) self._updatingSubPlot = True self.txtSubPlotSummary.setPlainText("") self._updatingSubPlot = False self.lstPlotPerso.selectionModel().clear() def updateSubPlotView(self): # Hide columns for i in range(self.mdlPlots.columnCount()): self.lstSubPlots.hideColumn(i) self.lstSubPlots.showColumn(Subplot.name.value) self.lstSubPlots.showColumn(Subplot.meta.value) self.lstSubPlots.horizontalHeader().setSectionResizeMode( Subplot.name.value, QHeaderView.Stretch) self.lstSubPlots.horizontalHeader().setSectionResizeMode( Subplot.meta.value, QHeaderView.ResizeToContents) self.lstSubPlots.verticalHeader().hide() def changeCurrentSubPlot(self, index): # Got segfaults when using textEditView model system, so ad hoc stuff. index = index.sibling(index.row(), Subplot.summary.value) item = self.mdlPlots.itemFromIndex(index) if not item: self.txtSubPlotSummary.setEnabled(False) return self.txtSubPlotSummary.setEnabled(True) txt = item.text() self._updatingSubPlot = True self.txtSubPlotSummary.setPlainText(txt) self._updatingSubPlot = False def updateSubPlotSummary(self): if self._updatingSubPlot: return index = self.lstSubPlots.currentIndex() if not index.isValid(): return index = index.sibling(index.row(), Subplot.summary.value) item = self.mdlPlots.itemFromIndex(index) self._updatingSubPlot = True item.setText(self.txtSubPlotSummary.toPlainText()) self._updatingSubPlot = False def plotPersoSelectionChanged(self): "Enables or disables remove plot perso button." self.btnRmPlotPerso.setEnabled( len(self.lstPlotPerso.selectedIndexes()) != 0) ############################################################################### # WORLD ############################################################################### def changeCurrentWorld(self): index = self.mdlWorld.selectedIndex() if not index.isValid(): self.tabWorld.setEnabled(False) return self.tabWorld.setEnabled(True) self.txtWorldName.setCurrentModelIndex(index) self.txtWorldDescription.setCurrentModelIndex(index) self.txtWorldPassion.setCurrentModelIndex(index) self.txtWorldConflict.setCurrentModelIndex(index) ############################################################################### # LOAD AND SAVE ############################################################################### def loadProject(self, project, loadFromFile=True): """Loads the project ``project``. If ``loadFromFile`` is False, then it does not load datas from file. It assumes that the datas have been populated in a different way.""" if loadFromFile and not os.path.exists(project): print(self.tr("The file {} does not exist. Try again.").format(project)) self.statusBar().showMessage( self.tr("The file {} does not exist. Try again.").format(project), 5000) return if loadFromFile: # Load empty settings imp.reload(settings) # Load data self.loadEmptyDatas() self.loadDatas(project) self.makeConnections() # Load settings for i in settings.openIndexes: idx = self.mdlOutline.indexFromPath(i) self.mainEditor.setCurrentModelIndex(idx, newTab=True) self.generateViewMenu() self.mainEditor.sldCorkSizeFactor.setValue(settings.corkSizeFactor) self.actSpellcheck.setChecked(settings.spellcheck) self.toggleSpellcheck(settings.spellcheck) self.updateMenuDict() self.setDictionary() self.mainEditor.setFolderView(settings.folderView) self.mainEditor.updateFolderViewButtons(settings.folderView) self.tabMain.setCurrentIndex(settings.lastTab) # We force to emit even if it opens on the current tab self.tabMain.currentChanged.emit(settings.lastTab) self.mainEditor.updateCorkBackground() # Set autosave self.saveTimer = QTimer() self.saveTimer.setInterval(settings.autoSaveDelay * 60 * 1000) self.saveTimer.setSingleShot(False) self.saveTimer.timeout.connect(self.saveDatas) if settings.autoSave: self.saveTimer.start() # Set autosave if no changes self.saveTimerNoChanges = QTimer() self.saveTimerNoChanges.setInterval(settings.autoSaveNoChangesDelay * 1000) self.saveTimerNoChanges.setSingleShot(True) self.mdlFlatData.dataChanged.connect(self.startTimerNoChanges) self.mdlOutline.dataChanged.connect(self.startTimerNoChanges) self.mdlPersos.dataChanged.connect(self.startTimerNoChanges) self.mdlPlots.dataChanged.connect(self.startTimerNoChanges) self.mdlWorld.dataChanged.connect(self.startTimerNoChanges) # self.mdlPersosInfos.dataChanged.connect(self.startTimerNoChanges) self.mdlStatus.dataChanged.connect(self.startTimerNoChanges) self.mdlLabels.dataChanged.connect(self.startTimerNoChanges) self.saveTimerNoChanges.timeout.connect(self.saveDatas) self.saveTimerNoChanges.stop() # UI for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuMode, self.menuView, self.menuTools, self.menuHelp]: i.setEnabled(True) # FIXME: set Window's name: project name # Stuff # self.checkPersosID() # Should'n be necessary any longer self.currentProject = project QSettings().setValue("lastProject", project) # Show main Window self.stack.setCurrentIndex(1) def closeProject(self): # Save datas self.saveDatas() self.currentProject = None QSettings().setValue("lastProject", "") # FIXME: close all opened tabs in mainEditor # Clear datas self.loadEmptyDatas() self.saveTimer.stop() # UI for i in [self.actSave, self.actSaveAs, self.actCloseProject, self.menuEdit, self.menuMode, self.menuView, self.menuTools, self.menuHelp]: i.setEnabled(False) # Reload recent files self.welcome.updateValues() # Show welcome dialog self.stack.setCurrentIndex(0) def readSettings(self): # Load State and geometry sttgns = QSettings(qApp.organizationName(), qApp.applicationName()) if sttgns.contains("geometry"): self.restoreGeometry(sttgns.value("geometry")) if sttgns.contains("windowState"): self.restoreState(sttgns.value("windowState")) else: self.dckCheatSheet.hide() self.dckSearch.hide() if sttgns.contains("metadataState"): state = [False if v == "false" else True for v in sttgns.value("metadataState")] self.redacMetadata.restoreState(state) if sttgns.contains("revisionsState"): state = [False if v == "false" else True for v in sttgns.value("revisionsState")] self.redacMetadata.revisions.restoreState(state) if sttgns.contains("splitterRedacH"): self.splitterRedacH.restoreState(sttgns.value("splitterRedacH")) if sttgns.contains("splitterRedacV"): self.splitterRedacV.restoreState(sttgns.value("splitterRedacV")) if sttgns.contains("toolbar"): # self.toolbar is not initialized yet, so we just store balue self._toolbarState = sttgns.value("toolbar") else: self._toolbarState = "" def closeEvent(self, event): # Save State and geometry and other things sttgns = QSettings(qApp.organizationName(), qApp.applicationName()) sttgns.setValue("geometry", self.saveGeometry()) sttgns.setValue("windowState", self.saveState()) sttgns.setValue("metadataState", self.redacMetadata.saveState()) sttgns.setValue("revisionsState", self.redacMetadata.revisions.saveState()) sttgns.setValue("splitterRedacH", self.splitterRedacH.saveState()) sttgns.setValue("splitterRedacV", self.splitterRedacV.saveState()) sttgns.setValue("toolbar", self.toolbar.saveState()) # Specific settings to save before quitting settings.lastTab = self.tabMain.currentIndex() if self.currentProject: # Remembering the current items sel = [] for i in range(self.mainEditor.tab.count()): sel.append(self.mdlOutline.pathToIndex(self.mainEditor.tab.widget(i).currentIndex)) settings.openIndexes = sel # Save data from models if self.currentProject and settings.saveOnQuit: self.saveDatas() # closeEvent # QMainWindow.closeEvent(self, event) # Causin segfaults? def startTimerNoChanges(self): if settings.autoSaveNoChanges: self.saveTimerNoChanges.start() def saveDatas(self, projectName=None): """Saves the current project (in self.currentProject). If ``projectName`` is given, currentProject becomes projectName. In other words, it "saves as...". """ if projectName: self.currentProject = projectName QSettings().setValue("lastProject", projectName) # Saving files = [] files.append((saveStandardItemModelXML(self.mdlFlatData), "flatModel.xml")) files.append((saveStandardItemModelXML(self.mdlPersos), "perso.xml")) files.append((saveStandardItemModelXML(self.mdlWorld), "world.xml")) files.append((saveStandardItemModelXML(self.mdlLabels), "labels.xml")) files.append((saveStandardItemModelXML(self.mdlStatus), "status.xml")) files.append((saveStandardItemModelXML(self.mdlPlots), "plots.xml")) files.append((self.mdlOutline.saveToXML(), "outline.xml")) files.append((settings.save(), "settings.pickle")) saveFilesToZip(files, self.currentProject) # Giving some feedback print(self.tr("Project {} saved.").format(self.currentProject)) self.statusBar().showMessage( self.tr("Project {} saved.").format(self.currentProject), 5000) def loadEmptyDatas(self): self.mdlFlatData = QStandardItemModel(self) self.mdlPersos = persosModel(self) # self.mdlPersosProxy = persosProxyModel(self) # self.mdlPersosInfos = QStandardItemModel(self) self.mdlLabels = QStandardItemModel(self) self.mdlStatus = QStandardItemModel(self) self.mdlPlots = plotModel(self) self.mdlOutline = outlineModel(self) self.mdlWorld = worldModel(self) def loadDatas(self, project): # Loading files = loadFilesFromZip(project) errors = [] if "flatModel.xml" in files: loadStandardItemModelXML(self.mdlFlatData, files["flatModel.xml"], fromString=True) else: errors.append("flatModel.xml") if "perso.xml" in files: loadStandardItemModelXML(self.mdlPersos, files["perso.xml"], fromString=True) else: errors.append("perso.xml") if "world.xml" in files: loadStandardItemModelXML(self.mdlWorld, files["world.xml"], fromString=True) else: errors.append("world.xml") if "labels.xml" in files: loadStandardItemModelXML(self.mdlLabels, files["labels.xml"], fromString=True) else: errors.append("perso.xml") if "status.xml" in files: loadStandardItemModelXML(self.mdlStatus, files["status.xml"], fromString=True) else: errors.append("perso.xml") if "plots.xml" in files: loadStandardItemModelXML(self.mdlPlots, files["plots.xml"], fromString=True) else: errors.append("perso.xml") if "outline.xml" in files: self.mdlOutline.loadFromXML(files["outline.xml"], fromString=True) else: errors.append("perso.xml") if "settings.pickle" in files: settings.load(files["settings.pickle"], fromString=True) else: errors.append("perso.xml") # Giving some feedback if not errors: print(self.tr("Project {} loaded.").format(project)) self.statusBar().showMessage( self.tr("Project {} loaded.").format(project), 5000) else: print(self.tr("Project {} loaded with some errors:").format(project)) for e in errors: print(self.tr(" * {} wasn't found in project file.").format(e)) self.statusBar().showMessage( self.tr("Project {} loaded with some errors.").format(project), 5000) ############################################################################### # MAIN CONNECTIONS ############################################################################### def makeUIConnections(self): "Connections that have to be made once only, event when new project is loaded." self.lstPersos.currentItemChanged.connect(self.changeCurrentPerso, AUC) self.txtPlotFilter.textChanged.connect(self.lstPlots.setFilter, AUC) self.lstPlots.currentItemChanged.connect(self.changeCurrentPlot, AUC) self.txtSubPlotSummary.document().contentsChanged.connect( self.updateSubPlotSummary, AUC) self.lstSubPlots.activated.connect(self.changeCurrentSubPlot, AUC) self.btnRedacAddFolder.clicked.connect(self.treeRedacOutline.addFolder, AUC) self.btnOutlineAddFolder.clicked.connect(self.treeOutlineOutline.addFolder, AUC) self.btnRedacAddText.clicked.connect(self.treeRedacOutline.addText, AUC) self.btnOutlineAddText.clicked.connect(self.treeOutlineOutline.addText, AUC) self.btnRedacRemoveItem.clicked.connect(self.outlineRemoveItemsRedac, AUC) self.btnOutlineRemoveItem.clicked.connect(self.outlineRemoveItemsOutline, AUC) self.tabMain.currentChanged.connect(self.toolbar.setCurrentGroup) def makeConnections(self): # Flat datas (Summary and general infos) for widget, col in [ (self.txtSummarySituation, 0), (self.txtSummarySentence, 1), (self.txtSummarySentence_2, 1), (self.txtSummaryPara, 2), (self.txtSummaryPara_2, 2), (self.txtPlotSummaryPara, 2), (self.txtSummaryPage, 3), (self.txtSummaryPage_2, 3), (self.txtPlotSummaryPage, 3), (self.txtSummaryFull, 4), (self.txtPlotSummaryFull, 4), ]: widget.setModel(self.mdlFlatData) widget.setColumn(col) widget.setCurrentModelIndex(self.mdlFlatData.index(1, col)) for widget, col in [ (self.txtGeneralTitle, 0), (self.txtGeneralSubtitle, 1), (self.txtGeneralSerie, 2), (self.txtGeneralVolume, 3), (self.txtGeneralGenre, 4), (self.txtGeneralLicense, 5), (self.txtGeneralAuthor, 6), (self.txtGeneralEmail, 7), ]: widget.setModel(self.mdlFlatData) widget.setColumn(col) widget.setCurrentModelIndex(self.mdlFlatData.index(0, col)) # Persos self.lstPersos.setPersosModel(self.mdlPersos) self.tblPersoInfos.setModel(self.mdlPersos) self.btnAddPerso.clicked.connect(self.mdlPersos.addPerso, AUC) self.btnRmPerso.clicked.connect(self.mdlPersos.removePerso, AUC) self.btnPersoColor.clicked.connect(self.mdlPersos.chosePersoColor, AUC) self.btnPersoAddInfo.clicked.connect(self.mdlPersos.addPersoInfo, AUC) self.btnPersoRmInfo.clicked.connect(self.mdlPersos.removePersoInfo, AUC) for w, c in [ (self.txtPersoName, Perso.name.value), (self.sldPersoImportance, Perso.importance.value), (self.txtPersoMotivation, Perso.motivation.value), (self.txtPersoGoal, Perso.goal.value), (self.txtPersoConflict, Perso.conflict.value), (self.txtPersoEpiphany, Perso.epiphany.value), (self.txtPersoSummarySentence, Perso.summarySentence.value), (self.txtPersoSummaryPara, Perso.summaryPara.value), (self.txtPersoSummaryFull, Perso.summaryFull.value), (self.txtPersoNotes, Perso.notes.value) ]: w.setModel(self.mdlPersos) w.setColumn(c) self.tabPersos.setEnabled(False) # Plots self.lstPlots.setPlotModel(self.mdlPlots) self.lstPlotPerso.setModel(self.mdlPlots) self.lstSubPlots.setModel(self.mdlPlots) self._updatingSubPlot = False self.btnAddPlot.clicked.connect(self.mdlPlots.addPlot, AUC) self.btnRmPlot.clicked.connect(lambda: self.mdlPlots.removePlot(self.lstPlots.currentPlotIndex()), AUC) self.btnAddSubPlot.clicked.connect(self.mdlPlots.addSubPlot, AUC) self.btnRmSubPlot.clicked.connect(self.mdlPlots.removeSubPlot, AUC) self.lstPlotPerso.selectionModel().selectionChanged.connect(self.plotPersoSelectionChanged) self.btnRmPlotPerso.clicked.connect(self.mdlPlots.removePlotPerso, AUC) for w, c in [ (self.txtPlotName, Plot.name.value), (self.txtPlotDescription, Plot.description.value), (self.txtPlotResult, Plot.result.value), (self.sldPlotImportance, Plot.importance.value), ]: w.setModel(self.mdlPlots) w.setColumn(c) self.tabPlot.setEnabled(False) self.mdlPlots.updatePlotPersoButton() self.mdlPersos.dataChanged.connect(self.mdlPlots.updatePlotPersoButton) self.lstOutlinePlots.setPlotModel(self.mdlPlots) self.lstOutlinePlots.setShowSubPlot(True) self.plotPersoDelegate = outlinePersoDelegate(self.mdlPersos, self) self.lstPlotPerso.setItemDelegate(self.plotPersoDelegate) self.plotDelegate = plotDelegate(self) self.lstSubPlots.setItemDelegateForColumn(Subplot.meta.value, self.plotDelegate) # World self.treeWorld.setModel(self.mdlWorld) for i in range(self.mdlWorld.columnCount()): self.treeWorld.hideColumn(i) self.treeWorld.showColumn(0) self.btnWorldEmptyData.setMenu(self.mdlWorld.emptyDataMenu()) self.treeWorld.selectionModel().selectionChanged.connect(self.changeCurrentWorld, AUC) self.btnAddWorld.clicked.connect(self.mdlWorld.addItem, AUC) self.btnRmWorld.clicked.connect(self.mdlWorld.removeItem, AUC) for w, c in [ (self.txtWorldName, World.name.value), (self.txtWorldDescription, World.description.value), (self.txtWorldPassion, World.passion.value), (self.txtWorldConflict, World.conflict.value), ]: w.setModel(self.mdlWorld) w.setColumn(c) self.tabWorld.setEnabled(False) self.treeWorld.expandAll() # Outline self.treeRedacOutline.setModel(self.mdlOutline) self.treeOutlineOutline.setModelPersos(self.mdlPersos) self.treeOutlineOutline.setModelLabels(self.mdlLabels) self.treeOutlineOutline.setModelStatus(self.mdlStatus) self.redacMetadata.setModels(self.mdlOutline, self.mdlPersos, self.mdlLabels, self.mdlStatus) self.outlineItemEditor.setModels(self.mdlOutline, self.mdlPersos, self.mdlLabels, self.mdlStatus) self.treeOutlineOutline.setModel(self.mdlOutline) # self.redacEditor.setModel(self.mdlOutline) self.storylineView.setModels(self.mdlOutline, self.mdlPersos, self.mdlPlots) self.treeOutlineOutline.selectionModel().selectionChanged.connect(lambda: self.outlineItemEditor.selectionChanged( self.treeOutlineOutline), AUC) self.treeOutlineOutline.clicked.connect(lambda: self.outlineItemEditor.selectionChanged(self.treeOutlineOutline), AUC) # Sync selection self.treeRedacOutline.selectionModel().selectionChanged.connect( lambda: self.redacMetadata.selectionChanged(self.treeRedacOutline), AUC) self.treeRedacOutline.clicked.connect( lambda: self.redacMetadata.selectionChanged(self.treeRedacOutline), AUC) self.treeRedacOutline.selectionModel().selectionChanged.connect(self.mainEditor.selectionChanged, AUC) # Cheat Sheet self.cheatSheet.setModels() # Debug self.mdlFlatData.setVerticalHeaderLabels(["Infos générales", "Summary"]) self.tblDebugFlatData.setModel(self.mdlFlatData) self.tblDebugPersos.setModel(self.mdlPersos) self.tblDebugPersosInfos.setModel(self.mdlPersos) self.tblDebugPersos.selectionModel().currentChanged.connect( lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlPersos.index( self.tblDebugPersos.selectionModel().currentIndex().row(), Perso.name.value)), AUC) self.tblDebugPlots.setModel(self.mdlPlots) self.tblDebugPlotsPersos.setModel(self.mdlPlots) self.tblDebugSubPlots.setModel(self.mdlPlots) self.tblDebugPlots.selectionModel().currentChanged.connect( lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index( self.tblDebugPlots.selectionModel().currentIndex().row(), Plot.persos.value)), AUC) self.tblDebugPlots.selectionModel().currentChanged.connect( lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index( self.tblDebugPlots.selectionModel().currentIndex().row(), Plot.subplots.value)), AUC) self.treeDebugWorld.setModel(self.mdlWorld) self.treeDebugOutline.setModel(self.mdlOutline) self.lstDebugLabels.setModel(self.mdlLabels) self.lstDebugStatus.setModel(self.mdlStatus) ############################################################################### # GENERAL AKA UNSORTED ############################################################################### def clickCycle(self, i): if i == 0: # step 2 - paragraph summary self.tabMain.setCurrentIndex(self.TabSummary) self.tabSummary.setCurrentIndex(1) if i == 1: # step 3 - characters summary self.tabMain.setCurrentIndex(self.TabPersos) self.tabPersos.setCurrentIndex(0) if i == 2: # step 4 - page summary self.tabMain.setCurrentIndex(self.TabSummary) self.tabSummary.setCurrentIndex(2) if i == 3: # step 5 - characters description self.tabMain.setCurrentIndex(self.TabPersos) self.tabPersos.setCurrentIndex(1) if i == 4: # step 6 - four page synopsis self.tabMain.setCurrentIndex(self.TabSummary) self.tabSummary.setCurrentIndex(3) if i == 5: # step 7 - full character charts self.tabMain.setCurrentIndex(self.TabPersos) self.tabPersos.setCurrentIndex(2) if i == 6: # step 8 - scene list self.tabMain.setCurrentIndex(self.TabPlots) def wordCount(self, i): src = { 0: self.txtSummarySentence, 1: self.txtSummaryPara, 2: self.txtSummaryPage, 3: self.txtSummaryFull }[i] lbl = { 0: self.lblSummaryWCSentence, 1: self.lblSummaryWCPara, 2: self.lblSummaryWCPage, 3: self.lblSummaryWCFull }[i] wc = wordCount(src.toPlainText()) if i in [2, 3]: pages = self.tr(" (~{} pages)").format(int(wc / 25) / 10.) else: pages = "" lbl.setText(self.tr("Words: {}{}").format(wc, pages)) def setupMoreUi(self): # Tool bar on the right self.toolbar = collapsibleDockWidgets(Qt.RightDockWidgetArea, self) self.toolbar.addCustomWidget(self.tr("Book summary"), self.grpPlotSummary, self.TabPlots) self.toolbar.addCustomWidget(self.tr("Project tree"), self.treeRedacWidget, self.TabRedac) self.toolbar.addCustomWidget(self.tr("Metadata"), self.redacMetadata, self.TabRedac) self.toolbar.addCustomWidget(self.tr("Story line"), self.storylineView, self.TabRedac) if self._toolbarState: self.toolbar.restoreState(self._toolbarState) # Custom "tab" bar on the left self.lstTabs.setIconSize(QSize(48, 48)) for i in range(self.tabMain.count()): icons = ["general-128px.png", "summary-128px.png", "characters-128px.png", "plot-128px.png", "world-128px.png", "outline-128px.png", "redaction-128px.png", "" ] self.tabMain.setTabIcon(i, QIcon(appPath("icons/Custom/Tabs/{}".format(icons[i])))) item = QListWidgetItem(self.tabMain.tabIcon(i), self.tabMain.tabText(i)) item.setSizeHint(QSize(item.sizeHint().width(), 64)) item.setTextAlignment(Qt.AlignCenter) self.lstTabs.addItem(item) self.tabMain.tabBar().hide() self.lstTabs.currentRowChanged.connect(self.tabMain.setCurrentIndex) self.tabMain.currentChanged.connect(self.lstTabs.setCurrentRow) # Splitters self.splitterPersos.setStretchFactor(0, 25) self.splitterPersos.setStretchFactor(1, 75) self.splitterPlot.setStretchFactor(0, 20) self.splitterPlot.setStretchFactor(1, 60) self.splitterPlot.setStretchFactor(2, 30) self.splitterWorld.setStretchFactor(0, 25) self.splitterWorld.setStretchFactor(1, 75) self.splitterOutlineH.setStretchFactor(0, 25) self.splitterOutlineH.setStretchFactor(1, 75) self.splitterOutlineV.setStretchFactor(0, 75) self.splitterOutlineV.setStretchFactor(1, 25) self.splitterRedacV.setStretchFactor(0, 75) self.splitterRedacV.setStretchFactor(1, 25) self.splitterRedacH.setStretchFactor(0, 30) self.splitterRedacH.setStretchFactor(1, 40) self.splitterRedacH.setStretchFactor(2, 30) # QFormLayout stretch for w in [self.txtWorldDescription, self.txtWorldPassion, self.txtWorldConflict]: s = w.sizePolicy() s.setVerticalStretch(1) w.setSizePolicy(s) # Help box references = [ (self.lytTabOverview, self.tr("Enter infos about your book, and yourself."), 0), (self.lytSituation, self.tr( """The basic situation, in the form of a 'What if...?' question. Ex: 'What if the most dangerous evil wizard could wasn't abled to kill a baby?' (Harry Potter)"""), 1), (self.lytSummary, self.tr( """Take time to think about a one sentence (~50 words) summary of your book. Then expand it to a paragraph, then to a page, then to a full summary."""), 1), (self.lytTabPersos, self.tr("Create your characters."), 0), (self.lytTabPlot, self.tr("Develop plots."), 0), (self.lytTabOutline, self.tr("Create the outline of your masterpiece."), 0), (self.lytTabRedac, self.tr("Write."), 0), (self.lytTabDebug, self.tr("Debug infos. Sometimes useful."), 0) ] for widget, text, pos in references: label = helpLabel(text, self) self.actShowHelp.toggled.connect(label.setVisible, AUC) widget.layout().insertWidget(pos, label) self.actShowHelp.setChecked(False) # Spellcheck if enchant: self.menuDict = QMenu(self.tr("Dictionary")) self.menuDictGroup = QActionGroup(self) self.updateMenuDict() self.menuTools.addMenu(self.menuDict) self.actSpellcheck.toggled.connect(self.toggleSpellcheck, AUC) self.dictChanged.connect(self.mainEditor.setDict, AUC) self.dictChanged.connect(self.redacMetadata.setDict, AUC) self.dictChanged.connect(self.outlineItemEditor.setDict, AUC) else: # No Spell check support self.actSpellcheck.setVisible(False) a = QAction(self.tr("Install PyEnchant to use spellcheck"), self) a.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxWarning)) a.triggered.connect(self.openPyEnchantWebPage, AUC) self.menuTools.addAction(a) ############################################################################### # SPELLCHECK ############################################################################### def updateMenuDict(self): if not enchant: return self.menuDict.clear() for i in enchant.list_dicts(): a = QAction(str(i[0]), self) a.setCheckable(True) if settings.dict is None: settings.dict = enchant.get_default_language() if str(i[0]) == settings.dict: a.setChecked(True) a.triggered.connect(self.setDictionary, AUC) self.menuDictGroup.addAction(a) self.menuDict.addAction(a) def setDictionary(self): if not enchant: return for i in self.menuDictGroup.actions(): if i.isChecked(): # self.dictChanged.emit(i.text().replace("&", "")) settings.dict = i.text().replace("&", "") # Find all textEditView from self, and toggle spellcheck for w in self.findChildren(textEditView, QRegExp(".*"), Qt.FindChildrenRecursively): w.setDict(settings.dict) def openPyEnchantWebPage(self): from PyQt5.QtGui import QDesktopServices QDesktopServices.openUrl(QUrl("http://pythonhosted.org/pyenchant/")) def toggleSpellcheck(self, val): settings.spellcheck = val # Find all textEditView from self, and toggle spellcheck for w in self.findChildren(textEditView, QRegExp(".*"), Qt.FindChildrenRecursively): w.toggleSpellcheck(val) ############################################################################### # SETTINGS ############################################################################### def settingsLabel(self): self.settingsWindow(3) def settingsStatus(self): self.settingsWindow(4) def settingsWindow(self, tab=None): self.sw = settingsWindow(self) self.sw.hide() self.sw.setWindowModality(Qt.ApplicationModal) self.sw.setWindowFlags(Qt.Dialog) r = self.sw.geometry() r2 = self.geometry() self.sw.move(r2.center() - r.center()) if tab: self.sw.setTab(tab) self.sw.show() ############################################################################### # TOOLS ############################################################################### def frequencyAnalyzer(self): self.fw = frequencyAnalyzer(self) self.fw.show() ############################################################################### # VIEW MENU ############################################################################### def generateViewMenu(self): values = [ (self.tr("Nothing"), "Nothing"), (self.tr("POV"), "POV"), (self.tr("Label"), "Label"), (self.tr("Progress"), "Progress"), (self.tr("Compile"), "Compile"), ] menus = [ (self.tr("Tree"), "Tree"), (self.tr("Index cards"), "Cork"), (self.tr("Outline"), "Outline") ] submenus = { "Tree": [ (self.tr("Icon color"), "Icon"), (self.tr("Text color"), "Text"), (self.tr("Background color"), "Background"), ], "Cork": [ (self.tr("Icon"), "Icon"), (self.tr("Text"), "Text"), (self.tr("Background"), "Background"), (self.tr("Border"), "Border"), (self.tr("Corner"), "Corner"), ], "Outline": [ (self.tr("Icon color"), "Icon"), (self.tr("Text color"), "Text"), (self.tr("Background color"), "Background"), ], } self.menuView.clear() # print("Generating menus with", settings.viewSettings) for mnu, mnud in menus: m = QMenu(mnu, self.menuView) for s, sd in submenus[mnud]: m2 = QMenu(s, m) agp = QActionGroup(m2) for v, vd in values: a = QAction(v, m) a.setCheckable(True) a.setData("{},{},{}".format(mnud, sd, vd)) if settings.viewSettings[mnud][sd] == vd: a.setChecked(True) a.triggered.connect(self.setViewSettingsAction, AUC) agp.addAction(a) m2.addAction(a) m.addMenu(m2) self.menuView.addMenu(m) def setViewSettingsAction(self): action = self.sender() item, part, element = action.data().split(",") self.setViewSettings(item, part, element) def setViewSettings(self, item, part, element): settings.viewSettings[item][part] = element if item == "Cork": self.mainEditor.updateCorkView() if item == "Outline": self.mainEditor.updateTreeView() self.treeOutlineOutline.viewport().update() if item == "Tree": self.treeRedacOutline.viewport().update() ############################################################################### # COMPILE ############################################################################### def doCompile(self): self.compileDialog = compileDialog() self.compileDialog.show()
class E5NetworkMonitor(QDialog, Ui_E5NetworkMonitor): """ Class implementing a network monitor dialog. """ _monitor = None @classmethod def instance(cls, networkAccessManager): """ Class method to get a reference to our singleton. @param networkAccessManager reference to the network access manager (QNetworkAccessManager) @return reference to the network monitor singleton (E5NetworkMonitor) """ if cls._monitor is None: cls._monitor = E5NetworkMonitor(networkAccessManager) return cls._monitor @classmethod def closeMonitor(cls): """ Class method to close the monitor dialog. """ if cls._monitor is not None: cls._monitor.close() def __init__(self, networkAccessManager, parent=None): """ Constructor @param networkAccessManager reference to the network access manager (QNetworkAccessManager) @param parent reference to the parent widget (QWidget) """ super(E5NetworkMonitor, self).__init__(parent) self.setupUi(self) self.__requestHeaders = QStandardItemModel(self) self.__requestHeaders.setHorizontalHeaderLabels( [self.tr("Name"), self.tr("Value")]) self.requestHeadersList.setModel(self.__requestHeaders) self.requestHeadersList.horizontalHeader().setStretchLastSection(True) self.requestHeadersList.doubleClicked.connect(self.__showHeaderDetails) self.__replyHeaders = QStandardItemModel(self) self.__replyHeaders.setHorizontalHeaderLabels( [self.tr("Name"), self.tr("Value")]) self.responseHeadersList.setModel(self.__replyHeaders) self.responseHeadersList.horizontalHeader().setStretchLastSection(True) self.responseHeadersList.doubleClicked.connect( self.__showHeaderDetails) self.requestsList.horizontalHeader().setStretchLastSection(True) self.requestsList.verticalHeader().setMinimumSectionSize(-1) self.__proxyModel = QSortFilterProxyModel(self) self.__proxyModel.setFilterKeyColumn(-1) self.searchEdit.textChanged.connect( self.__proxyModel.setFilterFixedString) self.removeButton.clicked.connect(self.requestsList.removeSelected) self.removeAllButton.clicked.connect(self.requestsList.removeAll) self.__model = E5RequestModel(networkAccessManager, self) self.__proxyModel.setSourceModel(self.__model) self.requestsList.setModel(self.__proxyModel) self.__proxyModel.rowsInserted.connect( self.requestsList.scrollToBottom) self.requestsList.selectionModel()\ .currentChanged[QModelIndex, QModelIndex]\ .connect(self.__currentChanged) fm = self.fontMetrics() em = fm.width("m") self.requestsList.horizontalHeader().resizeSection(0, em * 5) self.requestsList.horizontalHeader().resizeSection(1, em * 20) self.requestsList.horizontalHeader().resizeSection(3, em * 5) self.requestsList.horizontalHeader().resizeSection(4, em * 15) self.__headersDlg = None def closeEvent(self, evt): """ Protected method called upon closing the dialog. @param evt reference to the close event object (QCloseEvent) """ self.__class__._monitor = None super(E5NetworkMonitor, self).closeEvent(evt) def reject(self): """ Public slot to close the dialog with a Reject status. """ self.__class__._monitor = None super(E5NetworkMonitor, self).reject() def __currentChanged(self, current, previous): """ Private slot to handle a change of the current index. @param current new current index (QModelIndex) @param previous old current index (QModelIndex) """ self.__requestHeaders.setRowCount(0) self.__replyHeaders.setRowCount(0) if not current.isValid(): return row = self.__proxyModel.mapToSource(current).row() req = self.__model.requests[row].request for header in req.rawHeaderList(): self.__requestHeaders.insertRows(0, 1, QModelIndex()) self.__requestHeaders.setData( self.__requestHeaders.index(0, 0), str(header, "utf-8")) self.__requestHeaders.setData( self.__requestHeaders.index(0, 1), str(req.rawHeader(header), "utf-8")) self.__requestHeaders.item(0, 0).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.__requestHeaders.item(0, 1).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) for header in self.__model.requests[row].replyHeaders: self.__replyHeaders.insertRows(0, 1, QModelIndex()) self.__replyHeaders.setData( self.__replyHeaders.index(0, 0), header[0]) self.__replyHeaders.setData( self.__replyHeaders.index(0, 1), header[1]) self.__replyHeaders.item(0, 0).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.__replyHeaders.item(0, 1).setFlags( Qt.ItemIsSelectable | Qt.ItemIsEnabled) def __showHeaderDetails(self, index): """ Private slot to show a dialog with the header details. @param index index of the entry to show (QModelIndex) """ if not index.isValid(): return headerList = self.sender() if headerList is None: return row = index.row() name = headerList.model().data(headerList.model().index(row, 0)) value = headerList.model().data(headerList.model().index(row, 1)) if self.__headersDlg is None: from .E5NetworkHeaderDetailsDialog import \ E5NetworkHeaderDetailsDialog self.__headersDlg = E5NetworkHeaderDetailsDialog(self) self.__headersDlg.setData(name, value) self.__headersDlg.show()
class TIM(QWidget, Ui_Form_For_Main): grouplist = [] userslist = [] tmpuseritem = [] groupInfo = {} chatWindow = {} groupChatWindow = {} my_groups = [] #Save my group glist = [] #Save all information for each group def __init__(self, client): super().__init__() self.m_drag = False self.m_DragPosition = QPoint() self.cache = Cache(self) self.setupUi(self) self.client = client self.Ui_init() self.menuflag = 1 self.temp = {} self.groupTemp = [] #New group id self.addTemp = [] #Join the group id self.setStyleSheet(open('styles/style5.qss').read()) self.setWindowIcon(QIcon('img/bubbles-alt-icon.png')) palette = QPalette() palette.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap('img/background/bg1.jpg'))) self.setPalette(palette) self.setWindowFlag(Qt.FramelessWindowHint) self.tray = MySystemTray(self) self.listener = Listener(self) self.listener.newSysMsgSignal.connect(self.cache.newSysMsg) self.listener.newFriendMsgSignal.connect(self.newFriendMsg) self.listener.newGroupMsgSignal.connect(self.newGroupMsg) self.listener.successAddFriendSignal.connect(self.successAddFriend) self.listener.friendOfflineSignal.connect(self.dealFriendOffline) self.listener.friendsOnlineSignal.connect(self.dealFriendOnline) self.listener.noExistSignal.connect(self.noExist) self.listener.offlineSignal.connect(self.offline) self.listener.beDelSignal.connect(self.dealBeDel) self.listener.createGroupOkSignal.connect(self.dealCreateGroupOk) self.listener.addGroupOkSignal.connect(self.dealAddGroupOk) self.listener.start() def Ui_init(self): image = QImage() image.loadFromData(self.client.head) self.lblHead.setScaledContents(True) self.lblHead.setPixmap(QPixmap.fromImage(image)) self.lblName.setText(self.client.name) self.lblId.setText(str(self.client.id)) self.bt_search.setIcon(QIcon('img/search.png')) self.minBt.setIcon(QIcon('img/min.png')) self.closeBt.setIcon(QIcon('img/wclose.png')) self.setupBt.setIcon(QIcon('img/setting.png')) self.bt_adduser.setIcon(QIcon('img/add.png')) self.cacheBt.setIcon(QIcon('img/msg.png')) self.groupBt.setIcon(QIcon('img/群组.png')) self.faceBt.setIcon(QIcon("img/face.png")) self.lblIcon.setPixmap(QPixmap('img/chat.png')) self.tabWidget.setStyleSheet("background-color:rgba(255,255,255,0.7)") self.treeWidget.setStyleSheet("background-color:rgba(255,255,255,0)") self.groups.setStyleSheet("background-color:rgba(255,255,255,0)") self.groupList.setStyleSheet("background-color:rgba(255,255,255,0)") self.friendList.setStyleSheet("background-color:rgba(255,255,255,0)") self.m_model = QStandardItemModel(0, 1, self) m_completer = QCompleter(self.m_model, self) self.lineEdit.setCompleter(m_completer) m_completer.activated[str].connect(self.onUsernameChoosed) self.setupBt.clicked.connect(self.setUp) self.closeBt.clicked.connect(self.close) self.minBt.clicked.connect(self.showMinimized) self.cacheBt.clicked.connect(self.msgCache) self.groupBt.clicked.connect(self.addGroup) self.faceBt.clicked.connect(self.changeFace) self.treeWidget.currentItemChanged.connect(self.restatistic) self.treeWidget.itemClicked.connect(self.isclick) self.bt_adduser.clicked.connect(self.on_bt_adduser_clicked) self.bt_search.clicked.connect(self.on_bt_search_clicked) self.lineEdit.textChanged[str].connect(self.on_lineEdit_textChanged) self.treeWidget.itemDoubleClicked.connect( self.cache.responseFriendItemClicked) self.groups.itemDoubleClicked.connect( self.cache.responseGroupItemClicked) self.treeWidget.setIndentation(0) self.treeWidget.setColumnCount(1) self.treeWidget.setColumnWidth(0, 50) self.treeWidget.setHeaderLabels(['Friend']) self.treeWidget.header().hide() self.treeWidget.setIconSize(QSize(70, 70)) self.treeWidget.setFocusPolicy(Qt.NoFocus) self.treeWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.creategroup() self.initGroup() def closeWindow(self): if self.cache.isVisible() == True: self.cache.close() for i in self.chatWindow.keys(): self.chatWindow[i].close() for i in self.groupChatWindow.keys(): self.groupChatWindow[i].close() def dealCreateGroupOk(self, gid, data): gname = data.decode('utf-8') for info in self.groupTemp: if gname == info[0]: ghead = info[1] newG = Group(gname, gid, ghead, [self.client.id]) item = QListWidgetItem(self.groups) item.setSizeHint(QSize(self.groups.width(), 61)) self.groups.setItemWidget(item, newG) self.groupTemp.remove(info) self.my_groups.append(gid) groupdic = { 'group': item, 'groupid': gid, 'groupname': gname, 'grouphead': ghead, 'groupmember': [self.client.id] } self.glist.append(groupdic) break def dealAddGroupOk(self, gid, data): if gid in self.addTemp: data = data.split('\n'.encode('utf-8'), 2) gname = data[0].decode('utf-8') gmembers = json.loads(data[1].decode('utf-8')) ghead = data[2] item = QListWidgetItem(self.groups) item.setSizeHint(QSize(self.groups.width(), 61)) newG = Group(gname, gid, ghead, gmembers) self.groups.setItemWidget(item, newG) self.addTemp.remove(gid) self.my_groups.append(gid) groupdic = { 'group': item, 'groupid': gid, 'groupname': gname, 'grouphead': ghead, 'groupmember': gmembers } self.glist.append(groupdic) def newGroupMsg(self, groupid, type, data): if groupid in self.groupChatWindow.keys( ) and self.groupChatWindow[groupid].isVisible(): if (type == Type.GROUP_TEXT): self.groupChatWindow[groupid].recviveMsg(data.decode('utf-8')) else: self.groupChatWindow[groupid].recvivePic(data) else: self.cache.newGroupMsg(groupid, type, data) def newFriendMsg(self, id, type, data): if type == Type.FILE: for user in self.userslist: if id == user['userid']: name = user['username'] break filename, file = data.split('\n'.encode('utf-8'), 1) filename = filename.decode('utf-8') response = QMessageBox.question( None, "Message", "Friend %s (%s) Send file %s,Would you like to accept it?" % (name, id, filename), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if response == QMessageBox.Yes: filepath = QFileDialog.getSaveFileName(None, 'Save as', './' + filename, '') if filepath[0]: with open(filepath[0], 'wb') as f: f.write(file) self.client.dealAcceptFile(id, filename) else: self.client.dealRefuseFile(id, filename) else: self.client.dealRefuseFile(id, filename) elif type == Type.FILE_AC: for user in self.userslist: if id == user['userid']: name = user['username'] break QMessageBox.information( None, 'Message', 'Friend %s (%s) Received file %s' % (name, id, data.decode('utf-8'))) elif type == Type.FILE_RF: for user in self.userslist: if id == user['userid']: name = user['username'] break QMessageBox.information( None, 'Message', 'Friend %s (%s) 拒绝接收文件 %s' % (name, id, data.decode('utf-8'))) else: if id in self.chatWindow.keys() and self.chatWindow[id].isVisible( ): if type == Type.TEXT: self.chatWindow[id].recviveMsg(data.decode('utf-8')) elif type == Type.PIC: self.chatWindow[id].recvivePic(data) else: self.cache.newFriendMsg(id, type, data) def sendGroupMsg(self, id, text): self.client.dealSendGroupMsg(id, text) def sendGroupPic(self, id, pic): self.client.dealSendGroupPic(id, pic) def sendMsg(self, id, text): index = self.searchuser(id) if self.userslist[index]['ishide'] == 1: self.chatWindow[id].notOnline() else: self.client.dealSendMsg(id, text) def sendPic(self, id, bytes): index = self.searchuser(id) if self.userslist[index]['ishide'] == 1: self.chatWindow[id].notOnline() else: self.client.dealSendPic(id, bytes) def sendFile(self, id, filename): index = self.searchuser(id) if self.userslist[index]['ishide'] == 1: self.chatWindow[id].notOnline() else: self.client.dealSendFile(id, filename) def initGroup(self): #格式{群id:[群成员id]}?? #grouplist格式为:列表[群id] self.my_groups = groupInfo = self.client.dealGetGroupList() for groupid in groupInfo: groupname, grouphead = self.client.dealGetGroupNameAndHead(groupid) groupmember = self.client.dealGetGroupMember(groupid) group = QListWidgetItem(self.groups) group.setSizeHint(QSize(self.groups.width(), 55)) groupdic = { 'group': group, 'groupid': groupid, 'groupname': groupname, 'grouphead': grouphead, 'groupmember': groupmember } g = Group(groupname, str(groupid), grouphead, groupmember) self.glist.append(groupdic) self.groups.setItemWidget(group, g) def addGroup(self): addG = AddGroup(self.my_groups, self.groupTemp, self.addTemp) response = addG.exec_() if response == 1: gname, ghead = self.groupTemp[-1] self.client.dealCreateGroup(gname, ghead) elif response == 2: gid = self.addTemp[-1] self.client.dealJoinGroup(gid) def changeFace(self): file = QFileDialog.getOpenFileName(self, 'Select background', '.', ("Images (*.png *.jpg *.bmp)")) if file[0]: palette = QPalette() palette.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap(file[0]))) self.setPalette(palette) def noExist(self, id): QMessageBox.information(self, 'Prompt', 'There is no account number %s User!' % (id)) for k, v in self.temp.items(): if k == id: self.temp.pop(k) break def dealBeDel(self, id): dindex = self.searchuser(id) ishide = self.userslist[dindex]['ishide'] delitem = self.userslist[dindex]['user'] pindex = delitem.parent().indexOfChild(delitem) name = self.userslist[dindex]['username'] del self.userslist[dindex] fathergroup = delitem.parent() findex = self.searchgroup(fathergroup) parentName = self.grouplist[findex]['groupname'] if ishide == 1: self.grouplist[findex]['childishide'] -= 1 self.grouplist[findex]['childcount'] -= 1 else: self.grouplist[findex]['childcount'] -= 1 delitem.parent().takeChild(pindex) for user in self.groupInfo[parentName]: if user['userid'] == id: self.groupInfo[parentName].remove(user) break def offline(self, id): QMessageBox.information( self, 'Prompt', 'Account number is %s Users are not online!' % (id)) for k, v in self.temp.items(): if k == id: self.temp.pop(k) break def dealRefuseAdd(self, id): QMessageBox.information( self, 'Prompt', 'Account number is %s User rejects your friend request!' % id) for k, v in self.temp.items(): if k == id: self.temp.pop(k) break def dealFriendOnline(self, id): useritemindex = self.searchuser(id) if useritemindex is not None: self.userslist[useritemindex]['ishide'] = 0 useritem = self.userslist[useritemindex]['user'] parent = useritem.parent() findex = self.searchgroup(parent) widget = self.treeWidget.itemWidget(useritem, 0) widget.lblonlinestate.setPixmap(QPixmap("img/bullet_green.png")) self.grouplist[findex]['childishide'] -= 1 fathergroupname = self.grouplist[findex]['groupname'] fathergroupname += ' ' + str( self.grouplist[findex]['childcount'] - self.grouplist[findex]['childhide']) + '/' + str( self.grouplist[findex]['childcount']) parent.setText(0, fathergroupname) def dealBeAdded(self, widget): reply = QMessageBox.question( self, 'Friend add Prompt', '%s(%s)Add you as a friend' % (widget.name, widget.id), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if reply == QMessageBox.No: self.client.dealRefuseAdded(widget.id) else: info = ['my good friend', widget.name] dialog = Add_Dialog(info) for g in self.grouplist: dialog.comboBox.addItem(g['groupname']) dialog.exec_() self.client.dealAcceptAdded(widget.id) newitem = QTreeWidgetItem() newitem.setSizeHint(0, QSize(self.treeWidget.width(), 55)) head = widget.data.split('\n'.encode('utf-8'), 1)[1] buddy = Buddy(info[1], str(widget.id), head, 0) userdic = { 'user': newitem, 'username': info[1], 'userid': widget.id, 'head': head, 'ishide': 0 } cindex = self.searchgroup(info[0]) group = self.grouplist[cindex]['group'] self.grouplist[cindex]['childcount'] += 1 self.userslist.append(userdic) group.addChild(newitem) self.treeWidget.setItemWidget(newitem, 0, buddy) self.treeWidget.setCurrentItem(newitem) user = {'username': info[1], 'userid': widget.id, 'ishide': 0} self.groupInfo[info[0]].append(user) def dealFriendOffline(self, id): useritemindex = self.searchuser(id) if useritemindex is not None: self.userslist[useritemindex]['ishide'] = 1 useritem = self.userslist[useritemindex]['user'] parent = useritem.parent() findex = self.searchgroup(parent) widget = self.treeWidget.itemWidget(useritem, 0) widget.lblonlinestate.setPixmap(QPixmap('img/bullet-grey.png')) self.grouplist[findex]['childishide'] += 1 fathergroupname = self.grouplist[findex]['groupname'] fathergroupname += ' ' + str( self.grouplist[findex]['childcount'] - self.grouplist[findex]['childhide']) + '/' + str( self.grouplist[findex]['childcount']) parent.setText(0, fathergroupname) self.treeWidget.setCurrentItem(parent) def on_bt_adduser_clicked(self): des_id = [-1] adduser = Dialog_additem(des_id, self.temp, self.userslist, self.client.id) for g in self.grouplist: adduser.comboBox.addItem(g['groupname']) if adduser.exec_() == 1: data = self.client.name.encode('utf-8') + "\n".encode( 'utf-8') + self.client.head protocol = Protocol(len(data), self.client.id, des_id[0], Type.ADD_FRIEND) header = protocol.make_packet_header() self.client.sock.sendall(header + data) def successAddFriend(self, friend, head): newitem = QTreeWidgetItem() newitem.setSizeHint(0, QSize(self.treeWidget.width(), 55)) friendName = friend['name'] friendId = friend['id'] ishide = friend['ishide'] buddy = Buddy(friendName, str(friendId), head, ishide) userdic = { 'user': newitem, 'username': friendName, 'userid': friendId, 'head': head, 'ishide': ishide } for k, v in self.temp.items(): if k == friend['id']: comboxinfo = self.temp.pop(k) break cindex = self.searchgroup(comboxinfo) group = self.grouplist[cindex]['group'] groupname = self.grouplist[cindex]['groupname'] self.grouplist[cindex]['childcount'] += 1 self.userslist.append(userdic) group.addChild(newitem) self.treeWidget.setItemWidget(newitem, 0, buddy) self.treeWidget.setCurrentItem(newitem) user = {'username': friendName, 'userid': friendId, 'ishide': 0} self.groupInfo[groupname].append(user) def creategroup(self): self.groupInfo = groupInfo = self.client.dealInitGroupInfo() for groupname in groupInfo.keys(): hidernum = 0 group = QTreeWidgetItem(self.treeWidget) groupdic = { 'group': group, 'groupname': groupname, 'childcount': 0, 'childhide': 0 } icon = self.searchIcon(groupname) group.setIcon(0, icon) for friend in groupInfo[groupname]: child = QTreeWidgetItem() child.setSizeHint(0, QSize(self.treeWidget.width(), 55)) friendName = friend['username'] friendId = friend['userid'] ishide = friend['ishide'] head = self.client.dealGetHead(friendId) buddy = Buddy(friendName, str(friendId), head, ishide) userdic = { 'user': child, 'username': friendName, 'userid': friendId, 'head': head, 'ishide': ishide } self.userslist.append(userdic) if friend['ishide'] == 1: hidernum += 1 userdic['ishide'] = 1 group.addChild(child) self.treeWidget.setItemWidget(child, 0, buddy) childnum = group.childCount() lastchildnum = childnum - hidernum groupdic['childcount'] = childnum groupdic['childishide'] = hidernum groupname += ' ' + str(lastchildnum) + '/' + str(childnum) group.setText(0, groupname) group.setExpanded(True) self.grouplist.append(groupdic) def createusers(self, num): randname = "黑子" randicon = QIcon(str(num) + '.jpg') font = QFont() font.setPointSize(16) isvip = random.randint(0, 5) ishider = random.randint(0, 5) if ishider == 1: randicon = QIcon(str(num) + 'h.jpg') return randname, randicon, font, isvip, ishider def searchIcon(self, gpname2): if gpname2.find('Friend') >= 0: return QIcon('img/buddy.ico') elif gpname2.find('同事'): return QIcon('img/partner.ico') elif gpname2.find('黑名单'): return QIcon('img/blacklist.ico') else: return QIcon('img/defalut.ico') def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.m_drag = True self.m_DragPosition = event.globalPos() - self.pos() event.accept() def mouseMoveEvent(self, QMouseEvent): if QMouseEvent.buttons() and Qt.LeftButton: self.move(QMouseEvent.globalPos() - self.m_DragPosition) QMouseEvent.accept() def mouseReleaseEvent(self, QMouseEvent): self.m_drag = False def onUsernameChoosed(self, name): self.lineEdit.setText(name) def on_lineEdit_textChanged(self, text): namelist = [] for itm in self.userslist: username = itm['username'] if username.find(text) >= 0: namelist.append(itm['username']) self.m_model.removeRows(0, self.m_model.rowCount()) for i in range(0, len(namelist)): self.m_model.insertRow(0) self.m_model.setData(self.m_model.index(0, 0), namelist[i]) def on_bt_search_clicked(self): username = self.lineEdit.text() if len(username) > 0: useritemindex = self.searchuser(username) if useritemindex is not None: useritem = self.userslist[useritemindex]['user'] self.treeWidget.setCurrentItem(useritem) else: QMessageBox.information(self, 'Message', 'This friend does not exist!') def closeEvent(self, event): reply = QMessageBox.question( self, 'Prompt', 'Are you sure you want to quit the program?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: event.ignore() else: self.hide() self.client.dealUpdate(self.groupInfo) self.closeWindow() time.sleep(3) self.client.dealQuit() time.sleep(1) self.listener.terminate() event.accept() def msgCache(self): self.cache.show() def setUp(self): setup = SetInfoDialog(self.client) if setup.exec_() > 0: self.lblName.setText( self.client.name ) ################################################################################需要设置头像!!!!!!! image = QImage() image.loadFromData(self.client.head) self.lblHead.setPixmap(QPixmap.fromImage(image)) self.client.dealSetHead() self.client.dealSetName() def delGroup(self): hititem = self.groups.currentItem() group = self.groups.itemWidget(hititem) gid = int(group.id.text()) self.client.dealDeleteGroup(gid) row = self.groups.row(hititem) self.groups.takeItem(row) def contextMenuEvent(self, event): x = QCursor.pos().x() y = QCursor.pos().y() widget = QApplication.widgetAt(x, y) if type(widget) == Group: menu = QMenu(self) pDeleteAct = QAction('Delete group', self.groups) menu.addAction(pDeleteAct) pDeleteAct.triggered.connect(self.delGroup) menu.popup(self.mapToGlobal(event.pos())) elif type(widget) == QWidget: hititem = self.treeWidget.currentItem() pgroupmenu = QMenu(self) pAddgroupAct = QAction('Add group', self.treeWidget) pRenameAct = QAction('Rename', self.treeWidget) pDeleteAct = QAction('Delete group', self.treeWidget) pgroupmenu.addAction(pAddgroupAct) pgroupmenu.addAction(pRenameAct) pgroupmenu.addAction(pDeleteAct) pAddgroupAct.triggered.connect(self.addgroup) pRenameAct.triggered.connect(self.renamegroup) if self.treeWidget.itemAbove(hititem) is None: pDeleteAct.setEnabled(False) else: pDeleteAct.setEnabled(True) pDeleteAct.triggered.connect(self.deletegroup) pgroupmenu.popup(self.mapToGlobal(event.pos())) elif type(widget) == Buddy: hititem = self.treeWidget.currentItem() root = hititem.parent() if root.childCount() > 0: pItemmenu = QMenu(self) pDeleteItemAct = QAction('Delete contact', pItemmenu) pItemmenu.addAction(pDeleteItemAct) pDeleteItemAct.triggered.connect(self.delete) if len(self.grouplist) > 1: pSubMenu = QMenu('Transfer contacts to', pItemmenu) pItemmenu.addMenu(pSubMenu) for item_dic in self.grouplist: if item_dic['group'] is not root: pMoveAct = QAction(item_dic['groupname'], pItemmenu) pSubMenu.addAction(pMoveAct) pMoveAct.triggered.connect(self.moveItem) if len(self.getListitems(self.menuflag)) == 1: pRenameItemAct = QAction('Setting note', pItemmenu) pItemmenu.addAction(pRenameItemAct) pRenameItemAct.triggered.connect(self.renameItem) if self.menuflag > 0 and root.childCount() > 1: pBatchAct = QAction('Batch operation within a group', pItemmenu) pItemmenu.addAction(pBatchAct) pBatchAct.triggered.connect(self.Batchoperation) elif self.menuflag < 0: pCancelBatchAct = QAction('Cancel batch operation', pItemmenu) pItemmenu.addAction(pCancelBatchAct) pCancelBatchAct.triggered.connect( self.CancelBatchoperation) pItemmenu.popup(self.mapToGlobal(event.pos())) def moveItem(self): movelist = self.getListitems(self.menuflag) togroupname = self.sender().text() mindex = self.searchgroup(togroupname) togroup = self.grouplist[mindex]['group'] self.deleteItems(movelist, flag=0) self.add(togroup, movelist) self.tmpuseritem.clear() def delete(self): delitems = self.getListitems(self.menuflag) self.deleteItems(delitems) self.tmpuseritem.clear() def deleteItems(self, items, flag=1): for delitem in items: delitem.setData(0, Qt.CheckStateRole, QVariant()) pindex = delitem.parent().indexOfChild(delitem) dindex = self.searchuser(delitem) ishide = self.userslist[dindex]['ishide'] id = self.userslist[dindex]['userid'] if flag == 1: self.client.dealDelFriend(id) del self.userslist[dindex] fathergroup = delitem.parent() findex = self.searchgroup(fathergroup) parentName = self.grouplist[findex]['groupname'] for user in self.groupInfo[parentName]: if user['userid'] == id: self.groupInfo[parentName].remove(user) break fathergroup = delitem.parent() findex = self.searchgroup(fathergroup) if ishide == 1: self.grouplist[findex]['childishide'] -= 1 self.grouplist[findex]['childcount'] -= 1 else: self.grouplist[findex]['childcount'] -= 1 delitem.parent().takeChild(pindex) def add(self, group, items): gindex = self.searchgroup(group) gname = self.grouplist[gindex]['groupname'] for item in items: aindex = self.searchuser(item) ishide = self.userslist[aindex]['ishide'] userid = self.userslist[aindex]['userid'] username = self.userslist[aindex]['username'] head = self.userslist[aindex]['head'] if ishide == 1: self.grouplist[gindex]['childishide'] += 1 self.grouplist[gindex]['childcount'] += 1 else: self.grouplist[gindex]['childcount'] += 1 buddy = Buddy(username, str(userid), head, ishide) group.addChild(item) self.treeWidget.setItemWidget(item, 0, buddy) self.treeWidget.itemWidget(item, 0).show() self.treeWidget.setCurrentItem(item) user = {'username': username, 'userid': userid, 'ishide': 0} self.groupInfo[gname].append(user) def Batchoperation(self): self.menuflag *= -1 group = self.getListitems()[0].parent() childnum = group.childCount() for c in range(childnum): child = group.child(c) child.setCheckState(0, Qt.Unchecked) def CancelBatchoperation(self): self.menuflag *= -1 group = self.getListitems()[0].parent() childnum = group.childCount() for c in range(childnum): child = group.child(c) child.setData(0, Qt.CheckStateRole, QVariant()) def isclick(self, item): if item.checkState(0) == Qt.Checked: if self.tmpuseritem.count(item) == 0: self.tmpuseritem.append(item) else: if len(self.tmpuseritem) > 0: if self.tmpuseritem.count(item) != 0: i = self.tmpuseritem.index(item) del self.tmpuseritem[i] def renameItem(self): hituser = self.treeWidget.currentItem() widget = self.treeWidget.itemWidget(hituser, 0) uindex = self.searchuser(hituser) unewname, ok = QInputDialog.getText(self, 'Prompt Information', 'Please enter a note name') if ok: if len(unewname) == 0: QMessageBox.information(self, 'Prompt', 'Note name cannot be empty') else: widget.name.setText(unewname) self.userslist[uindex]['username'] = unewname id = self.userslist[uindex]['userid'] parent = hituser.parent() parentIndex = self.searchgroup(parent) parentName = self.grouplist[parentIndex]['groupname'] for user in self.groupInfo[parentName]: if user['userid'] == id: user['username'] = unewname def searchuser(self, hituser): if isinstance(hituser, str): if hituser.isdigit(): for i, u in enumerate(self.userslist): if str(u['userid']) == hituser: return i else: for i, u in enumerate(self.userslist): if u['username'] == hituser: return i elif isinstance(hituser, int): for i, u in enumerate(self.userslist): if u['userid'] == hituser: return i else: for i, u in enumerate(self.userslist): if hituser == u['user']: return i return None def getListitems(self, flag=1): if flag > 0: return self.treeWidget.selectedItems() else: return self.tmpuseritem def addgroup(self): gname, ok = QInputDialog.getText(self, 'Prompt Information', 'Please enter a group name') if ok: if len(gname) == 0: QMessageBox.information(self, 'Prompt', 'Group name cannot be empty') else: hidernum = 0 group = QTreeWidgetItem(self.treeWidget) groupdic = { 'group': group, 'groupname': gname, 'childcount': 0, 'childhide': 0 } #sself.groupInfo[gname] = '' icon = self.searchIcon(gname) group.setIcon(0, icon) childnum = group.childCount() lastchildnum = childnum - hidernum groupdic['childcount'] = childnum groupdic['childishide'] = hidernum self.groupInfo[gname] = [] gname += ' ' + str(lastchildnum) + '/' + str(childnum) group.setText(0, gname) self.grouplist.append(groupdic) def renamegroup(self): hitgroup = self.treeWidget.currentItem() gnewname, ok = QInputDialog.getText(self, 'Prompt', 'Please enter a new group name') if ok: if len(gnewname) == 0: QMessageBox.information(self, 'Prompt', 'Group name cannot be empty') else: hitgroup.setText(0, gnewname) newicon = self.searchIcon(hitgroup.text(0)) hitgroup.setIcon(0, newicon) gindex = self.searchgroup(hitgroup) oldname = self.grouplist[gindex]['groupname'] self.grouplist[gindex]['groupname'] = gnewname self.treeWidget.setCurrentItem(hitgroup.child(0)) self.groupInfo[gnewname] = self.groupInfo.pop(oldname) def deletegroup(self): hitgroup = self.treeWidget.currentItem() gindex = self.searchgroup(hitgroup) reply = QMessageBox.question( self, 'Warning', 'Are you sure you want to delete this group?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.treeWidget.takeTopLevelItem(gindex) groupname = self.grouplist[gindex]['groupname'] del self.grouplist[gindex] del self.groupInfo[groupname] def searchgroup(self, hitgroup): if isinstance(hitgroup, str): for i, g in enumerate(self.grouplist): if g['groupname'] == hitgroup: return i else: for i, g in enumerate(self.grouplist): if g['group'] == hitgroup: return i def restatistic(self, item, preitem): if item: fathergroup = item.parent() if fathergroup: self.restatistic_op(fathergroup) else: self.restatistic_op(item) elif preitem.parent().childCount() == 1: lastgroupname = preitem.parent().text(0).split()[0] + ' 0/0' preitem.parent().setText(0, lastgroupname) self.menuflag = 1 def restatistic_op(self, itemorgroup): gindex = self.searchgroup(itemorgroup) totalcount = self.grouplist[gindex]['childcount'] hidecount = self.grouplist[gindex]['childishide'] fathergroupname = self.grouplist[gindex]['groupname'] fathergroupname += ' ' + str(totalcount - hidecount) + '/' + str(totalcount) itemorgroup.setText(0, fathergroupname)