summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRené Stadler <mail@renestadler.de>2009-01-29 22:32:17 +0200
committerRené Stadler <mail@renestadler.de>2009-02-26 00:29:30 +0200
commitc38423e95cd789ebf4840cf8a3208749b5368915 (patch)
tree12a4963a8b145c4472e4c4a86e8ae79ecfba287c
parentc3bd2b0fe36f88f7bd83f25bca0c80b110b2a483 (diff)
GUI: Move element view handling to its own base class
-rw-r--r--GstInspector/GUI/filters.py2
-rw-r--r--GstInspector/GUI/models.py11
-rw-r--r--GstInspector/GUI/views.py205
-rw-r--r--GstInspector/GUI/window.py183
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 _