def __init__(self): super(MainWindowV2, self).__init__() # self.model - вместо трёх отдельных lists (arr_sheet, arr_Dash, arr_Tab) # в QStandardItemModel будем append-ить # один из трёх классов, наследующихся от QStandardItem self.model = QStandardItemModel(self) self.tabWidget = QTabWidget(self) self.tabWidget.setTabPosition(QTabWidget.South) self.tabWidget.setTabsClosable(True) # можно премещать вкладки self.tabWidget.setMovable( True) # но пока по нажатию ничего не происходит self.tabWidget.tabCloseRequested.connect(self.closeTabFromTabWidget) self.setCentralWidget(self.tabWidget) # summerfield "Rapid GUI Programming" ch6 logDockWidget = QDockWidget("Tabs", self) logDockWidget.setTitleBarWidget(QWidget()) # logDockWidget = QDockWidget(self) logDockWidget.setObjectName("LogDockWidget") logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) logDockWidget.setFeatures(QDockWidget.DockWidgetMovable) # logDockWidget.setMinimumSize(100, 0) self.navListView = QListView() self.navListView.setModel(self.model) logDockWidget.setWidget(self.navListView) self.addDockWidget(Qt.LeftDockWidgetArea, logDockWidget) self.createActions() tabsToolbar = self.addToolBar("Tabs") tabsToolbar.setObjectName("tabsToolBar") tabsToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) for action in [ self.newChartAction, self.newTableAction, self.newDashboardAction, self.closeTabAction ]: tabsToolbar.addAction(action) self.navListView.selectionModel().selectionChanged.connect( self.setActiveTab) # easy start self.newChart()
class JobSearchAggregator: def __init__(self, job_service): self.app = QApplication(sys.argv) self.job_service = job_service self.list_view = ListView() self.info_panel = JobInfoPanel() self.dock = QDockWidget() self.dock.setWidget(self.list_view) self.dock.setFeatures(self.dock.NoDockWidgetFeatures) self.dock.setTitleBarWidget(QWidget()) self.main_window = MainWindow() self.main_window.setCentralWidget(self.info_panel) self.main_window.addDockWidget(Qt.LeftDockWidgetArea, self.dock) self.list_view.selectionModel().currentChanged.connect(self.list_item_selected) def run(self): self.__populate_item_model() self.list_view.select(0) self.main_window.show() sys.exit(self.app.exec_()) def __populate_item_model(self): jobs = self.job_service.gather_all_jobs() self.uids = [job.uid for job in jobs] [self.list_view.append(job) for job in jobs] def list_item_selected(self, index): job_id = self.uids[index.row()] job = self.job_service.consult_job(job_id) self.info_panel.title.setText(job.title) self.info_panel.description.setPlainText(job.description) self.info_panel.about.setPlainText(job.about) restrictions = '\n\n'.join(job.restrictions) self.info_panel.restrictions.setPlainText(restrictions) requirements = '\n\n'.join(job.requirements) self.info_panel.requirements.setPlainText(requirements) add_marker = 'try { add_marker(' + f'{job.location.lat}, {job.location.lng})' + '} catch(e) {}' self.info_panel.webpage.runJavaScript(add_marker) self.info_panel.set_contact_info(job.contact_info.contact, job.contact_info.email, job.contact_info.website, job.company)
class LiverSupportWidget(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.segmented_images = LivSupp_SegmentedImagesWidget() self.dockWidget = QDockWidget() self.dockWidget.setTitleBarWidget(QWidget()) self.dockWidget.setWidget(self.segmented_images) layout = QVBoxLayout(self) layout.addWidget(self.dockWidget)
class MainWindow(QMainWindow): changePage = Signal(bool) def __init__(self): super().__init__() self.setWindowTitle('Petro-Explorer v1.0') win_icon = QIcon('icons/Logo.ico') self.setWindowIcon(win_icon) self.setStyleSheet('background-color: #363f49;') self.header = Header() self.navigation = Navigation() self.p_top_bar = PetrophysicsTopBar() self.s_top_bar = StatisticsTopBar() self.p_options_1 = PetrophysicsOptions(_mode='KCarman') self.p_options_2 = PetrophysicsOptions(_mode='TCoates') self.p_options_3 = PetrophysicsOptions(_mode='Winland') self.p_options_4 = PetrophysicsOptions(_mode='RQIFZI') self.p_options_5 = PetrophysicsOptions(_mode='Lucia') self.p_options_6 = PetrophysicsOptions(_mode='DParsons') self.s_options_1 = StatisticsOptions(_mode='Regression') self.s_options_2 = StatisticsOptions(_mode='Statistics') self.s_options_3 = StatisticsOptions(_mode='Histogram') self.s_options_4 = StatisticsOptions(_mode='Boxplot') self.sp_controls = SpreadsheetControls() self.plot_controls = PlotControls() self.plot_viewer = PlotViewer() self.spreadsheet = Spreadsheet() self.status_bar = QStatusBar() self.scroll_area_1 = QScrollArea() self.scroll_area_1.setWidget(self.spreadsheet) self.scroll_area_1.setWidgetResizable(True) self.scroll_area_2 = QScrollArea() self.scroll_area_2.setWidget(self.plot_viewer) self.scroll_area_2.setWidgetResizable(True) self.bar_widget = QWidget() self.bar_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) self.central_widget = QWidget() self.options_widget = QWidget() self.docking_options = QDockWidget() self.docking_options.setWidget(self.options_widget) self.docking_options.setTitleBarWidget( DockWidgetRibbon(' Opções de cálculo')) self.docking_options2 = QDockWidget() self.docking_options2.setWidget(self.sp_controls) self.docking_options2.setTitleBarWidget( DockWidgetRibbon(' Controles de visualização')) self.setCentralWidget(self.central_widget) self.setStatusBar(self.status_bar) self.addToolBar(self.navigation) self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.docking_options) self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.docking_options2) self.connections() self.buildLayout() self.centralWidget().setStyleSheet('background-color: #2e3843') self.spreadsheet.setStyleSheet('background-color: white') self.status_bar.setStyleSheet('color: white') def buildLayout(self): stacked_layout_1 = QStackedLayout() # stacked_layout_1.addWidget(QWidget()) stacked_layout_1.addWidget(self.p_top_bar) stacked_layout_1.addWidget(self.s_top_bar) stacked_layout_2 = QStackedLayout() # stacked_layout_2.addWidget(QWidget()) stacked_layout_2.addWidget(self.p_options_1) stacked_layout_2.addWidget(self.p_options_2) stacked_layout_2.addWidget(self.p_options_3) stacked_layout_2.addWidget(self.p_options_4) stacked_layout_2.addWidget(self.p_options_5) stacked_layout_2.addWidget(self.p_options_6) stacked_layout_2.addWidget(self.s_options_1) stacked_layout_2.addWidget(self.s_options_2) stacked_layout_2.addWidget(self.s_options_3) stacked_layout_2.addWidget(self.s_options_4) self.stacked_layout_3 = QStackedLayout() self.stacked_layout_3.addWidget(self.scroll_area_1) self.stacked_layout_3.addWidget(self.scroll_area_2) central_widget_layout = QVBoxLayout() central_widget_layout.addWidget(self.bar_widget) central_widget_layout.addLayout(self.stacked_layout_3) self.central_widget.setLayout(central_widget_layout) self.bar_widget.setLayout(stacked_layout_1) self.options_widget.setLayout(stacked_layout_2) def connections(self): self.navigation.PetroAnalysis.connect( lambda: self.bar_widget.layout().setCurrentIndex(0)) self.navigation.StatsAnalysis.connect( lambda: self.bar_widget.layout().setCurrentIndex(1)) self.navigation.Save.connect(lambda: self.saveDialog()) self.navigation.Import.connect(lambda: self.importDialog()) self.navigation.About.connect(lambda: self.aboutDialog()) self.navigation.Help.connect(lambda: self.helpDialog()) self.navigation.header.HomePage.connect( lambda: self.changePage.emit(True)) self.navigation.ViewSheet.connect(lambda: self.displaySheet()) self.navigation.ViewPlot.connect(lambda: self.displayPltE()) self.navigation.New.connect(lambda: self.spreadsheet.addBlankSheet()) self.p_top_bar.KCarman.connect( lambda: self.options_widget.layout().setCurrentIndex(0)) self.p_top_bar.TCoates.connect( lambda: self.options_widget.layout().setCurrentIndex(1)) self.p_top_bar.Winland.connect( lambda: self.options_widget.layout().setCurrentIndex(2)) self.p_top_bar.DParsons.connect( lambda: self.options_widget.layout().setCurrentIndex(5)) self.p_top_bar.Lucia.connect( lambda: self.options_widget.layout().setCurrentIndex(4)) self.p_top_bar.RF.connect( lambda: self.options_widget.layout().setCurrentIndex(3)) self.s_top_bar.Regr.connect( lambda: self.options_widget.layout().setCurrentIndex(6)) self.s_top_bar.StatDesc.connect( lambda: self.options_widget.layout().setCurrentIndex(7)) self.s_top_bar.Boxplt.connect( lambda: self.options_widget.layout().setCurrentIndex(9)) self.s_top_bar.Hist.connect( lambda: self.options_widget.layout().setCurrentIndex(8)) self.s_options_1.run_button.clicked.connect(self.startRegr) self.s_options_2.run_button.clicked.connect(self.startStat) self.s_options_3.run_button.clicked.connect(self.startHist) self.s_options_4.run_button.clicked.connect(self.startBxpl) self.p_options_1.run.clicked.connect(self.startKCoz) self.p_options_2.run.clicked.connect(self.startTCoa) self.p_options_3.run.clicked.connect(self.startWinl) self.p_options_4.run.clicked.connect(self.startFZIR) self.p_options_5.run.clicked.connect(self.startLuci) self.p_options_6.run.clicked.connect(self.startDyks) self.sp_controls.AddColumn.connect( lambda: self.spreadsheet.addColumn()) self.sp_controls.AddRow.connect(lambda: self.spreadsheet.addRow()) self.sp_controls.DeleteRow.connect( lambda: self.spreadsheet.deleteRow()) self.sp_controls.DeleteColumn.connect( lambda: self.spreadsheet.deleteColumn()) self.plot_controls.run_button.clicked.connect(lambda: self.startPltE()) self.plot_controls.erasePlot.connect( lambda: self.plot_viewer.erasePlot()) self.plot_viewer.feedPlotControls.connect( self.plot_controls.fillFromJson) def startPltE(self): old_json = self.plot_viewer.json_data title = self.plot_controls.modify_title.text() xtype = self.plot_controls.modify_x_axis_type.currentText() ytype = self.plot_controls.modify_y_axis_type.currentText() xlabel = self.plot_controls.modify_x_axis_label.text() ylabel = self.plot_controls.modify_y_axis_label.text() if len(self.plot_controls.modify_lower_x_range.text()) > 0: lxrange = float(self.plot_controls.modify_lower_x_range.text()) else: lxrange = None if len(self.plot_controls.modify_upper_x_range.text()) > 0: uxrange = float(self.plot_controls.modify_upper_x_range.text()) else: uxrange = None if len(self.plot_controls.modify_lower_y_range.text()) > 0: lyrange = float(self.plot_controls.modify_lower_y_range.text()) else: lyrange = None if len(self.plot_controls.modify_upper_y_range.text()) > 0: uyrange = float(self.plot_controls.modify_upper_y_range.text()) else: uyrange = None if len(self.plot_controls.add_x_trace.text()) > 0 and len( self.plot_controls.add_y_trace.text()): trace_type = self.plot_controls.type_of_trace.currentText() x_trace = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.plot_controls. add_x_trace.text( ))] y_trace = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.plot_controls. add_y_trace.text( ))] trace_name = self.plot_controls.trace_name.text() else: trace_type = None x_trace = None y_trace = None trace_name = None io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.loadPltE(io_operations_handler.results)) io_operations_handler.loadParameters(f=pceManifold, _args=[ old_json, title, xtype, ytype, xlabel, ylabel, lxrange, uxrange, lyrange, uyrange, trace_type, x_trace, y_trace, trace_name ]) io_operations_handler.start() def loadPltE(self, results, typ='Regressão'): self.plot_viewer.loadPlot(results[0], results[1], _type=typ) self.displayPltE() def displayPltE(self): self.stacked_layout_3.setCurrentIndex(1) self.docking_options2.setWidget(self.plot_controls) #self.removeDockWidget(self.docking_options3) #self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.docking_options2) def loadSheet(self, df): self.spreadsheet.changeModel(data=df, header=list(df.keys())) self.displaySheet() def displaySheet(self): self.stacked_layout_3.setCurrentIndex(0) self.docking_options2.setWidget(self.sp_controls) self.status_bar.clearMessage() #self.removeDockWidget(self.docking_options2) #self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.docking_options3) def importDialog(self): func = None file_settings = QFileDialog().getOpenFileName( self, 'Importar Arquivo', filter= "Todos os arquivos (*);; Arquivo de Texto (*.txt);; Arquivo CSV (*.csv);; " "Planilha Excel (*.xlsx)") if ".txt" in file_settings[0]: func = Data.readTXT if ".csv" in file_settings[0]: func = Data.readCSV if ".xlsx" in file_settings[0]: func = Data.readExcel self.status_bar.showMessage('Importando arquivo. Aguarde.') io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.loadSheet(io_operations_handler.results)) io_operations_handler.loadParameters(f=func, _args=[ file_settings[0], ]) io_operations_handler.start() def saveDialog(self): func = None file_settings = QFileDialog().getSaveFileName( self, "Salvar Arquivo", filter="Arquivo de Texto (*.txt);; Arquivo CSV (*.csv);; " "Planilha Excel (*.xlsx)") if ".txt" in file_settings[0]: func = Data.toTXT if ".csv" in file_settings[0]: func = Data.toCSV if ".xlsx" in file_settings[0]: func = Data.toExcel io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.loadParameters( f=func, _args=[self.spreadsheet.retrieveModel(), file_settings[0]]) io_operations_handler.start() def aboutDialog(self): icon = QIcon(r'icons/sobre.png') text = "O Petro-Explorer é um software desenvolvido no Laboratório de Exploração e Produção de Petróleo (" \ "LENEP) da UENF para análises petrofísicas e estatísticas de dados de rocha. " msg = QMessageBox() msg.setWindowTitle('Sobre Petro-Explorer') msg.setWindowIcon(icon) msg.setText(text) msg.exec_() def helpDialog(self): icon = QIcon(r'icons/ajuda.png') text = r"Para utilizar o Petro-Explorer de maneira correta siga os seguintes passos:" \ "\n1 - Clique no botão Novo na barra de navegação, isto irá limpar quaisquer dados de antigas análises.\n" \ "2 - Para começar a sua análise é preciso importar os dados, assim, clique no botão Importar para escolher o seu arquivo. Atente para o fato que somente três tipos de arquivo são suportados (i.e. *.txt, *.csv, *.xlsx). Depois da sua escolha, os dados devem aparecer na planilha do software.\n" \ "3 - Se você desejar realizar uma análise petrofísica, clique no botão de Análise Petrofísica na barra de navegação. Caso queira realizar uma análise estatística, clique no botão de Análise Estatística na barra de navegação.\n" \ "4 - Selecione na barra superior à planilha, a análise que desejas realizar sobre seus dados.\n" \ "5 - No canto direito da janela, selecione os parâmetros de sua análise assim como o destino de seus resultados. Clique no botão 'Começar Análise' para continuar.\n" \ "6 - Analise seus resultados na planilha, e, quando disponível, no gráfico também.\n" \ "7 - Quando terminar, clique no botão Salvar para salvar os resultados de suas análises no disco.\n" \ "8 - Caso queira realizar outra análise, clique no botão \"Novo\" e comece novamente.\n" msg = QMessageBox() msg.setWindowTitle('Ajuda') msg.setWindowIcon(icon) msg.setText(text) msg.exec_() def startRegr(self): xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.s_options_1. payload['x_column'])] ydata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.s_options_1. payload['y_column'])] _type = self.s_options_1.payload['calculate'] dgr = self.s_options_1.degree.value() io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayRegr(self.s_options_1.payload['output_column'], io_operations_handler.results)) io_operations_handler.loadParameters(f=regressionManifold, _args=[xdata, ydata, dgr, _type]) io_operations_handler.start() def startStat(self): xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.s_options_2. payload['x_column'])] mthd = self.s_options_2.payload['calculate'] qtl = self.s_options_2.quartile.value() pctl = self.s_options_2.percentile.value() io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayStat(self.s_options_2.payload['output_column'], io_operations_handler.results)) io_operations_handler.loadParameters(f=statisticsManifold, _args=[xdata, mthd, qtl, pctl]) io_operations_handler.start() def startHist(self): xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.s_options_3. payload['x_column'])] nbins = self.s_options_3.payload['y_column'] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayHist(io_operations_handler.results)) io_operations_handler.loadParameters(f=histogramManifold, _args=[xdata, nbins]) io_operations_handler.start() def startBxpl(self): indexes = [] columns = self.s_options_4.payload['column_range'] for col in columns: indexes.append(self.spreadsheet.model.header_info.index(col)) xdata = self.spreadsheet.model.input_data[:, indexes] box_orientation = self.s_options_4.payload['y_column'] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayBxpl(io_operations_handler.results)) io_operations_handler.loadParameters(f=boxplotManifold, _args=[xdata, box_orientation]) io_operations_handler.start() def startKCoz(self): #you need to ascertain if x corresponds to Permeability, y to Porosity and z to Swir/Svgr k = None phi = None svgr = None prp = self.p_options_1.payload['calculate'] if prp == 'Permeabilidade (mD)': phi = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.p_options_1. payload['x_column'])] svgr = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_1. payload['y_column'])] elif prp == 'SVgr (cm-1)': k = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.p_options_1. payload['x_column'])] phi = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.p_options_1. payload['y_column'])] else: k = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.p_options_1. payload['x_column'])] phi = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info. index(self.p_options_1. payload['y_column'])] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayKCoz(io_operations_handler.results)) io_operations_handler.loadParameters(f=kCarmanManifold, _args=[k, phi, svgr, prp]) io_operations_handler.start() def startTCoa(self): #you need to ascertain if x corresponds to Permeability, y to Porosity and z to Swir/Svgr prp = self.p_options_2.payload['calculate'] if prp == "Swir (%)": xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_2. payload['x_column'])] ydata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_2. payload['y_column'])] zdata = None else: xdata = None ydata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_2. payload['y_column'])] zdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_2. payload['x_column'])] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayTCoa(io_operations_handler.results)) io_operations_handler.loadParameters(f=tCoatesManifold, _args=[xdata, ydata, zdata, prp]) io_operations_handler.start() def startWinl(self): #you need to ascertain if x corresponds to Permeability, y to Porosity and z to Swir/Svgr if self.p_options_3.payload['x_column'] != '': xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_3. payload['x_column'])] else: xdata = [] if self.p_options_3.payload['y_column'] != '': ydata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_3. payload['y_column'])] else: ydata = [] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayWinl(io_operations_handler.results)) io_operations_handler.loadParameters(f=winlandManifold, _args=[xdata, ydata]) io_operations_handler.start() def startFZIR(self): # you need to ascertain if x corresponds to Permeability, y to Porosity and z to Swir/Svgr if self.p_options_4.payload['x_column'] != '': xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_4. payload['x_column'])] else: xdata = None if self.p_options_4.payload['y_column'] != '': ydata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_4. payload['y_column'])] else: ydata = None if self.p_options_4.payload['z_column'] != '': zdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_4. payload['z_column'])] else: zdata = None prp = self.p_options_4.payload['calculate'] un = self.p_options_4.payload['column_range'] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayFZIR(io_operations_handler.results)) io_operations_handler.loadParameters( f=fzManifold, _args=[xdata, ydata, zdata, un, prp]) io_operations_handler.start() def startLuci(self): #you need to ascertain if x corresponds to Permeability, y to Porosity and z to Swir/Svgr if self.p_options_5.payload['x_column'] != '': xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_5. payload['x_column'])] else: xdata = [] if self.p_options_5.payload['y_column'] != '': ydata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_5. payload['y_column'])] else: ydata = [] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayLuci(io_operations_handler.results)) io_operations_handler.loadParameters(f=luciaManifold, _args=[xdata, ydata]) io_operations_handler.start() def startDyks(self): #you need to ascertain if x corresponds to Permeability, y to Porosity and z to Swir/Svgr if self.p_options_6.payload['x_column'] != '': xdata = self.spreadsheet.model.input_data[:, self.spreadsheet.model. header_info.index( self.p_options_6. payload['x_column'])] else: xdata = [] prp = self.p_options_6.payload['calculate'] io_operations_handler = HandlerThread() io_operations_handler.messageSent.connect(self.status_bar.showMessage) io_operations_handler.daemon = True io_operations_handler.hasFinished.connect( lambda: self.displayDyks(io_operations_handler.results)) io_operations_handler.loadParameters(f=dParsonsManifold, _args=[xdata, prp]) io_operations_handler.start() def displayKCoz(self, content): content = list(content) content.insert(0, 'Resultados - Kozeny-Carman') self.spreadsheet.addColumn(content) def displayWinl(self, content): self.loadPltE(content[:2]) content[2].insert(0, 'R35 - Winland') content[3].insert(0, 'Ports - Winland') self.spreadsheet.addColumn(content[2]) self.spreadsheet.addColumn(content[3]) def displayTCoa(self, content): content.insert(0, 'Resultados - Timur Coates') self.spreadsheet.addColumn(content) def displayDyks(self, content): content.insert(0, 'Resultados - Dykstra-Parsons') self.spreadsheet.addColumn(content) self.p_options_6.results.setText( 'Atenção! Resultado pode ser diferente do coeficiente calculado através do gráfico de probabilidade. \n' + str(content[0]) + ': ' + str(content[1])) def displayLuci(self, results): self.loadPltE(results[:2]) results[2].insert(0, 'Resultados - RFN/Lucia') self.spreadsheet.addColumn(results[2]) def displayFZIR(self, results): results[0].insert(0, 'Resultados - RQI (μm)') self.spreadsheet.addColumn(results[0]) results[1].insert(0, 'Resultados - PhiZ') self.spreadsheet.addColumn(results[1]) self.loadPltE(results[2:]) def displayRegr(self, display_name, results): self.s_options_1.results.setText(str(results[0])) self.loadPltE(results[-2:]) def displayStat(self, display_name, results): self.s_options_2.results.setText(str(results)) def displayHist(self, results): self.loadPltE(results, 'Histograma') def displayBxpl(self, results): self.loadPltE(results, 'Boxplot')
class MainWidget(QWidget): def __init__(self, parent=None): super().__init__(parent=parent) self.username = parent.user self.left = 10 self.top = 10 self.width = 1200 self.height = 800 self.leftPanelWidth = 250 self.setContentsMargins(QMargins(0, 0, 0, 0)) self.initUI() def initUI(self): self.pacs_ctrl: PACS_ServerCtrl = PACS_OrthancServerCtrl() self.setGeometry(self.left, self.top, self.width, self.height) self.pacs_widget = PACS_MainWidget() self.dicom_widget = Dicom_Browser() # self.liver_support_widget = LiverSupportWidget() self.button_bar = MenuLeftPane() topLayout = QVBoxLayout() topLayout.setAlignment(Qt.AlignTop) topLayout.addWidget(self.button_bar) self.mainWidget = QDockWidget() self.mainWidget.setFeatures(QDockWidget.NoDockWidgetFeatures) self.mainWidget.setTitleBarWidget(QWidget()) self.mainWidget.setWidget(self.dicom_widget) mainLayout = QHBoxLayout(self) mainLayout.setContentsMargins(QMargins(0, 0, 0, 0)) mainLayout.addLayout(topLayout) mainLayout.addWidget(self.mainWidget) self.button_bar.pacs_btn.clicked.connect(self.show_PACSWidget) self.button_bar.dcm_btn.clicked.connect(self.show_DICOMBrowser) # self.button_bar.liv_support_btn.clicked.connect(self.show_liverSupport) self.pacs_widget.dcm_to_browser.connect(self.send_file_to_browser) self.show_PACSWidget() def show_PACSWidget(self): connect = self.pacs_ctrl.isConnect() if connect: self.mainWidget.setWidget(self.pacs_widget) self.button_bar.pacs_btn.setDisabled(1) self.button_bar.dcm_btn.setDisabled(0) # self.button_bar.liv_support_btn.setDisabled(0) else: QMessageBox.warning( self, 'Connect Error', '''Application is not able to connect with PACS Server Check Klient and Archive data ''', QMessageBox.Ok) def show_DICOMBrowser(self): self.mainWidget.setWidget(self.dicom_widget) self.button_bar.dcm_btn.setDisabled(1) self.button_bar.pacs_btn.setDisabled(0) # self.button_bar.liv_support_btn.setDisabled(0) # def show_liverSupport(self): # self.mainWidget.setWidget(self.liver_support_widget) # self.button_bar.pacs_btn.setDisabled(0) # self.button_bar.dcm_btn.setDisabled(0) # self.button_bar.liv_support_btn.setDisabled(1) def send_file_to_browser(self, path): self.mainWidget.setWidget(self.dicom_widget) self.dicom_widget.load_series(path) self.dicom_widget.series_id = self.pacs_widget.stage_chain['series'] self.button_bar.dcm_btn.setDisabled(1) self.button_bar.pacs_btn.setDisabled(0)
class AsemblerIDE(QMainWindow): def __init__(self): super(AsemblerIDE, self).__init__() self.workspace = None self.backupTimer = 300000 PathManager.START_DIRECTORY = os.getcwd() self.workspaceConfiguration = WorkspaceConfiguration.loadConfiguration( ) self.snippetManager = SnippetManager.loadSnippetConfiguration() self.tooltipManager = TooltipManager.loadTooltipConfiguration() self.configurationManager = ConfigurationManager() self.editorTabs = EditorTabWidget(self.snippetManager, self.tooltipManager) self.menuBar = MenuBar() self.terminal = Terminal() self.toolBar = ToolBar(self.configurationManager) self.statusBar = StatusBar() self.treeView = TreeView(self.configurationManager) self.help = HelpWidget() self.ascii = AsciiTableWidget() self.setStatusBar(self.statusBar) self.addToolBar(self.toolBar) self.addDockWidget(Qt.BottomDockWidgetArea, self.terminal) self.addDockWidget(Qt.RightDockWidgetArea, self.help) self.addDockWidget(Qt.RightDockWidgetArea, self.ascii) self.splitDockWidget(self.help, self.ascii, Qt.Vertical) self.treeDock = QDockWidget() self.treeDock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.treeDock.setStyleSheet("background-color: #2D2D30; color: white;") self.treeDock.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable) self.treeDock.setWindowTitle("Workspace explorer") self.treeDock.setWidget(self.treeView) header = QLabel("Workspace explorer") # header.setStyleSheet("background-color: #007ACC;") self.treeDock.setTitleBarWidget(header) self.addDockWidget(Qt.LeftDockWidgetArea, self.treeDock) self.setMenuBar(self.menuBar) self.setMinimumSize(1200, 800) self.setWindowTitle("i386 Assembly Integrated Development Environment") self.setCentralWidget(self.editorTabs) self.setStyleSheet("background-color: #3E3E42; color: white;") self.setWindowIcon(QIcon(resource_path("resources/app_icon.ico"))) self.addTabWidgetEventHandlers() self.addMenuBarEventHandlers() self.addToolBarEventHandlers() self.addTreeViewEventHandlers() self.checkWorkspaceConfiguration() #self.populateTreeView() #self.statusBar.comboBox.currentTextChanged.connect(self.changeEditorSyntax) self.statusBar.tabWidthComboBox.currentTextChanged.connect( self.changeEditorTabWidth) self.timer = QTimer() self.timer.start(self.backupTimer) self.timer.timeout.connect(self.makeBackupSave) self.terminal.console.setFocus() self.tabSwitcher = TabSwitcher(self.editorTabs) self.tabSwitcher.hide() self.projectSwitcher = ProjectSwitcher(self.configurationManager, self.toolBar.projectComboBox) self.projectSwitcher.hide() self.terminal.projectSwitchRequested.connect(self.showProjectSwitcher) self.terminal.tabSwitchRequested.connect(self.showTabSwitcher) self.editorTabs.tabSwitchRequested.connect(self.showTabSwitcher) self.editorTabs.projectSwitchRequested.connect( self.showProjectSwitcher) self.helpDocsDialog = GettingStartedDialog() self.helpDocsDialog.hide() def makeBackupSave(self): self.workspace.saveBackup() self.timer.setInterval( self.backupTimer ) # interval has to be reset cause the timer may have been paused def changeEditorTabWidth(self, text): currentTab: EditorTab = self.editorTabs.getCurrentTab() if currentTab: currentTab.widget.editor.tabSize = int(text) def changeEditorSyntax(self, text): currentTab: EditorTab = self.editorTabs.getCurrentTab() if currentTab: if text == "Assembly": currentTab.widget.editor.sintaksa = AsemblerSintaksa( currentTab.widget.editor.document()) elif text == "C": currentTab.widget.editor.sintaksa = CSyntax( currentTab.widget.editor.document()) currentTab.widget.editor.update() def checkWorkspaceConfiguration(self): defaultWorkspace = self.workspaceConfiguration.getDefaultWorkspace() if defaultWorkspace: if self.openWorkspaceAction(defaultWorkspace): self.show() return else: self.workspaceConfiguration.removeWorkspace(defaultWorkspace) dialog = WorkspaceConfigurationEditor(self.workspaceConfiguration, self) if dialog.exec_(): self.show() else: sys.exit(0) def addTabWidgetEventHandlers(self): self.editorTabs.currentChanged.connect(self.activeTabChanged) def addTreeViewEventHandlers(self): self.treeView.fileDoubleCliked.connect(self.loadFileText) self.treeView.workspaceReload.connect( lambda wsProxy: self.openWorkspaceAction(wsProxy.path, updateWorkspace=True)) self.treeView.workspaceRename.connect( lambda oldPath, wsProxy: self.workspaceConfiguration. replaceWorkpsace(oldPath, wsProxy.path)) self.treeView.newProjectAdded.connect( lambda: self.toolBar.updateComboBox()) self.treeView.projectCompile.connect( lambda proxy: self.compileAction(proxy)) self.treeView.projectDebug.connect( lambda proxy: self.debugAction(proxy)) self.treeView.projectRun.connect(lambda proxy: self.runAction(proxy)) self.treeView.projectRemove.connect( lambda proxy: self.removeProject(proxy)) self.treeView.projectRename.connect( lambda oldPath, project: self.renameProject(oldPath, project)) self.treeView.fileRemove.connect( lambda fileProxy: self.removeFile(fileProxy)) self.treeView.fileRename.connect( lambda oldPath, fileProxy: self.renameFile(oldPath, fileProxy)) self.treeView.fileSave.connect( lambda fileProxy: self.updateEditorTrie(fileProxy)) self.treeView.invalidWorkspace.connect(self.invalidWorkspace) self.treeView.projectSave.connect(self.saveProject) self.treeView.quickAssemblyFile.connect(self.loadFileText) self.treeView.newFile.connect(self.loadFileText) def saveProject(self, projectProxy: ProjectProxy): self.saveAllFiles(projectProxy) def invalidWorkspace(self, workspace: WorkspaceNode): workspace.deleted = True msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText("Workspace '{}' has been deleted from the disk.".format( workspace.path)) msg.setWindowTitle("Invalid workspace") msg.exec_() if workspace.path in self.workspaceConfiguration.getWorkspaces(): self.workspaceConfiguration.removeWorkspace(workspace.path) self.switchWorkspaceAction() def renameFile(self, oldPath: str, fileProxy: FileProxy): # fileProxy.text = None key = "{}/{}".format(fileProxy.parent.path, oldPath) if key in self.editorTabs.projectTabs: newKey = "{}/{}".format(fileProxy.parent.path, fileProxy.path) tab = self.editorTabs.projectTabs.pop(key) self.editorTabs.projectTabs[newKey] = tab tab.tabName = newKey index = self.editorTabs.tabs.index(fileProxy) tabText = newKey + "*" if fileProxy.hasUnsavedChanges else newKey self.editorTabs.setTabText(index, tabText) def renameProject(self, oldPath: str, project: ProjectNode): self.toolBar.updateComboBox() for fileProxy in project.proxy.files: oldKey = "{}/{}".format(oldPath, fileProxy.path) if oldKey in self.editorTabs.projectTabs: newKey = "{}/{}".format(project.proxy.path, fileProxy.path) tab = self.editorTabs.projectTabs.pop(oldKey) self.editorTabs.projectTabs[newKey] = tab tab.tabName = newKey index = self.editorTabs.tabs.index(fileProxy) tabText = newKey + "*" if fileProxy.hasUnsavedChanges else newKey self.editorTabs.setTabText(index, tabText) def removeFile(self, proxy: FileProxy): key = "{}/{}".format(proxy.parent.path, proxy.path) if key in self.editorTabs.projectTabs: self.editorTabs.closeTab(self.editorTabs.tabs.index(proxy), askToSave=False) def removeProject(self, proxy: ProjectProxy): for file in proxy.files: if file in self.editorTabs.tabs: self.editorTabs.closeTab(self.editorTabs.tabs.index(file), askToSave=False) self.toolBar.updateComboBox() def checkIfWorkspaceDeleted(self): if not os.path.exists(self.workspace.path): self.workspace.deleted = True def activeTabChanged(self, index): if index == -1: self.statusBar.tabWidthComboBox.setCurrentText('4') return syntax = "Assembly" if self.editorTabs.tabs[index].path[-1].lower( ) == "s" else "C" proxy = self.editorTabs.tabs[index] key = "{}/{}".format(proxy.parent.path, proxy.path) self.statusBar.comboBox.setCurrentText(syntax) self.statusBar.tabWidthComboBox.setCurrentText( str(self.editorTabs.projectTabs[key].widget.editor.tabSize)) #self.changeEditorSyntax(syntax) def populateTreeView(self): workspace = WorkspaceNode() workspace.setText(0, "My workspace") self.treeView.setRoot(workspace) for i in range(5): project = ProjectNode() project.setText(0, "My Project {}".format(i + 1)) assemblyFile = AssemblyFileNode() assemblyFile.setText(0, "procedure_{}.S".format(i + 1)) cFile = CFileNode() cFile.setText(0, "main_{}.c".format(i + 1)) self.treeView.addNode(workspace, project) self.treeView.addNode(project, assemblyFile) self.treeView.addNode(project, cFile) project.setExpanded(True) self.workspace = workspace def closeEvent(self, event): if self.tabSwitcher.isActiveWindow(): self.tabSwitcher.hide() if self.helpDocsDialog.isVisible(): self.helpDocsDialog.hide() for proxy in self.editorTabs.tabs: if proxy.hasUnsavedChanges: msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setParent(None) msg.setModal(True) msg.setWindowTitle("Confirm Exit") msg.setText("The file {}/{} has been modified.".format( proxy.parent.path, proxy.path)) msg.setInformativeText("Do you want to save the changes?") msg.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msg.setDefaultButton(QMessageBox.Save) retValue = msg.exec_() if retValue == QMessageBox.Save: if not self.saveFileAction(): event.ignore() return elif retValue == QMessageBox.Discard: pass else: event.ignore() return self.workspaceConfiguration.saveConfiguration() self.snippetManager.saveConfiguration() self.tooltipManager.saveConfiguration() self.checkIfWorkspaceDeleted() if not self.workspace.deleted: self.workspace.proxy.closedNormally = True self.saveWorkspaceAction() else: if self.workspace.path in self.workspaceConfiguration.getWorkspaces( ): self.workspaceConfiguration.removeWorkspace( self.workspace.path) super(AsemblerIDE, self).closeEvent(event) def addMenuBarEventHandlers(self): self.menuBar.quickAssemblyProjectAction.triggered.connect( self.quickAssemblyProject) self.menuBar.newWorkspaceAction.triggered.connect( self.newWorkspaceAction) self.menuBar.saveWorkspaceAction.triggered.connect( self.saveWorkpsaceAllFiles) self.menuBar.openWorkspaceAction.triggered.connect( self.openWorkspaceAction) self.menuBar.switchWorkspaceAction.triggered.connect( self.switchWorkspaceAction) self.menuBar.saveAction.triggered.connect(self.saveFileAction) self.menuBar.findAction.triggered.connect(self.findAction) self.menuBar.editDefaultWorkspace.triggered.connect( self.editDefaultWorkspaceConfiguration) self.menuBar.editCodeSnippets.triggered.connect(self.editCodeSnippets) self.menuBar.editSettings.triggered.connect(self.editSettings) self.menuBar.aboutAction.triggered.connect(self.showAbout) self.menuBar.helpAction.triggered.connect(self.showGettingStarted) self.menuBar.view.addAction(self.terminal.toggleViewAction()) self.menuBar.view.addAction(self.treeDock.toggleViewAction()) self.menuBar.view.addAction(self.help.toggleViewAction()) self.menuBar.view.addAction(self.ascii.toggleViewAction()) self.menuBar.view.addAction(self.toolBar.toggleViewAction()) def quickAssemblyProject(self): if self.workspace: self.workspace.createQuickAssemblyProject() def showAbout(self): dialog = AboutDialog() dialog.exec_() def showGettingStarted(self): if self.helpDocsDialog.isHidden(): self.helpDocsDialog.show() def findAction(self): currentTab: EditorTabWidget = self.editorTabs.getCurrentTab() if not currentTab: msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText( "Cannot open file and replace window because there is no open file at the moment." ) msg.setWindowTitle("Find & Replace error") msg.exec_() return currentTab.widget.find.setVisible(True) if currentTab.widget.editor.lastFind: currentTab.widget.find.findLabel.setText( currentTab.widget.editor.lastFind) currentTab.widget.find.findLabel.setFocus() def switchWorkspaceAction(self): remaining = self.timer.remainingTime() self.timer.stop( ) # timer for creating backups needs to be paused when switching ws dialog = WorkspaceConfigurationEditor(self.workspaceConfiguration, self, switch=True) if dialog.exec_() and dialog.workspaceDirectory: self.workspace.proxy.closedNormally = True self.saveWorkspaceAction() if not self.editorTabs.closeAllTabs(): self.timer.start( remaining) # timer for saving backups is resumed return self.openWorkspaceAction(dialog.workspaceDirectory) self.timer.start(remaining) # timer for saving backups is resumed def editDefaultWorkspaceConfiguration(self): editor = DefaultWorkspaceEditor(self.workspaceConfiguration) if editor.exec_(): self.workspaceConfiguration.saveConfiguration() def editCodeSnippets(self): editor = SnippetEditor(self.snippetManager) if editor.exec_(): self.snippetManager.saveConfiguration() def editSettings(self): editor = SettingsEditor(self.tooltipManager) if editor.exec_(): self.tooltipManager.saveConfiguration() def newWorkspaceAction(self): remaining = self.timer.remainingTime() self.timer.stop( ) # timer for creating backups needs to be paused when switching ws if not self.editorTabs.closeAllTabs(): self.timer.start(remaining) # timer for saving backups is resumed return False self.workspace.proxy.closedNormally = True self.saveWorkspaceAction() workspace = WorkspaceNode() name = QFileDialog.getExistingDirectory( self, "New workspace", "select new workspace directory") if name: path = os.path.join(name, ".metadata") backup_path = os.path.join(name, ".backup") if os.path.isdir(path) or os.path.isdir(backup_path): self.msgInvalidFolderError(name) self.timer.start( remaining) # timer for saving backups is resumed return wsname = name[name.rindex(os.path.sep) + 1:] regex = re.compile('[@!#$%^&*()<>?/\|}{~:]') if ' ' in name or regex.search(wsname): msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText( "Workspace path/name cannot contain whitespace or special characters." ) msg.setWindowTitle("Workspace creation error") msg.exec_() self.timer.start( remaining) # timer for saving backups is resumed return False workspace.path = name proxy = WorkspaceProxy() proxy.path = name workspace.proxy = proxy workspace.setIcon(0, QIcon(resource_path("resources/workspace.png"))) workspace.setText(0, wsname) self.workspace = workspace self.treeView.setRoot(self.workspace) self.saveWorkspaceAction() self.configurationManager.allProjects = [] self.configurationManager.currentProject = None self.toolBar.updateComboBox() self.terminal.executeCommand("cd {}".format(self.workspace.path)) self.workspaceConfiguration.addWorkspace(self.workspace.proxy.path) self.timer.start(remaining) # timer for saving backups is resumed return True self.timer.start(remaining) # timer for saving backups is resumed return False def saveWorkspaceAction(self, workspacePath=None): if self.workspace: self.workspace.saveWorkspace(workspacePath) def saveWorkpsaceAllFiles(self): self.saveAllFiles() self.saveWorkspaceAction() def updateProjectList(self): self.configurationManager.allProjects = [] self.configurationManager.currentProject = None projects = self.treeView.getProjects() if len(projects): self.configurationManager.allProjects = self.treeView.getProjects() self.configurationManager.currentProject = projects[0] self.toolBar.updateComboBox() def openWorkspaceAction(self, workspacePath=None, updateWorkspace=False): if not self.editorTabs.closeAllTabs(): return if not workspacePath: workspacePath = QFileDialog.getExistingDirectory( self, "Open workspace", "select new workspace directory") if not workspacePath: return regex = re.compile('[@!#$%^&*()<>?/\|}{~:]') if ' ' in workspacePath or regex.search( os.path.basename(workspacePath)): msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText( "Workspace path/name cannot contain whitespace or special characters." ) msg.setWindowTitle("Workspace creation error") msg.exec_() return False path = os.path.join(workspacePath, ".metadata") backup_path = os.path.join(workspacePath, ".backup") if os.path.isdir(path) or os.path.isdir(backup_path): self.msgInvalidFolderError(workspacePath) return workspace = WorkspaceProxy() self.workspace = WorkspaceNode() if os.path.exists(path): try: # in try block in case there is a corrupted .metadata file on the path with open(path, 'rb') as file: workspace = pickle.load(file) except: workspace.closedNormally = False # set it to false to trigger backup msg in case .metadata is corrupted elif not os.path.exists( backup_path ): # creates a .metadata file for a clean new workspace self.workspace.proxy = workspace self.applyWsCompatibilityFix(workspacePath) self.saveWorkspaceAction(workspacePath) self.workspace.proxy = workspace self.applyWsCompatibilityFix(workspacePath) attempted_backup = False if not self.workspace.proxy.closedNormally: if self.restoreBackupMessage(workspacePath, updateWorkspace=updateWorkspace): attempted_backup = True if self.loadWorkspaceAction( workspacePath, backup=True): # attempt to load backup self.updateProjectList() return True else: self.messageBackupError("closedAbruptly") if self.loadWorkspaceAction( workspacePath, backup=False): # attempt to load regular ws file self.updateProjectList() return True # If the regular file won't load for some reason and there was no backup attempt, ask to load the backup file elif not attempted_backup and self.restoreBackupMessage( workspacePath, failedToLoad=True): if self.loadWorkspaceAction( workspacePath, backup=True): # attempt to load the backup file self.updateProjectList() return True else: self.messageBackupError() return False def msgInvalidFolderError(self, path): msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText( "Invalid folder for a workspace." "\nEnsure there are no .metadata and .backup folders in \n{}". format(path)) msg.setWindowTitle("Failed to load workspace.") msg.exec_() def messageBackupError(self, msgType=None): msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) if msgType == "closedAbruptly": msg.setText("Failed to load {}." "\nRegular workspace save will be restored.".format( ".backup workspace file")) else: msg.setText("Failed to load {}.".format(".backup workspace file")) msg.setWindowTitle("Failed to load backup workspace.") msg.exec_() def applyWsCompatibilityFix(self, workspacePath): try: closedNormally = self.workspace.proxy.closedNormally except AttributeError: closedNormally = True self.workspace.proxy.closedNormally = closedNormally # adds attribute to old ws files self.workspace.path = workspacePath # changes the path to currently selected dir, in case it was moved self.workspace.proxy.path = workspacePath def restoreBackupMessage(self, wsName, failedToLoad=False, updateWorkspace=False): try: msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setParent(None) msg.setModal(True) msg.setWindowTitle("Workspace recovery") time = strftime( '%m/%d/%Y %H:%M:%S', localtime(os.path.getmtime(os.path.join(wsName, ".backup")))) if failedToLoad: msg.setText("The workplace {} could not be loaded.\n" "\nTime the backup was created: {}".format( wsName, time)) elif updateWorkspace: msg.setText( "Choose if you want to reload workspace or to recover from backup.\n" "\nTime the backup was created: {}".format(wsName, time)) else: msg.setText("The workplace {} was closed unexpectedly.\n" "\nTime the backup was created: {}".format( wsName, time)) if not updateWorkspace: msg.setInformativeText( "Would you like to recover from backup?") else: msg.setInformativeText( "Would you like to recover from backup? Select No if you just want to update the workspace." ) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.Yes) retValue = msg.exec_() if retValue == QMessageBox.Yes: return True else: return except: return False def loadWorkspaceAction(self, workspacePath, backup=False): if backup: path = os.path.join(workspacePath, ".backup") else: path = os.path.join(workspacePath, ".metadata") if os.path.exists(path): try: # in try block in case there is a corrupted .metadata file on the path with open(path, 'rb') as file: workspace = pickle.load(file) except: return False else: return False self.workspace = WorkspaceNode() self.workspace.proxy = workspace self.applyWsCompatibilityFix(workspacePath) self.workspace.setIcon(0, QIcon(resource_path("resources/workspace.png"))) self.workspace.setText( 0, workspacePath[workspacePath.rindex(os.path.sep) + 1:]) self.workspace.proxy.closedNormally = False if backup: success = self.workspace.loadBackupWorkspace(workspacePath) else: success = self.workspace.loadWorkspace() if not success: return False self.treeView.setRoot(self.workspace) projects = self.treeView.getProjects() if projects: self.configurationManager.allProjects.clear() self.configurationManager.allProjects.extend(projects) self.toolBar.updateComboBox() #self.treeView.expandAll() self.terminal.executeCommand("cd {}".format(self.workspace.path)) self.workspaceConfiguration.addWorkspace(self.workspace.proxy.path) if workspacePath: self.saveWorkspaceAction(workspacePath) return True def addToolBarEventHandlers(self): self.toolBar.compile.triggered.connect(self.compileAction) self.toolBar.run.triggered.connect(self.runAction) self.toolBar.debug.triggered.connect(self.debugAction) def debugAction(self, projectProxy=None): currentProject: ProjectNode = self.configurationManager.currentProject if not currentProject: self.showNoCurrentProjectMessage("Debug") return if not os.path.exists(currentProject.proxy.getProjectPath()): currentProject.eventManager.invalidProject.emit(currentProject) return proxy = None if projectProxy: proxy = projectProxy else: if currentProject: proxy = currentProject.proxy if proxy: commandString = proxy.getProjectDebugCommand() self.terminal.console.setFocus() if self.terminal.executeCommand(proxy.getProjectCompileCommand()): copmileString = proxy.getProjectCompileCommand() if ' -g ' not in copmileString: msg = QMessageBox() msg.setStyleSheet( "background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Warning) msg.setText( "Please set '-g' option in compiler configuration to be able to debug your project." ) msg.setWindowTitle("Debug warning") msg.exec_() return False self.terminal.executeCommand(commandString) self.toolBar.projectComboBox.setCurrentText(proxy.path) def runAction(self, projectProxy=None): currentProject: ProjectNode = self.configurationManager.currentProject if not currentProject: self.showNoCurrentProjectMessage("Run") return if not os.path.exists(currentProject.proxy.getProjectPath()): currentProject.eventManager.invalidProject.emit(currentProject) return proxy = None if projectProxy: proxy = projectProxy else: if currentProject: proxy = currentProject.proxy if proxy: commandString = proxy.getProjectRunCommand() self.terminal.console.setFocus() if self.terminal.executeCommand(proxy.getProjectCompileCommand()): self.terminal.executeCommand(commandString) self.toolBar.projectComboBox.setCurrentText(proxy.path) def compileAction(self, projectProxy=None): currentProject: ProjectNode = self.configurationManager.currentProject if not currentProject: self.showNoCurrentProjectMessage("Compile") return if not os.path.exists(currentProject.proxy.getProjectPath()): currentProject.eventManager.invalidProject.emit(currentProject) return proxy = None if projectProxy: proxy = projectProxy else: if currentProject: proxy = currentProject.proxy if proxy: commandString = proxy.getProjectCompileCommand() self.terminal.console.setFocus() self.terminal.executeCommand(commandString) self.toolBar.projectComboBox.setCurrentText(proxy.path) def showNoCurrentProjectMessage(self, action: str): msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText("You have to select a project first.") msg.setWindowTitle("{} error".format(action.capitalize())) msg.exec_() def checkExecutable(self): if self.editor.filePath: destination = self.editor.filePath[:-1] + "out" return os.path.exists(destination) return None def loadFileText(self, fileProxy): key = "{}/{}".format(fileProxy.parent.path, fileProxy.path) if key in self.editorTabs.projectTabs: self.editorTabs.setCurrentIndex( self.editorTabs.tabs.index(fileProxy)) return text = self.openFileAction(fileProxy) fileProxy.text = text fileProxy.hasUnsavedChanges = False if fileProxy.getFilePath()[-1].lower() == "c": currentText = "C" else: currentText = "Assembly" update = True if len(self.editorTabs.tabs) == 0: self.editorTabs.tabs.append(fileProxy) update = False self.editorTabs.addNewTab(fileProxy, update) self.statusBar.comboBox.setCurrentText(currentText) if currentText == "Assembly": self.editorTabs.projectTabs[ key].widget.editor.sintaksa = AsemblerSintaksa( self.editorTabs.projectTabs[key].widget.editor.document()) elif currentText == "C": self.editorTabs.projectTabs[key].widget.editor.sintaksa = CSyntax( self.editorTabs.projectTabs[key].widget.editor.document()) def updateEditorTrie(self, proxy: FileProxy): key = "{}/{}".format(proxy.parent.path, proxy.path) if key in self.editorTabs.projectTabs: self.editorTabs.projectTabs[key].widget.editor.updateTrie() self.editorTabs.removeChangeIdentificator(proxy) def saveAllFiles(self, projectProxy=None): couldNotBeSaved = [] for i in range(len(self.editorTabs.tabs)): fileProxy = self.editorTabs.tabs[i] try: if fileProxy and fileProxy.hasUnsavedChanges: if projectProxy and fileProxy.parent.path != projectProxy.path: continue with open(fileProxy.getFilePath(), 'w') as file: file.write(fileProxy.text) fileProxy.hasUnsavedChanges = False self.updateEditorTrie(fileProxy) except: couldNotBeSaved.append(fileProxy.path) self.saveWorkspaceAction() if couldNotBeSaved: msg = QMessageBox() msg.setStyleSheet("background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText("The following file(s) could not be saved: {}".format( ','.join(couldNotBeSaved))) msg.setWindowTitle("File save error") msg.exec_() def saveFileAction(self): if len(self.editorTabs.tabs): proxy = self.editorTabs.getCurrentFileProxy() if proxy and proxy.hasUnsavedChanges: try: with open(proxy.getFilePath(), 'w') as file: file.write(proxy.text) proxy.hasUnsavedChanges = False self.updateEditorTrie(proxy) except: msg = QMessageBox() msg.setStyleSheet( "background-color: #2D2D30; color: white;") msg.setModal(True) msg.setIcon(QMessageBox.Critical) msg.setText( "The following file could not be saved: {}".format( proxy.path)) msg.setWindowTitle("File save error") msg.exec_() self.saveWorkspaceAction() return True def openFileAction(self, fileName: FileProxy): text = None # if fileName.text: # return fileName.text with open(fileName.getFilePath(), 'r') as file: text = file.read() return text def keyPressEvent(self, event): if event.modifiers() == Qt.ControlModifier: if event.key() == Qt.Key_Tab: self.showTabSwitcher() elif event.key() == Qt.Key_E: self.showProjectSwitcher() super(AsemblerIDE, self).keyPressEvent(event) def showProjectSwitcher(self): if self.projectSwitcher.isHidden() and len( self.configurationManager.allProjects): self.projectSwitcher.showSwitcher() self.projectSwitcher.setFocus() def showTabSwitcher(self): if self.tabSwitcher.isHidden() and len(self.editorTabs.tabs): self.tabSwitcher.showSwitcher() self.tabSwitcher.setFocus()
class PuppetMaster(QMainWindow): requestEditMode = Signal(bool) def __init__(self, parent=None, editMode=bool(False)): super(PuppetMaster, self).__init__(parent) self._parent = parent self._model = list() self.editMode = editMode self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) self.setWindowTitle('PuppetMaster') self.setMinimumHeight(1) self.setMinimumWidth(1) self.setContextMenuPolicy(Qt.PreventContextMenu) # Main tabs self.tab = CanvasGraphicsViewTab(parent=self) self.tab.requestEditMode.connect(self.set_edit) self.setCentralWidget(self.tab) # Parameter Widget self.parameter = Parameters(parent=self) self.parameterDock = QDockWidget(": Parameters ::", self) self.parameterDock.setObjectName('Parameters') self.parameterDock.setFeatures(QDockWidget.DockWidgetClosable) self.parameterDock.setWidget(self.parameter) self.parameterDock.setTitleBarWidget(QWidget(self.parameterDock)) self.parameterDock.setVisible(self.editMode) self.addDockWidget(Qt.BottomDockWidgetArea, self.parameterDock) self.tab.onSelection.connect(self.update_parameters) self.parameter.onChangeBGColor.connect(self.tab.update_bg_color) self.parameter.onChangeFontColor.connect(self.tab.update_font_color) self.parameter.onChangeFontSize.connect(self.tab.update_font_size) self.parameter.onChangeText.connect(self.tab.update_text) self.parameter.onChangeShape.connect(self.tab.update_shape) # maya Signal on selection items self.idx = OpenMaya.MEventMessage.addEventCallback( "SelectionChanged", self.tab.maya_selection) # Menu self.setMenuBar(self.create_menu()) self.set_edit(self.editMode) def update_parameters(self, node=PickNode): shape = node.Shape if isinstance(node, PickNode) else str() self.parameter.update_param(text=node.toPlainText(), fontSize=node.font().pointSize(), fontColor=node.defaultTextColor(), bgColor=node.Background, shapeName=shape) def create_menu(self): window_menu = QMenuBar(self) file_menu = window_menu.addMenu("&File") new_action = QAction("&New...", self) new_action.setShortcut('Ctrl+N') new_action.setShortcutContext(Qt.WidgetShortcut) new_action.setStatusTip('Create a new Set') new_action.triggered.connect(self.tab.new_tab) file_menu.addAction(new_action) open_action = QAction("&Open...", self) open_action.setShortcut('Ctrl+O') open_action.setShortcutContext(Qt.WidgetShortcut) open_action.setStatusTip('Open a new set') open_action.triggered.connect(self.tab.open_set) file_menu.addAction(open_action) refresh_action = QAction("&Refresh...", self) refresh_action.setStatusTip('Refresh the current sets') refresh_action.triggered.connect(self.tab.refresh_set) file_menu.addAction(refresh_action) file_menu.addSeparator() save_action = QAction("&Save...", self) save_action.setShortcut('Ctrl+S') save_action.setShortcutContext(Qt.WidgetShortcut) save_action.setStatusTip('Save the current tab') save_action.triggered.connect(self.tab.save_set) file_menu.addAction(save_action) saveAs_action = QAction("&Save As...", self) saveAs_action.setShortcut('Ctrl+Shift+S') saveAs_action.setShortcutContext(Qt.WidgetShortcut) saveAs_action.setStatusTip('Save the current tab as a new Set') saveAs_action.triggered.connect(self.tab.saveAs_set) file_menu.addAction(saveAs_action) saveAsTemp_action = QAction("&Save As Template...", self) saveAsTemp_action.setStatusTip( 'Save the current tab as a new Template') saveAsTemp_action.triggered.connect(self.tab.saveAsTemplate_set) file_menu.addAction(saveAsTemp_action) file_menu.addSeparator() rename_action = QAction("&Rename Tab...", self) rename_action.setStatusTip('Rename the current Tab') rename_action.triggered.connect(self.tab.rename_set) file_menu.addAction(rename_action) close_action = QAction("&Close Tab...", self) close_action.setShortcut('Ctrl+Shift+W') close_action.setShortcutContext(Qt.WidgetShortcut) close_action.setStatusTip('Close the current Tab') close_action.triggered.connect(self.tab.closeCurrentTab) file_menu.addAction(close_action) picker_menu = window_menu.addMenu("&Picker") self.edit_action = QAction("&Edit Mode", self) self.edit_action.setStatusTip('Toggle between view and edit mode.') self.edit_action.triggered.connect(self.edit_toggle) self.edit_action.setCheckable(True) self.edit_action.setChecked(self.editMode) picker_menu.addAction(self.edit_action) picker_menu.addSeparator() self.background_action = QAction("&Change Background...", self) self.background_action.setEnabled(self.editMode) self.background_action.setStatusTip('Change the background.') self.background_action.triggered.connect(self.tab.set_background) picker_menu.addAction(self.background_action) self.namespace_action = QAction("&Change Namespace...", self) self.namespace_action.setEnabled(self.editMode) self.namespace_action.setStatusTip('Change the namespace.') self.namespace_action.triggered.connect(self.tab.set_namespace) picker_menu.addAction(self.namespace_action) help_menu = window_menu.addMenu("&Help") wiki_action = QAction("&About PuppetMaster...", self) wiki_action.setStatusTip('Open Wiki page') wiki_action.triggered.connect(self.wiki_open) help_menu.addAction(wiki_action) return window_menu def edit_toggle(self): self.set_edit(not self.editMode) def wiki_open(self): webbrowser.open_new_tab( 'https://github.com/Bernardrouhi/PuppetMaster/wiki') def force_load(self, paths=list): self.tab.force_load(paths) def findAndLoad(self, names=list()): ''' Find the names in PuppetMaster folder and load them Parameters ---------- names: (list) List of dictionaries of name and namespace. ''' if names: self.tab.findAndLoad(names) def destroyMayaSignals(self): # destroy the connection OpenMaya.MMessage.removeCallback(self.idx) def get_edit(self): return self.editMode def set_edit(self, value=bool): self.editMode = value self.background_action.setEnabled(self.editMode) self.namespace_action.setEnabled(self.editMode) self.parameterDock.setVisible(self.editMode) self.edit_action.setChecked(self.editMode) self.tab.Edit = self.editMode # Notification if not self.editMode: warningMes( "PUPPETMASTER-INFO: Out of 'Edit Mode' you won't be able to create/edit/move or delete any node." ) else: warningMes( "PUPPETMASTER-INFO: In 'Edit Mode' command buttons won't run any commands." ) Edit = property(get_edit, set_edit) def keyPressEvent(self, event): if event.modifiers() == (Qt.ControlModifier | Qt.ShiftModifier): if event.key() == Qt.Key_W: self.tab.closeCurrentTab() elif event.key() == Qt.Key_S: self.tab.saveAs_set() elif event.modifiers() == Qt.ControlModifier: if event.key() == Qt.Key_S: self.tab.save_set() elif event.key() == Qt.Key_N: self.tab.new_tab() elif event.key() == Qt.Key_O: self.tab.open_set() else: super(PuppetMaster, self).keyPressEvent(event)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.re_editing = False self.initUI() self.setup_shortcuts() self._tmp = NamedTemporaryFile(suffix=".srt", delete=False) self.tmp = self._tmp.name self.importing = False def initUI(self): self.setMinimumSize(50, 70) self.setWindowTitle(f"Angel SubTitle Pro ({__version__})") self.sb = self.statusBar() self.updateStatusBar(__version__) # Dockable Widgets ----------------------------------------------------------- # self.dock1 = QDockWidget("Video Player", self) # Coverted to Central Widget self.dock2 = QDockWidget("Text Editing View", self) self.dock3 = QDockWidget("Table View", self) self.dock4 = QDockWidget("Waveform View", self) # Title Widgets ----------------------------------------------------------- # self.oldD1Title = self.dock1.titleBarWidget() # Dock1 self.oldD2Title = self.dock2.titleBarWidget() self.oldD3Title = self.dock3.titleBarWidget() self.oldD4Title = self.dock4.titleBarWidget() # self.noTitle1 = QWidget() # Dock1 self.noTitle2 = QWidget() self.noTitle3 = QWidget() self.noTitle4 = QWidget() # self.dock1.setTitleBarWidget(self.noTitle1) # Dock1 self.dock2.setTitleBarWidget(self.noTitle2) self.dock3.setTitleBarWidget(self.noTitle3) self.dock4.setTitleBarWidget(self.noTitle4) # Dockable Areas self.dock2.setAllowedAreas(Qt.AllDockWidgetAreas) self.dock3.setAllowedAreas(Qt.AllDockWidgetAreas) self.dock4.setAllowedAreas(Qt.AllDockWidgetAreas) # Adding Dockable Widgets ---------------------------------------------------- # self.addDockWidget(Qt.RightDockWidgetArea, self.dock1) # Video Player Panel self.addDockWidget(Qt.BottomDockWidgetArea, self.dock3) # Subtitle Table Panel self.addDockWidget(Qt.RightDockWidgetArea, self.dock2) # Subtitle Editing Panel self.addDockWidget(Qt.BottomDockWidgetArea, self.dock4) # Waveform Panel self.tabifyDockWidget(self.dock3, self.dock4) self.dock3.raise_() # Panel Instances ------------------------------------------------------------ self.videoPanel = vlcPlayer() self.editPanel = subTitleEdit() self.subTablePanel = subTitleTable() self.setCentralWidget(self.videoPanel) self.waveFormPanel = waveform(self) # self.dock1.setWidget(self.videoPanel) self.dock2.setWidget(self.editPanel) self.dock3.setWidget(self.subTablePanel) # self.dock4.setWidget(QLabel("Under Construction")) self.dock4.setWidget(self.waveFormPanel) # Right Click Actions -------------------------------------------------------- self.actShowT = QAction("Show TitleBar", self) self.actShowT.triggered.connect(self.showTitleBar) self.actHideT = QAction("Hide TitleBar", self) self.actHideT.triggered.connect(self.hideTitleBar) # Signals & Slot Connections self.videoPanel.message.connect(self.updateStatusBar) self.subTablePanel.verticalHeader().sectionDoubleClicked.connect( self.edit_row) self.subTablePanel.row_deleted.connect(self.row_deleted_update) self.subTablePanel.row_added.connect(self.row_added_update) self.waveFormPanel.file_loaded.connect(self.updateStatusBar) self.waveFormPanel.selectionCtrl.sigRegionChangeFinished.connect( self.processWaveformSelection) # Final Cleanup before show self.editPanel.subtitle.setFocus() def isVideoParsed(self): return self.videoPanel.fileParsed def getVideoFilePath(self): if self.isVideoParsed(): return self.videoPanel.currVideoFile else: return None def setup_shortcuts(self): shortcut_open = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_O), self) shortcut_open.activated.connect(self.open_project) shortcut_save = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_S), self) shortcut_save.activated.connect(self.save_project) shortcut_export = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_E), self) shortcut_export.activated.connect(self.export_project) shortcut_import = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_I), self) shortcut_import.activated.connect(self.import_project) # Subtitle Editing Shortcuts shortcut_setIn = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_BracketLeft), self) shortcut_setIn.activated.connect(self.set_intime) shortcut_setOut = QShortcut( QKeySequence(Qt.CTRL + Qt.Key_BracketRight), self) shortcut_setOut.activated.connect(self.set_outtime) shortcut_insert = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Equal), self) shortcut_insert.activated.connect(self.insert_new_subtitle) # Video Player ShortCuts shortcut_rewind = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_J), self) shortcut_rewind.activated.connect(self.videoPanel.rewind) shortcut_play_pause = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_K), self) shortcut_play_pause.activated.connect(self.videoPanel.play_pause) shortcut_forward = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_L), self) shortcut_forward.activated.connect(self.videoPanel.fastforward) shortcut_nf = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Slash), self) shortcut_nf.activated.connect(self.videoPanel.nextFrame) shortcut_pf = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Comma), self) shortcut_pf.activated.connect(self.videoPanel.previousFrame) shortcut_loadV = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_P), self) shortcut_loadV.activated.connect(self.videoPanel.load_video) shortcut_safezone = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_T), self) shortcut_safezone.activated.connect( self.videoPanel.set_overlay_safezone) @Slot(str) def updateStatusBar(self, message): self.sb.showMessage(message) def contextMenuEvent(self, event): menu = QMenu(self) menu.addAction(self.actShowT) menu.addAction(self.actHideT) menu.exec_(event.globalPos()) def showTitleBar(self): # self.dock1.setTitleBarWidget(self.oldD1Title) self.dock2.setTitleBarWidget(self.oldD2Title) self.dock3.setTitleBarWidget(self.oldD3Title) self.dock4.setTitleBarWidget(self.oldD4Title) def hideTitleBar(self): # self.dock1.setTitleBarWidget(self.noTitle1) self.dock2.setTitleBarWidget(self.noTitle2) self.dock3.setTitleBarWidget(self.noTitle3) self.dock4.setTitleBarWidget(self.noTitle4) self.repaint() @Slot() def insert_new_subtitle(self): index = self.editPanel.no.value() - 1 # Starts at 1 numRows = self.subTablePanel.rowCount() tcIn = QTableWidgetItem(self.editPanel.tcIn.text()) tcOut = QTableWidgetItem(self.editPanel.tcOut.text()) sub = QTableWidgetItem(self.editPanel.subtitle.toPlainText()) if not self.re_editing: # print(index, numRows) if index >= numRows: # print("Everything is ok, can Insert") self.subTablePanel.setRowCount(index + 1) # Insert Row Data self.subTablePanel.setItem(numRows, 0, tcIn) self.subTablePanel.setItem(numRows, 1, tcOut) self.subTablePanel.setItem(numRows, 2, sub) self.editPanel.no.setValue(index + 2) # Increment Number self.editPanel.tcIn.setText(tcOut.text()) else: self.subTablePanel.setItem(index, 0, tcIn) self.subTablePanel.setItem(index, 1, tcOut) self.subTablePanel.setItem(index, 2, sub) self.editPanel.subtitle.clear() self.editPanel.no.setValue(numRows + 1) self.editPanel.tcIn.setText( self.subTablePanel.item(numRows - 1, 1).text()) self.re_editing = False self.editPanel.subtitle.clear() self.editPanel.tcOut.setText("00000000") self.editPanel.tcDur.setText("00000000") if not self.importing: self.setup_temp_subtitles() def setup_temp_subtitles(self): self.saveSrt(self.tmp) print("Temp_File:", self.tmp) if self.videoPanel.fileParsed: self.videoPanel.set_subtitle_file(self.tmp) @Slot() def open_project(self): # print("Opening project!") file_dialog = QFileDialog(self, "Open Project") file_dialog.setNameFilter("AngelSubTitle Project Files (*.asp)") file_dialog.setDefaultSuffix("asp") selected_file, valid = file_dialog.getOpenFileName() if valid: filename, ext = splitext(selected_file) if ext == ".asp": project = xmlET.parse(selected_file) video_root = project.find("./video") subtitle_root = project.find("./subtitle") self.videoPanel.loadVideoFile(video_root.text) self.clear_table() self.editPanel.no.setValue(1) for i, sub in enumerate(subtitle_root.findall("./en/sub")): inTime, outTime, data = list(sub) # print(i, inTime.text, outTime.text, data.text) self.editPanel.tcIn.setText(inTime.text) self.editPanel.tcOut.setText(outTime.text) self.editPanel.subtitle.setText(data.text) self.insert_new_subtitle() videofile, videoext = splitext(video_root.text) if not exists(f"{videofile}.srt"): self.setup_temp_subtitles() else: self.updateStatusBar("Please select a valid Project File!") def clear_table(self): for i in range(self.subTablePanel.rowCount()): # print("removing, row", i) self.subTablePanel.removeCellWidget(i, 0) self.subTablePanel.removeCellWidget(i, 1) self.subTablePanel.removeCellWidget(i, 2) self.subTablePanel.setRowCount(0) @Slot() def row_deleted_update(self): self.editPanel.no.setValue(self.editPanel.no.value() - 1) @Slot() def row_added_update(self): self.editPanel.no.setValue(self.editPanel.no.value() + 1) @Slot() def save_project(self): # print("Saving project!") file_dialog = QFileDialog(self, "Save as") file_dialog.setNameFilter("AngelSubTitle Project Files (*.asp)") file_dialog.setDefaultSuffix("asp") selected_file, valid = file_dialog.getSaveFileName() if valid: filename, ext = splitext(selected_file) if ext != ".asp": # print(join(filename+".asp")) selected_file = f"{filename}.asp" project = xmlET.Element("Angel_Subtitle_Pro_Project") project.text = __version__ video_root = xmlET.SubElement(project, "video") video_root.text = self.videoPanel.currVideoFile subtitle_root = xmlET.SubElement(project, "subtitle") sub_en = xmlET.SubElement(subtitle_root, "en") sub_en.text = "English" for i in range(self.subTablePanel.rowCount()): curRow = xmlET.SubElement(sub_en, "sub") tcIn = xmlET.SubElement(curRow, "intime") tcIn.text = self.subTablePanel.item(i, 0).text() tcOut = xmlET.SubElement(curRow, "outtime") tcOut.text = self.subTablePanel.item(i, 1).text() sub = xmlET.SubElement(curRow, "data") sub.text = self.subTablePanel.item(i, 2).text() with open(selected_file, 'w', encoding='utf-8') as fp: fp.write( xmlET.tostring(project, encoding="unicode", method="xml")) self.updateStatusBar(f"File saved {selected_file}") @Slot() def export_project(self): # Testing SubRip (SRT) # print("Exporting current project!") file_dialog = QFileDialog(self, "Save as") selected_file, valid = file_dialog.getSaveFileName() if valid: fileName, ext = splitext(selected_file) if ext == ".txt": self.saveAvidTxt(selected_file) elif ext == ".srt": self.saveSrt(selected_file) self.updateStatusBar(f"{selected_file} Exported!") def saveAvidTxt(self, filename): with open(filename, 'w', encoding='utf-8') as fp: fp.write("<begin subtitles>\n\n") for i in range(self.subTablePanel.rowCount()): tcIn = self.subTablePanel.item(i, 0).text() tcOut = self.subTablePanel.item(i, 1).text() sub = self.subTablePanel.item(i, 2).text() fp.write(f"{tcIn} {tcOut}\n") fp.write(f"{sub}\n") fp.write("\n") fp.write("<end subtitles>") def saveSrt(self, filename): with open(filename, 'w', encoding='utf-8') as fp: for i in range(self.subTablePanel.rowCount()): fp.write(f"{i+1}\n") tcIn = TimeCode(self.subTablePanel.item(i, 0).text()) tcOut = TimeCode(self.subTablePanel.item(i, 1).text()) sub = self.subTablePanel.item(i, 2).text() fp.write(f"{tcIn.get_mstc()} --> {tcOut.get_mstc()}\n") fp.write(f"{sub}\n") fp.write("\n") @Slot() def import_project(self): file_dialog = QFileDialog(self, "Import File") selected_file, valid = file_dialog.getOpenFileName() if valid: self.importing = True # print(f"Importing {selected_file}") fileName, ext = splitext(selected_file) if ext == ".xml": self.clear_table() self.editPanel.no.setValue(1) project = xmlET.parse(selected_file) # print(project.findall('.//generatoritem')) for card in project.findall('.//generatoritem'): tcIn = TimeCode() tcOut = TimeCode() tcIn.setFrames(int(card[5].text)) tcOut.setFrames(int(card[6].text)) # print(tcIn.timecode, tcOut.timecode, card[10][6][2].text) try: sub = deepcopy( card[10][6][2].text) # Standard FCP Outline Text except IndexError: sub = deepcopy( card[13][6][2].text) # Texte avec bordure self.editPanel.tcIn.setText(tcIn.timecode) self.editPanel.tcOut.setText(tcOut.timecode) self.editPanel.subtitle.setText(sub) self.insert_new_subtitle() videofile = project.find( ".//media/video/track/clipitem/file/pathurl") p = urlparse(videofile.text) finalPath = abspath(join(p.netloc, p.path)) if exists(finalPath): # print(f"Loading {finalPath}") self.videoPanel.loadVideoFile(finalPath) else: # print(f"File not found {finalPath}") self.updateStatusBar(f"File not found {finalPath}") videofile, videoext = splitext(finalPath) if not exists(f"{videofile}.srt"): self.setup_temp_subtitles() self.importing = False self.saveSrt(self.tmp) @Slot() def set_intime(self): if not self.videoPanel.isPlaying and self.videoPanel.fileParsed: self.editPanel.tcIn.setText(self.videoPanel.currPos.timecode) @Slot() def set_outtime(self): if not self.videoPanel.isPlaying and self.videoPanel.fileParsed: self.editPanel.tcOut.setText(self.videoPanel.currPos.timecode) self.editPanel.calculate_duration() @Slot() def edit_row(self, row_number): self.editPanel.no.setValue(row_number + 1) self.editPanel.tcIn.setText( self.subTablePanel.item(row_number, 0).text()) self.editPanel.tcOut.setText( self.subTablePanel.item(row_number, 1).text()) self.editPanel.calculate_duration() self.editPanel.subtitle.clear() self.editPanel.subtitle.setText( self.subTablePanel.item(row_number, 2).text()) self.editPanel.clearStyles() self.re_editing = True def map(self, value, low1, high1, low2, high2): # Value Remap function return low2 + (value - low1) * (high2 - low2) / (high1 - low1) def processWaveformSelection(self): try: wavIn, wavOut = self.waveFormPanel.selectionCtrl.getRegion() total_audio_frames = self.waveFormPanel.getTotalAudioFrames() total_video_frames = self.videoPanel.video_duration.frames x = self.map(int(wavIn), 0, total_audio_frames / 100, 0, total_video_frames) # Because audio filtering y = self.map( int(wavOut), 0, total_audio_frames / 100, 0, total_video_frames) # of 100 in wavformPanel.py Line 83 selIn = TimeCode() selIn.setFrames(int(x)) selOut = TimeCode() selOut.setFrames(int(y)) # print("Selected ->", wavIn, wavOut, "->", x, y, "->",selIn, selOut, "->", selIn.frames, selOut.frames) self.editPanel.tcIn.setText(selIn.timecode) self.editPanel.tcOut.setText(selOut.timecode) self.editPanel.calculate_duration() except AttributeError: print("please make sure you have a video and audio file loaded!") def closeEvent(self, event): # print("closing now!") self._tmp.close() os.unlink(self._tmp.name)