def run_statistics(self):
        text = self.comp_type_crt_text
        x_vals = []
        y_vals = []
        if text[:5] == "Inter":
            data_sets = []
            for check_box in self.check_boxes:
                if check_box.isChecked():
                    data_sets.append(self.check_boxes[check_box])

            metric = self.select_metric_inter.currentText()
            metric_alias = self.dict_metric_inter[metric]
            res = ResultsManager.get_results_inter(metric_alias, data_sets)
            # self.graphWidget.plot(data_sets, res)
            x_vals = data_sets
            y_vals = res
        elif text[:5] == "Intra":
            ds_name = self.intra_ds_current
            metric = self.select_metric_intra.currentText()
            metric_alias = self.dict_metric_intra[metric]
            names, res = ResultsManager.get_results_intra(metric_alias, ds_name)
            # self.graphWidget.plot(names, res)
            x_vals = names
            y_vals = res
        #horizontal bar
        chart_view = None
        if self.select_chart.currentIndex() == 0:
            chart = QChart(flags=Qt.WindowFlags())
            series = QHorizontalBarSeries()
            for i in range(len(x_vals)):
                name = x_vals[i]
                set0 = QBarSet(name)
                set0.append(y_vals[i])
                series.append(set0)
            chart.addSeries(series)
            if text[:5] == "Inter":
                chart.setTitle(f"Comparison by {self.select_metric_inter.currentText()}")
            else:
                chart.setTitle(f"Comparison by {self.select_metric_intra.currentText()}")
            chart.setAnimationOptions(QChart.SeriesAnimations)

            chart_view = QChartView(chart)
            self.graph_layout.replaceWidget(self.crt_chart, chart_view)
            self.crt_chart = chart_view

            axisX = QValueAxis()
            chart.addAxis(axisX, Qt.AlignBottom)
            series.attachAxis(axisX)

            axisX.applyNiceNumbers()

            chart.legend().setVisible(True)
            chart.legend().setAlignment(Qt.AlignBottom)

            chart_view.setRenderHint(QPainter.Antialiasing)
            chart_view.setBackgroundBrush(QColor(0, 0, 0, 255))
            chart.setBackgroundBrush(QColor(255, 255, 0, 255))
        # vertical bar
        elif self.select_chart.currentIndex() == 1:
            chart = QChart(flags=Qt.WindowFlags())
            series = QBarSeries()
            for i in range(len(x_vals)):
                name = x_vals[i]
                set0 = QBarSet(name)
                set0.append(y_vals[i])
                series.append(set0)
            chart.addSeries(series)
            if text[:5] == "Inter":
                chart.setTitle(f"Comparison by {self.select_metric_inter.currentText()}")
            else:
                chart.setTitle(f"Comparison by {self.select_metric_intra.currentText()}")
            chart.setAnimationOptions(QChart.SeriesAnimations)

            chart_view = QChartView(chart)
            self.graph_layout.replaceWidget(self.crt_chart, chart_view)
            self.crt_chart = chart_view

            axisY = QValueAxis()
            chart.addAxis(axisY, Qt.AlignLeft)
            series.attachAxis(axisY)
            axisY.applyNiceNumbers()

            chart.legend().setVisible(True)
            chart.legend().setAlignment(Qt.AlignBottom)

            chart_view.setRenderHint(QPainter.Antialiasing)
            chart_view.setBackgroundBrush(QColor(0, 0, 0, 255))
            chart.setBackgroundBrush(QColor(255, 255, 0, 255))
        # pie chart
        elif self.select_chart.currentIndex() == 2:
            chart = QChart(flags=Qt.WindowFlags())
            series = QPieSeries()
            for i in range(len(x_vals)):
                series.append(x_vals[i], y_vals[i])
            chart.addSeries(series)
            if text[:5] == "Inter":
                chart.setTitle(f"Comparison by {self.select_metric_inter.currentText()}")
            else:
                chart.setTitle(f"Comparison by {self.select_metric_intra.currentText()}")
            chart.setAnimationOptions(QChart.SeriesAnimations)
            chart.legend().setAlignment(Qt.AlignBottom)
            # chart.legend().setFont(QFont("Arial", 12))

            chart_view = QChartView(chart)
            self.graph_layout.replaceWidget(self.crt_chart, chart_view)
            self.crt_chart = chart_view

            chart_view.setRenderHint(QPainter.Antialiasing)
            chart_view.setBackgroundBrush(QColor(0, 0, 0, 255))
            chart.setBackgroundBrush(QColor(255, 255, 0, 255))

        chart_view.setRubberBand(QChartView.HorizontalRubberBand)
        chart_view.setRubberBand(QChartView.VerticalRubberBand)
