added HDF5 read capability. Closes #27
This commit is contained in:
+160
-28
@@ -169,7 +169,7 @@ class DamarisGUI:
|
||||
|
||||
self.log = LogWindow( self.xml_gui , self)
|
||||
|
||||
self.sw = ScriptWidgets( self.xml_gui )
|
||||
self.sw = ScriptWidgets( self.xml_gui, self )
|
||||
|
||||
self.toolbar_init( )
|
||||
|
||||
@@ -218,6 +218,7 @@ class DamarisGUI:
|
||||
"on_experiment_script_line_textfield_value_changed": self.sw.column_line_widgets_changed_event,
|
||||
"on_experiment_script_column_textfield_value_changed": self.sw.column_line_widgets_changed_event,
|
||||
"on_toolbar_open_file_button_clicked": self.sw.open_file,
|
||||
"on_toolbar_open_hdf5_button_clicked": self.sw.open_hdf5,
|
||||
"on_toolbar_new_button_clicked": self.sw.new_file,
|
||||
"on_toolbar_save_as_button_clicked": self.sw.save_file_as,
|
||||
"on_toolbar_save_file_button_clicked": self.sw.save_file,
|
||||
@@ -297,6 +298,14 @@ class DamarisGUI:
|
||||
self.config = None
|
||||
self.xml_gui = None
|
||||
|
||||
def observe_data_pool( self, data_pool ):
|
||||
"""
|
||||
Delegate to monitor widgets
|
||||
"""
|
||||
self.data = data_pool
|
||||
if hasattr(self, "monitor"):
|
||||
self.monitor.observe_data_pool(data_pool)
|
||||
|
||||
# event handling: the real acitons in gui programming
|
||||
|
||||
# first global events
|
||||
@@ -1103,11 +1112,12 @@ class LogWindow:
|
||||
|
||||
|
||||
class ScriptWidgets:
|
||||
def __init__( self, xml_gui ):
|
||||
def __init__( self, xml_gui, outer_space ):
|
||||
"""
|
||||
initialize text widgets with text
|
||||
"""
|
||||
self.xml_gui = xml_gui
|
||||
self.outer_space = outer_space
|
||||
|
||||
# my states
|
||||
# editing enabled/disabled
|
||||
@@ -1572,7 +1582,7 @@ get_ylabel set_ylabel"""
|
||||
elif response == gtk.ResponseType.CANCEL:
|
||||
return 0
|
||||
|
||||
def response( self, response_id, script_widget ):
|
||||
def response( dialog, response_id, script_widget ):
|
||||
if response_id == gtk.ResponseType.OK:
|
||||
file_name = dialog.get_filename( )
|
||||
if file_name is None:
|
||||
@@ -1580,7 +1590,13 @@ get_ylabel set_ylabel"""
|
||||
|
||||
script_filename = os.path.abspath( file_name )
|
||||
if not os.access( script_filename, os.R_OK ):
|
||||
self.outer_space.show_error_dialog( "File I/O Error", "Cannot read from file %s" % script_filename )
|
||||
error_dialog = gtk.MessageDialog(parent=script_widget.xml_gui.get_object( "main_window"),
|
||||
type=gtk.MessageType.ERROR,
|
||||
flags=gtk.DialogFlags.MODAL,
|
||||
buttons=("_OK", gtk.ResponseType.OK))
|
||||
error_dialog.set_markup("Cannot read from file %s" % script_filename)
|
||||
error_dialog.run()
|
||||
error_dialog.destroy()
|
||||
return True
|
||||
|
||||
script_string = script_widget.load_file_as_unicode( script_filename )
|
||||
@@ -1613,6 +1629,103 @@ get_ylabel set_ylabel"""
|
||||
|
||||
return True
|
||||
|
||||
def open_hdf5( self, widget, Data=None ):
|
||||
"""
|
||||
Open and load an HDF5 file written by DAMARIS.
|
||||
"""
|
||||
# ignore
|
||||
if not self.editing_state:
|
||||
return 0
|
||||
|
||||
parent_window = self.xml_gui.get_object( "main_window" )
|
||||
dialog = gtk.FileChooserDialog( title="Open HDF5 File...",
|
||||
parent=parent_window,
|
||||
action=gtk.FileChooserAction.OPEN,
|
||||
buttons=("_Open", gtk.ResponseType.OK, "_Cancel", gtk.ResponseType.CANCEL)
|
||||
)
|
||||
dialog.set_default_response( gtk.ResponseType.OK )
|
||||
dialog.set_select_multiple( False )
|
||||
|
||||
# Add filter for HDF5 files
|
||||
filter_hdf5 = gtk.FileFilter()
|
||||
filter_hdf5.set_name("HDF5 files")
|
||||
filter_hdf5.add_pattern("*.h5")
|
||||
filter_hdf5.add_pattern("*.hdf5")
|
||||
filter_hdf5.add_pattern("*.HDF5")
|
||||
filter_hdf5.add_pattern("*.H5")
|
||||
dialog.add_filter(filter_hdf5)
|
||||
|
||||
# Also allow all files
|
||||
filter_all = gtk.FileFilter()
|
||||
filter_all.set_name("All files")
|
||||
filter_all.add_pattern("*")
|
||||
dialog.add_filter(filter_all)
|
||||
|
||||
def response( dialog, response_id, script_widget ):
|
||||
if response_id == gtk.ResponseType.OK:
|
||||
file_name = dialog.get_filename( )
|
||||
if file_name is None:
|
||||
return
|
||||
|
||||
file_name = os.path.abspath( file_name )
|
||||
if not os.access( file_name, os.R_OK ):
|
||||
error_dialog = gtk.MessageDialog(parent=script_widget.xml_gui.get_object( "main_window"),
|
||||
type=gtk.MessageType.ERROR,
|
||||
flags=gtk.DialogFlags.MODAL,
|
||||
buttons=("_OK", gtk.ResponseType.OK))
|
||||
error_dialog.set_markup("Cannot read from file %s" % file_name)
|
||||
error_dialog.run()
|
||||
error_dialog.destroy()
|
||||
return True
|
||||
|
||||
try:
|
||||
# Load DataPool and metadata from HDF5
|
||||
data_pool, metadata = DataPool.load_hdf5(file_name)
|
||||
|
||||
# Set the loaded data pool in the outer space (main application)
|
||||
if hasattr(script_widget.outer_space, 'observe_data_pool'):
|
||||
script_widget.outer_space.observe_data_pool(data_pool)
|
||||
elif hasattr(script_widget.outer_space, 'monitor'):
|
||||
# Fallback if delegate not present
|
||||
script_widget.outer_space.data = data_pool
|
||||
script_widget.outer_space.monitor.observe_data_pool(data_pool)
|
||||
|
||||
# If there are scripts in metadata, load them
|
||||
if 'scripts' in metadata:
|
||||
scripts = metadata['scripts']
|
||||
exp_script = scripts.get('experiment_script', None)
|
||||
res_script = scripts.get('result_script', None)
|
||||
if exp_script or res_script:
|
||||
script_widget.set_scripts(exp_script, res_script)
|
||||
|
||||
# Show success message
|
||||
success_dialog = gtk.MessageDialog(parent=script_widget.xml_gui.get_object( "main_window"),
|
||||
type=gtk.MessageType.INFO,
|
||||
flags=gtk.DialogFlags.MODAL,
|
||||
buttons=("_OK", gtk.ResponseType.OK))
|
||||
success_dialog.set_markup("Successfully loaded data from %s" % os.path.basename(file_name))
|
||||
success_dialog.run()
|
||||
success_dialog.destroy()
|
||||
|
||||
except Exception as e:
|
||||
error_dialog = gtk.MessageDialog(parent=script_widget.xml_gui.get_object( "main_window"),
|
||||
type=gtk.MessageType.ERROR,
|
||||
flags=gtk.DialogFlags.MODAL,
|
||||
buttons=("_OK", gtk.ResponseType.OK))
|
||||
error_dialog.set_markup("Failed to load HDF5 file: %s" % str(e))
|
||||
error_dialog.run()
|
||||
error_dialog.destroy()
|
||||
|
||||
return True
|
||||
|
||||
# Event-Handler for response-signal (when one of the button is pressed)
|
||||
dialog.connect( "response", response, self )
|
||||
|
||||
dialog.run( )
|
||||
dialog.destroy( )
|
||||
|
||||
return True
|
||||
|
||||
def save_file( self, widget=None, Data=None ):
|
||||
"""
|
||||
save file to associated filename
|
||||
@@ -2411,7 +2524,7 @@ class MonitorWidgets:
|
||||
def source_list_find_one( self, model, iter, what ):
|
||||
"""find node in subcategory"""
|
||||
while iter is not None:
|
||||
if model.get( iter, 0 )[ 0 ] == what:
|
||||
if str( model.get( iter, 0 )[ 0 ] ) == what:
|
||||
return iter
|
||||
iter = model.iter_next( iter )
|
||||
return iter
|
||||
@@ -2482,31 +2595,50 @@ class MonitorWidgets:
|
||||
register a listener and save reference to data
|
||||
assume to be in gtk/gdk lock
|
||||
"""
|
||||
if self.data_pool is not None:
|
||||
# maybe some extra cleanup needed
|
||||
print("ToDo: cleanup widgets")
|
||||
if self.displayed_data[ 1 ] is not None and hasattr( self.displayed_data[ 1 ], "unregister_listener" ):
|
||||
self.displayed_data[ 1 ].unregister_listener( self.datastructures_listener )
|
||||
self.displayed_data[ 1 ] = None
|
||||
self.displayed_data = [ None, None ]
|
||||
self.data_pool.unregister_listener( self.datapool_listener )
|
||||
self.data_pool = None
|
||||
gdk.threads_enter( )
|
||||
try:
|
||||
if self.data_pool is not None:
|
||||
# maybe some extra cleanup needed
|
||||
print("ToDo: cleanup widgets")
|
||||
if self.displayed_data[ 1 ] is not None and hasattr( self.displayed_data[ 1 ], "unregister_listener" ):
|
||||
self.displayed_data[ 1 ].unregister_listener( self.datastructures_listener )
|
||||
self.displayed_data[ 1 ] = None
|
||||
self.displayed_data = [ None, None ]
|
||||
self.data_pool.unregister_listener( self.datapool_listener )
|
||||
self.data_pool = None
|
||||
|
||||
self.update_counter_lock.acquire( )
|
||||
self.update_counter = 0
|
||||
self.update_counter_lock.release( )
|
||||
|
||||
# display states
|
||||
self.source_list_reset( )
|
||||
self.update_counter_lock.acquire( )
|
||||
self.update_counter = 0
|
||||
self.update_counter_lock.release( )
|
||||
self.__rescale = True
|
||||
self.displayed_data = [ None, None ]
|
||||
self.display_source_path_label.set_label( "" )
|
||||
self.clear_display( )
|
||||
|
||||
# display states
|
||||
self.__rescale = True
|
||||
self.displayed_data = [ None, None ]
|
||||
self.display_source_path_label.set_label( "" )
|
||||
self.clear_display( )
|
||||
|
||||
if data_pool is not None:
|
||||
# keep track of data
|
||||
self.data_pool = data_pool
|
||||
self.data_pool.register_listener( self.datapool_listener )
|
||||
if data_pool is not None:
|
||||
# keep track of data
|
||||
self.data_pool = data_pool
|
||||
self.data_pool.register_listener( self.datapool_listener )
|
||||
|
||||
# Populate source list with existing data since the listener
|
||||
# was registered after the data was loaded
|
||||
for key in sorted(data_pool.keys()):
|
||||
if key != "__builtins__": # Skip internal keys
|
||||
self.source_list_add(key)
|
||||
|
||||
# Select first data item if available
|
||||
keys = [k for k in data_pool.keys() if not k.startswith("__")]
|
||||
if keys:
|
||||
keys.sort()
|
||||
first_key = keys[0]
|
||||
first_iter = self.source_list_find(first_key.split("/"))
|
||||
if first_iter:
|
||||
self.display_source_combobox.set_active_iter(first_iter)
|
||||
finally:
|
||||
gdk.threads_leave( )
|
||||
|
||||
#################### observing data structures and produce idle events
|
||||
|
||||
@@ -2643,7 +2775,7 @@ class MonitorWidgets:
|
||||
gdk.threads_leave( )
|
||||
elif event.what == DataPool.Event.destroy:
|
||||
gdk.threads_enter( )
|
||||
self.source_list_reset( 'None' )
|
||||
self.source_list_reset( )
|
||||
self.displayed_data = [ None, None ]
|
||||
self.clear_display( )
|
||||
gdk.threads_leave( )
|
||||
|
||||
Reference in New Issue
Block a user