Beispiel #1
0
class MainWindow(QtGui.QMainWindow):
	query_config = None
	
	def __init__(self):
		QtGui.QMainWindow.__init__(self)
		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)
		
		''' Signals '''
		QtCore.QObject.connect(self.ui.actionRefreshTicketList, QtCore.SIGNAL(_fromUtf8("triggered()")), self.refreshTicketList)
		QtCore.QObject.connect(self.ui.actionModifyQuery, QtCore.SIGNAL(_fromUtf8("triggered()")), self.modifyTicketQuery)
		self.ui.ticketListTree.doubleClicked.connect(self.TicketTreeDoubleClicked)
		
		QtCore.QTimer.singleShot(50, self.OnLoad)
		
	def OnLoad(self):
		try:
			''' Setup ticket tree '''
			self.ui.ticketListTree.setItemsExpandable(True)
			self.ui.ticketListTree.expandAll()
			
			''' Setup a timer to keep refreshing ticket list '''
			self.query_config = QueryConfig()
			self.refreshTicketList()
		except QueryError, e:
			msgbox = Messages.MessageBox()
			msgbox.showMessageWithError(e)
Beispiel #2
0
class MainWindow(QMainWindow):
    def __init__(self, user):
        QMainWindow.__init__(self)
        self.ui=Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.mdiArea.setOption(QMdiArea.DontMaximizeSubWindowOnActivation, True)
        self.user = user
        QObject.connect(self.ui.client_add_menu, SIGNAL("triggered()"), self, SLOT("show_add_client_widget()"))
        QObject.connect(self.ui.order_search_menu, SIGNAL("triggered()"), self, SLOT("show_orders_widget()"))
        QObject.connect(self.ui.order_add_menu, SIGNAL("triggered()"), self, SLOT("show_add_order_widget()"))


    @pyqtSlot()
    def show_add_client_widget(self):
        frame = QMdiSubWindow()
        widget = AddClientWidget(self)
        widget.setWindowModality(2)
        frame.setWidget(widget)
        frame.setAttribute(Qt.WA_DeleteOnClose)
        self.ui.mdiArea.addSubWindow(widget)
        widget.show()

    @pyqtSlot()
    def show_add_order_widget(self):
        frame = QMdiSubWindow()
        widget = AddOrderWidget(self)
        widget.setWindowModality(2)
        frame.setWidget(widget)
        frame.setAttribute(Qt.WA_DeleteOnClose)
        self.ui.mdiArea.addSubWindow(widget)
        widget.show()

    @pyqtSlot()
    def show_orders_widget(self):
        frame = QMdiSubWindow()
        widget = OrdersWidget(self)
        widget.setWindowModality(2)
        frame.setWidget(widget)
        frame.setAttribute(Qt.WA_DeleteOnClose)
        self.ui.mdiArea.addSubWindow(widget)
        widget.show()
Beispiel #3
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent = None):
        super().__init__(parent)
        self.newEntry = newEntryWindow()
        self.MainWindow = Ui_MainWindow()
        self.editLocationWindow = ui.editLocSubWindow.editLocSubWindow()

        self.initMe()

    def initMe(self):
        self.MainWindow.setupUi(self)
        self.statusBar().showMessage('Hallo und Willkommen!')
        self.setWindowTitle("Vorratslager")
        self.MainWindow.pB_hinzufuegen.clicked.connect(self.addNewEntry)
        self.itemDetailFrame = self.MainWindow.ItemDetailframe
        self.itemDetailFrame.setEnabled(False)
        self.itemDetailFrame.hide()

        #Menubar Actions
        self.MainWindow.actionBeenden.triggered.connect(self.close)
        self.MainWindow.actionAddFood.triggered.connect(self.addNewEntry)
        self.MainWindow.actionRefresh.triggered.connect(self.readDataIntoTable)
        self.MainWindow.actionKategorienBearbeiten.triggered.connect(self.openEditLocationWindow)

        #Database einlesen
        self.readDataIntoTable()
        self.MainWindow.listWidget.itemClicked.connect(self.listItemClicked)

    def listItemClicked(self, item):
        listdata = item.data(qt.UserRole)

        itemdetails = db.readItem(listdata[0])

        self.MainWindow.lbl_DetailName_2.setText(itemdetails['name'])
        self.MainWindow.lbl_DetailMHD.setText(itemdetails['mhd'])
        print(itemdetails['mhd'])
        mainlocation = listdata[5]
        if mainlocation is not None:
            self.MainWindow.lbl_DetailMainLagerplatz.setText(db.locationfromid('main', listdata[5])['name'])
        if not itemdetails['subLocation'] is None:
            self.MainWindow.lbl_DetailSubLagerplatz.show()
            self.MainWindow.lbl_DetailPfeilLocation.show()
            self.MainWindow.lbl_DetailSubLagerplatz.setText(db.locationfromid('sub', listdata[6])['name'])
        else:
            self.MainWindow.lbl_DetailSubLagerplatz.hide()
            self.MainWindow.lbl_DetailPfeilLocation.hide()
        self.itemDetailFrame.setEnabled(True)
        self.itemDetailFrame.show()
        print(listdata[11])

    def readDataIntoTable(self):
        items = db.readDb()
        if not (len(items) <= 0):
            columnCount = len(items[0])
            self.MainWindow.tW_Items.setColumnCount(columnCount)
            self.MainWindow.tW_Items.setRowCount(0)
            header = self.MainWindow.tW_Items.horizontalHeader()
            self.MainWindow.listWidget.clear()
            for i in items:
                data = []
                listItem = Qt.QListWidgetItem()
                listItem.setText(str(i['anzahl']) + 'x ' + i['name'] + ' ' + str(i['menge']))
                for e in i:
                    data.append(i[e])
                if i['type'] == 'food':
                    listItem.setIcon(QIcon(item.icon_food))
                    #Haltbarkeit in Tage ausrechnen
                    haltbarkeit = []
                    #tagenochHaltbar = calculateHaltbarkeitinTagen(i[7])
                    haltbarkeit = calculateHaltbarkeit(i['mhd'])
                    data.append(haltbarkeit)
                elif i['type'] == 'nonfood':
                    listItem.setIcon(QIcon(item.icon_nonfood))
                listItem.setData(qt.UserRole, data)
                self.MainWindow.listWidget.addItem(listItem)

            for row_number, row_data in enumerate(items):
                self.MainWindow.tW_Items.insertRow(row_number)

                for column_number, data in enumerate(row_data):

                    self.MainWindow.tW_Items.setItem(row_number, column_number, QtWidgets.QTableWidgetItem(str(data)))


    def addNewEntry(self):
        if self.newEntry.exec() == QDialog.Rejected:
            print("fertig")
            self.readDataIntoTable()


    def openEditLocationWindow(self):
        self.editLocationWindow.exec()
