Skip to content

Commit

Permalink
Merge pull request #7 from TUB-Control/release2
Browse files Browse the repository at this point in the history
Release v.0.8
  • Loading branch information
StefanBerlin committed Dec 15, 2014
2 parents 3bd2781 + 00fa01c commit d2455c0
Show file tree
Hide file tree
Showing 25 changed files with 600 additions and 128 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,18 @@ Documentation
Sphinx doc on GitHub: https://tub-control.github.io/PaPI/

PaPI wiki on GitHub: https://github.com/TUB-Control/PaPI/wiki


Changelog
------

v.0.8
---

* Use plugin as wizards for configurations
* Use ESC and RETURN for window interaction
* New file dialog to avoid performance issues
* [fix] signal names instead of id in overview
* Run/Edit mode
* Set/load backgorund and save it to config
* [fix] When plugin in gui crashs, gui stays alive and plugin will be stopped
Binary file added bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions cfg_collection/bgtest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<PaPiConfig Date="2014-12-15 17:53:33" PaPI_version="v_0.6">
<Size h="800" w="800" />
<Background image="/home/control/PycharmProjects/PaPI/bg.png" />
</PaPiConfig>
29 changes: 29 additions & 0 deletions cfg_collection/wizard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<PaPiConfig Date="2014-12-15 14:47:35" PaPI_version="v_0.6">
<Size h="800" w="800" />
<Plugin uname="WizardExample">
<Identifier>WizardExample</Identifier>
<StartConfig>
<Parameter Name="uname">
<value>WizardExample</value>
</Parameter>
<Parameter Name="size">
<value>(300,300)</value>
<regex>\(([0-9]+),([0-9]+)\)</regex>
<tooltip>Determine size: (height,width)</tooltip>
<advanced>1</advanced>
</Parameter>
<Parameter Name="position">
<value>(0,0)</value>
<regex>\(([0-9]+),([0-9]+)\)</regex>
<tooltip>Determine position: (x,y)</tooltip>
<advanced>1</advanced>
</Parameter>
<Parameter Name="name">
<value>VisualPlugin</value>
<tooltip>Used display name</tooltip>
</Parameter>
</StartConfig>
<PreviousParameters />
<Subscriptions />
</Plugin>
</PaPiConfig>
2 changes: 2 additions & 0 deletions papi/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@
PLUGIN_API_CONSOLE_LOG_LEVEL = 1

# CONFIG/PROFILE SYSTEM CONSTANTS

CONFIG_DEFAULT_DIRECTORY = 'cfg_collection/'
CONFIG_DEFAULT_FILE = 'cfg_collection/testcfg.xml'
CONFIG_ROOT_ELEMENT_NAME = 'PaPiConfig' # for xml save
CONFIG_LOADER_SUBCRIBE_DELAY = 1000 # ms
81 changes: 46 additions & 35 deletions papi/gui/gui_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
class Gui_api(QtCore.QObject):

resize_gui = QtCore.Signal(int, int)
set_bg_gui = QtCore.Signal(str)


def __init__(self, gui_data, core_queue, gui_id, LOG_IDENT = GUI_PROCESS_CONSOLE_IDENTIFIER):
super(Gui_api, self).__init__()
Expand All @@ -57,6 +59,7 @@ def __init__(self, gui_data, core_queue, gui_id, LOG_IDENT = GUI_PROCESS_CONSOLE
self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL, LOG_IDENT)
self.gui_size_width = None
self.gui_size_height = None
self.gui_bg_path = None



Expand Down Expand Up @@ -452,43 +455,48 @@ def do_load_xml(self, path):
h = int(plugin_xml.attrib['h'])
self.resize_gui.emit(w,h)
else:
pl_uname = plugin_xml.attrib['uname']
identifier = plugin_xml.find('Identifier').text
config_xml = plugin_xml.find('StartConfig')
config_hash = {}
for parameter_xml in config_xml.findall('Parameter'):
para_name = parameter_xml.attrib['Name']
config_hash[para_name] = {}
for detail_xml in parameter_xml:
detail_name = detail_xml.tag
config_hash[para_name][detail_name]= detail_xml.text

