source: lliurex-up/trunk/fuentes/lliurex-up-gui/lliurex-up @ 2673

Last change on this file since 2673 was 2673, checked in by jrpelegrina, 3 years ago

WIP in GUI

File size: 14.7 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import gi
5gi.require_version('Gtk', '3.0')
6gi.require_version('PangoCairo', '1.0')
7gi.require_version('Vte', '2.91')
8
9import cairo
10import os
11import threading
12import ConfigParser
13import platform
14import subprocess
15import sys
16import time
17
18from gi.repository import Gtk, Gdk, GdkPixbuf, GObject, GLib, PangoCairo, Pango, Vte
19
20import signal
21signal.signal(signal.SIGINT, signal.SIG_DFL)
22
23import gettext
24gettext.textdomain('lliurex-up')
25_ = gettext.gettext
26
27
28
29RSRC_DIR="rsrc/"
30CACHED_ICON="rsrc/cached.png"
31DONE_ICON="rsrc/done.png"
32ERROR_ICON="rsrc/error.png"
33
34class Package:
35
36        def __init__(self,name,version,size,desktop_file,changelog_file):
37
38                self.name=name
39                self.version=version
40                self.size=size
41                self.parse_desktop(desktop_file)
42                self.parse_changelog(changelog_file)
43                self.parse_installed(CACHED_ICON)
44
45        def parse_desktop(self,desktop_file):
46               
47                try:
48                        config = ConfigParser.ConfigParser()
49                        config.optionxform=str
50                        config.read(desktop_file)
51                       
52                        if config.has_section("Desktop Entry") and config.has_option("Desktop Entry","Icon"):
53                                self.icon=config.get("Desktop Entry","Icon")
54                        else:
55                                self.icon="package"
56                               
57                except Exception as e:
58                       
59                        self.icon="package"
60                       
61
62        def parse_changelog(self,changelog_file):
63               
64                try:
65                       
66                        f=open(changelog_file,"r")
67                        self.changelog=f.readlines()
68                        f.close()
69                                               
70                except Exception as e:
71                       
72                        self.changelog="Changelog not found"
73
74        def parse_installed(self, icon_file):
75                        image=Gtk.Image()
76                        image.set_from_file(icon_file)         
77                        self.installed=image.get_pixbuf()
78
79
80class LliurexUp:
81
82        def __init__(self):
83
84
85                self.start_gui()
86
87        def start_gui(self):
88               
89                builder=Gtk.Builder()
90               
91                glade_path=RSRC_DIR+"lliurex-up.ui"
92                builder.add_from_file(glade_path)
93
94                self.stack = Gtk.Stack()
95                self.stack.set_transition_duration(1000)
96                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
97
98
99                self.window=builder.get_object("main_window")
100                self.main_box=builder.get_object("main_box")
101                self.pbar=builder.get_object("progressbar")
102                self.pbar_label=builder.get_object("progressbar_label")
103               
104
105                self.cancel_button_box=builder.get_object("cancel_button_box")
106                self.cancel_eb=builder.get_object("cancel_button_eventbox")
107                self.cancel_eb.connect("button-press-event", self.quit)
108                self.cancel_label=builder.get_object("cancel_button_label")
109
110
111                self.gather_box=builder.get_object("gather_box")
112                self.yes_button_box=builder.get_object("yes_button_box")
113                self.yes_button_label=builder.get_object("yes_button_label")
114                self.no_button_box=builder.get_object("no_button_box")
115                self.no_button_eb=builder.get_object("no_button_eventbox")
116                self.no_button_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
117                self.no_button_eb.connect("button-release-event", self.no_button_clicked)
118                self.no_button_label=builder.get_object("no_button_label")
119                self.gather_logo_box=builder.get_object("gather_logo_box")
120                self.gather_label=builder.get_object("gather_label")
121
122                self.update_box=builder.get_object("update_box")
123                self.version_available_label=builder.get_object("version_available_label")
124                self.version_update_label=builder.get_object("version_update_label")
125                self.number_packages_label=builder.get_object("number_packages_label")
126                self.size_update_label=builder.get_object("size_update_label")
127                self.view_packages_button_box=builder.get_object("view_packages_button_box")
128                self.view_packages_eb=builder.get_object("view_packages_eventbox")
129                self.view_packages_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
130                self.view_packages_eb.connect("button-release-event", self.view_packages_clicked)
131                self.view_packages_label=builder.get_object("view_packages_label")
132
133                self.update_button_box=builder.get_object("update_button_box")
134                self.update_button_eb=builder.get_object("update_button_eventbox")
135                self.update_button_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
136                self.update_button_eb.connect("button-release-event", self.install_packages)
137                self.update_button_label=builder.get_object("update_button_label")
138                self.terminal_label=builder.get_object("terminal_label")
139                self.viewport=builder.get_object("viewport")
140                self.terminal_scrolled=builder.get_object("terminalScrolledWindow")
141                self.vterminal=Vte.Terminal()
142                font_terminal = Pango.FontDescription("monospace normal 10")
143                self.vterminal.set_font(font_terminal)
144                self.terminal_scrolled.add(self.vterminal)
145               
146
147                self.packages_box=builder.get_object("packages_box")
148                self.return_arrow_box=builder.get_object("return_arrow_box")
149                self.return_arrow_eb=builder.get_object("return_arrow_eventbox")
150                self.return_arrow_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
151                self.return_arrow_eb.connect("button-release-event", self.arrow_clicked)
152                self.packages_label=builder.get_object("packages_label")
153                self.packages_tv=builder.get_object("packages_treeview")
154                self.changelog_texview=builder.get_object("changelog_textview")
155
156                self.packages_store=Gtk.ListStore(str,str,str,GdkPixbuf.Pixbuf)
157                self.packages_tv.set_model(self.packages_store)
158                column=Gtk.TreeViewColumn("")
159                cell=Gtk.CellRendererPixbuf()
160                cell.set_property("stock-size",Gtk.IconSize.DIALOG)
161                column.pack_start(cell,True)
162                column.add_attribute(cell,"icon-name",0)
163                self.packages_tv.append_column(column)
164               
165                column=Gtk.TreeViewColumn("Package")
166                cell=Gtk.CellRendererText()
167                column.pack_start(cell,True)
168                column.add_attribute(cell,"markup",1)
169                column.set_expand(True)
170
171               
172                self.packages_tv.append_column(column)
173               
174                self.packages_tv.connect("button-release-event",self.package_clicked)
175               
176                column=Gtk.TreeViewColumn("Size")
177                cell=Gtk.CellRendererText()
178                cell.set_property("alignment",Pango.Alignment.CENTER)
179                column.pack_start(cell,False)
180                column.add_attribute(cell,"markup",2)
181                self.packages_tv.append_column(column)         
182
183
184                done_icon=Gtk.Image()
185                done_icon.set_from_file(CACHED_ICON)
186                pixbuf=done_icon.get_pixbuf()
187                column=Gtk.TreeViewColumn("Installed")
188                cell=Gtk.CellRendererPixbuf()
189                #cell.set_property("stock-size",Gtk.IconSize.DIALOG)
190                column.pack_start(cell,True)
191                column.add_attribute(cell,"pixbuf",3)
192                self.packages_tv.append_column(column)
193               
194                self.changelog_textview=builder.get_object("changelog_textview")
195                self.changelog_label=builder.get_object("changelog_label")
196
197
198                self.stack.add_titled(self.gather_box,"gather","Gather")
199                self.stack.add_titled(self.update_box,"update", "Update")
200                self.stack.add_titled(self.packages_box, "packages", "Packages")
201
202                self.main_box.pack_start(self.stack,True,False,5)
203
204                self.window.show_all()
205                self.terminal_scrolled.hide()
206                self.viewport.hide()
207                self.terminal_label.hide()
208                self.cancel_button_box.hide()
209                self.yes_button_box.hide()
210                self.no_button_box.hide()
211
212                self.pbar_label.show()
213                self.pbar.show()
214               
215                self.window.connect("destroy",self.quit)
216               
217               
218                self.set_css_info()
219               
220
221
222                GLib.timeout_add(100,self.pulsate_gathering_info)
223               
224                self.t=threading.Thread(target=self.gather_info)
225                self.t.daemon=True
226                self.t.start()
227                self.no_mirror=False
228
229                self.package_list=[]
230
231                GObject.threads_init()
232                Gtk.main()
233
234
235        def set_css_info(self):
236       
237                css = """
238
239
240                #WHITE_BACKGROUND {
241                        background-image:-gtk-gradient (linear, left top, left bottom, from (#ffffff),  to (#ffffff));;
242               
243                }
244
245                #BUTTON_LABEL{
246                        color:white;
247                        font: Roboto 10;
248                }
249
250                #DISABLED_BUTTON_OVER{
251                        background-image:-gtk-gradient (linear, left top, left bottom, from (#888888),  to (#888888));;
252                }
253               
254                #DISABLED_BUTTON{
255                        background-image:-gtk-gradient (linear, left top, left bottom, from (#666666),  to (#666666));;
256                }
257               
258                #CANCEL_BUTTON{
259                        background-image:-gtk-gradient (linear, left top, left bottom, from (#D32F2F),  to (#D32F2F));;
260                }
261               
262                #CANCEL_BUTTON_OVER{
263                        background-image:-gtk-gradient (linear, left top, left bottom, from (#F44336),  to (#F44336));;
264                }
265
266                #BUTTON_COLOR {
267                        background-image:-gtk-gradient (linear, left top, left bottom, from (#448AFF),  to (#448AFF));;
268               
269                }
270               
271                #UPDATE_BUTTON_LABEL{
272                        color:white;
273                        font: Roboto 11;
274                }
275               
276                #UPDATE_BUTTON_COLOR {
277                        background-image:-gtk-gradient (linear, left top, left bottom, from (#43A047),  to (#43A047));;
278               
279                }
280               
281                #GATHER_ICON_COLOR {
282                        background-image:-gtk-gradient (linear, left top, left bottom, from (#b0bec5),  to (#b0bec5));;
283               
284                }
285               
286               
287                #BLUE_FONT {
288                        color: #3366cc;
289                        font: Roboto 10;
290                       
291                }       
292               
293
294                #CHANGELOG_FONT {
295                        color: #3366cc;
296                        font: Roboto 11;
297                       
298                }
299
300                #LABEL_OPTION{
301               
302                        color: #808080;
303                        font: Roboto 11;
304                }
305               
306                """
307
308                self.style_provider=Gtk.CssProvider()
309                self.style_provider.load_from_data(css)
310                Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),self.style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
311               
312                self.window.set_name("WHITE_BACKGROUND")
313                self.update_box.set_name("WHITE_BACKGROUND")
314                self.gather_box.set_name("WHITE_BACKGROUND")
315                self.packages_box.set_name("WHITE_BACKGROUND")
316                self.gather_label.set_name("CHANGELOG_FONT")
317                self.pbar_label.set_name("CHANGELOG_FONT")
318
319                self.yes_button_box.set_name("BUTTON_COLOR")
320                self.yes_button_label.set_name("BUTTON_LABEL")
321
322                self.no_button_box.set_name("BUTTON_COLOR")
323                self.no_button_label.set_name("BUTTON_LABEL")
324
325                self.view_packages_button_box.set_name("BUTTON_COLOR")
326                self.view_packages_label.set_name("BUTTON_LABEL")
327
328                self.cancel_button_box.set_name("BUTTON_COLOR")
329                self.cancel_label.set_name("BUTTON_LABEL")     
330
331                self.version_available_label.set_name("LABEL_OPTION")
332                self.version_update_label.set_name("LABEL_OPTION")     
333                self.number_packages_label.set_name("LABEL_OPTION")
334                self.size_update_label.set_name("LABEL_OPTION")
335                self.update_button_label.set_name("UPDATE_BUTTON_LABEL")
336                self.update_button_box.set_name("UPDATE_BUTTON_COLOR")
337                self.terminal_label.set_name("LABEL_OPTION")
338
339
340                self.packages_label.set_name("LABEL_OPTION")
341                self.changelog_label.set_name("LABEL_OPTION")
342                self.changelog_texview.set_name("CHANGELOG_FONT")
343
344        def check_lliurexup_version(self):
345
346                print "Checking lliurex-up version"
347                msg_gather="<span><b>"+_("Checking for new version of lliurex-up")+"</b></span>"
348                self.gather_label.set_markup(msg_gather)
349                time.sleep(2)
350                return True
351
352
353        def check_mirror(self):
354                print "Checking mirror"
355                self.response=-1
356                t=0
357                self.yes_button_box.show()
358                self.no_button_box.show()
359                msg_gather="<span><b>"+_("Do you want to update your mirror?")+"</b></span>"
360                self.gather_label.set_markup(msg_gather)
361               
362                while self.response==-1:
363                        time.sleep(t)
364                        t=t+1
365
366                self.yes_button_box.hide()
367                self.no_button_box.hide()       
368                return True
369
370
371        def gather_info(self):
372
373                self.check_lliurexup_version()
374                self.check_mirror()
375                               
376
377                cmd="sudo apt-get update"
378                msg_gather="<span><b>"+_("Checking for new updates")+"</b></span>"
379                self.gather_label.set_markup(msg_gather)
380               
381                #p=subprocess.Popen([cmd],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)     
382                #output=p.communicate()
383                try:
384                        p1=subprocess.Popen(["llxcfg-upgrade-version-scripts","details"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
385                        output=p1.communicate()[0]
386                        f=open("/tmp/.lliurex_up_log","w")
387                        if output!=None:
388                                f.write(output)
389                        f.close()
390       
391                except:
392                        pass 
393
394
395
396        def pulsate_gathering_info(self):
397               
398                self.pbar.pulse()
399               
400                if not self.t.is_alive():
401                       
402                        self.parse_simulate_output("/tmp/.lliurex_up_log")
403                        self.populate_packages_tv()     
404                        self.get_update_info()
405                        self.pbar.hide()
406                        self.pbar_label.hide()
407                        if len(self.package_list)==0:
408                                msg_gather="<span><b>"+_("Your system is update")+"</b></span>"
409                                self.gather_label.set_markup(msg_gather)
410
411                        else:
412                               
413                                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
414                                self.stack.set_visible_child_name("update")     
415                       
416                        self.cancel_button_box.show()
417
418                return self.t.is_alive()       
419
420               
421        def populate_packages_tv(self):
422               
423                for package in self.package_list:
424                        print package
425                        self.packages_store.append((package.icon,"<span font='Roboto'><b>"+package.name+"</b></span>\n"+"<span font='Roboto' size='small'>"+package.version+"</span>","<span font='Roboto' size='large'><b>"+package.size+"</b></span>",package.installed))
426                       
427                       
428                print len(self.packages_store) 
429        #def populate_packages_tv
430       
431        def parse_simulate_output(self,test_file=None):
432               
433                if test_file!=None:
434                        f=open(test_file,"r")
435                       
436                        for line in f:
437                                if line.find("#")==0:
438                                        pass
439                                else:
440                                        tmp=line.split(";")
441                                        if len(tmp)>4:
442                                                package=Package(tmp[0],tmp[1],tmp[2],tmp[3],tmp[4])
443                                                self.package_list.append(package)
444
445                       
446                else:
447                        #to be done later
448                        pass   
449
450
451        def package_clicked(self,x,y):
452               
453                selection=self.packages_tv.get_selection()
454                model,iter=selection.get_selected()
455                name=self.packages_store.get_value(iter,1)
456                name=name[name.find("<b>")+3:name.find("</b>")]
457                               
458                for package in self.package_list:
459                       
460                        if package.name==name:
461                                self.changelog_textview.get_buffer().set_text("".join(package.changelog))
462                               
463                                break
464                               
465
466        def execute(self):
467               
468                self.vterminal.spawn_sync(
469                        Vte.PtyFlags.DEFAULT,
470                        os.environ['HOME'],
471                        ["/usr/sbin/dpkg-reconfigure", "xdm"],
472                        [],
473                        GLib.SpawnFlags.DO_NOT_REAP_CHILD,
474                        None,
475                        None,
476                )
477
478                self.update_status()
479                               
480        def install_packages(self,widget, event=None):
481                self.t=threading.Thread(target=self.execute,args=())
482                self.t.daemon=True
483                self.t.start()
484                GLib.timeout_add(100,self.pulsate_pbar)
485                self.pbar.show()
486                self.pbar_label.show()
487                self.viewport.show()
488                self.terminal_scrolled.show()
489                self.terminal_label.show()
490                msg_terminal=_("Update process details")
491                self.terminal_label.set_markup(msg_terminal)
492       
493
494
495        def get_update_info(self):
496                self.version_available="16.160916"
497                self.version_update="16.160915"
498                self.number_pkg="15"
499                self.size_update="100 Mb"
500               
501                msg_version_available=_("Version available: ")+"<span foreground='#3366cc'><b>"+self.version_available+"</b></span>"
502                msg_version_update=_("Version to update: ")+"<span foreground='#3366cc'><b>"+self.version_update+"</b></span>"
503
504                msg_number=_("Number packages: ")+"<span foreground='#3366cc'><b>"+self.number_pkg+"</b></span>"
505                msg_size=_("Size of update: ")+"<span foreground='#3366cc'><b>"+self.size_update+"</b></span>"
506               
507                self.version_available_label.set_markup(msg_version_available)
508                self.version_update_label.set_markup(msg_version_update)
509                self.number_packages_label.set_markup(msg_number)
510                self.size_update_label.set_markup(msg_size)
511               
512
513        def pulsate_pbar(self):
514                if not self.t.is_alive():
515                        self.pbar.pulse()
516                else:
517                        self.pbar.hide()
518
519                       
520        def view_packages_clicked(self,widget,event):
521                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
522                self.stack.set_visible_child_name("packages")
523
524
525        def no_button_clicked(self,widget,event):
526               
527                self.response=1 
528
529        def arrow_clicked(self,widget,event):
530                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_RIGHT)
531                self.stack.set_visible_child_name("update")     
532       
533
534        def update_status(self):
535                image=Gtk.Image()
536                image.set_from_file(ERROR_ICON)         
537                icon=image.get_pixbuf()
538
539                for item in self.packages_store:
540                        item[3]=icon
541
542        def quit(self,widget,event=None):
543               
544                Gtk.main_quit() 
545
546#class LliurexMirror
547
548at=LliurexUp()         
Note: See TracBrowser for help on using the repository browser.