Beispiel #2
0
class Chart(QWidget):
    def __init__(self, ch0Name='ch0', ch1Name='ch1', ch2Name='ch2', ch3Name='ch3'):
        super(Chart, self).__init__()
        self.ch0Name = ch0Name
        self.ch1Name = ch1Name
        self.ch2Name = ch2Name
        self.ch3Name = ch3Name
        self.data = []
        self.initUI()

    def initUI(self):
        vbox = QVBoxLayout()
        vbox.addWidget(self.chartUI())
        vbox.addWidget(self.controlUI())

        self.setLayout(vbox)

    def chartUI(self):
        self.chart1 = QLineSeries()
        self.chart1.setName(self.ch0Name)
        self.chart1.setPen(QPen(Qt.red))
        self.chart2 = QLineSeries()
        self.chart2.setName(self.ch1Name)
        self.chart2.setPen(QPen(Qt.darkYellow))
        self.chart3 = QLineSeries()
        self.chart3.setName(self.ch2Name)
        self.chart3.setPen(QPen(Qt.green))
        self.chart4 = QLineSeries()
        self.chart4.setName(self.ch3Name)
        self.chart4.setPen(QPen(Qt.blue))

        self.chart = QChart()
        self.chart.addSeries(self.chart1)
        self.chart.addSeries(self.chart2)
        self.chart.addSeries(self.chart3)
        self.chart.addSeries(self.chart4)
        self.chart.setAnimationOptions(QChart.AllAnimations)
        self.chart.setTitle("laser data")

        self.axis_x = QValueAxis()
        self.axis_y = QValueAxis()
        self.axis_x.setTickCount(10)
        self.axis_y.setTickCount(10)
        self.axis_x.setLabelFormat('%d')
        self.axis_y.setLabelFormat('%d')

        self.axis_x.setRange(0, 1000)
        self.axis_y.setRange(100, 300)
        self.chart.setAxisX(self.axis_x, self.chart1)
        self.chart.setAxisY(self.axis_y, self.chart1)
        self.chart.setAxisX(self.axis_x, self.chart2)
        self.chart.setAxisY(self.axis_y, self.chart2)
        self.chart.setAxisX(self.axis_x, self.chart3)
        self.chart.setAxisY(self.axis_y, self.chart3)
        self.chart.setAxisX(self.axis_x, self.chart4)
        self.chart.setAxisY(self.axis_y, self.chart4)

        self.chartView = QChartView()
        self.chartView.setChart(self.chart)
        self.chartView.setRubberBand(QChartView.RectangleRubberBand)
        self.chartView.setRenderHint(QPainter.Antialiasing)

        return self.chartView

    def controlUI(self):
        self.autoRefreshCb = QCheckBox('自动刷新')
        self.autoRefreshCb.setChecked(True)
        self.ch0Enable = QCheckBox(self.ch0Name)
        self.ch1Enable = QCheckBox(self.ch1Name)
        self.ch2Enable = QCheckBox(self.ch2Name)
        self.ch3Enable = QCheckBox(self.ch3Name)
        self.ch0Enable.setChecked(True)
        self.ch1Enable.setChecked(True)
        self.ch2Enable.setChecked(True)
        self.ch3Enable.setChecked(True)
        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.autoRefreshCb)
        hbox1.addWidget(self.ch0Enable)
        hbox1.addWidget(self.ch1Enable)
        hbox1.addWidget(self.ch2Enable)
        hbox1.addWidget(self.ch3Enable)

        self.xDataMinLabel = QLabel('x min:')
        self.xDataMaxLabel = QLabel('x max:')
        self.yDataMinLabel = QLabel('y min:')
        self.yDataMaxLabel = QLabel('y max:')

        self.xDataMinLine = QLineEdit()
        self.xDataMaxLine = QLineEdit()
        self.yDataMinLine = QLineEdit()
        self.yDataMaxLine = QLineEdit()
        self.setBtn = QPushButton('设置')

        hbox = QHBoxLayout()
        hbox.addWidget(self.xDataMinLabel)
        hbox.addWidget(self.xDataMinLine)
        hbox.addWidget(self.xDataMaxLabel)
        hbox.addWidget(self.xDataMaxLine)
        hbox.addWidget(self.yDataMinLabel)
        hbox.addWidget(self.yDataMinLine)
        hbox.addWidget(self.yDataMaxLabel)
        hbox.addWidget(self.yDataMaxLine)
        hbox.addWidget(self.setBtn)

        mainLayout = QVBoxLayout()
        mainLayout.addLayout(hbox1)
        mainLayout.addLayout(hbox)
        frame = QFrame()
        frame.setLayout(mainLayout)

        self.setBtn.clicked.connect(self.setAxisRange)
        self.ch0Enable.clicked.connect(self.changeCh)
        self.ch1Enable.clicked.connect(self.changeCh)
        self.ch2Enable.clicked.connect(self.changeCh)
        self.ch3Enable.clicked.connect(self.changeCh)
        return frame

    # @timethis
    def update(self):
        x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data
        self.chart1.clear()
        self.chart2.clear()
        self.chart3.clear()
        self.chart4.clear()
        try:
            for i in range(0, len(x0Data)):
                if self.ch0Enable.isChecked():
                    self.chart1.append(QPoint(x0Data[i], y0Data[i]))
            for i in range(0, len(x1Data)):
                if self.ch1Enable.isChecked():
                    self.chart2.append(QPoint(x1Data[i], y1Data[i]))
            for i in range(0, len(x2Data)):
                if self.ch2Enable.isChecked():
                    self.chart3.append(QPoint(x2Data[i], y2Data[i]))
            for i in range(0, len(x3Data)):
                if self.ch3Enable.isChecked():
                    self.chart4.append(QPoint(x3Data[i], y3Data[i]))
        except:
            logging.debug('y0Data is %s' % y0Data)
            logging.debug('y1Data is %s' % y1Data)
            logging.debug('y2Data is %s' % y2Data)
            logging.debug('y3Data is %s' % y3Data)
            self.chart1.clear()
            self.chart2.clear()
            self.chart3.clear()
            self.chart4.clear()
        # self.chartView.update()

        if self.autoRefreshCb.isChecked():
            self.fillAxisRange()
            self.setAxisRange()

    def fillAxisRange(self):
        x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data
        tmp = [min(x0Data), min(x1Data), min(x2Data), min(x3Data)]
        xDataMin = min(tmp)
        tmp = [max(x0Data), max(x1Data), max(x2Data), max(x3Data)]
        xDataMax = max(tmp)
        tmp = [min(y0Data), min(y1Data), min(y2Data), min(y3Data)]
        yDataMin = min(tmp)
        tmp = [max(y0Data), max(y1Data), max(y2Data), max(y3Data)]
        yDataMax = max(tmp)

        xDataAvr = (xDataMin + xDataMax) // 2
        yDataAvr = (yDataMin + yDataMax) // 2

        self.xDataMinLine.setText(str(xDataAvr - xDataAvr*6//5))
        self.xDataMaxLine.setText(str(xDataAvr + xDataAvr*6//5))
        self.yDataMinLine.setText(str(yDataAvr - yDataAvr*6//5))
        self.yDataMaxLine.setText(str(yDataAvr + yDataAvr*6//5))

    @pyqtSlot()
    def setAxisRange(self):
        if self.xDataMinLine.text() and self.xDataMaxLine.text() and \
            self.yDataMinLine.text() and self.yDataMaxLine.text():
            self.axis_x.setRange(int(self.xDataMinLine.text()), int(self.xDataMaxLine.text()))
            self.axis_y.setRange(int(self.yDataMinLine.text()), int(self.yDataMaxLine.text()))
        else:
            QMessageBox.warning(self, '警告', '缺少参数')

    @pyqtSlot()
    def changeCh(self):

        self.chart1.clear()
        self.chart2.clear()
        self.chart3.clear()
        self.chart4.clear()
        x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data

        for i in range(0, len(x0Data)):
            if self.ch0Enable.isChecked():
                self.chart1.append(QPoint(x0Data[i], y0Data[i]))
        for i in range(0, len(x1Data)):
            if self.ch1Enable.isChecked():
                self.chart2.append(QPoint(x1Data[i], y1Data[i]))
        for i in range(0, len(x2Data)):
            if self.ch2Enable.isChecked():
                self.chart3.append(QPoint(x2Data[i], y2Data[i]))
        for i in range(0, len(x3Data)):
            if self.ch3Enable.isChecked():
                self.chart4.append(QPoint(x3Data[i], y3Data[i]))
Beispiel #3
0
class Ui(mainwindow.Ui_MainWindow):
    def __init__(self, MainWindow):
        super(Ui, self).setupUi(MainWindow)
        self.MainWindow = MainWindow
        self.socketPacketReceiver = None

        self.timmer_is_on = False
        self.hexParser = StixHexStringParser()
        self.socketPacketReceiver = StixSocketPacketReceiver()
        self.socketPacketServer = StixSocketPacketServer()
        self.dataReader = StixFileReader()

        slots = {
            'info': self.onDataReaderInfo,
            'warning': self.onDataReaderWarning,
            'error': self.onDataReaderError,
            'critical': self.onDataReaderCritical,
            'dataLoaded': self.onDataReady,
            'packetArrival': self.onPacketArrival,
            'progress': self.onProgressUpdated
        }

        self.socketPacketReceiver.connectSignalSlots(slots)
        self.dataReader.connectSignalSlots(slots)
        self.hexParser.connectSignalSlots(slots)
        self.socketPacketServer.connectSignalSlots(slots)


        self.tabWidget.setCurrentIndex(0)
        self.actionExit.triggered.connect(self.close)
        self.actionPlot.setEnabled(False)

        self.actionNext.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_ArrowForward))
        self.actionPrevious.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_ArrowBack))
        self.actionOpen.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_DialogOpenButton))
        self.actionSave.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_DriveFDIcon))

        self.actionSave.triggered.connect(self.save)

        self.actionOpen.triggered.connect(self.getOpenFilename)
        self.filterPattern = None

        self.actionNext.triggered.connect(self.nextPacket)
        self.actionPrevious.triggered.connect(self.previousPacket)
        self.actionAbout.triggered.connect(self.about)

        self.actionPrevious.setEnabled(False)
        self.actionNext.setEnabled(False)
        self.actionSave.setEnabled(False)
        self.actionPlot.setEnabled(False)
        self.actionCopy.triggered.connect(self.onCopyTriggered)

        self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected)

        self.actionCopy.setEnabled(False)
        self.actionPaste.triggered.connect(self.onPasteTriggered)
        self.actionLog.triggered.connect(self.dockWidget.show)
        self.actionSetIDB.triggered.connect(self.onSetIDBClicked)
        self.plotButton.clicked.connect(
            partial(self.onPlotButtonClicked, None))

        #self.progressBar = QtWidgets.QProgressBar()
        #self.statusbar.addPermanentWidget(self.progressBar)
        self.progressDiag = None
        #self.progressBar.hide()

        self.actionPacketServer.triggered.connect(self.startPacketServer)

        self.exportButton.clicked.connect(self.onExportButtonClicked)
        self.actionPlot.triggered.connect(self.onPlotActionClicked)
        self.actionLoadMongodb.triggered.connect(self.onLoadMongoDBTriggered)
        self.actionConnectTSC.triggered.connect(self.onConnectTSCTriggered)
        self.actionPacketFilter.triggered.connect(self.filter)
        self.actionPlugins.triggered.connect(self.onPluginTriggered)
        self.actionOnlineHelp.triggered.connect(self.onOnlineHelpTriggered)
        self.actionViewBinary.triggered.connect(self.onViewBinaryTriggered)
        self.actionTimestampConvertor.triggered.connect(self.onTimestampConvertorTriggered)
        #self.actionPythonConsole.triggered.connect(self.startPythonConsole)
        self.autoUpdateButton.clicked.connect(
            self.onPlotAutoUpdateButtonClicked)

        self.packetTreeWidget.customContextMenuRequested.connect(
            self.packetTreeContextMenuEvent)

        #self.statusListWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        #self.statusListWidget.customContextMenuRequested.connect(self.statusListContextMenuEvent)

        self.mdb = None

        self.current_row = 0
        self.data = []
        self.x = []
        self.y = []
        self.xlabel = 'x'
        self.ylabel = 'y'

        self.buttons_enabled = False

        self.chart = QChart()
        self.chart.layout().setContentsMargins(0, 0, 0, 0)
        self.chart.setBackgroundRoundness(0)
        self.savePlotButton.clicked.connect(self.savePlot)

        self.chartView = QChartView(self.chart)
        self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15)
        self.selected_services = SELECTED_SERVICES
        self.selected_SPID = []
        self.selected_tmtc = 3

        # IDB location

        self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.idb_filename = self.settings.value('idb_filename', [], str)
        if self.idb_filename:
            STIX_IDB.reload(self.idb_filename)
        if not STIX_IDB.is_connected():
            self.showMessage('IDB has not been set!')
        else:
            idb_filename = STIX_IDB.get_idb_filename()
            self.showMessage('IDB loaded from : {} '.format(idb_filename), 1)
            if idb_filename != self.idb_filename:
                self.settings.setValue('idb_filename', idb_filename)
                self.idb_filename = idb_filename

    #def startPythonConsole(self):
    #    console.start({'packets': self.data})
    def close(self):
        self.MainWindow.close()
    def style(self):
        return self.MainWindow.style()

    def startPacketServer(self):
        host = 'localhost'
        port = 9096

        self.socketPacketServer.connect(host, port)
        self.socketPacketServer.setData(self.current_row, self.data)
        self.socketPacketServer.start()

        abspath = os.path.dirname(os.path.abspath(__file__))

        template = (
            "import sys\nsys.path.append('{}')\nimport client_packet_request as req\n"
            "packets=req.request(query_str='len', host='{}',port={}, verbose_level=1)\n"
            "#a query_string can be \n"
            "#  -  a python slice notation, for example, ':' '0:-1', 3:-1\n"
            "#  -  'len',  to get the total number of packets,\n"
            "#  -   index ,  to get a packet of the given index"
            "#set verbose_level to 0, to suppress print output  ").format(
                abspath, host, port)
        cb = QtWidgets.QApplication.clipboard()
        cb.clear(mode=cb.Clipboard)
        cb.setText(template, mode=cb.Clipboard)
        msg = QtWidgets.QMessageBox()
        msg.setIcon(QtWidgets.QMessageBox.Information)
        msg.setText(
            "Packet server started and a template to request packet has been copied to your clipboard!"
        )
        retval = msg.exec_()

    def onPlotAutoUpdateButtonClicked(self):
        if not self.timmer_is_on:
            if not self.data:
                return
            num_packets = len(self.data)
            if num_packets > 200:
                packets = self.data[-200:-1]
            else:
                packets = self.data
            self.timer = QTimer()
            self.timer.timeout.connect(
                partial(self.onPlotButtonClicked, packets))
            self.timer.start(2000)
            self.timmer_is_on = True
            self.autoUpdateButton.setText('Stop Auto Update')
        else:
            if self.timer:
                self.timer.stop()
            self.timmer_is_on = False
            self.autoUpdateButton.setText('Start Auto Update')

    #def statusListContextMenuEvent(self,pos):
    #    menu = QtWidgets.QMenu()
    #    clearLogAction= menu.addAction('Empty log')
    #    clearLogAction.triggered.connect(self.clearLog)
    #def clearLog(self):
    #    self.statusListWidget.clear()

    def packetTreeContextMenuEvent(self, pos):
        menu = QtWidgets.QMenu()
        filterAction = menu.addAction('Filter')
        menu.addSeparator()
        rawDataAction = menu.addAction('Raw binary data')
        menu.addSeparator()
        copyPacketAction = menu.addAction('Copy packet')
        menu.addSeparator()
        deleteAllAction = menu.addAction('Delete all packets')
        self.current_row = self.packetTreeWidget.currentIndex().row()

        rawDataAction.triggered.connect(self.onViewBinaryTriggered)
        filterAction.triggered.connect(self.filter)
        copyPacketAction.triggered.connect(self.onCopyTriggered)
        deleteAllAction.triggered.connect(self.onDeleteAllTriggered)
        action = menu.exec_(self.packetTreeWidget.viewport().mapToGlobal(pos))

    def filter(self):
        text, okPressed = QtWidgets.QInputDialog.getText(
            None, "Packet filtering",
            "Filtering by SPID or description (! to exclude):",
            QtWidgets.QLineEdit.Normal, "")
        if okPressed:
            self.filterPattern = text
            self.addPacketsToView(self.data, True, show_stat=False)

    def onDeleteAllTriggered(self):
        self.data.clear()
        self.current_row = 0
        self.packetTreeWidget.clear()
        self.paramTreeWidget.clear()

    #def onPacketTreeItemDoubleClicked(self):
    #    self.onViewBinaryTriggered()

    def onViewBinaryTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = raw_viewer.Ui_Dialog()
        diag_ui.setupUi(diag)
        if self.data:
            try:
                raw = self.data[self.current_row]['bin']
                header = self.data[self.current_row]['header']
                diag_ui.setPacketInfo('{}({},{})  {}'.format(
                    header['TMTC'], header['service_type'],
                    header['service_subtype'], header['descr']))
                diag_ui.displayRaw(raw)
            except (IndexError, KeyError):
                diag_ui.setText('Raw data not available.')
        diag.exec_()

    def onOnlineHelpTriggered(self):
        webbrowser.open(
            'https://github.com/i4Ds/STIX-python-data-parser', new=2)

    def onTimestampConvertorTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = timestamp_convertor.Ui_Dialog()
        diag_ui.setupUi(diag)
        diag.exec_()


    def onPluginTriggered(self):
        self.plugin_location = self.settings.value('plugin_location', [], str)
        diag = QtWidgets.QDialog()
        diag_ui = plugin.Ui_Dialog()
        diag_ui.setupUi(diag)
        if self.plugin_location:
            diag_ui.setPluginLocation(self.plugin_location)

        diag_ui.setData(self.data, self.current_row)
        diag.exec_()
        location = diag_ui.getPluginLocation()
        if location != self.plugin_location:
            self.settings.setValue('plugin_location', location)

    def onPacketFilterTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = packet_filter.Ui_Dialog()
        diag_ui.setupUi(diag)
        self.filterPattern = ''  #empty search string
        diag_ui.setSelectedServices(self.selected_services)

        diag_ui.buttonBox.accepted.connect(
            partial(self.applyServiceFilter, diag_ui))
        diag.exec_()

    def applyServiceFilter(self, diag_ui):
        self.selected_SPID = diag_ui.getSelectedSPID()
        self.selected_services = diag_ui.getSelectedServices()
        self.selected_tmtc = diag_ui.getTMTC()
        self.showMessage('Applying filter...')

        self.addPacketsToView(self.data, True, show_stat=False)

    def onExportButtonClicked(self):
        if self.y:
            filename = str(
                QtWidgets.QFileDialog.getSaveFileName(
                    None, "Save data to file", "", "CSV(*.csv)")[0])
            if filename:
                with open(filename, 'w') as f:
                    f.write('{},{}\n'.format(self.xlabel, self.ylabel))
                    for xx, yy in zip(self.x, self.y):
                        f.write('{},{}\n'.format(xx, yy))
                    self.showMessage(
                        'The data has been written to {}'.format(filename))
        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('Plot first!')
            msgBox.setWindowTitle("Warning")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def savePlot(self):
        # if self.figure.get_axes():
        if self.chart:
            filetypes = "PNG (*.png);;JPEG (*.jpg)"
            filename = str(
                QtWidgets.QFileDialog.getSaveFileName(
                    None, "Save plot to file", "", filetypes)[0])
            if filename:
                if not filename.endswith(('.png', '.jpg')):
                    filename += '.png'
                # self.figure.savefig(filename)
                p = self.chartView.grab()
                p.save(filename)
                self.showMessage(('Has been saved to %s.' % filename))

        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('No figure to save')
            msgBox.setWindowTitle("STIX raw data viewer")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def onCopyTriggered(self):
        packet_id = self.current_row
        try:
            packet = self.data[packet_id]
            ss = pprint.pformat(packet)

            cb = QtWidgets.QApplication.clipboard()
            cb.clear(mode=cb.Clipboard)
            cb.setText(ss, mode=cb.Clipboard)
            msg = QtWidgets.QMessageBox()
            msg.setIcon(QtWidgets.QMessageBox.Information)
            msg.setText(
                "The data of the selected packet has been copied to the clipboard."
            )
            msg.setWindowTitle("Information")
            msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
            retval = msg.exec_()

        except Exception as e:
            self.showMessage(str(e), 0)

    def onPasteTriggered(self):
        raw_hex = QtWidgets.QApplication.clipboard().text()
        if len(raw_hex) < 16:
            self.showMessage('No data in the clipboard.')
            return
        self.hexParser.setHex(raw_hex)
        self.hexParser.start()

    def showMessage(self, msg, where=0):
        if where != 1:
            self.statusbar.showMessage(msg)
        if where != 0:
            self.statusListWidget.addItem(msg)

    def onSetIDBClicked(self):
        self.idb_filename = QtWidgets.QFileDialog.getOpenFileName(
            None, 'Select file', '.', 'IDB file(*.db *.sqlite *.sqlite3)')[0]

        if not self.idb_filename:
            return

        STIX_IDB.reload(self.idb_filename)
        if STIX_IDB.is_connected():
            #settings = QtCore.QSettings('FHNW', 'stix_parser')
            self.settings.setValue('idb_filename', self.idb_filename)
        self.showMessage(
            'IDB location: {} '.format(STIX_IDB.get_idb_filename()), 1)

    def save(self):
        filetypes = 'python compressed pickle (*.pklz);; python pickle file (*.pkl);; binary data (*.dat)'
        self.output_filename = str(
            QtWidgets.QFileDialog.getSaveFileName(None, "Save packets to", "",
                                                  filetypes)[0])

        if not self.output_filename.endswith(('.pklz', '.pkl', '.dat')):
            msg = 'unsupported file format !'
            self.showMessage(msg)
            return

        msg = 'Writing data to file %s' % self.output_filename
        self.showMessage(msg)
        if self.output_filename.endswith(('.pklz', '.pkl')):
            stw = stix_writer.StixPickleWriter(self.output_filename)
            stw.register_run(str(self.input_filename))
            stw.write_all(self.data)
        elif self.output_filename.endswith('.dat'):
            stw = stix_writer.StixBinaryWriter(self.output_filename)
            stw.write_all(self.data)
            num_ok = stw.get_num_sucess()
            msg = (
                'The binary data of {} packets written to file {}, total packets {}'
                .format(num_ok, self.output_filename, len(self.data)))
            self.showMessage(msg)
        msg = 'Packets have been written to %s' % self.output_filename
        self.showMessage(msg)

    def setListViewSelected(self, row):
        #index = self.model.createIndex(row, 0);
        # if index.isValid():
        #    self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select)
        pass

    def about(self):
        msgBox = QtWidgets.QMessageBox()
        msgBox.setIcon(QtWidgets.QMessageBox.Information)
        msgBox.setText("STIX raw data parser and viewer, [email protected]")
        msgBox.setWindowTitle("Stix data viewer")

        msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
        msgBox.exec_()

    def nextPacket(self):
        self.current_row += 1
        length = len(self.data)

        if self.current_row >= length:
            self.current_row = length - 1
            self.showMessage('No more packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def previousPacket(self):
        self.current_row -= 1
        if self.current_row < 0:
            self.current_row = 0
            self.showMessage('Reach the first packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def getOpenFilename(self):

        location = self.settings.value('location', [], str) 
        if not location:
            location = '.'


        filetypes = (
            'Supported file (*.dat *.bin *.binary *.pkl *.pklz *.xml *ascii *BDF *txt) ;; All(*)'
        )
        self.input_filename = QtWidgets.QFileDialog.getOpenFileName(
            None, 'Select file', location, filetypes)[0]
        if not self.input_filename:
            return
        self.settings.setValue('location', os.path.abspath(self.input_filename))

        diag = QtWidgets.QDialog()
        diag_ui = packet_filter.Ui_Dialog()
        diag_ui.setupUi(diag)
        diag_ui.setSelectedServices(SELECTED_SERVICES)
        diag_ui.buttonBox.accepted.connect(
            partial(self.onOpenFile, self.input_filename, diag_ui))
        diag.exec_()

    def onOpenFile(self, input_filename, diag):
        self.selected_SPID = diag.getSelectedSPID()
        self.selected_services = diag.getSelectedServices()
        self.openFile(input_filename, self.selected_services,
                      self.selected_SPID)

    def openFile(self, filename, selected_services=None, selected_SPID=None):
        msg = 'Loading file %s ...' % filename
        self.progressDiag = QtWidgets.QProgressDialog()
        #self.showMessage(msg)
        self.progressDiag.setLabelText(msg)
        self.progressDiag.setWindowTitle('Loading data')
        self.progressDiag.setCancelButtonText('Cancel')
        self.progressDiag.setRange(0, 100)
        self.progressDiag.setMinimumWidth(300)
        self.progressDiag.canceled.connect(self.stopParsing)
        self.filterPattern = ''
        self.dataReader.setPacketFilter(selected_services, selected_SPID)
        self.dataReader.setFilename(filename)
        self.dataReader.start()
        self.progressDiag.show()

    def stopParsing(self):
        if self.dataReader:
            self.dataReader.stopParsing()
            self.progressDiag.hide()

    def onProgressUpdated(self, progress):
        if not self.progressDiag:
            return
        self.progressDiag.setValue(progress)
        if progress >=99:
            self.progressDiag.hide()

    def onDataReaderCritical(self, msg):
        self.showMessage(msg, 1)

    def onDataReaderInfo(self, msg):
        self.showMessage(msg, 0)

    def onDataReaderWarning(self, msg):
        self.showMessage(msg, 1)

    def onDataReaderError(self, msg):
        self.showMessage(msg, 1)

    def onDataReady(self, data, clear=True, show_stat=True):
        #self.progressBar.hide()
        if not clear:
            self.data.extend(data)
        else:
            self.data = data
        if data:
            self.addPacketsToView(data, clear=clear, show_stat=show_stat)
            self.enableButtons()
        else:
            self.showMessage('No packet loaded')

    def enableButtons(self):
        if not self.buttons_enabled:
            self.actionPrevious.setEnabled(True)
            self.actionNext.setEnabled(True)
            self.actionSave.setEnabled(True)
            self.actionCopy.setEnabled(True)
            self.actionPlot.setEnabled(True)
            self.actionViewBinary.setEnabled(True)
            self.buttons_enabled = True

    def addPacketsToView(self, data, clear=True, show_stat=True):
        if clear:
            self.packetTreeWidget.clear()

        for p in data:
            if not isinstance(p, dict):
                continue
            header = p['header']
            root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget)
            colors = {2: '#FFA500', 1: '#000080', 3: '#FF0000', 4: '#800000'}
            tc_color = '#78281F'
            if header['TMTC'] == 'TC':
                root.setForeground(0, QtGui.QBrush(QtGui.QColor(tc_color)))
                root.setForeground(1, QtGui.QBrush(QtGui.QColor(tc_color)))
            else:
                if header['service_type'] == 5:
                    if header['service_subtype'] in colors.keys():
                        root.setForeground(
                            0,
                            QtGui.QBrush(
                                QtGui.QColor(
                                    colors[header['service_subtype']])))
                        root.setForeground(
                            1,
                            QtGui.QBrush(
                                QtGui.QColor(
                                    colors[header['service_subtype']])))

            timestamp_str = stix_datetime.format_datetime(header['unix_time'])
            root.setText(0, timestamp_str)
            description = '{}({},{}) - {}'.format(
                header['TMTC'], header['service_type'],
                header['service_subtype'], header['descr'])
            root.setText(1, description)
            hidden = False

            if self.selected_SPID:
                if header['TMTC'] == 'TC':
                    hidden = True
                elif -int(header['SPID']) in self.selected_SPID or int(
                        header['SPID']) not in self.selected_SPID:
                    hidden = True
            else:
                if int(header['service_type']) not in self.selected_services:
                    hidden = True

            TMTC = header['TMTC']
            if TMTC == 'TM' and self.selected_tmtc in [2, 0]:
                hidden = True
            if TMTC == 'TC' and self.selected_tmtc in [1, 0]:
                hidden = True


            if self.filterPattern:
                to_exclude = False
                pattern = self.filterPattern.strip()
                if pattern.startswith('!'):
                    to_exclude = True
                    pattern = pattern[1:]
                try:
                    spid = int(pattern)
                    hidden = to_exclude == (header['SPID'] == spid)
                    #XNOR operation
                except (TypeError, ValueError):
                    hidden = to_exclude == (pattern in description)

            root.setHidden(hidden)

        if show_stat:
            total_packets = len(self.data)
            self.showMessage(('Total packet(s): %d' % total_packets))

    def onConnectTSCTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = tsc_connection.Ui_Dialog()
        diag_ui.setupUi(diag)
        self.tsc_host = self.settings.value('tsc_host', [], str)
        self.tsc_port = self.settings.value('tsc_port', [], str)
        if self.tsc_host:
            diag_ui.serverLineEdit.setText(self.tsc_host)
        if self.tsc_port:
            diag_ui.portLineEdit.setText(self.tsc_port)
        diag_ui.buttonBox.accepted.connect(partial(self.connectToTSC, diag_ui))
        diag.exec_()

    def connectToTSC(self, dui):
        host = dui.serverLineEdit.text()
        port = dui.portLineEdit.text()
        self.showMessage('Connecting to TSC...')

        self.socketPacketReceiver.connect(host, int(port))
        self.socketPacketReceiver.start()

    def onPacketArrival(self, packets):
        clear = False
        if packets:
            if len(self.data) > MAX_NUM_PACKET_IN_BUFFER:
                clear = True
            self.onDataReady(packets, clear=clear, show_stat=True)

    def onLoadMongoDBTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = mongo_dialog.Ui_Dialog()
        diag_ui.setupUi(diag)
        #self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.mongo_server = self.settings.value('mongo_server', [], str)
        self.mongo_port = self.settings.value('mongo_port', [], str)
        self.mongo_user = self.settings.value('mongo_user', [], str)
        self.mongo_pwd = self.settings.value('mongo_pwd', [], str)

        if self.mongo_server:
            diag_ui.serverLineEdit.setText(self.mongo_server)
        if self.mongo_port:
            diag_ui.portLineEdit.setText(self.mongo_port)

        if self.mongo_user:
            diag_ui.userLineEdit.setText(self.mongo_user)
        if self.mongo_pwd:
            diag_ui.pwdLineEdit.setText(self.mongo_pwd)

        diag_ui.pushButton.clicked.connect(
            partial(self.loadRunsFromMongoDB, diag_ui))
        diag_ui.buttonBox.accepted.connect(
            partial(self.loadDataFromMongoDB, diag_ui, diag))
        diag.exec_()

    def loadRunsFromMongoDB(self, dui):
        server = dui.serverLineEdit.text()
        port = dui.portLineEdit.text()
        user = dui.userLineEdit.text()
        pwd = dui.pwdLineEdit.text()

        self.showMessage('saving setting...')
        if self.mongo_server != server:
            self.settings.setValue('mongo_server', server)
        if self.mongo_port != port:
            self.settings.setValue('mongo_port', port)

        if self.mongo_user != user:
            self.settings.setValue('mongo_user', user)
        if self.mongo_pwd != pwd:
            self.settings.setValue('mongo_pwd', pwd)

        self.showMessage('connecting Mongo database ...')
        self.mdb = mgdb.MongoDB(server, int(port), user, pwd)
        if not self.mdb.is_connected():
            self.showMessage('Failed to connect to MongoDB')
            return

        dui.treeWidget.clear()
        self.showMessage('Fetching data...')
        for run in self.mdb.select_all_runs():
            root = QtWidgets.QTreeWidgetItem(dui.treeWidget)
            root.setText(0, str(run['_id']))
            root.setText(1, run['filename'])
            root.setText(2, stix_datetime.format_datetime(run['date']))
            root.setText(3, stix_datetime.format_datetime(run['data_start_unix_time']))
            root.setText(4, stix_datetime.format_datetime(run['data_stop_unix_time']))

    def loadDataFromMongoDB(self, dui, diag):
        self.showMessage('Loading packets ...')
        selected_runs = []
        for item in dui.treeWidget.selectedItems():
            selected_runs.append(item.text(0))
        if not selected_runs:
            self.showMessage('Run not selected!')
        if selected_runs:
            diag.done(0)
            self.showMessage('Loading data ...!')
            data = list(self.mdb.select_packets_by_run(selected_runs[0]))
            if data:
                self.onDataReady(data, clear=True)
            else:
                self.showMessage('No packets found!')
        # close

    def onPacketSelected(self, cur, pre):
        self.current_row = self.packetTreeWidget.currentIndex().row()
        self.showMessage(('Packet #%d selected' % self.current_row))
        self.showPacket(self.current_row)

    def showPacket(self, row):
        if not self.data:
            return
        header = self.data[row]['header']
        total_packets = len(self.data)
        self.showMessage(
            ('Packet %d / %d  %s ' % (row, total_packets, header['descr'])))
        self.paramTreeWidget.clear()
        header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        header_root.setText(0, "Header")
        rows = len(header)
        for key, val in header.items():
            root = QtWidgets.QTreeWidgetItem(header_root)
            root.setText(0, key)
            root.setText(1, str(val))

        params = self.data[row]['parameters']
        param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        param_root.setText(0, "Parameters")
        self.showParameterTree(params, param_root)
        self.paramTreeWidget.expandItem(param_root)
        self.paramTreeWidget.expandItem(header_root)
        self.current_row = row

    def showParameterTree(self, params, parent, parent_id=[]):
        if not params:
            return
        for i, p in enumerate(params):
            root = QtWidgets.QTreeWidgetItem(parent)
            if not p:
                continue
            param = Parameter(p)
            param_name = param['name']
            desc = param['desc']
            current_ids = parent_id[:]
            current_ids.append(i)
            root.setText(0, param_name)

            root.setText(1, desc)
            root.setText(2, str(param['raw']))
            tip='parameter'+''.join(['[{}]'.format(x) for x in current_ids])
            root.setToolTip(0, tip)

            long_desc = STIX_IDB.get_scos_description(param_name)
            if long_desc:
                root.setToolTip(1, long_desc)

            try:
                root.setToolTip(2, hex(param['raw_int']))
            except:
                pass
            unit=STIX_IDB.get_parameter_unit(param_name)
            eng=str(param['eng'])
            root.setText(3, eng)
            root.setText(4, unit)
            if 'NIXG' in param_name:
                root.setHidden(True)
                #groups should not be shown
            if param.children:
                self.showParameterTree(param['children'], root, current_ids)
        self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked)

    def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0):
        if not params:
            return
        timestamp = header['unix_time']
        for p in params:
            if not p:
                continue
            param = Parameter(p)
            if name == param.name:
                values = None
                if data_type == 0:
                    values = param.raw
                else:
                    values = param.eng
                try:
                    yvalue = float(values)
                    ret_y.append(yvalue)
                    if xaxis == 1:
                        ret_x.append(timestamp)
                    else:
                        self.showMessage(('Can not plot %s  ' % str(yvalue)))
                except Exception as e:
                    self.showMessage(('%s ' % str(e)))

            if param.children:
                self.walk(name, param.children, header, ret_x, ret_y, xaxis,
                          data_type)

    def onPlotButtonClicked(self, packets=None):
        if self.chart:
            self.chart.removeAllSeries()
        if packets is None:
            packets = self.data
        if not packets:
            return

        self.showMessage('Preparing plot ...')
        name = self.paramNameEdit.text()
        packet_selection = self.comboBox.currentIndex()
        xaxis_type = self.xaxisComboBox.currentIndex()
        data_type = self.dataTypeComboBox.currentIndex()
        timestamp = []
        self.y = []
        params = self.paramNameEdit.text()
        header = packets[0]['header']
        current_spid = 0
        spid_text = self.spidLineEdit.text()
        if spid_text:
            current_spid = int(spid_text)
        selected_packets=[] 
        if packet_selection == 0:
            selected_packets=[packets[self.current_row]]
        elif packet_selection == 1:
            selected_packets=packets

        for packet in selected_packets:
            header = packet['header']
            if packet['header']['SPID'] != current_spid:
                continue
            params = packet['parameters']
            self.walk(name, params, header, timestamp, self.y, xaxis_type,
                      data_type)


        self.x = []

        if not self.y:
            self.showMessage('No data points')
        elif self.y:
            style = self.styleEdit.text()
            if not style:
                style = '-'
            title = '%s' % str(name)
            desc = self.descLabel.text()
            if desc:
                title += '- %s' % desc

            self.chart.setTitle(title)

            ylabel = 'Raw value'
            xlabel = name
            if data_type == 1:
                ylabel = 'Engineering / Decompressed  value'
            if xaxis_type == 0:
                if packet_selection == 1:
                    xlabel = "Packet #"
                else:
                    xlabel = "Repeat #"
                self.x = range(0, len(self.y))
            if xaxis_type == 1:
                self.x = [t - timestamp[0] for t in timestamp]
                xlabel = 'Time -T0 (s)'

            if xaxis_type != 2:
                series = QLineSeries()
                series2 = None
                for xx, yy in zip(self.x, self.y):
                    series.append(xx, yy)
                if 'o' in style:
                    series2 = QScatterSeries()
                    for xx, yy in zip(self.x, self.y):
                        series2.append(xx, yy)
                    self.chart.addSeries(series2)
                self.chart.addSeries(series)
                axisX = QValueAxis()
                axisX.setTitleText(xlabel)
                axisY = QValueAxis()
                axisY.setTitleText(ylabel)

                self.chart.setAxisX(axisX)
                self.chart.setAxisY(axisY)
                series.attachAxis(axisX)
                series.attachAxis(axisY)
            else:
                nbins = len(set(self.y))
                ycounts, xedges = np.histogram(self.y, bins=nbins)
                series = QLineSeries()
                for i in range(0, nbins):
                    meanx = (xedges[i] + xedges[i + 1]) / 2.
                    series.append(meanx, ycounts[i])
                self.chart.addSeries(series)
                axisX = QValueAxis()
                axisX.setTitleText(name)
                axisY = QValueAxis()
                axisY.setTitleText("Counts")

                self.chart.setAxisY(axisY)
                self.chart.setAxisX(axisX)
                series.attachAxis(axisX)
                series.attachAxis(axisY)

            self.xlabel = xlabel
            self.ylabel = ylabel
            self.chartView.setRubberBand(QChartView.RectangleRubberBand)
            self.chartView.setRenderHint(QtGui.QPainter.Antialiasing)
            msg = 'Number of data points: {}, Ymin: {}, Ymax: {}'.format(
                len(self.y), min(self.y), max(self.y))
            self.showMessage(msg, 1)

            self.showMessage('The canvas updated!')

    def plotParameter(self, SPID=None, pname=None, desc=None):
        self.tabWidget.setCurrentIndex(1)
        if pname:
            self.paramNameEdit.setText(pname)
        if desc:
            self.descLabel.setText(desc)
        if SPID:
            self.spidLineEdit.setText(str(SPID))

    def onPlotActionClicked(self):
        self.tabWidget.setCurrentIndex(1)
        self.plotParameter()

    def onTreeItemClicked(self, it, col):
        SPID = None
        try:
            SPID = self.data[self.current_row]['header']['SPID']
        except IndexError:
            pass
        self.plotParameter(SPID, it.text(0), it.text(1))
