diff options
author | René Stadler <mail@renestadler.de> | 2009-01-29 22:32:17 +0200 |
---|---|---|
committer | René Stadler <mail@renestadler.de> | 2009-02-26 00:29:30 +0200 |
commit | c38423e95cd789ebf4840cf8a3208749b5368915 (patch) | |
tree | 12a4963a8b145c4472e4c4a86e8ae79ecfba287c | |
parent | c3bd2b0fe36f88f7bd83f25bca0c80b110b2a483 (diff) |
GUI: Move element view handling to its own base class
-rw-r--r-- | GstInspector/GUI/filters.py | 2 | ||||
-rw-r--r-- | GstInspector/GUI/models.py | 11 | ||||
-rw-r--r-- | GstInspector/GUI/views.py | 205 | ||||
-rw-r--r-- | GstInspector/GUI/window.py | 183 |
4 files changed, 242 insertions, 159 deletions
diff --git a/GstInspector/GUI/filters.py b/GstInspector/GUI/filters.py index b1d7927..b79b277 100644 --- a/GstInspector/GUI/filters.py +++ b/GstInspector/GUI/filters.py @@ -574,7 +574,7 @@ class FilterManager (Manager): self.app = inspector_window.app widgets = inspector_window.widgets - self.set_filter_func = inspector_window.set_filter_func + self.set_filter_func = inspector_window.element_view.set_filter_func self.combo = widgets.filter_combo self.book = widgets.filter_params_book diff --git a/GstInspector/GUI/models.py b/GstInspector/GUI/models.py index 3ea71f1..80f3b60 100644 --- a/GstInspector/GUI/models.py +++ b/GstInspector/GUI/models.py @@ -107,6 +107,17 @@ class ElementModel (gtk.ListStore, Data.Consumer): self.COL_PACKAGE, package, self.COL_SOURCE, source) + def find_element (self, name): + + col = self.COL_ELEMENT + + for row in self: + element = row[col] + if element.name == name: + return element + else: + raise KeyError ("no such element with name %r" % (name,)) + class NameValueModel (gtk.TreeStore): __metaclass__ = MetaModel diff --git a/GstInspector/GUI/views.py b/GstInspector/GUI/views.py new file mode 100644 index 0000000..f78197d --- /dev/null +++ b/GstInspector/GUI/views.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Inspector - Multimedia system plugin introspection +# +# Copyright (C) 2007, 2008, 2009 René Stadler <mail@renestadler.de> +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see <http://www.gnu.org/licenses/>. + +"""GStreamer Inspector GUI.views module.""" + +import logging +from gettext import ngettext + +import gtk + +from GstInspector import Data + +class ElementView (Data.Consumer): + + def _get_active (self): + + selection = self.view.get_selection () + model, tree_iter = selection.get_selected () + if tree_iter is None: + return None + else: + element = model.get (tree_iter, self.model.COL_ELEMENT)[0] + return element + + def _set_active (self, element): + + model = self.view.props.model + col = self.model.COL_ELEMENT + selection = self.view.get_selection () + + if model is None: + raise KeyError ("view model is None, cannot set active element") + + for row in model: + if row[col] == element: + selection.select_iter (row.iter) + return + else: + raise KeyError ("no such row with element %r" % (element,)) + + active = property (_get_active, _set_active) + + def __init__ (self): + + self.logger = logging.getLogger ("ui.element-view") + + self.model = None + self.view = None + self.count_label = None + + self.default_active_name = None + + def attach (self, model, view, count_label): + + self.model = model + self.view = view + self.count_label = count_label + + view.drag_dest_unset () + view.unset_rows_drag_source () + + self.filter_model = model.filter_new () + def initial_filter_func (*a): + return True + self.filter_func = initial_filter_func + + model_get = model.get + element_col = model.COL_ELEMENT + def filter_func (model, tree_iter): + element = model_get (tree_iter, element_col)[0] + if element is None: + # This happens during (re)load. The model filter reacts to + # row-inserted signals and lets us evaluate these new rows. + # However, our ElementModel is based on gtk.ListStore. For + # these, adding a row and setting its values are separated + # operations. Therefore, all added rows are initially empty. + return False + else: + return self.filter_func (element) + self.filter_model.set_visible_func (filter_func) + + def post_attach (self): + + view = self.view + view.props.model = gtk.TreeModelSort (self.filter_model) + view.set_search_column (self.model.COL_FACTORY_NAME) + + self.update_element_count () + + def detach (self): + + self.model = None + self.view = None + self.count_label = None + + def handle_load_started (self): + + """Data.Consumer method.""" + + if self.active is not None: + self.default_active_name = self.active.name + + self.filtered_row_insertions = 0 + self.filter_model.connect ("row-inserted", self.handle_filtered_row_inserted) + + self.update_element_count () + + def handle_filtered_row_inserted (self, model, tree_path, tree_iter): + + self.filtered_row_insertions += 1 + if self.filtered_row_insertions % 11 == 0: + self.update_element_count () + + def handle_load_finished (self): + + """Data.Consumer method.""" + + self.filter_model.disconnect_by_func (self.handle_filtered_row_inserted) + del self.filtered_row_insertions + + def update_element_count (self): + + """Update the label text to reflect the number of currently displayed + elements in the list view.""" + + model = self.view.props.model + if model is None: + count = 0 + else: + count = model.iter_n_children (None) + text = ngettext ("%i Element shown", "%i Elements shown", count) + self.count_label.props.label = text % (count,) + + def set_filter_func (self, func): + + if func == self.filter_func: + self.logger.debug ("ignoring attempt to set same filter func again") + return + + if self.active is not None: + self.default_active_name = self.active.name + + self.logger.debug ("changing filter func, refiltering element model") + self.filter_func = func + self.filter_model.refilter () + self.update_element_count () + + if self.active is None and self.default_active_name is not None: + try: + self.active = self.model.find_element (name = self.default_active_name) + except KeyError: + pass + else: + self.scroll_to_active () + + def select_first_row (self): + + view = self.view + # Get the derived model, which accounts for filtering and sorting: + model = view.props.model + if model is None: + return + tree_iter = model.get_iter_first () + if tree_iter is None: + return + view.scroll_to_cell (model.get_path (tree_iter), view.get_column (0)) + selection = view.get_selection () + selection.select_iter (tree_iter) + + def scroll_to_active (self): + + view = self.view + model = view.props.model + col = self.model.COL_ELEMENT + + if model is None: + return + + element = self.active + if element is None: + return + + for row in model: + if row[col] == element: + tree_iter = model.get_iter (row.path) + view.scroll_to_cell (model.get_path (tree_iter), + view.get_column (0), + True, 0.5, 0.0) + diff --git a/GstInspector/GUI/window.py b/GstInspector/GUI/window.py index a7640c0..ed148c7 100644 --- a/GstInspector/GUI/window.py +++ b/GstInspector/GUI/window.py @@ -20,7 +20,6 @@ """GStreamer Inspector GUI.window module.""" import logging -from gettext import ngettext import gobject import gtk @@ -32,6 +31,7 @@ from GstInspector.GUI.columns import InspectorColumnManager from GstInspector.GUI.filters import FilterManager, UIFilterNone from GstInspector.GUI.pages import PageManager from GstInspector.GUI.utils import widget_add_popup_menu +from GstInspector.GUI.views import ElementView class PanedState (object): @@ -259,33 +259,6 @@ class InspectorWindowState (object): class InspectorWindow (Data.Consumer): - def _get_active (self): - - selection = self.element_view.get_selection () - model, tree_iter = selection.get_selected () - if tree_iter is None: - return None - else: - element = model.get (tree_iter, self.element_model.COL_ELEMENT)[0] - return element - - def _set_active (self, element): - - model = self.element_view.props.model - col = self.element_model.COL_ELEMENT - selection = self.element_view.get_selection () - - if model is None: - raise KeyError ("view model is None, cannot set active element") - - for row in model: - if row[col] == element: - selection.select_iter (row.iter) - return - else: - raise KeyError ("no such row with element %r" % (element,)) - - active = property (_get_active, _set_active) count = -1 def __init__ (self, app): @@ -299,6 +272,7 @@ class InspectorWindow (Data.Consumer): self.idle_update_source = None + self.element_view = ElementView () self.page_manager = PageManager () self.filter_manager = FilterManager () self.column_manager = InspectorColumnManager () @@ -335,8 +309,10 @@ class InspectorWindow (Data.Consumer): self.widgets = widgets self.gtk_window = widgets.inspector_window - self.element_view = widgets.main_view - self.element_count_label = widgets.row_count_label + self.element_view.attach (self.app.element_model, + widgets.main_view, + widgets.row_count_label) + self.element_view.filter_func = UIFilterNone.filter_func ui = self.app.ui_factory.make (self.actions) self.gtk_window.add_accel_group (ui.get_accel_group ()) @@ -356,25 +332,9 @@ class InspectorWindow (Data.Consumer): model = self.app.element_model self.element_model = model - self.element_filter = model.filter_new () - self.filter_func = UIFilterNone.filter_func - model_get = model.get - element_col = model.COL_ELEMENT - def filter_func (model, tree_iter): - element = model_get (tree_iter, element_col)[0] - if element is None: - # This happens during (re)load. The model filter reacts to - # row-inserted signals and lets us evaluate these new rows. - # However, our ElementModel is based on gtk.ListStore. For - # these, adding a row and setting its values are separated - # operations. Therefore, all added rows are initially empty. - return False - else: - return self.filter_func (element) - self.element_filter.set_visible_func (filter_func) self.default_focus_widget = None - self.default_active_name = self.app.state.element + self.element_view.default_active_name = self.app.state.element self.attach () @@ -405,9 +365,7 @@ class InspectorWindow (Data.Consumer): window.connect ("realize", self.handle_window_realize) model = self.app.element_model - view = self.element_view - view.drag_dest_unset () - view.unset_rows_drag_source () + view = self.element_view.view view_selection = view.get_selection () view_selection.connect ("changed", self.handle_element_view_selection_changed) widget_add_popup_menu (view, self.columns_popup) @@ -425,40 +383,38 @@ class InspectorWindow (Data.Consumer): def post_attach (self): - view = self.element_view - view.props.model = gtk.TreeModelSort (self.element_filter) - view.set_search_column (self.element_model.COL_FACTORY_NAME) - self.filter_manager.handle_load_finished () - self.update_element_count () + self.element_view.post_attach () # Sorting was postponed until now, which is much faster: self.column_manager.enable_sort () - if self.default_active_name is None: - self.select_first_row () + if self.element_view.default_active_name is None: + self.element_view.select_first_row () else: try: - self.active = self.find_element (name = self.default_active_name) + element_name = self.element_view.default_active_name + element = self.element_model.find_element (name = element_name) + self.element_view.active = element except KeyError: - self.select_first_row () + self.element_view.select_first_row () - self.scroll_to_active () + self.element_view.scroll_to_active () if self.default_focus_widget is None: # The element view isn't set as initial default right away because # the tree view sets the first column header button as focus widget # if the model contains no rows (like before load). - self.default_focus_widget = self.element_view + self.default_focus_widget = self.element_view.view self.default_focus_widget.grab_focus () def detach (self): state = self.app.state - if self.active is not None: - state.element = self.active.name + if self.element_view.active is not None: + state.element = self.element_view.active.name self.page_manager.detach () self.filter_manager.detach () @@ -471,39 +427,6 @@ class InspectorWindow (Data.Consumer): self.gtk_window.destroy () - def find_element (self, name): - - col = self.element_model.COL_ELEMENT - - for row in self.element_model: - element = row[col] - if element.name == name: - return element - else: - raise KeyError ("no such element with name %r" % (name,)) - - def set_filter_func (self, func): - - if func == self.filter_func: - self.logger.debug ("ignoring attempt to set same filter func again") - return - - if self.active is not None: - self.default_active_name = self.active.name - - self.logger.debug ("changing filter func, refiltering element model") - self.filter_func = func - self.element_filter.refilter () - self.update_element_count () - - if self.active is None and self.default_active_name is not None: - try: - self.active = self.find_element (name = self.default_active_name) - except KeyError: - pass - else: - self.scroll_to_active () - def set_busy_cursor (self, setting): window = self.gtk_window @@ -584,11 +507,7 @@ class InspectorWindow (Data.Consumer): """Data.Consumer method.""" - if self.active is not None: - self.default_active_name = self.active.name - - self.filtered_row_insertions = 0 - self.element_filter.connect ("row-inserted", self.handle_filtered_row_inserted) + self.element_view.handle_load_started () if self.default_focus_widget is not None: focus_widget = self.gtk_window.get_focus () @@ -597,25 +516,17 @@ class InspectorWindow (Data.Consumer): self.gtk_window.props.sensitive = False self.set_busy_cursor (True) - self.update_element_count () self.filter_manager.handle_load_started () - if self.element_view.props.model: + if self.element_view.view.props.model: self.column_manager.disable_sort () - def handle_filtered_row_inserted (self, model, tree_path, tree_iter): - - self.filtered_row_insertions += 1 - if self.filtered_row_insertions % 11 == 0: - self.update_element_count () - def handle_load_finished (self): """Data.Consumer method.""" - self.element_filter.disconnect_by_func (self.handle_filtered_row_inserted) - del self.filtered_row_insertions + self.element_view.handle_load_finished () self.set_busy_cursor (False) self.gtk_window.props.sensitive = True @@ -633,7 +544,7 @@ class InspectorWindow (Data.Consumer): def real_update (): - element = self.active + element = self.element_view.active if element is not None: self.page_manager.update (element) self.actions.show_documentation.entry = element.hierarchy[-1] @@ -645,62 +556,18 @@ class InspectorWindow (Data.Consumer): self.idle_update_source = gobject.timeout_add (50, real_update) - def update_element_count (self): - - """Update the label text to reflect the number of currently displayed - elements in the list view.""" - - model = self.element_filter - count = model.iter_n_children (None) - text = ngettext ("%i Element shown", "%i Elements shown", count) - self.element_count_label.props.label = text % (count,) - def handle_element_view_selection_changed (self, tree_selection): - element = self.active + element = self.element_view.active if element is None: # Unselected. The filter has changed and the element got filtered # out. We do not update in this case; doing so would be too odd to # the user. Things reach a consistent state again if the user # picks another element or changes the filter again to make the # previously selected one reappear (of which we stored the name in - # self.default_active_name). + # self.element_view.default_active_name). return else: self.update (element) - def select_first_row (self): - - view = self.element_view - # Get the derived model, which accounts for filtering and sorting: - model = view.props.model - if model is None: - return - tree_iter = model.get_iter_first () - if tree_iter is None: - return - view.scroll_to_cell (model.get_path (tree_iter), view.get_column (0)) - selection = view.get_selection () - selection.select_iter (tree_iter) - - def scroll_to_active (self): - - view = self.element_view - model = view.props.model - col = self.element_model.COL_ELEMENT - - if model is None: - return - - element = self.active - if element is None: - return - - for row in model: - if row[col] == element: - tree_iter = model.get_iter (row.path) - view.scroll_to_cell (model.get_path (tree_iter), - view.get_column (0), - True, 0.5, 0.0) - from gettext import gettext as _ |