From 7b4c2e97b5eb49fb8a83022cb7279913861cd173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 1 Aug 2013 17:09:47 +0200 Subject: [PATCH] Manage selection tree state review823002 --- tryton/config.py | 2 +- tryton/gui/main.py | 8 +-- tryton/gui/window/attachment.py | 6 +-- tryton/gui/window/form.py | 6 +-- tryton/gui/window/view_form/screen/screen.py | 51 ++++++++++++------- tryton/gui/window/view_form/view/list.py | 36 +++++++++++-- .../window/view_form/view/list_gtk/parser.py | 7 --- tryton/gui/window/win_search.py | 2 + 8 files changed, 80 insertions(+), 38 deletions(-) diff --git a/tryton/config.py b/tryton/config.py index 98ad557a58..ac9763de4e 100644 --- a/tryton/config.py +++ b/tryton/config.py @@ -57,7 +57,7 @@ class ConfigManager(object): 'client.form_tab': form_tab, 'client.maximize': False, 'client.save_width_height': True, - 'client.save_tree_expanded_state': True, + 'client.save_tree_state': True, 'client.spellcheck': False, 'client.default_path': get_home_dir(), 'client.lang': locale.getdefaultlocale()[0], diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 0ab0719b3e..ba8ba93f62 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -610,15 +610,15 @@ class Main(object): checkmenuitem_save_width_height.set_active(True) checkmenuitem_save_tree_state = gtk.CheckMenuItem( - _('Save Tree Expanded State')) + _('Save Tree State')) checkmenuitem_save_tree_state.connect('activate', lambda menuitem: CONFIG.__setitem__( - 'client.save_tree_expanded_state', + 'client.save_tree_state', menuitem.get_active())) checkmenuitem_save_tree_state.set_accel_path( - '/Options/Form/Save Tree Expanded State') + '/Options/Form/Save Tree State') menu_form.add(checkmenuitem_save_tree_state) - if CONFIG['client.save_tree_expanded_state']: + if CONFIG['client.save_tree_state']: checkmenuitem_save_tree_state.set_active(True) if gtkspell: diff --git a/tryton/gui/window/attachment.py b/tryton/gui/window/attachment.py index f19b579a16..1ad9d00ba2 100644 --- a/tryton/gui/window/attachment.py +++ b/tryton/gui/window/attachment.py @@ -8,8 +8,8 @@ from tryton.gui.window.win_form import WinForm class Attachment(WinForm): "Attachment window" - def __init__(self, model_name, record_id, callback=None): - self.resource = '%s,%s' % (model_name, record_id) + def __init__(self, record, callback=None): + self.resource = '%s,%s' % (record.model_name, record.id) self.attachment_callback = callback screen = Screen('ir.attachment', domain=[ ('resource', '=', self.resource), @@ -17,7 +17,7 @@ class Attachment(WinForm): 'resource': self.resource, }, exclude_field='resource') screen.search_filter() - screen.parent = True + screen.parent = record super(Attachment, self).__init__(screen, self.callback, view_type='tree') diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py index 14685b9b3a..eba3979017 100644 --- a/tryton/gui/window/form.py +++ b/tryton/gui/window/form.py @@ -201,10 +201,10 @@ class Form(SignalEvent, TabContent): return self.screen.id_get() def sig_attach(self, widget=None): - record_id = self.id_get() - if record_id is False or record_id < 0: + record = self.screen.current_record + if not record or record.id < 0: return - Attachment(self.model, record_id, + Attachment(record, lambda: self.update_attachment_count(reload=True)) def update_attachment_count(self, reload=False): diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index e234209f21..4bf279e17b 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -14,6 +14,7 @@ import urllib import urlparse import xml.dom.minidom import gettext +import logging from tryton.gui.window.view_form.model.group import Group from tryton.gui.window.view_form.model.record import Record @@ -88,8 +89,9 @@ class Screen(SignalEvent): self.fields_view_tree = None self.order = order self.view_to_load = [] - self.expanded_nodes = collections.defaultdict( + self.tree_states = collections.defaultdict( lambda: collections.defaultdict(lambda: None)) + self.tree_states_done = set() self.domain_parser = None self.pre_validate = False self.view_to_load = mode[:] @@ -611,29 +613,39 @@ class Screen(SignalEvent): def set_tree_state(self): view = self.current_view - if (not CONFIG['client.save_tree_expanded_state'] - or not self.current_view - or self.current_view.view_type != 'tree' - or not self.current_view.children_field + if (not CONFIG['client.save_tree_state'] + or not view + or view.view_type != 'tree' or not self.group): return + if id(view) in self.tree_states_done: + return parent = self.parent.id if self.parent else None - expanded_nodes = self.expanded_nodes[parent][view.children_field] - if expanded_nodes is None: + state = self.tree_states[parent][view.children_field] + if state is None: json_domain = self.get_tree_domain(parent) try: - expanded_nodes = RPCExecute('model', - 'ir.ui.view_tree_expanded_state', 'get_expanded', + expanded_nodes, selected_nodes = RPCExecute('model', + 'ir.ui.view_tree_state', 'get', self.model_name, json_domain, self.current_view.children_field) expanded_nodes = json.loads(expanded_nodes) + selected_nodes = json.loads(selected_nodes) except RPCException: + logging.getLogger(__name__).warn( + _('Unable to get view tree state')) expanded_nodes = [] - self.expanded_nodes[parent][view.children_field] = expanded_nodes + selected_nodes = [] + self.tree_states[parent][view.children_field] = ( + expanded_nodes, selected_nodes) + else: + expanded_nodes, selected_nodes = state view.expand_nodes(expanded_nodes) + view.select_nodes(selected_nodes) + self.tree_states_done.add(id(view)) def save_tree_state(self, store=True): - if not CONFIG['client.save_tree_expanded_state']: + if not CONFIG['client.save_tree_state']: return for view in self.views: if view.view_type == 'form': @@ -644,17 +656,21 @@ class Screen(SignalEvent): elif (view.view_type == 'tree' and view.children_field): parent = self.parent.id if self.parent else None paths = view.get_expanded_paths() - self.expanded_nodes[parent][view.children_field] = paths + selected_paths = view.get_selected_paths() + self.tree_states[parent][view.children_field] = ( + paths, selected_paths) if store: json_domain = self.get_tree_domain(parent) json_paths = json.dumps(paths) + json_selected_path = json.dumps(selected_paths) try: - RPCExecute('model', 'ir.ui.view_tree_expanded_state', - 'set_expanded', self.model_name, json_domain, - view.children_field, json_paths, + RPCExecute('model', 'ir.ui.view_tree_state', 'set', + self.model_name, json_domain, view.children_field, + json_paths, json_selected_path, process_exception=False) except (TrytonServerError, TrytonServerUnavailable): - pass + logging.getLogger(__name__).warn( + _('Unable to set view tree state')) def get_tree_domain(self, parent): if parent: @@ -665,7 +681,8 @@ class Screen(SignalEvent): return json_domain def load(self, ids, set_cursor=True, modified=False): - self.expanded_nodes.clear() + self.tree_states.clear() + self.tree_states_done.clear() self.group.load(ids, modified=modified) self.current_view.reset() if ids: diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 11678f4f04..132ce53096 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -750,8 +750,7 @@ class ViewList(ParserView): elif tree_sel.get_mode() == gtk.SELECTION_MULTIPLE: model, paths = tree_sel.get_selected_rows() if model and paths: - iter_ = model.get_iter(paths[0]) - record = model.get_value(iter_, 0) + record = model.on_get_iter(paths[0]) self.screen.current_record = record else: self.screen.current_record = None @@ -862,7 +861,11 @@ class ViewList(ParserView): self.widget_tree.expand_to_path(path[:-1]) self.widget_tree.scroll_to_cell(path, focus_column, use_align=False) - self.widget_tree.set_cursor(path, focus_column, new) + current_path = self.widget_tree.get_cursor()[0] + selected_path = \ + self.widget_tree.get_selection().get_selected_rows()[1] + if (current_path != path and path not in selected_path) or new: + self.widget_tree.set_cursor(path, focus_column, new) def sel_ids_get(self): def _func_sel_get(store, path, iter, ids): @@ -896,6 +899,33 @@ class ViewList(ParserView): else: renderer.set_property('editable', False) + def get_selected_paths(self): + selection = self.widget_tree.get_selection() + model, rows = selection.get_selected_rows() + id_paths = [] + for row in rows: + path = () + id_path = [] + for node in row: + path += (node,) + id_path.append(model.on_get_iter(path).id) + id_paths.append(id_path) + return id_paths + + def select_nodes(self, nodes): + selection = self.widget_tree.get_selection() + if not nodes: + return + selection.unselect_all() + scroll = False + for node in nodes: + path = path_convert_id2pos(self.store, node) + if path: + selection.select_path(path) + if not scroll: + self.widget_tree.scroll_to_cell(path) + scroll = True + def get_expanded_paths(self, starting_path=None, starting_id_path=None): # Use id instead of position # because the position may change between load diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index 8c0505b506..163e3a0e59 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -108,7 +108,6 @@ class ParserTree(ParserInterface): treeview.sequence = attrs.get('sequence', False) treeview.colors = attrs.get('colors', '"black"') treeview.keyword_open = attrs.get('keyword_open', False) - treeview.connect('focus', self.set_selection) self.treeview = treeview treeview.set_property('rules-hint', True) if not self.title: @@ -296,12 +295,6 @@ class ParserTree(ParserInterface): treeview.set_fixed_height_mode(True) return treeview, dict_widget, state_widgets, on_write, [], None - def set_selection(self, treeview, direction): - selection = treeview.get_selection() - if len(treeview.get_model()) and not selection.count_selected_rows(): - selection.select_path(0) - return False - class Affix(object): diff --git a/tryton/gui/window/win_search.py b/tryton/gui/window/win_search.py index 0f901d4cbc..388b1e0ba8 100644 --- a/tryton/gui/window/win_search.py +++ b/tryton/gui/window/win_search.py @@ -58,6 +58,8 @@ class WinSearch(NoModal): row_activate=self.sig_activate) self.view = self.screen.current_view self.view.unset_editable() + # Prevent to set tree_state + self.screen.tree_states_done.add(id(self.view)) sel = self.view.widget_tree.get_selection() if not sel_multi: