complete most xml relax ng work.
work on real interface xml
work on python scripts for parsing interface xml
This commit is contained in:
lizhi-rocky
2010-07-08 11:52:50 +08:00
commit d1760bad48
11 changed files with 900 additions and 0 deletions

102
design.txt Normal file
View File

@@ -0,0 +1,102 @@
Refactory of Install Program
Li Zhi
06/18/2010
1. Introduction
Why I start to rewrite the install program? What problems are there in current install program? These are 2 questions being first raised. My answer is the current install program has 7 sins :-)
1) Very verbose. Same or similar code being scattered everywhere.
2) Complicated. I have asked the author why it is so complicated. He said it was the nature. I do not think so.
3) No layer. There should be at least 3 layers: interface layer( GUI or curses), data layer, and operation layer. In current code, they are messed up, no layers seen.
4) Different operating logic between different interfaces. GUI and curses used different operating code. This is very ridiculous. So it was always heard that bug XXX was fixed in GUI but not in curses, or vice versa.
5) No unified data representation. It seems that every step stores its own information into one or more data files, with its own decided file names. It is very hard to have general, whole, deep insight on information used in install progress.
6) Ridiculous representation on devices, partitions, etc. This is related to sin 5. It is strange and ridiculous to see that current install program can not handle HP machine, just because its hard disk is like "/dev/cciss/xxx", not like "/dev/sdaX".
7) Monolithic. Although it is formed by several program files, you can not divide it easily. Can I hand write the data files, then run the install program? Can I write a script to run install program automatically? The answer is no.
So, if you were I, would you re-write it or not?
2. Overview
The key point, I deem as the first, is layering, with which sin 3 and 4 will be removed. I would like to divide the install program into 3 layers: interface layer, data manipulating layer, and install operation layer.
The second is to construct a unified data representtation, with which sin 5 and 6 will be removed.
To sin 1 and 2, it is related to programming skills.
If all above sins are removed, sin 7 will be probably distinguished too.
The overall graph will be:
Interface Data Operation
----------
| |
| GUI |----------------
| | \
---------- \
----------- \ ----------- -----------
| XML for | \ | | | |
| Interface | --- | XML for | ----- | Install |
----------- / | Install | | Operation |
/ | | | |
---------- / ----------- -----------
| | /
| Curses |----------------
| |
----------
figure 2-1
3. Details
Current install program is written in Tcl language. Tcl has a fame of not suitable to write big software project. And, I am not familar with it. So I choose Python as the programming language.
3.1 Interface layer
There will be 2 interfaces: GUI and Curses. I want to have the same layout and the same style between them. So I need a central data file to record the widgets. That will be a "XML for Interface" file, as indicated in figure 2-1. In before, install program has 2 seperate interface, among which there's no relation. This is not good.
One world, one dream!
As mentioned above, there will be one unified xml file for both GUI and Curses. Another one I want to unify is the structure/relation among processes and windowes. In the current install program, there's a strange behavior. Every step starts a new process, which will display a window. For example, there are 3 steps: step1, step2, step3. In normal sequence, when you executes step 1, then step 2, and finally step 3, if you "ps" processes, you will find 3 processes. But when you execute step 1, step 2, then back to step 1, step 2 again, finally step 3, there will be 5 processes: step 1, step 2, step 1, step 2, and step 3. If you wander in steps back and forth more, you will get more processes. In GUI, you will find many windows too, for each process has a window.
One method to solve this problem is to use "exec" rather than starting a new sub-process. Do you think that is best? OK, after I saw a demo program to show python plus dialog usage, I know there is a much better way. In my code, there will be only one process and only one window. What is changed is the display content among differnt steps.
3.1.1 GUI
Python Tkinter is chosen as the tool. Grid is chose as the geometry manager.
Basically, each window will be divided into 5x3 grids, 5 rows plus 3 columns. Among them, row 0, 1, and 3 are same, while row 4 is partially same. The only changable one is row 3.
The graph is as below:
column 0 column 1 column 2
------------------------------------------------------------
row 0 | logo version |
row 1 |------------------------------------------------------------|
row 2 | |
row 3 | copyright information |
row 4 | quit previous next |
------------------------------------------------------------
figure 3.1.1-1
How to connect different windows? There are 2 alternatives. One is using Ids. Every window has a id, my program just sorts windows according to Ids. For example, there are 3 windows with id 1, 2, and 3. Number 1 window will be first displayed, when user clicks "next", number 2 window will be displayed. It seems reasonable, right? If it did not have the following 2 drawbacks, I would not think about the second alternative: first, id is an inborn attribute to each window, you have to decide the install sequence at the same time or before you define the window; second it is a little hard to solve the "detour" problem. The install sequence is not a straight line, but has some side road, which is called "detour" by I. For example, when in partition dividing, there may or may not be some windows for RAID setup.
Now comes the second alternative: using names. I admit and believe that human beings like string while computers like number. Each window has a name. The install/setup sequence will be defined separately like ["welcome", "serial number", "partition dividing", "package selecting"]. For detour problem, the sequence will be like ["welcome", "serial number", "partition dividing", ["raid 1" "raid 2" "raid 3"], "package selecting"].
3.1.2 Curses
I have investigated several choices: urwid, pycdk, and python+dialog. Some is a little complicated and error-prone: urwid. Some has few documents: pycdk. Finally, I chose python+dialog. It is simple, and workable. I like the demo.py in it very much. It is very terse.
The curses interface will be simple and terse. It will only include the changing part in GUI interface, that is, the row 2.
3.1.3 XML and XML parser
As previously mentioned, I will use XML to record widgets (Frame, Button, Label...). Here the detail will be discussed. For GUI, there shall be 3 kinds of information: Widgets attributes: background, height, width, text, command, etc, grid location - which row and column it will be located, and grid management. For details, please refer to:
* http://www.pythonware.com/library/tkinter/
* http://www.tkdocs.com/tutorial/
Besides these, 2 things I also think about: multi-language support(at least English & Chinese) and inheritance among windows/frames. Can Chinese font be displayed in Curses mode? I'm not sure for now. And, at least supporting English is not a bad choice, I think. As I mentioned in section 3.1.1, most windows are similar, they are 5 rows X 3 columns, and only one or two rows are different. So if I brought in a somehow inheritance way into xml format, it would save a lot of code lines and errors.
To the first problem, I will design a data type "Message" in XML in which there're key, English text, and Chinese text. All messages used, such as a text on a button, will be references to "Message" variables, via key(for long message) or just English text(for short text). To the second problem, I will introduce XML elements/attributes "derived_from" and "exception", which are similar to what I have done in building system implementation.
3.2 Data layer
I have inspected those data files generated by current install program. After trying to merge them into one unified data, in xml format, I found it is unbelievable simple!
Data layer will provide a xml file, and a series of functions to access data in it.
3.3 Operation
This is a typical data-driven design. At last, based data read from xml file, operation layer does installing work. Roughly, it will include the following part:
* partitioning
* setting up raid(optional)
* mounting
* configuring network
* packages installing
* init scripts handling.
* initrd generating
* boot (grub/elilo/yaboot) installing

