Ejemplo n.º 1
0
    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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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')
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
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()
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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)