source: lliurex-mirror/trunk/fuentes/lliurex-mirror-gui/usr/share/lliurex-mirror/lliurex-mirror.py @ 2635

Last change on this file since 2635 was 2635, checked in by hectorgh, 4 years ago

wip

  • Property svn:executable set to *
File size: 53.9 KB
Line 
1#!/usr/bin/env python
2
3import gi
4gi.require_version('Gtk', '3.0')
5gi.require_version('PangoCairo', '1.0')
6
7import cairo
8import os
9import threading
10import ConfigParser
11import platform
12import json
13import random
14import xmlrpclib
15import time
16import math
17import sys
18import tempfile
19from math import pi
20import lliurex_mirror_connect
21
22from gi.repository import Gtk, Gdk, GObject, GLib, PangoCairo, Pango,GdkPixbuf
23
24import signal
25signal.signal(signal.SIGINT, signal.SIG_DFL)
26
27import glob
28
29import gettext
30gettext.textdomain('lliurex-mirror')
31_ = gettext.gettext
32
33BASE_DIR="/usr/share/lliurex-mirror/"
34BANNERS_PATH=BASE_DIR+"./banners/"
35UNKNOWN_BANNER=BANNERS_PATH+"mirror_banner.png"
36SHADOW_BANNER=BASE_DIR+"rsrc/shadow.png"
37MIRROR_CONF_DIR="/etc/lliurex-mirror/conf/"
38GLADE_FILE=BASE_DIR+"rsrc/lliurex-mirror.ui"
39ADD_IMAGE=BASE_DIR+"rsrc/a1.png"
40ADD_IMAGE_OVER=BASE_DIR+"rsrc/a2.png"
41TOKEN_FILE="/run/lliurex-mirror.pid"
42ERROR=Gtk.MessageType.ERROR
43INFO=Gtk.MessageType.INFO
44
45class MirrorButton:
46       
47        def __init__(self,info):
48               
49                self.info=info # "pkg"
50                self.info["updating"]=False
51                self.info["exporting"]=False
52                self.info["executing"]=False
53                self.info["shadow_alpha"]=0.1
54                self.info["animation_active"]=False
55                self.info["shadow_start"]=0
56                self.info["available"]=True
57                self.info["degree_offset"]=0
58                self.info["red_position"]=0
59                self.info["red_right"]=True
60                self.info["max_random_lights"]=30
61                self.info["random_lights"]=[]
62                self.info["cancelled"]=False
63               
64                if os.path.exists(BANNERS_PATH+self.info["BANNER"]+".png"):
65                        self.info["image"]=BANNERS_PATH+self.info["BANNER"]+".png"
66                else:
67                        self.info["image"]=UNKNOWN_BANNER
68               
69        #def init
70       
71       
72#class GridButton
73
74class LightPoint:
75       
76        def __init__(self,x,y,radius=None):
77               
78                #self.degree=degree
79                self.radius=radius
80               
81                self.x=x
82                self.y=y
83                self.opacity=1.0
84               
85        #def
86
87class CustomColor:
88       
89        def __init__(self,r,g,b):
90               
91                self.r=r/255.0
92                self.g=g/255.0
93                self.b=b/255.0
94
95#class CustomColor             
96
97class LliurexMirror:
98       
99        def __init__(self):
100       
101                self.frame_size=116
102                self.percentage=0
103                self.circle={}
104                self.circle["x"]=58
105                self.circle["y"]=58
106                self.circle["radius"]=46
107                self.degree_offset=0
108                self.y_offset=5
109               
110                self.wave_xoffset=0
111                self.wave_yoffset=0
112                self.wave_lenght=80
113                self.wave_amplitude=3
114                self.wave_amplitude2=2
115                self.wave_amplitude3=2
116                self.wave_xoffset2=50
117                self.wave_xoffset3=80
118               
119                self.add_flag=False
120               
121                self.current_grid_width=0
122                self.current_grid_height=0
123                self.max_grid_width=2
124       
125                self.dark_gray=CustomColor(130.0,151.0,161.0)
126                self.light_gray=CustomColor(185.0,195.0,195.0)
127               
128                self.green=CustomColor(74.0,166.,69.0)
129                self.light_green=CustomColor(88.0,208.0,86.0)
130               
131               
132                self.conf_light=CustomColor(49.0,55.0,66.0)
133                self.conf_dark=CustomColor(30.0,36.0,42.0)
134               
135                self.conf_light_shadow=CustomColor(107.0,116.0,137.0)
136                self.conf_dark_shadow=CustomColor(0,0,0)
137                self.red=CustomColor(255,0,0)
138               
139                self.update_water_colors=[]
140               
141                self.update_water_colors.append(CustomColor(12,54,64))
142                self.update_water_colors.append(CustomColor(17,92,108))
143                self.update_water_colors.append(CustomColor(0.2*255,0.93*255,0.97*255))
144                self.update_water_colors.append(CustomColor(82, 176, 225))
145                self.update_water_colors.append(CustomColor(68, 159, 255))
146               
147               
148                self.export_water_colors=[]
149               
150               
151               
152                self.export_water_colors.append(CustomColor(29,12,64))
153                self.export_water_colors.append(CustomColor(47,17,108))
154                self.export_water_colors.append(CustomColor(93,51,247))
155                self.export_water_colors.append(CustomColor(153,82,225))
156                self.export_water_colors.append(CustomColor(182,68,225))
157               
158                #self.update_water_colors=self.export_water_colors
159               
160                self.login_animation_x=236 + 127/2
161                self.login_animation_y=131 + 128/2
162                self.login_animation_r=60
163               
164                self.login_enabled=True
165               
166                self.current_mirror=None
167                self.updating_mirror=None
168               
169                self.update_percentage_time=10000
170                self.update_y_time=50
171                self.update_degree_time=50
172                self.update_mirror_button_time=50
173               
174               
175        #def init
176       
177        def check_root(self):
178               
179                try:
180               
181                        f=open(TOKEN_FILE,"w")
182                        f.write(str(os.getpid()))
183                        f.close()
184                       
185                        return True
186                       
187                except:
188                       
189                        dialog = Gtk.MessageDialog(self.window, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CANCEL, "Lliurex Mirror")
190                        dialog.format_secondary_text("You need administration privileges to run this application.")
191                        dialog.run()
192                        sys.exit(1)
193               
194        #def check_root
195       
196        def start_gui(self):
197               
198                ui_path=GLADE_FILE
199                builder=Gtk.Builder()
200                builder.add_from_file(ui_path)
201               
202               
203               
204               
205                self.stack = Gtk.Stack()
206                self.stack.set_transition_duration(1000)
207                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
208               
209                self.label_image=builder.get_object("label_da")
210                self.label_image1=builder.get_object("label_da1")
211                self.label_image.connect("draw",self.draw_label)
212                self.label_image1.connect("draw",self.draw_label)
213               
214               
215                self.window=builder.get_object("main_window")
216                self.mirror_header_box=builder.get_object("mirror_header_box")
217                self.mirror_name_label=builder.get_object("mirror_name_label")
218                self.conf_mirror_name_label=builder.get_object("conf_mirror_name_label")
219                self.llx_mirror_label=builder.get_object("llx_mirror_label")
220                self.arch_label=builder.get_object("arch_label")
221                self.progress_da=builder.get_object("progress_drawingarea")
222                self.shadow_box=builder.get_object("shadow_box")
223                self.shadow_box1=builder.get_object("shadow_box1")
224                self.shadow_box2=builder.get_object("shadow_box2")
225                self.content_box=builder.get_object("mirror_box")
226                #self.main_content_box=builder.get_object("main_content_box")
227                self.progress_label=builder.get_object("progress_label")
228                self.list_box=builder.get_object("list_box")
229                self.arrow_eb=builder.get_object("arrow_eventbox")
230                self.main_header_box=builder.get_object("main_header_box")
231                self.update_label_box=builder.get_object("update_label_box")
232                self.export_label_box=builder.get_object("export_label_box")
233                self.configuration_label_box=builder.get_object("configuration_label_box")
234                self.folder_fcb=builder.get_object("folder_fcb")
235                self.folder_fcb.connect("file-set",self.folder_fcb_changed)
236                self.local_folder_label=builder.get_object("local_folder_label")
237                self.destination_fcb=builder.get_object("destination_fcb")
238                self.destination_fcb.connect("file-set",self.destination_fcb_changed)
239                self.destination_label=builder.get_object("destination_label")
240                self.scrolledwindow=builder.get_object("scrolledwindow1")
241               
242                self.internet_rb=builder.get_object("internet_rb")
243                self.local_folder_rb=builder.get_object("local_folder_rb")
244                self.url_rb=builder.get_object("url_rb")
245                self.url_entry=builder.get_object("url_entry")
246               
247                self.configuration_infobar=builder.get_object("configuration_infobar")
248                self.configuration_panel_label=builder.get_object("configuration_panel_label")
249                self.configuration_infobar.connect("response",self.ib_response)
250               
251                self.arrow_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK )
252                self.arrow_eb.connect("button-release-event",self.arrow_clicked)
253               
254                self.update_eb=builder.get_object("update_eventbox")
255                self.update_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK )
256                self.update_eb.connect("motion-notify-event",self.mouse_over_update)
257                self.update_eb.connect("leave_notify_event",self.mouse_exit_update)
258                self.update_eb.connect("button-release-event",self.update_clicked)
259               
260                self.export_eb=builder.get_object("export_eventbox")
261                self.export_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK )
262                self.export_eb.connect("motion-notify-event",self.mouse_over_export)
263                self.export_eb.connect("leave_notify_event",self.mouse_exit_export)
264                self.export_eb.connect("button-release-event",self.export_clicked)
265               
266                self.configuration_eb=builder.get_object("configuration_eventbox")
267                self.configuration_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK )
268                self.configuration_eb.connect("motion-notify-event",self.mouse_over_conf)
269                self.configuration_eb.connect("leave_notify_event",self.mouse_exit_conf)
270                self.configuration_eb.connect("button-release-event",self.conf_clicked)
271               
272               
273                self.configuration_box=builder.get_object("configuration_box")
274                self.configuration_header_box=builder.get_object("configuration_header_box")
275                self.configuration_arrow_eb=builder.get_object("configuration_arrow_eventbox")
276                self.configuration_arrow_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK )
277                self.configuration_arrow_eb.connect("button-release-event",self.configuration_arrow_clicked)
278               
279                self.name_label=builder.get_object("name_label")
280                self.banner_label=builder.get_object("banner_label")
281                self.origin_label=builder.get_object("origin_label")
282                self.distributions_label=builder.get_object("distributions_label")
283                self.sections_label=builder.get_object("sections_label")
284                self.architectures_label=builder.get_object("architectures_label")
285                self.local_path_label=builder.get_object("local_path_label")
286                self.check_md5_label=builder.get_object("check_md5_label")
287                self.ign_gpg_label=builder.get_object("ign_gpg_label")
288                self.ign_release_label=builder.get_object("ign_release_label")
289               
290                self.name_entry=builder.get_object("name_entry")
291                self.banner_combobox=builder.get_object("banner_combobox")
292                self.origin_entry=builder.get_object("origin_entry")
293                self.distributions_entry=builder.get_object("distributions_entry")
294                self.sections_entry=builder.get_object("sections_entry")
295                self.i386_cb=builder.get_object("i386_checkbutton")
296                self.amd64_cb=builder.get_object("amd64_checkbutton")
297                self.mirror_path_entry=builder.get_object("mirror_path_entry")
298                self.check_md5_cb=builder.get_object("check_md5_checkbutton")
299                self.ign_gpg_cb=builder.get_object("ign_gpg_checkbutton")
300                self.ign_release_cb=builder.get_object("ign_release_checkbutton")
301               
302               
303                self.save_button_box=builder.get_object("save_button_box")
304                self.save_eb=builder.get_object("save_eventbox")
305                self.save_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK  )
306                self.save_eb.connect("button-release-event",self.save_button_clicked)
307                self.save_eb.connect("motion-notify-event",self.mouse_over_save)
308                self.save_eb.connect("leave_notify_event",self.mouse_exit_save)
309               
310                self.export_label=builder.get_object("export_label")
311                self.update_label=builder.get_object("update_label")
312                self.save_label=builder.get_object("save_label")
313                self.conf_label=builder.get_object("conf_label")
314                self.i386_label=builder.get_object("i386_label")
315                self.amd64_label=builder.get_object("amd64_label")
316               
317                self.update_header_label=builder.get_object("update_header_label")
318                self.export_header_label=builder.get_object("export_header_label")
319                self.internet_rb_label=builder.get_object("internet_rb_label")
320                self.internet_rb_label=builder.get_object("internet_rb_label")
321                self.local_folder_rb_label=builder.get_object("local_folder_rb_label")
322                self.url_rb_label=builder.get_object("url_rb_label")
323                self.destination_opt_label=builder.get_object("destination_opt_label")
324                               
325                self.ib=builder.get_object("infobar1")
326                self.ib.connect("response",self.ib_response)
327                self.info_label=builder.get_object("info_label")
328               
329                self.info_button=builder.get_object("info_button")
330                self.info_button.connect("clicked",self.info_button_clicked)
331               
332                self.main_content_box=Gtk.Grid()
333                self.main_content_box.set_column_homogeneous(True)
334                self.main_content_box.set_row_spacing(10)
335                self.main_content_box.set_margin_top(15)
336                self.main_content_box.set_margin_left(40)
337               
338                self.viewport=builder.get_object("viewport1")
339                self.viewport.add(self.main_content_box)
340               
341       
342                self.overlay=Gtk.Overlay()
343                self.overlay.add(self.list_box)
344                self.overlay.show_all()
345               
346                eb=Gtk.EventBox()
347                eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK  )
348                b=Gtk.Image()
349               
350                eb.connect("button-release-event",self.add_clicked)
351                eb.connect("motion-notify-event",self.add_mouse_over,b)
352                eb.connect("leave_notify_event",self.add_mouse_left,b)
353                b.set_from_file(ADD_IMAGE)
354                b.show()
355               
356                eb.add(b)
357               
358                eb.set_valign(Gtk.Align.END)
359                eb.set_halign(Gtk.Align.END)
360                eb.set_margin_bottom(5)
361                eb.set_margin_right(20)
362                self.overlay.add_overlay(eb)
363               
364               
365                self.login_da_box=builder.get_object("login_da_box")
366                self.login_da=builder.get_object("login_drawingarea")
367                self.login_da.connect("draw",self.draw_login)
368               
369                self.login_overlay=Gtk.Overlay()
370                self.login_overlay.add(self.login_da_box)
371               
372                '''
373                self.login_box=Gtk.VBox()
374               
375                self.login_button=Gtk.Button("Login")
376                self.login_button.connect("clicked",self.login_clicked)
377               
378                self.login_box.pack_end(self.login_button,False,True,5)
379                self.login_box.pack_end(Gtk.Entry(),False,True,5)
380                self.login_box.pack_end(Gtk.Entry(),False,True,5)
381                self.tmp_label=Gtk.Label("hola")
382                self.login_box.pack_start(self.tmp_label,False,True,100)
383                '''
384               
385                self.login_box=builder.get_object("login_box")
386                self.login_eb=builder.get_object("login_eventbox")
387                self.login_eb.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK  )
388                self.login_eb.connect("button-press-event",self.login_clicked)
389                self.login_eb.connect("motion-notify-event",self.mouse_over_login)
390                self.login_eb.connect("leave_notify_event",self.mouse_exit_login)
391                self.user_entry=builder.get_object("user_entry")
392                self.user_entry.connect("activate",self.entries_press_event)
393                self.password_entry=builder.get_object("password_entry")
394                self.password_entry.connect("activate",self.entries_press_event)
395                self.login_eb_box=builder.get_object("login_eb_box")
396                self.login_msg_label=builder.get_object("login_msg_label")
397               
398                self.server_ip_entry=builder.get_object("server_ip_entry")
399                self.server_ip_entry.connect("activate",self.entries_press_event)
400               
401                self.button1=builder.get_object("button1")
402                self.button1.grab_focus()
403               
404               
405                self.login_overlay.add_overlay(self.login_box)
406                self.login_overlay.show_all()
407               
408               
409                self.stack.add_titled(self.login_overlay,"login","Login")
410                self.stack.add_titled(self.overlay, "main", "Main")
411                self.stack.add_titled(self.content_box, "mirror", "Mirror")
412                self.stack.add_titled(self.configuration_box,"configuration","Configuration")
413               
414               
415                self.banner_combo=builder.get_object("banner_combobox")
416                self.banner_store=Gtk.ListStore(GdkPixbuf.Pixbuf,str)
417               
418                for x in glob.glob(BANNERS_PATH+"*.png"):
419                        f_name=x.replace(BANNERS_PATH,"").split(".png")[0]
420                        image=Gtk.Image()
421                        image.set_from_file(x)
422                        pixbuf=image.get_pixbuf()
423                        pixbuf=pixbuf.scale_simple(64,64,GdkPixbuf.InterpType.BILINEAR)
424                        self.banner_store.append([pixbuf,f_name])
425                       
426                       
427                self.banner_combobox.set_model(self.banner_store)
428                txt_renderer=Gtk.CellRendererText()
429                pixbuf_renderer=Gtk.CellRendererPixbuf()
430               
431                self.banner_combobox.pack_start(pixbuf_renderer,True)
432                self.banner_combobox.add_attribute(pixbuf_renderer,"pixbuf",0)
433                self.banner_combobox.pack_start(txt_renderer,True)
434                self.banner_combobox.add_attribute(txt_renderer,"text",1)
435               
436               
437                self.window.add(self.stack)
438               
439                self.check_root()
440               
441                self.set_css_info()
442               
443                self.window.show_all()
444                self.ib.hide()
445                self.button1.hide()
446                self.configuration_infobar.hide()
447               
448                self.progress_da.connect("draw",self.draw_progress)
449                self.window.connect("destroy",self.quit)
450               
451                               
452               
453               
454               
455                #self.set_previous_values()
456               
457               
458                GObject.threads_init()
459                Gtk.main()
460               
461        #def start_gui
462       
463       
464        def set_css_info(self):
465               
466                css = """
467               
468                #BLUE_HEADER {
469                        background-image:-gtk-gradient (linear, left top, left bottom, from (#455A64),  to (#455A64));;
470                       
471                }
472               
473                #LIGHT_BLUE_BACKGROUND {
474                        background-image:-gtk-gradient (linear, left top, left bottom, from (#338fef),  to (#338fef));;
475                       
476                }
477               
478                #HEADER_SHADOW {
479                        background-image:-gtk-gradient (linear, left top, left bottom, from (#7b7b7b),  to (#ffffff));;
480               
481                }
482               
483               
484                #WHITE_BACKGROUND {
485                        background-image:-gtk-gradient (linear, left top, left bottom, from (#ffffff),  to (#ffffff));;
486               
487                }
488               
489                #RED_BACKGROUND {
490                        background-image:-gtk-gradient (linear, left top, left bottom, from (#cc0000),  to (#cc0000));;
491               
492                }
493               
494                #ORANGE_BACKGROUND {
495                        background-image:-gtk-gradient (linear, left top, left bottom, from (#ff6600),  to (#ff6600));;
496                }
497               
498                #LIGHT_RED_BACKGROUND {
499                        background-image:-gtk-gradient (linear, left top, left bottom, from (#ff2d2d),  to (#ff2d2d));;
500               
501                }
502               
503                #BUTTON_COLOR {
504                        background-image:-gtk-gradient (linear, left top, left bottom, from (#448AFF),  to (#448AFF));;
505                       
506               
507                }
508               
509                #DISABLED_BUTTON_OVER{
510                        background-image:-gtk-gradient (linear, left top, left bottom, from (#888888),  to (#888888));;
511                }
512               
513                #DISABLED_BUTTON{
514                        background-image:-gtk-gradient (linear, left top, left bottom, from (#666666),  to (#666666));;
515                }
516               
517                #CANCEL_BUTTON{
518                        background-image:-gtk-gradient (linear, left top, left bottom, from (#D32F2F),  to (#D32F2F));;
519                }
520               
521                #CANCEL_BUTTON_OVER{
522                        background-image:-gtk-gradient (linear, left top, left bottom, from (#F44336),  to (#F44336));;
523                }
524               
525                #SECTION_LABEL {
526                        font: Roboto 16;
527                }
528               
529               
530                #BUTTON_OVER_COLOR {
531                        background-image:-gtk-gradient (linear, left top, left bottom, from (#449fff),  to (#449fff));;
532                       
533               
534                }
535               
536                #BUTTON_LABEL{
537                        color:white;
538                        font: Roboto 10;
539                }
540               
541               
542                #WHITE_MIRROR_NAME {
543                        color: white;
544                        font: Roboto Medium 20;
545               
546                }
547               
548                #WHITE_EXTRA_INFO {
549                        color: white;
550                        font: Roboto Light 12;
551               
552                }
553               
554                #BLUE_FONT {
555                        color: #3366cc;
556                        font: Roboto 10;
557                       
558                }
559
560                #LABEL_OPTION{
561               
562                        color: #808080;
563                        font: Roboto 11;
564                }
565               
566                #LOGIN_BUTTON {
567                        background-image:-gtk-gradient (linear, left top, left bottom, from (#448AFF),  to (#448AFF));;
568                        color: #FFFFFF;
569                        font: Roboto 12;
570                }
571               
572                #LOGIN_BUTTON_OVER {
573                        background-image:-gtk-gradient (linear, left top, left bottom, from (#449fff),  to (#449fff));;
574                        color: #FFFFFF;
575                        font: Roboto 12;
576                }
577               
578                #LOGIN_BUTTON_DISABLED {
579                        background-image:-gtk-gradient (linear, left top, left bottom, from (#666666),  to (#666666));;
580                        color: #FFFFFF;
581                        font: Roboto 12;
582                }
583               
584                #LOGIN_BUTTON_DISABLED_OVER {
585                        background-image:-gtk-gradient (linear, left top, left bottom, from (#888888),  to (#888888));;
586                        color: #FFFFFF;
587                        font: Roboto 12;
588                }
589               
590                #ERROR_FONT {
591                        color: #CC0000;
592                        font: Roboto 10;
593                }
594               
595
596                """
597               
598                self.style_provider=Gtk.CssProvider()
599                self.style_provider.load_from_data(css)
600                Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),self.style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
601               
602                self.mirror_header_box.set_name("BLUE_HEADER")
603                self.main_header_box.set_name("BLUE_HEADER")
604                self.update_label_box.set_name("BUTTON_COLOR")
605                self.export_label_box.set_name("BUTTON_COLOR")
606                self.save_button_box.set_name("BUTTON_COLOR")
607                self.configuration_header_box.set_name("BLUE_HEADER")
608                self.configuration_label_box.set_name("BUTTON_COLOR")
609               
610                self.mirror_name_label.set_name("WHITE_MIRROR_NAME")
611                self.llx_mirror_label.set_name("WHITE_MIRROR_NAME")
612                self.conf_mirror_name_label.set_name("WHITE_MIRROR_NAME")
613                self.arch_label.set_name("WHITE_EXTRA_INFO")
614                self.shadow_box.set_name("HEADER_SHADOW")
615                self.shadow_box1.set_name("HEADER_SHADOW")
616                self.shadow_box2.set_name("HEADER_SHADOW")
617                self.content_box.set_name("WHITE_BACKGROUND")
618                self.list_box.set_name("WHITE_BACKGROUND")
619                self.configuration_box.set_name("WHITE_BACKGROUND")
620               
621                self.name_label.set_name("LABEL_OPTION")
622                self.banner_label.set_name("LABEL_OPTION")
623                self.origin_label.set_name("LABEL_OPTION")
624                self.distributions_label.set_name("LABEL_OPTION")
625                self.sections_label.set_name("LABEL_OPTION")
626                self.architectures_label.set_name("LABEL_OPTION")
627                self.local_path_label.set_name("LABEL_OPTION")
628                self.check_md5_label.set_name("LABEL_OPTION")
629                self.ign_gpg_label.set_name("LABEL_OPTION")
630                self.ign_release_label.set_name("LABEL_OPTION")
631       
632                self.update_label.set_name("BUTTON_LABEL")
633                self.export_label.set_name("BUTTON_LABEL")
634                self.save_label.set_name("BUTTON_LABEL")
635                self.conf_label.set_name("BUTTON_LABEL")
636               
637                self.url_entry.set_name("BLUE_FONT")
638                self.name_entry.set_name("BLUE_FONT")
639                self.origin_entry.set_name("BLUE_FONT")
640                self.distributions_entry.set_name("BLUE_FONT")
641                self.sections_entry.set_name("BLUE_FONT")
642                self.mirror_path_entry.set_name("BLUE_FONT")
643                self.i386_label.set_name("BLUE_FONT")
644                self.amd64_label.set_name("BLUE_FONT")
645               
646                self.user_entry.set_name("BLUE_FONT")
647                self.password_entry.set_name("BLUE_FONT")
648                self.server_ip_entry.set_name("BLUE_FONT")
649               
650                self.update_header_label.set_name("SECTION_LABEL")
651                self.export_header_label.set_name("SECTION_LABEL")
652               
653                self.internet_rb_label.set_name("LABEL_OPTION")
654                self.local_folder_rb_label.set_name("LABEL_OPTION")
655                self.url_rb_label.set_name("LABEL_OPTION")
656                self.destination_opt_label.set_name("LABEL_OPTION")
657               
658                self.local_folder_label.set_name("BLUE_FONT")
659                self.destination_label.set_name("BLUE_FONT")
660                self.login_eb.set_name("LOGIN_BUTTON")
661                #self.login_eb_box.set_name("HEADER_SHADOW")
662                self.login_msg_label.set_name("ERROR_FONT")
663               
664               
665        #def set_css
666       
667        def set_mirror_info(self,mirror_button):
668
669
670                '''
671                "NAME": "",
672                "BANNER": "",
673                "ORIGS" : {"1":"lliruex.net/xenial","2":"","3":""},
674                "ARCHITECTURES": [ "amd64", "i386"],
675                "SECTIONS": ["main", "main/debian-installer", "universe", "restricted", "multiverse", "partner"],
676                "MIRROR_PATH": "/net/mirror/llx16",
677                "DISTROS": ["xenial","xenial-updates","xenial-security"],
678                "IGN_GPG":1,
679                "IGN_RELEASE":0,
680                "CHK_MD5":0,
681                "CURRENT_UPDATE_OPTION":"1"
682                '''
683
684                self.url_entry.set_text(mirror_button.info["ORIGS"]["3"])
685                if len(mirror_button.info["NAME"]) < 22 :
686                        self.mirror_name_label.set_text(mirror_button.info["NAME"])
687                        self.conf_mirror_name_label.set_text(mirror_button.info["NAME"])
688                        self.mirror_name_label.set_tooltip_text("")
689                        self.conf_mirror_name_label.set_tooltip_text("")
690                else:
691                        self.mirror_name_label.set_text(mirror_button.info["NAME"][0:19]+"...")
692                        self.mirror_name_label.set_tooltip_text(mirror_button.info["NAME"])
693                        self.conf_mirror_name_label.set_tooltip_text(mirror_button.info["NAME"])       
694                        self.conf_mirror_name_label.set_text(mirror_button.info["NAME"][0:19]+"...")
695               
696               
697               
698               
699                self.arch_label.set_text(", ".join(mirror_button.info["ARCHITECTURES"]))
700               
701                self.internet_rb.set_active(True)
702               
703                #if mirror_button.info["CURRENT_UPDATE_OPTION"]=="2":
704                #       self.local_folder_rb.set_active(True)
705                       
706                if mirror_button.info["CURRENT_UPDATE_OPTION"]=="3":
707                        self.url_rb.set_active(True)
708               
709                self.name_entry.set_text(mirror_button.info["NAME"])
710               
711                c=0
712               
713                for i in self.banner_store:
714                        if i[1]==mirror_button.info["BANNER"]:
715                                break
716                        c+=1
717                       
718                self.banner_combobox.set_active(c)
719                       
720                       
721               
722                self.origin_entry.set_text(mirror_button.info["ORIGS"]["1"])
723                self.distributions_entry.set_text(", ".join(mirror_button.info["DISTROS"]))
724                self.sections_entry.set_text(", ".join(mirror_button.info["SECTIONS"]))
725                self.i386_cb.set_active("i386" in mirror_button.info["ARCHITECTURES"])
726                self.amd64_cb.set_active("amd64" in mirror_button.info["ARCHITECTURES"])
727                self.mirror_path_entry.set_text(mirror_button.info["MIRROR_PATH"])
728               
729                self.check_md5_cb.set_active(mirror_button.info["CHK_MD5"]==1)
730                self.ign_gpg_cb.set_active(mirror_button.info["IGN_GPG"]==1)
731                self.ign_release_cb.set_active(mirror_button.info["IGN_RELEASE"]==1)
732               
733                self.progress_label.set_text("")
734               
735                self.current_mirror=mirror_button
736
737               
738               
739               
740                if self.updating_mirror!=None:
741                        if self.current_mirror!=self.updating_mirror and self.updating_mirror.info["updating"]:
742                                self.update_label_box.set_name("DISABLED_BUTTON")
743                                self.update_label.set_text("Update")
744                               
745                        if self.current_mirror!=self.updating_mirror and self.updating_mirror.info["exporting"]:
746                                self.export_label_box.set_name("DISABLED_BUTTON")
747                                self.export_label.set_text("Export")
748                               
749                        if self.current_mirror==self.updating_mirror:
750                               
751                                if self.updating_mirror.info["updating"]:
752                                        self.update_label.set_text("Cancel")
753                                        self.update_label_box.set_name("CANCEL_BUTTON")
754                                       
755                                if self.updating_mirror.info["exporting"]:
756                                        self.export_label.set_text("Cancel")
757                                        self.export_label_box.set_name("CANCEL_BUTTON")
758                                       
759               
760                '''
761                if "2.5" in self.current_mirror.info["ORIGS"]:
762               
763                        if self.current_mirror.info["ORIGS"]["2.5"]!="":
764                                self.folder_fcb.set_filename(self.current_mirror.info["ORIGS"]["2.5"])
765                                self.local_folder_label.set_text(self.current_mirror.info["ORIGS"]["2.5"])
766                        else:
767                                self.folder_fcb.set_filename(os.environ["HOME"])
768                                self.local_folder_label.set_text(os.environ["HOME"])
769                '''             
770               
771               
772                self.destination_fcb.set_filename(os.environ["HOME"])
773                self.destination_label.set_text(os.environ["HOME"])
774               
775               
776               
777                return True
778               
779        #def set_mirror_info
780
781
782        def parse_mirrors(self):
783                '''
784                self.mirrors={}
785               
786                once=True
787               
788                for t in range(0,1):
789               
790                        for m_file in glob.glob(MIRROR_CONF_DIR+"*"):
791                               
792                                f=open(m_file,"r")
793                                data=json.load(f)
794                                f.close()
795                                m=MirrorButton(data)
796
797                                if once:
798                                       
799                                        if m.info["updating"]:
800                                                if once:
801                                                        GLib.timeout_add(5,self.update_mirror_button_animation,m)
802                                                        once=False
803                                                               
804                                else:
805                                               
806                                        m.info["updating"]=False
807                                       
808                                if t == 0:
809                                        self.mirrors[m_file.split("/")[-1]]=m
810                                else:
811                                        self.mirrors[m_file.split("/")[-1]+"%s"%t]=m
812                                self.add_mirror_button(m)
813               
814                return True
815                '''
816               
817                self.mirrors=self.llx_conn.mirror_list()
818               
819                #print self.mirrors["mippa"]
820               
821                mirror_key=self.llx_conn.is_alive()
822               
823                for key in self.mirrors:
824               
825                        m=MirrorButton(self.mirrors[key])
826                        m.info["KEY"]=key
827                        if key==mirror_key["msg"] and mirror_key["status"]:
828                                m.info["executing"]=True
829                                m.info["updating"]=True
830                                self.updating_mirror=m
831                               
832                                GLib.timeout_add(self.update_y_time,self.update_ys)
833                                GLib.timeout_add(self.update_percentage_time,self.update_percentage)
834                                GLib.timeout_add(self.update_degree_time,self.update_degree)
835                               
836                                GLib.timeout_add(self.update_mirror_button_time,self.update_mirror_button_animation,self.updating_mirror)
837                                self.export_label_box.set_name("DISABLED_BUTTON")
838                               
839                               
840                               
841                        self.add_mirror_button(m)
842               
843                return True
844               
845               
846        #def parse_mirrors
847       
848
849        def set_previous_values(self):
850               
851                #self.folder_fcb.set_filename("/home/cless")
852                #self.local_folder_label.set_text("/home/cless")
853               
854                #self.destination_fcb.set_filename("/home/cless")
855                #self.destination_label.set_text("/home/cless")
856               
857                pass
858               
859        #def set_previous_values
860       
861        def set_info_text(self,txt,message_type=Gtk.MessageType.INFO):
862               
863                self.ib.set_message_type(message_type)
864                self.info_label.set_markup(txt)
865                self.ib.show()
866               
867        #def set_info_text
868       
869        def set_conf_text(self,txt,message_type=Gtk.MessageType.INFO):
870               
871                self.configuration_infobar.set_message_type(message_type)
872                self.configuration_panel_label.set_markup(txt)
873                self.configuration_infobar.show()
874               
875        #def set_info_text
876       
877        def show_content(self,widget):
878               
879                self.ib.hide()
880                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
881                self.stack.set_visible_child_name("mirror")
882               
883               
884        #show_content
885       
886        def add_mirror_button(self,mirror_button):
887               
888                #print mirror_button.info
889               
890                da=Gtk.DrawingArea()
891                da.set_size_request(140,148)
892                da.add_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK | Gdk.EventMask.BUTTON_PRESS_MASK )
893               
894                da.connect("draw",self.draw_button,mirror_button)
895                da.connect("motion-notify-event",self.mouse_over,mirror_button)
896                da.connect("leave_notify_event",self.mouse_left,mirror_button)
897                da.connect("button-press-event",self.mirror_button_clicked,mirror_button)
898               
899                da.size_request()
900               
901                da.show()
902               
903                mirror_button.info["da"]=da
904               
905                self.main_content_box.attach(da,self.current_grid_width,self.current_grid_height,1,1)
906               
907                self.current_grid_width+=1
908               
909                if self.current_grid_width > self.max_grid_width:
910                        self.current_grid_width=0
911                        self.current_grid_height+=1
912                       
913        #def add_mirror_button
914       
915
916        def add_clicked(self,widget,event):
917               
918                print "add clicked"
919               
920                self.add_flag=True
921       
922                info={}
923               
924                info["NAME"]=""
925                info["ARCHITECTURES"]=""
926                info["CURRENT_UPDATE_OPTION"]=""
927                info["BANNER"]=""
928                info["DISTROS"]=""
929                info["SECTIONS"]=""
930                info["MIRROR_PATH"]=""
931                info["ORIGS"]={}
932                info["ORIGS"]["1"]=""
933                info["ORIGS"]["2"]=""
934                info["ORIGS"]["3"]=""
935                info["CHK_MD5"]=""
936                info["IGN_GPG"]=""
937                info["IGN_RELEASE"]=""
938               
939               
940                mirror=MirrorButton(info)
941                mirror.info["updating"]=False
942               
943                self.set_mirror_info(mirror)
944                self.banner_combobox.set_active(0)
945                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
946                self.stack.set_visible_child_name("configuration")
947               
948               
949               
950        #def add_clicked
951       
952        def add_mouse_over(self,widget,event,i):
953               
954                i.set_from_file(ADD_IMAGE_OVER)
955               
956        #def add_mouse_over
957       
958       
959        def add_mouse_left(self,widget,event,i):
960               
961                i.set_from_file(ADD_IMAGE)
962               
963        #def add_mouse_over
964       
965        def entries_press_event(self,widget):
966               
967               
968               
969                self.login_clicked(None,None)
970
971        def ib_response(self,widget,response):
972
973                widget.hide()
974               
975        #
976       
977        def folder_fcb_changed(self,widget):
978               
979               
980                self.local_folder_label.set_text(self.folder_fcb.get_filename())
981               
982        #def
983       
984        def destination_fcb_changed(self,widget):
985               
986               
987                self.destination_label.set_text(self.destination_fcb.get_filename())
988               
989        #def
990       
991       
992        def configuration_arrow_clicked(self,widget,event):
993               
994                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_RIGHT)
995                if self.add_flag:
996                        self.stack.set_visible_child_name("main")
997                        self.add_flag=False
998                        return True
999               
1000                self.ib.hide()                 
1001                self.stack.set_visible_child_name("mirror")
1002               
1003               
1004        #def arrow_clicked
1005       
1006       
1007        def arrow_clicked(self,widget,event):
1008               
1009                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_RIGHT)
1010                self.stack.set_visible_child_name("main")
1011               
1012               
1013               
1014        #def arrow_clicked
1015
1016       
1017        def mouse_over_update(self,widget,event):
1018               
1019               
1020                if self.updating_mirror!=None and self.updating_mirror.info["updating"]:
1021                       
1022                        if self.updating_mirror==self.current_mirror:
1023                                self.update_label_box.set_name("CANCEL_BUTTON_OVER")
1024                                return True
1025                               
1026                        self.update_label_box.set_name("DISABLED_BUTTON_OVER")
1027                        return True
1028                       
1029               
1030                if self.updating_mirror!=None and self.updating_mirror.info["exporting"]:
1031                       
1032                        self.update_label_box.set_name("DISABLED_BUTTON_OVER")
1033                        return True
1034               
1035                       
1036                self.update_label_box.set_name("BUTTON_OVER_COLOR")
1037               
1038        #def mouse_over_event
1039       
1040        def mouse_exit_update(self,widget,event):
1041               
1042               
1043                if self.updating_mirror!=None and self.updating_mirror.info["updating"]:
1044                       
1045                        if self.updating_mirror==self.current_mirror:
1046                                self.update_label_box.set_name("CANCEL_BUTTON")
1047                                return True
1048                               
1049                        self.update_label_box.set_name("DISABLED_BUTTON")
1050                        return True
1051                       
1052               
1053                if self.updating_mirror!=None and self.updating_mirror.info["exporting"]:
1054                       
1055                        self.update_label_box.set_name("DISABLED_BUTTON")
1056                        return True
1057               
1058                       
1059                self.update_label_box.set_name("BUTTON_COLOR")
1060               
1061               
1062        #def mouse left_update
1063       
1064        def update_clicked(self,widget,event):
1065               
1066                print "Update clicked"
1067       
1068                mode="1"
1069                data=None
1070       
1071                self.current_mirror.info["cancelled"]=False
1072               
1073                if self.updating_mirror!=None and self.updating_mirror!=self.current_mirror:
1074                        if self.updating_mirror.info["executing"]:
1075                                self.set_info_text("'%s' is currently %s."%(self.updating_mirror.info["NAME"], 'updating' if self.updating_mirror.info["updating"] else 'exporting'),Gtk.MessageType.ERROR)
1076                                return False
1077               
1078                if self.current_mirror.info["exporting"]:
1079                        self.set_info_text("'%s' is currently exporting."%self.updating_mirror.info["NAME"],Gtk.MessageType.ERROR)
1080                        return False
1081               
1082                if self.internet_rb.get_active():
1083                        print "INTERNET"
1084               
1085                if self.local_folder_rb.get_active():
1086                        print "LOCAL_FOLDER: %s"%self.folder_fcb.get_filename()
1087                        mode="2"
1088                        data=self.folder_fcb.get_filename()
1089                        self.current_mirror.info["ORIGS"]["2"]=data
1090                       
1091                       
1092                if self.url_rb.get_active():
1093                        print "URL: %s"%self.url_entry.get_text()
1094                        mode="3"
1095                        data=self.url_entry.get_text()
1096                        self.current_mirror.info["ORIGS"]["3"]=data
1097               
1098                self.current_mirror.info["CURRENT_UPDATE_OPTION"]=mode
1099               
1100                if not self.current_mirror.info["executing"]:
1101                       
1102                        self.percentage=0
1103                        self.progress_label.set_text("")
1104                        GLib.idle_add(self.ib.hide)
1105                        self.updating_mirror=self.current_mirror
1106                        self.current_mirror.info["updating"]=True
1107                        self.current_mirror.info["executing"]=True
1108                        self.current_mirror.info["cancelled"]=False
1109                        GLib.timeout_add(self.update_y_time,self.update_ys)
1110                        GLib.timeout_add(self.update_percentage_time,self.update_percentage)
1111                        GLib.timeout_add(self.update_degree_time,self.update_degree)
1112                       
1113                        self.llx_conn.update(self.current_mirror.info["KEY"],mode,data)
1114                       
1115                        GLib.timeout_add(self.update_mirror_button_time,self.update_mirror_button_animation,self.updating_mirror)
1116                        self.update_label.set_text("Cancel")
1117                        self.update_label_box.set_name("CANCEL_BUTTON_OVER")
1118                        self.export_label_box.set_name("DISABLED_BUTTON")
1119                       
1120                else:
1121                       
1122                        self.llx_conn.stop_update()
1123                       
1124                        self.updating_mirror.info["updating"]=False
1125                        self.updating_mirror.info["executing"]=False
1126                        self.updating_mirror.info["cancelled"]=True
1127                        self.update_label.set_text("Update")
1128                        self.update_label_box.set_name("BUTTON_COLOR")
1129                        self.export_label_box.set_name("BUTTON_COLOR")
1130
1131        #def update_clicked
1132
1133       
1134        def mouse_over_export(self,widget,event):
1135               
1136               
1137                if self.updating_mirror!=None and self.updating_mirror.info["exporting"]:
1138                       
1139                        if self.updating_mirror==self.current_mirror:
1140                                self.export_label_box.set_name("CANCEL_BUTTON_OVER")
1141                                return True
1142                               
1143                        self.export_label_box.set_name("DISABLED_BUTTON_OVER")
1144                        return True
1145                       
1146               
1147                if self.updating_mirror!=None and self.updating_mirror.info["updating"]:
1148                       
1149                        self.export_label_box.set_name("DISABLED_BUTTON_OVER")
1150                        return True
1151               
1152                self.export_label_box.set_name("BUTTON_OVER_COLOR")
1153               
1154        #def mouse_over_event
1155       
1156        def mouse_exit_export(self,widget,event):
1157               
1158                if self.updating_mirror!=None and self.updating_mirror.info["exporting"]:
1159                       
1160                        if self.updating_mirror==self.current_mirror:
1161                                self.export_label_box.set_name("CANCEL_BUTTON")
1162                                return True
1163                               
1164                        self.export_label_box.set_name("DISABLED_BUTTON")
1165                        return True
1166                       
1167               
1168                if self.updating_mirror!=None and self.updating_mirror.info["updating"]:
1169                       
1170                        self.export_label_box.set_name("DISABLED_BUTTON")
1171                        return True
1172               
1173                self.export_label_box.set_name("BUTTON_COLOR")
1174               
1175        #def mouse left_update
1176       
1177        def export_clicked(self,widget,event):
1178               
1179                print "Export clicked: %s"%self.destination_fcb.get_filename()
1180               
1181               
1182                if self.updating_mirror!=None and self.updating_mirror!=self.current_mirror:
1183                        if self.updating_mirror.info["executing"]:
1184                                self.set_info_text("'%s' is currently %s."%(self.updating_mirror.info["NAME"], 'updating' if self.updating_mirror.info["updating"] else 'exporting'),Gtk.MessageType.ERROR)
1185                                return False
1186               
1187
1188                if self.current_mirror.info["updating"]:
1189                        self.set_info_text("'%s' is currently updating."%self.updating_mirror.info["NAME"],Gtk.MessageType.ERROR)
1190                        return False
1191
1192                if not self.current_mirror.info["exporting"]:
1193                       
1194                        self.percentage=0
1195                        self.updating_mirror=self.current_mirror
1196                        self.updating_mirror.info["exporting"]=True
1197                        self.updating_mirror.info["executing"]=True
1198                        self.updating_mirror.info["cancelled"]=False
1199                        GLib.timeout_add(self.update_y_time,self.update_ys)
1200                        GLib.timeout_add(self.update_percentage_time,self.update_percentage)
1201                        GLib.timeout_add(self.update_degree_time,self.update_degree)
1202                       
1203                        self.llx_conn.export(self.updating_mirror.info["KEY"],self.destination_fcb.get_filename())
1204                       
1205                        GLib.timeout_add(self.update_mirror_button_time,self.update_mirror_button_animation,self.updating_mirror)
1206                       
1207                       
1208
1209                        self.export_label.set_text("Cancel")
1210                        self.export_label_box.set_name("CANCEL_BUTTON_OVER")
1211                       
1212                        self.update_label_box.set_name("DISABLED_BUTTON")
1213
1214                       
1215                else:
1216                       
1217                        self.updating_mirror.info["exporting"]=False
1218                        self.updating_mirror.info["executing"]=False
1219                        self.updating_mirror.info["cancelled"]=True
1220                        self.export_label.set_text("Export")
1221                        self.update_label_box.set_name("BUTTON_COLOR")
1222                        self.export_label_box.set_name("BUTTON_COLOR")
1223               
1224               
1225               
1226               
1227               
1228               
1229        #def update_clicked
1230               
1231
1232        def mouse_over_conf(self,widget,event):
1233               
1234                self.configuration_label_box.set_name("BUTTON_OVER_COLOR")
1235               
1236        #def mouse_over_event
1237       
1238        def mouse_exit_conf(self,widget,event):
1239               
1240                self.configuration_label_box.set_name("BUTTON_COLOR")
1241               
1242        #def mouse left_update
1243       
1244        def conf_clicked(self,widget,event):
1245               
1246                print "Configuration clicked"
1247                self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT)
1248                self.stack.set_visible_child_name("configuration")
1249               
1250        #def update_clicked
1251
1252        def mirror_button_clicked(self,widget,event,mirror_button):
1253               
1254                self.set_mirror_info(mirror_button)
1255                self.show_content(None)
1256               
1257        #def button_clicked
1258       
1259        def mouse_over_save(self,widget,event):
1260               
1261                self.save_button_box.set_name("BUTTON_OVER_COLOR")
1262               
1263        #def mouse_over_event
1264       
1265        def mouse_exit_save(self,widget,event):
1266               
1267                self.save_button_box.set_name("BUTTON_COLOR")
1268               
1269        #def mouse left_update
1270       
1271       
1272        def save_button_clicked(self,widget,event):
1273               
1274                self.current_mirror.info["NAME"]=self.name_entry.get_text()
1275               
1276                self.current_mirror.info["BANNER"]=self.banner_store[self.banner_combobox.get_active()][1]
1277               
1278                # internal info based on banner name
1279                if os.path.exists(BANNERS_PATH+self.current_mirror.info["BANNER"]+".png"):
1280                        self.current_mirror.info["image"]=BANNERS_PATH+self.current_mirror.info["BANNER"]+".png"
1281                else:
1282                        self.current_mirror.info["image"]=UNKNOWN_BANNER
1283                       
1284                if "img" in self.current_mirror.info:
1285                        self.current_mirror.info.pop("img")
1286               
1287                #
1288               
1289               
1290               
1291                self.label_image.queue_draw()
1292                self.label_image1.queue_draw()
1293               
1294               
1295                self.current_mirror.info["ORIGS"]["1"]=self.origin_entry.get_text()
1296               
1297                self.current_mirror.info["DISTROS"]=[]
1298                for item in self.distributions_entry.get_text().split(","):
1299                       
1300                        item=item.lstrip(" ").rstrip(" ")
1301                        self.current_mirror.info["DISTROS"].append(item)
1302               
1303                self.current_mirror.info["SECTIONS"]=[]
1304                for item in self.sections_entry.get_text().split(","):
1305                       
1306                        item=item.lstrip(" ").rstrip(" ")
1307                        self.current_mirror.info["SECTIONS"].append(item)
1308                       
1309                self.current_mirror.info["ARCHITECTURES"]=[]
1310                if self.i386_cb.get_active():
1311                        self.current_mirror.info["ARCHITECTURES"].append("i386")
1312                if self.amd64_cb.get_active():
1313                        self.current_mirror.info["ARCHITECTURES"].append("amd64")
1314               
1315                self.current_mirror.info["MIRROR_PATH"]=self.mirror_path_entry.get_text()
1316               
1317                self.current_mirror.info["IGN_GPG"]=0
1318                if self.ign_gpg_cb.get_active():
1319                        self.current_mirror.info["IGN_GPG"]=1
1320               
1321                self.current_mirror.info["IGN_RELEASE"]=0
1322                if self.ign_release_cb.get_active():
1323                        self.current_mirror.info["IGN_RELEASE"]=1
1324               
1325                self.current_mirror.info["CHK_MD5"]=0
1326                if self.check_md5_cb.get_active():
1327                        self.current_mirror.info["CHK_MD5"]=1
1328
1329                self.set_mirror_info(self.current_mirror)
1330               
1331                if self.add_flag:
1332                       
1333                        self.mirrors[str(random.random())]=self.current_mirror
1334                        self.add_mirror_button(self.current_mirror)
1335                        self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_RIGHT)
1336                        self.ib.hide()
1337                        self.stack.set_visible_child_name("mirror")
1338                       
1339                        self.add_flag=False
1340                       
1341                        try:
1342                                key=self.llx_conn.create_config(self.current_mirror.info)
1343                                self.current_mirror.info["KEY"]=key
1344                                self.set_conf_text("Configuration Saved",INFO)
1345                        except Exception as e:
1346                                self.set_conf_text("Could not save configuration [%s]"%e,ERROR)
1347               
1348                else:
1349                        try:
1350                                self.llx_conn.save_config(self.current_mirror.info["KEY"],self.current_mirror.info)
1351                                self.configuration_infobar.hide()
1352                                self.set_conf_text("Configuration Saved",INFO)
1353                        except Exception as e:
1354                                self.set_conf_text("Could not save configuration [%s]"%e,ERROR)
1355               
1356        #def save_button_clicked
1357
1358       
1359        def mouse_over_login(self,widget,event):
1360               
1361                if self.login_enabled:
1362               
1363                        self.login_eb.set_name("LOGIN_BUTTON_OVER")
1364                       
1365                else:
1366                       
1367                        self.login_eb.set_name("LOGIN_BUTTON_DISABLED")
1368               
1369        #def mouse_over_login
1370       
1371        def mouse_exit_login(self,widget,event):
1372               
1373                if self.login_enabled:
1374               
1375                        self.login_eb.set_name("LOGIN_BUTTON")
1376                else:
1377                       
1378                        self.login_eb.set_name("LOGIN_BUTTON_DISABLED")
1379               
1380        #def mouse_over_login
1381
1382        def validate_user(self):
1383               
1384                GLib.idle_add(self.validate_thread)
1385               
1386        #validate_user
1387       
1388        def validate_thread(self):
1389               
1390               
1391                c=xmlrpclib.ServerProxy("https://"+self.server_ip+":9779")
1392                self.ret=None
1393
1394                try:
1395                        self.ret=c.validate_user(self.user,self.password)
1396                except Exception as e:
1397                        self.ret=[False,str(e)]
1398                        GLib.idle_add(self.set_login_msg,str(e))
1399                        GLib.idle_add(self.login_form_sensitive)
1400                        return
1401
1402               
1403                if self.ret[0]:
1404                        GLib.timeout_add(10,self.update_login_animation)
1405                        GLib.idle_add(self.set_login_msg,"")
1406                else:
1407                        GLib.idle_add(self.set_login_msg,"Wrong user and/or password")
1408                        GLib.idle_add(self.login_form_sensitive)
1409                       
1410               
1411        #def validate_thread
1412
1413        def set_login_msg(self,msg):
1414               
1415                self.login_msg_label.set_text(msg)
1416               
1417        #def set_login_msg
1418       
1419       
1420        def login_form_sensitive(self,state=None):
1421               
1422                if state==None:
1423                        state=not self.login_enabled
1424               
1425                self.login_enabled=state
1426               
1427                self.user_entry.set_sensitive(state)
1428                self.password_entry.set_sensitive(state)
1429                self.server_ip_entry.set_sensitive(state)
1430               
1431                if state:
1432                        self.login_eb.set_name("LOGIN_BUTTON")
1433                else:
1434                        self.login_eb.set_name("LOGIN_BUTTON_DISABLED")
1435               
1436               
1437        #def login_form_sensible
1438       
1439
1440        def login_clicked(self,widget,event):
1441               
1442               
1443                if self.login_enabled:
1444               
1445                       
1446                        self.user=self.user_entry.get_text()
1447                        self.password=self.password_entry.get_text()
1448                        self.server_ip=self.server_ip_entry.get_text()
1449                       
1450                        if self.server_ip=="":
1451                                #self.server_ip="server"
1452                                self.server_ip="localhost"
1453                               
1454                        if self.user=="":       
1455                                self.user="lliurex"
1456                        if self.password=="":
1457                                self.password="lliurex"
1458                       
1459                        self.login_animation_r=60
1460                        self.login_form_sensitive()
1461                       
1462                       
1463                       
1464                        self.t=threading.Thread(target=self.validate_thread)
1465                        self.t.daemon=True
1466                        self.t.start()
1467                       
1468                       
1469                       
1470               
1471               
1472        #def login_clicked
1473       
1474        def update_login_animation(self):
1475               
1476                #print "update_login_animation"
1477               
1478                self.login_animation_r+=8
1479               
1480                if self.login_animation_r<650:
1481                        self.login_da.queue_draw()
1482                        return True
1483                else:
1484                        #return False
1485                        self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
1486                        self.stack.set_visible_child_name("main")
1487                        self.llx_conn=lliurex_mirror_connect.LliurexMirrorN4d(self.server_ip,(self.user,self.password))
1488                        self.parse_mirrors()
1489                       
1490        def update_mirror_button_animation(self,mirror_button):
1491               
1492                #print "update_button_animation"
1493               
1494                if self.stack.get_visible_child_name()!="main":
1495                        return True
1496               
1497                mirror_button.info["degree_offset"]+=1
1498               
1499                if self.updating_mirror.info["executing"]:
1500                        if self.stack.get_visible_child_name()=="main":
1501                                mirror_button.info["da"].queue_draw()
1502                        return True
1503               
1504        #def update_mirror_animation
1505       
1506                       
1507               
1508
1509
1510        def update_ys(self):
1511               
1512               
1513               
1514               
1515               
1516                self.wave_xoffset-=1
1517                self.wave_xoffset2+=2
1518                self.wave_xoffset3+=1
1519               
1520                if self.stack.get_visible_child_name()=="mirror":
1521                        self.progress_da.queue_draw()
1522
1523                if self.updating_mirror.info["executing"]:
1524               
1525                        return True
1526                       
1527
1528               
1529               
1530               
1531        #def update_ys
1532
1533               
1534        def update_percentage(self):
1535               
1536
1537               
1538                ret={}
1539                ret["status"]=False
1540               
1541                if self.updating_mirror.info["updating"]:
1542                        ret=self.llx_conn.is_alive()
1543                        self.percentage=self.llx_conn.get_percentage(self.updating_mirror.info["KEY"])
1544                if self.updating_mirror.info["exporting"]:
1545                        ret=self.llx_conn.is_alive_export()
1546                        self.percentage=self.llx_conn.get_percentage_export()
1547               
1548                self.progress_label.set_text(str(self.percentage) + "%")
1549               
1550               
1551                '''
1552               
1553                if self.percentage>=100:
1554                                       
1555                        self.updating_mirror.info["executing"]=False
1556                        self.updating_mirror.info["updating"]=False
1557                        self.updating_mirror.info["exporting"]=False
1558                        self.export_label_box.set_name("BUTTON_COLOR")
1559                        self.update_label_box.set_name("BUTTON_COLOR")
1560                                       
1561                        self.update_label.set_text("Update")
1562                        self.export_label.set_text("Export")
1563
1564                '''
1565
1566                if ret["status"]:
1567                        return True
1568                else:
1569                       
1570                        self.updating_mirror.info["executing"]=False
1571                        self.updating_mirror.info["updating"]=False
1572                        self.updating_mirror.info["exporting"]=False
1573                        self.export_label_box.set_name("BUTTON_COLOR")
1574                        self.update_label_box.set_name("BUTTON_COLOR")
1575                                               
1576                        self.update_label.set_text("Update")
1577                        self.export_label.set_text("Export")
1578
1579
1580                        if not self.updating_mirror.info["cancelled"]:
1581                                ret=self.llx_conn.get_status(self.updating_mirror.info["KEY"])
1582                                if ret["status"]:
1583                                        pass
1584                                else:
1585                                        error="Error:\n"
1586
1587                                        error+=ret["msg"].lstrip().rstrip()
1588                                        self.set_info_text(error,Gtk.MessageType.ERROR)
1589                                               
1590                                        self.updating_mirror.info["executing"]=False
1591                                        self.updating_mirror.info["updating"]=False
1592                                        self.updating_mirror.info["exporting"]=False
1593                                        self.updating_mirror.info["cancelled"]=True
1594                                        self.export_label_box.set_name("BUTTON_COLOR")
1595                                        self.update_label_box.set_name("BUTTON_COLOR")
1596                                        self.update_label.set_text("Update")
1597                                        self.export_label.set_text("Export")
1598
1599               
1600        #def update_percentage
1601
1602               
1603        def update_degree(self):
1604               
1605                #print "update degree"
1606               
1607                self.degree_offset+=1
1608               
1609                if self.degree_offset==360:
1610                        self.dregree_offset=0
1611               
1612                if self.updating_mirror.info["executing"]:
1613                        if self.stack.get_visible_child_name()=="mirror":
1614                                self.updating_mirror.info["da"].queue_draw()
1615                       
1616                        return True
1617               
1618        #def update_degree
1619       
1620
1621        def draw_label(self,widget,ctx):
1622               
1623                if self.stack.get_visible_child_name()=="main" :
1624                        return
1625               
1626                ctx.move_to(0,0)
1627                if "img" not in self.current_mirror.info:
1628                        self.current_mirror.info["img"]=cairo.ImageSurface.create_from_png(self.current_mirror.info["image"])
1629                ctx.set_source_surface(self.current_mirror.info["img"],(140-116)/-2,(140-116)/-2)
1630                ctx.paint()
1631               
1632                ctx.set_source_rgba(69/255.0,90/255.0,100/255.0,1)
1633                ctx.rectangle(0,0,116,116)
1634                ctx.arc_negative(self.circle["x"],self.circle["y"],self.circle["radius"]*0.9,self.to_rad(360),self.to_rad(0))
1635                ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
1636                ctx.fill()
1637               
1638                ctx.set_fill_rule(cairo.FILL_RULE_WINDING)
1639                ctx.set_source_rgba(1,1,1,1)
1640                ctx.set_line_width(1)
1641                ctx.arc(self.circle["x"],self.circle["y"],self.circle["radius"]*0.9,self.to_rad(0),self.to_rad(360))
1642                ctx.stroke()
1643               
1644        #def draw
1645
1646       
1647        def draw_progress(self,widget,ctx):
1648
1649                if self.stack.get_visible_child_name()!="mirror":
1650                        return
1651
1652                if self.current_mirror==self.updating_mirror and self.updating_mirror.info["executing"]:
1653                        percentage=self.percentage
1654                else:
1655                        percentage=110
1656
1657                ctx.set_source_rgba(1,1,1,1)
1658                ctx.rectangle(0,0,self.frame_size,self.frame_size)
1659                ctx.fill()
1660               
1661                ctx.move_to(0,self.frame_size)
1662
1663               
1664               
1665                ctx.set_source_rgba(self.update_water_colors[0].r,self.update_water_colors[0].g,self.update_water_colors[0].b,1)
1666                self.wave_yoffset=self.frame_size-(self.frame_size - (self.circle["radius"]*2))/2 - 7  - self.circle["radius"]*2*percentage/100
1667               
1668               
1669                first=True
1670                for x in range(0,self.frame_size + 1):
1671                       
1672                        y=self.get_wave_y(x,2)
1673                        if y>self.frame_size:
1674                                y=self.frame_size
1675                        if first:
1676                                fy=y
1677                                first=False
1678                        ctx.line_to(x,y)
1679               
1680                ctx.line_to(x,self.frame_size)
1681                ctx.line_to(0,self.frame_size)
1682                ctx.fill()
1683               
1684                               
1685                ctx.set_source_rgba(self.update_water_colors[1].r,self.update_water_colors[1].g,self.update_water_colors[1].b,1)
1686                self.wave_yoffset=self.frame_size-(self.frame_size - (self.circle["radius"]*2))/2 - 5  - self.circle["radius"]*2*percentage/100
1687               
1688                first=True
1689                for x in range(0,self.frame_size + 1):
1690                       
1691                        y=self.get_wave_y(x,1)
1692                        if y>self.frame_size:
1693                                y=self.frame_size
1694                        if first:
1695                                fy=y
1696                                first=False
1697                        ctx.line_to(x,y)
1698               
1699                ctx.line_to(x,self.frame_size)
1700                ctx.line_to(0,self.frame_size)
1701                ctx.fill()
1702               
1703                               
1704                ctx.set_source_rgba(self.update_water_colors[2].r,self.update_water_colors[2].g,self.update_water_colors[2].b,1)
1705                self.wave_yoffset=self.frame_size- (self.frame_size - (self.circle["radius"]*2))/2  - 2  - self.circle["radius"]*2*percentage/100
1706               
1707                first=True
1708               
1709                ys=[]           
1710                for x in range(0,self.frame_size + 1):
1711                       
1712                        y=self.get_wave_y(x)
1713                        ys.append(y)
1714                        if y>self.frame_size:
1715                                y=self.frame_size
1716                       
1717                        if first:
1718                                fy=y
1719                                first=False
1720                               
1721                       
1722                        ctx.line_to(x,y)
1723               
1724                ctx.line_to(x,self.frame_size)
1725                ctx.line_to(0,self.frame_size)
1726                ctx.fill()
1727               
1728               
1729               
1730                r2 = cairo.RadialGradient(0, 40, 1,0, 50, 100)
1731                r2.add_color_stop_rgb(0,self.update_water_colors[3].r,self.update_water_colors[3].g,self.update_water_colors[3].b)
1732                r2.add_color_stop_rgb(1, self.update_water_colors[4].r,self.update_water_colors[4].g,self.update_water_colors[4].b)
1733                ctx.set_source(r2)
1734                self.wave_yoffset=self.frame_size -  (self.frame_size - (self.circle["radius"]*2))/2   - self.circle["radius"]*2*percentage/100
1735               
1736                first=True
1737               
1738                for x in range(0,self.frame_size + 1):
1739                       
1740                        y=ys[x]+3
1741                       
1742                        if y>self.frame_size:
1743                                y=self.frame_size
1744                       
1745                        if first:
1746                                fy=y
1747                                first=False
1748                               
1749                       
1750                        ctx.line_to(x,y)
1751               
1752                ctx.line_to(x,self.frame_size)
1753                ctx.line_to(0,self.frame_size)
1754                ctx.fill()
1755               
1756                ctx.set_source_rgba(69/255.0,90/255.0,100/255.0,1)
1757                ctx.rectangle(0,0,self.frame_size,self.frame_size)
1758                ctx.arc_negative(self.circle["x"],self.circle["y"],self.circle["radius"],self.to_rad(360),self.to_rad(0))
1759                ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD)
1760                ctx.fill()
1761               
1762                ctx.set_fill_rule(cairo.FILL_RULE_WINDING)
1763                ctx.set_source_rgba(52/255.0,52/255.0,52/255.0,1)
1764                ctx.set_line_width(2)
1765                ctx.arc(self.circle["x"],self.circle["y"],self.circle["radius"],self.to_rad(0),self.to_rad(360))
1766                ctx.stroke()
1767               
1768                ctx.set_line_width(2)
1769                ctx.set_source_rgba(1,1,1,1)
1770                if self.current_mirror.info["cancelled"]:
1771                        ctx.set_source_rgba(1,0,0,1)
1772                ctx.arc(self.circle["x"],self.circle["y"],self.circle["radius"]+1,self.to_rad(0+self.degree_offset),self.to_rad(percentage*360/100+self.degree_offset))
1773                ctx.stroke()
1774               
1775        #
1776
1777        def draw_login(self,widget,ctx):
1778               
1779               
1780               
1781               
1782                ctx.move_to(0,0)
1783                ctx.set_source_rgba(1,1,1,1)
1784                ctx.rectangle(0,0,600,1000)
1785                ctx.fill()
1786               
1787               
1788                '''
1789                ctx.set_source_rgba(0.4,0.4,1,1)
1790                ctx.arc(300,150,50,self.to_rad(0),self.to_rad(360))
1791                ctx.fill()
1792                '''
1793               
1794               
1795               
1796                #ctx.set_source_rgba(0,0,0,0.1)
1797               
1798       
1799               
1800                ctx.set_source_rgba(69/255.0,90/255.0,100/255.0,1)
1801               
1802               
1803                ctx.arc(self.login_animation_x,self.login_animation_y,self.login_animation_r,self.to_rad(0),self.to_rad(360))
1804                ctx.fill()
1805               
1806                               
1807                '''
1808                ctx.arc(self.login_animation_x,self.login_animation_y,self.login_animation_r,self.to_rad(0),self.to_rad(360))
1809                x,y=ctx.get_current_point()
1810
1811                r2 = cairo.RadialGradient(x, y, self.login_animation_r/2,x, y, self.login_animation_r)
1812                r2.add_color_stop_rgba(0, 1,1,0,1)
1813                r2.add_color_stop_rgba(1, 0, 0, ,1)
1814                ctx.set_line_width(8)
1815                ctx.set_source(r2)
1816                       
1817                ctx.stroke()
1818                '''
1819               
1820               
1821        #def draw_login
1822
1823
1824        def draw_button(self,widget,ctx,mirror_button):
1825               
1826                if self.stack.get_visible_child_name()!="main":
1827                        return 
1828               
1829                ctx.move_to(0,0)
1830                img=cairo.ImageSurface.create_from_png(SHADOW_BANNER)
1831                ctx.set_source_surface(img,0,mirror_button.info["shadow_start"])
1832                ctx.paint_with_alpha(mirror_button.info["shadow_alpha"])
1833               
1834                ctx.move_to(0,0)
1835                img=cairo.ImageSurface.create_from_png(mirror_button.info["image"])
1836                ctx.set_source_surface(img,0,0)
1837                ctx.paint()
1838               
1839                ctx.move_to(0,0)
1840                ctx.set_source_rgba(1,1,1,1)
1841                ctx.rectangle(0,110,140,30)
1842                ctx.fill()
1843               
1844                ctx.set_source_rgba(self.dark_gray.r,self.dark_gray.g,self.dark_gray.b,1)
1845               
1846                pctx = PangoCairo.create_layout(ctx)
1847               
1848                desc = Pango.font_description_from_string ("Roboto 9")
1849                pctx.set_font_description(desc)
1850                pctx.set_markup(mirror_button.info["NAME"])
1851                width=pctx.get_pixel_size()[0]
1852               
1853                if width > 130:
1854                        pctx.set_markup(mirror_button.info["NAME"][0:22]+"...")
1855                       
1856                       
1857               
1858                ctx.move_to(5,118)
1859                PangoCairo.show_layout(ctx, pctx)
1860               
1861               
1862               
1863               
1864                if mirror_button.info["executing"]:
1865                       
1866                        ctx.move_to(0,0)
1867                        ctx.set_source_rgba(0,0,0,0.5)
1868                        ctx.rectangle(0,0,140,110)
1869                        ctx.fill()
1870                       
1871                        ctx.arc(70,70-15,40,self.to_rad(0+mirror_button.info["degree_offset"]),self.to_rad(180+mirror_button.info["degree_offset"]))
1872                        x,y=ctx.get_current_point()
1873
1874                        r2 = cairo.RadialGradient(x, y, 10,x, y, 60)
1875                        r2.add_color_stop_rgba(0, 1,1,1,1)
1876                        r2.add_color_stop_rgba(1, 68/255.0, 159/255.0, 255/255.0,0)
1877                        ctx.set_line_width(8)
1878                        ctx.set_source(r2)
1879                       
1880                        ctx.stroke()
1881                       
1882                        ctx.set_line_width(1)
1883                       
1884                        ctx.set_source_rgba(1,1,1,1)
1885                        ctx.arc(x,y,4,self.to_rad(0),self.to_rad(360))
1886                        ctx.fill()
1887                       
1888                        if int(random.random()*100) > 35:
1889       
1890                                if len(mirror_button.info["random_lights"]) < mirror_button.info["max_random_lights"]:
1891                                       
1892                                        offset=int(random.random()*12)
1893                                       
1894                                        if offset > 6:
1895                                               
1896                                                offset=offset/-2
1897                                       
1898                                        mirror_button.info["random_lights"].append(LightPoint(x+offset,y,random.random()*2))
1899
1900                               
1901                        for i in range(len(mirror_button.info["random_lights"])-1,-1,-1):
1902                               
1903                                mirror_button.info["random_lights"][i].opacity-=0.02
1904                                if mirror_button.info["random_lights"][i].opacity <=0.0:
1905                                        mirror_button.info["random_lights"].pop(i)
1906                                        continue
1907                               
1908                                #ctx.set_source_rgba(1,1,1,mirror_button.info["random_lights"][i].opacity)
1909                                ctx.set_source_rgba(random.random(),1,1,mirror_button.info["random_lights"][i].opacity)
1910                                ctx.arc(mirror_button.info["random_lights"][i].x,mirror_button.info["random_lights"][i].y,mirror_button.info["random_lights"][i].radius,self.to_rad(0),self.to_rad(360))
1911                                #ctx.arc(mirror_button.info["random_lights"][i].x,mirror_button.info["random_lights"][i].y,random.random()*3,self.to_rad(0),self.to_rad(360))
1912                                ctx.fill()
1913       
1914        #def draw_button
1915
1916       
1917        def mouse_over(self,widget,event,mirror_button):
1918               
1919                #print mirror_button.info
1920                mirror_button.info["animation_active"]=False
1921                if mirror_button.info["shadow_alpha"] <0.3 :
1922                        mirror_button.info["shadow_alpha"]+=0.1
1923                        widget.queue_draw()
1924                        return True
1925                       
1926                return False
1927               
1928        #def mouse_over
1929
1930       
1931        def mouse_left(self,widget,event,mirror_button):
1932               
1933                if not mirror_button.info["animation_active"]:
1934                       
1935                        mirror_button.info["animation_active"]=True
1936                        GLib.timeout_add(10,self.restore_shadow_alpha,mirror_button,widget)
1937                       
1938        #def mouse_left
1939
1940        def info_button_clicked(self,button):
1941               
1942                ret=self.llx_conn.get_last_log()
1943                if ret!=None:
1944                        os.system("xdg-open %s &"%ret)
1945               
1946        #def info_button_clicked
1947
1948        def hide_window(self,widget,event):
1949               
1950                widget.hide()
1951                return True
1952               
1953        #def
1954
1955       
1956        def restore_shadow_alpha(self,mirror_button,widget):
1957
1958                if mirror_button.info["shadow_alpha"] >=0.2 :
1959                        mirror_button.info["shadow_alpha"]-=0.1
1960                        widget.queue_draw()
1961                        return True
1962                       
1963                mirror_button.info["animation_active"]=False
1964                return False
1965               
1966        #def  restore_shadow_alpha
1967       
1968
1969        def to_rad(self,degree):
1970               
1971                return degree * (pi/180)
1972               
1973        #def to_rad
1974       
1975       
1976        def get_wave_y(self,x,wtype=0):
1977               
1978               
1979                #return 1
1980               
1981                x_offset=self.wave_xoffset
1982                amplitude=self.wave_amplitude
1983               
1984                if wtype==1:
1985                        x_offset=self.wave_xoffset2
1986                        amplitude=self.wave_amplitude2
1987                       
1988                if wtype==2:
1989                        x_offset=self.wave_xoffset3
1990                        amplitude=self.wave_amplitude3
1991               
1992                return amplitude * math.sin((2*pi / self.wave_lenght)*(x - x_offset)) + self.wave_yoffset
1993               
1994               
1995        #def get_wave_y
1996
1997
1998        def quit(self,widget):
1999               
2000                Gtk.main_quit()
2001       
2002        #def quit
2003
2004       
2005#class LliurexMirror
2006
2007lm=LliurexMirror()
2008lm.start_gui()
Note: See TracBrowser for help on using the repository browser.