107
python/mine/install_xml.py Normal file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/python
import sys
from xml.dom import minidom
import Tkinter
def attr_to_dict(attr):
''' convert (widget or grid_location) attributes into a dict '''
dict = {}
for a in attr.values():
if a.name == 'image':
dict[a.name] = Tkinter.PhotoImage(file=a.value)
elif a.name == 'command':
module = sys.modules[__name__]
dict[a.name] = getattr(module, a.value)
else:
dict[a.name] = a.value
return dict
def construct_widget_dict():
''' Go through all widget xml nodes on first level, I mean, those widgets defined
inside other widget will not be checked. If the widget has a name, it will
be recorded in the widget_dict.'''
widgets = [e for e in xmldoc.firstChild.childNodes
if e.nodeType == e.ELEMENT_NODE and e.nodeName == "widget"]
for w in widgets:
if "name" in w.attributes.keys():
widget_dict[w.attributes["name"].value] = w
def widget(w_xml, p_win):
''' create a widget.
w_xml is a xml node describing the widget.
p_win is the parent widget.'''
func = getattr(Tkinter, w_xml.attributes["type"].value)
# convert attributes into dictionary
wa_list = [wa for wa in w_xml.childNodes
if wa.nodeType == wa.ELEMENT_NODE and wa.nodeName =="widget_attribute"]
if wa_list:
# only process the first element, and there should be only one element.
attr_dict = attr_to_dict(wa_list[0].attributes)
w_win = func(p_win, attr_dict)
else:
w_win = func(p_win)
gm_list = [m for m in w_xml.childNodes
if m.nodeType == m.ELEMENT_NODE and m.nodeName == "grid_management"]
gl_list = [l for l in w_xml.childNodes
if l.nodeType == l.ELEMENT_NODE and l.nodeName == "grid_location"]
w_list = [ w for w in w_xml.childNodes
if w.nodeType == w.ELEMENT_NODE and w.nodeName == "widget" ]
for w in w_list:
widget(w, w_win)
for m in gm_list:
for cf in m.childNodes:
if cf.nodeType != m.ELEMENT_NODE or cf.nodeName != "configure":
continue
if "row" in cf.attributes.keys():
cf_func = getattr(w_win, "rowconfigure")
n = cf.attributes["row"].value
elif "column" in cf.attributes.keys():
cf_func = getattr(w_win, "columnconfigure")
n = cf.attributes["column"].value
else:
continue
cf_func(n, weight=cf.attributes["weight"].value)
# only process the first item
break
for l in gl_list:
ld = attr_to_dict(l.attributes)
w_win.grid(ld)
# only process the first item
break
def display():
''' Display a series of widgets '''
root_window = Tkinter.Tk()
# first display the main frame
widget(widget_dict["main"], root_window)
root_window.columnconfigure(0, weight=1)
root_window.rowconfigure(0, weight=1)
root_window.geometry('800x600+0+0')
root_window.mainloop()
# commands for buttons
def quit():
print "quit"
def previous_step():
print "previous step"
def next_step():
print "next step"
xmldoc = minidom.parse("../../xml/interface_t.xml")
widget_dict={}
construct_widget_dict()
sequence_dict={}
construct_sequence_dict()
display()

