class Window(QMainWindow, Ui_MainWindow): def __init__(self): super(QMainWindow, self).__init__() self.setupUi(self) self.statusBar.showMessage("请选择文件") self.AdNDP = AdNDP() self.AdNDP.resultSignal.connect(self.resultTextEdit.append) self.AdNDP.logSignal.connect(self.logTextEdit.append) self.AdNDP.informationSignal.connect(self.informationTextEdit.append) self.AdNDP.setMaximumSignal.connect(self.progressBar.setMaximum) self.AdNDP.setValueSignal.connect(self.progressBar.setValue) @pyqtSlot() def on_openFileAct_triggered(self): path = QFileDialog.getOpenFileName( self, "请选择初始化文件", "./example", "NBO Files (*.log);;All Files (*)")[0] # path = "./example/Li5+.log" if path != '': self.AdNDP.readFile(path) self.progressBar.setValue(0) self.startAnalysisAct.setEnabled(True) self.settingAct.setEnabled(True) else: QMessageBox.warning(self, "错误", "请选择文件") @pyqtSlot() def on_startAnalysisAct_triggered(self): self.statusBar.showMessage("分析中......") self.WorkThread = WorkThread(self.AdNDP) self.WorkThread.start() self.WorkThread.finishSignal.connect(self.on_workThread_finishSignal) def on_workThread_finishSignal(self): QMessageBox.about(self, "提示", "分析完成") self.exportFileAct.setEnabled(True) self.statusBar.showMessage("分析结束,共找到" + str(self.AdNDP.nboAmnt) + "个轨道") @pyqtSlot() def on_aboutAct_triggered(self): self.aboutWindow = AboutWindow() self.aboutWindow.show() @pyqtSlot() def on_exportFileAct_triggered(self): savePath = QFileDialog.getSaveFileName(self, "请选择保存位置", "./example", "log格式 (*.log)")[0] if savePath != '': self.AdNDP.nboPlotMolden(savePath) QMessageBox.about(self, "提示", "保存成功") else: QMessageBox.warning(self, "提示", "请重新选择保存位置") @pyqtSlot() def on_settingAct_triggered(self): self.settingWindow = SettingWindow(self.AdNDP.NAt) self.settingWindow.resultSignal.connect(self.AdNDP.setThreshold) self.settingWindow.show() @pyqtSlot() def on_clearScreenAct_triggered(self): self.resultTextEdit.clear() self.informationTextEdit.clear() self.logTextEdit.clear() self.progressBar.setValue(0) self.startAnalysisAct.setEnabled(False) self.exportFileAct.setEnabled(False) self.settingAct.setEnabled(False) self.statusBar.showMessage("清除完成,请重新选择文件......")
class MainWindow(MainWindow_Ui): def __init__(self): super().__init__() self.system_tray_icon = QSystemTrayIcon() self.system_tray_icon.setIcon(QIcon.fromTheme('persepolis',QIcon(':/icon.svg') )) system_tray_menu = QMenu() system_tray_menu.addAction(self.addlinkAction) system_tray_menu.addAction(self.pauseAllAction) system_tray_menu.addAction(self.stopAllAction) system_tray_menu.addAction(self.minimizeAction) system_tray_menu.addAction(self.exitAction) self.system_tray_icon.setContextMenu(system_tray_menu) self.system_tray_icon.activated.connect(self.systemTrayPressed) self.system_tray_icon.show() self.system_tray_icon.setToolTip('Persepolis Download Manager') f = Open(setting_file) setting_file_lines = f.readlines() f.close() setting_dict_str = str(setting_file_lines[0].strip()) setting_dict = ast.literal_eval(setting_dict_str) if setting_dict['tray-icon'] != 'yes': self.minimizeAction.setEnabled(False) self.trayAction.setChecked(False) self.system_tray_icon.hide() self.statusbar.showMessage('Please Wait ...') self.checkSelectedRow() #touch download_list_file if not(os.path.isfile(download_list_file)): f = Open(download_list_file , 'w') f.close() #touch download_list_file_active if not(os.path.isfile(download_list_file_active)): f = Open(download_list_file_active , 'w') f.close() #lock files perventing to access a file simultaneously #removing lock files in starting persepolis os.system("rm " + config_folder +"/*.lock" + " 2>/dev/null" ) os.system("rm " + download_info_folder + "/*.lock" + " 2>/dev/null" ) #threads self.threadPool=[] #starting aria start_aria = StartAria2Thread() self.threadPool.append(start_aria) self.threadPool[0].start() self.threadPool[0].ARIA2RESPONDSIGNAL.connect(self.startAriaMessage) #initializing #add downloads to the download_table f_download_list_file = Open(download_list_file) download_list_file_lines = f_download_list_file.readlines() f_download_list_file.close() for line in download_list_file_lines: gid = line.strip() self.download_table.insertRow(0) download_info_file = download_info_folder + "/" + gid download_info_file_list = readList(download_info_file,'string') for i in range(10): item = QTableWidgetItem(download_info_file_list[i]) self.download_table.setItem(0 , i , item) row_numbers = self.download_table.rowCount() for row in range(row_numbers): status = self.download_table.item(row , 1).text() if (status != "complete" and status != "error"): gid = self.download_table.item(row,8).text() add_link_dictionary_str = self.download_table.item(row,9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str.strip()) add_link_dictionary['start_hour'] = None add_link_dictionary['start_minute'] = None add_link_dictionary['end_hour'] = None add_link_dictionary['end_minute'] = None add_link_dictionary['after_download'] = 'None' download_info_file = download_info_folder + "/" + gid download_info_file_list = readList(download_info_file,'string') for i in range(10): if i == 1 : download_info_file_list[i] = 'stopped' item = QTableWidgetItem('stopped') self.download_table.setItem(row , i , item ) download_info_file_list[9] = add_link_dictionary writeList(download_info_file , download_info_file_list) self.addlinkwindows_list = [] self.propertieswindows_list = [] self.progress_window_list = [] self.afterdownload_list = [] self.progress_window_list_dict = {} check_download_info = CheckDownloadInfoThread() self.threadPool.append(check_download_info) self.threadPool[1].start() self.threadPool[1].DOWNLOAD_INFO_SIGNAL.connect(self.checkDownloadInfo) check_selected_row = CheckSelectedRowThread() self.threadPool.append(check_selected_row) self.threadPool[2].start() self.threadPool[2].CHECKSELECTEDROWSIGNAL.connect(self.checkSelectedRow) check_flashgot = CheckFlashgot() self.threadPool.append(check_flashgot) self.threadPool[3].start() self.threadPool[3].CHECKFLASHGOTSIGNAL.connect(self.checkFlashgot) self.threadPool[3].SHOWMAINWINDOWSIGNAL.connect(self.showMainWindow) self.download_table.itemDoubleClicked.connect(self.openFile) def startAriaMessage(self,message): global aria_startup_answer if message == 'yes': sleep (2) self.statusbar.showMessage('Ready...') aria_startup_answer = 'ready' else: self.statusbar.showMessage('Error...') notifySend('Persepolis can not connect to Aria2' , 'Restart Persepolis' ,10000,'critical' , systemtray = self.system_tray_icon ) def checkDownloadInfo(self,gid): try: #get download information from download_info_file according to gid and write them in download_table cells download_info_file = config_folder + "/download_info/" + gid download_info_file_list = readList(download_info_file) download_info_file_list_string = readList(download_info_file ,'string') #finding row of this gid! for i in range(self.download_table.rowCount()): row_gid = self.download_table.item(i , 8).text() if gid == row_gid : row = i break for i in range(10): #check flag of download! #It's showing that selection mode is active or not! if i == 0 : flag = int(self.download_table.item(row , i).flags()) #remove gid of completed download from active downloads list file elif i == 1 : status = str(download_info_file_list[i]) status_download_table = str(self.download_table.item(row , 1 ) . text()) if status == "complete": f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() f = Open(download_list_file_active , "w") for line in download_list_file_active_lines : if line.strip() != gid : f.writelines(line.strip() + "\n") f.close() #update download_table cells item = QTableWidgetItem(download_info_file_list_string[i]) #48 means that item is checkable and enabled if i == 0 and flag == 48: item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) if self.download_table.item(row , i).checkState() == 2: item.setCheckState(QtCore.Qt.Checked) else: item.setCheckState(QtCore.Qt.Unchecked) self.download_table.setItem(row , i , item) self.download_table.viewport().update() #update progresswindow try : #finding progress_window for gid member_number = self.progress_window_list_dict[gid] progress_window = self.progress_window_list[member_number] #link add_link_dictionary = download_info_file_list[9] link = "<b>Link</b> : " + str(add_link_dictionary ['link']) progress_window.link_label.setText(link) progress_window.link_label.setToolTip(link) #Save as final_download_path = add_link_dictionary['final_download_path'] if final_download_path == None : final_download_path = str(add_link_dictionary['download_path']) save_as = "<b>Save as</b> : " + final_download_path + "/" + str(download_info_file_list[0]) progress_window.save_label.setText(save_as) progress_window.save_label.setToolTip(save_as) #status progress_window.status = download_info_file_list[1] status = "<b>Status</b> : " + progress_window.status progress_window.status_label.setText(status) if progress_window.status == "downloading": progress_window.resume_pushButton.setEnabled(False) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(True) elif progress_window.status == "paused": progress_window.resume_pushButton.setEnabled(True) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(False) elif progress_window.status == "waiting": progress_window.resume_pushButton.setEnabled(False) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(False) elif progress_window.status == "scheduled": progress_window.resume_pushButton.setEnabled(False) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(False) elif progress_window.status == "stopped" or progress_window.status == "error" or progress_window.status == "complete" : #close progress_window if download status is stopped or completed or error progress_window.close() self.progress_window_list[member_number] = [] del self.progress_window_list_dict[gid] if progress_window.status == "stopped": notifySend("Download Stopped" , str(download_info_file_list[0]) , 10000 , 'no', systemtray = self.system_tray_icon ) elif progress_window.status == "error": notifySend("Error - " + add_link_dictionary['error'] , str(download_info_file_list[0]) , 10000 , 'fail', systemtray = self.system_tray_icon ) add_link_dictionary['start_hour'] = None add_link_dictionary['start_minute'] = None add_link_dictionary['end_hour'] = None add_link_dictionary['end_minute'] = None add_link_dictionary['after_download'] = 'None' for i in range(10): if i == 9 : download_info_file_list[i] = add_link_dictionary download_info_file_list[9] = add_link_dictionary writeList(download_info_file , download_info_file_list ) #this section is sending shutdown signal to the shutdown script(if user select shutdown for after download) if os.path.isfile('/tmp/persepolis/shutdown/' + gid ) == True and progress_window.status != 'stopped': answer = download.shutDown() #KILL aria2c if didn't respond if answer == 'error': os.system('killall aria2c') f = Open('/tmp/persepolis/shutdown/' + gid , 'w') notifySend('Persepolis is shutting down','your system in 20 seconds' , 15000 ,'warning', systemtray = self.system_tray_icon ) f.writelines('shutdown') f.close() elif os.path.isfile('/tmp/persepolis/shutdown/' + gid ) == True and progress_window.status == 'stopped': f = Open('/tmp/persepolis/shutdown/' + gid , 'w') f.writelines('canceled') f.close() #showing download compelete dialog #check user's Preferences f = Open(setting_file) setting_file_lines = f.readlines() f.close() setting_dict_str = str(setting_file_lines[0].strip()) setting_dict = ast.literal_eval(setting_dict_str) if progress_window.status == "complete" and setting_dict['after-dialog'] == 'yes' : afterdownloadwindow = AfterDownloadWindow(download_info_file_list,setting_file) self.afterdownload_list.append(afterdownloadwindow) self.afterdownload_list[len(self.afterdownload_list) - 1].show() elif progress_window.status == "complete" and setting_dict['after-dialog'] == 'no' : notifySend("Download Complete" ,str(download_info_file_list[0]) , 10000 , 'ok' , systemtray = self.system_tray_icon ) #downloaded downloaded = "<b>Downloaded</b> : " + str(download_info_file_list[3]) + "/" + str(download_info_file_list[2]) progress_window.downloaded_label.setText(downloaded) #Transfer rate rate = "<b>Transfer rate</b> : " + str(download_info_file_list[6]) progress_window.rate_label.setText(rate) #Estimate time left estimate_time_left = "<b>Estimate time left</b> : " + str(download_info_file_list[7]) progress_window.time_label.setText(estimate_time_left) #Connections connections = "<b>Connections</b> : " + str(download_info_file_list[5]) progress_window.connections_label.setText(connections) #progressbar value = download_info_file_list[4] file_name = str(download_info_file_list[0]) if file_name != "***": windows_title = '(' + str(value) + ')' + str(file_name) progress_window.setWindowTitle(windows_title) value = value[:-1] progress_window.download_progressBar.setValue(int(value)) except : pass except: pass #contex menu def contextMenuEvent(self, event): self.tablewidget_menu = QMenu(self) self.tablewidget_menu.addAction(self.openFileAction) self.tablewidget_menu.addAction(self.openDownloadFolderAction) self.tablewidget_menu.addAction(self.resumeAction) self.tablewidget_menu.addAction(self.pauseAction) self.tablewidget_menu.addAction(self.stopAction) self.tablewidget_menu.addAction(self.removeAction) self.tablewidget_menu.addAction(self.deleteFileAction) self.tablewidget_menu.addAction(self.propertiesAction) self.tablewidget_menu.addAction(self.progressAction) self.tablewidget_menu.popup(QtGui.QCursor.pos()) #drag and drop for links def dragEnterEvent(self, droplink): text = str(droplink.mimeData().text()) if ("tp:/" in text[2:6]) or ("tps:/" in text[2:7]) : droplink.accept() else: droplink.ignore() def dropEvent(self, droplink): link_clipborad = QApplication.clipboard() link_clipborad.clear(mode=link_clipborad.Clipboard ) link_string = droplink.mimeData().text() link_clipborad.setText(str(link_string), mode=link_clipborad.Clipboard) self.addLinkButtonPressed(button =link_clipborad ) def gidGenerator(self): my_gid = hex(random.randint(1152921504606846976,18446744073709551615)) my_gid = my_gid[2:18] my_gid = str(my_gid) f = Open(download_list_file_active) active_gid_list = f.readlines() f.close() while my_gid in active_gid_list : my_gid = self.gidGenerator() active_gids = download.activeDownloads() while my_gid in active_gids: my_gid = self.gidGenerator() return my_gid def selectedRow(self): try: item = self.download_table.selectedItems() selected_row_return = self.download_table.row(item[1]) download_info = self.download_table.item(selected_row_return , 9).text() download_info = ast.literal_eval(download_info) link = download_info['link'] self.statusbar.showMessage(str(link)) except : selected_row_return = None return selected_row_return def checkSelectedRow(self): try: item = self.download_table.selectedItems() selected_row_return = self.download_table.row(item[1]) except : selected_row_return = None if selected_row_return != None : status = self.download_table.item(selected_row_return , 1).text() if status == "scheduled": self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(False) self.stopAction.setEnabled(True) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) elif status == "stopped" or status == "error" : self.stopAction.setEnabled(False) self.pauseAction.setEnabled(False) self.resumeAction.setEnabled(True) self.removeAction.setEnabled(True) self.propertiesAction.setEnabled(True) self.progressAction.setEnabled(False) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) elif status == "downloading": self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(True) self.stopAction.setEnabled(True) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) elif status == "waiting": self.stopAction.setEnabled(True) self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) elif status == "complete": self.stopAction.setEnabled(False) self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(True) self.propertiesAction.setEnabled(True) self.progressAction.setEnabled(False) self.openDownloadFolderAction.setEnabled(True) self.openFileAction.setEnabled(True) self.deleteFileAction.setEnabled(True) elif status == "paused": self.stopAction.setEnabled(True) self.resumeAction.setEnabled(True) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) else: self.progressAction.setEnabled(False) self.resumeAction.setEnabled(False) self.stopAction.setEnabled(False) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) else: self.progressAction.setEnabled(False) self.resumeAction.setEnabled(False) self.stopAction.setEnabled(False) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.openDownloadFolderAction.setEnabled(False) self.openFileAction.setEnabled(False) self.deleteFileAction.setEnabled(False) def checkFlashgot(self): sleep(0.5) flashgot_file = Open("/tmp/persepolis-flashgot") flashgot_line = flashgot_file.readlines() flashgot_file.close() flashgot_file.remove() flashgot_add_link_dictionary_str = flashgot_line[0] flashgot_add_link_dictionary = ast.literal_eval(flashgot_add_link_dictionary_str) self.flashgotAddLink(flashgot_add_link_dictionary) def flashgotAddLink(self,flashgot_add_link_dictionary): addlinkwindow = AddLinkWindow(self.callBack , flashgot_add_link_dictionary) self.addlinkwindows_list.append(addlinkwindow) self.addlinkwindows_list[len(self.addlinkwindows_list) - 1].show() def addLinkButtonPressed(self ,button): addlinkwindow = AddLinkWindow(self.callBack) self.addlinkwindows_list.append(addlinkwindow) self.addlinkwindows_list[len(self.addlinkwindows_list) - 1].show() def callBack(self , add_link_dictionary): gid = self.gidGenerator() download_info_file_list = ['***','waiting','***','***','***','***','***','***',gid , add_link_dictionary] download_info_file = config_folder + "/download_info/" + gid os.system("touch " + download_info_file ) writeList(download_info_file , download_info_file_list) self.download_table.insertRow(0) j = 0 download_info_file_list[9] = str(download_info_file_list[9]) for i in download_info_file_list : item = QTableWidgetItem(i) self.download_table.setItem(0,j,item) j = j + 1 if self.selectAction.isChecked() == True: item = self.download_table.item(0 , 0) item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) item.setCheckState(QtCore.Qt.Unchecked) f = Open (download_list_file , "a") f.writelines(gid + "\n") f.close() f = Open (download_list_file_active , "a") f.writelines(gid + "\n") f.close() new_download = DownloadLink(gid) self.threadPool.append(new_download) self.threadPool[len(self.threadPool) - 1].start() self.progressBarOpen(gid) if add_link_dictionary['start_hour'] == None : message = "Download Starts" else: message = "Download Scheduled" notifySend(message ,'' , 10000 , 'no', systemtray = self.system_tray_icon ) def resumeButtonPressed(self,button): self.resumeAction.setEnabled(False) selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() download_status = self.download_table.item(selected_row_return , 1).text() if download_status == "paused" : answer = download.downloadUnpause(gid) if answer == 'None': notifySend("Aria2 did not respond!","Try agian!",10000,'warning' , systemtray = self.system_tray_icon ) else: new_download = DownloadLink(gid) self.threadPool.append(new_download) self.threadPool[len(self.threadPool) - 1].start() sleep(1) self.progressBarOpen(gid) else: self.statusbar.showMessage("Please select an item first!") def stopButtonPressed(self,button): self.stopAction.setEnabled(False) selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() answer = download.downloadStop(gid) if answer == 'None': notifySend("Aria2 did not respond!","Try agian!" , 10000 , 'critical' , systemtray = self.system_tray_icon ) else: self.statusbar.showMessage("Please select an item first!") def pauseButtonPressed(self,button): self.pauseAction.setEnabled(False) selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() answer = download.downloadPause(gid) if answer == 'None': notifySend("Aria2 did not respond!" , "Try agian!" , 10000 , 'critical' , systemtray = self.system_tray_icon ) else: self.statusbar.showMessage("Please select an item first!") sleep(1) def removeButtonPressed(self,button): self.removeAction.setEnabled(False) global remove_flag if remove_flag !=3 : remove_flag = 1 while remove_flag != 2 : sleep(0.1) selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() file_name = self.download_table.item(selected_row_return , 0).text() status = self.download_table.item(selected_row_return , 1).text() sleep(0.5) self.download_table.removeRow(selected_row_return) #remove gid of download from download list file f = Open(download_list_file) download_list_file_lines = f.readlines() f.close() f = Open(download_list_file , "w") for i in download_list_file_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove gid of download from active download list file f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() f = Open(download_list_file_active , "w") for i in download_list_file_active_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove download_info_file download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) f.close() f.remove() #remove file of download form download temp folder if file_name != '***' and status != 'complete' : file_name_path = temp_download_folder + "/" + str(file_name) os.system('rm "' + str(file_name_path) +'"') file_name_aria = file_name_path + str('.aria2') os.system('rm "' + str(file_name_aria) +'"') else: self.statusbar.showMessage("Please select an item first!") remove_flag = 0 self.selectedRow() def propertiesButtonPressed(self,button): self.propertiesAction.setEnabled(False) selected_row_return = self.selectedRow() if selected_row_return != None : add_link_dictionary_str = self.download_table.item(selected_row_return , 9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str) gid = self.download_table.item(selected_row_return , 8 ).text() propertieswindow = PropertiesWindow(self.propertiesCallback ,gid) self.propertieswindows_list.append(propertieswindow) self.propertieswindows_list[len(self.propertieswindows_list) - 1].show() def propertiesCallback(self,add_link_dictionary , gid ): download_info_file = download_info_folder + "/" + gid download_info_file_list = readList(download_info_file ) download_info_file_list [9] = add_link_dictionary writeList(download_info_file , download_info_file_list) def progressButtonPressed(self,button): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() if gid in self.progress_window_list_dict : member_number = self.progress_window_list_dict[gid] if self.progress_window_list[member_number].isVisible() == False: self.progress_window_list[member_number].show() else : self.progress_window_list[member_number].hide() def progressBarOpen(self,gid): progress_window = ProgressWindow(parent = self,gid = gid) self.progress_window_list.append(progress_window) member_number = len(self.progress_window_list) - 1 self.progress_window_list_dict[gid] = member_number self.progress_window_list[member_number].show() #close event def closeEvent(self, event): print("Please Wait...") self.hide() self.system_tray_icon.hide() download.shutDown() sleep(0.5) global shutdown_notification shutdown_notification = 1 while shutdown_notification != 2: sleep (0.1) QCoreApplication.instance().closeAllWindows() QCoreApplication.instance().quit print("Persepolis Closed") sys.exit(0) def showTray(self,menu): if self.trayAction.isChecked() == True : self.system_tray_icon.show() self.minimizeAction.setEnabled(True) else: self.system_tray_icon.hide() self.minimizeAction.setEnabled(False) def systemTrayPressed(self,click): if click == 3 : self.minMaxTray(click) def minMaxTray(self,menu): if self.isVisible() == False: self.show() self.minimizeAction.setText('Minimize to system tray') self.minimizeAction.setIcon(QIcon(icons + 'minimize')) else : self.minimizeAction.setText('Show main Window') self.minimizeAction.setIcon(QIcon(icons + 'window')) self.hide() def showMainWindow(self): self.show() self.minimizeAction.setText('Minimize to system tray') self.minimizeAction.setIcon(QIcon(icons + 'minimize')) def stopAllDownloads(self,menu): active_gids = [] for i in range(self.download_table.rowCount()): try: row_status = self.download_table.item(i , 1).text() if row_status == 'downloading' or row_status == 'paused' or row_status == 'waiting': row_gid = self.download_table.item(i , 8).text() active_gids.append(row_gid) except : pass for gid in active_gids: answer = download.downloadStop(gid) if answer == 'None': notifySend("Aria2 did not respond!" , "Try agian!" , 10000 , 'critical' , systemtray = self.system_tray_icon ) sleep(0.3) def pauseAllDownloads(self,menu): #get active gid of downloads from aria active_gids = download.activeDownloads() #check that if gid is in download_list_file_active f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() for i in range(len(download_list_file_active_lines)): download_list_file_active_lines[i] = download_list_file_active_lines[i].strip() for gid in active_gids : if gid in download_list_file_active_lines : answer = download.downloadPause(gid) if answer == 'None': notifySend("Aria2 did not respond!" , "Try agian!" , 10000 , 'critical' , systemtray = self.system_tray_icon ) sleep(0.3) def openPreferences(self,menu): self.preferenceswindow = PreferencesWindow(self) self.preferenceswindow.show() def openAbout(self,menu): self.about_window = AboutWindow() self.about_window.show() def openDefaultDownloadFolder(self,menu): f = Open(setting_file) setting_file_lines = f.readlines() f.close() setting_dict_str = str(setting_file_lines[0].strip()) setting_dict = ast.literal_eval(setting_dict_str) download_path = setting_dict ['download_path'] if os.path.isdir(download_path): os.system("xdg-open '" + download_path + "'" ) else: notifySend(str(download_path) ,'Not Found' , 5000 , 'warning' , systemtray = self.system_tray_icon ) def openDownloadFolder(self,menu): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() download_status = self.download_table.item(selected_row_return , 1).text() if download_status == 'complete': add_link_dictionary_str = self.download_table.item(selected_row_return , 9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str) if 'file_path' in add_link_dictionary : file_path = add_link_dictionary ['file_path'] file_path_split = file_path.split('/') del file_path_split[-1] download_path = '/'.join(file_path_split) if os.path.isdir(download_path): os.system("xdg-open '" + download_path + "' &" ) else: notifySend(str(download_path) ,'Not Found' , 5000 , 'warning' , systemtray = self.system_tray_icon ) def openFile(self,menu): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() download_status = self.download_table.item(selected_row_return , 1).text() if download_status == 'complete': add_link_dictionary_str = self.download_table.item(selected_row_return , 9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str) if 'file_path' in add_link_dictionary: file_path = add_link_dictionary['file_path'] if os.path.isfile(file_path): os.system("xdg-open '" + file_path + "' &" ) else: notifySend(str(file_path) ,'Not Found' , 5000 , 'warning' , systemtray = self.system_tray_icon ) def deleteFile(self,menu): selected_row_return = self.selectedRow() global remove_flag remove_flag = 1 while remove_flag != 2 : sleep(0.1) #This section is checking the download status , if download was completed then download file is removing if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() download_status = self.download_table.item(selected_row_return , 1).text() if download_status == 'complete': add_link_dictionary_str = self.download_table.item(selected_row_return , 9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str) if 'file_path' in add_link_dictionary: file_path = add_link_dictionary['file_path'] if os.path.isfile(file_path): os.system("rm '" + file_path + "'" ) else: notifySend(str(file_path) ,'Not Found' , 5000 , 'warning' , systemtray = self.system_tray_icon ) remove_flag = 3 self.removeButtonPressed(menu) def selectDownloads(self,menu): if self.selectAction.isChecked() == True: #selectAllAction is checked >> activating actions and adding removeSelectedAction and deleteSelectedAction to the toolBar self.toolBar.clear() for i in self.addlinkAction,self.resumeAction, self.pauseAction , self.stopAction, self.removeSelectedAction , self.deleteSelectedAction , self.propertiesAction, self.progressAction , self.exitAction : self.toolBar.addAction(i) self.toolBar.insertSeparator(self.addlinkAction) self.toolBar.insertSeparator(self.resumeAction) self.toolBar.insertSeparator(self.removeSelectedAction) self.toolBar.insertSeparator(self.exitAction) self.toolBar.addSeparator() for i in range(self.download_table.rowCount()): item = self.download_table.item(i , 0) item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) item.setCheckState(QtCore.Qt.Unchecked) self.selectAllAction.setEnabled(True) self.removeSelectedAction.setEnabled(True) self.deleteSelectedAction.setEnabled(True) else: #selectAction is unchecked deactivate actions and adding removeAction and deleteFileAction to the toolBar self.toolBar.clear() for i in self.addlinkAction,self.resumeAction, self.pauseAction , self.stopAction, self.removeAction , self.deleteFileAction , self.propertiesAction, self.progressAction , self.exitAction : self.toolBar.addAction(i) self.toolBar.insertSeparator(self.addlinkAction) self.toolBar.insertSeparator(self.resumeAction) self.toolBar.insertSeparator(self.removeSelectedAction) self.toolBar.insertSeparator(self.exitAction) self.toolBar.addSeparator() for i in range(self.download_table.rowCount()): item_text = self.download_table.item(i , 0).text() item = QTableWidgetItem(item_text) self.download_table.setItem(i , 0 , item) self.selectAllAction.setEnabled(False) self.removeSelectedAction.setEnabled(False) self.deleteSelectedAction.setEnabled(False) def selectAll(self,menu): for i in range(self.download_table.rowCount()): item = self.download_table.item(i , 0) item.setCheckState(QtCore.Qt.Checked) def removeSelected(self,menu): global remove_flag remove_flag = 1 while remove_flag != 2 : sleep(0.1) gid_list = [] for row in range(self.download_table.rowCount()): status = self.download_table.item(row , 1).text() item = self.download_table.item(row , 0) if (item.checkState() == 2) and (status == 'complete' or status == 'error' or status == 'stopped' ): gid = self.download_table.item(row , 8 ).text() gid_list.append(gid) for gid in gid_list: for i in range(self.download_table.rowCount()): row_gid = self.download_table.item(i , 8).text() if gid == row_gid : row = i break file_name = self.download_table.item(row , 0).text() sleep(0.5) self.download_table.removeRow(row) #remove gid of download from download list file f = Open(download_list_file) download_list_file_lines = f.readlines() f.close() f = Open(download_list_file , "w") for i in download_list_file_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove gid of download from active download list file f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() f = Open(download_list_file_active , "w") for i in download_list_file_active_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove download_info_file download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) f.close() f.remove() #remove file of download form download temp folder if file_name != '***' and status != 'complete' : file_name_path = temp_download_folder + "/" + str(file_name) os.system('rm "' + str(file_name_path) +'"') file_name_aria = file_name_path + str('.aria2') os.system('rm "' + str(file_name_aria) +'"') remove_flag = 0 def deleteSelected(self,menu): global remove_flag remove_flag = 1 while remove_flag != 2 : sleep(0.1) gid_list = [] for row in range(self.download_table.rowCount()): status = self.download_table.item(row , 1).text() item = self.download_table.item(row , 0) if (item.checkState() == 2) and (status == 'complete' or status == 'error' or status == 'stopped' ): gid = self.download_table.item(row , 8 ).text() gid_list.append(gid) for gid in gid_list: for i in range(self.download_table.rowCount()): row_gid = self.download_table.item(i , 8).text() if gid == row_gid : row = i break file_name = self.download_table.item(row , 0).text() add_link_dictionary_str = self.download_table.item(row , 9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str) sleep(0.5) self.download_table.removeRow(row) #remove gid of download from download list file f = Open(download_list_file) download_list_file_lines = f.readlines() f.close() f = Open(download_list_file , "w") for i in download_list_file_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove gid of download from active download list file f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() f = Open(download_list_file_active , "w") for i in download_list_file_active_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove download_info_file download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) f.close() f.remove() #remove file of download form download temp folder if file_name != '***' and status != 'complete' : file_name_path = temp_download_folder + "/" + str(file_name) os.system('rm "' + str(file_name_path) +'"') file_name_aria = file_name_path + str('.aria2') os.system('rm "' + str(file_name_aria) +'"') #remove download file if status == 'complete': if 'file_path' in add_link_dictionary: file_path = add_link_dictionary['file_path'] if os.path.isfile(file_path): os.system("rm '" + file_path + "'" ) else: notifySend(str(file_path) ,'Not Found' , 5000 , 'warning' , systemtray = self.system_tray_icon ) remove_flag = 0
class MainWindow(MainWindow_Ui): def __init__(self): super().__init__() self.statusbar.showMessage('Please Wait ...') #threads self.threadPool=[] #starting aria start_aria = StartAria2Thread() self.threadPool.append(start_aria) self.threadPool[0].start() self.threadPool[0].ARIA2RESPONDSIGNAL.connect(self.startAriaMessage) #initializing #add downloads to the download_table f_download_list_file = Open(download_list_file) download_list_file_lines = f_download_list_file.readlines() f_download_list_file.close() for line in download_list_file_lines: gid = line.strip() self.download_table.insertRow(0) download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) download_info_file_lines = f.readlines() f.close() for i in range(10): item = QTableWidgetItem(download_info_file_lines[i].strip()) self.download_table.setItem(0 , i , item) row_numbers = self.download_table.rowCount() for row in range(row_numbers): status = self.download_table.item(row , 1).text() if (status != "complete" and status != "error"): gid = self.download_table.item(row,8).text() add_link_dictionary_str = self.download_table.item(row,9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str.strip()) add_link_dictionary['start_hour'] = None add_link_dictionary['start_minute'] = None add_link_dictionary['end_hour'] = None add_link_dictionary['end_minute'] = None add_link_dictionary['after_download'] = 'None' download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) download_info_file_lines = f.readlines() f.close() f = Open(download_info_file , "w") for i in range(10): if i == 1 : f.writelines("stopped" + "\n") item = QTableWidgetItem('stopped') self.download_table.setItem(row , i , item ) elif i == 9 : f.writelines(str(add_link_dictionary) + "\n") item = QTableWidgetItem(str(add_link_dictionary)) self.download_table.setItem(row,i , item) else: f.writelines(download_info_file_lines[i].strip() + "\n") f.close() self.addlinkwindows_list = [] self.propertieswindows_list = [] self.progress_window_list = [] self.progress_window_list_dict = {} check_download_info = CheckDownloadInfoThread() self.threadPool.append(check_download_info) self.threadPool[1].start() self.threadPool[1].DOWNLOAD_INFO_SIGNAL.connect(self.checkDownloadInfo) check_selected_row = CheckSelectedRowThread() self.threadPool.append(check_selected_row) self.threadPool[2].start() self.threadPool[2].CHECKSELECTEDROWSIGNAL.connect(self.checkSelectedRow) check_flashgot = CheckFlashgot() self.threadPool.append(check_flashgot) self.threadPool[3].start() self.threadPool[3].CHECKFLASHGOTSIGNAL.connect(self.checkFlashgot) self.system_tray_icon = QSystemTrayIcon() self.system_tray_icon.setIcon(QIcon('icon')) system_tray_menu = QMenu() system_tray_menu.addAction(self.addlinkAction) system_tray_menu.addAction(self.pauseAllAction) system_tray_menu.addAction(self.stopAllAction) system_tray_menu.addAction(self.minimizeAction) system_tray_menu.addAction(self.exitAction) self.system_tray_icon.setContextMenu(system_tray_menu) self.system_tray_icon.activated.connect(self.systemTrayPressed) self.system_tray_icon.show() def startAriaMessage(self,message): global aria_startup_answer if message == 'yes': sleep (2) self.statusbar.showMessage('Ready...') aria_startup_answer = 'ready' else: self.statusbar.showMessage('Error...') notifySend('Persepolis can not connect to Aria2' , 'Restart Persepolis' ,10000,'critical' ) def checkDownloadInfo(self,gid): try: #get download information from download_info_file according to gid and write them in download_table cells download_info_file = config_folder + "/download_info/" + gid f = Open(download_info_file) download_info_file_lines = f.readlines() f.close() #finding row of this gid! for i in range(self.download_table.rowCount()): row_gid = self.download_table.item(i , 8).text() if gid == row_gid : row = i break for i in range(10): #remove gid of completed download from active downloads list file if i == 1 : status = download_info_file_lines[i].strip() status = str(status) status_download_table = str(self.download_table.item(row , 1 ) . text()) if status == "complete": f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() f = Open(download_list_file_active , "w") for line in download_list_file_active_lines : if line.strip() != gid : f.writelines(line.strip() + "\n") f.close() #update download_table cells item = QTableWidgetItem(download_info_file_lines[i].strip()) self.download_table.setItem(row , i , item) self.download_table.viewport().update() #update progresswindow try : member_number = self.progress_window_list_dict[gid] progress_window = self.progress_window_list[member_number] #link add_link_dictionary_str = str(download_info_file_lines[9].strip()) add_link_dictionary = ast.literal_eval(add_link_dictionary_str) link = "<b>Link</b> : " + str(add_link_dictionary ['link']) progress_window.link_label.setText(link) progress_window.setToolTip(link) #Save as final_download_path = add_link_dictionary['final_download_path'] if final_download_path == None : final_download_path = str(add_link_dictionary['download_path']) save_as = "<b>Save as</b> : " + final_download_path + "/" + str(download_info_file_lines[0].strip()) progress_window.save_label.setText(save_as) file_name = str(download_info_file_lines[0].strip()) if file_name != "***": progress_window.setWindowTitle(file_name ) #status progress_window.status = download_info_file_lines[1].strip() status = "<b>status</b> : " + progress_window.status progress_window.status_label.setText(status) if progress_window.status == "downloading": progress_window.resume_pushButton.setEnabled(False) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(True) elif progress_window.status == "paused": progress_window.resume_pushButton.setEnabled(True) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(False) elif progress_window.status == "waiting": progress_window.resume_pushButton.setEnabled(False) progress_window.stop_pushButton.setEnabled(False) progress_window.pause_pushButton.setEnabled(False) elif progress_window.status == "scheduled": progress_window.resume_pushButton.setEnabled(False) progress_window.stop_pushButton.setEnabled(True) progress_window.pause_pushButton.setEnabled(False) elif progress_window.status == "stopped" or progress_window.status == "error" or progress_window.status == "complete" : progress_window.close() self.progress_window_list[member_number] = [] del self.progress_window_list_dict[gid] if progress_window.status == "complete": notifySend("Download Complete" ,str(download_info_file_lines[0]) , 10000 , 'ok' ) elif progress_window.status == "stopped": notifySend("Download Stopped" , str(download_info_file_lines[0]) , 10000 , 'no') elif progress_window.status == "error": notifySend("Download Error" , str(download_info_file_lines[0]) , 10000 , 'fail') add_link_dictionary['start_hour'] = None add_link_dictionary['start_minute'] = None add_link_dictionary['end_hour'] = None add_link_dictionary['end_minute'] = None add_link_dictionary['after_download'] = 'None' f = Open(download_info_file , "w") for i in range(10): if i == 9 : f.writelines(str(add_link_dictionary) + "\n") else: f.writelines(download_info_file_lines[i].strip() + "\n") f.close() if os.path.isfile('/tmp/persepolis/shutdown/' + gid ) == True and progress_window.status != 'stopped': answer = download.shutDown() if answer == 'error': os.system('killall aria2c') f = Open('/tmp/persepolis/shutdown/' + gid , 'w') f.writelines('shutdown') f.close() elif os.path.isfile('/tmp/persepolis/shutdown/' + gid ) == True and progress_window.status == 'stopped': f = Open('/tmp/persepolis/shutdown/' + gid , 'w') f.writelines('canceled') f.close() #downloaded downloaded = "<b>Downloaded</b> : " + str(download_info_file_lines[3].strip()) + "/" + str(download_info_file_lines[2].strip()) progress_window.downloaded_label.setText(downloaded) #Transfer rate rate = "<b>Transfer rate</b> : " + str(download_info_file_lines[6].strip()) progress_window.rate_label.setText(rate) #Estimate time left estimate_time_left = "<b>Estimate time left</b> : " + str(download_info_file_lines[7].strip()) progress_window.time_label.setText(estimate_time_left) #Connections connections = "<b>Connections</b> : " + str(download_info_file_lines[5].strip()) progress_window.connections_label.setText(connections) #progressbar value = download_info_file_lines[4].strip() value = value[:-1] progress_window.download_progressBar.setValue(int(value)) except : pass except: pass #contex menu def contextMenuEvent(self, event): self.tablewidget_menu = QMenu(self) self.tablewidget_menu.addAction(self.resumeAction) self.tablewidget_menu.addAction(self.pauseAction) self.tablewidget_menu.addAction(self.stopAction) self.tablewidget_menu.addAction(self.removeAction) self.tablewidget_menu.addAction(self.propertiesAction) self.tablewidget_menu.addAction(self.progressAction) self.tablewidget_menu.popup(QtGui.QCursor.pos()) #drag and drop for links def dragEnterEvent(self, droplink): text = str(droplink.mimeData().text()) if ("tp:/" in text[2:6]) or ("tps:/" in text[2:7]) : droplink.accept() else: droplink.ignore() def dropEvent(self, droplink): link_clipborad = QApplication.clipboard() link_clipborad.clear(mode=link_clipborad.Clipboard ) link_string = droplink.mimeData().text() link_clipborad.setText(str(link_string), mode=link_clipborad.Clipboard) self.addLinkButtonPressed(button =link_clipborad ) def gidGenerator(self): my_gid = hex(random.randint(1152921504606846976,18446744073709551615)) my_gid = my_gid[2:18] my_gid = str(my_gid) f = Open(download_list_file_active) active_gid_list = f.readlines() f.close() while my_gid in active_gid_list : my_gid = self.gidGenerator() active_gids = download.activeDownloads() while my_gid in active_gids: my_gid = self.gidGenerator() return my_gid def selectedRow(self): try: item = self.download_table.selectedItems() selected_row_return = self.download_table.row(item[1]) download_info = self.download_table.item(selected_row_return , 9).text() download_info = ast.literal_eval(download_info) link = download_info['link'] self.statusbar.showMessage(str(link)) except : selected_row_return = None return selected_row_return def checkSelectedRow(self): try: item = self.download_table.selectedItems() selected_row_return = self.download_table.row(item[1]) except : selected_row_return = None if selected_row_return != None : status = self.download_table.item(selected_row_return , 1).text() if status == "scheduled": self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(False) self.stopAction.setEnabled(True) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) elif status == "stopped" or status == "error" : self.stopAction.setEnabled(False) self.pauseAction.setEnabled(False) self.resumeAction.setEnabled(True) self.removeAction.setEnabled(True) self.propertiesAction.setEnabled(True) self.progressAction.setEnabled(False) elif status == "downloading": self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(True) self.stopAction.setEnabled(True) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) elif status == "waiting": self.stopAction.setEnabled(False) self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) elif status == "complete": self.stopAction.setEnabled(False) self.resumeAction.setEnabled(False) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(True) self.propertiesAction.setEnabled(True) self.progressAction.setEnabled(False) elif status == "paused": self.stopAction.setEnabled(True) self.resumeAction.setEnabled(True) self.pauseAction.setEnabled(False) self.removeAction.setEnabled(False) self.propertiesAction.setEnabled(False) self.progressAction.setEnabled(True) else: self.resumeAction.setEnabled(True) self.stopAction.setEnabled(True) self.pauseAction.setEnabled(True) self.propertiesAction.setEnabled(True) else: self.resumeAction.setEnabled(True) self.stopAction.setEnabled(True) self.pauseAction.setEnabled(True) self.removeAction.setEnabled(True) self.propertiesAction.setEnabled(True) def checkFlashgot(self): sleep(0.5) flashgot_file = Open("/tmp/persepolis-flashgot") flashgot_line = flashgot_file.readlines() flashgot_file.close() flashgot_file.remove() flashgot_add_link_dictionary_str = flashgot_line[0] flashgot_add_link_dictionary = ast.literal_eval(flashgot_add_link_dictionary_str) self.flashgotAddLink(flashgot_add_link_dictionary) def flashgotAddLink(self,flashgot_add_link_dictionary): addlinkwindow = AddLinkWindow(self.callBack , flashgot_add_link_dictionary) self.addlinkwindows_list.append(addlinkwindow) self.addlinkwindows_list[len(self.addlinkwindows_list) - 1].show() def addLinkButtonPressed(self ,button): addlinkwindow = AddLinkWindow(self.callBack) self.addlinkwindows_list.append(addlinkwindow) self.addlinkwindows_list[len(self.addlinkwindows_list) - 1].show() def callBack(self , add_link_dictionary): gid = self.gidGenerator() download_info_file_list = ['***','waiting','***','***','***','***','***','***',gid , str(add_link_dictionary)] download_info_file = config_folder + "/download_info/" + gid os.system("touch " + download_info_file ) f = Open(download_info_file , "w") for i in range(10): f.writelines(download_info_file_list[i] + "\n") f.close() self.download_table.insertRow(0) j = 0 for i in download_info_file_list : item = QTableWidgetItem(i) self.download_table.setItem(0,j,item) j = j + 1 f = Open (download_list_file , "a") f.writelines(gid + "\n") f.close() f = Open (download_list_file_active , "a") f.writelines(gid + "\n") f.close() new_download = DownloadLink(gid) self.threadPool.append(new_download) self.threadPool[len(self.threadPool) - 1].start() self.progressBarOpen(gid) if add_link_dictionary['start_hour'] == None : message = "Download Starts" else: message = "Download Scheduled" notifySend(message ,'' , 10000 , 'no') def resumeButtonPressed(self,button): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() download_status = self.download_table.item(selected_row_return , 1).text() if download_status == "paused" : answer = download.downloadUnpause(gid) if answer == 'None': notifySend("Aria2 did not respond!","Try agian!",10000,'warning' ) else: new_download = DownloadLink(gid) self.threadPool.append(new_download) self.threadPool[len(self.threadPool) - 1].start() sleep(1) self.progressBarOpen(gid) else: self.statusbar.showMessage("Please select an item first!") def stopButtonPressed(self,button): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() answer = download.downloadStop(gid) if answer == 'None': notifySend("Aria2 did not respond!","Try agian!" , 10000 , 'critical' ) else: self.statusbar.showMessage("Please select an item first!") def pauseButtonPressed(self,button): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() answer = download.downloadPause(gid) if answer == 'None': notifySend("Aria2 did not respond!" , "Try agian!" , 10000 , 'critical' ) else: self.statusbar.showMessage("Please select an item first!") sleep(1) def removeButtonPressed(self,button): self.removeAction.setEnabled(False) selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() try: file_name = self.download_table.item(selected_row_return , 0).text() except: file_name = None sleep(0.5) self.download_table.removeRow(selected_row_return) #remove gid of download from download list file f = Open(download_list_file) download_list_file_lines = f.readlines() f.close() f = Open(download_list_file , "w") for i in download_list_file_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove gid of download from active download list file f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() f = Open(download_list_file_active , "w") for i in download_list_file_active_lines: if i.strip() != gid: f.writelines(i.strip() + "\n") f.close() #remove download_info_file download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) f.close() f.remove() #remove file of download form download temp folder if file_name != None : file_name_path = temp_download_folder + "/" + str(file_name) os.system('rm "' + str(file_name_path) +'"') file_name_aria = file_name_path + str('.aria2') os.system('rm "' + str(file_name_aria) +'"') else: self.statusbar.showMessage("Please select an item first!") self.selectedRow() def propertiesButtonPressed(self,button): selected_row_return = self.selectedRow() if selected_row_return != None : add_link_dictionary_str = self.download_table.item(selected_row_return , 9).text() add_link_dictionary = ast.literal_eval(add_link_dictionary_str) gid = self.download_table.item(selected_row_return , 8 ).text() propertieswindow = PropertiesWindow(self.propertiesCallback ,gid) self.propertieswindows_list.append(propertieswindow) self.propertieswindows_list[len(self.propertieswindows_list) - 1].show() def propertiesCallback(self,add_link_dictionary , gid ): download_info_file = download_info_folder + "/" + gid f = Open(download_info_file) download_info_file_lines = f.readlines() f.close() f = Open(download_info_file , "w") for i in range(10): if i == 9 : f.writelines(str(add_link_dictionary) + "\n") else: f.writelines(download_info_file_lines[i].strip() + "\n") f.close() def progressButtonPressed(self,button): selected_row_return = self.selectedRow() if selected_row_return != None: gid = self.download_table.item(selected_row_return , 8 ).text() member_number = self.progress_window_list_dict[gid] if self.progress_window_list[member_number].isVisible() == False: self.progress_window_list[member_number].show() else : self.progress_window_list[member_number].hide() def progressBarOpen(self,gid): progress_window = ProgressWindow(gid) self.progress_window_list.append(progress_window) member_number = len(self.progress_window_list) - 1 self.progress_window_list_dict[gid] = member_number self.progress_window_list[member_number].show() #close event def closeEvent(self, event): self.hide() self.system_tray_icon.hide() download.shutDown() sleep(0.5) global shutdown_notification shutdown_notification = 1 while shutdown_notification != 2: sleep (0.1) QCoreApplication.instance().closeAllWindows() for qthread in self.threadPool : try: qthread.exit(0) sleep(0.1) answer = qthread.isRunning() print(answer) except: print("not quit") QCoreApplication.instance().quit print("Persepolis Closed") def systemTrayPressed(self,click): if click == 3 : self.minMaxTray(click) def minMaxTray(self,menu): if self.isVisible() == False: self.minimizeAction.setText('Minimize to system tray') self.minimizeAction.setIcon(QIcon(icons + 'minimize')) self.show() else : self.hide() self.minimizeAction.setText('Show main Window') self.minimizeAction.setIcon(QIcon(icons + 'window')) def stopAllDownloads(self,menu): active_gids = [] for i in range(self.download_table.rowCount()): try: row_status = self.download_table.item(i , 1).text() if row_status == 'downloading' or row_status == 'paused' or row_status == 'waiting': row_gid = self.download_table.item(i , 8).text() active_gids.append(row_gid) except : pass for gid in active_gids: answer = download.downloadStop(gid) if answer == 'None': notifySend("Aria2 did not respond!" , "Try agian!" , 10000 , 'critical' ) sleep(0.3) def pauseAllDownloads(self,menu): #get active gid of downloads from aria active_gids = download.activeDownloads() #check that if gid is in download_list_file_active f = Open(download_list_file_active) download_list_file_active_lines = f.readlines() f.close() for i in range(len(download_list_file_active_lines)): download_list_file_active_lines[i] = download_list_file_active_lines[i].strip() for gid in active_gids : if gid in download_list_file_active_lines : answer = download.downloadPause(gid) if answer == 'None': notifySend("Aria2 did not respond!" , "Try agian!" , 10000 , 'critical' ) sleep(0.3) def openPreferences(self,menu): self.preferenceswindow = PreferencesWindow() self.preferenceswindow.show() def openAbout(self,menu): self.about_window = AboutWindow() self.about_window.show()
class RootPainter(QtWidgets.QMainWindow): closed = QtCore.pyqtSignal() def __init__(self, sync_dir): super().__init__() self.sync_dir = sync_dir self.instruction_dir = sync_dir / 'instructions' self.send_instruction = partial(send_instruction, instruction_dir=self.instruction_dir, sync_dir=sync_dir) self.tracking = False self.image_pixmap_holder = None self.seg_pixmap_holder = None self.annot_pixmap_holder = None self.image_visible = True self.seg_visible = False self.annot_visible = True self.pre_segment_count = 0 self.im_width = None self.im_height = None self.initUI() def mouse_scroll(self, event): scroll_up = event.angleDelta().y() > 0 modifiers = QtWidgets.QApplication.keyboardModifiers() alt_down = (modifiers & QtCore.Qt.AltModifier) shift_down = (modifiers & QtCore.Qt.ShiftModifier) if alt_down or shift_down: # change by 10% (nearest int) or 1 (min) increment = max(1, int(round(self.scene.brush_size / 10))) if scroll_up: self.scene.brush_size += increment else: self.scene.brush_size -= increment self.scene.brush_size = max(1, self.scene.brush_size) self.update_cursor() else: if scroll_up: self.graphics_view.zoom *= 1.1 else: self.graphics_view.zoom /= 1.1 self.graphics_view.update_zoom() def initUI(self): if len(sys.argv) < 2: self.init_missing_project_ui() return fname = sys.argv[1] if os.path.splitext(fname)[1] == '.seg_proj': proj_file_path = os.path.abspath(sys.argv[1]) self.open_project(proj_file_path) else: # only warn if -psn not in the args. -psn is in the args when # user opened app in a normal way by clicking on the Application icon. if not '-psn' in sys.argv[1]: QtWidgets.QMessageBox.about( self, 'Error', sys.argv[1] + ' is not a valid ' 'segmentation project (.seg_proj) file') self.init_missing_project_ui() def open_project(self, proj_file_path): # extract json with open(proj_file_path, 'r') as json_file: settings = json.load(json_file) self.dataset_dir = self.sync_dir / 'datasets' / PurePath( settings['dataset']) self.proj_location = self.sync_dir / PurePath(settings['location']) self.image_fnames = settings['file_names'] self.seg_dir = self.proj_location / 'segmentations' self.log_dir = self.proj_location / 'logs' self.train_annot_dir = self.proj_location / 'annotations' / 'train' self.val_annot_dir = self.proj_location / 'annotations' / 'val' self.model_dir = self.proj_location / 'models' self.message_dir = self.proj_location / 'messages' self.proj_file_path = proj_file_path # If there are any annotations which have already been saved # then go through the annotations in the order specified # by self.image_fnames # and set fname (current image) to be the last image with annotation last_with_annot = last_fname_with_annotations( self.image_fnames, self.train_annot_dir, self.val_annot_dir) if last_with_annot: fname = last_with_annot else: fname = self.image_fnames[0] # manual override for the image to show if 'image_index' in settings: fname = self.image_fnames[settings['image_index']] # set first image from project to be current image self.image_path = os.path.join(self.dataset_dir, fname) self.update_window_title() self.seg_path = os.path.join(self.seg_dir, fname) self.annot_path = get_annot_path(fname, self.train_annot_dir, self.val_annot_dir) self.init_active_project_ui() self.track_changes() def update_file(self, fpath): # Save current annotation (if it exists) before moving on self.save_annotation() # save current annotation first fname = os.path.basename(fpath) # set first image from project to be current image self.image_path = os.path.join(self.dataset_dir, fname) self.png_fname = os.path.splitext(fname)[0] + '.png' self.seg_path = os.path.join(self.seg_dir, self.png_fname) self.annot_path = get_annot_path(self.png_fname, self.train_annot_dir, self.val_annot_dir) self.update_image() self.scene.history = [] self.scene.redo_list = [] self.update_seg() self.update_annot() self.segment_current_image() self.update_window_title() def update_image(self): # Will also update self.im_width and self.im_height assert os.path.isfile( self.image_path), f"Cannot find file {self.image_path}" image_pixmap = QtGui.QPixmap(self.image_path) im_size = image_pixmap.size() im_width, im_height = im_size.width(), im_size.height() assert im_width > 0, self.image_path assert im_height > 0, self.image_path self.graphics_view.image = image_pixmap # for resize later self.im_width = im_width self.im_height = im_height self.scene.setSceneRect(-15, -15, im_width + 30, im_height + 30) # Used to replace the segmentation or annotation when they are not visible. self.blank_pixmap = QtGui.QPixmap(self.im_width, self.im_height) self.blank_pixmap.fill(Qt.transparent) self.black_pixmap = QtGui.QPixmap(self.im_width, self.im_height) self.black_pixmap.fill(Qt.black) if self.image_pixmap_holder: self.image_pixmap_holder.setPixmap(image_pixmap) else: self.image_pixmap_holder = self.scene.addPixmap(image_pixmap) if not self.image_visible: self.image_pixmap_holder.setPixmap(self.black_pixmap) def update_seg(self): # if seg file is present then load. if os.path.isfile(self.seg_path): self.seg_mtime = os.path.getmtime(self.seg_path) self.seg_pixmap = QtGui.QPixmap(self.seg_path) self.nav.next_image_button.setText('Save && Next >') if hasattr(self, 'vis_widget'): self.vis_widget.seg_checkbox.setText('Segmentation (S)') self.nav.next_image_button.setEnabled(True) else: self.seg_mtime = None # otherwise use blank self.seg_pixmap = QtGui.QPixmap(self.im_width, self.im_height) self.seg_pixmap.fill(Qt.transparent) painter = QtGui.QPainter() painter.begin(self.seg_pixmap) font = QtGui.QFont() font.setPointSize(48) painter.setFont(font) painter.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255))) painter.setBrush( QtGui.QBrush(QtGui.QColor(255, 255, 255), Qt.SolidPattern)) if sys.platform == 'win32': # For some reason the text has a different size # and position on windows # so change the background rectangle also. painter.drawRect(0, 0, 657, 75) else: painter.drawRect(10, 10, 465, 55) painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0, 150))) painter.drawText(16, 51, 'Loading segmentation') painter.end() self.nav.next_image_button.setText('Loading Segmentation...') if hasattr(self, 'vis_widget'): self.vis_widget.seg_checkbox.setText('Segmentation (Loading)') self.nav.next_image_button.setEnabled(False) if self.seg_pixmap_holder: self.seg_pixmap_holder.setPixmap(self.seg_pixmap) else: self.seg_pixmap_holder = self.scene.addPixmap(self.seg_pixmap) if not self.seg_visible: self.seg_pixmap_holder.setPixmap(self.blank_pixmap) def update_annot(self): # if annot file is present then load if self.annot_path and os.path.isfile(self.annot_path): self.annot_pixmap = QtGui.QPixmap(self.annot_path) else: # otherwise use blank self.annot_pixmap = QtGui.QPixmap(self.im_width, self.im_height) self.annot_pixmap.fill(Qt.transparent) if self.annot_pixmap_holder: self.annot_pixmap_holder.setPixmap(self.annot_pixmap) else: self.annot_pixmap_holder = self.scene.addPixmap(self.annot_pixmap) self.scene.annot_pixmap_holder = self.annot_pixmap_holder self.scene.annot_pixmap = self.annot_pixmap self.scene.history.append(self.scene.annot_pixmap.copy()) if not self.annot_visible: self.annot_pixmap_holder.setPixmap(self.blank_pixmap) def segment_image(self, image_fnames): # send instruction to segment the new image. content = { "dataset_dir": self.dataset_dir, "seg_dir": self.seg_dir, "file_names": image_fnames, "message_dir": self.message_dir, "model_dir": self.model_dir } self.send_instruction('segment', content) def segment_current_image(self): dir_path, _ = os.path.split(self.image_path) path_list = self.nav.get_path_list(dir_path) cur_index = path_list.index(self.image_path) to_segment_paths = path_list[cur_index:1 + cur_index + self.pre_segment_count] to_segment_paths = [ f for f in to_segment_paths if os.path.isfile(os.path.join(self.seg_dir, f)) ] to_segment_fnames = [os.path.basename(p) for p in to_segment_paths] self.segment_image(to_segment_fnames) def show_open_project_widget(self): options = QtWidgets.QFileDialog.Options() default_loc = self.sync_dir / 'projects' file_path, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Load project file", str(default_loc), "Segmentation project file (*.seg_proj)", options=options) if file_path: self.open_project(file_path) def show_create_project_widget(self): print("Open the create project widget..") self.create_project_widget = CreateProjectWidget(self.sync_dir) self.create_project_widget.show() self.create_project_widget.created.connect(self.open_project) def init_missing_project_ui(self): ## Create project menu # project has not yet been selected or created # need to open minimal interface which allows users # to open or create a project. menu_bar = self.menuBar() self.menu_bar = menu_bar self.menu_bar.clear() self.project_menu = menu_bar.addMenu("Project") # Open project self.open_project_action = QtWidgets.QAction(QtGui.QIcon(""), "Open project", self) self.open_project_action.setShortcut("Ctrl+O") self.project_menu.addAction(self.open_project_action) self.open_project_action.triggered.connect( self.show_open_project_widget) # Create project self.create_project_action = QtWidgets.QAction(QtGui.QIcon(""), "Create project", self) self.create_project_action.setShortcut("Ctrl+C") self.project_menu.addAction(self.create_project_action) self.create_project_action.triggered.connect( self.show_create_project_widget) # Network Menu self.network_menu = menu_bar.addMenu('Network') # # segment folder self.segment_folder_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Segment folder', self) def show_segment_folder(): self.segment_folder_widget = SegmentFolderWidget( self.sync_dir, self.instruction_dir) self.segment_folder_widget.show() self.segment_folder_btn.triggered.connect(show_segment_folder) self.network_menu.addAction(self.segment_folder_btn) self.add_measurements_menu(menu_bar) self.add_extras_menu(menu_bar) self.add_about_menu(menu_bar) ### Add project btns to open window (so it shows something useful) project_btn_widget = QtWidgets.QWidget() self.setCentralWidget(project_btn_widget) layout = QtWidgets.QHBoxLayout() project_btn_widget.setLayout(layout) open_project_btn = QtWidgets.QPushButton('Open existing project') open_project_btn.clicked.connect(self.show_open_project_widget) layout.addWidget(open_project_btn) create_project_btn = QtWidgets.QPushButton('Create new project') create_project_btn.clicked.connect(self.show_create_project_widget) layout.addWidget(create_project_btn) create_dataset_btn = QtWidgets.QPushButton('Create training dataset') def show_create_dataset(): self.create_dataset_widget = CreateDatasetWidget(self.sync_dir) self.create_dataset_widget.show() create_dataset_btn.clicked.connect(show_create_dataset) layout.addWidget(create_dataset_btn) self.setWindowTitle("RootPainter") self.resize(layout.sizeHint()) def add_extras_menu(self, menu_bar, project_open=False): extras_menu = menu_bar.addMenu('Extras') comp_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Extract composites', self) comp_btn.triggered.connect(self.show_extract_comp) extras_menu.addAction(comp_btn) conv_to_rve_btn = QtWidgets.QAction( QtGui.QIcon('missing.png'), 'Convert segmentations for RhizoVision Explorer', self) conv_to_rve_btn.triggered.connect(self.show_conv_to_rve) extras_menu.addAction(conv_to_rve_btn) if project_open: extend_dataset_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Extend dataset', self) def update_dataset_after_check(): was_extended, file_names = check_extend_dataset( self, self.dataset_dir, self.image_fnames, self.proj_file_path) if was_extended: self.image_fnames = file_names self.nav.all_fnames = file_names self.nav.update_nav_label() extend_dataset_btn.triggered.connect(update_dataset_after_check) extras_menu.addAction(extend_dataset_btn) def add_about_menu(self, menu_bar): about_menu = menu_bar.addMenu('About') license_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'License', self) license_btn.triggered.connect(self.show_license_window) about_menu.addAction(license_btn) about_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'RootPainter', self) about_btn.triggered.connect(self.show_about_window) about_menu.addAction(about_btn) def show_license_window(self): self.license_window = LicenseWindow() self.license_window.show() def show_about_window(self): self.about_window = AboutWindow() self.about_window.show() def update_window_title(self): proj_dirname = os.path.basename(self.proj_location) self.setWindowTitle(f"RootPainter {proj_dirname}" f" {os.path.basename(self.image_path)}") def init_active_project_ui(self): # container for both nav and graphics view. container = QtWidgets.QWidget() container_layout = QtWidgets.QVBoxLayout() container_layout.setContentsMargins(0, 0, 0, 0) container.setLayout(container_layout) self.setCentralWidget(container) self.graphics_view = CustomGraphicsView() self.graphics_view.zoom_change.connect(self.update_cursor) container_layout.addWidget(self.graphics_view) scene = GraphicsScene() scene.parent = self self.graphics_view.setScene(scene) self.graphics_view.mouse_scroll_event.connect(self.mouse_scroll) # Required so graphics scene can track mouse up when mouse is not pressed self.graphics_view.setMouseTracking(True) self.scene = scene self.nav = NavWidget(self.image_fnames) self.update_file(self.image_path) # bottom bar bottom_bar = QtWidgets.QWidget() bottom_bar_layout = QtWidgets.QHBoxLayout() # left, top, right, bottom bottom_bar_layout.setContentsMargins(20, 0, 20, 20) bottom_bar_layout.setSpacing(0) bottom_bar.setLayout(bottom_bar_layout) container_layout.addWidget(bottom_bar) # Bottom bar left self.vis_widget = VisibilityWidget() self.vis_widget.setMaximumWidth(200) self.vis_widget.setMinimumWidth(200) self.vis_widget.seg_checkbox.stateChanged.connect( self.seg_checkbox_change) self.vis_widget.annot_checkbox.stateChanged.connect( self.annot_checkbox_change) self.vis_widget.im_checkbox.stateChanged.connect( self.im_checkbox_change) bottom_bar_layout.addWidget(self.vis_widget) # bottom bar right bottom_bar_r = QtWidgets.QWidget() bottom_bar_r_layout = QtWidgets.QVBoxLayout() bottom_bar_r.setLayout(bottom_bar_r_layout) bottom_bar_layout.addWidget(bottom_bar_r) # Nav self.nav.file_change.connect(self.update_file) self.nav.image_path = self.image_path self.nav.update_nav_label() # info label info_container = QtWidgets.QWidget() info_container_layout = QtWidgets.QHBoxLayout() info_container_layout.setAlignment(Qt.AlignCenter) info_label = QtWidgets.QLabel() info_label.setText("") info_container_layout.addWidget(info_label) # left, top, right, bottom info_container_layout.setContentsMargins(0, 0, 0, 0) info_container.setLayout(info_container_layout) self.info_label = info_label bottom_bar_r_layout.addWidget(info_container) bottom_bar_r_layout.addWidget(self.nav) self.add_menu() self.resize(container_layout.sizeHint()) self.update_cursor() def view_fix(): """ hack for linux bug """ self.update_cursor() self.graphics_view.fit_to_view() QtCore.QTimer.singleShot(100, view_fix) def track_changes(self): if self.tracking: return print('Starting watch for changes') self.tracking = True def check(): # check for any messages messages = os.listdir(str(self.message_dir)) for m in messages: if hasattr(self, 'info_label'): self.info_label.setText(m) try: # Added try catch because this error happened (very rarely) # PermissionError: [WinError 32] # The process cannot access the file because it is # being used by another process os.remove(os.path.join(self.message_dir, m)) except Exception as e: print('Caught exception when trying to detele msg', e) if hasattr(self, 'seg_path') and os.path.isfile(self.seg_path): try: # seg mtime is not actually used any more. new_mtime = os.path.getmtime(self.seg_path) # seg_mtime is None before the seg is loaded. if not self.seg_mtime: print('load seg from file.') self.seg_pixmap = QtGui.QPixmap(self.seg_path) self.seg_mtime = new_mtime self.nav.next_image_button.setText('Save && Next >') self.nav.next_image_button.setEnabled(True) if self.seg_visible: self.seg_pixmap_holder.setPixmap(self.seg_pixmap) if hasattr(self, 'vis_widget'): self.vis_widget.seg_checkbox.setText( 'Segmentation (S)') except Exception as e: print('Error: when trying to load segmention ' + str(e)) # sometimes problems reading file. # don't worry about this exception else: print('no seg found', end=",") QtCore.QTimer.singleShot(500, check) QtCore.QTimer.singleShot(500, check) def close_project_window(self): self.close() self.closed.emit() def add_menu(self): menu_bar = self.menuBar() menu_bar.clear() self.project_menu = menu_bar.addMenu("Project") self.close_project_action = QtWidgets.QAction(QtGui.QIcon(""), "Close project", self) self.project_menu.addAction(self.close_project_action) self.close_project_action.triggered.connect(self.close_project_window) edit_menu = menu_bar.addMenu("Edit") # Undo undo_action = QtWidgets.QAction(QtGui.QIcon(""), "Undo", self) undo_action.setShortcut("Z") edit_menu.addAction(undo_action) undo_action.triggered.connect(self.scene.undo) # Redo redo_action = QtWidgets.QAction(QtGui.QIcon(""), "Redo", self) redo_action.setShortcut("Ctrl+Shift+Z") edit_menu.addAction(redo_action) redo_action.triggered.connect(self.scene.redo) options_menu = menu_bar.addMenu("Options") # pre segment count pre_segment_count_action = QtWidgets.QAction(QtGui.QIcon(""), "Pre-Segment", self) options_menu.addAction(pre_segment_count_action) pre_segment_count_action.triggered.connect( self.open_pre_segment_count_dialog) # change brush colors change_foreground_color_action = QtWidgets.QAction( QtGui.QIcon(""), "Foreground brush colour", self) options_menu.addAction(change_foreground_color_action) change_foreground_color_action.triggered.connect( self.change_foreground_color) change_background_color_action = QtWidgets.QAction( QtGui.QIcon(""), "Background brush colour", self) options_menu.addAction(change_background_color_action) change_background_color_action.triggered.connect( self.change_background_color) brush_menu = menu_bar.addMenu("Brushes") foreground_color_action = QtWidgets.QAction(QtGui.QIcon(""), "Foreground", self) foreground_color_action.setShortcut("Q") brush_menu.addAction(foreground_color_action) foreground_color_action.triggered.connect(self.set_foreground_color) background_color_action = QtWidgets.QAction(QtGui.QIcon(""), "Background", self) background_color_action.setShortcut("W") brush_menu.addAction(background_color_action) background_color_action.triggered.connect(self.set_background_color) eraser_color_action = QtWidgets.QAction(QtGui.QIcon(""), "Eraser", self) eraser_color_action.setShortcut("E") brush_menu.addAction(eraser_color_action) eraser_color_action.triggered.connect(self.set_eraser_color) ## View menu # Fit to view view_menu = menu_bar.addMenu('View') fit_to_view_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Fit to View', self) fit_to_view_btn.setShortcut('Ctrl+F') fit_to_view_btn.setStatusTip('Fit image to view') fit_to_view_btn.triggered.connect(self.graphics_view.fit_to_view) view_menu.addAction(fit_to_view_btn) # Actual size actual_size_view_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Actual size', self) actual_size_view_btn.setShortcut('Ctrl+A') actual_size_view_btn.setStatusTip('Show image at actual size') actual_size_view_btn.triggered.connect( self.graphics_view.show_actual_size) view_menu.addAction(actual_size_view_btn) toggle_seg_visibility_btn = QtWidgets.QAction( QtGui.QIcon('missing.png'), 'Toggle segmentation visibility', self) toggle_seg_visibility_btn.setShortcut('S') toggle_seg_visibility_btn.setStatusTip('Show or hide segmentation') toggle_seg_visibility_btn.triggered.connect(self.show_hide_seg) view_menu.addAction(toggle_seg_visibility_btn) toggle_annot_visibility_btn = QtWidgets.QAction( QtGui.QIcon('missing.png'), 'Toggle annotation visibility', self) toggle_annot_visibility_btn.setShortcut('A') toggle_annot_visibility_btn.setStatusTip('Show or hide annotation') toggle_annot_visibility_btn.triggered.connect(self.show_hide_annot) view_menu.addAction(toggle_annot_visibility_btn) toggle_image_visibility_btn = QtWidgets.QAction( QtGui.QIcon('missing.png'), 'Toggle image visibility', self) toggle_image_visibility_btn.setShortcut('I') toggle_image_visibility_btn.setStatusTip('Show or hide image') toggle_image_visibility_btn.triggered.connect(self.show_hide_image) view_menu.addAction(toggle_image_visibility_btn) def zoom_in(): self.graphics_view.zoom *= 1.1 self.graphics_view.update_zoom() def zoom_out(): self.graphics_view.zoom /= 1.1 self.graphics_view.update_zoom() zoom_in_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Zoom in', self) zoom_in_btn.setShortcut('+') zoom_in_btn.setStatusTip('Zoom in') zoom_in_btn.triggered.connect(zoom_in) view_menu.addAction(zoom_in_btn) zoom_out_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Zoom out', self) zoom_out_btn.setShortcut('-') zoom_out_btn.setStatusTip('Zoom out') zoom_out_btn.triggered.connect(zoom_out) view_menu.addAction(zoom_out_btn) # Network Menu network_menu = menu_bar.addMenu('Network') # start training start_training_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Start training', self) start_training_btn.triggered.connect(self.start_training) network_menu.addAction(start_training_btn) # stop training stop_training_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Stop training', self) stop_training_btn.triggered.connect(self.stop_training) network_menu.addAction(stop_training_btn) # # segment folder segment_folder_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Segment folder', self) def show_segment_folder(): self.segment_folder_widget = SegmentFolderWidget( self.sync_dir, self.instruction_dir) self.segment_folder_widget.show() segment_folder_btn.triggered.connect(show_segment_folder) network_menu.addAction(segment_folder_btn) # segment current image # segment_image_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), # 'Segment current image', self) # segment_image_btn.triggered.connect(self.segment_current_image) # network_menu.addAction(segment_image_btn) self.add_measurements_menu(menu_bar) self.add_extras_menu(menu_bar, project_open=True) def add_measurements_menu(self, menu_bar): # Measurements measurements_menu = menu_bar.addMenu('Measurements') # object count object_count_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Extract count', self) def show_extract_count(): self.extract_count_widget = ExtractCountWidget() self.extract_count_widget.show() object_count_btn.triggered.connect(show_extract_count) measurements_menu.addAction(object_count_btn) # length length_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Extract length', self) def show_extract_length(): self.extract_length_widget = ExtractLengthWidget() self.extract_length_widget.show() length_btn.triggered.connect(show_extract_length) measurements_menu.addAction(length_btn) # region props region_props_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Extract region properties', self) def show_extract_region_props(): self.extract_regions_widget = ExtractRegionsWidget() self.extract_regions_widget.show() region_props_btn.triggered.connect(show_extract_region_props) measurements_menu.addAction(region_props_btn) def show_extract_comp(self): self.extract_comp_widget = ExtractCompWidget() self.extract_comp_widget.show() def show_conv_to_rve(self): """ show window to convert segmentations to RhizoVision Explorer compatible format """ self.convert_to_rve_widget = ConvertSegForRVEWidget() self.convert_to_rve_widget.show() def stop_training(self): self.info_label.setText("Stopping training...") content = {"message_dir": self.message_dir} self.send_instruction('stop_training', content) def start_training(self): self.info_label.setText("Starting training...") content = { "model_dir": self.model_dir, "dataset_dir": self.dataset_dir, "train_annot_dir": self.train_annot_dir, "val_annot_dir": self.val_annot_dir, "seg_dir": self.seg_dir, "log_dir": self.log_dir, "message_dir": self.message_dir } self.send_instruction('start_training', content) def seg_checkbox_change(self, state): checked = (state == QtCore.Qt.Checked) if checked is not self.seg_visible: self.show_hide_seg() def annot_checkbox_change(self, state): checked = (state == QtCore.Qt.Checked) if checked is not self.annot_visible: self.show_hide_annot() def im_checkbox_change(self, state): checked = (state == QtCore.Qt.Checked) if checked is not self.image_visible: self.show_hide_image() def show_hide_seg(self): # show or hide the current segmentation. if self.seg_visible: self.seg_pixmap_holder.setPixmap(self.blank_pixmap) self.seg_visible = False else: self.seg_pixmap_holder.setPixmap(self.seg_pixmap) self.seg_visible = True self.vis_widget.seg_checkbox.setChecked(self.seg_visible) def show_hide_image(self): # show or hide the current image. # Could be useful to help inspect the segmentation or annotation if self.image_visible: self.image_pixmap_holder.setPixmap(self.black_pixmap) self.image_visible = False else: self.image_pixmap_holder.setPixmap(self.graphics_view.image) self.image_visible = True self.vis_widget.im_checkbox.setChecked(self.image_visible) def show_hide_annot(self): # show or hide the current annotations. # Could be useful to help inspect the background image if self.annot_visible: self.annot_pixmap_holder.setPixmap(self.blank_pixmap) self.annot_visible = False else: self.scene.annot_pixmap_holder.setPixmap(self.scene.annot_pixmap) self.annot_visible = True self.vis_widget.annot_checkbox.setChecked(self.annot_visible) def set_foreground_color(self, _event): self.scene.brush_color = self.scene.foreground_color self.update_cursor() def change_foreground_color(self, _event): foreground_set = ( self.scene.brush_color == self.scene.foreground_color) show_alpha_option = QtWidgets.QColorDialog.ColorDialogOption(1) new_color = QtWidgets.QColorDialog.getColor( self.scene.foreground_color, options=show_alpha_option) if new_color.isValid(): self.scene.foreground_color = new_color if foreground_set: self.scene.brush_color = self.scene.foreground_color self.update_cursor() def change_background_color(self, _event): background_set = ( self.scene.brush_color == self.scene.background_color) show_alpha_option = QtWidgets.QColorDialog.ColorDialogOption(1) new_color = QtWidgets.QColorDialog.getColor( self.scene.background_color, options=show_alpha_option) if new_color.isValid(): self.scene.background_color = new_color if background_set: self.scene.brush_color = self.scene.background_color self.update_cursor() def set_background_color(self, _event): self.scene.brush_color = self.scene.background_color self.update_cursor() def set_eraser_color(self, _event): self.scene.brush_color = self.scene.eraser_color self.update_cursor() def update_cursor(self): brush_w = self.scene.brush_size * self.graphics_view.zoom * 0.93 brush_w = max(brush_w, 3) canvas_w = max(brush_w, 30) pm = QtGui.QPixmap(canvas_w, canvas_w) pm.fill(Qt.transparent) painter = QtGui.QPainter(pm) painter.drawPixmap(canvas_w, canvas_w, pm) brush_rgb = self.scene.brush_color.toRgb() r, g, b = brush_rgb.red(), brush_rgb.green(), brush_rgb.blue() cursor_color = QtGui.QColor(r, g, b, 120) painter.setPen( QtGui.QPen(cursor_color, 3, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) ellipse_x = int(round(canvas_w / 2 - (brush_w) / 2)) ellipse_y = int(round(canvas_w / 2 - (brush_w) / 2)) ellipse_w = brush_w ellipse_h = brush_w painter.drawEllipse(ellipse_x, ellipse_y, ellipse_w, ellipse_h) painter.setPen( QtGui.QPen(QtGui.QColor(0, 0, 0, 180), 2, Qt.SolidLine, Qt.FlatCap)) # Draw black to show where cursor is even when brush is small painter.drawLine(0, (canvas_w / 2), canvas_w * 2, (canvas_w / 2)) painter.drawLine((canvas_w / 2), 0, (canvas_w / 2), canvas_w * 2) painter.end() cursor = QtGui.QCursor(pm) self.setCursor(cursor) def open_pre_segment_count_dialog(self): new_count, ok = QtWidgets.QInputDialog.getInt( self, "", "Select Pre-Segment count", self.pre_segment_count, 0, 100, 1) if ok: self.pre_segment_count = new_count # For some reason the events get confused and # scroll+pan gets switched on here. # Check if control key is up to disble it. modifiers = QtWidgets.QApplication.keyboardModifiers() if not modifiers & QtCore.Qt.ControlModifier: self.graphics_view.setDragMode(QtWidgets.QGraphicsView.NoDrag) def save_annotation(self): if self.scene.annot_pixmap: self.annot_path = maybe_save_annotation( self.proj_location, self.scene.annot_pixmap, self.annot_path, self.png_fname, self.train_annot_dir, self.val_annot_dir)
class Window(QMainWindow, Ui_MainWindow): def __init__(self): super(Window, self).__init__() self.setupUi(self) # -------setupUi------------ self.originImgFigure = ImgFigure() self.enhancedImgFigure = ImgFigure() self.originImgLayout = QHBoxLayout(self.originBox) self.enhancedImgLayout = QHBoxLayout(self.enhancedBox) self.originImgLayout.addWidget(self.originImgFigure) self.enhancedImgLayout.addWidget(self.enhancedImgFigure) self.statusBar.showMessage("请选择文件") self.progressBar = QProgressBar() self.statusBar.addPermanentWidget(self.progressBar) # self.progressBar.setVisible(False) self.showProgressBarAct.triggered['bool'].connect( self.progressBar.setVisible) self.showToolBarAct.setChecked(True) self.showProgressBarAct.setChecked(True) # -------setupUi------------ self.alpha = 1 self.gamma = 0.7 self.weigh = 1 self.settingWindow = SettingWindow() self.settingWindow.changeParameterSignal.connect(self.changeParameter) self._illuMapWindowFlag = False with open("./resource/config/.history", 'r') as fp: self.action1 = self.recentOpenMenu.addAction(fp.readline()) self.action1.triggered.connect( lambda: self.openImage(self.action1.text())) self.action2 = self.recentOpenMenu.addAction(fp.readline()) self.action2.triggered.connect( lambda: self.openImage(self.action2.text())) self.action3 = self.recentOpenMenu.addAction(fp.readline()) self.action3.triggered.connect( lambda: self.openImage(self.action3.text())) @pyqtSlot() def on_openAct_triggered(self): # imgPath = "./data/13.jpg" imgPath = QFileDialog.getOpenFileName(self, "请选择图片", "/", "All Files (*)")[0] self.openImage(imgPath) def openImage(self, imgPath): self.imgPath = imgPath.strip() if imgPath != '': self.originImg = imread(self.imgPath) self.originImgFigure.axes.imshow(self.originImg) self.originImgFigure.draw() self.statusBar.showMessage("当前图片路径: " + self.imgPath) self.historyFile() self.progressBar.setValue(0) self.enhanceAct.setEnabled(True) else: QMessageBox.warning(self, "提示", "请重新选择图片") def historyFile(self): with open("./resource/config/.history", 'r+') as fp: history = fp.readlines() history = self.imgPath + '\n' + history[0] + history[1] fp.seek(0, 0) fp.truncate() fp.write(history) def changeParameter(self, alpha, gamma, weigh): self.alpha = alpha self.gamma = gamma self.weigh = weigh @pyqtSlot() def on_enhanceAct_triggered(self): self.progressBar.setValue(0) # self.progressBar.setVisible(True) self.workThread = WorkThread(self.imgPath, self.progressBar, self.alpha, self.gamma) self.workThread.start() self.workThread.finishSignal.connect(self.on_workThread_finishSignal) def on_workThread_finishSignal(self, T, R): self.T = T self.R = R self.statusBar.showMessage("当前图片路径: " + self.imgPath + " 图像增强成功") # self.imgFigure.T_axes.imshow(self.T, ) self.enhancedImgFigure.axes.imshow(self.R) self.progressBar.setValue(self.progressBar.maximum()) # self.progressBar.setVisible(False) self.enhancedImgFigure.draw() self.saveAct.setEnabled(True) self.saveAsAct.setEnabled(True) self.saveIlluMapAct.setEnabled(True) self.denoiseAct.setEnabled(True) self.illuMapAct.setEnabled(True) @pyqtSlot() def on_saveAsAct_triggered(self): savePath = QFileDialog.getSaveFileName( self, "请选择保存位置", "/", "BMP格式 (*.bmp);;JPG格式 (*.jpg)")[0] if savePath != '': imsave(savePath, self.R) QMessageBox.about(self, "提示", "保存成功") else: QMessageBox.warning(self, "提示", "请重新选择保存位置") @pyqtSlot() def on_saveAct_triggered(self): savePath = self.imgPath imsave(savePath, self.R) QMessageBox.about(self, "提示", "保存成功") @pyqtSlot() def on_clearAct_triggered(self): self.originImgFigure.axes.cla() self.originImgFigure.draw() self.enhancedImgFigure.axes.cla() self.enhancedImgFigure.draw() self.enhanceAct.setEnabled(False) self.saveIlluMapAct.setEnabled(False) self.saveAsAct.setEnabled(False) self.saveAct.setEnabled(False) self.denoiseAct.setEnabled(False) @pyqtSlot() def on_quitAct_triggered(self): qApp.quit() @pyqtSlot() def on_denoiseAct_triggered(self): self.R = restoration.denoise_tv_bregman(self.R, self.weigh) self.enhancedImgFigure.axes.imshow(self.R) self.enhancedImgFigure.draw() QMessageBox.about(self, "提示", "去噪成功") @pyqtSlot() def on_saveIlluMapAct_triggered(self): savePath = QFileDialog.getSaveFileName( self, "请选择保存位置", "/", "BMP格式 (*.bmp);;JPG格式 (*.jpg)")[0] if savePath != '': if self._illuMapWindowFlag == True: color = self.illuMapWindow.colorComboBox.currentText() color = self.illuMapWindow.colorMap[color] imsave(savePath, self.T, cmap=get_cmap(color)) else: imsave(savePath, self.T, cmap=get_cmap('OrRd_r')) QMessageBox.about(self, "提示", "保存成功") else: QMessageBox.warning(self, "提示", "请重新选择保存位置") # -------------其他界面------------- @pyqtSlot() def on_aboutAct_triggered(self): self.aboutWindow = AboutWindow() self.aboutWindow.show() @pyqtSlot() def on_illuMapAct_triggered(self): self.illuMapWindow = IlluMapWindow() self._illuMapWindowFlag = True self.illuMapWindow.saveIlluMapBtn.clicked.connect( self.on_saveIlluMapAct_triggered) self.illuMapWindow.confirmBtn.clicked.connect( self.on_confirmBtn_triggered) self.illuMapWindow.figure.axes.imshow(self.T, cmap=get_cmap('OrRd_r')) self.illuMapWindow.figure.draw() self.illuMapWindow.show() def on_confirmBtn_triggered(self): color = self.illuMapWindow.colorComboBox.currentText() color = self.illuMapWindow.colorMap[color] self.illuMapWindow.figure.axes.imshow(self.T, cmap=get_cmap(color)) self.illuMapWindow.figure.draw() @pyqtSlot() def on_settingAct_triggered(self): self.settingWindow.smoothnessSlider.setValue( int(401 - 100 * self.alpha)) self.settingWindow.brightnessSlider.setValue(int(100 * self.gamma)) self.settingWindow.denosieSlider.setValue(int(100 * self.weigh)) self.settingWindow.show()