Source

vasm / src / vasm / ui / gtk2 / modules / services.py

Full commit
#!/usr/bin/env python

#    This file is part of VASM.
#
#    VASM is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License v3 as published by
#    the Free Software Foundation.
#
#    VASM is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with VASM.  If not, see <http://www.gnu.org/licenses/>.

__author__ = "Moises Henriquez"
__author_email__ = "moc.liamg@xnl.E0M"[::-1]

import sys
import os
from vasm.ui.gtk2.support import widgets, dialogs
from vasm.backend import services
from vasm.backend.utils import _, datapath
import gtk
import gobject
import threading
import time
import logging

logger = logging.getLogger('vasm')

gobject.threads_init()
# vasm flags

VASM_CATEGORY="%s/%s" % (_("System"), _("Startup Options"))
VASM_LABEL=_("System Services")
VASM_ICON=gtk.STOCK_EXECUTE

def __vasm_test__():
    """ Tests to decide who sees this module in vasm... Must return True | False"""
    return os.geteuid() == 0

class ServicesManager(widgets.VasmModule):
    def __init__(self, parent):
        exp = _("Select which services you would like to enable for each runlevel.") + \
        "  " + _("Click 'Apply' to save your changes.")
        widgets.VasmModule.__init__(self, parent, VASM_LABEL, exp)
        
        # Setup a model to interact with the services
        self.servicemodel = services.ServiceModel()
        
        # the grid
        
        treebox = gtk.HBox()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.servicetree = self.get_service_tree()
        sw.add(self.servicetree)
        treebox.pack_start(sw, True, True, 4)
        self.pack_start(treebox, True, True, 4)
        
        # add the service descriptor to display service details
        self.descriptor = self.get_service_descriptor()
        self.pack_start(self.descriptor, False, True, 4)
        self.idle = True
        self.workmsg = ""
        
        # Add buttons to the action area
        btapply = gtk.Button(stock=gtk.STOCK_APPLY)
        btclose = gtk.Button(stock=gtk.STOCK_CANCEL)
        bthelp = gtk.Button(stock=gtk.STOCK_HELP)
        btclose.connect('clicked', self.close_module)
        btapply.connect('clicked', self.apply_event)
        bthelp.connect('clicked', self.show_services_help)
        self.add_button(btclose)
        self.add_button(btapply)
        self.add_button(bthelp)
        self.describe_service(None)

    def get_service_tree(self):
        """ return a treeview that holds the services grid """
        store = gtk.ListStore(str, bool, bool, bool, bool, bool)
        tree = gtk.TreeView(model=store)
        tree.connect('cursor-changed', self.describe_service)
        tree.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL)
        rendSName = gtk.CellRendererText()
        rendRL2 = gtk.CellRendererToggle()
        rendRL3 = gtk.CellRendererToggle()
        rendRL4 = gtk.CellRendererToggle()
        rendRL5 = gtk.CellRendererToggle()
        
        col = 1
        for rend in (rendRL2, rendRL3, rendRL4, rendRL5):
            col += 1
            rend.connect('toggled', self.toggle_event, store, col)
        # Display the current service status
        for line in self.servicemodel.list_services_with_status():
            store.append(line)
        
        colSName = gtk.TreeViewColumn("Service", rendSName, text=0)
        colRL2 = gtk.TreeViewColumn("Run level 2", rendRL2, active=2, activatable=1)
        colRL3 = gtk.TreeViewColumn("Run level 3", rendRL3, active=3, activatable=1)
        colRL4 = gtk.TreeViewColumn("Run level 4", rendRL4, active=4, activatable=1)
        colRL5 = gtk.TreeViewColumn("Run level 5", rendRL5, active=5, activatable=1)
        
        tree.append_column(colSName)
        colSName.set_resizable(True)
        colSName.set_expand(True)
        colSName.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
        colSName.set_min_width(130)
        for col in (colRL2, colRL3, colRL4, colRL5):
            col.set_resizable(False)
            col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
            col.set_fixed_width(80)
            col.set_expand(False)
            tree.append_column(col)
            
        return tree

    def show_services_help(self, widget=None):
        """ Display a dialog with a little guide for the services module"""
        dia = gtk.Dialog(parent=self._parent, title=_("System Services Help"))
        dia.set_modal(True)
        dia.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL)
        buffer = gtk.TextBuffer()
        helpfile = os.path.join(datapath, 'servicehelp.txt')
        f = open(helpfile, 'r')
        data = f.readlines()
        f.close()
        
        buffer.set_text("".join(data))
        tview = gtk.TextView(buffer)
        tview.set_editable(False)
        hbox = gtk.HBox()
        hbox.pack_start(tview, True, True, 2)
        hbox.show_all()
        dia.get_content_area().pack_start(hbox, True, True, 4)
        dia.set_size_request(400, 300)
        if dia.run():
            dia.destroy()

    def describe_service(self, treeview=None):
        if not treeview:
            # Only expand the label
            self.svc_desc_label.set_markup(
                _("Select a service to see it's description.") + "\n\n")
            return
        model = treeview.get_model()
        cursor = treeview.get_cursor()[0][0]
        selected = model[cursor][0]
        # get the description for this service
        self.svc_desc_label.set_markup(
            "<b>%s</b>\n\n%s"% (selected,
                                services.get_service_desc(selected)))

    def get_service_descriptor(self):
        """ Create a frame with a label inside it used to describe the currently
        selected service"""
        frm = gtk.Frame(_("About this service"))
        box = gtk.HBox()
        frm.add(box)
        self.svc_desc_label = widgets.DLabel()
        box.pack_start(self.svc_desc_label, True, True, 4)
        frm.show_all()
        return frm
    
    def toggle_event(self, cell, path, model, column):
        item = model.get_iter(path)
        model.set_value(item, column, not cell.get_active())
    
    def apply_event(self, widget=None):
        """ Save services configuration as specified in the grid """
    
    # launch a pop-up window with a progressbar indicating the progress.
        treemodel = self.servicetree.get_model()
        svcmodel = self.servicemodel
        wlist = [self.servicetree]
        #wlist = [self.servicetree, self.get_action_area()]
        w = ProgressDialog(parent=self._parent, treemodel=treemodel,
                           servicemodel=svcmodel, wlist=wlist)
        w.set_modal(True)
        w.show_all()
        t = threading.Thread(target=w.pulse_bar)
        wt = threading.Thread(target=w.save_changes)
        w.done = False
        t.start()
        wt.start()