28
python/mine/ri_cmd.py Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/python
''' handle gui button related commands.'''
import ri_tk
import ri_seq
import ri_widget
def quit():
''' correspond to quit button '''
ri_tk.quit()
def previous():
''' correspond to previous button '''
if 'current_window' in dir(ri_tk):
ri_tk.kill_widget(ri_tk.current_window)
wid_name = ri_seq.previous()
if wid_name is not None:
ri_tk.display_widget(ri_widget.Widget.dict[wid_name])
def next():
''' correspond to next button '''
if 'current_window' in dir(ri_tk):
ri_tk.kill_widget(ri_tk.current_window)
wid_name = ri_seq.next()
if wid_name is not None:
ri_tk.display_widget(ri_widget.Widget.dict[wid_name])

44
python/mine/ri_seq.py Normal file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/python
current_sequence=""
previous_sequences=[]
dict={}
class Sequence:
''' implement sequence in interface xml'''
def __init__(self, xml_node):
self.steps = [ s.attributes["name"].value for s in xml_node.childNodes
if s.nodeType == s.ELEMENT_NODE and s.nodeName == "widget" ]
self.current_step = 0
def construct(xml_root):
''' construct Sequence's static members'''
global current_sequence
current_sequence = xml_root.attributes["sequence"].value
for s in xml_root.childNodes:
if s.nodeType == s.ELEMENT_NODE and s.nodeName == "sequence":
dict[s.attributes["name"].value] = Sequence(s)
def previous():
global current_sequence
cur_seq = dict[current_sequence]
if cur_seq.current_step:
cur_seq.current_step -= 1
return cur_seq.steps[cur_seq.current_step]
# current sequence already in first step
elif previous_sequences:
current_sequence = previous_sequences.pop()
cur_seq = dict[current_sequence]
return cur_seq.steps[cur_seq.current_step]
def next():
global current_sequence
cur_seq = dict[current_sequence]
if cur_seq.current_step < len(cur_seq.steps)-1:
cur_seq.current_step += 1
return cur_seq.steps[cur_seq.current_step]
# current sequence already in last step
elif previous_sequences:
current_sequence = previous_sequences.pop()
cur_seq = dict[current_sequence]
return cur_seq.steps[cur_seq.current_step]