class AQMain(QtGui.QMainWindow):
    
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        background = xml.find("./Settings/Background").text
        self.ui.panel_container.setStyleSheet("QStackedWidget{background-image: url(" + background + ");}")
        
        #logging
        logging.basicConfig(filename='logfile.log',level=logging.DEBUG)
        logging.basicConfig(format='%(asctime)s %(filename)s %(lineno)d %(message)s')
                
        # communicator and event dispatcher building                
        self._ui_event_dispatcher = UIEventDispatcher() 
        self._communicator = SerialCommunicator()
        self._vehicle_event_dispatcher = VehicleEventDispatcher()
        self._connection_manager = ConnectionManager(app, 
                                                     self.ui, 
                                                     xml, 
                                                     self._communicator, 
                                                     self._ui_event_dispatcher, 
                                                     self._vehicle_event_dispatcher)
        self._panels_context_builder = PanelsContextBuilder(self._ui_event_dispatcher, self._vehicle_event_dispatcher)
        self._view_menu_context_builder = ViewMenuContextBuilder(self.ui.menu_view,
                                                                 self._ui_event_dispatcher,
                                                                 self._ui_event_dispatcher) 
        self._side_menu_contextual_builder = SideMenuContextualBuilder(self._ui_event_dispatcher,
                                                                       self._ui_event_dispatcher,
                                                                       self.ui.side_menu_info_page,
                                                                       self.ui.side_menu_setting_page,
                                                                       self.ui.side_menu_troubleshooting_page,
                                                                       self.ui.side_menu_mission_planer_page)
        
        # Default main window conditions
        self.ui.buttonDisconnect.setEnabled(False)
        self.ui.buttonConnect.setEnabled(True)
        self.ui.comPort.setEnabled(True)
        self.ui.baudRate.setEnabled(True)
        self.ui.status.setText("Not connected to the AeroQuad")
        self.availablePorts = []
        self.boardConfiguration = {}
        self.manualConnect = True
        
        self.ui.side_menu.hide()
        self.ui.button_home.hide()
        
        # Load splash_screen screen
        self._splash_screen = SplashScreen()
        self._splash_screen.setupUi(self._splash_screen)
        self.ui.panel_container.addWidget(self._splash_screen)
        
        # Dynamically configure board type menu and subPanel menu from XML configuration file
        self._current_active_panel = None
        self.activeSubPanelName = ''

        # Connect GUI slots and signals
        self.ui.comPort.return_handler = self._connection_manager.connect_to_aeroquad
        self.ui.buttonConnect.clicked.connect(self._connection_manager.connect_to_aeroquad)
        self.ui.buttonDisconnect.clicked.connect(self._connection_manager.disconnect_from_aeroquad)
        self.ui.action_exit.triggered.connect(QtGui.qApp.quit)
        self.ui.comPort.currentIndexChanged.connect(self._connection_manager.search_for_available_COM_port)
        self.ui.action_bootup_delay.triggered.connect(self._connection_manager.save_boot_delay)
        self.ui.action_comm_timeout.triggered.connect(self._connection_manager.save_connection_timeout_delay)
        
        self._ui_event_dispatcher.register(self._display_panel_event, UIEventDispatcher.DISPLAY_PANEL_EVENT)
        self._ui_event_dispatcher.register(self._connection_state_changed, UIEventDispatcher.CONNECTION_STATE_CHANGED_EVENT)
       
    def _display_panel_event(self, event, panel_id):
        if self._current_active_panel != None:
            self._current_active_panel.stop()
            self.ui.panel_container.removeWidget(self._current_active_panel)
        try :
            self._current_active_panel = PanelsContextBuilder.PANELS_DICTIONNARY[panel_id]
            self.ui.panel_container.addWidget(self._current_active_panel)
            self.ui.panel_container.setCurrentWidget(self._current_active_panel)
            self._current_active_panel.start();
        except:
            logging.error("Failed to load panel = " + panel_id)
            print "Failed to load panel = " + panel_id
            
        
    def _connection_state_changed(self, event, is_connected):
        if not is_connected :
            if self._current_active_panel != None:
                self._current_active_panel.stop()
                self.ui.panel_container.removeWidget(self._current_active_panel)
                self._current_active_panel = None
            self.ui.panel_container.setCurrentIndex(0)
            self.ui.side_menu.hide()
            self.ui.button_home.hide()
        else :
            self.ui.side_menu.show()
            self.ui.button_home.show()

    def exit(self):
        self._communicator.disconnect()
        sys.exit(app.exec_())

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
Beispiel #5
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.retranslateUi(self)

        self.ui.tabClients.setTabsClosable(True)
        self.ui.tabClients.tabCloseRequested.connect(self.tab_close_requested)

        self.scanDevice = ScanDevice()
        self.scanDevice.new_device.connect(self.ui.lwdScanResult.addItem)
        self.ui.cmbServiceIp.addItems(self.scanDevice.get_host_ip())
        self.ui.cmbServiceIp.currentIndexChanged.connect(
            self.scanDevice.set_current_index)

        self.server = Server(self.ui.cmbServiceIp.currentText(),
                             int(self.ui.leServerPort.text()), self)
        self.server.new_client.connect(self.new_client)
        self.ui.btnRestartServer.clicked.connect(self.restart_server)

        self.ui.btnScanDevice.clicked.connect(self.scan_device)
        self.ui.lwdScanResult.itemDoubleClicked.connect(
            self.lwd_scan_result_double_clicked)

        self.__double_tag = None

        self.titleToClient = {}

    def new_client(self, client):
        tag = self.__double_tag
        if tag:
            index = self.find_tab(tag)
            if index == -1:
                message_ctrl = MessageCtrl(client, self)
                self.ui.tabClients.addTab(message_ctrl, self.__double_tag)
            else:
                message_ctrl = self.ui.tabClients.widget(index)
                message_ctrl.set_new_client(client)
            self.__double_tag = None

    def restart_server(self):
        self.clear_result()
        self.server.restart_server(self.ui.cmbServiceIp.currentText(),
                                   int(self.ui.leServerPort.text()))

    # 找到指定title,return index,否则return -1
    def find_tab(self, title):
        for index in range(self.ui.tabClients.count()):
            if self.ui.tabClients.tabText(index) == title:
                return index
        return -1

    def scan_device(self):
        self.ui.lwdScanResult.clear()
        self.scanDevice.search()

    def lwd_scan_result_double_clicked(self, item):
        tag = item.text()
        self.__double_tag = tag
        if self.find_tab(tag) == -1:
            self.scanDevice.connect_device(tag.split(":")[1])

    def close_tab(self, index):
        tag = self.ui.tabClients.tabText(index)
        self.scanDevice.disconnect_device(tag.split(":")[1])
        self.ui.tabClients.removeTab(index)

    def tab_close_requested(self, index):
        self.close_tab(index)

    def clear_result(self):
        self.ui.lwdScanResult.clear()
        count = self.ui.tabClients.count()
        for index in range(count):
            self.close_tab(0)
Beispiel #6
0
class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(ApplicationWindow, self).__init__()
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self._translate = self.ui.retranslateUi(self)

        self.ui.tabWidget.clear()

        self.model = QFileSystemModel()
        self.model.setRootPath(QtCore.QDir().rootPath())
        #        self.model.setFilter(QtCore.QDir().AllDirs|QtCore.QDir().NoDot)
        self.model.setNameFilters(filters)
        source = self.model.index(QtCore.QDir().homePath())

        self.proxyModel = QtCore.QSortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.model)
        self.proxyModel.setDynamicSortFilter(True)
        index = self.proxyModel.mapFromSource(source)

        self.ui.treeView.setModel(self.model)
        self.ui.treeView.setRootIndex(source)

        #        self.ui.treeView.setModel(self.proxyModel)
        #        self.ui.treeView.setRootIndex(index)

        #        self.ui.treeView.setRootIndex(self.model.index(user_home()))
        #        self.ui.treeView.setModel(self.proxyModel)
        #        self.ui.treeView.setRootIndex(self.proxyModel)

        [self.ui.treeView.setColumnHidden(cols, True) for cols in range(1, 4)]
        self.ui.treeView.doubleClicked.connect(self.onClick)
        self.ui.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.ui.treeView.customContextMenuRequested.connect(
            self.create_popup_menu)

        self.ui.filedirsearch.textChanged.connect(self.textFilter)
        self.ui.actionOpenProject.triggered.connect(self.openProjDialog)
        self.ui.actionOpenFile.triggered.connect(self.openFileDialog)
        self.ui.actionAbout_Qt.triggered.connect(self.aboutQt)
        self.ui.actionQuit.triggered.connect(self.close)
        self.ui.action_Save.triggered.connect(self.save)

        self.ui.tabWidget.tabCloseRequested.connect(self.removeTab)
        self.textFilter()

    def add_cb(self):
        print "add callback"

    def new_file(self):
        pass

    def load_yaml_to_gui(self, path):
        self.ui.tabWidget.addTab(self.addXCCDFTab(path),
                                 os.path.basename(path))
        data = open_yaml(path)
        if data is not None:
            if "title" in data:
                self.ui.txtTitle.setText(data['title'])
            if "description" in data:
                self.ui.txtDesc.setPlainText(data['description'])

            if path.endswith(".rule"):
                if "severity" in data:
                    self.ui.severityComboBox.setCurrentText(
                        data['severity'].title())
                if "ocil_clause" in data:
                    self.ui.txtOCILclause.setText(data['ocil_clause'])
                if "ocil" in data:
                    self.ui.txtOCIL.setPlainText(data['ocil'])
                if "rationale" in data:
                    self.ui.txtRationale.setPlainText(data['rationale'])
                header = self.ui.identsTable
                header.setHorizontalHeaderLabels(["OS", "CCE"])
                header.setColumnCount(3)
                header.verticalHeader().hide()
                header.setHorizontalHeaderItem(
                    0, QtWidgets.QTableWidgetItem("Identifier Type"))
                header.setHorizontalHeaderItem(
                    1, QtWidgets.QTableWidgetItem("Operating System"))
                header.setHorizontalHeaderItem(
                    2, QtWidgets.QTableWidgetItem("Identifier"))
                header.setColumnWidth(0, 137)
                header.setColumnWidth(1, 160)
                header.setColumnWidth(2, 137)
                header.insertRow(header.rowCount())
                if "identifiers" in data:
                    for row, keys in enumerate(data["identifiers"].keys()):
                        val = data["identifiers"][keys]
                        if "@" in keys:
                            ident_type = keys.split("@")[0]
                            os_type = keys.split("@")[1]
                        else:
                            ident_type = keys
                            os_type = "All"
                        header.setItem(row, 0,
                                       QtWidgets.QTableWidgetItem(ident_type))
                        header.setItem(row, 1,
                                       QtWidgets.QTableWidgetItem(os_type))
                        header.setItem(row, 2, QtWidgets.QTableWidgetItem(val))
                        header.insertRow(header.rowCount())
#                header.doubleClicked.connect()

                self.ui.severityComboBox.activated.connect(self.onChange)
                self.ui.txtOCIL.textChanged.connect(self.onChange)
                self.ui.txtOCILclause.textChanged.connect(self.onChange)
                self.ui.txtRationale.textChanged.connect(self.onChange)