class ProgressDialog(gtk.Dialog):
    """ just a pop-up progress dialog to indicate the system is performing the
    requested changes """
    def __init__(self, parent=None, treemodel=None, servicemodel=None, wlist=[]):
        gtk.Dialog.__init__(self, parent=parent)
        self.treemodel = treemodel
        self.wlist = wlist
        self.servicemodel = servicemodel
        #self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL)
        self.body = self.get_content_area()
        self.set_has_separator(True)
        lbbox = gtk.HBox()
        lbbox.pack_start(gtk.Label(_("Saving system service configuration.")), True, True, 4)
        self.body.pack_start(lbbox, False, True, 4)
        barbox = gtk.HBox()
        self.progressbar = gtk.ProgressBar()
        barbox.pack_start(self.progressbar, True, True, 4)
        self.body.pack_start(barbox, False, True, 4)
        self.set_size_request(300,100)
        self.set_title(_("Working"))
        
        lbbox.show_all()
        barbox.show_all()
        self.done = True
        self.message = ""
        #self.barthread = threading.Thread(target=self.pulse_bar)
        #self.save_changes()
    
    def save_changes(self):
        """ Loop through the services selected and save the changes """
             # columns:
            # 0 = service name
            # 1 = activatable (True or False) [ignored for operations ]
            # 2 = Runlevel 2 value
            # 3 = Runlevel 3 value
            # 4 = Runlevel 4 value
            # 5 = Runlevel 5 value
        
        errors = False # Errors flag
        # Start the thread to pulse the bar
        #self.barthread.start()
        for row in self.treemodel:
            service = row[0]
            for rl in range(2, 6):
                if row[rl] is True:
                    self.message = "Enabling %s for runlevel %s"%(service, rl)
                    logger.debug(self.message)
                    rcode, output = self.servicemodel.enable_service(service, rl)
                    if rcode > 0:
                        errors = True
                        self.parent.errors = True
                else:
                    self.message = "Disabling %s for runlevel %s"% (service, rl)
                    logger.debug(self.message)
                    rcode, output = self.servicemodel.disable_service(service, rl)
                    if rcode > 0:
                        errors = True
                        self.parent.errors = True
        self.done = True
        if errors:
            self.progressbar.set_text(_("Some operations failed!"))
        
        self.progressbar.set_text(_("All operations completed successfully."))
        self.progressbar.set_fraction(1.0)
        
        # automatically close this thing.
        self.set_modal(False)
        self.destroy()
    
    def do_pulse(self):
        self.progressbar.pulse()
        return False
    
    def update_pb_text(self):
        self.progressbar.set_text(self.message)
        return False
        #return self.progressbar.set_text(self.message)
    
    def pulse_bar(self):
        while not self.done:
            gobject.idle_add(self.do_pulse)
            gobject.idle_add(self.update_pb_text)
            time.sleep(0.1)

def __run__(parent):
    manager=ServicesManager(parent)
    return manager.launch()