class Result_window(QWidget): def __init__(self): super().__init__() # OLD self.initUI() self.table = QTableView(self) self.table.setGeometry(0, 0, 400, 300) self.model = QStandardItemModel(self) self.table.setModel(self.model) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.populate() self.table.doubleClicked.connect(self.on_click) def on_click(self, signal): row = signal.row() column = signal.column() cell_dict = self.model.itemData(signal) cell_value = cell_dict.get(0) index = signal.sibling(row, 0) index_dict = self.model.itemData(index) index_value = index_dict.get(0) print( "Row {}, \nColumn {}, \n clicked - value: {} \nColumn 1 contents: {} \n \n ---- \n \n".format(row, \ column, \ cell_value, \ index_value) ) def populate(self): values = [] for i in range(10): sub_values = [] for i in range(4): value = random.randrange(1, 100) sub_values.append(value) values.append(sub_values) for value in values: row = [] for item in value: cell = QStandardItem( str(item) ) row.append(cell) self.model.appendRow(row) self.show() def initUI(self): self.setGeometry(0, 500, 640, 480) #TODO calibrate coordinates self.setWindowTitle( "Result of SQL callbacks" ) self.setWindowIcon( QIcon('result.png') ) self.show()
class AccountDialog(QDialog): def __init__(self, parent=None): super(AccountDialog, self).__init__(parent) # init ui self.ui = Ui_Account_Dialog() self.ui.setupUi(self) # init list view # self.load_all_persons() # init combox self.model = QStandardItemModel() self.load_all_persons() # init collections self.selected_persons = [] def on_select_begin_date(self): calendarDialog = CalendarDialog() calendarDialog.show() if calendarDialog.exec_(): date = calendarDialog.date_time print("value get from calendar window is:" + date.strftime('%Y/%m/%d')) self.ui.start_date.setPlainText(date.strftime('%Y/%m/%d')) self.compute_begin_date = date.strftime('%Y/%m/%d') calendarDialog.destroy() def on_select_end_date(self): calendarDialog = CalendarDialog() calendarDialog.show() if calendarDialog.exec_(): date = calendarDialog.date_time print("value get from calendar window is:" + date.strftime('%Y/%m/%d')) self.ui.end_date.setPlainText(date.strftime('%Y/%m/%d')) self.compute_end_date = date.strftime('%Y/%m/%d') calendarDialog.destroy() def on_person_name_select_finished(self, item): self.selected_name = self.people_names_collection[item] def on_person_name_from_list_view_selected(self): row_index = self.ui.listView.currentIndex().row() print(row_index, "selected!!!!!!!!!!!!!") self.row_index_selected = row_index def on_add_person(self): print("input name is", self.selected_name, "selected persons", self.selected_persons) if self.selected_name not in self.selected_persons: self.selected_persons.append(self.selected_name) item = QStandardItem(self.selected_name) self.__add_item_to_list_view(item) # self.person_name = self.ui.person_name.text() def delete_person_name_from_list_view(self): row_index = self.ui.listView.currentIndex().row() if row_index is -1: QMessageBox.information(self, '请选择删除项', '请选择删除项', QMessageBox.Yes) else: name = self.model.itemData(self.ui.listView.currentIndex())[0] self.selected_persons.remove(name) self.model.removeRow(self.row_index_selected) self.ui.listView.reset() # 重置当前 listview 的游标 # self.ui.listView.setUpdatesEnabled(True) def __add_item_to_list_view(self, item): row_count = self.model.rowCount() print("already have items num", row_count) self.model.appendRow(item) self.ui.listView.setModel(self.model) def on_start_compute_cmd(self): print("begin to compute account......") info = str(self.selected_persons) + ',' + str(self.compute_begin_date) + ',' \ + str(self.compute_end_date) print(info) self.ui.output_result.setText(info) def load_all_persons(self): self.people_names_collection = ["erha", "erya", "xxxx"] self.ui.people_names.addItems(self.people_names_collection)
class Controller(object): """ The Controller class is for loading the specific guis from the GUI folder. It also implements and fill the required GUI with logic. """ def __init__(self, path: str): # the actual path self.actualPath = path # A IDatabaseManager to communicate with the database self.database = DatabaseManager() # Tries to create the required tables self.database.createTables() # The path to the different GUIs self.pathMainGui = self.actualPath + '/GUI' + '/MainGui.ui' self.pathStartDownload = self.actualPath + '/GUI' + '/StartDownload.ui' self.pathCurrentDownload = self.actualPath + '/GUI' + '/CurrentDownload.ui' self.pathSettings = self.actualPath + '/GUI' + '/Settings.ui' self.pathError = self.actualPath + '/GUI' + '/ErrorMessage.ui' self.pathHelp = self.actualPath + '/GUI' + '/Help.ui' self.pathMoodleSummary = self.actualPath + '/GUI' + '/MoodleSummary.ui' # path to the folder, where temporary files shall be stored self.pathTempFolder = self.actualPath + '/temp/' app = QtWidgets.QApplication(sys.argv) # the main and error window self.MainWindow = None self.ErrorWindow = None # courseData, which was selected from the user self.selectedCourseData = None # The filter (lecturer name, semester, course name) which is selected self.selectedFilter = None # The model of the courseData which is selected self.modelCourseData = None # Will set on True, when the moodle download was started, because # scrapy can only run one time per program run self.startedMoodleCrawler = False # The IFileHandler to handle the CourseData self.fileHandler = FileHandler() # The used ITextAbstraction self.textSummarizer = TextAbstraction(database=self.database) user = self.database.getUser() # check if the program has already a user if user is None: # no user in the database # go to settings self.openSettings() else: # go to main page self.goBackMainPage() sys.exit(app.exec_()) # Guis # Open MainPage def goBackMainPage(self): """ goBackMainPage will start the MainPage and will connect everything with the required functions and print the required information to the gui. """ # close and clean up the old Main Window self.cleanMainWindow() # Load and show the new Main Window self.MainWindow = loadUi(self.pathMainGui) self.MainWindow.showMaximized() self.MainWindow.show() # disable that the user can edit the entries from table for general course information self.MainWindow.tab_courses.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_courses.setSortingEnabled(True) # Fill the table for the general course information with data self.printGeneralCourseInformation() # if some data from the general course information is clicked, show all data for this filter # in tab_data self.MainWindow.tab_courses.clicked.connect( self.selectGeneralCourseInformation) # disable that the user can edit the entries from table for course data self.MainWindow.tab_data.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_data.setSortingEnabled(True) # if an cell was selected in table for course data, mark the whole row self.MainWindow.tab_data.setSelectionBehavior( QAbstractItemView.SelectRows) # if some data from the CourseData is clicked, load the summary to the field text_Abstract self.MainWindow.tab_data.clicked.connect(self.selectCourseData) # Connect the Buttons with functionality # open Window for checking, if it is necessary to download moodle-data self.MainWindow.but_downloadMoodle.clicked.connect( self.openWindowStartDownload) # open Window for storing username and password self.MainWindow.but_settings.clicked.connect(self.openSettings) # open Window for help self.MainWindow.but_help.clicked.connect(self.openHelp) # open Window for get the summary from the last moodle download self.MainWindow.but_moodleSummary.clicked.connect( lambda: self.openMoodleSummary(destination="Main Page")) # search functions self.MainWindow.but_searchAll.clicked.connect( lambda: self.searchData(filter="All")) self.MainWindow.but_searchCell.clicked.connect( lambda: self.searchData(filter="Cell")) # show Text without Text-Mining self.MainWindow.but_withoutTextMiningAll.clicked.connect( lambda: self.showDataWithoutTextMining(filter="All")) self.MainWindow.but_withoutTextMiningCell.clicked.connect( lambda: self.showDataWithoutTextMining(filter="Cell")) # open Data self.MainWindow.but_openData.clicked.connect(self.openData) self.MainWindow.but_openAllData.clicked.connect(self.openAllData) # save Data self.MainWindow.but_saveData.clicked.connect(self.saveData) self.MainWindow.but_saveAllData.clicked.connect(self.saveAllData) # close program self.MainWindow.but_close.clicked.connect(self.quitProgram) # StartDownloadPage def openWindowStartDownload(self): """ open the gui to ask the user, if he really wants to download the moodle data. It will connect everything with the required functions and print the required information to the gui. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathStartDownload) # Check if the Crawler was executed, because you can´t start again a Crawler if (self.startedMoodleCrawler): # Crawler was executed # deactivate the Button for starting the Crawler self.MainWindow.but_startDownload.setEnabled(False) # inform the user that he can not start again the crawler self.MainWindow.label_info.setText( """<html><head/><body><p align="center">Achtung:</p><p align="center">Es ist nur möglich einen Moodledownload pro </p><p align="center">Programmstart auszuführen.</p><p align="center">Falls Sie erneut den Download starten wollen, starten Sie das Porgramm neu!<br/></p></body></html>""" ) else: # Crawler was not executed # get the las date of Crawling lastDateOfCrawling = self.database.getMaxDateOfCrawling() if lastDateOfCrawling is None: # inform the user, that he never start a download process from moodle self.MainWindow.label_info.setText( self.MainWindow.label_info.text().replace( '%String', 'Sie haben noch keinen Download gestartet!')) else: # inform the user, when his last download was self.MainWindow.label_info.setText( self.MainWindow.label_info.text().replace( '%String', lastDateOfCrawling.dateCrawling.strftime( "%H:%M:%S %d.%m.%Y "))) self.MainWindow.show() # connect button to go back to Main Page self.MainWindow.but_abortDownload.clicked.connect(self.goBackMainPage) # connect button to start moodle download self.MainWindow.but_startDownload.clicked.connect( self.openCurrentDownload) def openCurrentDownload(self): """ Will open the current download gui and connect the scrapy logger to the gui. It start also the Crawler, if the user stored all required information. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathCurrentDownload) self.MainWindow.showMaximized() # Activate logger to textbox logTextBox = QTextEditLogger(self.MainWindow) # You can format what is printed to text box logTextBox.setFormatter( logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) # You can control the logging level logging.getLogger().setLevel(logging.INFO) # disable button done until the crawler finished self.MainWindow.but_done.setEnabled(False) # the log output is only readable self.MainWindow.plainTextEdit.setReadOnly(True) self.MainWindow.show() # get the moodle user user = self.database.getUser() # Check if a user is in the database or none of his attributes is null if (user is None or not user.username or not user.password): logTextBox.deactivate() self.goBackMainPage() self.errorMessage(e="""Sie haben noch keinen Nutzer angelegt. \n Bitte legen Sie bei \"Einstellungen\" auf dem Startbildschirm, einen Nutzer an!""" ) else: # the user has all attributes # start the moodle crawler crawler = MoodleCrawlerHTWBerlin() crawler.startCrawler(self.database, user.username, user.password) # set the information, that the crawler was started on true self.startedMoodleCrawler = True # move the cursor to the end of the text field self.MainWindow.plainTextEdit.moveCursor(QTextCursor.End) logTextBox.deactivate() # check if the login was sucessfully if not self.database.loginSuccessfully(): self.errorMessage(e=""" Das Passwort oder der Nutzername sind falsch. \n Bitte ändern Sie bei \"Einstellungen\" auf dem Startbildschirm den Nutzer!""" ) self.MainWindow.but_done.setEnabled(True) self.MainWindow.but_done.clicked.connect(self.goBackMainPage) else: # login was a success self.MainWindow.but_done.setEnabled(True) self.MainWindow.but_done.clicked.connect( lambda: self.openMoodleSummary(destination="Text Process")) def openMoodleSummary(self, destination: str = "Main Page"): """ Open the GUI for the getMoodleSummary. And print all informations to the gui. This GUI is for informing the user about what data per course is new, old and could not be downloaded. Also every specific error in the download process will be shown. :param destination: Which GUI shall load after this gui. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathMoodleSummary) # Fill the moodle data summary with data modelMoodleSummaryData = QStandardItemModel() self.MainWindow.tab_numberOfData.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_numberOfData.setSortingEnabled(True) self.MainWindow.tab_numberOfData.setModel(modelMoodleSummaryData) # get the summary from the database moodleSummaryData = self.database.getMoodleSummary() # get the header from the table header = MoodleSummary.getHeader() modelMoodleSummaryData.setHorizontalHeaderLabels(header) for moodleSummaryItem in moodleSummaryData: listOfValues = moodleSummaryItem.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) modelMoodleSummaryData.appendRow(row) # Fill the moodle error data summary with data modelMoodleError = QStandardItemModel() self.MainWindow.tab_errorData.setModel(modelMoodleError) self.MainWindow.tab_errorData.setEditTriggers( QAbstractItemView.NoEditTriggers) self.MainWindow.tab_errorData.setSortingEnabled(True) # get the error summary from the database moodleErrorData = self.database.getMoodleErrorSummary() # get the header from the table header = MoodleErrorSummary.getHeader() modelMoodleError.setHorizontalHeaderLabels(header) for moodleErrorItem in moodleErrorData: listOfValues = moodleErrorItem.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) modelMoodleError.appendRow(row) self.MainWindow.showMaximized() self.MainWindow.show() if destination == "Main Page": self.MainWindow.but_back.setText("Zurück zur Hauptseite") self.MainWindow.but_back.clicked.connect(self.goBackMainPage) elif destination == "Text Process": self.MainWindow.but_back.clicked.connect(self.openTextProcessing) def openSettings(self): """ open the GUI for settings. It is for saving the user information password and username from moodle. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathSettings) self.MainWindow.show() # get the user from the database user = self.database.getUser() # set passwordline on password, that the password is not readable for the user self.MainWindow.linePassword.setEchoMode(QLineEdit.Password) # check if in the database is an user if user is not None: # in the database is an user # fill the text fields with his information self.MainWindow.lineUsername.setText(user.username) self.MainWindow.linePassword.setText(user.password) else: self.MainWindow.lineUsername.setPlaceholderText('s0111111') self.MainWindow.linePassword.setPlaceholderText( 'Hier dein Passwort') # go back to main page, without saving self.MainWindow.but_abortSettings.clicked.connect(self.goBackMainPage) # go back to main page, with saving self.MainWindow.but_save.clicked.connect(self.saveSettings) def openHelp(self): """ open the help GUI. This is for helping the user to work with the application """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathHelp) self.MainWindow.showMaximized() self.MainWindow.show() # the user can not edit the help text self.MainWindow.helpText.setReadOnly(True) # go back to main page self.MainWindow.but_back.clicked.connect(self.goBackMainPage) # open textProcessing Page def openTextProcessing(self): """ open the GUI CurrentDownload and start the text processing. Also it connects the logger to the edit line. This Gui informs the user about which CourseData will be textually processed. """ self.cleanMainWindow() self.MainWindow = loadUi(self.pathCurrentDownload) self.MainWindow.showMaximized() # Activate logger to textbox logTextBox = QTextEditLogger(self.MainWindow) # You can format what is printed to text box logTextBox.setFormatter( logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) # You can control the logging level logging.getLogger().setLevel(logging.INFO) # disable button until the text process is finished self.MainWindow.but_done.setEnabled(False) self.MainWindow.plainTextEdit.setReadOnly(True) self.MainWindow.show() # create the text mining logic textProcessing = TextProcessing(database=self.database, path=self.pathTempFolder, textSummarizer=self.textSummarizer) # get the CourseData from the database, which do not have a text abstraction and not raised an error in a past process fileTypes = ['pdf', 'docx', 'pptx', 'html'] dataWithoutTextMining = self.database.getCourseDataWithoutTextMiningForParsing( fileTypes) # i is the position of the course data in the list i = 1 countDataWithoutTextMining = len(dataWithoutTextMining) self.MainWindow.plainTextEdit.appendPlainText( "Es sind insgesamt %d Dateien textuell aufzuarbeiten!".replace( "%d", str(countDataWithoutTextMining))) # start for each data the text mining process for data in dataWithoutTextMining: self.MainWindow.plainTextEdit.appendPlainText( "Beginn mit der %d1. Datei von %d2!".replace( "%d1", str(i)).replace("%d2", str(countDataWithoutTextMining))) textProcessing.textProcessing(data) self.MainWindow.plainTextEdit.appendPlainText( "Fertig mit der %d1. Datei von %d2!".replace( "%d1", str(i)).replace("%d2", str(countDataWithoutTextMining))) i += 1 QtWidgets.QApplication.processEvents() # enable the button for finish this self.MainWindow.but_done.setEnabled(True) # deactivate the logger logTextBox.deactivate() # go back to main page self.MainWindow.but_done.clicked.connect(self.goBackMainPage) def saveSettings(self): """ It tries to save the informations from the settings to the database. If every field is filled save the information to the database and go back to the main page. Otherwise print an error message and do nothing. """ # read the arguments of the user username = self.MainWindow.lineUsername.text() password = self.MainWindow.linePassword.text() if username == "" or password == "": self.errorMessage(e="""Der Nuzername oder das Passwort sind leer. Bitte füllen Sie die Felder aus!""") else: user = User(username=username, password=password) # delete the current user from the database self.database.deleteUsers() # insert the new user self.database.insertObject(user) # go back to main page self.goBackMainPage() def quitProgram(self): """ Tries to delete every file in the temp folder. Only the files, which are not any more in use will be deleted. After this quit the program. """ self.fileHandler.deleteAllFilesInFolder(self.pathTempFolder) sys.exit() def printGeneralCourseInformation(self): """ print the generalCourseInformation to the table tab_courses """ self.modelGeneralCourseInformation = QStandardItemModel() self.MainWindow.tab_courses.setModel( self.modelGeneralCourseInformation) courses = self.database.getGeneralCourseInformation() header = GeneralCourseInformation.getHeader() self.modelGeneralCourseInformation.setHorizontalHeaderLabels(header) # fill the table with the information for course in courses: listOfValues = course.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) self.modelGeneralCourseInformation.appendRow(row) def printCourseData(self, table=""): """ print all CourseData from the table to the table tab_data. :param table: the table which shall be printed """ self.modelCourseData = QStandardItemModel() self.MainWindow.tab_data.setModel(self.modelCourseData) header = CourseDataWithInformation.getHeader() self.modelCourseData.setHorizontalHeaderLabels(header) for course in table: listOfValues = course.getListForPrinting() row = [] for value in listOfValues: cell = QStandardItem() cell.setData(value, Qt.DisplayRole) row.append(cell) self.modelCourseData.appendRow(row) def searchData(self, filter: str): """ search for data if filter is all search for all data for search string otherwise for the selected filter after this print the searched data to table tab_data :param filter: filter = "All" if all data shall be searched; filter = "Cell" if only for the specific selected filter data shall be searched """ searchString = self.MainWindow.line_search.text() table = None if filter == 'All': table = self.database.getCourseDataByText( searchString=searchString, filter="") elif filter == 'Cell': if self.selectedFilter: table = self.database.getCourseDataByText( searchString=searchString, filter=self.selectedFilter) else: self.errorMessage( e="""Sie haben keine Zelle ausgewählt. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff""") if table: self.printCourseData(table) def showDataWithoutTextMining(self, filter: str): """ Search for data without text mining and print them to the table tab_data. :param filter: filter = "All" if all data without text-mining shall be searched; filter = "Cell" if only for the specific selected filter data without text-mining shall be searched """ table = None if filter == 'All': table = self.database.getCourseDataWithoutTextMining(filter="") elif filter == 'Cell': if self.selectedFilter: table = self.database.getCourseDataWithoutTextMining( filter=self.selectedFilter) else: self.errorMessage(e="""Sie haben keine Zelle ausgewählt. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff""" ) if table: self.printCourseData(table) def openData(self): """ open the the selected CourseData if None is selected inform the user that he has to select a CourseData in the table """ if self.selectedCourseData is not None: self.fileHandler.openFile(courseData=self.selectedCourseData, path=self.pathTempFolder) else: self.errorMessage(e="""Sie haben keine Datei ausgewählt. \n Bitte drücken Sie in der mittleren Tabelle auf Ihren gewünschte Datei.""" ) def openAllData(self): """ open all Data which are in the tab_data(modle = modelCourseData) printed If no data is printed inform the user that he has to search for CourseData to open a data """ if self.modelCourseData is not None: courseDataID_list = [] self.modelCourseData.columnCount() for y in range(self.modelCourseData.columnCount()): header = self.modelCourseData.horizontalHeaderItem(y).text() if header == "DataID": column = y continue for x in range(self.modelCourseData.rowCount()): index = self.modelCourseData.index(x, column) courseDataID_list.append( self.modelCourseData.itemData(index).get(0)) for courseDataId in courseDataID_list: courseData = self.database.getCourseDataByID(int(courseDataId)) self.fileHandler.openFile(courseData=courseData, path=self.pathTempFolder) else: self.errorMessage( e="""Sie haben keine Dateien gesucht, die Sie auswählen können. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff, um die zugehörigen Dateien anzuzeigen.""" ) def selectGeneralCourseInformation(self, signal): """ Set the selectedFilter on the selected Value, which the user selected. And print all Data for the specific filter to the tab_data """ cell_dict = self.modelGeneralCourseInformation.itemData(signal) self.selectedFilter = cell_dict.get(0) result = self.database.getAllCourseData(filter=self.selectedFilter) self.printCourseData(table=result) def errorMessage(self, e: str): """ open the error Gui and print the error message :param e: the error message """ if self.ErrorWindow is not None: self.ErrorWindow.close() self.ErrorWindow = loadUi(self.pathError) self.ErrorWindow.label_info.setText( self.ErrorWindow.label_info.text().replace('%String', str(e))) self.ErrorWindow.but_ok.clicked.connect(self.ErrorWindow.close) self.ErrorWindow.show() def saveData(self): """ save the selected data to a folder, which the user select. if None is selected inform the user that he has to select a CourseData in the table """ if self.selectedCourseData is not None: saveFolder = QFileDialog.getExistingDirectory( self.MainWindow, "Select Directory") saveFolder += '/' if len(saveFolder) > 0: self.fileHandler.saveFile(courseData=self.selectedCourseData, path=saveFolder) else: self.errorMessage(e="""Sie haben keine Datei ausgewählt. \n Bitte drücken Sie in der mittleren Tabelle auf Ihren gewünschte Datei.""" ) def saveAllData(self): """ save all CourseData which are printed in the tab_data(modle = modelCourseData) If no data is printed inform the user that he has to search for CourseData to open a data """ if self.modelCourseData is not None: saveFolder = str( QFileDialog.getExistingDirectory(self.MainWindow, "Select Directory")) if len(saveFolder) > 0: saveFolder += '/' courseDataID_list = [] self.modelCourseData.columnCount() for y in range(self.modelCourseData.columnCount()): header = self.modelCourseData.horizontalHeaderItem( y).text() if header == "DataID": column = y continue for row in range(self.modelCourseData.rowCount()): index = self.modelCourseData.index(row, column) courseDataID_list.append( self.modelCourseData.itemData(index).get(0)) for courseDataId in courseDataID_list: courseData = self.database.getCourseDataByID( int(courseDataId)) self.fileHandler.saveFile(courseData=courseData, path=saveFolder) else: self.errorMessage( e="""Sie haben keine Dateien gesucht, die Sie auswählen können. \n Bitte drücken Sie in der linken Tabelle auf Ihren gewünschten Suchbegriff, um die zugehörigen Dateien anzuzeigen.""" ) def selectCourseData(self, signal): """ set the selectedCourseData on the data which was selected. Print the abstract, the frequency of words and the errors from the data to the text field "text_Abstract" """ row = signal.row() for y in range(self.modelCourseData.columnCount()): header = self.modelCourseData.horizontalHeaderItem(y).text() if header == "DataID": column = y break index = self.modelCourseData.index(row, column) courseDataID = self.modelCourseData.itemData(index).get(0) self.selectedCourseData = self.database.getCourseDataByID( idCourseData=courseDataID) self.MainWindow.text_Abstract.clear() if self.selectedCourseData.abstract is not None: self.MainWindow.text_Abstract.appendPlainText( self.selectedCourseData.abstract) if self.selectedCourseData.abstractWordFrequency is not None: self.MainWindow.text_Abstract.appendPlainText( self.selectedCourseData.abstractWordFrequency) if self.selectedCourseData.error is not None: self.MainWindow.text_Abstract.appendPlainText( self.selectedCourseData.error) self.MainWindow.text_Abstract.setReadOnly(True) def cleanMainWindow(self): """ reset all fields """ if self.MainWindow is not None: self.selectedCourseData = None self.selectedFilter = None self.modelCourseData = None
class GUI_table(QDialog): def __init__(self, params=test.HPparams): super(GUI_table, self).__init__() self.Main = QGridLayout(self) self.resize(1600, 400) self.Main_Splitter = QSplitter(Qt.Vertical) self.table = QTableView() self.header = list(params.keys()) self.value = list(params.values()) self.model = QStandardItemModel(1, len(self.header), self) self.model.setHorizontalHeaderLabels(self.header) for i in range(len(self.header)): newItem = QStandardItem(str(self.value[i])) self.model.setItem(0, i, newItem) self.table.setModel(self.model) self.Main_Splitter.addWidget(self.table) self.Main.addWidget(self.Main_Splitter, 0, 0, 2, 16) self.okButton = QPushButton("&OK", self) self.okButton.clicked.connect(self.OK) self.cancelButton = QPushButton("Cancel", self) self.cancelButton.clicked.connect(self.Cancel) buttonLayout = QHBoxLayout() buttonLayout.addStretch() buttonLayout.addWidget(self.okButton) buttonLayout.addWidget(self.cancelButton) self.Main.addLayout(buttonLayout, 2, 14, 1, 2) def OK(self): self.get_table_data() self.close() def Cancel(self): self.close() def get_table_data(self): self.params = np.zeros(len(self.header)) for j in range(len(self.header)): try: index = self.model.index(0, j) self.params[j] = (self.model.itemData(index)[0]) except: pass #a = self.showdialog('Please fill in all the blank ') return self.params def showdialog(self, message1=' ', message2=' '): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(message1) msg.setWindowTitle("MessageBox") msg.setDetailedText(message2) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) if msg.exec_() == QMessageBox.Yes: return True else: return False
class Scripts(QtWidgets.QDialog, Ui_Scripts): path = '/var/camera/scripts' def __init__(self, window): super().__init__() self.setupUi(self) # Panel init. self.setFixedSize(window.app.primaryScreen().virtualSize()) self.setWindowFlags(QtCore.Qt.FramelessWindowHint) self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True) self.uiStop.hide() self.permissionDenied = QStandardItemModel(self) message = self.tr(f"Can not run script: Permission Denied\nTo fix, set the executable bit on the script and ⟳refresh.\nExample: chmod +x \"{self.path}/my_script.py\"").split('\n') for line in message: line = QStandardItem(line) line.setFlags(Qt.NoItemFlags | Qt.ItemNeverHasChildren) self.permissionDenied.appendRow(line) self.scripts = QStandardItemModel(self) self.uiScripts.setModel(self.scripts) self.loadScripts() # Button binding. self.uiRefresh.clicked.connect(self.loadScripts) self.uiRun.clicked.connect(self.runScript) self.uiStop.clicked.connect(self.stopScript) self.uiScripts.selectionModel().currentChanged.connect(self.showSelectedOutput) self.uiDone.clicked.connect(window.back) def loadScripts(self): self.uiOutput.setModel(None) self.scripts.clear() for file in (i for it in (iglob('/var/camera/scripts/*'), iglob('/media/*/scripts/*')) for i in it): entry = QStandardItem(file.split('/')[-1]) #File name. executable = os.access(file, os.X_OK) entry.setData({ 'path': file, 'executable': executable, 'output': QStandardItemModel(self), 'process': None, }, Qt.UserRole) entry.setData(QColor('#000' if executable else '#666'), Qt.ForegroundRole) self.scripts.appendRow(entry) self.uiScripts.selectionModel().setCurrentIndex( self.scripts.index(0,0), QItemSelectionModel.ClearAndSelect, ) self.showSelectedOutput(self.scripts.index(0,0)) def runScript(self): index = self.uiScripts.selectionModel().currentIndex() script = index.data(Qt.UserRole) if not script['executable']: return log.info(f"run script {script['path']}") self.executeAndPoll(index) self.updateRunButton() def stopScript(self): index = self.uiScripts.selectionModel().currentIndex() script = index.data(Qt.UserRole) script['process'].kill() def scriptStopped(self, index: QtCore.QModelIndex): script = index.data(Qt.UserRole) script['process'] = None self.scripts.setData(index, script, Qt.UserRole ) self.updateRunButton() log.info(f"stop script {script['path']}") def showSelectedOutput(self, index: QtCore.QModelIndex): if not self.scripts.rowCount(): return script = self.scripts.itemData(index)[Qt.UserRole] self.uiOutput.setModel( script['output'] if script['executable'] else self.permissionDenied ) self.uiOutput.scrollToBottom() self.updateRunButton() def updateRunButton(self): if not self.scripts.rowCount(): self.uiStop.hide() self.uiRun.hide() return script = self.uiScripts.selectionModel().currentIndex().data(Qt.UserRole) if script['process']: self.uiStop.show() self.uiRun.hide() else: self.uiRun.show() self.uiStop.hide() def executeAndPoll(self, index: QtCore.QModelIndex): """Run the user script. See http://eyalarubas.com/python-subproc-nonblock.html for commentary and additional approaches.""" script = index.data(Qt.UserRole) proc = subprocess.Popen( script['path'], stdout=subprocess.PIPE, stderr=sys.stdout, #Echo stderr to our logs, so they can be retrieved and watched for debugging. shell=True, cwd=self.path, env=dict({('GUI_PID', str(os.getpid()))} | os.environ.items()) #Use this for SIGSTOP and SIGCONT, NOT SIGKILL. Run service stop chronos-gui2[-dev] for that. Note that $PPID is the parent *shell* we spawn, not the gui, which is why we provide the gui variable. ) script['process'] = proc self.scripts.setData(index, script, Qt.UserRole ) flags = fcntl(proc.stdout, F_GETFL) fcntl(proc.stdout, F_SETFL, flags | os.O_NONBLOCK) currentLine = '' currentEntry = QStandardItem(currentLine) script['output'].clear() script['output'].appendRow(currentEntry) def checkProc(*, timeout): nonlocal currentLine, currentEntry try: poll = proc.poll() data = proc.stdout.read() #this read kills the process: #data = os.read(proc.stdout.fileno(), 1024) #read() seems a bit more stable, but still not 100%. I don't have any idea why. --DDR 2019-10-29 if data: data = data.decode('utf8') if data: lines = data.split('\n') #Load the remainder of the current line. currentLine += lines[0] currentEntry.setData(currentLine, Qt.EditRole) #If any new line(s), append them. If they are unfinished, we'll load the remainder of them next time around. for line in lines[1:]: currentLine = line currentEntry = QStandardItem(line) script['output'].appendRow(currentEntry) lines[1:2] and self.scrollOutputToBottom(script) delay(self, timeout, lambda: checkProc(timeout=16) ) elif poll is None: #Subprocess hasn't exited yet. delay(self, timeout, lambda: checkProc(timeout=max(250, timeout*2)) ) else: message = f'exit {proc.poll()}' if currentLine: currentEntry = QStandardItem(message) script['output'].appendRow(currentEntry) else: currentEntry.setData(message, Qt.EditRole) self.scriptStopped(index) self.scrollOutputToBottom(script) except OSError: message = f'process output closed' #Exit code is None, the process is still running, we just can't read from it. if currentLine: currentEntry = QStandardItem(message) script['output'].appendRow(currentEntry) else: currentEntry.setData(message, Qt.EditRole) self.scriptStopped(index) self.scrollOutputToBottom(script) delay(self, 200, lambda: #Initial delay for startup, then try every frame at most or 4x a second at least. Hopefully we get more than 4fps. 😬 checkProc(timeout=16) ) def scrollOutputToBottom(self, script: dict): if self.uiOutput.model() == script['output']: self.uiOutput.scrollToBottom()
class ArbolView(QTreeView): model = None #modelo del arbol nombre = 'short_name' #nombre para el indice de datos valor = 'valor' #nombre si tiene un valor id = 'dbID' #nombre para el indice del ID parent_id = 'parentID' #nombre para el campo del parent level = 'level' #nombre para el campo del nivel del arbol checked = 'checked' #campo para guardar el estado si tiene checkbox coldato = 0 #columna de datos colindice = 1 #columna con los indices checkeado = [] #filas que estan chequeadas nocheckeado = [] #finas que no estan chequeadas def __init__(self): super().__init__() self.model = QStandardItemModel() self.checkeado = [] self.nocheckeado = [] def ArmaCabecera(self, cabecera=''): self.model.setHorizontalHeaderLabels(cabecera) self.setModel(self.model) self.header().setSectionResizeMode(QHeaderView.ResizeToContents) def ImportaDatos(self, datos='', root=None, concheck=False): self.model.setRowCount(0) if root is None: root = self.model.invisibleRootItem() seen = {} values = deque(datos) while values: value = values.popleft() if value[self.level] == 0: parent = root else: pid = value[self.parent_id] if pid not in seen: values.append(value) continue parent = seen[pid] dbid = value[self.id] itemnombre = QtGui.QStandardItem(value[self.nombre]) try: itemValor = QtGui.QStandardItem(value[self.valor]) except: itemValor = '' itemid = QtGui.QStandardItem(str(dbid)) itemnombre.setEditable(False) if concheck: if value[self.checked]: itemnombre.setCheckState(Qt.Checked) else: itemnombre.setCheckState(Qt.Unchecked) itemnombre.setFlags(itemnombre.flags() | Qt.ItemIsUserCheckable) itemid.setEditable(False) if itemValor: parent.appendRow([ itemnombre, itemValor, itemid, ]) else: parent.appendRow([ itemnombre, itemid, ]) seen[dbid] = parent.child(parent.rowCount() - 1) def ObtenerItemSeleccionado(self, col=0): try: resultado = self.model.itemData(self.selectedIndexes()[col])[0] except: resultado = '' return resultado def recorrer(self, model=None, parent=QModelIndex()): for row in range(model.rowCount(parent)): # dato = self.view.tree.ObtenerItem(0) # print(dato) index = model.index(row, self.coldato, parent) indexid = index nombre = model.data(index) index = model.index(row, self.colindice, parent) id = model.data(index) print(nombre, id) if model.data(indexid, Qt.CheckStateRole) == Qt.Checked: self.checkeado.append(id) else: self.nocheckeado.append(id) if model.hasChildren(indexid): self.recorrer(model, indexid) return self.checkeado, self.nocheckeado
class Window(QWidget, Ui_CustomContextMenu): def __init__(self, parent=None): super(Window, self).__init__(parent) self.setupUi(self) self.m_model = None self._init_tree() self.m_leDatabaseDirectory.setText(os.path.dirname(__file__)) self.m_bbConfirm.clicked.connect(self.on_confirm) def _init_tree(self): self.m_tvProduct.setEditTriggers(QTreeView.NoEditTriggers) self.m_tvProduct.setSelectionMode(QTreeView.SingleSelection) self.m_tvProduct.header().setDefaultSectionSize(200) self.m_tvProduct.header().setHighlightSections(True) headers = ['结构树'] self.m_model = QStandardItemModel(self.m_tvProduct) self.m_model.setHorizontalHeaderLabels(headers) item_type = QStandardItem('RDX(2.7)') self.m_model.setItem(0, 0, item_type) item_product = QStandardItem('HgABC-123') item_type.setChild(0, 0, item_product) item_batch = QStandardItem('2001-ABCD') item_product.setChild(0, 0, item_batch) item_batch.setChild(0, 0, QStandardItem('001')) item_batch.setChild(1, 0, QStandardItem('002')) item_batch.setChild(2, 0, QStandardItem('003')) self.m_tvProduct.setModel(self.m_model) self.m_tvProduct.setContextMenuPolicy(Qt.CustomContextMenu) self.m_tvProduct.customContextMenuRequested.connect(self.on_tree_menu) self.m_tvProduct.clicked.connect(self.on_clicked) def on_clicked(self, index): item = self.m_model.itemData(index) print(item[0]) if 'RDX' in item[0]: self.m_leProductType.setText(item[0]) self.m_leProduct.clear() if 'HgABC' in item[0]: self.m_leProductType.setText('RDX(2.7)') self.m_leProduct.setText(item[0]) if '2001-ABCD' in item[0]: self.m_leProductBatch.setText(item[0]) # self.m_leProduct.setText(item[0]) if item[0] in ['00' + str(i) for i in range(10)]: self.m_leProjectID.setText(item[0]) def on_confirm(self): self.close() def on_tree_menu(self, pos): menu = QMenu() current_index = self.m_tvProduct.indexAt(pos) index = current_index.sibling(current_index.row(), 0) if index.isValid(): text = index.data(Qt.DisplayRole) if 'RDX' in text: menu.addAction('添加产品', self.on_add) menu.exec(self.mapToGlobal(pos)) if 'HgABC' in text: menu.addAction('添加批次', self.on_add) menu.exec(self.mapToGlobal(pos)) if '2001-ABCD' in text: menu.addAction('添加编号', self.on_add) menu.exec(self.mapToGlobal(pos)) # print(index.column()) def on_add(self): pass