def __init__(self, project=None): " 'project' may be a Project object or a filename. " self.eConfig = config.read_configfile(self, const.CONFIG_FILE) Signals.connect(self, "write-config", (lambda sender: self.write_recentfiles())) self.plugins = dict() self.recent_files = list() self.read_recentfiles() # init() is a good place for initialization of derived class self.init() # Set up the Project... self._project = None if isinstance(project, basestring): try: self.load_project(project) except IOError: logger.error("Failed to load project '%s'\nSetting up an empty project instead." % project) self.set_project(Project()) else: self.set_project(project) self.init_plugins()
def _construct_toolwindow(self): window = tools.ToolWindow(self.app, None) window.set_transient_for(self) window.set_destroy_with_parent(True) window.hide() def cb_toggle_window(action, window): if action.get_active() is True: window.show() else: window.hide() t = gtk.ToggleAction('ToggleToolWindow', 'Show tools window', None, None) t.connect("toggled", cb_toggle_window, window) uihelper.get_action_group(self.uimanager, 'Application').add_action(t) def cb_window_hideshow(window): action = self.uimanager.get_action('/MainMenu/ViewMenu/ToggleToolWindow') action.set_active(window.get_property('visible')) window.connect('hide', cb_window_hideshow) window.connect('show', cb_window_hideshow) def on_notify_project(sender, project, toolwin): print "==> project = ", project print "==> toolwin = ", toolwin toolwin.set_project(project) Signals.connect(self.app, 'notify::project', on_notify_project, window) return window
def set_dataset(self, dataset): if dataset is None: self.set_title("(no dataset)") else: self.set_title("DS: %s" % dataset.key) # FIXME # this is inconsistent: we expect 'table' to be fixed, # even though we argued before that the dataset.data field # is not necessarily fixed, only the Dataset. table = dataset.get_data() if not isinstance(table, Table): raise TypeError("TableWindow can only use Datasets with a Table as data.") self.tableview.set_table(table) for signal in self._signals: Signals.disconnect(signal) self._signals += [ Signals.connect(table, 'update-columns', (lambda sender: self.tableview.setup_columns())), Signals.connect(dataset,'notify', (lambda sender: self.tableview.queue_draw())) ] # TODO: set metadata widget self._dataset = dataset
def _cb_select_line(self, action): def finish_select_line(sender): print "FINISHED SELECT LINE", sender.line s = mpl_selector.SelectLine(self.backend.figure,mode=mpl_selector.SELECTLINE_VERTICAL) Signals.connect(s, "finished", finish_select_line) self.select(s)
def add_plotwidget(self, widget): n = self.plotbook.append_page(widget) self.plotbook.set_tab_label_text(widget, "Plot") # TODO: this signal should be a gobject signal Signals.connect(widget, "closed", self.detach_plotwidget) for ag in widget.get_actiongroups(): self.uimanager.insert_action_group(ag, 0) self.add_accel_group(self.uimanager.get_accel_group()) self.uimanager.add_ui_from_string(widget.get_uistring())
def __init__(self, app, project, plot): gtk.Window.__init__(self) self.set_size_request(width=360,height=400) self.app = app self.project = project self.plot = None # will be set after everything else is set up self.backend = None self._signals = list() # some icons are not right at all.... groups = { 'Common': [('Replot', gtk.STOCK_REFRESH, 'Replot', '<control>R', 'Replot everything', '_cb_replot'), ('Edit', gtk.STOCK_PROPERTIES, 'Edit Plot', None, 'Edit Plot', '_cb_edit_plot'), ('ZoomSelection', gtk.STOCK_ZOOM_FIT, 'use current range', None, 'Use Current Range', '_cb_zoom_selection'), ('ZoomAutoscale', gtk.STOCK_ZOOM_100, 'do not limit range', None, 'Do not limit Range', '_cb_zoom_autoscale'), ('ExportPostscript', gtk.STOCK_SAVE, 'export as postscript', None, 'Export as Postscript file', '_cb_export_postscript') ] } ui = \ """ <ui> <toolbar name='Toolbar'> <toolitem action='Replot'/> <separator/> <toolitem action='Edit'/> <toolitem action='ZoomSelection'/> <toolitem action='ZoomAutoscale'/> <separator/> <toolitem action='ExportPostscript'/> </toolbar> </ui> """ self.uimanager = self._construct_uimanager(groups,ui) self.toolbar = self._construct_toolbar() # vbox self.vbox = gtk.VBox(False) self.vbox.pack_start(self.toolbar, expand=False, fill=True) self.vbox.pack_start(self._construct_history(), expand=True, fill=True) self.vbox.show() self.add(self.vbox) self.connect("destroy", (lambda sender: self.destroy())) Signals.connect(self.project, "close", (lambda sender: self.destroy())) self.set_plot(plot)
def _cb_zoom_axes(self, action): def finish_moving(sender): ul = UndoList().describe("Zoom") layer = self.backend.axes_to_layer[sender.axes] self.zoom_to_region(layer, sender.region, undolist=ul) self.project.journal.add_undo(ul) s = mpl_selector.ZoomAxes(self.backend.figure) Signals.connect(s, "finished", finish_moving) self.select(s)
def on_action_SelectLine(self, action): def finish_select_line(sender): print "FINISHED SELECT LINE", sender.line layer = self.backend.layer axes = self.backend.layer_to_axes[layer] s = mpl_selector.SelectLine(self.backend.figure, axes, mode=mpl_selector.SELECTLINE_VERTICAL) Signals.connect(s, "finished", finish_select_line) self.select(s)
def set_plot(self, plot): Signals.disconnect_list(self._signals) self.backend is not None and self.backend.disconnect() if plot is None: return self.plot = plot self.set_title( "Plot: %s" % plot.key ) self.backend = project.new_backend('gnuplot/x11', plot=plot) # connect signals for treeview # these are disconnect by the backend if it closes Signals.connect(self.backend, 'gnuplot-send-cmd', self.on_send_cmd) Signals.connect(self.backend, 'gnuplot-finish-cmd', self.on_finish_cmd) Signals.connect(self.backend, 'gnuplot-start-plotting', self.on_start_plotting) # connect signal for plot # these should be disconnected before the plot needs to do it. self._signals += [ Signals.connect(plot, "plot-changed", (lambda sender: self.backend.draw())), Signals.connect(plot, "closed", (lambda sender: self.destroy())) ] self.backend.draw()
def on_action_MoveAxes(self, action): def finish_moving(sender): ul = UndoList().describe("Move Graph") layer = self.backend.axes_to_layer[sender.axes] self.zoom_to_region(layer, sender.region, undolist=ul) self.project.journal.add_undo(ul) layer = self.backend.layer axes = self.backend.layer_to_axes[layer] s = mpl_selector.MoveAxes(self.backend.figure, axes) Signals.connect(s, "finished", finish_moving) self.select(s)
def set_plot(self, plot): if plot == self.plot: return self.plot = plot if plot is not None: self.layer = plot.current_layer Signals.connect(plot, "notify::current_layer", self.on_notify_layer) else: self.layer = None self.set_sensitive(plot is not None) # TODO: connect properly on change of plot self.update_plot()
def set_backend(self, backend): """ Set the backend to the new value (implies setting a new layer). """ if self.backend != backend: Signals.disconnect_list(self.backend_signals) self.backend = backend if self.backend is not None: # If no active layer is set, even though there are layers, # then we should set the first layer as being active. if self.backend.layer is None and len(self.backend.plot.layers) > 0: self.backend.layer = self.backend.plot.layers[0] self.layer = self.backend.layer # make sure we keep track of changes to the active layer self.backend_signals.append( Signals.connect(backend, "notify::layer", (lambda sender, layer: self.set_layer(layer))) ) else: self.layer = None # propagate the new backend to all tools self.dock.foreach((lambda tool: tool.set_backend(self.backend))) # Adjust the active index of the combobox so that the new # backend is displayed. if self.backend is None: index = -1 else: model = self.combobox.get_model() index = self.project.backends.index(backend) self.combobox.set_active(index)
def set_project(self, project): if project == self.project: return if project is not None: # update combobox again if plots change Signals.connect(project.plots, 'notify', (lambda sender: self.update_combobox())) Signals.connect(project.app, 'notify::current_plot', (lambda sender, plot: self.set_plot(plot))) self.dock.foreach((lambda tool: tool.set_data('project', project))) self.project = project self.update_combobox() self.update_plot()
def set_project(self, project, confirm=True): # if project changes, then close the Project properly! if self._project is not None and id(project) != id(self._project): self._project.close() self._project = project if project is not None: project.app = self def detach_project(project): if id(self._project) == id(project): self._project.app = None self._project = None # TODO: connect_once would be nice. Signals.connect(project, 'close', detach_project)
def set_plot(self, plot): # TODO: remove old plot # TODO: connect to plot's title if plot is not None: backend = self.project.request_backend('matplotlib', plot=plot) #backend.canvas.set_size_request(800, 600) sw = uihelper.add_scrollbars(backend.canvas, viewport=True) sw.show() self.vbox.pack_start(sw) else: backend = None # disconnect old stuff if self.backend is not None and self.backend != backend: self.backend.disconnect() for signal in self._signals: Signals.disconnect(signal) self._signals = [] if self.cursor is not None: self.cursor.finish() # connect new backend self.plot = plot self.backend = backend if backend is not None: self._signals.extend( [Signals.connect(plot, "plot-changed", (lambda sender: backend.draw())), Signals.connect(plot, "closed", (lambda sender: Signals.emit(self, 'closed')))] ) try: backend.draw() except: #gtkutils.info_msg("Nothing to plot.") raise # Cursor self.cursor = mpl_selector.Cursor(self.backend.figure) Signals.connect(self.cursor, "move", (lambda sender,x,y: self.set_coords(x,y))) self.cursor.init()
def set_project(self,project): """ Assign a project to the TreeView and repopulate the tree. If no project is given, the TreeView will be empty. """ if project: self.set_property('sensitive',True) else: self.set_property('sensitive',False) self._project = project self.populate_treeview() # TODO: remove old signals if self.project is not None: Signals.connect(self.project.datasets, "changed", self.populate_treeview) Signals.connect(self.project.plots, "changed", self.populate_treeview)
def _cb_zoom_rect(self, action): def finish_zooming(sender): self.statusbar.pop( self.statusbar.get_context_id('action-zoom')) ul = UndoList().describe("Zoom Region") layer = self.backend.axes_to_layer[sender.axes] self.zoom_to_region(layer, sender.region, undolist=ul) self.project.journal.add_undo(ul) s = mpl_selector.SelectRegion(self.backend.figure) Signals.connect(s, 'finished', finish_zooming) self.statusbar.push( self.statusbar.get_context_id('action-zoom'), "Use the left mouse button to zoom.") self.select(s)
def __init__(self, app, project, dataset=None): gtk.Window.__init__(self) self.set_size_request(280,320) self.set_transient_for(app.window) self.app = app self._signals = [] self.uimanager = self._construct_uimanager() self.menubar = self._construct_menubar() self.toolbar = self._construct_toolbar() self.popup = self.uimanager.get_widget('/popup_column') self.popup_info = None # needed for popup self.statusbar = self._construct_statusbar() self.tableview = self._construct_tableview() sw = uihelper.add_scrollbars(self.tableview) sw.show() hpaned = gtk.HPaned() hpaned.pack1( sw ) # hpaned.pack2( self._construct_metadata_widget() ) hpaned.show() self.hpaned = hpaned vbox = gtk.VBox() vbox.pack_start( self.menubar, expand=False, fill=True ) vbox.pack_start( self.toolbar, expand=False, fill=True ) vbox.pack_start( self.hpaned, expand=True, fill=True ) vbox.pack_start( self.statusbar, expand=False, fill=True ) vbox.show() self.add(vbox) self.project = project # immutable self._dataset = None self.dataset = dataset Signals.connect(self.project, "close", (lambda sender: self.destroy())) Signals.connect(self.dataset, "closed", (lambda sender: self.destroy())) self.tableview.emit('cursor_changed')
def set_project(self, project, confirm=True): has_changed = (id(self._project) != id(project)) if self._project is not None and has_changed: self._project.close() self._project = project if project is not None: project.app = self def detach_project(project): if id(self._project) == id(project): self._project.app = None self._project = None # TODO: connect_once would be nice. Signals.connect(project, 'close', detach_project) if has_changed is True: Signals.emit(self, 'notify::project', self._project)
def set_project(self, project): if project == self.project: return Signals.disconnect_list(self.project_signals) if project is not None: # update combobox again if plots change self.project_signals.extend( [Signals.connect(project, 'notify::plots', (lambda sender: self.update_combobox())), Signals.connect(project.app, 'notify::current_plot', (lambda sender, plot: self.set_plot(plot))) ]) self.dock.foreach((lambda tool: tool.set_data('project', project))) self.project = project self.update_combobox() self.update_plot()
def set(self, project,plot): logging.debug("Assigning project %s to Backend" % repr(project)) # if necessary, detach messages from old project for signal in self.Signals: Signals.disconnect(signal) self.Signals.clear() # assign project and plot self.plot = plot self.project = project if self.project is not None: logging.debug("Connecting Signals.") self.Signals['close'] = Signals.connect( self.project, 'close', self.cb_project_closed) self.Signals['plot-changed'] = Signals.connect( self.plot, 'plot-changed', self.cb_plot_changed) self.Signals['plot-closed'] = Signals.connect( self.plot, 'closed', (lambda sender: self.disconnect()))
def select(self, selector): self.emit("edit-mode-started") self._current_selector = None def on_finish(sender): # Be careful not to call self.abort_selection() in this place. self._current_selector = None self.btn_cancel.set_sensitive(False) self.emit("edit-mode-ended") self.btn_cancel.set_sensitive(True) self.btn_cancel.connect("clicked", (lambda sender: self.abort_selection())) Signals.connect(selector, "finished", on_finish) Signals.connect(selector, "aborted", on_finish) self._current_selector = selector selector.init()
def __init__(self, app, project, plot): gtk.VBox.__init__(self) self._current_selector = None self.app = app self._construct_actiongroups() self.statusbar = self._construct_statusbar() self.coords = self._construct_coords() self.btn_cancel = self._construct_cancel_button() self.context_id = self.statusbar.get_context_id("coordinates") #self.statusbar.push(self.context_id, "X: 10, Y: 20") #self.statusbar.pop(self.context_id) vbox = self.vbox = gtk.VBox() hbox = gtk.HBox() hbox.pack_start(self.btn_cancel, False, padding=4) hbox.pack_start(self.coords, False, padding=4) hbox.pack_start(self.statusbar, padding=4) hbox.show() vbox.pack_end(hbox, False, True) vbox.show() self.add(vbox) # set up project/plot self.project = project self.plot = None self.backend = None self.cursor = None self._signals = [] self.set_plot(plot) Signals.connect(self.project, "close", (lambda sender: self.destroy())) # set up file selector for export dialog # TODO: this could be put into a plugin, since it is desirable to have # TODO: such a method in the shell frontend as well. self.fileselect = FileChooserDialog(title='Save the figure', parent=None)
def set_layer(self, layer): if layer == self.layer: return Signals.disconnect_list(self.layer_signals) self.layer = layer if layer is not None: self.layer_signals.append( Signals.connect(self.layer, "notify::labels", self.on_notify_labels) ) self.update_layer()
def on_action_DataCursor(self, action): layer = self.backend.layer axes = self.backend.layer_to_axes[layer] s = mpl_selector.DataCursor(self.backend.figure, axes) def abort_selector(sender, context_id): self.statusbar.pop(context_id) def finish_selector(sender, context_id): self.statusbar.pop(context_id) xvalue, yvalue = sender.point def update_position(sender, line, index, point, context_id): # Note that 'line' is a Line2d instance from matplotlib! x, y = point self.statusbar.pop(context_id) self.statusbar.push(context_id, "X: %f, Y: %f (value #%s)" % (x, y, index)) context_id = self.statusbar.get_context_id("data_cursor") Signals.connect(s, "update-position", update_position, context_id) Signals.connect(s, "finished", finish_selector, context_id) Signals.connect(s, "aborted", abort_selector, context_id) self.select(s)
def __init__(self, app, project, plot): gtk.VBox.__init__(self) self._current_selector = None self.app = app self._construct_actiongroups() self.statusbar = self._construct_statusbar() self.coords = self._construct_coords() self.btn_cancel = self._construct_cancel_button() self.context_id = self.statusbar.get_context_id("coordinates") self.statusbar.push(self.context_id, "X: 10, Y: 20") self.statusbar.pop(self.context_id) vbox = self.vbox = gtk.VBox() hbox = gtk.HBox() hbox.pack_start(self.btn_cancel, False, padding=4) hbox.pack_start(self.coords, False, padding=4) hbox.pack_start(self.statusbar, padding=4) hbox.show() vbox.pack_end(hbox, False, True) vbox.show() self.add(vbox) # set up project/plot self.project = project self.plot = None self.backend = None self.cursor = None self._signals = [] self.set_plot(plot) Signals.connect(self.project, "close", (lambda sender: self.destroy()))
def arrange(self, rows=1, cols=1): layers = self.plot.layers n = len(layers) if n > (rows*cols): rows = int((rows*cols) / n) + 1 cols = rows * n #raise ValueError("Not enough rows and cols for all layers!") self.figure.clear() self.figure.axes = [] self.layer_to_axes.clear() self.axes_to_layer.clear() self.layers_cache = [] for signal_list in self.layer_signals.itervalues(): for signal in signal_list: Signals.disconnect(signal) self.layer_signals = {} j = 1 for layer in layers: print "Setting up layer", layer axes = self.figure.add_subplot("%d%d%d" % (rows,cols,j)) self.layer_to_axes[layer] = axes self.axes_to_layer[axes] = layer self.layers_cache.append(layer) print "Connecting to notify of ", layer self.layer_signals[layer] = \ [Signals.connect(layer, 'notify', self.on_update_layer), Signals.connect(layer, 'notify::labels', self.on_update_labels)] j += 1
def _construct_toolbox(self): window = tools.Toolbox(self.app, None) window.set_transient_for(self) window.set_destroy_with_parent(True) window.hide() def cb_toggle_window(action, window): if action.get_active() is True: window.show() else: window.hide() t = gtk.ToggleAction('ToggleToolbox', 'Show tools window', None, None) t.connect("toggled", cb_toggle_window, window) uihelper.get_action_group(self.uimanager, 'Application').add_action(t) def on_window_visibility_toggled(window, action): action.set_active(window.get_property('visible')) window.connect('hide', on_window_visibility_toggled, t) window.connect('show', on_window_visibility_toggled, t) def on_notify_project(sender, project, toolwin): toolwin.set_project(project) Signals.connect(self.app, 'notify::project', on_notify_project, window) return window
def update_backend(self): if self.backend is None: self.treeview.set_sensitive(False) return self.treeview.set_sensitive(True) # check_in model = self.treeview.get_model() model.clear() for layer in self.backend.plot.layers: model.append((layer,)) # connect to change of current layer self.backend_signals.append( Signals.connect(self.backend, "notify::layer", (lambda sender, layer: self.set_layer(layer))) )
def set_plot(self, plot): if plot == self.plot: return Signals.disconnect_list(self.plot_signals) if plot is not None: self.layer = plot.current_layer self.plot_signals.append( Signals.connect(plot, "notify::current_layer", self.on_notify_layer) ) else: self.layer = None self.set_sensitive(plot is not None) self.plot = plot self.update_plot()