source: lliurex-store/trunk/fuentes/lliurex-store-gui/usr/share/lliurex-store/lliurex-store-gui/MainWindow.py @ 7440

Last change on this file since 7440 was 7440, checked in by hectorgh, 20 months ago

fixing scrolled windows and character width limit in pkg results when searching

File size: 14.0 KB
Line 
1import gi
2gi.require_version('Gtk', '3.0')
3from gi.repository import Gtk, Pango, GdkPixbuf, Gdk, Gio, GObject,GLib
4
5import Core
6import Package
7
8import threading
9import multiprocessing
10import time
11
12import gettext
13gettext.textdomain('lliurex-store')
14_ = gettext.gettext
15
16import signal
17signal.signal(signal.SIGINT, signal.SIG_DFL)
18
19
20class MainWindow:
21       
22        def __init__(self):
23               
24                self.core=Core.Core.get_core()
25                self.load_thread=threading.Thread()
26                self.search_process=multiprocessing.Process()
27                self.thread_aborted=False
28                self.search_aborted=False
29                self.last_search=""
30                self.path_followed=["main"]
31                self.load_gui()
32               
33        #def init
34       
35       
36        # ### MAIN UI FUNCTIONS # ####################
37       
38        def load_gui(self):
39               
40                builder=Gtk.Builder()
41                builder.set_translation_domain('lliurex-store')
42                ui_path=self.core.ui_path
43                builder.add_from_file(ui_path)
44               
45                self.window=builder.get_object("window1")
46                self.menu_button=builder.get_object("menu_button")
47               
48                self.main_scroll=builder.get_object("main_scrolledwindow")
49                self.location_label=builder.get_object("location_label")
50                self.search_entry=builder.get_object("search_entry")
51                self.main_box=builder.get_object("main_box")
52                self.header_box=builder.get_object("header_box")
53                self.go_back_button=builder.get_object("go_back_button")
54               
55               
56               
57                self.main_menu=self.core.main_menu
58                self.loading_box=self.core.loading_box
59                self.details_box=self.core.details_box
60                self.popup_menu=self.core.popup_menu
61                self.screenshot_viewer=self.core.screenshot_viewer
62                self.search_box=self.core.search_box
63               
64                self.stack=Gtk.Stack()
65                self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
66                self.stack.set_transition_duration(500)
67               
68                self.stack.add_titled(self.loading_box,"loading","Loading")
69                self.stack.add_titled(self.main_menu,"main","Main")
70                self.stack.add_titled(self.details_box,"details","Details")
71                self.stack.add_titled(self.search_box,"search","Search")
72                self.main_scroll.add(self.stack)
73       
74                self.overlay=Gtk.Overlay()
75                self.main_eb=Gtk.EventBox()
76                self.main_eb.add(self.main_box)
77               
78                self.main_eb.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
79                self.main_eb.connect("button-press-event",self.main_eb_clicked)
80               
81                self.overlay.add(self.main_eb)
82                self.overlay.show_all()
83               
84                self.fade_box_revealer=Gtk.Revealer()
85                self.fade_box_revealer.set_valign(Gtk.Align.END)
86                self.fade_box_revealer.set_halign(Gtk.Align.END)
87               
88                self.fade_box=Gtk.HBox()
89                self.fade_eb=Gtk.EventBox()
90                self.fade_eb.add(self.fade_box)
91                self.fade_eb.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
92                self.fade_eb.connect("button-press-event",self.main_eb_clicked)
93               
94                self.fade_box_revealer.set_transition_type(Gtk.RevealerTransitionType.SLIDE_UP)
95                self.fade_box_revealer.set_transition_duration(self.popup_menu.revealer.get_transition_duration())
96                self.fade_box_revealer.add(self.fade_eb)
97                self.fade_box_revealer.show_all()
98               
99               
100                self.overlay.add_overlay(self.fade_box_revealer)
101                self.overlay.add_overlay(self.popup_menu)
102                self.overlay.add_overlay(self.screenshot_viewer)
103
104                self.window.add(self.overlay)
105               
106                self.connect_signals()
107                self.set_css_info()
108                self.build_home()
109               
110                self.window.show_all()
111               
112        #def load_gui
113
114       
115        def set_css_info(self):
116               
117                self.style_provider=Gtk.CssProvider()
118                f=Gio.File.new_for_path(self.core.rsrc_dir+"lliurex-store.css")
119                self.style_provider.load_from_file(f)
120                Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),self.style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
121               
122                self.window.set_name("MAIN_BOX")
123                self.header_box.set_name("HEADER_MENU")
124                self.menu_button.set_name("MENU_BUTTON")
125                self.location_label.set_name("RELATED_LABEL")
126                self.fade_box.set_name("FADE_BOX")
127                self.go_back_button.set_name("BACK_BUTTON")
128               
129        #def set-css_info       
130
131       
132        def connect_signals(self):
133               
134                self.window.connect("size-allocate",self.window_size_changed)
135                self.window.connect("destroy",Gtk.main_quit)
136                self.menu_button.connect("clicked",self.menu_button_clicked)
137                self.search_entry.connect("changed",self.search_entry_changed)
138                self.search_entry.connect("activate",self.entries_press_event)
139                self.go_back_button.connect("clicked",self.go_back)
140               
141        #def connect_signals
142       
143       
144        def start_gui(self):
145               
146                GObject.threads_init()
147                Gtk.main()
148               
149        #def start_gui
150
151        # #################################################### ##
152
153
154
155        # #### STACK FAST ACCESS FUNCTIONS # #################
156       
157        def go_back(self,widget=None):
158               
159                if len(self.path_followed)>1:
160                       
161                       
162                        current_txt=self.location_label.get_text().split(" > ")
163                        current_txt=" > ".join(current_txt[0:-1])
164                        self.location_label.set_text(current_txt)
165                        dest=self.path_followed[-2]
166                        self.stack.set_visible_child_name(dest)
167                        self.path_followed.pop(-1)
168                        self.main_scroll.get_vadjustment().set_value(0)
169                        self.core.search_box.search_sw.get_vadjustment().set_value(0)
170                       
171                        if dest=="main":
172                                self.search_entry.set_text("")
173               
174        #def go_back
175       
176       
177        def show_loading(self):
178               
179                self.stack.set_visible_child_name("loading")
180               
181        #def show_loading
182
183
184        def show_details_box(self):
185               
186                self.thread_aborted=True
187                self.search_aborted=True
188                current_txt=self.location_label.get_text()
189                if self.path_followed[-1]!="details":
190                        self.location_label.set_text(current_txt + " > " + _("Details"))
191                        self.path_followed.append("details")
192                self.stack.set_visible_child_name("details")
193               
194        #def show_details_box
195
196
197        def show_home(self):
198               
199                self.thread_aborted=True
200                self.search_aborted=True
201               
202                self.search_entry.set_text("")
203                self.location_label.set_text(_("Home"))
204                self.path_followed=["main"]
205                self.stack.set_visible_child_name("main")
206               
207        #def show_details_box
208       
209       
210        def show_search_results(self,category=None):
211               
212                current_txt=self.location_label.get_text()
213               
214                if category==None:
215                        category=_("Search")
216               
217                if self.path_followed[-1]=="details":
218                        self.path_followed.pop(-1)
219                        current_txt=" > ".join(current_txt.split(" > ")[0:-1])
220               
221                if self.path_followed[-1]=="search":
222                        current_txt="".join(current_txt.split(" > ")[0:-1])
223                else:
224                        self.path_followed.append("search")
225                       
226                self.location_label.set_text(current_txt + " > " + category)
227                self.stack.set_visible_child_name("search")
228               
229        #def show_search_results
230       
231        # ############################################
232
233
234
235        # ### HOME LOADING FUNCTIONS # ##############
236       
237        def build_home(self):
238               
239                self.load_thread=threading.Thread(target=self.download_home_info_thread)
240                self.load_thread.daemon=True
241                self.load_thread.start()
242               
243                GLib.timeout_add(500,self.build_home_listener)
244               
245        #def build_home
246
247
248        def build_home_listener(self):
249               
250                if self.thread_aborted:
251                        self.thread_aborted=False
252                        return False
253               
254               
255                if self.load_thread.is_alive():
256                        return True
257               
258                self.main_menu.build_banners()
259                self.show_home()
260                return False
261               
262        #def load_home
263
264       
265        def download_home_info_thread(self):
266               
267                self.main_menu.download_home_info()
268
269        #def load_home_thread
270       
271        # #################################
272
273       
274       
275        # ### LOAD PKG FUNCTIONS # ##################
276       
277       
278        def set_pkg_data(self,pkg):
279               
280                self.current_pkg=Package.Package(pkg)
281                self.details_box.set_package_info(self.current_pkg)
282                self.show_details_box()
283               
284        #def set_data
285       
286       
287        def load_pkg_data(self,pkg_id,pkg_data=None):
288               
289                self.current_pkg=None
290                self.thread_aborted=False
291                self.load_thread=threading.Thread(target=self.load_pkg_data_thread,args=(pkg_id,))
292                self.load_thread.daemon=True
293                self.load_thread.start()
294                self.show_loading()
295                GLib.timeout_add(500,self.load_pkg_listener)
296               
297        #def load_pkg_data
298       
299       
300        def load_pkg_data_thread(self,pkg_id):
301               
302                self.current_pkg=self.core.store.get_info(pkg_id)
303                       
304        #def load_pkg_data_thread
305       
306       
307        def load_pkg_listener(self):
308               
309                if self.thread_aborted:
310                        self.thread_aborted=False
311                        return False
312               
313                if self.load_thread.is_alive():
314                        return True
315                       
316                if self.current_pkg!=None:
317                        self.details_box.set_package_info(self.current_pkg)
318                        self.show_details_box()
319               
320                return False
321               
322        #def load_pkg_listener
323       
324        # #################################
325
326
327        # ## SEARCH FUNCTIONS ######################
328       
329       
330        def entries_press_event(self,widget):
331               
332                self.last_search=None
333                self.search_entry_changed(None)
334               
335        #def entries_press_event
336       
337       
338        def search_entry_changed(self,widget):
339               
340                txt=self.search_entry.get_text()
341                current_stack=self.stack.get_visible_child_name()
342                txt=txt.strip(" ")
343               
344                if self.last_search!=txt:
345                        self.last_search=txt
346                else:
347                        return
348               
349                if len(txt)==0:
350                        self.show_home()
351                        return
352                       
353                if len(txt)>2:
354                        self.search_aborted=False
355                        self.show_loading()
356                        self.search_package(txt)
357               
358        #def search_entry_changed
359       
360       
361        def search_package(self,pkg_id):
362               
363                if self.search_process.is_alive():
364                        self.search_process.terminate()
365               
366                self.current_search_id=self.core.get_random_id()
367                self.counter=0
368                self.search_queue=multiprocessing.Queue()
369                self.search_process=multiprocessing.Process(target=self.search_package_thread,args=(pkg_id,self.search_queue,))
370               
371                self.search_process.daemon=True
372                self.search_process.start()
373               
374                GLib.timeout_add(500, self.search_listener,self.current_search_id)
375               
376        #def search_package
377       
378       
379        def search_package_thread(self,pkg_id,search_queue):
380               
381                ret=self.core.store.search_package(pkg_id)
382                self.core.dprint("Search complete")
383                search_queue.put(ret)
384               
385        #def search_package_thread
386       
387       
388        def search_listener(self,search_id):
389               
390                if self.current_search_id!=search_id:
391                        return False
392               
393                if self.search_aborted:
394                        self.core.dprint("Search aborted [!]")
395                        self.thread_aborted=False
396                        return False
397               
398                if self.search_process.is_alive():
399                        self.counter+=1
400                       
401                        if self.search_queue.empty():
402                                return True
403                       
404                search_result=self.search_queue.get()
405               
406                if search_result!=None:
407                        self.core.search_box.populate_search_results(search_result)
408                        self.show_search_results()
409               
410                return False
411               
412        #def search_listener
413       
414
415        # ########################################
416       
417        # ### SEARCH CATEGORIES #### #
418       
419        def search_category(self,category):
420       
421                if self.search_process.is_alive():
422                        self.search_process.terminate()
423       
424
425                self.search_aborted=False
426                self.show_loading()
427               
428                self.current_search_id=self.core.get_random_id()
429                self.counter=0
430                self.search_queue=multiprocessing.Queue()
431                self.search_process=multiprocessing.Process(target=self.search_category_thread,args=(category,self.search_queue,))
432               
433                self.search_process.daemon=True
434                self.search_process.start()
435               
436                GLib.timeout_add(500, self.search_category_listener,self.current_search_id)
437       
438        #def search_category
439       
440       
441        def search_category_thread(self,category,search_queue):
442               
443                ret=self.core.store.get_package_list_from_category(category)
444                self.core.dprint("Search complete")
445                search_queue.put(ret)
446               
447        #def search_package_thread
448       
449       
450        def search_category_listener(self,search_id):
451               
452                if self.current_search_id!=search_id:
453                        return False
454               
455                if self.search_aborted:
456                        self.core.dprint("Search aborted [!]")
457                        self.thread_aborted=False
458                        return False
459               
460                if self.search_process.is_alive():
461                        self.counter+=1
462                       
463                        if self.search_queue.empty():
464                                return True
465                       
466                search_result=self.search_queue.get()
467               
468                if search_result!=None:
469                       
470                        search_result,categories=search_result
471                        self.core.search_box.populate_search_results(search_result,categories)
472                        self.show_search_results(self.core.search_box.current_category)
473               
474                return False
475               
476        #def search_listener
477       
478       
479       
480        # ########################
481       
482       
483        # ## INSTALLED LIST QUERY ## #
484       
485       
486        def get_installed_list(self):
487               
488                if self.search_process.is_alive():
489                        self.search_process.terminate()
490               
491                self.search_aborted=False
492                self.show_loading()
493               
494                self.current_search_id=self.core.get_random_id()
495                self.counter=0
496                self.search_queue=multiprocessing.Queue()
497                self.search_process=multiprocessing.Process(target=self.get_installed_list_thread,args=(self.search_queue,))
498               
499                self.search_process.daemon=True
500                self.search_process.start()
501               
502                GLib.timeout_add(500, self.search_listener,self.current_search_id)
503               
504        #def search_package
505       
506       
507        def get_installed_list_thread(self,search_queue):
508               
509                ret=self.core.store.get_installed_list()
510                self.core.dprint("Search complete")
511                search_queue.put(ret)
512
513        #def search_package_thread
514       
515       
516        # ##################### #
517       
518       
519       
520
521        # ## SCREENSHOTVIEWER FUNCTIONS ## ##############
522       
523        def window_size_changed(self,widget,allocation):
524               
525                x,y=self.window.get_size()
526                self.popup_menu.popup_menu.set_size_request(400,y)
527                self.screenshot_viewer.content_box.set_size_request(x,y)
528                self.screenshot_viewer.sw.set_size_request(x-20,150)
529                self.fade_box.set_size_request(x,y)
530               
531        #def window_size_allocation
532
533
534        def screenshot_clicked(self,widget):
535
536                if widget.get_children()[0].get_visible_child_name()=="image":
537                       
538                        if self.popup_menu.revealer.get_reveal_child():
539                                self.popup_menu.revealer.set_reveal_child(False)
540                                return
541                       
542                        if widget.get_children()[0].image_info["video_url"]==None:
543                                self.screenshot_viewer.set_screenshot(widget.get_children()[0].image_info["image_id"],self.details_box.screenshots_box)
544                        else:
545                                self.screenshot_viewer.set_screenshot(widget.get_children()[0].image_info["video_url"],self.details_box.screenshots_box,True)
546                               
547                        self.screenshot_viewer.revealer.set_reveal_child(True)
548                       
549                       
550        #def screenshot_clicked
551       
552        # ####################################### #
553
554
555
556        # ## POPUP MENU FUNCTIONS # #####################
557
558        def main_eb_clicked(self,widget,event):
559               
560                if self.popup_menu.revealer.get_reveal_child():
561                        self.popup_menu.revealer.set_reveal_child(False)
562                       
563                if self.fade_box_revealer.get_reveal_child():
564                        self.fade_box_revealer.set_transition_type(Gtk.RevealerTransitionType.CROSSFADE)
565                        GLib.timeout_add(30,self.check_fade_out)
566                        self.fade_box_revealer.set_reveal_child(False)
567                       
568        #def main_eb_clicked
569
570       
571        def menu_button_clicked(self,widget):
572               
573                self.fade_box_revealer.set_transition_type(Gtk.RevealerTransitionType.CROSSFADE)
574                self.popup_menu.revealer.set_reveal_child(not self.popup_menu.revealer.get_reveal_child())
575                self.fade_box_revealer.set_reveal_child(True)
576               
577        #def menu_button_clicked
578
579
580        def check_fade_out(self):
581               
582                if self.fade_box_revealer.get_child_revealed():
583                        return True
584                       
585                self.fade_box_revealer.set_transition_type(Gtk.RevealerTransitionType.SLIDE_UP)
586               
587        #def check_fade_out
588       
589        # ########################################## #
590       
591
592
593       
594       
595       
596#class LliurexStore
597
598if __name__=="__main__":
599       
600        llx_store=LliurexStore()
Note: See TracBrowser for help on using the repository browser.