#        if path.endswith(".profile"):
#            tv = self.ui.tableView
#            header = ['rule_selection']
#        tm = MyTableModel(self.tabledata, header, self)
#        tv.setModel(tm)
#
#        # hide grid
##            tv.setShowGrid(True)
#
#        # set the font
#        font = QFont("Courier New", 8)
#        tv.setFont(font)
#
#        # hide vertical header
#            vh = tv.verticalHeader()
#            vh.setVisible(False)
#
#        # set horizontal header properties
#            hh = tv.horizontalHeader()
#            hh.setStretchLastSection(True)
#
#        # set column width to fit contents
#            tv.resizeColumnsToContents()
#
#        # set row height
#        nrows = len(self.tabledata)
#        for row in xrange(nrows):
#            tv.setRowHeight(row, 18)
#
##        # enable sorting
#            tv.setSortingEnabled(True)
#
#        self.model = QtGui.QStandardItemModel(parent=self)
#        self.model.setHorizontalHeaderLabels(['Source', 'Destination', 'Protoco', 'Info'])
#        self.setModel(self.model)
#        self.setColumnWidth(0, 120)
#        self.setColumnWidth(1, 120)
#        self.setColumnWidth(2, 100)
#        self.setColumnWidth(3, 350)
#        self.setAlternatingRowColors(True)
#        self.setAutoScroll(True)
#        self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
#        self.setEditTriggers(QtGui.QTableView.NoEditTriggers)
#        self.setSelectionMode(QtGui.QTableView.SingleSelection)
#            for selection in data["selections"]:
#                tv.setItem(selection)
#
#
#
        self.ui.txtDesc.textChanged.connect(self.onChange)
        self.ui.txtTitle.textChanged.connect(self.onChange)

    def addXCCDFTab(self, path):
        self.ui.tab = QtWidgets.QWidget()
        _translate = QtCore.QCoreApplication.translate
        self.ui.tab.setObjectName("tab")
        self.ui.formLayoutWidget = QtWidgets.QWidget(self.ui.tab)
        self.ui.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 501, 541))
        self.ui.formLayoutWidget.setObjectName("formLayoutWidget")
        self.ui.scap = QtWidgets.QFormLayout(self.ui.formLayoutWidget)
        self.ui.scap.setContentsMargins(1, 1, 1, 1)
        self.ui.scap.setObjectName("scap")
        self.ui.lblscap = QtWidgets.QLabel(self.ui.formLayoutWidget)
        self.ui.lblscap.setObjectName("lblscap")
        self.ui.scap.setWidget(0, QtWidgets.QFormLayout.LabelRole,
                               self.ui.lblscap)
        self.ui.txtTitle = QtWidgets.QLineEdit(self.ui.formLayoutWidget)
        self.ui.txtTitle.setObjectName("txtTitle")
        self.ui.scap.setWidget(0, QtWidgets.QFormLayout.FieldRole,
                               self.ui.txtTitle)
        self.ui.lbldesc = QtWidgets.QLabel(self.ui.formLayoutWidget)
        self.ui.lbldesc.setObjectName("lbldesc")
        self.ui.scap.setWidget(1, QtWidgets.QFormLayout.LabelRole,
                               self.ui.lbldesc)
        self.ui.txtDesc = QtWidgets.QPlainTextEdit(self.ui.formLayoutWidget)
        self.ui.txtDesc.setObjectName("txtDesc")
        self.ui.scap.setWidget(1, QtWidgets.QFormLayout.FieldRole,
                               self.ui.txtDesc)

        self.ui.lblscap.setText(_translate("MainWindow", "Title"))
        self.ui.lbldesc.setText(_translate("MainWindow", "Description"))

        if path.endswith(".rule"):
            self.ui.severityLabel = QtWidgets.QLabel(self.ui.formLayoutWidget)
            self.ui.severityLabel.setObjectName("severityLabel")
            self.ui.scap.setWidget(2, QtWidgets.QFormLayout.LabelRole,
                                   self.ui.severityLabel)
            self.ui.severityComboBox = QtWidgets.QComboBox(
                self.ui.formLayoutWidget)
            self.ui.severityComboBox.setObjectName("severityComboBox")
            self.ui.scap.setWidget(2, QtWidgets.QFormLayout.FieldRole,
                                   self.ui.severityComboBox)
            self.ui.identsLabel = QtWidgets.QLabel(self.ui.formLayoutWidget)
            self.ui.identsLabel.setObjectName("identsLabel")
            self.ui.scap.setWidget(3, QtWidgets.QFormLayout.LabelRole,
                                   self.ui.identsLabel)
            self.ui.identsTable = QtWidgets.QTableWidget(
                self.ui.formLayoutWidget)
            self.ui.identsTable.setObjectName("identsTable")
            self.ui.scap.setWidget(3, QtWidgets.QFormLayout.FieldRole,
                                   self.ui.identsTable)

            self.ui.oCILClauseLabel = QtWidgets.QLabel(
                self.ui.formLayoutWidget)
            self.ui.oCILClauseLabel.setObjectName("oCILClauseLabel")
            self.ui.scap.setWidget(4, QtWidgets.QFormLayout.LabelRole,
                                   self.ui.oCILClauseLabel)
            self.ui.txtOCILclause = QtWidgets.QLineEdit(
                self.ui.formLayoutWidget)
            self.ui.txtOCILclause.setObjectName("txtOCILclause")
            self.ui.scap.setWidget(4, QtWidgets.QFormLayout.FieldRole,
                                   self.ui.txtOCILclause)
            self.ui.oCILLabel = QtWidgets.QLabel(self.ui.formLayoutWidget)
            self.ui.oCILLabel.setObjectName("oCILLabel")
            self.ui.scap.setWidget(5, QtWidgets.QFormLayout.LabelRole,
                                   self.ui.oCILLabel)
            self.ui.txtOCIL = QtWidgets.QPlainTextEdit(
                self.ui.formLayoutWidget)
            self.ui.txtOCIL.setObjectName("txtOCIL")
            self.ui.scap.setWidget(5, QtWidgets.QFormLayout.FieldRole,
                                   self.ui.txtOCIL)
            self.ui.oRationaleLabel = QtWidgets.QLabel(
                self.ui.formLayoutWidget)
            self.ui.oRationaleLabel.setFrameShape(QtWidgets.QFrame.NoFrame)
            self.ui.oRationaleLabel.setObjectName("oRationaleLabel")
            self.ui.scap.setWidget(6, QtWidgets.QFormLayout.LabelRole,
                                   self.ui.oRationaleLabel)
            self.ui.txtRationale = QtWidgets.QPlainTextEdit(
                self.ui.formLayoutWidget)
            self.ui.txtRationale.setObjectName("txtRationale")
            self.ui.scap.setWidget(6, QtWidgets.QFormLayout.FieldRole,
                                   self.ui.txtRationale)

            self.ui.identsLabel.setText(
                _translate("MainWindow", "Indentifiers"))
            self.ui.severityLabel.setText(_translate("MainWindow", "Severity"))
            self.ui.oCILClauseLabel.setText(
                _translate("MainWindow", "OCIL Clause"))
            self.ui.oCILLabel.setText(_translate("MainWindow", "OCIL"))
            self.ui.oRationaleLabel.setText(
                _translate("MainWindow", "Rationale"))

            [self.ui.severityComboBox.addItem(sevs) for sevs in severity]
        if path.endswith(".profile"):
            self.ui.selectionLabel = QtWidgets.QLabel(self.ui.formLayoutWidget)
            self.ui.selectionLabel.setObjectName("selectionLabel")
            self.ui.scap.setWidget(2, QtWidgets.QFormLayout.LabelRole,
                                   self.ui.selectionLabel)

            self.ui.selectionLabel.setText(
                _translate("MainWindow", "Rule Selection"))

        return self.ui.tab

    def onClick(self, index):
        path = self.sender().model().filePath(index)
        if not self.sender().model().isDir(index):
            self.load_yaml_to_gui(path)
        else:
            #            if path.endswith(".."):
            #                path = path.rsplit("/", 2)[0]
            #                print index
            self.ui.treeView.setRootIndex(index)

    def openProjDialog(self):
        dirname = QFileDialog()
        dirname.setFileMode(QFileDialog.Directory)
        dirname = QFileDialog.getExistingDirectory(
            self,
            "Open Project Folder",
            options=QFileDialog.DontUseNativeDialog
            | QFileDialog.HideNameFilterDetails | QFileDialog.ShowDirsOnly)

        if dirname != "":
            self.setDirectory(dirname)
        else:
            self.setDirectory(QtCore.QDir().homePath())

    def openFileDialog(self):
        fname = QFileDialog()
        fname.setFileMode(QFileDialog.Directory)
        fname = QFileDialog.getOpenFileNames(
            self,
            "Select File to Open",
            QtCore.QDir().homePath(),
            "All (*.rule *.group *.profile);;Rules ( *.rule);;Groups (*.group);;Profiles (*.profile)",
            options=QFileDialog.DontUseNativeDialog)
        path = "".join(fname[0])
        if path:
            self.load_yaml_to_gui(path)

    def saveFileDialog(self, path):
        quit_msg = "Save changes before closing?"
        reply = QtWidgets.QMessageBox.question(self, 'Message', quit_msg,
                                               QtWidgets.QMessageBox.Yes,
                                               QtWidgets.QMessageBox.No)

        if reply == QtWidgets.QMessageBox.Yes:
            yaml_dict = UnsortableOrderedDict([
                ("documentation_complete", "true"),
            ])
            yaml_dict["title"] = self.ui.txtTitle.text()
            yaml_dict["description"] = self.ui.txtDesc.toPlainText()
            if path.endswith("*.rule"):
                yaml_dict["severity"] = self.ui.severityComboBox.currentText(
                ).lower()
                yaml_dict["ocil_clause"] = self.ui.txtOCILclause.text()
                yaml_dict["ocil"] = self.ui.txtOCIL.toPlainText()
                yaml_dict["rationale"] = self.ui.txtRationale.toPlainText()

            write_yaml(yaml_dict, path.strip("*"))

    def save(self, index):
        index = self.ui.tabWidget.currentIndex()
        filename = self.ui.tabWidget.tabText(index)
        yaml_dict = UnsortableOrderedDict([
            ("documentation_complete", "true"),
        ])
        yaml_dict["title"] = self.ui.txtTitle.text()
        yaml_dict["description"] = self.ui.txtDesc.toPlainText()
        if filename.endswith(".rule"):
            yaml_dict["severity"] = self.ui.severityComboBox.currentText(
            ).lower()
            yaml_dict["ocil_clause"] = self.ui.txtOCILclause.text()
            yaml_dict["ocil"] = self.ui.txtOCIL.toPlainText()
            yaml_dict["rationale"] = self.ui.txtRationale.toPlainText()

        write_yaml(yaml_dict, self.ui.tabWidget.tabText(index).strip("*"))
        self.ui.tabWidget.setTabText(index, filename.strip("*"))

    def setDirectory(self, directory):
        self.ui.treeView.setModel(self.model)
        self.ui.treeView.setRootIndex(self.model.index(directory))

    def create_popup_menu(self, pos):
        self.popup_menu = QtWidgets.QMenu()
        self.popup_menu.addAction("New", self.add_cb)
        self.popup_menu.addAction("Rename", self.add_cb)
        self.popup_menu.addSeparator()
        self.popup_menu.addAction("Delete", self.add_cb)

        self.popup_menu.exec_(self.ui.treeView.viewport().mapToGlobal(pos))

    def on_context_menu(self, pos):
        node = self.treeWidget.mapToGlobal(pos)
        self.popup_menu.exec_(self.treeWidget.mapToGlobal(pos))

    def textFilter(self):
        regExp = QtCore.QRegExp(self.ui.filedirsearch.text(),
                                QtCore.Qt.CaseInsensitive)
        self.proxyModel.setFilterRegExp(regExp)

    def removeTab(self, index):
        if self.ui.tabWidget.tabText(index).startswith("*"):
            self.saveFileDialog(self.ui.tabWidget.tabText(index))
        self.ui.tabWidget.removeTab(index)

    def onChange(self):
        index = self.ui.tabWidget.currentIndex()
        filename = self.ui.tabWidget.tabText(index)
        if not filename.startswith("*"):
            filename = "*" + filename
        self.ui.tabWidget.setTabText(index, filename)

    def aboutQt(self):
        QMessageBox.aboutQt(self)