54
python/mine/ri_tk.py Normal file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/python
''' handle display related work upon Tkinter '''
import Tkinter
def initialize(base_w):
''' base widget xml node '''
global root_window
root_window = Tkinter.Tk()
# grid management for root_window
root_window.columnconfigure(0, weight=1)
root_window.rowconfigure(0, weight=1)
root_window.geometry("%sx%s+0+0" %(root_window.winfo_screenwidth(),root_window.winfo_screenheight()))
global base_widget
base_widget = display_widget_sub(base_w, root_window)
def quit():
''' exit root window '''
root_window.quit()
def display_widget(w):
''' w - widget instance '''
global current_window
current_window = display_widget_sub(w, base_widget)
def display_widget_sub(w, p_win):
'''
w - widget instance
p_win - Tk parent window '''
tk_func = getattr(Tkinter, w.tp)
w_win = tk_func(p_win, w.attr)
# display sub widgets
if 'widgets' in dir(w):
for sub_w in w.widgets:
display_widget_sub(sub_w, w_win)
# grid management
if 'grid_management' in dir(w):
for cf in w.grid_management.cf_list:
cf_func = getattr(w_win, cf[0])
cf_func( cf[1], weight=cf[2])
# grid location
if 'grid_location' in dir(w):
w_win.grid(w.grid_location.dict)
return w_win
def kill_widget(win):
''' win - Tk window instance '''
win.destroy()

78
python/mine/ri_widget.py Normal file
View File

@@ -0,0 +1,78 @@
#!/usr/bin/python
import Tkinter
import sys
class GridManagement:
''' implement grid management '''
def __init__(self, xml_node):
self.cf_list=[]
for cf in xml_node.childNodes:
if cf.nodeType != cf.ELEMENT_NODE or cf.nodeName != "configure":
continue
if "row" in cf.attributes.keys():
cf_func = "rowconfigure"
n = cf.attributes["row"].value
elif "column" in cf.attributes.keys():
cf_func = "columnconfigure"
n = cf.attributes["column"].value
else:
continue
self.cf_list.append((cf_func, n, cf.attributes["weight"].value))
class GridLocation:
''' implement grid_location in interface xml '''
def __init__(self, xml_node):
self.dict={}
for a in xml_node.attributes.values():
self.dict[a.name] = a.value
class Widget:
''' implement widget in interface xml '''
current_widget=""
dict={}
def __init__(self, xml_node):
self.tp = xml_node.attributes["type"].value
self.attr = self.widget_attribute(xml_node)
gm_list = [m for m in xml_node.childNodes
if m.nodeType == m.ELEMENT_NODE and m.nodeName == "grid_management"]
if gm_list:
self.grid_management = GridManagement(gm_list[0])
gl_list = [l for l in xml_node.childNodes
if l.nodeType == l.ELEMENT_NODE and l.nodeName == "grid_location"]
if gl_list:
self.grid_location = GridLocation(gl_list[0])
w_list = [ w for w in xml_node.childNodes
if w.nodeType == w.ELEMENT_NODE and w.nodeName == "widget" ]
if w_list:
self.widgets=[]
for w in w_list:
self.widgets.append(Widget(w))
def widget_attribute(self, xml_node):
attr_list = [ a for a in xml_node.childNodes
if a.nodeType == a.ELEMENT_NODE and a.nodeName == "widget_attribute"]
d = {}
if attr_list:
for a in attr_list[0].attributes.values():
if a.name == 'image':
#d[a.name] = Tkinter.PhotoImage(file=a.value)
pass
elif a.name == 'command':
if not "ri_cmd" in sys.modules.keys():
import ri_cmd
d[a.name] = getattr(sys.modules["ri_cmd"], a.value)
else:
d[a.name] = a.value
return d
def construct(xml_root):
''' construct Widget's static members'''
for w in xml_root.childNodes:
if w.nodeType == w.ELEMENT_NODE and w.nodeName == "widget" and "name" in w.attributes.keys():
Widget.dict[w.attributes["name"].value] = Widget(w)

