403Webshell
Server IP : 182.53.201.61  /  Your IP : 216.73.217.175
Web Server : Apache/2.2.15 (Fedora)
System : Linux km10.dyndns.org 2.6.31.5-127.fc12.i686.PAE #1 SMP Sat Nov 7 21:25:57 EST 2009 i686
User : apache ( 48)
PHP Version : 5.3.3
Disable Function : NONE
MySQL : ON  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/share/system-config-lvm/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/share/system-config-lvm/Volume_Tab_View.py
import sys
import types
import select
import math
import operator
import signal
import gobject
import string
import os
from renderer import DisplayView
from Properties_Renderer import Properties_Renderer
from lvm_model import lvm_model
from InputController import InputController
from lvmui_constants import *
from WaitMsg import WaitMsg
from execute import ForkedCommand, execWithCapture



import stat
import gettext
_ = gettext.gettext

### gettext first, then import gtk (exception prints gettext "_") ###
try:
    import gobject
    import gtk
    import gtk.glade
except RuntimeError, e:
    print _("""
  Unable to initialize graphical environment. Most likely cause of failure
  is that the tool was not run using a graphical environment. Please either
  start your graphical user interface or set your DISPLAY variable.
                                                                                
  Caught exception: %s
""") % e
    sys.exit(-1)

import gnome
import gnome.ui