Beispiel #7
0
class ControlMainWindow(QtGui.QMainWindow):
	_storeButtonUsed = False
	_gv = None
	_parser = None
	_inter = None
	_workpiecePos = [ 5, 5, 5 ]
	_originOffset = [ 0, 0 ]
	_polarCorrection = [ 1, 0 ]
	_debounce = None

	def __init__(self, chatBackend):
		super(ControlMainWindow, self).__init__(None)

		self._machine = MachineController(chatBackend);
		self._machine.machineStatus().statusUpdated.connect(self.statusUpdated)

		self._ui = Ui_MainWindow()
		self._ui.setupUi(self)

		self._ui.stop.clicked.connect(self._machine.stop)
		self._ui.refMovement.clicked.connect(self.refMovement)
		self._ui.importGCode.clicked.connect(self.importGCode)
		self._ui.run.clicked.connect(self.run)
		self._ui.resume.clicked.connect(self.resume)
		self._ui.showGraphicsView.clicked.connect(self.showGraphicsView)

		self._ui.gotoOther.setMenu(self._ui.menuGoto)
		self._ui.storeOther.setMenu(self._ui.menuStore)
		self._ui.menuBar.hide()

		self._ui.storeXY.triggered.connect(self.storeXY)
		self._ui.storeXYZ.triggered.connect(self.storeXYZ)
		self._ui.storeX.triggered.connect(self.storeX)
		self._ui.storeY.triggered.connect(self.storeY)
		self._ui.storeZ.triggered.connect(self.storeZ)

		self._ui.gotoXY.triggered.connect(self.gotoWorkpieceXY)
		self._ui.gotoXYZ.triggered.connect(self.gotoWorkpieceXYZ)
		self._ui.gotoX.triggered.connect(self.gotoWorkpieceX)
		self._ui.gotoY.triggered.connect(self.gotoWorkpieceY)
		self._ui.gotoZ.triggered.connect(self.gotoWorkpieceZ)

		self._ui.driveXUp.clicked.connect(self.driveXUp)
		self._ui.driveYUp.clicked.connect(self.driveYUp)
		self._ui.driveZUp.clicked.connect(self.driveZUp)
		self._ui.driveUUp.clicked.connect(self.driveUUp)
		self._ui.driveXDown.clicked.connect(self.driveXDown)
		self._ui.driveYDown.clicked.connect(self.driveYDown)
		self._ui.driveZDown.clicked.connect(self.driveZDown)
		self._ui.driveUDown.clicked.connect(self.driveUDown)

		self._ui.feedRateOverride.valueChanged.connect(self.feedRateOverrideChanged)

		self._machine.machineStatus().updateStatus()

	@QtCore.Slot()
	def refMovement(self):
		# @fixme assert machine is not moving
		self._machine.setAction(ReferenceMotionController(self._machine))

	@QtCore.Slot()
	def showGraphicsView(self):
		if self._parser == None:
			QtGui.QMessageBox.information(
				self, 'PyPC-NC Graphics View',
				'You need to import G-Code before visualizing it.')
			return

		if self._gv == None:
			self._gv = ControlGraphicsView(self, self._machine)
			self._gv.render(self._parser)
			self._gv.show()
                        self._gv.closed.connect(self.graphicsViewClosed)

        @QtCore.Slot()
        def graphicsViewClosed(self):
                self._gv = None


	@QtCore.Slot()
	def statusUpdated(self):
		infos = []
		if self._machine.machineStatus().status() & 0x10: infos.append('moving')
		if self._machine.machineStatus().status() & 0x04: infos.append("ref'd")
		if self._machine.machineStatus().status() & 0x08: infos.append("ref'ing")

		status = hex(self._machine.machineStatus().status())

		if infos:
			status += ' (' + ', '.join(infos) + ')'

		self._ui.statusX.setText(status)
		self._ui.statusPx.setText("%.3f" % (self._machine.machineStatus().x() / 1000))
		self._ui.statusPy.setText("%.3f" % (self._machine.machineStatus().y() / 1000))
		self._ui.statusPz.setText("%.3f" % (self._machine.machineStatus().z() / 1000))
		self._ui.statusPu.setText("%.3f" % (self._machine.machineStatus().u() / 1000))

		self._ui.relX.setText("%.3f" % ((self._workpiecePos[0] - self._machine.machineStatus().x()) / 1000))
		self._ui.relY.setText("%.3f" % ((self._workpiecePos[1] - self._machine.machineStatus().y()) / 1000))
		self._ui.relZ.setText("%.3f" % ((self._workpiecePos[2] - self._machine.machineStatus().z()) / 1000))

		if isinstance(self._machine.action(), ProgrammedMotionController):
			self._ui.progress.setMaximum(self._machine.action().totalSteps())
			self._ui.progress.setValue(self._machine.action().completedSteps())
		elif self._inter and self._inter.pause:
			if self._ui.progress.maximum():
				QtGui.QMessageBox.information(
					self, 'Tool Change',
					'Insert tool %d now.' % self._inter.nextTool)

			self._ui.progress.setMaximum(0)
		else:
			self._ui.progress.setMaximum(1)
			self._ui.progress.setValue(0)

	@QtCore.Slot()
	def importGCode(self):
		filename = QtGui.QFileDialog.getOpenFileName(self, 'Import G-Code', '.')
		if filename[0] == '': return
		self.importGCodeFromFile(filename[0])

	def importGCodeFromFile(self, filename):
		parser = GCode.GCodeParser()
		parser.readFile(filename)
		parser.removeTapeMarkers()
		parser.removeComments()
		parser.removeInlineComments()
		parser.removeBlockSkipLines()
		parser.normalizeAddressWhitespace()
		parser.normalizeLeadingZeros()
		parser.readSequenceNumbers()

		self._parser = parser

	@QtCore.Slot()
	def run(self):
		if not self._machine.machineStatus().status() & 0x04:
			reply = QtGui.QMessageBox.question(self, 'G-Code Import',
				    'Are you sure to import G-Code without reference movement?',
				    QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)

			if reply == QtGui.QMessageBox.No:
				return

		if not self._storeButtonUsed:
			reply = QtGui.QMessageBox.question(self, 'G-Code Import',
				    'Are you sure to import G-Code without setting workpiece location?',
				    QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)

			if reply == QtGui.QMessageBox.No:
				return

		filters = [
			Filters.OffsetFilter([ -self._originOffset[0], -self._originOffset[1] ]),
			Filters.PolarFixer(self._polarCorrection[0], self._polarCorrection[1]),
			Filters.OffsetFilter(self._workpiecePos)
		]

		fc = Filters.FilterChain(filters, CNCCon.CNCConWriter())
		self._inter = GCode.GCodeInterpreter(fc)
		self._inter.position = [
			self._machine.machineStatus().x() - self._workpiecePos[0] + self._originOffset[0],
			self._machine.machineStatus().y() - self._workpiecePos[1] + self._originOffset[1],
			self._machine.machineStatus().z() - self._workpiecePos[2]
		]
		self._inter.invertZ = self._ui.invertZ.isChecked()
		self._inter.run(self._parser)

		self._machine.setAction(ProgrammedMotionController(self._machine))
		self._machine.action().setFeedRateOverride(self._ui.feedRateOverride.value())
		self._machine.action().setCommands(self._inter.target.buffer)

	@QtCore.Slot()
	def resume(self):
		if not self._inter:
			QtGui.QMessageBox.information(
				self, 'PyPC-NC',
				'Interpreter not initialized.  You need to open & "Run" first.')
			return

		if not self._inter.pause:
			QtGui.QMessageBox.information(
				self, 'PyPC-NC',
				'Interpreter not currently paused.  You may want to start over by clicking "Run".')
			return

		self._inter.target.buffer = [ ]
		self._inter.position = [
			self._machine.machineStatus().x() - self._workpiecePos[0] + self._originOffset[0],
			self._machine.machineStatus().y() - self._workpiecePos[1] + self._originOffset[1],
			self._machine.machineStatus().z() - self._workpiecePos[2]
		]
		self._inter.target.filters()[2].setOffsets(self._workpiecePos)
		self._inter.resume(self._parser)

		self._machine.setAction(ProgrammedMotionController(self._machine))
		self._machine.action().setFeedRateOverride(self._ui.feedRateOverride.value())
		self._machine.action().setCommands(self._inter.target.buffer)

	@QtCore.Slot(int)
	def feedRateOverrideChanged(self, value):
		if isinstance(self._machine.action(), ProgrammedMotionController):
			self._machine.action().setFeedRateOverride(self._ui.feedRateOverride.value())

	@QtCore.Slot()
	def storeXY(self):
		self.storeX()
		self.storeY()

	@QtCore.Slot()
	def storeXYZ(self):
		self.storeXY()
		self.storeZ()

	@QtCore.Slot()
	def storeX(self):
		self._storeButtonUsed = True
		self._workpiecePos[0] = self._machine.machineStatus().x()

	@QtCore.Slot()
	def storeY(self):
		self._storeButtonUsed = True
		self._workpiecePos[1] = self._machine.machineStatus().y()

	@QtCore.Slot()
	def storeZ(self):
		self._storeButtonUsed = True
		self._workpiecePos[2] = self._machine.machineStatus().z()

	def gotoWorkpiece(self, x, y, z):
		if isinstance(self._machine.action(), ProgrammedMotionController):
			return
		elif not isinstance(self._machine.action(), ManualMotionController):
			self._machine.setAction(ManualMotionController(self._machine))

		self._machine.action().gotoXYZ(x, y, z)

	def workpiecePos(self):
		return 

	def originOffset(self):
		return self._originOffset

	def setOriginOffset(self, x, y):
		self._originOffset = (x, y)

	def polarCorrection(self):
		return self._polarCorrection

	def setPolarCorrection(self, r, phi):
		self._polarCorrection = (r, phi)

	@QtCore.Slot()
	def gotoWorkpieceXY(self):
		self.gotoWorkpiece(self._workpiecePos[0], self._workpiecePos[1], None) 

	@QtCore.Slot()
	def gotoWorkpieceXYZ(self):
		self.gotoWorkpiece(self._workpiecePos[0], self._workpiecePos[1], self._workpiecePos[2]) 

	@QtCore.Slot()
	def gotoWorkpieceX(self):
		self.gotoWorkpiece(self._workpiecePos[0], None, None)

	@QtCore.Slot()
	def gotoWorkpieceY(self):
		self.gotoWorkpiece(None, self._workpiecePos[1], None) 

	@QtCore.Slot()
	def gotoWorkpieceZ(self):
		self.gotoWorkpiece(None, None, self._workpiecePos[2]) 

	def workpiecePos(self):
		return self._workpiecePos


	@QtCore.Slot()
	def driveXUp(self):
		self.manualMove('X', True)

	@QtCore.Slot()
	def driveYUp(self):
		self.manualMove('Y', True)

	@QtCore.Slot()
	def driveZUp(self):
		self.manualMove('Z', True)

	@QtCore.Slot()
	def driveUUp(self):
		self.manualMove('U', True)

	@QtCore.Slot()
	def driveXDown(self):
		self.manualMove('X', False)

	@QtCore.Slot()
	def driveYDown(self):
		self.manualMove('Y', False)

	@QtCore.Slot()
	def driveZDown(self):
		self.manualMove('Z', False)

	@QtCore.Slot()
	def driveUDown(self):
		self.manualMove('U', False)

	def manualMove(self, axis, positive):
		if isinstance(self._machine.action(), ProgrammedMotionController):
			return
		elif not isinstance(self._machine.action(), ManualMotionController):
			self._machine.setAction(ManualMotionController(self._machine))

		fast = self._ui.driveFast.isChecked()

		if self._ui.drive1Step.isChecked():
			self._machine.action().singleStep(axis, positive, fast)
		elif self._ui.drive001mm.isChecked():
			self._machine.action().manualMove(axis, positive, 10, fast)
		elif self._ui.drive01mm.isChecked():
			self._machine.action().manualMove(axis, positive, 100, fast)
		elif self._ui.drive1mm.isChecked():
			self._machine.action().manualMove(axis, positive, 1000, fast)
		elif self._ui.drive10mm.isChecked():
			self._machine.action().manualMove(axis, positive, 10000, fast)
		elif self._ui.drive100mm.isChecked():
			self._machine.action().manualMove(axis, positive, 100000, fast)

	@QtCore.Slot(int)
	def readControlEvent(self, fd):
		ev = os.read(fd, 4)
		if len(ev) != 4: return

		button, x, y, z = struct.unpack('bbbb', ev)
		print 'control event: button=%d, x=%d, y=%d, z=%d; time=%f' % (button, x, y, z, time.time())

		if self._debounce != None and time.time() - self._debounce < .1:
			if x != self._debounceX or y != self._debounceY:
				print 'discarding event, bounce detected'
				return

			if x == -1:
				self.manualMove('X', False)
			elif x == 1:
				self.manualMove('X', True)

			if y == -1:
				self.manualMove('Y', False)
			elif y == 1:
				self.manualMove('Y', True)

			self._debounce = None
		else:
			self._debounce = time.time()
			self._debounceX = x
			self._debounceY = y

		if z == -1:
			self.manualMove('Z', False)
		elif z == 1:
			self.manualMove('Z', True)

	@QtCore.Slot(int)
	def pollStatus(self, fd):
		self._machine.cts()
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        # 声明工具对象
        self._sniffer_tool = None
        self._scan_tool = None

        # 初始化嗅探IP表格数据源
        self._table_model = QStandardItemModel()
        self._scan_table_model = QStandardItemModel()

        # 声明嗅探列表刷新线程
        self._table_refresh_thread = None

        # 加载UI
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # 使窗口居中
        self.center()

        # 连接信号和槽
        self.ui.action_about.triggered.connect(self.about)
        self.ui.local_refresh_button.clicked.connect(
            self.load_local_net_config)
        self.ui.sniffer_start_button.clicked.connect(self.start_sniffer_thread)
        self.ui.sniffer_stop_button.clicked.connect(self.stop_sniffer_thread)
        self.ui.scan_start_button.clicked.connect(self.start_scan_thread)
        self.ui.scan_stop_button.clicked.connect(self.stop_scan_thread)

        # 初始化控件状态
        self.ui.sniffer_stop_button.setEnabled(False)
        self.ui.scan_stop_button.setEnabled(False)

        # 初始化完成
        self.statusBar().showMessage('准备就绪。')

    def center(self):
        """
        使窗口居中
        """
        screen_g = QDesktopWidget().screenGeometry()
        window_g = self.geometry()
        left = int((screen_g.width() - window_g.width()) / 2)
        up = int((screen_g.height() - window_g.height()) / 2)
        self.move(left, up)

    def about(self):
        """
        显示软件关于信息
        """
        QMessageBox.information(
            self, '关于Net Listener', '本软件用来进行网络嗅探、端口扫描,\
以发现局域网中的主机或任何主机的端口开放情况,使用全部功能需要使用ROOT权限运行', QMessageBox.Yes, QMessageBox.Yes)

    def load_local_net_config(self):
        """
        程序被第一次打开,加载本地网络配置
        """
        self.ui.device_tip_label.setHidden(True)
        self.ui.local_refresh_button.setEnabled(False)
        self.statusBar().clearMessage()
        self.statusBar().showMessage('正在读取网络配置……')
        tool = LocalhostNetInfoTool()
        tool.start_local_info_thread(self.ui.device_info_label,
                                     self.ui.scroll_area_widget_contents,
                                     self.statusBar(),
                                     self.ui.local_refresh_button)

    def start_sniffer_thread(self):
        """
        开启嗅探线程
        """
        # 测试当前是否是root用户
        if not OtherToolFunctionSet.test_root_permission():
            user_input = QMessageBox.information(
                self, '需要ROOT权限', '请以ROOT权限重启程序以运行嗅探功能。',
                QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
            if user_input == QMessageBox.Yes:
                # 退出应用程序
                QCoreApplication.instance().quit()
            else:
                return

        # 开启网卡混杂模式
        if_turn_promisc_on = QMessageBox.question(
            self, '需要开启网卡混杂模式', '嗅探功能需要开启网卡混杂模式,是否开启?',
            QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        if if_turn_promisc_on == QMessageBox.Yes:
            if not OtherToolFunctionSet.turn_net_card_promisc(True):
                QMessageBox.information(self, '开启结果', '开启混杂模式失败。',
                                        QMessageBox.Yes, QMessageBox.Yes)
                return
        else:
            self.statusBar().showMessage('停止嗅探,需要开启网卡混杂模式。')
            return

        self.ui.sniffer_tip_label.setHidden(True)

        # 设置表格数据源
        self._table_model.clear()
        self.ui.sniffer_table.setModel(self._table_model)
        self._table_model.setHorizontalHeaderLabels(['IP', 'MAC'])
        self._table_model.setColumnCount(2)

        # 开启嗅探线程
        self._sniffer_tool = NetSnifferTool()
        self._sniffer_tool.start_sniffer_thread(self._table_model,
                                                self.ui.sniffer_table,
                                                self.statusBar(),
                                                self.ui.sniffer_start_button,
                                                self.ui.sniffer_stop_button)

        # 修改控件状态
        self.ui.sniffer_stop_button.setEnabled(True)
        self.ui.sniffer_start_button.setEnabled(False)

    def stop_sniffer_thread(self):
        """
        关闭嗅探线程
        """
        # 关闭嗅探线程
        if self._sniffer_tool is not None:
            self._sniffer_tool.stop_sniffer_thread()
            self._sniffer_tool = None

            self.statusBar().showMessage('正在停止……')

    def start_scan_thread(self):
        """
        扫描给定IP的给定端口
        """
        target_ip = self.ui.scan_target_ip_edit.text()
        target_port_start = self.ui.scan_start_port_edit.text()
        target_port_stop = self.ui.scan_stop_port_edit.text()
        scan_timeout = self.ui.scan_timeout_edit.text()

        self._scan_tool = PortScanningTool(target_ip, target_port_start,
                                           target_port_stop, scan_timeout,
                                           self.statusBar())

        # 启动扫描线程
        self.statusBar().showMessage('正在扫描……')
        print('启动端口扫描:')

        # 设置表格模型
        self.ui.scan_result_table.setModel(self._scan_table_model)
        self._scan_table_model.clear()
        self._scan_table_model.setHorizontalHeaderLabels(['端口', '状态'])
        self._scan_table_model.setColumnCount(2)

        # 开始扫描
        self._scan_tool.start_scan_thread(self._scan_table_model,
                                          self.ui.scan_result_table,
                                          self.ui.scan_start_button,
                                          self.ui.scan_stop_button)

        # 修改控件状态
        self.ui.scan_stop_button.setEnabled(True)
        self.ui.scan_start_button.setEnabled(False)

    def stop_scan_thread(self):
        """
        停止端口扫描线程
        """
        if self._scan_tool is not None:
            self._scan_tool.stop_scan_thread()
            self._scan_tool = None

            self.statusBar().showMessage('正在停止……')

    def closeEvent(self, event: QCloseEvent):
        """
        窗口关闭回调,用于关闭工作线程。
        :param event: 关闭事件
        """
        # 关闭嗅探线程
        self.stop_sniffer_thread()
        # 关闭端口扫描线程
        self.stop_scan_thread()
class AQMain(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        background = xml.find("./Settings/Background").text
        self.ui.subPanel.setStyleSheet("QStackedWidget{background-image: url(" + background + ");}")
        
        #logging
        logging.basicConfig(filename='logfile.log',level=logging.DEBUG)
        logging.basicConfig(format='%(asctime)s %(filename)s %(lineno)d %(message)s')
        
        # TODO: figure out way to configure for different comm types (TCP, MAVLINK, etc)
        # Kenny answer: use a different communicator if not serial, protocol handler will be responsible to feed the model correcly 
        self.comm = SerialCommunicator()
        

        self._vehicle_model = VehicleModel()
        # @todo Kenny, remove this!
        self._protocol_handler = AQV32ProtocolHandler(self.comm,self._vehicle_model)
        
                
        # Default main window conditions
        self.ui.buttonDisconnect.setEnabled(False)
        self.ui.buttonConnect.setEnabled(True)
        self.ui.comPort.setEnabled(True)
        self.ui.baudRate.setEnabled(True)
        self.ui.status.setText("Not connected to the AeroQuad")
        self.availablePorts = []
        self.updateComPortSelection()
        self.updateBaudRates()
        self.boardConfiguration = {}
        self.manualConnect = True
        
        # Update comm port combo box to use last used comm port
        defaultComPort = xml.find("./Settings/DefaultComPort").text
        commIndex = self.ui.comPort.findText(defaultComPort)
        if commIndex == -1:
            commIndex = 0
        self.ui.comPort.setCurrentIndex(commIndex)
        
        # Load splash screen
        splash = SplashScreen()
        splash.setupUi(splash)
        self.ui.subPanel.addWidget(splash)
        
        # Dynamically configure board type menu and subPanel menu from XML configuration file
        self.configureSubPanelMenu()
        self.activeSubPanel = None
        self.activeSubPanelName = ""

        # Connect GUI slots and signals
        self.ui.comPort.return_handler = self.connectBoard
        self.ui.buttonConnect.clicked.connect(self.connectBoard)
        self.ui.buttonDisconnect.clicked.connect(self.disconnectBoard)
        self.ui.actionExit.triggered.connect(QtGui.qApp.quit)
        self.ui.comPort.currentIndexChanged.connect(self.updateDetectedPorts)
        self.ui.actionBootUpDelay.triggered.connect(self.updateBootUpDelay)
        self.ui.actionCommTimeout.triggered.connect(self.updateCommTimeOut)
        self.ui.button_home.clicked.connect(self.return_home)
       
        #SideMenuButtons
        self.ui.sidemenu_button_vehicle_status.clicked.connect(self.button_vehicle_status)
        self.ui.sidemenu_button_vehicle_configuration.clicked.connect(self.button_vehicle_configuration)
        
        self.ui.sidemenu_button_vehicle_setup.clicked.connect(self.button_vehicle_setup)
        self.ui.sidemenu_button_sensors_calibration.clicked.connect(self.button_sensors_calibration)
        self.ui.sidemenu_button_magnetometer_calibration.clicked.connect(self.button_magnetometer_calibration)
        self.ui.sidemenu_button_RC_channels_detection.clicked.connect(self.button_RC_channels_detection)
        self.ui.sidemenu_button_RC_calibartion.clicked.connect(self.button_RC_calibration)
        self.ui.sidemenu_button_motor_command.clicked.connect(self.button_motor_command)
        self.ui.sidemenu_button_PID_update.clicked.connect(self.button_PID_update)
        
        self.ui.sidemenu_button_serial_monitor.clicked.connect(self.button_serial_monitor)
        self.ui.sidemenu_button_sensor_data.clicked.connect(self.button_sensor_data)
        self.ui.sidemenu_button_gyroscope_data.clicked.connect(self.button_gyroscope_data)
        self.ui.sidemenu_button_accelerometer_data.clicked.connect(self.accelerometer_data)
        self.ui.sidemenu_button_magnetometer_data.clicked.connect(self.magnetometer_data)
        self.ui.sidemenu_button_attitude_data.clicked.connect(self.button_attitude_data)
        self.ui.sidemenu_button_transmitter_data.clicked.connect(self.button_transmitter_data)
        self.ui.sidemenu_button_altitude_data.clicked.connect(self.button_altitude_data)
            
    ####### Communication Methods #######       
    def connectBoard(self):
        '''Initiates communication with the AeroQuad'''
        # Setup GUI
        self.ui.status.setText("Connecting...")
        self.ui.buttonDisconnect.setEnabled(True)
        self.ui.buttonConnect.setEnabled(False)
        self.ui.comPort.setEnabled(False)
        self.ui.baudRate.setEnabled(False)
        # Update the GUI
        app.processEvents()
        
        # Setup serial port
        bootupDelay = float(xml.find("./Settings/BootUpDelay").text)
        commTimeOut = float(xml.find("./Settings/CommTimeOut").text)
        try:
            self.comm.connect(str(self.ui.comPort.currentText()), int(self.ui.baudRate.currentText()), bootupDelay, commTimeOut)

            self._protocol_handler.unsubscribe_command()
            version = self._protocol_handler.get_flight_software_version()

            if version != "":
                self.storeComPortSelection()
                self.ui.status.setText("Connected to AeroQuad Flight Software v" + version)
                self._vehicle_model.set_is_connected(True)
                
                if version == '4.0' :
                    self._protocol_handler.request_board_configuration()
                    pass
                    # this do nothign really for now, but, should be like this, currently, panels need it instantiated before!
#                    self.communication_protocol_handler = AQV4ProtocolHandler(self.comm,self.vehicle_model)
#                    self.message_sender = AQV4MessageSender(self.comm)
                elif version == '3.2' :
                    self._protocol_handler.request_board_configuration()
                    pass
#                    self.communication_protocol_handler = AQV32ProtocolHandler(self.comm,self.vehicle_model)
#                    self.message_sender = AQV32MessageSender(self.comm)

                else :
                    logging.error("Flight software version " + version + " unsuported")
                    self.disconnectBoard()
                    self.ui.status.setText("Not connected to the AeroQuad")
                
                return True
            else:
                self.disconnectBoard()
                self.ui.status.setText("Not connected to the AeroQuad")
                if self.manualConnect:
                    QtGui.QMessageBox.information(self, "Connection Error", "Unable to connect to the AeroQuad.  Verify the board is plugged in.\n\nIf it is, try increasing the Boot Up Delay.\nThis is found under File->Preferences->Boot Up Delay.")
                return False
        except SerialException:
            self.ui.buttonDisconnect.setEnabled(False)
            self.ui.buttonConnect.setEnabled(True)
            self.ui.comPort.setEnabled(True)
            self.ui.baudRate.setEnabled(True)
            self.ui.status.setText("Connection Failed")
            self.boardConfiguration = {}
            return False
        
    def disconnectBoard(self):
        '''Disconnect from the AeroQuad'''
        self.comm.write(xml.find("./Settings/StopTelemetry").text)
        self.comm.disconnect()
        # Update GUI
        self.ui.buttonDisconnect.setEnabled(False)
        self.ui.buttonConnect.setEnabled(True)
        self.ui.comPort.setEnabled(True)
        self.ui.baudRate.setEnabled(True)
        self.ui.status.setText("Disconnected from the AeroQuad")
        self.boardConfiguration = {}
        self.restartSubPanel()
        self._vehicle_model.set_is_connected(False)

    def updateDetectedPorts(self):
        '''Cycles through 256 ports and checks if there is a response from them.'''
        selection = self.ui.comPort.currentText()
        if selection == "Refresh":
            self.updateComPortSelection()
            self.ui.comPort.setCurrentIndex(0)
            self.ui.status.setText("Updated list of available COM ports")
        elif selection == "Autoconnect":
            self.updateComPortSelection()
            self.ui.comPort.setCurrentIndex(0)
            self.ui.status.setText("Beginning autoconnect...")
            self.autoConnect()
            
    def autoConnect(self):
        self.manualConnect = False
        autoConnectState = False
        self.updateComPortSelection()
        self.ui.comPort.setCurrentIndex(0)
        for port in xrange(self.ui.comPort.count() - 2):
            self.ui.comPort.setCurrentIndex(port)
            self.ui.status.setText("Attempting to connect to " + self.ui.comPort.currentText() + "...")
            if self.connectBoard():
                self.ui.status.setText("Autoconnect successful!")
                autoConnectState = True
                break
            else:
                self.ui.status.setText("Autoconnect not successful...")
        if not autoConnectState:
            if sys.platform.startswith("linux"):
                QtGui.QMessageBox.information(self, 'Autoconnect Not Successful', 'Verify that you are a member of the dialout group.  To add yourself to the dialout group, issue the following command in a terminal:\n"sudo adduser yourUserName dialout."\n\nYou may need to restart the Configurator.')
        self.manualConnect = True
    
    def updateBootUpDelay(self):
        '''Creates dialog box to ask user for desired boot up delay.
        This delay waits for Arduino based boards to finish booting up before sending commands.
        '''
        bootUpDelay = float(xml.find("./Settings/BootUpDelay").text)
        data, ok = QtGui.QInputDialog.getDouble(self, "Boot Up Delay", "Boot Up Delay:", bootUpDelay, 0, 60, 3)
        if ok:
            xml.find("./Settings/BootUpDelay").text = str(data)
            xml.write("AeroQuadConfigurator.xml")
 
    def updateCommTimeOut(self):
        '''Creates dialog box to ask user for desired comm timeout.
        This is timeout value used by serial drivers to wait for response from device
        '''
        commTimeOut = float(xml.find("./Settings/CommTimeOut").text)
        data, ok = QtGui.QInputDialog.getDouble(self, "Comm Time Out", "Comm Time Out:", commTimeOut, 0, 60, 3)
        if ok:
            xml.find("./Settings/CommTimeOut").text = str(data)
            xml.write("AeroQuadConfigurator.xml")

    def updateComPortSelection(self):
        '''Look for available comm ports and updates combo box'''
        self.ui.comPort.clear()
        for n in self.comm.detect_ports():
            self.ui.comPort.addItem(n)
        self.ui.comPort.insertSeparator(self.ui.comPort.count())
        self.ui.comPort.addItem("Autoconnect")
        self.ui.comPort.addItem("Refresh")
        
    def storeComPortSelection(self):
        '''Stores comm port selection to xml file for later recall'''
        xml.find("./Settings/DefaultBaudRate").text = str(self.ui.baudRate.currentText())
        xml.find("./Settings/DefaultComPort").text = str(self.ui.comPort.currentText())
        xml.write("AeroQuadConfigurator.xml")
               
    def updateBaudRates(self):
        '''Reads baud rates from xml and displays in combo box.
        Updates the xml file to display different baud rates
        '''
        defaultBaudRate = xml.find("./Settings/DefaultBaudRate").text
        baudRates = xml.find("./Settings/AvailableBaudRates").text
        baudRate = baudRates.split(',')
        for i in baudRate:
            self.ui.baudRate.addItem(i)
        self.ui.baudRate.setCurrentIndex(baudRate.index(defaultBaudRate))
        
    def autoSetup(self):
        # Load menu and autoconnect to board by default
        self.selectSubPanel("Home")


    ####### SubPanel Methods #######
    def configureSubPanelMenu(self):
        '''Dynamically add subpanels to View menu based on XML file configuration
        This also adds the subpanel to a stacked widget and stores object instances so that they can run when selected'''
        subPanels = xml.findall("./Subpanels/Subpanel")
        subPanelCount = 1
        self.subPanelList = [] # Stores subpanel names
        self.subPanelClasses = [] # Stores subpanel object instances
        for subPanel in subPanels:
            self.subPanelList.append(subPanel.get("Name"))
            pathName = xml.find("./Subpanels/Subpanel/[@Name='" + subPanel.get("Name") +"']/Path").text
            className = xml.find("./Subpanels/Subpanel/[@Name='" + subPanel.get("Name") +"']/Class").text
            packageList = pathName.split('.')
            packageList.insert(0, 'subpanel')
            packageString = packageList[0] + '.' + packageList[1] + '.' + packageList[2]
            module = __import__(packageString)
            for package in packageList[1:]: # In case the module is buried into a deep package folder, loop until module is reached
                module = getattr(module, package)
            module = getattr(module, className)
            tempSubPanel = module(self._vehicle_model,self._protocol_handler)          
            tempSubPanel.initialize()
            self.ui.subPanel.addWidget(tempSubPanel)
            self.subPanelClasses.append(tempSubPanel)
            subPanelCount += 1
        self.subPanelMapper = QtCore.QSignalMapper(self)
        self.subPanelMenu = []
        for subPanelName in self.subPanelList:
            subPanel = self.ui.menuView.addAction(subPanelName)
            self.subPanelMenu.append(subPanel) # Need to store this separately because Python only binds stuff at runtime
            self.subPanelMapper.setMapping(subPanel, subPanelName)
            subPanel.triggered.connect(self.subPanelMapper.map)
            subPanel.setCheckable(True)
        self.subPanelMapper.mapped[str].connect(self.selectSubPanel)       
  
    def selectSubPanel(self, subPanelName):
        '''Places check mark beside selected subpanel name
        Menu item instances stored in dedicated list because Python only updates during runtime making everything point to the last item in the list
        '''
        if self.activeSubPanel != None:
            self.activeSubPanel.stop()
        types = len(self.subPanelList)
        for index in range(types):
            self.subPanelMenu[index].setChecked(False)
        selected = self.subPanelList.index(subPanelName)
        self.subPanelMenu[selected].setChecked(True)
        self.ui.subPanel.setCurrentIndex(selected+1) # index 0 is splash screen
        self.activeSubPanel = self.subPanelClasses[selected]
        self.activeSubPanelName = "./Subpanels/Subpanel/[@Name='" + str(subPanelName) + "']" 
        self.activeSubPanel.start()
        if subPanelName == "Menu":
            self.ui.status.setText("Choose Configurator Function")
        else:
            self.ui.status.setText(subPanelName)
        app.processEvents()

    def clearSubPanelMenu(self):
        ''' Clear subPanel menu and disconnect subPanel related signals'''
        self.ui.menuView.clear()
        self.subPanelMapper.mapped[str].disconnect(self.selectSubPanel)
        
    def restartSubPanel(self):
        if self.activeSubPanel != None: # Restart any running subpanels
            self.activeSubPanel.stop()
            self.activeSubPanel.start()
            app.processEvents()
            
    def checkRequirementsMatch(self, subPanelName):
        # Read requirements for the specified subpanel form the XML config file
        xmlRequirement = "./Subpanels/Subpanel/[@Name='" + subPanelName +"']/Requirement"
        subPanelRequirements = xml.findall(xmlRequirement)
        
        panelRequirements = {}
        booleanOperation = {}      
        for requirements in subPanelRequirements:
            requirement = requirements.text.split(':')
            if requirement[0] == "All": # Need element 1 populated if "All" detected
                requirement.append("All")
            panelRequirements[requirement[0]] = requirement[1].strip()
            booleanOperation[requirement[0]] = requirements.get("type")

        # Go through each subpanel requirement and check against board configuration
        # If no boolean type defined, assume AND
        requirementType = panelRequirements.keys()
        # If no Requirement found, assume ALL
        try:
            if (requirementType[0] == "All"):
                check = True
            else:
                check = any(panelRequirements[requirementType[0]] in s for s in self.boardConfiguration.values())
                for testRequirement in requirementType[1:]:
                    if (booleanOperation[testRequirement] == "or") or (booleanOperation[testRequirement] == "OR"):
                        check = check or any(panelRequirements[testRequirement] in s for s in self.boardConfiguration.values())
                    else:
                        check = check and any(panelRequirements[testRequirement] in s for s in self.boardConfiguration.values())
        except:
            check = True
        return check


    ####### Housekeeping Functions #######
        
    def exit(self):
        self.comm.disconnect()
        sys.exit(app.exec_())

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def return_home(self):
        self.selectSubPanel("Home") 
        
    def button_vehicle_status(self):
        self.selectSubPanel("Vehicle Status") 
    
    def button_vehicle_configuration(self):
        self.selectSubPanel("Vehicle Configuration")

    def button_vehicle_setup(self):
        self.selectSubPanel("Vehicle configuration")
        
    def button_sensors_calibration(self):
        self.selectSubPanel("Sensors calibration")
        
    def button_magnetometer_calibration(self):
        self.selectSubPanel("Magnetometer calibration")
        
    def button_RC_channels_detection(self):
        self.selectSubPanel("Receiver channels detection")
        
    def button_RC_calibration(self):
        self.selectSubPanel("Receiver Calibration")
        
    def button_motor_command(self):
        self.selectSubPanel("Motor Command")
    
    def button_PID_update(self):
        self.selectSubPanel("PID Update")
    
    def button_serial_monitor(self):
        self.selectSubPanel("Serial Monitor")
    
    def button_sensor_data(self):
        self.selectSubPanel("Sensor Data")
    
    def button_gyroscope_data(self):
        self.selectSubPanel("Gyroscope Data")
        
    def accelerometer_data(self):
        self.selectSubPanel("Accelerometer Data")
        
    def magnetometer_data(self):
        self.selectSubPanel("Magnetometer Data")
        
    def button_attitude_data(self):
        self.selectSubPanel("Attitude Data")
    
    def button_transmitter_data(self):
        self.selectSubPanel("Transmitter Data")
    
    def button_altitude_data(self):
        self.selectSubPanel("Altitude Data")
Beispiel #10
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.connect_handlers()

        # Sub Views
        self.server_form = ServerForm()
        self.server_form.set_main_window(self)
        self.server_form.hide()

        # Initiate empty list
        self.data = []
        self.notifications = []

        # Refresh list
        self.refresh_list()

        # Set icons
        icon = QtGui.QIcon(os.path.join(os.path.dirname(__file__), "icon.png"))
        self.setWindowIcon(icon)

        self.msgIcon = QSystemTrayIcon.MessageIcon(QSystemTrayIcon.Information)
        self.systray_icon = QSystemTrayIcon(icon)
        self.systray_icon.activated.connect(self.toggle_window)
        self.systray_icon.show()

    def toggle_window(self):
        if self.isVisible():
            self.hide()
        else:
            self.show()

    def update_list(self):
        save_data(self.data, JSON_PATH)

    def refresh_list(self):
        # List Data
        self.data = read_data(JSON_PATH)

        self.ui.serverList.clear()
        for x in self.data:
            # print x
            self.ui.serverList.addItem(x['name'])

    def connect_handlers(self):
        user_interface = self.ui

        # Bind Add Events
        user_interface.addButton.clicked.connect(self.handle_add_events)
        user_interface.actionAdd_Server.triggered.connect(self.handle_add_events)

        # Bind Edit Events
        user_interface.editButton.clicked.connect(self.handle_edit_events)

        # Bind Del Events
        user_interface.delButton.clicked.connect(self.handle_del_events)

        # Bind Toggle Events
        user_interface.toggleButton.clicked.connect(self.handle_toggle_events)
        user_interface.actionStart_Monitoring.triggered.connect(self.handle_toggle_events)
        user_interface.actionStop_Monitoring.triggered.connect(self.handle_toggle_events)

        # Bind Quit Events
        user_interface.actionQuit.triggered.connect(self.handle_quit_events)

        # Bind Signals
        NOTIFIER.notify.connect(self.push_notifications)

    def handle_add_events(self):
        self.server_form.show()
        self.hide()

    def handle_edit_events(self):
        try:
            item = self.ui.serverList.selectedIndexes()[0]
            index = item.row()
        except:
            index = None

        if index is not None:
            self.server_form.set_entry_id(index)
        else:
            self.server_form.set_default_texts()

        self.server_form.show()
        self.hide()

    def handle_del_events(self):
        try:
            item = self.ui.serverList.selectedIndexes()[0]
            index = item.row()
            del self.data[index]
        except:
            pass

        self.update_list()
        self.refresh_list()

    def handle_toggle_events(self):
        try:
            timer = self.timer
            self.timer.cancel()
            del self.timer
            self.ui.toggleButton.setText("START")
            self.ui.actionStop_Monitoring.setDisabled(True)
            self.ui.actionStart_Monitoring.setEnabled(True)

            self.systray_icon.showMessage('STOP', "Server monitoring was stopped!", self.msgIcon)
        except:
            self.ui.actionStop_Monitoring.setEnabled(True)
            self.ui.actionStart_Monitoring.setDisabled(True)
            self.ui.toggleButton.setText("STOP")
            self.handle_timed_loop()

            self.systray_icon.showMessage('START', "Server monitoring has started!", self.msgIcon)

    def handle_quit_events(self):
        self.timer.cancel()
        self.close()

    def handle_timed_loop(self):
        self.notifications = monitor_servers(self.data)
        self.timer = threading.Timer(10, self.handle_timed_loop)
        self.timer.start()
        NOTIFIER.notify.emit()

    def push_notifications(self):
        # print "ok- called"
        for x in self.notifications:
            self.systray_icon.showMessage('ALERT', x, self.msgIcon)
            # pass

    def closeEvent(self, event):
        try:
            timer = self.timer
            self.timer.cancel()
            del self.timer
        except:
            pass

        event.accept()
Beispiel #11
0
from PyQt5 import QtWidgets
from PyQt5.QtGui import QIcon

from ui.MainWindow import Ui_MainWindow

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(window)
    window.show()
    sys.exit(app.exec_())
Beispiel #12
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.watcher = Watcher()

        self.runState = False
        self.currentSelectedSaveDir = ''

        self.initWindow()

    def initWindow(self):
        self.initMenuBar()
        self.initCentralWidget()

    def selectSaveDirClick(self):
        dir = QFileDialog.getExistingDirectory(
            self, '选择存档文件目录', self.currentSelectedSaveDir
            if self.currentSelectedSaveDir != '' else str(Path.home()))
        if (dir != ''):
            self.onSaveDirChange(dir)

    def btnRunClick(self):
        if self.runState:
            self.ui.pushButton_run.setText('开始')
            self.ui.pushButton_selectSaveDir.setDisabled(False)
            self.watcher.stop()
            self.runState = False
        else:
            if self.currentSelectedSaveDir != '':
                self.ui.pushButton_selectSaveDir.setDisabled(True)
                self.ui.pushButton_run.setText('停止')
                self.watcher.start()
                self.runState = True
            else:
                QMessageBox.warning(self, "提示", "请先选择存档文件所在目录")

    def btnOpenSaveFolderClick(self):
        folder_path = self.currentSelectedSaveDir
        if folder_path != '':
            plt = system()
            if (plt == 'Linux'):
                Popen(['xdg-open', folder_path])
            elif (plt == 'Windows'):
                os.startfile(folder_path)
            elif (plt == 'Darwin'):
                os.system('open "%s"' % folder_path)

    def initCentralWidget(self):
        self.ui.pushButton_selectSaveDir.clicked.connect(
            self.selectSaveDirClick)
        self.ui.pushButton_run.clicked.connect(self.btnRunClick)
        self.ui.pushButton_openFolder.clicked.connect(
            self.btnOpenSaveFolderClick)

    def onSaveDirChange(self, path):
        self.ui.label_saveDir.setText(path)
        self.currentSelectedSaveDir = path
        self.watcher.change_path(path)

    def initMenuBar(self):
        self.ui.action_exit.triggered.connect(app.exit)
        self.ui.action_about.triggered.connect(
            lambda _: self.showAboutDialog())

    def showAboutDialog(self):
        dlg = AboutDialog()
        dlg.exec_()