[d-feet/listbox: 1/2] Use GtkListBox instead of a TreeView
- From: Thomas Bechtold <toabctl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [d-feet/listbox: 1/2] Use GtkListBox instead of a TreeView
- Date: Sun, 14 Jul 2013 17:35:50 +0000 (UTC)
commit 65079819487353fc8d9e4134133d490d88b6fd53
Author: Thomas Bechtold <thomasbechtold jpberlin de>
Date: Sun Jul 14 19:12:15 2013 +0200
Use GtkListBox instead of a TreeView
configure.ac | 2 +-
data/ui/bus.ui | 86 +++++++++++++
data/ui/buswatch.ui | 231 ----------------------------------
src/dfeet/bus_watch.py | 321 ++++++++++++++++++++++++++++--------------------
src/dfeet/uiloader.py | 10 +-
src/dfeet/window.py | 4 +-
6 files changed, 279 insertions(+), 375 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 0737399..2a4321f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,7 +18,7 @@ YELP_HELP_INIT
AM_PATH_PYTHON([2.7])
PKG_CHECK_MODULES(DFEET, [
- gtk+-3.0 >= 3.6
+ gtk+-3.0 >= 3.9.4
])
AC_ARG_ENABLE(tests,
diff --git a/data/ui/bus.ui b/data/ui/bus.ui
new file mode 100644
index 0000000..a1566e1
--- /dev/null
+++ b/data/ui/bus.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkBox" id="box_bus">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkBox" id="box_left">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkBox" id="box_filter">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Filter busnames:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entry_filter">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image_placeholder">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pixel_size">128</property>
+ <property name="icon_name">d-feet</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/src/dfeet/bus_watch.py b/src/dfeet/bus_watch.py
index 4fbeb65..6d7974f 100644
--- a/src/dfeet/bus_watch.py
+++ b/src/dfeet/bus_watch.py
@@ -7,87 +7,130 @@ from dfeet.uiloader import UILoader
from dfeet.introspection import AddressInfo
-class DBusBusName(GObject.GObject):
- """class to represent a name on the bus"""
- def __init__(self, bus_name_unique):
- super(DBusBusName, self).__init__()
- self.__bus_name_unique = bus_name_unique
- self.__pid = 0
- self.__cmdline = ''
+class BusNameBox(Gtk.VBox):
+ """class to represent a BusName (eg 'org.freedesktop.NetworkManager')"""
+ def __init__(self, bus_name):
+ super(BusNameBox, self).__init__(spacing=5, expand=True)
+ self.__bus_name = bus_name
+ self.__process_id = 0
+ self.__command_line = ''
+ self.__activatable = False
+
+ #first element
+ self.__label_bus_name = Gtk.Label()
+ self.__label_bus_name.set_markup("<b>{0}</b>".format(self.__bus_name))
+ self.__label_bus_name.set_halign(Gtk.Align.START)
+ self.pack_start(self.__label_bus_name, True, True, 0)
+ #second element
+ self.__label_info = Gtk.Label()
+ self.__label_info.set_halign(Gtk.Align.START)
+ self.pack_start(self.__label_info, True, True, 0)
+ #separator for the boxes
+ self.pack_end(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), True, True, 0)
+ #update widget information
+ self.__update_widget()
+ self.show_all()
+
+ def __update_widget(self):
+ """update the widget with the available information"""
+ #update the label info
+ label_info_str = "<small>"
+ if self.__activatable:
+ label_info_str += "activatable: yes"
+ else:
+ label_info_str += "activatable: no"
+ if self.__process_id:
+ label_info_str += ", pid: {0}".format(self.__process_id)
+ if self.__command_line:
+ label_info_str += ", cmd: {0}".format(self.__command_line)
+ label_info_str += "</small>"
+ self.__label_info.set_markup(label_info_str)
def __repr__(self):
- return "%s (pid: %s)" % (self.bus_name_unique, self.pid)
+ return "%s (pid: %s)" % (self.__bus_name, self.__process_id)
- def __update_cmdline(self):
- if self.pid > 0:
- procpath = '/proc/' + str(self.pid) + '/cmdline'
+ def __update_command_line(self):
+ """get the command line of process-id is available"""
+ if self.__process_id > 0:
+ procpath = '/proc/' + str(self.__process_id) + '/cmdline'
with open(procpath, 'r') as f:
- self.__cmdline = " ".join(f.readline().split('\0'))
+ self.__command_line = " ".join(f.readline().split('\0'))
else:
- self.__cmdline = ''
+ self.__command_line = ''
@property
- def bus_name_unique(self):
- return self.__bus_name_unique
+ def bus_name(self):
+ return self.__bus_name
@property
- def pid(self):
- return self.__pid
+ def activatable(self):
+ return self.__activatable
- @pid.setter
- def pid(self, pid_new):
- self.__pid = pid_new
- try:
- self.__update_cmdline()
- except:
- self.__cmdline = ''
+ @activatable.setter
+ def activatable(self, act_new):
+ self.__activatable = act_new
+
+ #update the shown widget
+ self.__update_widget()
@property
- def cmdline(self):
- return self.__cmdline
+ def process_id(self):
+ return self.__process_id
+
+ @process_id.setter
+ def process_id(self, process_id_new):
+ self.__process_id = process_id_new
+ try:
+ self.__update_command_line()
+ except:
+ self.__command_line = ''
+ #update the shown widget
+ self.__update_widget()
class BusWatch(object):
"""watch for a given bus"""
- def __init__(self, data_dir, address):
- self.data_dir = data_dir
- self.address = address
+ def __init__(self, data_dir, bus_address):
+ self.__data_dir = data_dir
+ self.__bus_address = bus_address
#setup UI
- ui = UILoader(self.data_dir, UILoader.UI_BUSWATCH)
- self.paned_buswatch = ui.get_root_widget()
- self.liststore_model = ui.get_widget('liststore_buswatch')
- self.treemodelfilter_buswatch = ui.get_widget('treemodelfilter_buswatch')
- self.treemodelfilter_buswatch.set_visible_func(self.__treemodelfilter_buswatch_cb)
- self.treemodelsort_buswatch = ui.get_widget("treemodelsort_buswatch")
- self.treemodelsort_buswatch.set_sort_func(2, self.__sort_on_name)
- self.treemodelsort_buswatch.set_sort_column_id(2, Gtk.SortType.ASCENDING)
- self.treeview = ui.get_widget('treeview_buswatch')
- self.entry_filter = ui.get_widget('entry_filter')
- self.grid_bus_name_selected_info = ui.get_widget('grid_bus_name_info')
- self.label_bus_name_selected_name = ui.get_widget('label_bus_name_selected_name')
- self.label_bus_name_selected_pid = ui.get_widget('label_bus_name_selected_pid')
- self.label_bus_name_selected_cmdline = ui.get_widget('label_bus_name_selected_cmdline')
- self.addr_info = None # hold the currently selected AddressInfo object
-
- self.treeview.connect('cursor-changed',
- self.__tree_view_cursor_changed_cb)
- self.entry_filter.connect("changed",
- self.__entry_filter_changed_cb)
-
- #setup the conection
- if self.address == Gio.BusType.SYSTEM or self.address == Gio.BusType.SESSION:
- self.connection = Gio.bus_get_sync(self.address, None)
- elif Gio.dbus_is_supported_address(self.address):
+ ui = UILoader(self.__data_dir, UILoader.UI_BUS)
+ self.__box_bus = ui.get_root_widget()
+ self.__scrolledwindow_listbox = ui.get_widget("scrolledwindow_listbox")
+ self.__bus_name_filter = ui.get_widget('entry_filter')
+ #create a listbox for all the busnames
+ self.__listbox = Gtk.ListBox(hexpand=True, vexpand=True, expand=True)
+ self.__listbox.set_sort_func(self.__listbox_sort_by_name, None)
+ self.__listbox.set_filter_func(self.__listbox_filter_by_name, None)
+ self.__scrolledwindow_listbox.add(self.__listbox)
+ self.__scrolledwindow_listbox.show_all()
+ #setup the bus connection
+ if self.__bus_address == Gio.BusType.SYSTEM or self.__bus_address == Gio.BusType.SESSION:
+ #TODO: do this async
+ self.connection = Gio.bus_get_sync(self.__bus_address, None)
+ elif Gio.dbus_is_supported_address(self.__bus_address):
+ #TODO: do this async
self.connection = Gio.DBusConnection.new_for_address_sync(
- self.address,
+ self.__bus_address,
Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT |
Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
None, None)
+ else:
+ raise ValueError("Invalid bus address '{0}'".format(self.__bus_address))
#setup signals
self.connection.signal_subscribe(None, "org.freedesktop.DBus", "NameOwnerChanged",
None, None, 0, self.__name_owner_changed_cb, None)
+ #refilter if someone wants to filter the busbox list
+ self.__bus_name_filter.connect("changed",
+ self.__bus_name_filter_changed_cb)
+
+ #change bus detail tree if a different bus is selected
+ self.__listbox.connect("row-selected",
+ self.__listbox_row_selected_cb)
+
+ #TODO: do this async
self.bus_proxy = Gio.DBusProxy.new_sync(self.connection,
Gio.DBusProxyFlags.NONE,
None,
@@ -95,74 +138,46 @@ class BusWatch(object):
'/org/freedesktop/DBus',
'org.freedesktop.DBus', None)
+ #get a list with activatable names
+ self.bus_proxy.ListActivatableNames('()',
+ result_handler=self.__list_act_names_handler,
+ error_handler=self.__list_act_names_error_handler)
+
#list all names
self.bus_proxy.ListNames('()',
result_handler=self.__list_names_handler,
error_handler=self.__list_names_error_handler)
- def __treemodelfilter_buswatch_cb(self, model, iter, user_data):
- #return model.get_value(iter, 1) in data
- bus_name_obj = model.get(iter, 0)[0]
- filter_text = self.entry_filter.get_text()
- return filter_text.lower() in bus_name_obj.bus_name_unique.lower()
-
- def __entry_filter_changed_cb(self, entry_filter):
- self.treemodelfilter_buswatch.refilter()
-
- def __tree_view_cursor_changed_cb(self, treeview):
- """do something when a row is selected"""
- selection = self.treeview.get_selection()
- if selection:
- model, iter_ = selection.get_selected()
- if not iter_:
- return
-
- bus_name_obj = model.get(iter_, 0)[0]
- #remove current child
- c2 = self.paned_buswatch.get_child2()
- if c2:
- c2.destroy()
- try:
- del(self.addr_info)
- except:
- pass
-
- #add Introspection to paned
- self.addr_info = AddressInfo(
- self.data_dir, self.address, bus_name_obj.bus_name_unique, connection_is_bus=True)
- self.paned_buswatch.add2(self.addr_info.introspect_box)
-
- #update info about selected bus name
- self.label_bus_name_selected_name.set_text(bus_name_obj.bus_name_unique)
- self.label_bus_name_selected_pid.set_text("%s" % bus_name_obj.pid)
- self.label_bus_name_selected_cmdline.set_text(bus_name_obj.cmdline)
- self.grid_bus_name_selected_info.set_visible(True)
-
- def __liststore_model_add(self, bus_name_obj):
- """add a DBusBusName object to the liststore model"""
- #update bus info stuff
- self.bus_proxy.GetConnectionUnixProcessID(
- '(s)', bus_name_obj.bus_name_unique,
- result_handler=self.__get_unix_process_id_cb,
- error_handler=self.__get_unix_process_id_error_cb,
- user_data=bus_name_obj)
- #add bus to liststore
- return self.liststore_model.append(
- [bus_name_obj, 0, "%s" % (bus_name_obj.bus_name_unique), bus_name_obj.cmdline])
-
- def __liststore_model_remove(self, bus_name_obj):
- """remove a DBusBusName object to the liststore model"""
- for n, obj in enumerate(self.liststore_model):
- if obj[2] == bus_name_obj.bus_name_unique:
- del(self.liststore_model[n])
- break
-
- def __liststore_model_get(self, bus_name_obj):
- """get a object from the liststore"""
- for n, obj in enumerate(self.liststore_model):
- if obj[2] == bus_name_obj.bus_name_unique:
- return obj
- raise Exception("bus name object '%s' not found in liststore" % (bus_name_obj))
+ @property
+ def box_bus(self):
+ """the main widget for the bus"""
+ return self.__box_bus
+
+ def __bus_name_filter_changed_cb(self, bus_name_filter):
+ """someone typed something in the searchbox - refilter"""
+ self.__listbox.invalidate_filter()
+
+ def __listbox_row_selected_cb(self, listbox, listbox_row):
+ """someone selected a different row of the listbox"""
+ childs = self.box_bus.get_children()
+ #never remove first element - that's the listbox with the busnames
+ if len(childs) > 1:
+ self.box_bus.remove(childs[-1])
+
+ try:
+ del(self.__addr_info)
+ except:
+ pass
+
+ #get the selected busname
+ if listbox_row:
+ row_childs = listbox_row.get_children()
+ bus_name_box = row_childs[0]
+ #add the introspection info to the left side
+ self.__addr_info = AddressInfo(
+ self.__data_dir, self.__bus_address, bus_name_box.bus_name, connection_is_bus=True)
+ self.box_bus.pack_end(self.__addr_info.introspect_box, True, True, 0)
+ self.box_bus.show_all()
def __name_owner_changed_cb(self, connection, sender_name,
object_path, interface_name, signal_name,
@@ -172,39 +187,73 @@ class BusWatch(object):
old_owner = parameters[1]
new_owner = parameters[2]
- bus_name_obj = DBusBusName(bus_name)
-
if bus_name[0] == ':':
if not old_owner:
- self.__liststore_model_add(bus_name_obj)
+ bus_name_box = BusNameBox(bus_name)
+ self.__listbox_add_bus_name(bus_name_box)
else:
- self.__liststore_model_remove(bus_name_obj)
+ self.__listbox_remove_bus_name(bus_name)
else:
if new_owner:
- self.__liststore_model_add(bus_name_obj)
+ bus_name_box = BusNameBox(bus_name)
+ self.__listbox_add_bus_name(bus_name_box)
if old_owner:
- self.__liststore_model_remove(bus_name_obj)
+ self.__listbox_remove_bus_name(bus_name)
+
+ def __listbox_remove_bus_name(self, bus_name):
+ """remove the given busname from the listbox"""
+ for listbox_child in self.__listbox.get_children():
+ if listbox_child.get_children()[0].bus_name == bus_name:
+ self.__listbox.remove(listbox_child)
+
+ def __listbox_add_bus_name(self, bus_name_box):
+ """add the given busnamebox to the listbox and update the info"""
+ #update bus info stuff
+ self.bus_proxy.GetConnectionUnixProcessID(
+ '(s)', bus_name_box.bus_name,
+ result_handler=self.__get_unix_process_id_cb,
+ error_handler=self.__get_unix_process_id_error_cb,
+ user_data=bus_name_box)
+ #check if bus name is dbus activatable
+ if bus_name_box.bus_name in self.__activatable_names:
+ bus_name_box.activatable = True
+ else:
+ bus_name_box.activatable = False
+ self.__listbox.add(bus_name_box)
def __list_names_handler(self, obj, names, userdata):
for n in names:
- bus_name_obj = DBusBusName(n)
- self.__liststore_model_add(bus_name_obj)
+ bus_name_box = BusNameBox(n)
+ self.__listbox_add_bus_name(bus_name_box)
def __list_names_error_handler(self, obj, error, userdata):
print("error getting bus names: %s" % str(error))
- def __get_unix_process_id_cb(self, obj, pid, bus_name_obj):
- bus_name_obj.pid = pid
+ def __list_act_names_handler(self, obj, act_names, userdata):
+ self.__activatable_names = act_names
+
+ def __list_act_names_error_handler(self, obj, error, userdata):
+ self.__activatable_names = []
+ print("error getting activatable names: %s" % str(error))
+
+ def __get_unix_process_id_cb(self, obj, pid, bus_name_box):
+ bus_name_box.process_id = pid
+
+ def __get_unix_process_id_error_cb(self, obj, error, bus_name_box):
+ #print("error getting unix process id for %s: %s" % (
+ # bus_name_box.bus_name, str(error)))
+ bus_name_box.process_id = 0
- def __get_unix_process_id_error_cb(self, obj, error, bus_name_obj):
- print(
- "error getting unix process id for %s: %s" % (
- bus_name_obj.bus_name_unique, str(error)))
- bus_name_obj.pid = 0
+ def __listbox_filter_by_name(self, row, user_data):
+ bus_name_box_list = row.get_children()
+ return self.__bus_name_filter.get_text().lower() in bus_name_box_list[0].bus_name.lower()
- def __sort_on_name(self, model, iter1, iter2, user_data):
- un1 = model.get_value(iter1, 2)
- un2 = model.get_value(iter2, 2)
+ def __listbox_sort_by_name(self, row1, row2, user_data):
+ """sort function for listbox"""
+ child1 = row1.get_children()
+ child2 = row2.get_children()
+ un1 = child1[0].bus_name
+ un2 = child2[0].bus_name
# covert to integers if comparing two unique names
if un1[0] == ':' and un2[0] == ':':
diff --git a/src/dfeet/uiloader.py b/src/dfeet/uiloader.py
index 08dda4b..1a63429 100644
--- a/src/dfeet/uiloader.py
+++ b/src/dfeet/uiloader.py
@@ -10,9 +10,9 @@ class UILoader:
(UI_MAINWINDOW,
UI_INTROSPECTION,
- UI_BUSWATCH,
UI_EXECUTEDIALOG,
- UI_ADDCONNECTIONDIALOG
+ UI_ADDCONNECTIONDIALOG,
+ UI_BUS
) = range(UI_COUNT)
# {ui_id: ((files,...), root widget)}
@@ -20,12 +20,12 @@ class UILoader:
'appwindow1'),
UI_INTROSPECTION: (('introspection.ui',),
'box_introspectview'),
- UI_BUSWATCH: (('buswatch.ui',),
- 'paned_buswatch'),
UI_EXECUTEDIALOG: (('executedialog.ui',),
'executedialog1'),
UI_ADDCONNECTIONDIALOG: (('addconnectiondialog.ui',),
- 'add_connection_dialog1')
+ 'add_connection_dialog1'),
+ UI_BUS: (('bus.ui',),
+ 'box_bus')
}
def __init__(self, data_dir, ui):
diff --git a/src/dfeet/window.py b/src/dfeet/window.py
index b170ff7..f043c1a 100644
--- a/src/dfeet/window.py
+++ b/src/dfeet/window.py
@@ -114,7 +114,7 @@ class DFeetWindow(Gtk.ApplicationWindow):
"""connect to system bus"""
try:
bw = BusWatch(self.data_dir, Gio.BusType.SYSTEM)
- self.__notebook_append_page(bw.paned_buswatch, "System Bus")
+ self.__notebook_append_page(bw.box_bus, "System Bus")
except Exception as e:
print(e)
@@ -122,7 +122,7 @@ class DFeetWindow(Gtk.ApplicationWindow):
"""connect to session bus"""
try:
bw = BusWatch(self.data_dir, Gio.BusType.SESSION)
- self.__notebook_append_page(bw.paned_buswatch, "Session Bus")
+ self.__notebook_append_page(bw.box_bus, "Session Bus")
except Exception as e:
print(e)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]