23
python/mine/test.py Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/python
import ri_widget
import ri_tk
import ri_seq
from xml.dom import minidom
xmldoc = minidom.parse("../../xml/interface_t.xml")
ri_widget.construct(xmldoc.firstChild)
ri_seq.construct(xmldoc.firstChild)
base_widget_name = xmldoc.firstChild.attributes["base_widget"].value
base_widget = ri_widget.Widget.dict[base_widget_name]
ri_tk.initialize(base_widget)
main_sequence_name = xmldoc.firstChild.attributes["sequence"].value
main_sequence = ri_seq.dict[main_sequence_name]
ri_tk.display_widget(ri_widget.Widget.dict[main_sequence.steps[0]])
ri_tk.root_window.mainloop()

38
xml/install.xml Normal file
View File

@@ -0,0 +1,38 @@
<?xml version='1.0' encoding='UTF-8'?>
<install>
<serial-number>123456789012</serial-number>
<partition device="/dev/hda1" boot="no" type="primary" id="5" size="101MB"/>
<partition device="/dev/hda2" boot="no" type="primary" id="5" size="101MB"/>
<partition device="/dev/hda3" boot="no" type="primary" id="5" size="203MB"/>
<partition device="/dev/hda4" boot="no" type="extended" id="5" size="9828MB"/>
<partition device="/dev/hda5" boot="no" type="logic" id="5" size="203MB"/>
<partition device="/dev/hda6" boot="no" type="logic" id="5" size="203MB"/>
<partition device="/dev/hdb1" boot="no" type="primary" id="83" size="5004MB"/>
<partition device="/dev/hdb2" boot="no" type="primary" id="82" size="800MB"/>
<partition device="/dev/hdb3" boot="no" type="extended" id="5" size="4431MB"/>
<partition device="/dev/hdb5" boot="no" type="logic" id="83" size="502MB"/>
<raid raid-device="/dev/md0" raid-type="RAID0">
<raw-device>/dev/hda1</raw-device>
<raw-device>/dev/hda2</raw-device>
</raid>
<raid raid-device="/dev/md1" raid-type="RAID5">
<raw-device>/dev/hda3</raw-device>
<raw-device>/dev/hda5</raw-device>
<raw-device>/dev/hda6</raw-device>
</raid>
<mount-point device="/dev/hdb1" directory="/" file-system="ext3"/>
<mount-point device="/dev/hdb5" directory="/usr" file-system="ext2"/>
<network hostname="localhost" configuration="static" ip="192.168.1.25" mask="255.255.255.0" gateway="192.168.1.254" primary_dns="192.168.1.254" secondary_dns="" domain="in.linx"/>
<service name="ssh" start="yes"/>
<group name="base">
<description>base software packages</description>
<including package="acct" type="mandatory" install="yes"/>
</group>
</install>