pl_uname_new = self.change_uname_to_uniqe(pl_uname)

plugins_to_start.append([identifier, pl_uname_new, config_hash])

subs_xml = plugin_xml.find('Subscriptions')
for sub_xml in subs_xml.findall('Subscription'):
data_source = sub_xml.find('data_source').text
for block_xml in sub_xml.findall('block'):
block_name = block_xml.attrib['Name']
signals = []
for sig_xml in block_xml.findall('Signal'):
signals.append(int(sig_xml.text))
alias_xml = block_xml.find('alias')
alias = alias_xml.text
pl_uname_new = self.change_uname_to_uniqe(pl_uname)
data_source_new = self.change_uname_to_uniqe(data_source)
subs_to_make.append([pl_uname_new,data_source_new,block_name,signals, alias])

if plugin_xml.tag == 'Background':
path = str(plugin_xml.attrib['image'])
if path != '' and path is not None and path !='default':
self.set_bg_gui.emit(path)
else:
pl_uname = plugin_xml.attrib['uname']
identifier = plugin_xml.find('Identifier').text
config_xml = plugin_xml.find('StartConfig')
config_hash = {}
for parameter_xml in config_xml.findall('Parameter'):
para_name = parameter_xml.attrib['Name']
config_hash[para_name] = {}
for detail_xml in parameter_xml:
detail_name = detail_xml.tag
config_hash[para_name][detail_name]= detail_xml.text

prev_parameters_xml = plugin_xml.find('PreviousParameters')
for prev_parameter_xml in prev_parameters_xml.findall('Parameter'):
para_name = prev_parameter_xml.attrib['Name']
para_value = prev_parameter_xml.text
pl_uname_new = self.change_uname_to_uniqe(pl_uname)
# TODO validate NO FLOAT in parameter
parameters_to_change.append([pl_uname_new, para_name, para_value])

plugins_to_start.append([identifier, pl_uname_new, config_hash])

subs_xml = plugin_xml.find('Subscriptions')
for sub_xml in subs_xml.findall('Subscription'):
data_source = sub_xml.find('data_source').text
for block_xml in sub_xml.findall('block'):
block_name = block_xml.attrib['Name']
signals = []
for sig_xml in block_xml.findall('Signal'):
signals.append(int(sig_xml.text))
alias_xml = block_xml.find('alias')
alias = alias_xml.text
pl_uname_new = self.change_uname_to_uniqe(pl_uname)
data_source_new = self.change_uname_to_uniqe(data_source)
subs_to_make.append([pl_uname_new,data_source_new,block_name,signals, alias])


prev_parameters_xml = plugin_xml.find('PreviousParameters')
for prev_parameter_xml in prev_parameters_xml.findall('Parameter'):
para_name = prev_parameter_xml.attrib['Name']
para_value = prev_parameter_xml.text
pl_uname_new = self.change_uname_to_uniqe(pl_uname)
# TODO validate NO FLOAT in parameter
parameters_to_change.append([pl_uname_new, para_name, para_value])

for pl in plugins_to_start:
# 0: ident, 1: uname, 2: config
Expand Down Expand Up @@ -530,6 +538,9 @@ def do_save_xml_config(self, path):
size_xml.set('w',str(self.gui_size_width))
size_xml.set('h',str(self.gui_size_height))

bg_xml = ET.SubElement(root, 'Background')
bg_xml.set('image',str(self.gui_bg_path))

# get plugins #
plugins = self.gui_data.get_all_plugins()
for dplugin_id in plugins:
Expand Down
71 changes: 50 additions & 21 deletions papi/gui/gui_event_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
PLUGIN_STATE_START_FAILED

import copy
import traceback