VOLUME_GROUPS=_("Volume Groups")
UNALLOCATED_VOLUMES=_("Unallocated Volumes")
UNINITIALIZED_ENTITIES=_("Uninitialized Entities")
PHYSICAL_VIEW=_("Physical View")
LOGICAL_VIEW=_("Logical View")

                                                                                
#############################################################
class Volume_Tab_View:
  def __init__(self, glade_xml, model_factory, app):
                                                                                
    self.model_factory = model_factory
    
    self.main_win = app
    self.width = 0
    self.height = 0
    self.glade_xml = glade_xml

    ##Set up list structure
    self.treeview = self.glade_xml.get_widget('treeview1')
    self.treemodel = self.treeview.get_model()
    self.treemodel = gtk.TreeStore (gobject.TYPE_STRING,
                                    gobject.TYPE_INT,
                                    gobject.TYPE_STRING,
                                    gobject.TYPE_STRING,
                                    gobject.TYPE_PYOBJECT)
    self.treeview.set_model(self.treemodel)
    self.treeview.set_headers_visible(False)
    
    self.input_controller = InputController(self.reset_tree_model,
                                            self.treeview, 
                                            self.model_factory, 
                                            self.glade_xml)
    
    #Change Listener
    selection = self.treeview.get_selection()
    selection.connect('changed', self.on_tree_selection_changed)
    
    #self.treeview.connect('expand-collapse-cursor-row',self.on_row_expand_collapse)
    #self.treeview.connect('row-collapsed',self.on_row_expand_collapse)
    
    self.icon_ellipse_hashtable = {}
    
    renderer1 = gtk.CellRendererText()
    column1 = gtk.TreeViewColumn("Volumes",renderer1,markup=0)
    self.treeview.append_column(column1)
    
    
    #Time to set up draw area
    window1 = self.glade_xml.get_widget("drawingarea1")
    window1.set_size_request(700, 500)
    window2 = self.glade_xml.get_widget("drawingarea2")
    window2.set_size_request(700, 500)
    window3 = self.glade_xml.get_widget("drawingarea3")
    window3.set_size_request(700, 500)
    window4 = self.glade_xml.get_widget("drawingarea4")
    window4.set_size_request(700, 500)
    
    pr_upper = Properties_Renderer(window3, window3.window)
    #pr_lower = Properties_Renderer(window4, window4.window)
    self.display_view = DisplayView(self.input_controller.register_highlighted_sections, window1, pr_upper, None, None)
    #self.display_view = DisplayView(self.input_controller.register_highlighted_sections, window1, pr_upper, window2, pr_lower)
    
    self.glade_xml.get_widget('best_fit_button').connect('clicked', self.on_best_fit)
    self.glade_xml.get_widget('zoom_in_button').connect('clicked', self.on_zoom_in)
    self.glade_xml.get_widget('zoom_out_button').connect('clicked', self.on_zoom_out)
    self.glade_xml.get_widget('viewport1').connect('size-allocate', self.on_resize_drawing_area)
    self.on_best_fit(None)
    self.glade_xml.get_widget('zoom_box').set_sensitive(False)
    
    # set up mirror copy progress
    self.mirror_sync_progress = MirrorSyncProgress(self.glade_xml.get_widget('messages_vbox'))
    
    
    #############################
    ##Highly experimental
    self.box = self.glade_xml.get_widget('vbox12')
    self.uninit_panel = self.glade_xml.get_widget('uninit_panel')
    self.uninit_panel.hide()
    self.unalloc_panel = self.glade_xml.get_widget('unalloc_panel')
    self.unalloc_panel.hide()
    self.phys_vol_view_panel = self.glade_xml.get_widget('phys_vol_view_panel')
    self.phys_vol_view_panel.hide()
    self.log_vol_view_panel = self.glade_xml.get_widget('log_vol_view_panel')
    self.log_vol_view_panel.hide()
    self.on_rm_select_lvs_button = self.glade_xml.get_widget('on_rm_select_lvs')
    self.phys_panel = self.glade_xml.get_widget('phys_panel')
    self.phys_panel.hide()
    self.log_panel = self.glade_xml.get_widget('log_panel')
    self.log_panel.hide()
    
    self.prepare_tree()
    model = self.treeview.get_model()
    vgs = self.model_factory.get_VGs()
    if len(vgs) > 0:
        model.foreach(self.check_tree_items, [vgs[0].get_name()])
    else:
        unallocs = self.model_factory.query_unallocated()
        if len(unallocs) > 0:
            model.foreach(self.check_tree_items, ['', '', unallocs[0].get_path()])
        else:
            uninits = self.model_factory.query_uninitialized()
            if len(uninits) > 0:
                model.foreach(self.check_tree_items, ['', '', uninits[0].get_path()])
  
  # format is [vgname, lvpath, pvpath] - put '' if none
  def reset_tree_model(self, *in_args):
      self.prepare_tree()
      
      args = []
      for arg in in_args:
          args.append(arg)
      model = self.treeview.get_model()
      model.foreach(self.check_tree_items, args)
  
  def check_tree_items(self, model, path, iter, *args):
    # return True to stop foreach, False to continue
    
    if len(args) == 0:
        return True # don't go any further
    args_internal = []
    for arg in args[0]:
        args_internal.append(arg)
    while len(args_internal) < 3:
        args_internal.append('')
    vgname = args_internal[0]
    lvpath = args_internal[1]
    pvpath = args_internal[2]
    
    selection = self.treeview.get_selection()
    type = model.get_value(iter, TYPE_COL)
    if type == VG_PHYS_TYPE:
        if vgname != '' and lvpath == '' and pvpath != '':
            vg = model.get_value(iter, OBJ_COL)
            if vgname == vg.get_name():
                self.treeview.expand_to_path(path)
                selection.select_path(path)
                return True
    elif type == VG_LOG_TYPE:
        if vgname != '' and lvpath != '' and pvpath == '':
            vg = model.get_value(iter, OBJ_COL)
            if vgname == vg.get_name():
                self.treeview.expand_to_path(path)
                selection.select_path(path)
                return True
    elif type == VG_TYPE:
        if vgname != '' and lvpath == '' and pvpath == '':
            vg = model.get_value(iter, OBJ_COL)
            if vgname == vg.get_name():
                self.treeview.expand_to_path(path)
                selection.select_path(path)
                return True
    elif type == LOG_TYPE:
        if vgname == '' and lvpath != '' and pvpath == '':
            lv = model.get_value(iter, OBJ_COL)
            if lvpath == lv.get_path():
                self.treeview.expand_to_path(path)
                selection.select_path(path)
                return True
    elif type == PHYS_TYPE or type == UNALLOCATED_TYPE or type == UNINITIALIZED_TYPE:
        if vgname == '' and lvpath == '' and pvpath != '':
            pv = model.get_value(iter, OBJ_COL)
            if pvpath in pv.get_paths():
                self.treeview.expand_to_path(path)
                selection.select_path(path)
                return True
    return False

  def prepare_tree(self):
    treemodel = self.treeview.get_model()
    treemodel.clear()
    
    self.model_factory.reload()
    self.mirror_sync_progress.initiate()
    
    vg_list = self.model_factory.get_VGs()
    if len(vg_list) > 0:
        vg_iter = treemodel.append(None)
        vg_string = "<span size=\"11000\"><b>" + VOLUME_GROUPS + "</b></span>"
        treemodel.set(vg_iter,
                      NAME_COL, vg_string, 
                      TYPE_COL,
                      UNSELECTABLE_TYPE)
        self.__sort_list_by_get_name_fcn(vg_list)
        for vg in vg_list:
            vg_child_iter = treemodel.append(vg_iter)
            vg_name = vg.get_name()
            vg_name_marked = vg_name
            if vg.clustered():
                vg_name_marked += '<span foreground="#FF00FF">   (' + _('Clustered VG') + ')</span>'
            treemodel.set(vg_child_iter,
                          NAME_COL, vg_name_marked, 
                          TYPE_COL, VG_TYPE, 
                          OBJ_COL, vg)
            phys_iter = treemodel.append(vg_child_iter)
            log_iter = treemodel.append(vg_child_iter)
            pview_string = "<span foreground=\"#ED1C2A\"><i>  " + PHYSICAL_VIEW + "</i></span>"
            treemodel.set(phys_iter,
                          NAME_COL, pview_string,
                          TYPE_COL, VG_PHYS_TYPE,
                          PATH_COL, vg_name, 
                          OBJ_COL, vg)
            lview_string = "<span foreground=\"#43ACF6\"><i>  " + LOGICAL_VIEW + "</i></span>"
            treemodel.set(log_iter,
                          NAME_COL, lview_string,
                          TYPE_COL, VG_LOG_TYPE,
                          PATH_COL, vg_name, 
                          OBJ_COL, vg)
            
            pv_list = vg.get_pvs().values()
            grouped_dir, ungrouped_list = self.__group_by_device(pv_list)
            grouped_dir_sorted = grouped_dir.keys()
            grouped_dir_sorted.sort()
            for main_dev in grouped_dir_sorted:
                dev_iter = treemodel.append(phys_iter)
                pvs = grouped_dir[main_dev]
                devnames = pvs[0].getDevnames()
                devnames_str = devnames[0]
                for devname in devnames[1:]:
                    devnames_str = devnames_str + ', ' + devname
                if len(devnames) > 1:
                    devnames_str = str(pvs[0].getMultipath()) + ' [' + devnames_str + ']'
                treemodel.set(dev_iter, 
                              NAME_COL, devnames_str, 
                              TYPE_COL, UNSELECTABLE_TYPE)
                for pv in pvs:
                    iter = treemodel.append(dev_iter)
                    phys_string = "<span foreground=\"#ED1C2A\">" + pv.get_name() + "</span>"
                    treemodel.set(iter, 
                                  NAME_COL, phys_string, 
                                  TYPE_COL, PHYS_TYPE, 
                                  PATH_COL, pv.get_path(), 
                                  OBJ_COL, pv)
            for pv in ungrouped_list:
                iter = treemodel.append(phys_iter)
                phys_string = "<span foreground=\"#ED1C2A\">" + pv.get_name() + "</span>"
                treemodel.set(iter, 
                              NAME_COL, phys_string, 
                              TYPE_COL, PHYS_TYPE, 
                              PATH_COL, pv.get_path(), 
                              OBJ_COL, pv)
            
            lv_list = vg.get_lvs().values()
            self.__sort_list_by_get_name_fcn(lv_list)
            for lv in lv_list:
                if lv.is_used():
                    iter = treemodel.append(log_iter)
                    log_string = "<span foreground=\"#43ACF6\">" + lv.get_name() + "</span>"
                    treemodel.set(iter, 
                                  NAME_COL, log_string, 
                                  TYPE_COL, LOG_TYPE,
                                  PATH_COL, lv.get_path(),
                                  SIMPLE_LV_NAME_COL, lv.get_name(),
                                  OBJ_COL, lv)
            
            #Expand if there are entries 
            self.treeview.expand_row(treemodel.get_path(vg_iter),False)
            
    unalloc_list = self.model_factory.query_unallocated()
    if len(unalloc_list) > 0:
        unallocated_iter = treemodel.append(None)
        unalloc_string = "<span size=\"11000\"><b>" + UNALLOCATED_VOLUMES + "</b></span>"
        treemodel.set(unallocated_iter,
                      NAME_COL, unalloc_string, 
                      TYPE_COL, UNSELECTABLE_TYPE)
        grouped_dir, ungrouped_list = self.__group_by_device(unalloc_list)
        grouped_dir_sorted = grouped_dir.keys()
        grouped_dir_sorted.sort()
        for main_dev in grouped_dir_sorted:
            dev_iter = treemodel.append(unallocated_iter)
            pvs = grouped_dir[main_dev]
            devnames = pvs[0].getDevnames()
            devnames_str = devnames[0]
            for devname in devnames[1:]:
                devnames_str = devnames_str + ', ' + devname
            if len(devnames) > 1:
                devnames_str = str(pvs[0].getMultipath()) + ' [' + devnames_str + ']'
            treemodel.set(dev_iter, 
                          NAME_COL, devnames_str, 
                          TYPE_COL, UNSELECTABLE_TYPE)
            for pv in pvs:
                iter = treemodel.append(dev_iter)
                phys_string = "<span foreground=\"#ED1C2A\">" + pv.get_name() + "</span>"
                treemodel.set(iter, 
                              NAME_COL, phys_string, 
                              TYPE_COL, UNALLOCATED_TYPE, 
                              PATH_COL, pv.get_path(), 
                              OBJ_COL, pv)
        for pv in ungrouped_list:
            iter = treemodel.append(unallocated_iter)
            phys_string = "<span foreground=\"#ED1C2A\">" + pv.get_path() + "</span>"
            treemodel.set(iter, 
                          NAME_COL, phys_string, 
                          TYPE_COL, UNALLOCATED_TYPE, 
                          PATH_COL, pv.get_path(), 
                          OBJ_COL, pv)
    
    uninit_list = self.model_factory.query_uninitialized()
    if len(uninit_list) > 0:
        uninitialized_iter = treemodel.append(None)
        uninit_string = "<span size=\"11000\"><b>" + UNINITIALIZED_ENTITIES + "</b></span>"
        treemodel.set(uninitialized_iter, 
                      NAME_COL, uninit_string, 
                      TYPE_COL, UNSELECTABLE_TYPE)
        grouped_dir, ungrouped_list = self.__group_by_device(uninit_list)
        grouped_dir_sorted = grouped_dir.keys()
        grouped_dir_sorted.sort()
        for main_dev in grouped_dir_sorted:
            dev_iter = treemodel.append(uninitialized_iter)
            pvs = grouped_dir[main_dev]
            devnames = pvs[0].getDevnames()
            devnames_str = devnames[0]
            for devname in devnames[1:]:
                devnames_str = devnames_str + ', ' + devname
            if len(devnames) > 1:
                devnames_str = str(pvs[0].getMultipath()) + ' [' + devnames_str + ']'
            treemodel.set(dev_iter,
                          NAME_COL, devnames_str, 
                          TYPE_COL, UNSELECTABLE_TYPE)
            for pv in grouped_dir[main_dev]:
                iter = treemodel.append(dev_iter)
                treemodel.set(iter, 
                              NAME_COL, pv.get_name(), 
                              TYPE_COL, UNINITIALIZED_TYPE, 
                              PATH_COL, pv.get_path(), 
                              OBJ_COL, pv)
        for pv in ungrouped_list:
            iter = treemodel.append(uninitialized_iter)
            treemodel.set(iter, 
                          NAME_COL, pv.get_path(), 
                          TYPE_COL, UNINITIALIZED_TYPE, 
                          PATH_COL, pv.get_path(), 
                          OBJ_COL, pv)
    
    #self.treeview.expand_all()
    self.clear_all_buttonpanels()
  
  # returns {main_dev : [pv1, pv2, ...], ...}
  def __group_by_device(self, pvlist):
      grouped = {}
      ungrouped = []
      for pv in pvlist:
          if len(pv.getDevnames()) == 0 or pv.wholeDevice():
              ungrouped.append(pv)
              continue
          if pv.getDevnames()[0] in grouped.keys():
              grouped[pv.getDevnames()[0]].append(pv)
          else:
              grouped[pv.getDevnames()[0]] = [pv]

      # sort lists
      for main_dev in grouped:
          self.__sort_list_by_get_name_fcn(grouped[main_dev])
      self.__sort_list_by_get_name_fcn(ungrouped)
      return grouped, ungrouped
  
  def __sort_list_by_get_name_fcn(self, some_list):
      d = {}
      l = []
      while len(some_list) != 0:
          o = some_list.pop()
          name = o.get_name()
          if name in d:
              d[name].append(o)
          else:
              d[name] = [o]
              l.append(name)
      l.sort()
      for name in l:
          for o in d[name]:
              some_list.append(o)
      return some_list
  
  def on_tree_selection_changed(self, *args):
    selection = self.treeview.get_selection()
    model,iter = selection.get_selected()
    if iter == None:
        self.glade_xml.get_widget('zoom_box').set_sensitive(False)
        self.display_view.render_no_selection()
        self.display_view.draw()
        return
    
    treepath = model.get_path(iter)
    self.treeview.expand_row(treepath, False)
    
    type = model.get_value(iter, TYPE_COL)
    if type == VG_PHYS_TYPE:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        self.phys_vol_view_panel.show()
        
        vg = model.get_value(iter, OBJ_COL)
        pv_list = vg.get_pvs().values()
        self.display_view.render_pvs(pv_list)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(True)
    elif type == VG_LOG_TYPE:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        
        vg = model.get_value(iter, OBJ_COL)
        lv_list = vg.get_lvs().values()
        self.show_log_vol_view_panel(lv_list)
        self.display_view.render_lvs(lv_list)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(True)
    elif type == VG_TYPE:
        self.clear_all_buttonpanels()
        self.input_controller.clear_highlighted_sections()
        
        vg = model.get_value(iter, OBJ_COL)
        self.display_view.render_vg(vg)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(True)
    elif type == LOG_TYPE:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        self.log_panel.show()
        
        lv = model.get_value(iter, OBJ_COL)
        self.display_view.render_lv(lv)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(False)
    elif type == PHYS_TYPE:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        self.phys_panel.show()
        
        pv = model.get_value(iter, OBJ_COL)
        self.display_view.render_pv(pv)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(True)
    elif type == UNALLOCATED_TYPE:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        self.unalloc_panel.show()
        
        pv = model.get_value(iter, OBJ_COL)
        self.display_view.render_unalloc_pv(pv)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(False)
    elif type == UNINITIALIZED_TYPE:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        button = self.input_controller.init_entity_button
        
        uv = model.get_value(iter, OBJ_COL)
        if uv.initializable:
            button.set_sensitive(True)
        else:
            button.set_sensitive(False)
        self.uninit_panel.show()
        self.display_view.render_uninit_pv(uv)
        self.on_best_fit(None)
        self.glade_xml.get_widget('zoom_box').set_sensitive(False)
    else:
        self.input_controller.clear_highlighted_sections()
        self.clear_all_buttonpanels()
        self.display_view.render_no_selection()
        self.display_view.draw()
        self.glade_xml.get_widget('zoom_box').set_sensitive(False)
  
  def on_row_expand_collapse(self, treeview, logical,expand, openall, *params):
    treeview.get_model()
    selection = treeview.get_selection()
    model, iter = selection.get_selected()
