diff --git a/python/ri_data.py b/python/ri_data.py index afb7b3c..1bbad89 100644 --- a/python/ri_data.py +++ b/python/ri_data.py @@ -462,7 +462,7 @@ p - pkg, that includes this service pass for s in Service.list: - if s.pkg in l: + if s.package in l: if s.start == 'disable': s.start = 'no' else: diff --git a/python/ri_dep.py b/python/ri_dep.py new file mode 100644 index 0000000..b657cda --- /dev/null +++ b/python/ri_dep.py @@ -0,0 +1,82 @@ +#!/usr/bin/python + +import ri_data + +from xml.dom import minidom +import os.path + +dep_xml = os.path.join(os.path.dirname(__file__), '../xml/dependency.xml') + +class Depending: + ''' Class recording depending relation ''' + dict={} + def __init__(self, n): + self.name = n + self.depending = set() + # flag for resolve recursive + self.resolved = False + Depending.dict[n] = self + + def resolve_recursive(self): + if self.resolved: return + for d in self.depending: + Depending.dict[d].resolve_recursive() + tmp=set(self.depending) + for d in self.depending: + tmp.update(Depending.dict[d].depending) + self.depending = tmp + self.resolved = True + +class Depended: + ''' Class recording depended by relation ''' + dict={} + def __init__(self, n): + self.name = n + self.depended_by = set() + Depended.dict[n] = self + +def construct_depending(): + xml_doc = minidom.parse(dep_xml) + xml_root = xml_doc.firstChild + xml_dict = {} + for n in xml_root.childNodes: + if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'package': + xml_dict[n.attributes['name'].value] = n + Depending(n.attributes['name'].value) + + for d in Depending.dict.values(): + n = xml_dict[d.name] + for r in n.getElementsByTagName('runtime'): + for dep in r.getElementsByTagName('depending'): + d.depending.add(dep.attributes['package'].value) + +def resolve_recursive_depending(): + for d in Depending.dict.values(): + d.resolve_recursive() + +def construct_depended(): + for d in Depending.dict.values(): + for dep in d.depending: + if not Depended.dict.has_key(dep): + Depended(dep) + Depended.dict[dep].depended_by.add(d.name) + +def get_extra_depending(): + l = [] + for g in ri_data.Group.dict.values(): + if g.install != 'no': + l.extend([ p for p in g.mandatory ]) + l.extend([ p[0] for p in g.optional if p[1] == 'yes' ]) + + set1 = set(l) + set2 = set(set1) + + for d in set1: + set2.update(Depending.dict[d].depending) + + res = {} + for d in set2.difference(set1): + res[d] = Depended.dict[d].depended_by.intersection(set1) + + return res + diff --git a/python/ri_tk.py b/python/ri_tk.py index a47e5c6..d0d2f30 100644 --- a/python/ri_tk.py +++ b/python/ri_tk.py @@ -210,6 +210,9 @@ class SoftwarePackageWindow(): if self.selection.get() == 'all': for ck in self.opt_chks: ck.configure(state='disable') + else: + for ck in self.opt_chks: + ck.configure(state='normal') def ok(self): @@ -218,10 +221,16 @@ class SoftwarePackageWindow(): for i in range(len(self.group.optional)): # install field, yes or no self.group.optional[i][1] = self.opt_vars[i].get() + # clear variables and check buttons + self.opt_vars = [] + self.opt_chks = [] self.win.destroy() def cancel(self): ''' callback function for button cancel ''' + # clear variables and check buttons + self.opt_vars = [] + self.opt_chks = [] self.win.destroy() def show(self): diff --git a/python/ri_tk_cmd.py b/python/ri_tk_cmd.py new file mode 100644 index 0000000..709f371 --- /dev/null +++ b/python/ri_tk_cmd.py @@ -0,0 +1,228 @@ +#!/usr/bin/python +''' handle gui commands ''' +import ri_tk as display +import ri_widget +import ri_data +import ri_dep + +import re +import copy +import sys + +def serial_no_init(): + display.var_dict['serial_no.number'].set(value=ri_data.SerialNumber.value) + +def serial_no_quit(): + ri_data.SerialNumber.value = display.var_dict['serial_no.number'].get() + +def mount_list_init(): + ''' initialize mount list ''' + l = [] + for m in ri_data.MountPoint.list: + # get size from Partition info + sz = ri_data.Partition.get_size(m.device) + if not sz: + sz = ri_data.Raid.get_size(m.device) + print m.device, m.directory, m.filesystem, m.format, sz + s = m.device.ljust(10) + m.directory.ljust(10) + m.filesystem.ljust(10) + m.format.ljust(4) + sz.ljust(6) + l.append(s) + display.var_dict['mount.list'].set(value=tuple([str(i) for i in l])) + +def mount_list_modify(*args): + ''' modify an item in mount list ''' + tw = ri_widget.TopWindow.dict['mount_list_modify'] + tw.show() + +def mp_top_init(): + ''' mount dir top window initialize ''' + ml_win = ri_widget.Widget.dict['mount.list'].tk_widget + idxs = ml_win.curselection() + if len(idxs) == 1: + idx = int(idxs[0]) + mp = ri_data.MountPoint.list[idx] + dev = mp.device + dir = mp.directory + fs = mp.filesystem + fm = mp.format + sz = mp.size + display.var_dict['mp_top_dev'].set(value=dev) + display.var_dict['mp_top_size'].set(value=sz) + display.var_dict['mp_top_dir'].set(value=dir) + if fm == 'yes': + ri_widget.Widget.dict['mp_top_format'].tk_widget.select() + else: + ri_widget.Widget.dict['mp_top_not_format'].tk_widget.select() + + fs_values = eval(display.var_dict['mp_top_fs'].get()) + for i in range(len(fs_values)): + if fs == fs_values[i]: + ri_widget.Widget.dict['mp_top_fs'].tk_widget.selection_set(i) + +def mp_top_ok(): + ''' mount dir top window OK ''' + l = [] + for itm in eval(display.var_dict['mount.list'].get()): + dev = itm.split()[0] + dev2 = display.var_dict['mp_top_dev'].get() + if dev == dev2: + sz = display.var_dict['mp_top_size'].get() + dir = display.var_dict['mp_top_dir'].get() + fm = display.var_dict['mp_top_format'].get() + idxs2 = ri_widget.Widget.dict['mp_top_fs'].tk_widget.curselection() + if len(idxs2): + idx2 = int(idxs2[0]) + fs = eval(display.var_dict['mp_top_fs'].get())[idx2] + else: + fs = '' + + s2 = dev.ljust(10) + dir.ljust(10) + fs.ljust(10) + fm.ljust(4) + sz.ljust(6) + l.append(s2) + # make change in internal data structure + ri_data.MountPoint.change(dev2, dir, fs, fm) + else: + l.append(itm) + + display.var_dict['mount.list'].set(value=tuple(l)) + ri_widget.TopWindow.dict['mount_list_modify'].hide() + +def mp_top_cancel(): + ''' mount dir top window cancel ''' + ri_widget.TopWindow.dict['mount_list_modify'].hide() + pass + +def network_init(): + ''' network initialize ''' + display.var_dict['network_host_name']. set(value=ri_data.Network.hostname) + ri_widget.Widget.dict['network_config_%s' %(ri_data.Network.configuration and ri_data.Network.configuration or 'static')].tk_widget.invoke() + display.var_dict['network_domain_name']. set(value=ri_data.Network.domain) + display.var_dict['network_ip']. set(value=ri_data.Network.ip) + display.var_dict['network_subnet_mask']. set(value=ri_data.Network.mask) + display.var_dict['network_gateway']. set(value=ri_data.Network.gateway) + display.var_dict['network_primary_dns']. set(value=ri_data.Network.primary_dns) + display.var_dict['network_secondary_dns'].set(value=ri_data.Network.secondary_dns) + +def network_quit(): + ''' network quit ''' + ri_data.Network.hostname = display.var_dict['network_host_name'].get() + ri_data.Network.configuration = display.var_dict['network_config_method'].get() + ri_data.Network.domain = display.var_dict['network_domain_name'].get() + ri_data.Network.ip = display.var_dict['network_ip'].get() + ri_data.Network.mask = display.var_dict['network_subnet_mask'].get() + ri_data.Network.gateway = display.var_dict['network_gateway'].get() + ri_data.Network.primary_dns = display.var_dict['network_primary_dns'].get() + ri_data.Network.secondary_dns = display.var_dict['network_secondary_dns'].get() + +def ncm_dynamic(): + ''' when radio button ncm dynamic is checked, several data entry will be set 'disable' ''' + + for n in ('network_domain_name','network_ip','network_subnet_mask','network_gateway','network_primary_dns','network_secondary_dns'): + ri_widget.Widget.dict[n].tk_widget.configure(state='disable') + +def ncm_static(): + ''' when radio button ncm static is checked, several data entry will be set 'normal' ''' + for n in ('network_domain_name','network_ip','network_subnet_mask','network_gateway','network_primary_dns','network_secondary_dns'): + ri_widget.Widget.dict[n].tk_widget.configure(state='normal') + +class GroupButton(object): + ''' A function class called whenever the group button is clicked ''' + dict={} + def __init__(self, g): + self.name = g.name + GroupButton.dict[g.name] = self + display.SoftwarePackageWindow(g) + + def __call__(self): + print self.name + display.SoftwarePackageWindow.dict[self.name].show() + +class GroupCheck(GroupButton): + ''' A function class called whenever the group check button is checked ''' + def __init__(self, g, v): + self.variable = v + GroupButton.__init__(self, g) + + def __call__(self): + v = display.var_dict[self.variable] + if v.get() == 'yes': + display.SoftwarePackageWindow.dict[self.name].show() + +def software_group_mandatory_construct(w): + ''' construct widgets based actual data +w - Widget instance ''' + mdt = [ m for m in ri_data.Group.dict.values() if m.install == 'mandatory' ] + wit = w.widgets.pop() + for i in mdt: + wi = copy.deepcopy(wit) + wi.attr['text'] = i.name + vn = "software_group_%s" %(i.name) + idx = mdt.index(i) + wi.grid_location.dict['column'] = idx % int(w.grid_management.columns) + wi.grid_location.dict['row'] = idx / int(w.grid_management.columns) + gc = GroupButton(i) + setattr(sys.modules['ri_cmd'], vn, gc) + wi.attr['command'] = vn + w.add_sub_widget(wi) + +def software_group_optional_construct(w): + ''' construct widgets based actual data +w - Widget instance ''' + opt = [ o for o in ri_data.Group.dict.values() if o.install != 'mandatory' ] + wit = w.widgets.pop() + for i in opt: + wi = copy.deepcopy(wit) + wi.attr['text'] = i.name + vn = "software_group_%s" %(i.name) + idx = opt.index(i) + wi.grid_location.dict['column'] = idx % int(w.grid_management.columns) + wi.grid_location.dict['row'] = idx / int(w.grid_management.columns) + gc = GroupCheck(i, vn) + setattr(sys.modules['ri_cmd'], vn, gc) + wi.attr['command'] = vn + wi.attr['variable'] = vn + wi.variables = [(vn, 'StringVar', i.install),] + w.add_sub_widget(wi) + +def software_group_optional_quit(): + ''' software group window quit, record optional group state ''' + opt = [ o for o in ri_data.Group.dict.values() if o.install != 'mandatory' ] + for i in opt: + print i.name + vn = "software_group_%s" %(i.name) + i.install = display.var_dict[vn].get() + print i.name, i.install + +def dependency_list_init(): + ''' init function for list in dependency step ''' + ri_dep.construct_depending() + ri_dep.resolve_recursive_depending() + ri_dep.construct_depended() + dep_dict = ri_dep.get_extra_depending() + l = [ k.ljust(15) + ': ' + ' '.join(dep_dict[k]) for k in dep_dict.keys()] + display.var_dict['dependency.list'].set(value=tuple(l)) + +def service_construct(w): + ''' construct service widget based on actual data +w - Widget instance ''' + + # first refresh service state + ri_data.Service.change_state() + wit = w.widgets.pop() + for i in ri_data.Service.list: + wi = copy.deepcopy(wit) + wi.attr['text'] = i.name + vn = "service_%s" %(i.name) + wi.attr['variable'] = vn + wi.variables = [(vn, 'StringVar', i.start=='yes' and 'yes' or 'no')] + if i.start == 'disable': + wi.attr['state'] = 'disable' + idx = ri_data.Service.list.index(i) + wi.grid_location.dict['column'] = idx % int(w.grid_management.columns) + wi.grid_location.dict['row'] = idx / int(w.grid_management.columns) + w.add_sub_widget(wi) + +def service_quit(): + ''' record service state ''' + for i in ri_data.Service.list: + if i.start != 'disable': + vn = "service_%s" %(i.name) + i.start = display.var_dict[vn].get() diff --git a/xml/install.xml b/xml/install.xml index 1f0bdca..6d3f0b3 100644 --- a/xml/install.xml +++ b/xml/install.xml @@ -23,7 +23,7 @@ - + @@ -85,7 +85,7 @@ - + 办公类包括 OpenOffice.org 等办公软件。 办公类都是必选软件包,当选择安装该类后,必选包是默认安装的。 @@ -94,7 +94,7 @@ - + KDE是一种著名的自由图形工作环境,整个系统采用Qt程序库 KDE桌面类都是可选软件包,可以自由选择安装。 @@ -240,8 +240,8 @@ - - + + @@ -461,7 +461,7 @@ - + diff --git a/xml/interface_t.xml b/xml/interface_t.xml index eca19d7..5ddc20b 100644 --- a/xml/interface_t.xml +++ b/xml/interface_t.xml @@ -456,6 +456,70 @@ row 4 | | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -615,5 +679,7 @@ row 4 | | + +