[thorstenp] improve advanced configuration editor speed. see #4457
This commit is contained in:
parent
2521ea6080
commit
b632a8d2e1
2 changed files with 83 additions and 59 deletions
121
src/advanced.py
121
src/advanced.py
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
import gtkgui_helpers
|
import gtkgui_helpers
|
||||||
|
import gobject
|
||||||
|
|
||||||
from common import gajim
|
from common import gajim
|
||||||
|
|
||||||
|
@ -41,6 +42,42 @@ C_TYPE
|
||||||
|
|
||||||
GTKGUI_GLADE = 'manage_accounts_window.glade'
|
GTKGUI_GLADE = 'manage_accounts_window.glade'
|
||||||
|
|
||||||
|
def rate_limit(rate):
|
||||||
|
''' call func at most *rate* times per second '''
|
||||||
|
def decorator(func):
|
||||||
|
timeout = [None]
|
||||||
|
def f(*args, **kwargs):
|
||||||
|
if timeout[0] is not None:
|
||||||
|
gobject.source_remove(timeout[0])
|
||||||
|
timeout[0] = None
|
||||||
|
def timeout_func():
|
||||||
|
func(*args, **kwargs)
|
||||||
|
timeout[0] = None
|
||||||
|
timeout[0] = gobject.timeout_add(int(1000.0 / rate), timeout_func)
|
||||||
|
return f
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
def tree_model_iter_children(model, treeiter):
|
||||||
|
it = model.iter_children(treeiter)
|
||||||
|
while it:
|
||||||
|
yield it
|
||||||
|
it = model.iter_next(it)
|
||||||
|
|
||||||
|
def tree_model_pre_order(model, treeiter):
|
||||||
|
yield treeiter
|
||||||
|
for childiter in tree_model_iter_children(model, treeiter):
|
||||||
|
for it in tree_model_pre_order(model, childiter):
|
||||||
|
yield it
|
||||||
|
|
||||||
|
try:
|
||||||
|
any(()) # builtin since python 2.5
|
||||||
|
except Exception:
|
||||||
|
def any(iterable):
|
||||||
|
for element in iterable:
|
||||||
|
if element:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
class AdvancedConfigurationWindow(object):
|
class AdvancedConfigurationWindow(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.xml = gtkgui_helpers.get_glade('advanced_configuration_window.glade')
|
self.xml = gtkgui_helpers.get_glade('advanced_configuration_window.glade')
|
||||||
|
@ -65,7 +102,9 @@ class AdvancedConfigurationWindow(object):
|
||||||
'color': _('Color')}
|
'color': _('Color')}
|
||||||
|
|
||||||
treeview = self.xml.get_widget('advanced_treeview')
|
treeview = self.xml.get_widget('advanced_treeview')
|
||||||
|
self.treeview = treeview
|
||||||
self.model = gtk.TreeStore(str, str, str)
|
self.model = gtk.TreeStore(str, str, str)
|
||||||
|
self.fill_model()
|
||||||
self.model.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
self.model.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||||
self.modelfilter = self.model.filter_new()
|
self.modelfilter = self.model.filter_new()
|
||||||
self.modelfilter.set_visible_func(self.visible_func)
|
self.modelfilter.set_visible_func(self.visible_func)
|
||||||
|
@ -88,9 +127,6 @@ class AdvancedConfigurationWindow(object):
|
||||||
treeview.insert_column_with_attributes(-1, _('Type'),
|
treeview.insert_column_with_attributes(-1, _('Type'),
|
||||||
renderer_text, text = 2)
|
renderer_text, text = 2)
|
||||||
|
|
||||||
# add data to model
|
|
||||||
gajim.config.foreach(self.fill, self.model)
|
|
||||||
|
|
||||||
treeview.set_model(self.modelfilter)
|
treeview.set_model(self.modelfilter)
|
||||||
|
|
||||||
# connect signal for selection change
|
# connect signal for selection change
|
||||||
|
@ -215,65 +251,34 @@ class AdvancedConfigurationWindow(object):
|
||||||
def on_advanced_close_button_clicked(self, widget):
|
def on_advanced_close_button_clicked(self, widget):
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
|
||||||
def find_iter(self, model, parent_iter, name):
|
def fill_model(self, node=None, parent=None):
|
||||||
if not parent_iter:
|
for item, option in gajim.config.get_children(node):
|
||||||
iter = model.get_iter_root()
|
name = item[-1]
|
||||||
else:
|
if option is None: # Node
|
||||||
iter = model.iter_children(parent_iter)
|
newparent = self.model.append(parent, [name, '', ''])
|
||||||
while iter:
|
self.fill_model(item, newparent)
|
||||||
if model[iter][C_PREFNAME].decode('utf-8') == name:
|
else: # Leaf
|
||||||
break
|
type_ = self.types[option[OPT_TYPE][0]]
|
||||||
iter = model.iter_next(iter)
|
|
||||||
return iter
|
|
||||||
|
|
||||||
def fill(self, model, name, parents, val):
|
|
||||||
iter = None
|
|
||||||
if parents:
|
|
||||||
for p in parents:
|
|
||||||
iter2 = self.find_iter(model, iter, p)
|
|
||||||
if iter2:
|
|
||||||
iter = iter2
|
|
||||||
|
|
||||||
if not val:
|
|
||||||
model.append(iter, [name, '', ''])
|
|
||||||
return
|
|
||||||
type = ''
|
|
||||||
if val[OPT_TYPE]:
|
|
||||||
type = val[OPT_TYPE][0]
|
|
||||||
type = self.types[type] # i18n
|
|
||||||
value = val[OPT_VAL]
|
|
||||||
if name == 'password':
|
if name == 'password':
|
||||||
#we talk about password
|
value = _('Hidden')
|
||||||
value = _('Hidden') # override passwords with this string
|
else:
|
||||||
if value in self.right_true_dict:
|
value = self.right_true_dict.get(option[OPT_VAL],
|
||||||
value = self.right_true_dict[value]
|
option[OPT_VAL])
|
||||||
model.append(iter, [name, value, type])
|
self.model.append(parent, [name, value, type_])
|
||||||
|
|
||||||
def visible_func(self, model, iter_):
|
def visible_func(self, model, treeiter):
|
||||||
str = self.entry.get_text().decode('utf-8')
|
search_string = self.entry.get_text()
|
||||||
if str in (None, ''):
|
return any(search_string in model[it][C_PREFNAME] for it in
|
||||||
return True # show all
|
tree_model_pre_order(model, treeiter) if model[it][C_VALUE] != '')
|
||||||
name = model[iter_][C_PREFNAME].decode('utf-8')
|
|
||||||
# If a child of the iter matches, we return True
|
|
||||||
if model.iter_has_child(iter_):
|
|
||||||
iterC = model.iter_children(iter_)
|
|
||||||
while iterC:
|
|
||||||
nameC = model[iterC][C_PREFNAME].decode('utf-8')
|
|
||||||
if model.iter_has_child(iterC):
|
|
||||||
iterCC = model.iter_children(iterC)
|
|
||||||
while iterCC:
|
|
||||||
nameCC = model[iterCC][C_PREFNAME].decode('utf-8')
|
|
||||||
if nameCC.find(str) != -1:
|
|
||||||
return True
|
|
||||||
iterCC = model.iter_next(iterCC)
|
|
||||||
elif nameC.find(str) != -1:
|
|
||||||
return True
|
|
||||||
iterC = model.iter_next(iterC)
|
|
||||||
elif name.find(str) != -1:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
@rate_limit(3)
|
||||||
def on_advanced_entry_changed(self, widget):
|
def on_advanced_entry_changed(self, widget):
|
||||||
self.modelfilter.refilter()
|
self.modelfilter.refilter()
|
||||||
|
if not widget.get_text():
|
||||||
|
# Maybe the expanded rows should be remembered here ...
|
||||||
|
self.treeview.collapse_all()
|
||||||
|
else:
|
||||||
|
# ... and be restored correctly here
|
||||||
|
self.treeview.expand_all()
|
||||||
|
|
||||||
# vim: se ts=3:
|
# vim: se ts=3:
|
||||||
|
|
|
@ -477,6 +477,25 @@ class Config:
|
||||||
for opt3 in dict[opt2]:
|
for opt3 in dict[opt2]:
|
||||||
cb(data, opt3, [opt, opt2], dict[opt2][opt3])
|
cb(data, opt3, [opt, opt2], dict[opt2][opt3])
|
||||||
|
|
||||||
|
def get_children(self, node=None):
|
||||||
|
''' Tree-like interface '''
|
||||||
|
if node is None:
|
||||||
|
for child, option in self.__options.iteritems():
|
||||||
|
yield (child, ), option
|
||||||
|
for grandparent in self.__options_per_key:
|
||||||
|
yield (grandparent, ), None
|
||||||
|
elif len(node) == 1:
|
||||||
|
grandparent, = node
|
||||||
|
for parent in self.__options_per_key[grandparent][1]:
|
||||||
|
yield (grandparent, parent), None
|
||||||
|
elif len(node) == 2:
|
||||||
|
grandparent, parent = node
|
||||||
|
children = self.__options_per_key[grandparent][1][parent]
|
||||||
|
for child, option in children.iteritems():
|
||||||
|
yield (grandparent, parent, child), option
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid node')
|
||||||
|
|
||||||
def is_valid_int(self, val):
|
def is_valid_int(self, val):
|
||||||
try:
|
try:
|
||||||
ival = int(val)
|
ival = int(val)
|
||||||
|
|
Loading…
Add table
Reference in a new issue