Beispiel #4
0
class Ui(mainwindow.Ui_MainWindow):
    def __init__(self, MainWindow):
        #super(Ui, self).__init__(M)
        super(Ui, self).setupUi(MainWindow)
        #uic.loadUi('UI/mainwindow.ui', self)

        self.MainWindow = MainWindow

        self.initialize()

    def close(self):
        self.MainWindow.close()

    def style(self):
        return self.MainWindow.style()

    def initialize(self):
        self.tabWidget.setCurrentIndex(0)
        self.actionExit.triggered.connect(self.close)
        self.action_Plot.setEnabled(False)

        self.actionNext.setIcon(
            self.style().standardIcon(
                QtWidgets.QStyle.SP_ArrowForward))
        self.actionPrevious.setIcon(
            self.style().standardIcon(
                QtWidgets.QStyle.SP_ArrowBack))
        self.action_Open.setIcon(
            self.style().standardIcon(
                QtWidgets.QStyle.SP_DialogOpenButton))
        self.actionSave.setIcon(
            self.style().standardIcon(
                QtWidgets.QStyle.SP_DriveFDIcon))

        self.actionSave.triggered.connect(self.save)

        self.action_Open.triggered.connect(self.getOpenFilename)

        self.actionNext.triggered.connect(self.nextPacket)
        self.actionPrevious.triggered.connect(self.previousPacket)
        self.actionAbout.triggered.connect(self.about)

        self.actionPrevious.setEnabled(False)
        self.actionNext.setEnabled(False)
        self.actionSave.setEnabled(False)
        self.action_Plot.setEnabled(False)
        self.actionPaste.triggered.connect(self.onPasteTriggered)
        # self.actionLog.triggered.connect(self.dockWidget_2.show)
        self.actionSet_IDB.triggered.connect(self.onSetIDBClicked)
        self.plotButton.clicked.connect(self.onPlotButtonClicked)
        self.exportButton.clicked.connect(self.onExportButtonClicked)
        self.action_Plot.triggered.connect(self.onPlotActionClicked)
        self.actionLoad_mongodb.triggered.connect(self.onLoadMongoDBTriggered)
        self.mdb=None

        self.current_row = 0
        self.data=[]
        self.x=[]
        self.y=[]
        self.xlabel='x'
        self.ylabel='y'

        self.chart = QChart()
        self.chart.layout().setContentsMargins(0,0,0,0)
        self.chart.setBackgroundRoundness(0)
        self.savePlotButton.clicked.connect(self.savePlot)
        
        self.chartView = QChartView(self.chart)
        self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15)

        # IDB location

        self.settings = QtCore.QSettings('FHNW', 'stix_parser')
    def onExportButtonClicked(self):
        if self.y:
            filename = str(QtWidgets.QFileDialog.getSaveFileName(
                None, "Save file", "", "*.csv")[0])
            if filename:
                with open(filename,'w') as f:
                    f.write('{},{}\n'.format(self.xlabel,self.ylabel))
                    for xx,yy in zip(self.x,self.y):
                        f.write('{},{}\n'.format(xx,yy))
                    self.showMessage('The data has been written to {}'.format(filename))
        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('Plot first!')
            msgBox.setWindowTitle("Warning")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()


    def savePlot(self):
        #if self.figure.get_axes():
        if self.chart:
            filename = str(QtWidgets.QFileDialog.getSaveFileName(
                None, "Save file", "", "*.png *.jpg")[0])
            if filename:
                if not filename.endswith(('.png','.jpg')):
                    filename+='.png'
                #self.figure.savefig(filename)
                p=self.chartView.grab()
                p.save(filename)
                self.showMessage(('Saved to %s.' % filename))


        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('The canvas is empty!')
            msgBox.setWindowTitle("STIX DATA VIEWER")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def onPasteTriggered(self):
        pass

    def showMessageBox(self, message, content):
        msg = QtWidgets.QMessageBox()
        msg.setIcon(QtWidgets.QMessageBox.Critical)
        msg.setText("Error")
        msg.setInformativeText(message)
        msg.setWindowTitle("Error")
        msg.setDetailedText(content)
        msg.setStandardButtons(QtWidgets.QMessageBox.Ok |
                               QtWidgets.QMessageBox.Cancel)
        retval = msg.exec_()

    def showMessage(self, msg):
        # if destination != 1:
        self.statusbar.showMessage(msg)
        # if destination !=0 :
        #    self.listWidget_2.addItem(msg)

    def onSetIDBClicked(self):
        pass
    def save(self):
        pass

    def setListViewSelected(self, row):
        #index = self.model.createIndex(row, 0);
        # if index.isValid():
        #    self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select)
        pass

    def about(self):
        msgBox = QtWidgets.QMessageBox()
        msgBox.setIcon(QtWidgets.QMessageBox.Information)
        msgBox.setText("STIX raw data parser and viewer, [email protected]")
        msgBox.setWindowTitle("Stix data viewer")
        msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
        msgBox.exec_()

    def nextPacket(self):
        self.current_row += 1
        length=len(self.data)
        
        if self.current_row>=length:
            self.current_row=length-1
            self.showMessage('No more packet!')
            

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def previousPacket(self):
        self.current_row -= 1
        if self.current_row <0:
            self.current_row=0
            self.showMessage('Reach the first packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def getOpenFilename(self):
        pass

    def openFile(self, filename):
        pass



    def onDataLoaded(self, data,clear=True):
        if not clear:
            self.data.append(data)
        else:
            self.data = data
        self.displayPackets(clear)

        if self.data:
            self.actionPrevious.setEnabled(True)
            self.actionNext.setEnabled(True)
            self.actionSave.setEnabled(True)
            self.action_Plot.setEnabled(True)

    def displayPackets(self,clear=True):
        if clear:
            self.packetTreeWidget.clear()
        t0=0
        for p in self.data:
            if type(p) is not dict:
                continue
            header = p['header']
            root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget)
            if t0==0:
                t0=header['time']

            root.setText(0, '{:.2f}'.format(header['time']-t0))
            root.setText(1,
                         ('TM({},{}) - {}').format(header['service_type'],
                                                   header['service_subtype'],
                                                   header['DESCR']))
        self.total_packets = len(self.data)
        self.showMessage((('%d packets loaded') % (self.total_packets)))
        self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected)
        self.showPacket(0)

    def onLoadMongoDBTriggered(self):
        diag=QtWidgets.QDialog()
        diag_ui=mongo_dialog.Ui_Dialog()
        diag_ui.setupUi(diag)
        diag_ui.pushButton.setFocus(True)
        #self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.mongo_server= self.settings.value('mongo_server', [], str)
        self.mongo_port= self.settings.value('mongo_port', [], str)
        self.mongo_user= self.settings.value('mongo_user', [], str)
        self.mongo_pwd= self.settings.value('mongo_pwd', [], str)

        if self.mongo_server:
            diag_ui.serverLineEdit.setText(self.mongo_server)
        if self.mongo_port:
            diag_ui.portLineEdit.setText(self.mongo_port)

        if self.mongo_user:
            diag_ui.userLineEdit.setText(self.mongo_user)
        if self.mongo_pwd:
            diag_ui.pwdLineEdit.setText(self.mongo_pwd)

        diag_ui.pushButton.clicked.connect(partial(self.loadRunsFromMongoDB,diag_ui))
        diag_ui.buttonBox.accepted.connect(partial(self.loadDataFromMongoDB,diag_ui,diag))
        diag.exec_()
    def loadRunsFromMongoDB(self,dui):
        server=dui.serverLineEdit.text()
        port=dui.portLineEdit.text()
        user=dui.userLineEdit.text()
        pwd=dui.pwdLineEdit.text()

        self.showMessage('saving setting...')
        if self.mongo_server!=server:
            self.settings.setValue('mongo_server', server)
        if self.mongo_port!=port:
            self.settings.setValue('mongo_port', port)

        if self.mongo_user!=user:
            self.settings.setValue('mongo_user', user)
        if self.mongo_pwd!=pwd:
            self.settings.setValue('mongo_pwd', pwd)


        self.showMessage('connecting Mongo database ...')
        self.mdb=mgdb.MongoDB(server,int(port),user,pwd)
        dui.treeWidget.clear()
        self.showMessage('Fetching data...')
        for run in self.mdb.get_runs():
            root = QtWidgets.QTreeWidgetItem(dui.treeWidget)
            root.setText(0, str(run['_id']))
            root.setText(1, run['file'])
            root.setText(2, run['date'])
            root.setText(3, str(run['start']))
            root.setText(4, str(run['end']))
        self.showMessage('Runs loaded!')
    def loadDataFromMongoDB(self,dui,diag):
        selected_runs=[]
        for item in dui.treeWidget.selectedItems():
            selected_runs.append(item.text(0))
        if not selected_runs:
            self.showMessage('Run not selected!')
        if selected_runs:
            diag.done(0)
            self.showMessage('Loading data ...!')
            data=self.mdb.get_packets(selected_runs[0])
            if data:
                self.onDataLoaded(data,clear=True)
            else:
                self.showMessage('No packets found!')
        #close

    def onPacketSelected(self, cur, pre):
        self.current_row = self.packetTreeWidget.currentIndex().row()
        self.showMessage((('Packet #%d selected') % self.current_row))
        self.showPacket(self.current_row)

    def showPacket(self, row):
        if not self.data:
            return
        header = self.data[row]['header']
        self.showMessage(
            (('Packet %d / %d  %s ') %
             (row, self.total_packets, header['DESCR'])))

        self.paramTreeWidget.clear()

        header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        header_root.setText(0, "Header")
        rows = len(header)
        for key, val in header.items():
            root = QtWidgets.QTreeWidgetItem(header_root)
            root.setText(0, key)
            root.setText(1, str(val))

        params = self.data[row]['parameters']
        param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        param_root.setText(0, "Parameters")
        self.showParameterTree(params, param_root)
        self.paramTreeWidget.expandItem(param_root)
        self.paramTreeWidget.expandItem(header_root)

    def showParameterTree(self, params, parent):
        for p in params:
            root = QtWidgets.QTreeWidgetItem(parent)
            if not p:
                continue
            try:
                param_name=p['name']
                desc=''
                scos_desc=''
                try:
                    desc=param_desc.PCF[param_name]
                    scos_desc=param_desc.SW[param_name]
                except KeyError:
                    pass
                root.setToolTip(1,scos_desc)
                root.setText(0, param_name)
                root.setText(1, desc)
                root.setText(2, str(p['raw']))
                root.setText(3, str(p['value']))
                if 'child' in p:
                    if p['child']:
                        self.showParameterTree(p['child'], root)
            except KeyError:
                self.showMessage(
                    ('[Error  ]: keyError occurred when adding parameter'))
        self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked)

    def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0):
        if not params:
            return
        timestamp = header['time']
        #parameters=[p for p in params if p['name'] == name] 
        for p in params:
            if type(p) is not dict:
                continue
        #for p in parameters:
            if name == p['name']:
                values = None
                #print('data type:{}'.format(data_type))
                if data_type == 0:
                    values = p['raw']
                else:
                    values = p['value']
                try:
                    yvalue = None
                    if (type(values) is tuple) or (type(values) is list):
                        yvalue = float(values[0])
                    else:
                        yvalue = float(values)
                    ret_y.append(yvalue)
                    if xaxis == 1:
                        ret_x.append(timestamp)
                    else:
                        self.showMessage((('Can not plot %s  ') % str(yvalue)))
                except Exception as e:
                    self.showMessage((('%s ') % str(e)))

            if 'child' in p:
                if p['child']:
                    self.walk(
                        name,
                        p['child'],
                        header,
                        ret_x,
                        ret_y,
                        xaxis,
                        data_type)

    def onPlotButtonClicked(self):
        if self.chart:
            self.chart.removeAllSeries()
        if not self.data:
            return
        self.showMessage('Preparing plot ...')
        name = self.paramNameEdit.text()
        packet_selection = self.comboBox.currentIndex()
        xaxis_type = self.xaxisComboBox.currentIndex()
        data_type = self.dataTypeComboBox.currentIndex()

        timestamp = []
        self.y = []
        packet_id = self.current_row
        params = self.data[packet_id]['parameters']
        header = self.data[packet_id]['header']
        current_spid=header['SPID']
        if packet_selection == 0:
            self.walk(
                name,
                params,
                header,
                timestamp,
                self.y,
                xaxis_type,
                data_type)
        elif packet_selection == 1:
            for packet in self.data:
                header = packet['header']
                if packet['header']['SPID'] != current_spid:
                    continue
                #only look for parameters in the packets of the same type
                params = packet['parameters']
                self.walk(
                    name,
                    params,
                    header,
                    timestamp,
                    self.y,
                    xaxis_type,
                    data_type)

        self.x = []



        if not self.y:
            self.showMessage('No data points')
        elif self.y:
            style = self.styleEdit.text()
            if not style:
                style = '-'
            title = '%s' % str(name)
            desc = self.descLabel.text()
            if desc:
                title += '- %s' % desc

            self.chart.setTitle(title)

            ylabel = 'Raw value'
            xlabel = name
            if data_type == 1:
                ylabel = 'Engineering  value'
            if xaxis_type == 0:
                xlabel = "Packet #"
                self.x = range(0, len(self.y))
            if xaxis_type == 1:
                self.x = [t - timestamp[0] for t in timestamp]
                xlabel = 'Time -T0 (s)'

            #if xaxis_type != 2:
            if True:
                series = QLineSeries()
                series2 = None

                # print(y)
                # print(x)
                for xx, yy in zip(self.x, self.y):
                    series.append(xx, yy)

                if 'o' in style:
                    series2 = QScatterSeries()
                    for xx, yy in zip(self.x, self.y):
                        series2.append(xx, yy)
                    self.chart.addSeries(series2)
                self.chart.addSeries(series)

                self.showMessage('plotted!')

                #self.chart.createDefaultAxes()
                axisX = QValueAxis()
                axisX.setTitleText(xlabel)
                axisY = QValueAxis()
                axisY.setTitleText(ylabel)

                self.chart.setAxisX(axisX)
                self.chart.setAxisY(axisY)
                series.attachAxis(axisX)
                series.attachAxis(axisY)

                # histogram
            #else:
            #    nbins = len(set(self.y))
            #    ycounts, xedges = np.histogram(self.y, bins=nbins)
            #    series = QLineSeries()
            #    for i in range(0, nbins):
            #        meanx = (xedges[i] + xedges[i + 1]) / 2.
            #        series.append(meanx, ycounts[i])
            #    # series.append(dataset)
            #    self.chart.addSeries(series)
            #    #self.chart.createDefaultAxes()
            #    self.showMessage('Histogram plotted!')

            #    axisX = QValueAxis()

            #    axisX.setTitleText(name)
            #    axisY = QValueAxis()

            #    axisY.setTitleText("Counts")

            #    self.chart.setAxisY(axisY)
            #    self.chart.setAxisX(axisX)
            ##    series.attachAxis(axisX)
            #    series.attachAxis(axisY)

            # self.widget.setChart(self.chart)
            self.xlabel=xlabel
            self.ylabel=ylabel
            self.chartView.setRubberBand(QChartView.RectangleRubberBand)
            self.chartView.setRenderHint(QtGui.QPainter.Antialiasing)

    def plotParameter(self, name=None, desc=None):
        self.tabWidget.setCurrentIndex(1)
        if name:
            self.paramNameEdit.setText(name)
        if desc:
            self.descLabel.setText(desc)

    def onPlotActionClicked(self):
        self.tabWidget.setCurrentIndex(1)
        self.plotParameter()

    def onTreeItemClicked(self, it, col):
        #print(it, col, it.text(0))
        self.plotParameter(it.text(0), it.text(1))

    def error(self, msg, description=''):
        self.showMessage((('Error: %s - %s') % (msg, description)))

    def warning(self, msg, description=''):
        self.showMessage((('Warning: %s - %s') % (msg, description)))

    def info(self, msg, description=''):
        self.showMessage((('Info: %s - %s') % (msg, description)))
