Commit f086be69 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Work on ASN.1 Value Editor <-> SQL DB

parent b9dea3f1
......@@ -23,14 +23,14 @@ import sys
import os
import importlib
from PySide.QtCore import (QObject, Signal, Slot, Qt, QRectF, QPointF, QPoint)
from PySide.QtGui import QDockWidget
from PySide.QtCore import (QObject, Signal, Slot, Qt)
import PySide.QtGui as QtGui
# User must list explicitly the classes he wants to expose to the GUI:
__all__ = ['SQLTelecommands', 'SQLTelemetries']
class TM(QDockWidget, QObject):
class TM(QtGui.QDockWidget, QObject):
''' Subclasses of TM will receive ASN.1 data from the GUI whenever a
value is updated (through a Qt slot)
'''
......@@ -40,6 +40,8 @@ class TM(QDockWidget, QObject):
def __init__(self, unused_asn1_type=None, parent=None):
''' Initialisation of the Widget '''
super(TM, self).__init__(parent)
self.setObjectName(self.name)
self.show()
@staticmethod
def applicable():
......@@ -52,7 +54,7 @@ class TM(QDockWidget, QObject):
pass
class TC(QDockWidget, QObject):
class TC(QtGui.QDockWidget, QObject):
''' Subclasses of TC can be used to provide ASN.1 data to the main GUI
and to automatically send it to the application.
Example of uses: Buttons, SQL interface...
......@@ -66,6 +68,8 @@ class TC(QDockWidget, QObject):
def __init__(self, unused_asn1_type=None, parent=None):
''' Initialisation of the Widget '''
super(TC, self).__init__(parent)
self.setObjectName(self.name)
self.show()
def connect_to_db():
......@@ -97,9 +101,10 @@ class SQLTelecommands(TC):
session = None
dbname = None
def __init__(self, asn1_typename, parent=None):
def __init__(self, asn1_typename, parent):
''' Initialise the widget '''
super(SQLTelecommands, self).__init__(asn1_typename, parent)
print 'Creating instance of SQLTelecommands'
if SQLTelecommands.session is None:
SQLTelecommands.session, SQLTelecommands.dbname = \
connect_to_db()
......@@ -108,6 +113,13 @@ class SQLTelecommands(TC):
self._asn1_klass = getattr(db_module, typename_sql, None)
if self._asn1_klass is None:
print "No class", typename_sql, "found in", SQLTelecommands.dbname
self.widget = QtGui.QListWidget()
# Get the first 50 entries in the database
self.widget.addItems([str(x) for x in self.getPageIndexes(0, 50)])
self.widget.itemClicked.connect(self.select)
self.setWidget(self.widget)
# parent is the ASN.1 value editor
self.parent = parent
@staticmethod
def applicable():
......@@ -126,6 +138,14 @@ class SQLTelecommands(TC):
)
]
def select(self, item):
''' Called when user clicks on a line of the table '''
# Get the ASN.1 value from the database (in native an1scc format)
native_asn1scc = self.sql2asn1(item.text())
# native_asn1scc.PrintAll() available
python_var = self.parent.backend.fromASN1ToPyside(native_asn1scc)
self.parent.tmToEditor(python_var)
def sql2asn1(self, idx):
row = SQLTelecommands.session.query(
self._asn1_klass
......@@ -159,14 +179,22 @@ class SQLTelemetries(TM):
def __init__(self, parent=None):
''' Initialise the widget '''
super(SQLTelemetries, self).__init__(parent)
print 'Creating instance of SQLTelemetries'
# to do here = display a window with two buttons:
# "start storing in DB", "stop storing in DB"
self.mode = 'recording'
if SQLTelemetries.session is None:
SQLTelemetries.session, SQLTelemetries.dbname = \
connect_to_db()
self.hide()
@Slot()
def new_tm(self):
''' Slot called when a TM has been received in the editor '''
# Nothing to do, the update() function does nothing thread-related
# that would need to be done here
print 'Recorded a new TM in the database'
def update(self, value):
''' Receive ASN.1 value '''
if self.mode == 'recording':
......
......@@ -203,6 +203,8 @@ class asn1Editor(QTreeView):
expandBranch = Signal(QModelIndex)
statusBarMessage = Signal(str)
msc = Signal(unicode, unicode)
# Whenever a new TM is received, the new_tm signal is emitted
new_tm = Signal()
def __init__(self, parent=None):
super(asn1Editor, self).__init__(parent)
......@@ -231,6 +233,10 @@ class asn1Editor(QTreeView):
self.plottedIdxs = []
self.log = None
self.pendingTM = None
# item is the ASN.1 node in Pyside format from datamodel.py
self.item = None
# List of classes that have an "update" method (user custom widgets)
self.tm_clients = []
def hideExtraColumns(self):
''' Hide the columns containing the type and constraint '''
......@@ -471,14 +477,18 @@ class asn1Editor(QTreeView):
msg = name + '(' + asnVN + ')'
self.log.debug('Emitting input to MSC') # + msg)
self.msc.emit('in', msg)
self.new_tm.emit()
self.log.debug("Leaving tmToEditor")
def ProcessTM(self, rawMsg):
''' Decode a TM received from the msgQ (not UDP) and update the model '''
''' Decode a TM received from the msgQ (not UDP)
and update the model '''
self.log.debug("Entering ProcessTM")
native_tm = self.backend.decode_TM(rawMsg)
pythonVar = self.backend.fromASN1ToPyside(native_tm)
self.tmToEditor(pythonVar)
for each in self.tm_clients:
each.update(native_tm)
self.log.debug("Leaving ProcessTM")
@Slot()
......@@ -650,11 +660,22 @@ class asn1Editor(QTreeView):
''' Create speedometers for the selected values '''
self.newPlot(meter=True)
def custom(self, custom_class):
''' Handle user-defined widgets: for TC, provide access to the Send
and Update APIs. Defined differently for the asn1Viwer (TM) class '''
custom_handler = custom_class(self.item['nodeTypename']
.replace('-', '_'), parent=self)
# Attach the docking widget to the GUI (XXX refactor)
self.parent().parent().parent().addDockWidget(Qt.RightDockWidgetArea,
custom_handler)
custom_handler.setFloating(True)
def displaytip(self, index):
''' Display a tip when the mouse moves above a cell '''
asnType = index.sibling(index.row(), 1).data()
constraint = index.sibling(index.row(), 2).data()
self.statusBarMessage.emit(asnType + ' ' + (constraint if constraint is not None else ''))
self.statusBarMessage.emit(asnType + ' ' +
(constraint if constraint is not None else ''))
@Slot(QModelIndex, int, int)
def seqofDisplay(self, parent, val, max):
......@@ -857,3 +878,14 @@ class asn1Viewer(asn1Editor):
def __init__(self, parent=None):
super(asn1Viewer, self).__init__(parent)
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
def custom(self, custom_class):
''' Handle user-defined widgets: for TM make sure a signal is emitted
with ASN1 value when a TM is received '''
custom_handler = custom_class(parent=self)
# Attach the docking widget to the GUI (XXX refactor)
self.parent().parent().parent().addDockWidget(Qt.RightDockWidgetArea,
custom_handler)
self.tm_clients.append(custom_handler)
self.new_tm.connect(custom_handler.new_tm)
custom_handler.setFloating(True)
......@@ -44,6 +44,8 @@ from asn1_value_editor import asn1Editor, asn1Viewer, __version__
from plotmanager import PlotManager
import vn
import UserWidgets
try:
import speedometer
except ImportError:
......@@ -71,8 +73,7 @@ from sdlHandler import sdlHandler
from PySide.QtCore import QThread, QFile, Qt, Signal, QObject
from PySide.QtGui import(QApplication, QStatusBar, QLabel, QWidget,
QListWidget, QPushButton, QDockWidget, QTabWidget, QMenu, QAction,
QComboBox)
QListWidget, QPushButton, QDockWidget, QTabWidget, QMenu, QAction)
from PySide.QtUiTools import QUiLoader
......@@ -395,16 +396,15 @@ def gui():
editor.log = log
dockWidget = editor.parent()
myButtons = dockWidget.findChildren(QPushButton)
customBtn = dockWidget.findChild(QComboBox, "customCombo")
# retrieve user widgets for TM and TC
customTC, customTM = [], []
# for each in UserWidgets.__all__:
# widget = getattr(UserWidget, each)
# if widget.__base__ == UserWidget.TC:
# customTC.append(widget)
# elif widget.__base__ == UserWidget.TM:
# customTM.append(widget)
for each in UserWidgets.__all__:
widget = getattr(UserWidgets, each)
if widget.__base__ == UserWidgets.TC and widget.applicable():
customTC.append(widget)
elif widget.__base__ == UserWidgets.TM and widget.applicable():
customTM.append(widget)
if isinstance(editor, asn1Viewer): # TM Viewer
hasTM = True
......@@ -421,9 +421,19 @@ def gui():
plotter.addPlotMenu(myMenu, editor)
elif button.objectName() == 'meterButton':
button.clicked.connect(editor.meter)
elif button.objectName() == 'customCombo':
if not customTM:
continue
myMenu = QMenu()
for each in customTM:
action = QAction(each.name, myMenu)
myMenu.addAction(action)
action.triggered.connect(partial(editor.custom,
each))
button.setMenu(myMenu)
else:
button.hide()
# button.clicked.connect(editor.unmeter)
else: # TC Editor
editor.setAsn1Model(datamodel.tc[editor.objectName()])
if not msgQ:
......@@ -440,6 +450,19 @@ def gui():
editor.objectName(),
'editor': editor,
'send_btn': button})
elif button.objectName() == 'customCombo':
if not customTC:
button.hide()
myMenu = QMenu()
for each in customTC:
action = QAction(each.name, myMenu)
myMenu.addAction(action)
action.triggered.connect(partial(editor.custom,
each))
button.setMenu(myMenu)
button.menu() # Seems there is a refresh issue without that
else:
button.hide()
# Create a thread to poll the message queue or open an UDP socket
if msgQ:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment