summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GstDebugViewer/Plugins/FindBar.py219
-rw-r--r--data/gst-debug-viewer.glade41
2 files changed, 246 insertions, 14 deletions
diff --git a/GstDebugViewer/Plugins/FindBar.py b/GstDebugViewer/Plugins/FindBar.py
new file mode 100644
index 0000000..21cfe5a
--- /dev/null
+++ b/GstDebugViewer/Plugins/FindBar.py
@@ -0,0 +1,219 @@
+# -*- coding: utf-8; mode: python; -*-
+#
+# GStreamer Debug Viewer - View and analyze GStreamer debug log files
+#
+# Copyright (C) 2007 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 Debug Viewer timeline widget plugin."""
+
+import logging
+
+from GstDebugViewer import Common, Data, GUI
+from GstDebugViewer.Plugins import *
+
+import gtk
+
+class SearchOperation (object):
+
+ def __init__ (self, model, search_string, search_forward = True, start_position = None):
+
+ self.model = model
+ self.search_string = search_string
+ self.search_forward = search_forward
+ self.start_position = start_position
+
+class SearchSentinel (object):
+
+ def __init__ (self):
+
+ self.dispatcher = Common.Data.GSourceDispatcher ()
+
+ def run_for (self, operation):
+
+ self.dispatcher.cancel ()
+ self.dispatcher (self.__process (operation))
+
+ def abort (self):
+
+ self.dispatcher.cancel ()
+
+ def __process (self, operation):
+
+ model = operation.model
+
+ if operation.start_position is not None:
+ start_iter = model.iter_nth_child (None, operation.start_position)
+ else:
+ start_iter = model.iter_nth_child (None, 0)
+
+ if not operation.search_forward:
+ # FIXME:
+ raise NotImplementedError ("backward search not supported yet")
+
+ search_string = operation.search_string
+ col_id = model.COL_MESSAGE
+ model_get = model.get_value
+ iter_next = model.iter_next
+
+ YIELD_LIMIT = 1000
+ i = YIELD_LIMIT
+ tree_iter = start_iter
+ while tree_iter:
+ i -= 1
+ if i == 0:
+ yield True
+ i = YIELD_LIMIT
+ msg = model_get (tree_iter, col_id)
+ if search_string in msg:
+ self.handle_match_found (model, tree_iter)
+ tree_iter = iter_next (tree_iter)
+
+ self.handle_search_complete ()
+ yield False
+
+ def handle_match_found (self, model, tree_iter):
+
+ pass
+
+ def handle_search_complete (self):
+
+ pass
+
+class FindBarWidget (gtk.HBox):
+
+ def __init__ (self):
+
+ gtk.HBox.__init__ (self)
+
+ label = gtk.Label (_("Find:"))
+ self.pack_start (label, False, False, 0)
+
+ self.entry = gtk.Entry ()
+ self.pack_start (self.entry)
+
+ self.show_all ()
+
+class FindBarFeature (FeatureBase):
+
+ def __init__ (self):
+
+ FeatureBase.__init__ (self)
+
+ self.matches = []
+
+ self.logger = logging.getLogger ("ui.findbar")
+
+ self.action_group = gtk.ActionGroup ("FindBarActions")
+ self.action_group.add_toggle_actions ([("show-find-bar",
+ None,
+ _("Find Bar"),
+ "<Ctrl>F")])
+
+ self.bar = None
+ self.operation = None
+
+ self.sentinel = SearchSentinel ()
+ self.sentinel.handle_match_found = self.handle_match_found
+ self.sentinel.handle_search_complete = self.handle_search_complete
+
+ def scroll_view_to_line (self, line_index):
+
+ view = self.log_view
+
+ path = (line_index,)
+
+ start_path, end_path = view.get_visible_range ()
+
+ if path >= start_path and path <= end_path:
+ self.logger.debug ("line index %i already visible, not scrolling", line_index)
+ return
+
+ self.logger.debug ("scrolling to line_index %i", line_index)
+ view.scroll_to_cell (path, use_align = True, row_align = .5)
+
+ def handle_attach_window (self, window):
+
+ ui = window.ui_manager
+
+ ui.insert_action_group (self.action_group, 0)
+
+ self.log_view = window.log_view
+
+ self.merge_id = ui.new_merge_id ()
+ ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions",
+ "ViewFindBar", "show-find-bar",
+ gtk.UI_MANAGER_MENUITEM, False)
+
+ box = window.widgets.vbox_view
+ self.bar = FindBarWidget ()
+ box.pack_end (self.bar, False, False, 0)
+ self.bar.hide ()
+
+ action = self.action_group.get_action ("show-find-bar")
+ handler = self.handle_show_find_bar_action_activate
+ action.connect ("toggled", handler)
+
+ self.bar.entry.connect ("changed", self.handle_entry_changed)
+
+ def handle_detach_window (self, window):
+
+ window.ui_manager.remove_ui (self.merge_id)
+ self.merge_id = None
+
+ def handle_show_find_bar_action_activate (self, action):
+
+ if action.props.active:
+ self.bar.show ()
+ self.bar.entry.grab_focus ()
+ else:
+ self.bar.hide ()
+
+ def handle_entry_changed (self, entry):
+
+ # FIXME: If the new search operation is stricter than the previous one
+ # (find as you type!), re-use the previous results for a nice
+ # performance gain (by only searching in previous results again)
+ del self.matches[:]
+
+ model = self.log_view.props.model
+ search_string = entry.props.text
+ if search_string == "":
+ self.logger.debug ("search string set to '', aborting search")
+ self.sentinel.abort ()
+ # FIXME: Set start position
+ self.logger.debug ("starting search for %r", search_string)
+ self.operation = SearchOperation (model, search_string)
+ self.sentinel.run_for (self.operation)
+
+ def handle_match_found (self, model, tree_iter):
+
+ line_index = model.get_path (tree_iter)[0]
+ self.matches.append (line_index)
+
+ if len (self.matches) == 1:
+ self.scroll_view_to_line (line_index)
+ elif len (self.matches) > 10000:
+ self.sentinel.abort ()
+
+ def handle_search_complete (self):
+
+ self.logger.debug ("search for %r complete, got %i results",
+ self.operation.search_string,
+ len (self.matches))
+
+class Plugin (PluginBase):
+
+ features = [FindBarFeature]
diff --git a/data/gst-debug-viewer.glade b/data/gst-debug-viewer.glade
index edc13c8..9fb9bad 100644
--- a/data/gst-debug-viewer.glade
+++ b/data/gst-debug-viewer.glade
@@ -36,26 +36,39 @@
<property name="spacing">0</property>
<child>
- <widget class="GtkScrolledWindow" id="log_view_scrolled_window">
+ <widget class="GtkVBox" id="vbox_view">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
<child>
- <widget class="GtkTreeView" id="log_view">
+ <widget class="GtkScrolledWindow" id="log_view_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="headers_visible">True</property>
- <property name="rules_hint">True</property>
- <property name="reorderable">True</property>
- <property name="enable_search">True</property>
- <property name="fixed_height_mode">False</property>
- <property name="hover_selection">False</property>
- <property name="hover_expand">False</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="log_view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">True</property>
+ <property name="reorderable">True</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
</widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
</child>
</widget>
<packing>