149
xml/install_ng.xml Normal file
View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8" ?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
<start>
<element name="install">
<ref name="serial-number"/>
<ref name="partitions"/>
<ref name="raids"/>
<ref name="mount-points"/>
<ref name="network"/>
<ref name="services"/>
<ref name="groups"/>
</element>
</start>
<define name="serial-number">
<element name="serial-number">
<text/>
</element>
</define>
<define name="partitions">
<oneOrMore>
<element name="partition">
<attribute name="device"/>
<attribute name="boot">
<ref name="mybool"/>
</attribute>
<attribute name="type">
<choice>
<value>primary</value>
<value>extended</value>
<value>logic</value>
</choice>
</attribute>
<attribute name="id"/>
<attribute name="size"/>
</element>
</oneOrMore>
</define>
<define name="raids">
<zeroOrMore>
<element name="raid">
<attribute name="raid-device"/>
<attribute name="raid-type">
<choice>
<value>RAID0</value>
<value>RAID1</value>
<value>RAID5</value>
</choice>
</attribute>
<oneOrMore>
<element name="raw-device">
<text/>
</element>
</oneOrMore>
</element>
</zeroOrMore>
</define>
<define name="mount-points">
<oneOrMore>
<element name="mount-point">
<attribute name="device"/>
<attribute name="directory"/>
<attribute name="file-system"/>
</element>
</oneOrMore>
</define>
<define name="network">
<element name="network">
<attribute name="hostname"/>
<attribute name="configuration">
<choice>
<value>dynamic</value>
<value>static</value>
</choice>
</attribute>
<optional>
<group>
<attribute name="ip"/>
<attribute name="mask"/>
<attribute name="gateway"/>
<attribute name="primary_dns"/>
<attribute name="secondary_dns"/>
<attribute name="domain"/>
</group>
</optional>
</element>
</define>
<define name="services">
<zeroOrMore>
<element name="service">
<attribute name="name"/>
<attribute name="start">
<ref name="mybool"/>
</attribute>
</element>
</zeroOrMore>
</define>
<define name="groups">
<oneOrMore>
<element name="group">
<attribute name="name"/>
<attribute name="install">
<ref name="mybool"/>
</attribute>
<optional>
<ref name="description"/>
</optional>
<oneOrMore>
<ref name="including"/>
</oneOrMore>
</element>
</oneOrMore>
</define>
<define name="description">
<element name="description">
<text/>
</element>
</define>
<define name="including">
<element name="including">
<attribute name="package"/>
<attribute name="type">
<choice>
<value>mandatory</value>
<value>optional</value>
</choice>
</attribute>
<attribute name="install">
<ref name="mybool"/>
</attribute>
</element>
</define>
<define name="mybool">
<choice>
<value>yes</value>
<value>no</value>
</choice>
</define>
</grammar>

150
xml/interface_ng.xml Normal file
View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8" ?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
<start>
<element name="interface">
<attribute name="base_widget"/>
<attribute name="sequence"/>
<oneOrMore>
<ref name="widget"/>
<zeroOrMore>
<ref name="message"/>
</zeroOrMore>
</oneOrMore>
<oneOrMore>
<ref name="sequence"/>
</oneOrMore>
</element>
</start>
<define name="widget">
<element name="widget">
<attribute name="type"/>
<optional>
<attribute name="name"/>
</optional>
<optional>
<ref name="widget_attribute"/>
</optional>
<interleave>
<optional>
<!-- geometry management is to manage its sons -->
<ref name="geometry_management"/>
</optional>
<optional>
<!-- geometry location is the location inside its parent -->
<ref name="geometry_location"/>
</optional>
</interleave>
<zeroOrMore>
<ref name="widget"/>
</zeroOrMore>
</element>
</define>
<!-- I split widget attributes from attributes added by I. So I
can easily convert add widget attributes into a dict without processing
on special cases -->
<define name="widget_attribute">
<element name="widget_attribute">
<interleave>
<optional>
<attribute name="background"/>
</optional>
<optional>
<attribute name="height"/>
</optional>
<optional>
<attribute name="width"/>
</optional>
<optional>
<attribute name="text"/>
</optional>
<optional>
<attribute name="command"/>
</optional>
<optional>
<attribute name="image"/>
</optional>
<optional>
<attribute name="state"/>
</optional>
</interleave>
</element>
</define>
<define name="geometry_management">
<!-- why choice? because there may be other geometry management-->
<choice>
<element name="grid_management">
<attribute name="rows"/>
<attribute name="columns"/>
<oneOrMore>
<element name="configure">
<choice>
<attribute name="row"/>
<attribute name="column"/>
</choice>
<attribute name="weight"/>
</element>
</oneOrMore>
</element>
</choice>
</define>
<define name="geometry_location">
<!-- why choice? because there may be other geometry location -->
<choice>
<element name="grid_location">
<attribute name="row"/>
<attribute name="column"/>
<interleave>
<optional>
<attribute name="columnspan"/>
</optional>
<optional>
<attribute name="rowspan"/>
</optional>
<optional>
<attribute name="sticky"/>
</optional>
<optional>
<attribute name="padx"/>
</optional>
<optional>
<attribute name="pady"/>
</optional>
</interleave>
</element>
</choice>
</define>
<define name="message">
<element name="message">
<optional>
<attribute name="key"/>
</optional>
<interleave>
<element name="English">
<text/>
</element>
<element name="Chinese">
<text/>
</element>
</interleave>
</element>
</define>
<define name="sequence">
<element name="sequence">
<attribute name="name"/>
<oneOrMore>
<element name="widget">
<attribute name="name"/>
</element>
</oneOrMore>
</element>
</define>
</grammar>