#    if model.iter_parent(iter) == None:  #Top level
    return True
#    else:
#    return False

  def show_log_vol_view_panel(self,lv_list):
    #This is a wrapper for self.log_vol_view_panel.show()
    #If the VG has no LVs, then a proxy LV is returned as an 'Unused' LV.
    #We do not want to allow the deletion of this unused LV.
    #So we'll gray out the button.
    self.on_rm_select_lvs_button.set_sensitive(True)
    if len(lv_list) == 1:
        if lv_list[0].is_used() == False:
            self.on_rm_select_lvs_button.set_sensitive(False)
    self.log_vol_view_panel.show()
  
  def clear_all_buttonpanels(self):
      self.unalloc_panel.hide()
      self.uninit_panel.hide()
      self.log_vol_view_panel.hide()
      self.phys_vol_view_panel.hide()
      self.log_panel.hide()
      self.phys_panel.hide()
      
  
  def on_best_fit(self, obj):
      self.on_resize_drawing_area(None, None)
      self.__set_zoom_buttons(self.display_view.set_best_fit())
      self.display_view.draw()
  
  def on_zoom_in(self, obj):
      self.__set_zoom_buttons(self.display_view.zoom_in())
      self.display_view.draw()
  
  def on_zoom_out(self, obj):
      self.__set_zoom_buttons(self.display_view.zoom_out())
      self.display_view.draw()
  
  def __set_zoom_buttons(self, (z_in, z_out)):
      if z_in:
          self.glade_xml.get_widget('zoom_in_button').set_sensitive(True)
      else:
          self.glade_xml.get_widget('zoom_in_button').set_sensitive(False)
      if z_out:
          self.glade_xml.get_widget('zoom_out_button').set_sensitive(True)
      else:
          self.glade_xml.get_widget('zoom_out_button').set_sensitive(False)
  
  def on_resize_drawing_area(self, obj1, obj2):
      self.display_view.set_visible_size(self.glade_xml.get_widget('viewport1').window.get_size())
  

