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

Last change on this file since 8187 was 8187, checked in by hectorgh, 15 months ago

search related by threads

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