127
xml/interface_t.xml Normal file
View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" ?>
<interface base_widget='main' sequence='main'>
<!--
column 0 column 1 column 2
____________________________________________________________
row 0 | logo version |
row 1 |____________________________________________________________|
row 2 | |
row 3 | copyright information |
row 4 | quit previous next |
|____________________________________________________________|
-->
<widget type='Frame' name='main'>
<grid_management rows='5' columns='3'>
<configure row='2' weight='1'/>
<configure column='0' weight='1'/>
<configure column='1' weight='3'/>
<configure column='2' weight='1'/>
</grid_management>
<grid_location row='0' column='0' sticky='NSWE'/>
<widget type="Label">
<widget_attribute image='/home/zhi/git/install/graphicalinstall/images/linxlogo.gif'/>
<grid_location row='0' column='0' sticky='W' padx='5' pady='5'/>
</widget>
<widget type='Label'>
<widget_attribute text='#os-name'/>
<grid_location row='0' column='2' sticky='E'/>
</widget>
<widget type='Frame'>
<widget_attribute height='3' background='black'/>
<grid_location row='1' column='0' columnspan='3' sticky='WE'/>
</widget>
<widget type='Label'>
<widget_attribute text='Copyright'/>
<grid_location row='3' column='0' columnspan='3' pady='20'/>
</widget>
<widget type='Button'>
<widget_attribute text='quit' command='quit'/>
<grid_location row='4' column='0'/>
</widget>
<widget type='Button'>
<widget_attribute text='previous' command='previous'/>
<grid_location row='4' column='1'/>
</widget>
<widget type='Button'>
<widget_attribute text='next' command='next'/>
<grid_location row='4' column='2' pady='20'/>
</widget>
</widget>
<message key='#os-name'>
<English>Rocky 4.2</English>
<Chinese>磐石 4.2</Chinese>
</message>
<message>
<English>Copyright</English>
<Chinese>版权</Chinese>
</message>
<!--
column 0 column 1 column 2
____________________________________________________________
row 0 | |
row 1 | |
row 2 | Welcome to Rocky OS |
row 3 | |
row 4 | |
|____________________________________________________________|
-->
<widget type='Label' name='welcome'>
<widget_attribute text='Welcome'/>
<grid_location row='2' column='0' columnspan='3'/>
</widget>
<!--
column 0 column 1 column 2
____________________________________________________________
row 0 | |
row 1 | |
row 2 | _________ _________________ |
| | text | | serial number | |
| | | | ______________ | |
| | | || | | |
| |_________| ||______________| | |
| |_________________| |
row 3 | |
row 4 | |
|____________________________________________________________|
-->
<widget type='Frame' name='serial_no'>
<grid_management rows='1' columns='3'>
<configure row='0' weight='1'/>
<configure column='0' weight='1'/>
<configure column='1' weight='1'/>
<configure column='2' weight='1'/>
</grid_management>
<grid_location row='2' column='0' columnspan='3' sticky='NSWE'/>
<widget type='Text'>
<widget_attribute width='40' height='15' state='disabled'/>
<grid_location row='0' column='0'/>
</widget>
<widget type='Frame'>
<grid_location row='0' column='1'/>
<widget type='Label'>
<widget_attribute text='serial number'/>
<grid_location row='0' column='0' sticky='W'/>
</widget>
<widget type='Entry'>
<widget_attribute width='12'/>
<grid_location row='1' column='0'/>
</widget>
</widget>
</widget>
<sequence name='main'>
<widget name='welcome'/>
<widget name='serial_no'/>
</sequence>
</interface>