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, 3 years 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.