from papi.gui.plugin_api import Plugin_api

Expand Down Expand Up @@ -59,6 +60,7 @@ class GuiEventProcessing(QtCore.QObject):
added_dplugin = QtCore.Signal(DPlugin)
removed_dplugin = QtCore.Signal(DPlugin)
dgui_changed = QtCore.Signal()
plugin_died = QtCore.Signal(DPlugin, Exception, str)

def __init__(self, gui_data, core_queue, gui_id, gui_queue):
super(GuiEventProcessing, self).__init__()
Expand Down Expand Up @@ -119,7 +121,6 @@ def gui_working(self, close_mock):
else:
self.process_event[op](event)


# after the loop ended, which means that there are no more new events, a new timer will be created to start
# this method again in a specific time
QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_working(close_mock))
Expand Down Expand Up @@ -148,10 +149,16 @@ def process_new_data_event(self, event):
# it exists, so call its execute function, but just if it is not paused ( no data delivery when paused )
if dplugin.state != PLUGIN_STATE_PAUSE and dplugin.state != PLUGIN_STATE_STOPPED:
# check if new_data is a parameter or new raw data
if opt.is_parameter is False:
dplugin.plugin.execute(dplugin.plugin.demux(opt.data_source_id, opt.block_name, opt.data))
else:
dplugin.plugin.set_parameter_internal(opt.parameter_alias, opt.data)
try:
if opt.is_parameter is False:
dplugin.plugin.execute(dplugin.plugin.demux(opt.data_source_id, opt.block_name, opt.data))
else:
dplugin.plugin.set_parameter_internal(opt.parameter_alias, opt.data)
except Exception as E:
tb = traceback.format_exc()

self.plugin_died.emit(dplugin, E, tb)

else:
# plugin does not exist in DGUI
self.log.printText(1,'new_data, Plugin with id '+str(dID)+' does not exist in DGui')
Expand All @@ -170,7 +177,11 @@ def process_plugin_closed(self, event):
dplugin = self.gui_data.get_dplugin_by_id(opt.plugin_id)
if dplugin is not None:
if dplugin.own_process is False:
dplugin.plugin.quit()
try:
dplugin.plugin.quit()
except Exception as E:
tb = traceback.format_exc()
self.plugin_died.emit(dplugin, E, tb)

if self.gui_data.rm_dplugin(opt.plugin_id) == ERROR.NO_ERROR:
self.log.printText(1,'plugin_closed, Plugin with id: '+str(opt.plugin_id)+' was removed in GUI')
Expand All @@ -183,18 +194,28 @@ def process_stop_plugin(self, event):
id = event.get_destinatioID()
dplugin = self.gui_data.get_dplugin_by_id(id)
if dplugin is not None:
dplugin.plugin.quit()
dplugin.state = PLUGIN_STATE_STOPPED
self.dgui_changed.emit()
try:
dplugin.plugin.quit()
dplugin.state = PLUGIN_STATE_STOPPED
self.removed_dplugin.emit(dplugin)
self.dgui_changed.emit()
except Exception as E:
tb = traceback.format_exc()
self.plugin_died.emit(dplugin, E, tb)

def process_start_plugin(self, event):
id = event.get_destinatioID()
dplugin = self.gui_data.get_dplugin_by_id(id)
if dplugin is not None:
if dplugin.plugin.start_init(dplugin.plugin.get_current_config()) is True:
dplugin.state = PLUGIN_STATE_START_SUCCESFUL
else:
dplugin.state = PLUGIN_STATE_START_FAILED
try:
if dplugin.plugin.start_init(dplugin.plugin.get_current_config()) is True:
dplugin.state = PLUGIN_STATE_START_SUCCESFUL
self.added_dplugin.emit(dplugin)
else:
dplugin.state = PLUGIN_STATE_START_FAILED
except Exception as E:
tb = traceback.format_exc()
self.plugin_died.emit(dplugin, E, tb)