class Ui(mainwindow.Ui_MainWindow):
    def __init__(self, MainWindow):
        super(Ui, self).setupUi(MainWindow)
        self.MainWindow = MainWindow
        self.stix_tctm_parser = stix_parser.StixTCTMParser()
        self.initialize()

    def close(self):
        self.MainWindow.close()

    def style(self):
        return self.MainWindow.style()

    def initialize(self):
        self.tabWidget.setCurrentIndex(0)
        self.actionExit.triggered.connect(self.close)
        self.actionPlot.setEnabled(False)

        self.actionNext.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_ArrowForward))
        self.actionPrevious.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_ArrowBack))
        self.actionOpen.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_DialogOpenButton))
        self.actionSave.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_DriveFDIcon))

        self.actionSave.triggered.connect(self.save)

        self.actionOpen.triggered.connect(self.getOpenFilename)

        self.actionNext.triggered.connect(self.nextPacket)
        self.actionPrevious.triggered.connect(self.previousPacket)
        self.actionAbout.triggered.connect(self.about)

        self.actionPrevious.setEnabled(False)
        self.actionNext.setEnabled(False)
        self.actionSave.setEnabled(False)
        self.actionPlot.setEnabled(False)
        self.actionCopy.triggered.connect(self.onCopyTriggered)

        self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected)

        self.actionCopy.setEnabled(False)
        self.actionPaste.triggered.connect(self.onPasteTriggered)
        self.actionLog.triggered.connect(self.dockWidget.show)
        self.actionSetIDB.triggered.connect(self.onSetIDBClicked)
        self.plotButton.clicked.connect(self.onPlotButtonClicked)
        self.exportButton.clicked.connect(self.onExportButtonClicked)
        self.actionPlot.triggered.connect(self.onPlotActionClicked)
        self.actionLoadMongodb.triggered.connect(self.onLoadMongoDBTriggered)
        self.actionConnectTSC.triggered.connect(self.onConnectTSCTriggered)
        self.actionPacketFilter.triggered.connect(self.onPacketFilterTriggered)
        self.actionPlugins.triggered.connect(self.onPluginTriggered)
        self.actionOnlineHelp.triggered.connect(self.onOnlineHelpTriggered)
        self.actionViewBinary.triggered.connect(self.onViewBinaryTriggered)

        self.packetTreeWidget.customContextMenuRequested.connect(
            self.packetTreeContextMenuEvent)

        self.mdb = None

        self.current_row = 0
        self.data = []
        self.x = []
        self.y = []
        self.xlabel = 'x'
        self.ylabel = 'y'

        self.buttons_enabled = False

        self.chart = QChart()
        self.chart.layout().setContentsMargins(0, 0, 0, 0)
        self.chart.setBackgroundRoundness(0)
        self.savePlotButton.clicked.connect(self.savePlot)

        self.chartView = QChartView(self.chart)
        self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15)
        #self.packetTreeWidget.itemDoubleClicked.connect(self.onPacketTreeItemDoubleClicked)
        self.selected_services = SELECTED_SERVICES
        self.selected_SPID = []

        # IDB location

        self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.idb_filename = self.settings.value('idb_filename', [], str)
        if self.idb_filename:
            idb._stix_idb.reload(self.idb_filename)
        if not idb._stix_idb.is_connected():
            self.showMessage('IDB has not been set!')
        else:
            self.showMessage(
                'IDB location: {} '.format(idb._stix_idb.get_idb_filename()),
                1)

    def packetTreeContextMenuEvent(self, pos):
        menu = QtWidgets.QMenu()
        rawDataAction = menu.addAction('Show raw data')
        menu.addSeparator()
        filterAction = menu.addAction('Filter packets')
        copyPacketAction = menu.addAction('Copy packet')
        menu.addSeparator()
        deleteAllAction = menu.addAction('Delete all packets')
        self.current_row = self.packetTreeWidget.currentIndex().row()

        rawDataAction.triggered.connect(self.onViewBinaryTriggered)
        filterAction.triggered.connect(self.onPacketFilterTriggered)
        copyPacketAction.triggered.connect(self.onCopyTriggered)
        deleteAllAction.triggered.connect(self.onDeleteAllTriggered)
        action = menu.exec_(self.packetTreeWidget.viewport().mapToGlobal(pos))

    def onDeleteAllTriggered(self):
        self.data.clear()
        self.packetTreeWidget.clear()
        self.paramTreeWidget.clear()

    #def onPacketTreeItemDoubleClicked(self):
    #    self.onViewBinaryTriggered()

    def onViewBinaryTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = raw_viewer.Ui_Dialog()
        diag_ui.setupUi(diag)
        if self.data:
            try:
                raw = self.data[self.current_row]['bin']
                header = self.data[self.current_row]['header']
                diag_ui.setPacketInfo('{}({},{})  {}'.format(
                    header['TMTC'], header['service_type'],
                    header['service_subtype'], header['DESCR']))
                diag_ui.displayRaw(raw)
            except (IndexError, KeyError):
                diag_ui.setText('Raw data not available.')
        diag.exec_()

    def onOnlineHelpTriggered(self):
        webbrowser.open('https://github.com/i4Ds/STIX-dataviewer', new=2)

    def onPluginTriggered(self):
        self.plugin_location = self.settings.value('plugin_location', [], str)
        diag = QtWidgets.QDialog()
        diag_ui = plugin.Ui_Dialog()
        diag_ui.setupUi(diag)
        if self.plugin_location:
            diag_ui.setPluginLocation(self.plugin_location)

        diag_ui.setData(self.data, self.current_row)
        diag.exec_()
        location = diag_ui.getPluginLocation()
        if location != self.plugin_location:
            self.settings.setValue('plugin_location', location)

    def onPacketFilterTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = packet_filter.Ui_Dialog()
        diag_ui.setupUi(diag)
        diag_ui.setSelectedServices(self.selected_services)
        diag_ui.buttonBox.accepted.connect(
            partial(self.applyServiceFilter, diag_ui))
        diag.exec_()

    def applyServiceFilter(self, diag_ui):
        self.selected_SPID = diag_ui.getSelectedSPID()
        self.selected_services = diag_ui.getSelectedServices()
        self.showMessage('Applying filter...')

        self.addPacketsToView(self.data, True, show_stat=False)

    def onExportButtonClicked(self):
        if self.y:
            filename = str(
                QtWidgets.QFileDialog.getSaveFileName(None,
                                                      "Save data to file", "",
                                                      "CSV(*.csv)")[0])
            if filename:
                with open(filename, 'w') as f:
                    f.write('{},{}\n'.format(self.xlabel, self.ylabel))
                    for xx, yy in zip(self.x, self.y):
                        f.write('{},{}\n'.format(xx, yy))
                    self.showMessage(
                        'The data has been written to {}'.format(filename))
        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('Plot first!')
            msgBox.setWindowTitle("Warning")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def savePlot(self):
        # if self.figure.get_axes():
        if self.chart:
            filetypes = "PNG (*.png);;JPEG (*.jpg)"
            filename = str(
                QtWidgets.QFileDialog.getSaveFileName(None,
                                                      "Save plot to file", "",
                                                      filetypes)[0])
            if filename:
                if not filename.endswith(('.png', '.jpg')):
                    filename += '.png'
                # self.figure.savefig(filename)
                p = self.chartView.grab()
                p.save(filename)
                self.showMessage(('Saved to %s.' % filename))

        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('No figure to save')
            msgBox.setWindowTitle("STIX raw data viewer")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def onCopyTriggered(self):
        packet_id = self.current_row
        try:
            packet = self.data[packet_id]
            ss = pprint.pformat(packet)
            cb = QtWidgets.QApplication.clipboard()
            cb.clear(mode=cb.Clipboard)
            cb.setText(ss, mode=cb.Clipboard)
            msg = QtWidgets.QMessageBox()
            msg.setIcon(QtWidgets.QMessageBox.Information)
            msg.setText(
                "The data of the selected packet has been copied to the clipboard."
            )
            msg.setWindowTitle("Information")
            msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
            retval = msg.exec_()

        except Exception as e:
            self.showMessage(str(e), 0)

    def onPasteTriggered(self):
        raw_hex = QtWidgets.QApplication.clipboard().text()
        if len(raw_hex) < 16:
            self.showMessage('No data in the clipboard.')
            return
        data_hex = re.sub(r"\s+", "", raw_hex)
        try:
            data_binary = binascii.unhexlify(data_hex)
            packets = self.stix_tctm_parser.parse_binary(data_binary,
                                                         0,
                                                         store_binary=True)
            if not packets:
                return
            self.showMessage('%d packets read from the clipboard' %
                             len(packets))
            self.onDataReady(packets, clear=False, show_stat=False)
        except Exception as e:
            self.showMessageBox(str(e), data_hex)

    def showMessageBox(self, message, content):
        msg = QtWidgets.QMessageBox()
        msg.setIcon(QtWidgets.QMessageBox.Critical)
        msg.setText("Error")
        msg.setInformativeText(message)
        msg.setWindowTitle("Error")
        msg.setDetailedText(content)
        msg.setStandardButtons(QtWidgets.QMessageBox.Ok
                               | QtWidgets.QMessageBox.Cancel)
        retval = msg.exec_()

    def showMessage(self, msg, where=0):
        if where != 1:
            self.statusbar.showMessage(msg)
        if where != 0:
            self.statusListWidget.addItem(msg)
        # if destination !=0 :
        #    self.listWidget_2.addItem(msg)

    def onSetIDBClicked(self):
        self.idb_filename = QtWidgets.QFileDialog.getOpenFileName(
            None, 'Select file', '.', 'IDB file(*.db *.sqlite *.sqlite3)')[0]

        if not self.idb_filename:
            return

        idb._stix_idb.reload(self.idb_filename)
        if idb._stix_idb.is_connected():
            #settings = QtCore.QSettings('FHNW', 'stix_parser')
            self.settings.setValue('idb_filename', self.idb_filename)
        self.showMessage(
            'IDB location: {} '.format(idb._stix_idb.get_idb_filename()), 1)

    def save(self):
        filetypes = 'python compressed pickle (*.pklz);; python pickle file (*.pkl);; binary data (*.dat)'
        self.output_filename = str(
            QtWidgets.QFileDialog.getSaveFileName(None, "Save packets to", "",
                                                  filetypes)[0])

        if not self.output_filename.endswith(('.pklz', '.pkl', '.dat')):
            msg = 'unsupported file format !'
            self.showMessage(msg)
            return

        msg = 'Writing data to file %s' % self.output_filename
        self.showMessage(msg)

        if self.output_filename.endswith(('.pklz', '.pkl')):
            stw = stix_writer.StixPickleWriter(self.output_filename)
            stw.register_run(str(self.input_filename))
            stw.write_all(self.data)
            #stw.done()
        elif self.output_filename.endswith('.dat'):
            stw = stix_writer.StixBinaryWriter(self.output_filename)
            stw.write_all(self.data)
            num_ok = stw.get_num_sucess()
            msg = (
                'The binary data of {} packets written to file {}, total packets {}'
                .format(num_ok, self.output_filename, len(self.data)))
            self.showMessage(msg)

    def setListViewSelected(self, row):
        #index = self.model.createIndex(row, 0);
        # if index.isValid():
        #    self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select)
        pass

    def about(self):
        msgBox = QtWidgets.QMessageBox()
        msgBox.setIcon(QtWidgets.QMessageBox.Information)
        msgBox.setText("STIX raw data parser and viewer, [email protected]")
        msgBox.setWindowTitle("Stix data viewer")

        msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
        msgBox.exec_()

    def nextPacket(self):
        self.current_row += 1
        length = len(self.data)

        if self.current_row >= length:
            self.current_row = length - 1
            self.showMessage('No more packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def previousPacket(self):
        self.current_row -= 1
        if self.current_row < 0:
            self.current_row = 0
            self.showMessage('Reach the first packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def getOpenFilename(self):
        filetypes = (
            'STIX raw data(*.dat *.bin *.binary);; python pickle files (*.pkl *pklz);;'
            'ESA xml files (*xml);;'
            'ESA ascii files(*.ascii);; CMDVS archive files (*.BDF);; All(*)')
        self.input_filename = QtWidgets.QFileDialog.getOpenFileName(
            None, 'Select file', '.', filetypes)[0]
        if not self.input_filename:
            return
        self.openFile(self.input_filename)

    def openFile(self, filename):
        self.packetTreeWidget.clear()
        msg = 'Loading file %s ...' % filename
        self.showMessage(msg)
        self.dataReader = StixFileReader(filename)
        #self.dataReader.dataLoaded.connect(self.onDataReady)
        self.dataReader.packetArrival.connect(self.onPacketArrival)
        self.dataReader.error.connect(self.onDataReaderError)
        self.dataReader.info.connect(self.onDataReaderInfo)
        self.dataReader.warn.connect(self.onDataReaderWarn)
        self.dataReader.start()

    def onDataReaderInfo(self, msg):
        self.showMessage(msg, 0)

    def onDataReaderWarn(self, msg):
        self.showMessage(msg, 1)

    def onDataReaderError(self, msg):
        self.showMessage(msg, 1)

    def onDataReady(self, data, clear=True, show_stat=True):
        if not clear:
            self.data.extend(data)
        else:
            self.data = data
        if data:
            self.addPacketsToView(data, clear=clear, show_stat=show_stat)
            self.enableButtons()

    def enableButtons(self):
        if not self.buttons_enabled:
            self.actionPrevious.setEnabled(True)
            self.actionNext.setEnabled(True)
            self.actionSave.setEnabled(True)
            self.actionCopy.setEnabled(True)
            self.actionPlot.setEnabled(True)
            self.actionViewBinary.setEnabled(True)
            self.buttons_enabled = True

    def addPacketsToView(self, data, clear=True, show_stat=True):
        if clear:
            self.packetTreeWidget.clear()
        #t0 = 0
        for p in data:
            if type(p) is not dict:
                continue
            header = p['header']

            root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget)
            # if t0 == 0:
            #    t0 = header['time']
            timestamp_str = ''
            try:
                timestamp_str = header['utc']
            except KeyError:
                timestamp_str = '{:.2f}'.format(header['time'])
                #- t0)

            root.setText(0, timestamp_str)
            root.setText(
                1,
                '{}({},{}) - {}'.format(header['TMTC'], header['service_type'],
                                        header['service_subtype'],
                                        header['DESCR']))

            if not self.selected_SPID:
                #not set then apply service
                if header['service_type'] not in self.selected_services:
                    root.setHidden(True)
            else:
                if header['SPID'] not in self.selected_SPID:
                    root.setHidden(True)

        if show_stat:
            total_packets = len(self.data)
            self.showMessage(('Total packet(s): %d' % total_packets))

    def onConnectTSCTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = tsc_connection.Ui_Dialog()
        diag_ui.setupUi(diag)
        self.tsc_host = self.settings.value('tsc_host', [], str)
        self.tsc_port = self.settings.value('tsc_port', [], str)
        if self.tsc_host:
            diag_ui.serverLineEdit.setText(self.tsc_host)
        if self.tsc_port:
            diag_ui.portLineEdit.setText(self.tsc_port)
        diag_ui.buttonBox.accepted.connect(partial(self.connectToTSC, diag_ui))
        diag.exec_()

    def connectToTSC(self, dui):
        host = dui.serverLineEdit.text()
        port = dui.portLineEdit.text()
        self.showMessage('Connecting to TSC...')
        self.socketPacketReceiver = StixSocketPacketReceiver(host, int(port))
        self.socketPacketReceiver.packetArrival.connect(self.onPacketArrival)
        self.socketPacketReceiver.error.connect(self.onDataReaderError)
        self.socketPacketReceiver.info.connect(self.onDataReaderInfo)
        self.socketPacketReceiver.warn.connect(self.onDataReaderWarn)
        self.socketPacketReceiver.start()

    def onPacketArrival(self, packets):
        if packets:
            self.onDataReady(packets, clear=False, show_stat=True)

    def onLoadMongoDBTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = mongo_dialog.Ui_Dialog()
        diag_ui.setupUi(diag)
        #self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.mongo_server = self.settings.value('mongo_server', [], str)
        self.mongo_port = self.settings.value('mongo_port', [], str)
        self.mongo_user = self.settings.value('mongo_user', [], str)
        self.mongo_pwd = self.settings.value('mongo_pwd', [], str)

        if self.mongo_server:
            diag_ui.serverLineEdit.setText(self.mongo_server)
        if self.mongo_port:
            diag_ui.portLineEdit.setText(self.mongo_port)

        if self.mongo_user:
            diag_ui.userLineEdit.setText(self.mongo_user)
        if self.mongo_pwd:
            diag_ui.pwdLineEdit.setText(self.mongo_pwd)

        diag_ui.pushButton.clicked.connect(
            partial(self.loadRunsFromMongoDB, diag_ui))
        diag_ui.buttonBox.accepted.connect(
            partial(self.loadDataFromMongoDB, diag_ui, diag))
        diag.exec_()

    def loadRunsFromMongoDB(self, dui):
        server = dui.serverLineEdit.text()
        port = dui.portLineEdit.text()
        user = dui.userLineEdit.text()
        pwd = dui.pwdLineEdit.text()

        self.showMessage('saving setting...')
        if self.mongo_server != server:
            self.settings.setValue('mongo_server', server)
        if self.mongo_port != port:
            self.settings.setValue('mongo_port', port)

        if self.mongo_user != user:
            self.settings.setValue('mongo_user', user)
        if self.mongo_pwd != pwd:
            self.settings.setValue('mongo_pwd', pwd)

        self.showMessage('connecting Mongo database ...')
        self.mdb = mgdb.MongoDB(server, int(port), user, pwd)
        if not self.mdb.is_connected():
            return

        dui.treeWidget.clear()
        self.showMessage('Fetching data...')
        for run in self.mdb.get_runs():
            root = QtWidgets.QTreeWidgetItem(dui.treeWidget)
            root.setText(0, str(run['_id']))
            root.setText(1, run['filename'])
            root.setText(2, run['date'])
            root.setText(3, str(run['start']))
            root.setText(4, str(run['end']))

    def loadDataFromMongoDB(self, dui, diag):
        self.showMessage('Loading packets ...')
        selected_runs = []
        for item in dui.treeWidget.selectedItems():
            selected_runs.append(item.text(0))
        if not selected_runs:
            self.showMessage('Run not selected!')
        if selected_runs:
            diag.done(0)
            self.showMessage('Loading data ...!')
            data = self.mdb.get_packets(selected_runs[0])
            if data:
                self.onDataReady(data, clear=True)
            else:
                self.showMessage('No packets found!')
        # close

    def onPacketSelected(self, cur, pre):
        self.current_row = self.packetTreeWidget.currentIndex().row()
        self.showMessage(('Packet #%d selected' % self.current_row))
        self.showPacket(self.current_row)

    def showPacket(self, row):
        if not self.data:
            return
        header = self.data[row]['header']
        total_packets = len(self.data)
        self.showMessage(
            ('Packet %d / %d  %s ' % (row, total_packets, header['DESCR'])))
        self.paramTreeWidget.clear()
        header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        header_root.setText(0, "Header")
        rows = len(header)
        for key, val in header.items():
            root = QtWidgets.QTreeWidgetItem(header_root)
            root.setText(0, key)
            root.setText(1, str(val))

        params = self.data[row]['parameters']
        param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        param_root.setText(0, "Parameters")
        self.showParameterTree(params, param_root)
        self.paramTreeWidget.expandItem(param_root)
        self.paramTreeWidget.expandItem(header_root)
        self.current_row = row

    def showParameterTree(self, params, parent):
        if not params:
            return
        for p in params:
            root = QtWidgets.QTreeWidgetItem(parent)
            if not p:
                continue
            try:
                param_name = p['name']
                desc = ''  #description of parameter
                if 'desc' in p:
                    desc = p['desc']
                if not desc:
                    desc = idb._stix_idb.get_PCF_description(param_name)
                scos_desc = idb._stix_idb.get_scos_description(param_name)
                if scos_desc:
                    root.setToolTip(1, scos_desc)
                root.setText(0, param_name)
                root.setText(1, desc)
                root.setText(2, str(p['raw']))
                try:
                    root.setToolTip(2, hex(p['raw'][0]))
                except:
                    pass
                root.setText(3, str(p['eng']))
                if 'children' in p:
                    if p['children']:
                        self.showParameterTree(p['children'], root)
            except KeyError:
                self.showMessage(
                    '[Error  ]: keyError occurred when adding parameter')
        self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked)

    def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0):
        if not params:
            return
        timestamp = header['time']
        for p in params:
            if type(p) is not dict:
                continue
            if name == p['name']:
                values = None
                #print('data type:{}'.format(data_type))
                if data_type == 0:
                    values = p['raw']
                else:
                    values = p['eng']
                try:
                    yvalue = None
                    if (type(values) is tuple) or (type(values) is list):
                        yvalue = float(values[0])
                    else:
                        yvalue = float(values)
                    ret_y.append(yvalue)
                    if xaxis == 1:
                        ret_x.append(timestamp)
                    else:
                        self.showMessage(('Can not plot %s  ' % str(yvalue)))
                except Exception as e:
                    self.showMessage(('%s ' % str(e)))

            if 'children' in p:
                if p['children']:
                    self.walk(name, p['children'], header, ret_x, ret_y, xaxis,
                              data_type)

    def onPlotButtonClicked(self):
        if self.chart:
            self.chart.removeAllSeries()
        if not self.data:
            return
        self.showMessage('Preparing plot ...')
        name = self.paramNameEdit.text()
        packet_selection = self.comboBox.currentIndex()
        xaxis_type = self.xaxisComboBox.currentIndex()
        data_type = self.dataTypeComboBox.currentIndex()

        timestamp = []
        self.y = []
        packet_id = self.current_row
        params = self.data[packet_id]['parameters']
        header = self.data[packet_id]['header']
        current_spid = header['SPID']
        if packet_selection == 0:
            self.walk(name, params, header, timestamp, self.y, xaxis_type,
                      data_type)
        elif packet_selection == 1:
            for packet in self.data:
                header = packet['header']
                if packet['header']['SPID'] != current_spid:
                    continue
                params = packet['parameters']
                self.walk(name, params, header, timestamp, self.y, xaxis_type,
                          data_type)

        self.x = []

        if not self.y:
            self.showMessage('No data points')
        elif self.y:
            style = self.styleEdit.text()
            if not style:
                style = '-'
            title = '%s' % str(name)
            desc = self.descLabel.text()
            if desc:
                title += '- %s' % desc

            self.chart.setTitle(title)

            ylabel = 'Raw value'
            xlabel = name
            if data_type == 1:
                ylabel = 'Engineering  value'
            if xaxis_type == 0:
                if packet_selection == 1:
                    xlabel = "Packet #"
                else:
                    xlabel = "Repeat #"
                self.x = range(0, len(self.y))
            if xaxis_type == 1:
                self.x = [t - timestamp[0] for t in timestamp]
                xlabel = 'Time -T0 (s)'

            if xaxis_type != 2:
                series = QLineSeries()
                series2 = None
                for xx, yy in zip(self.x, self.y):
                    series.append(xx, yy)
                if 'o' in style:
                    series2 = QScatterSeries()
                    for xx, yy in zip(self.x, self.y):
                        series2.append(xx, yy)
                    self.chart.addSeries(series2)
                self.chart.addSeries(series)
                axisX = QValueAxis()
                axisX.setTitleText(xlabel)
                axisY = QValueAxis()
                axisY.setTitleText(ylabel)

                self.chart.setAxisX(axisX)
                self.chart.setAxisY(axisY)
                series.attachAxis(axisX)
                series.attachAxis(axisY)
            else:
                nbins = len(set(self.y))
                ycounts, xedges = np.histogram(self.y, bins=nbins)
                series = QLineSeries()
                for i in range(0, nbins):
                    meanx = (xedges[i] + xedges[i + 1]) / 2.
                    series.append(meanx, ycounts[i])
                self.chart.addSeries(series)
                axisX = QValueAxis()
                axisX.setTitleText(name)
                axisY = QValueAxis()
                axisY.setTitleText("Counts")

                self.chart.setAxisY(axisY)
                self.chart.setAxisX(axisX)
                series.attachAxis(axisX)
                series.attachAxis(axisY)

            self.xlabel = xlabel
            self.ylabel = ylabel
            self.chartView.setRubberBand(QChartView.RectangleRubberBand)
            self.chartView.setRenderHint(QtGui.QPainter.Antialiasing)
            msg = 'Y length: {}, min-Y:  {}, max-Y: {}'.format(
                len(self.y), min(self.y), max(self.y))

            self.showMessage(msg, 1)

            self.showMessage('The canvas updated!')

    def plotParameter(self, name=None, desc=None):
        self.tabWidget.setCurrentIndex(1)
        if name:
            self.paramNameEdit.setText(name)
        if desc:
            self.descLabel.setText(desc)

    def onPlotActionClicked(self):
        self.tabWidget.setCurrentIndex(1)
        self.plotParameter()

    def onTreeItemClicked(self, it, col):
        self.plotParameter(it.text(0), it.text(1))