class MirrorSyncProgress:
    def __init__(self, vbox):
        self.vbox = vbox
        
        # {name : [hbox, progressbar], ...}
        self.progress_bars = {}
        
        self.timer = 0
        
        self.forked_command = None
        
    
    def initiate(self):
        if MIRRORING_UI_SUPPORT == False:
            return
        
        # return if timer is already ticking
        if self.timer != 0:
            return
        if self.crank():
            # set up timer to call crank
            self.timer = gobject.timeout_add(1000, self.crank)
    
    def crank(self):
        # initiate lvprobe if not initiated
        if self.forked_command == None:
            args = [LVM_BIN_PATH, 'lvs', '--noheadings', '--separator', ';', '-o', 'lv_name,vg_name,lv_attr,copy_percent,move_pv']
            self.forked_command = ForkedCommand(LVM_BIN_PATH, args)
            self.forked_command.fork()
        
        # get lv data if completed
        out, err, status = self.forked_command.get_stdout_stderr_status()
        if out == None:
            # not done yet
            return True
        else:
            # command completed
            self.forked_command = None
            
            # find mirrors and copy percent
            mirrors = {}
            lines = out.splitlines()
            for line in lines:
                words = line.strip().split(';')
                lvname = words[0]
                vgname = words[1]
                lvattrs = words[2]
                copy_percent = words[3]
                if lvattrs[0] == 'm':
                    percent = float(copy_percent)
                    if percent != float('100.00'):
                        mirrors[vgname + '/' + lvname] = percent
            
            # add new lvs
            for name in mirrors:
                if name not in self.progress_bars:
                    progress = gtk.ProgressBar()
                    progress.set_text(_("%s mirror synchronisation") % name)
                    progress.set_fraction(mirrors[name]/100.0)
                    hbox = gtk.HBox()
                    hbox.pack_end(progress)
                    self.vbox.pack_start(hbox)
                    self.progress_bars[name] = [hbox, progress]
            # remove completed or renamed lvs
            for name in self.progress_bars.keys()[:]:
                if name not in mirrors:
                    self.vbox.remove(self.progress_bars[name][0])
                    self.progress_bars.pop(name)
            
            self.vbox.show_all()
            # update progress bars
            for name in self.progress_bars:
                self.progress_bars[name][1].set_fraction(mirrors[name]/100.0)
                
            # stop timer if all done
            if len(self.progress_bars.keys()) == 0:
                self.timer = 0
                return False
            else:
                return True

Youez - 2016 - github.com/yon3zu
LinuXploit