1 # Copyright (C) 2009 Canonical
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; either version 2 of the License, or (at your option) any later
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 # You should have received a copy of the GNU General Public License along with
17 # this program; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 from SimpleGtkbuilderApp import SimpleGtkbuilderApp
28 from view.appview import AppView, AppStore, AppViewFilter
29 from view.catview import CategoriesView
30 from view.viewswitcher import ViewSwitcher, ViewSwitcherList
31 from view.appdetailsview import AppDetailsView
32 from view.pendingview import PendingView
34 from gettext import gettext as _
36 XAPIAN_BASE_PATH = "/var/cache/app-center"
37 APP_INSTALL_PATH = "/usr/share/app-install"
38 ICON_PATH = APP_INSTALL_PATH+"/icons/"
40 class AppCenter(SimpleGtkbuilderApp):
42 (NOTEBOOK_PAGE_CATEGORIES,
43 NOTEBOOK_PAGE_APPLIST,
44 NOTEBOOK_PAGE_APP_DETAILS,
45 NOTEBOOK_PAGE_PENDING) = range(4)
47 DEFAULT_SEARCH_APPS_LIMIT = 200
49 def __init__(self, datadir):
50 SimpleGtkbuilderApp.__init__(self, datadir+"/ui/AppCenter.ui")
53 xapian_base_path = XAPIAN_BASE_PATH
54 pathname = os.path.join(xapian_base_path, "xapian")
55 self.xapiandb = xapian.Database(pathname)
56 self.xapian_parser = xapian.QueryParser()
57 self.xapian_parser.set_database(self.xapiandb)
58 self.xapian_parser.add_boolean_prefix("pkg", "AP")
59 #self.xapian_parser.add_boolean_prefix("section", "AS")
61 # additional icons come from app-install-data
62 self.icons = gtk.icon_theme_get_default()
63 self.icons.append_search_path(ICON_PATH)
66 # FIXME: progress or thread
67 self.cache = apt.Cache()
70 self.view_switcher = ViewSwitcher()
71 self.scrolledwindow_viewswitcher.add(self.view_switcher)
72 self.view_switcher.show()
73 self.view_switcher.connect("row-activated",
74 self.on_view_switcher_activated)
77 self.cat_view = CategoriesView(APP_INSTALL_PATH, self.xapiandb, self.icons)
78 self.scrolledwindow_categories.add(self.cat_view)
80 self.cat_view.connect("item-activated", self.on_category_activated)
83 empty_store = gtk.ListStore(gtk.gdk.Pixbuf, str)
84 self.app_view = AppView(empty_store)
85 self.app_view.connect("row-activated", self.on_app_activated)
86 self.scrolledwindow_applist.add(self.app_view)
90 self.pending_view = PendingView(self.icons)
91 self.scrolledwindow_transactions.add(self.pending_view)
94 self.app_details_view = AppDetailsView(self.xapiandb, self.icons, self.cache)
95 self.scrolledwindow_app_details.add(self.app_details_view)
96 self.app_details_view.show()
99 self.entry_search.connect("changed", self.on_entry_search_changed)
102 self.apps_filter = AppViewFilter(self.cache)
103 self.apps_category_query = None
104 self.apps_search_query = None
105 self.apps_sorted = True
109 self.entry_search.grab_focus()
112 def get_query_from_search_entry(self, search_term):
113 """ get xapian.Query from a search term string """
114 query = self.xapian_parser.parse_query(search_term,
115 xapian.QueryParser.FLAG_PARTIAL)
116 # FIXME: expand to add "AA" and "AP" before each search term?
120 def add_navigation_button(self, name, callback, type):
121 self.remove_navigation_button(type)
122 button = gtk.Button()
123 button.set_label(name)
125 button.connect("clicked", callback)
126 button.set_data("navigation-type", type)
127 self.hbox_navigation_buttons.pack_start(button, expand=False)
129 def remove_navigation_buttons(self):
130 for w in self.hbox_navigation_buttons:
131 self.hbox_navigation_buttons.remove(w)
133 def remove_navigation_button(self, type):
134 for w in self.hbox_navigation_buttons:
135 if w.get_data("navigation-type") == type:
136 self.hbox_navigation_buttons.remove(w)
139 def on_menuitem_close_activate(self, widget):
142 def on_menuitem_about_activate(self, widget):
144 # FIXME: add once we have a name
146 def on_menuitem_view_all_activate(self, widget):
147 print "on_menuitem_view_all_activate", widget
148 self.apps_filter.set_supported_only(False)
151 def on_menuitem_view_canonical_activate(self, widget):
152 print "on_menuitem_view_canonical_activate", widget
153 self.apps_filter.set_supported_only(True)
156 def on_button_home_clicked(self, widget):
157 logging.debug("on_button_home_clicked")
158 self.apps_category_query = None
159 self.remove_navigation_buttons()
160 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_CATEGORIES)
162 def on_entry_search_changed(self, widget):
163 self.remove_navigation_button("search")
164 new_text = widget.get_text()
165 logging.debug("on_entry_changed: %s" % new_text)
168 self.apps_sorted = True
169 self.apps_search_query = None
171 self.apps_search_query = self.get_query_from_search_entry(new_text)
172 self.apps_sorted = False
173 self.apps_limit = self.DEFAULT_SEARCH_APPS_LIMIT
174 self.add_navigation_button(_("Search"),
175 self.on_navigation_button_category,
178 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_APPLIST)
180 def on_button_search_entry_clear_clicked(self, widget):
181 self.entry_search.set_text("")
183 def on_view_switcher_activated(self, view_switcher, row, column):
184 logging.debug("view_switcher_activated")
185 model = view_switcher.get_model()
186 action = model[row][ViewSwitcherList.COL_ACTION]
187 if action == ViewSwitcherList.ACTION_ITEM_AVAILABLE:
188 logging.debug("show available")
189 if self.notebook_view.get_current_page() == self.NOTEBOOK_PAGE_PENDING:
190 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_CATEGORIES)
191 self.apps_filter.set_installed_only(False)
193 elif action == ViewSwitcherList.ACTION_ITEM_INSTALLED:
194 logging.debug("show installed")
195 if self.notebook_view.get_current_page() == self.NOTEBOOK_PAGE_PENDING:
196 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_CATEGORIES)
197 self.apps_filter.set_installed_only(True)
199 elif action == ViewSwitcherList.ACTION_ITEM_PENDING:
200 logging.debug("show pending")
201 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_PENDING)
203 assert False, "Not reached"
205 def on_navigation_button_category(self, widget):
206 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_APPLIST)
208 def on_navigation_button_app_details(self, widget):
209 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_APP_DETAILS)
211 def on_app_activated(self, app_view, path, column):
212 (name, icon) = app_view.get_model()[path]
214 self.app_details_view.show_app(name)
215 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_APP_DETAILS)
216 # add navigation button
217 self.add_navigation_button(name, self.on_navigation_button_app_details, "app")
219 def on_category_activated(self, cat_view, path):
220 (name, pixbuf, query) = cat_view.get_model()[path]
221 self.apps_category_query = query
224 self.notebook_view.set_current_page(self.NOTEBOOK_PAGE_APPLIST)
225 # update navigation bar
226 self.add_navigation_button(name, self.on_navigation_button_category, "category")
229 def refresh_apps(self):
231 if self.apps_category_query and self.apps_search_query:
232 query = xapian.Query(xapian.Query.OP_AND,
233 self.apps_category_query,
234 self.apps_search_query)
235 elif self.apps_category_query:
236 query = self.apps_category_query
237 elif self.apps_search_query:
238 query = self.apps_search_query
242 # create new model and attach it
243 new_model = AppStore(self.xapiandb,
246 limit=self.apps_limit,
247 sort=self.apps_sorted,
248 filter=self.apps_filter)
249 self.app_view.set_model(new_model)
250 id = self.statusbar_main.get_context_id("items")
251 self.statusbar_main.push(id, _("%s items available") % len(new_model))
255 self.window_main.show_all()
256 SimpleGtkbuilderApp.run(self)