self.dgui_changed.emit()

Expand Down Expand Up @@ -259,17 +280,25 @@ def process_create_plugin(self, event):
dplugin.startup_config = config
# call the init function of plugin and set queues and id
api = Plugin_api(self.gui_data,self.core_queue,self.gui_id, uname + ' API:')
dplugin.plugin.init_plugin(self.core_queue, self.gui_queue, dplugin.id, api)


# call the plugin developers init function with config
if dplugin.plugin.start_init(copy.deepcopy(config)) is True:
#start succcessfull
self.core_queue.put( Event.status.StartSuccessfull(dplugin.id, 0, None))
else:
self.core_queue.put( Event.status.StartFailed(dplugin.id, 0, None))
try:
dplugin.plugin.init_plugin(self.core_queue, self.gui_queue, dplugin.id, api)
if dplugin.plugin.start_init(copy.deepcopy(config)) is True:
#start succcessfull
self.core_queue.put( Event.status.StartSuccessfull(dplugin.id, 0, None))
else:
self.core_queue.put( Event.status.StartFailed(dplugin.id, 0, None))

# first set meta to plugin (meta infos in plugin)
dplugin.plugin.update_plugin_meta(dplugin.get_meta())

except Exception as E:
tb = traceback.format_exc()
self.plugin_died.emit(dplugin, E, tb)


# first set meta to plugin (meta infos in plugin)
dplugin.plugin.update_plugin_meta(dplugin.get_meta())

# debug print
self.log.printText(1,'create_plugin, Plugin with name '+str(uname)+' was started as ViP')
Expand Down
5 changes: 4 additions & 1 deletion papi/gui/qt_new/create_plugin_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
self.close()

if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
self.show_create_plugin_dialog()


def pluginItemChanged(self, index):
Expand Down Expand Up @@ -143,4 +145,5 @@ def clear(self):
self.pathEdit.setText('')

def closeEvent(self, *args, **kwargs):
self.plugin_create_dialog.close()
self.plugin_create_dialog.close()

21 changes: 16 additions & 5 deletions papi/gui/qt_new/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
__author__ = 'knuths'

from PySide.QtGui import QLineEdit, QFileDialog

import os

class FileLineEdit(QLineEdit):
def __init__(self):
Expand All @@ -41,8 +41,19 @@ def set_file_type(self, type):
self.file_type = type

def mousePressEvent(self, event):
filename = QFileDialog.getOpenFileName(self,
self.tr("File"), "./", self.tr(self.file_type))

if len(filename[0]) > 0:
self.setText(filename[0])
fileNames = ''

path, file = os.path.split(self.text())

dialog = QFileDialog(self)
dialog.setFileMode(QFileDialog.AnyFile)
dialog.setNameFilter( self.tr(self.file_type))
dialog.setDirectory(path)

if dialog.exec_():
fileNames = dialog.selectedFiles()

if len(fileNames):
if fileNames[0] != '':
self.setText(fileNames[0])
20 changes: 17 additions & 3 deletions papi/gui/qt_new/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,12 @@ def data(self, role):
return None

def clean(self):
'''
"""
This function is called to remove all rows which contain an item marked as 'deleted'.
This only works with items having an state-attribute e.g. DPlugin.
:return:
'''
:return:
"""
for row in range(self.rowCount()):
treeItem = self.child(row)
if treeItem is not None:
Expand All @@ -118,6 +118,20 @@ def clean(self):
if item.state == 'deleted':
self.removeRow(row)

def hasItem(self, sItem):
"""
Used to check if an item is already part of this Tree
:param sItem: Searched for this item
:return:
"""
for row in range(self.rowCount()):
treeItem = self.child(row)
if treeItem is not None:
item = treeItem.data(Qt.UserRole)
if item == sItem:
return True

# ------------------------------------
# Model Objects
# ------------------------------------
Expand Down
Loading

0 comments on commit d2455c0

Please sign in to comment.