FINALLY
[appstream:software-center.git] / softwarecenter / ui / gtk3 / session / viewmanager.py
1 # Copyright (C) 2010 Canonical
2 #
3 # Authors:
4 #  Michael Vogt
5 #
6 # This program is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free Software
8 # Foundation; version 3.
9 #
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13 # details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19 from gi.repository import Gtk, GObject
20
21 from navhistory import NavigationHistory, NavigationItem
22 from softwarecenter.ui.gtk3.widgets.backforward import BackForwardButton
23 from softwarecenter.ui.gtk3.widgets.searchentry import SearchEntry
24
25
26 _viewmanager = None  # the global Viewmanager instance
27
28
29 def get_viewmanager():
30     return _viewmanager
31
32
33 class ViewManager(GObject.GObject):
34
35     __gsignals__ = {
36         "view-changed": (GObject.SignalFlags.RUN_LAST,
37                          None,
38                          (GObject.TYPE_PYOBJECT, ),
39                         ),
40     }
41
42     def __init__(self, notebook_view, options=None):
43         GObject.GObject.__init__(self)
44         self.notebook_view = notebook_view
45         self.search_entry = SearchEntry()
46         self.search_entry.connect(
47             "terms-changed", self.on_search_terms_changed)
48         self.search_entry.connect(
49             "key-press-event", self.on_search_entry_key_press_event)
50
51         self.back_forward = BackForwardButton()
52         self.back_forward.connect(
53             "left-clicked", self.on_nav_back_clicked)
54         self.back_forward.connect(
55             "right-clicked", self.on_nav_forward_clicked)
56
57         self.navhistory = NavigationHistory(self.back_forward, options)
58         self.spinner = Gtk.Spinner()
59
60         self.all_views = {}
61         self.view_to_pane = {}
62         self._globalise_instance()
63
64     def _globalise_instance(self):
65         global _viewmanager
66         if _viewmanager is not None:
67             msg = "Only one instance of ViewManager is allowed!"
68             raise ValueError(msg)
69         else:
70             _viewmanager = self
71
72     def destroy(self):
73         """Destroy the global instance."""
74         global _viewmanager
75         _viewmanager = None
76
77     def on_search_terms_changed(self, widget, new_text):
78         pane = self.get_current_view_widget()
79         if hasattr(pane, "on_search_terms_changed"):
80             pane.on_search_terms_changed(widget, new_text)
81
82     def on_nav_back_clicked(self, widget):
83         pane = self.get_current_view_widget()
84         if hasattr(pane, "on_nav_back_clicked"):
85             pane.on_nav_back_clicked(widget)
86
87     def on_nav_forward_clicked(self, widget):
88         pane = self.get_current_view_widget()
89         if hasattr(pane, "on_nav_forward_clicked"):
90             pane.on_nav_forward_clicked(widget)
91
92     def on_search_entry_key_press_event(self, widget, event):
93
94         pane = self.get_current_view_widget()
95         if hasattr(pane, "on_search_entry_key_press_event"):
96             pane.on_search_entry_key_press_event(event)
97
98     def register(self, pane, view_id):
99         page_id = self.notebook_view.append_page(
100             pane,
101             Gtk.Label.new("View %s" % view_id))  # label is for debugging only
102         self.all_views[view_id] = page_id
103         self.view_to_pane[view_id] = pane
104
105     def get_current_view_widget(self):
106         current_view = self.get_active_view()
107         return self.get_view_widget(current_view)
108
109     def get_view_id_from_page_id(self, page_id):
110         for (k, v) in self.all_views.items():
111             if page_id == v:
112                 return k
113
114     def set_spinner_active(self, active):
115         if active:
116             self.spinner.show()
117             self.spinner.start()
118         else:
119             self.spinner.stop()
120             self.spinner.hide()
121
122     def set_active_view(self, view_id):
123         # no views yet
124         if not self.all_views:
125             return
126         # if the view switches, ensure that the global spinner is hidden
127         self.spinner.hide()
128
129         # emit signal
130         self.emit('view-changed', view_id)
131         page_id = self.all_views[view_id]
132         view_widget = self.get_view_widget(view_id)
133
134         # it *seems* that this shouldn't be called here if we want the history
135         # to work, but I'm not familiar with the code, so I'll leave it here
136         # for the mean time
137 #        view_page = view_widget.get_current_page()
138 #        view_state = view_widget.state
139
140         if (self.search_entry.get_text() !=
141             view_widget.state.search_term):
142             self.search_entry.set_text_with_no_signal(
143                                         view_widget.state.search_term)
144
145 #        callback = view_widget.get_callback_for_page(view_page,
146 #                                                     view_state)
147
148 #        nav_item = NavigationItem(self, view_widget, view_page,
149 #                                  view_state.copy(), callback)
150 #        self.navhistory.append(nav_item)
151
152         self.notebook_view.set_current_page(page_id)
153         if view_widget:
154             view_widget.init_view()
155         return view_widget
156
157     def get_active_view(self):
158         page_id = self.notebook_view.get_current_page()
159         return self.get_view_id_from_page_id(page_id)
160
161     def is_active_view(self, view_id):
162         return view_id == self.get_active_view()
163
164     def get_notebook_page_from_view_id(self, view_id):
165         return self.all_views[view_id]
166
167     def get_view_widget(self, view_id):
168         return self.view_to_pane.get(view_id, None)
169
170     def get_latest_nav_item(self):
171         return self.navhistory.stack[-1]
172
173     def display_page(self, pane, page, view_state, callback=None):
174         # if previous page is a list view, then store the scroll positions
175         if self.navhistory.stack:
176             ni = self.navhistory.stack[self.navhistory.stack.cursor]
177             if ni.pane.is_applist_view_showing():
178                 v = ni.pane.app_view.tree_view_scroll.get_vadjustment()
179                 ni.view_state.vadjustment = v.get_value()
180
181         if callback is None:
182             callback = pane.get_callback_for_page(page, view_state)
183
184         nav_item = NavigationItem(self, pane, page,
185                                   view_state.copy(), callback)
186
187         self.navhistory.append(nav_item)
188
189         text = view_state.search_term
190         if text != self.search_entry.get_text():
191             self.search_entry.set_text_with_no_signal(text)
192
193         pane.state = view_state
194         if callback is not None:
195             callback(page, view_state)
196
197         if page is not None:
198             pane.notebook.set_current_page(page)
199
200         if self.get_current_view_widget() != pane:
201             view_id = None
202             for view_id, widget in self.view_to_pane.items():
203                 if widget == pane:
204                     break
205
206             self.set_active_view(view_id)
207
208         if (not pane.searchentry or
209             (hasattr(pane, 'Pages') and
210              hasattr(pane.Pages, 'DETAILS') and
211              page == pane.Pages.DETAILS) or
212             (hasattr(pane, 'Pages') and
213              hasattr(pane.Pages, 'PURCHASE') and
214              page == pane.Pages.PURCHASE)):
215             self.search_entry.hide()
216         else:
217             self.search_entry.show()
218             self.spinner.hide()
219
220     def nav_back(self):
221         self.navhistory.nav_back()
222
223     def nav_forward(self):
224         self.navhistory.nav_forward()
225
226     def clear_forward_history(self):
227         self.navhistory.clear_forward_history()
228
229     def get_global_searchentry(self):
230         return self.search_entry
231
232     def get_global_backforward(self):
233         return self.back_forward
234
235     def get_global_spinner(self):
236         return self.spinner