[GRASS5] xml interface description

Jan-Oliver Wagner jan at intevation.de
Tue Oct 24 12:33:26 EDT 2000


Dear GRASS developers,

I have checked in a new parser.c with the ability
to print out a xml interface description.
The argument for this is --interface-description.

I have also implemented a coarse wxPython program
that loads a xml interface description and builds
a simple dialog. Code is ugly, but it works.
A next milestone of our work towards integration
into OSSIM (which is base on wxWindows)
includes an improved implementation.

The wxPython programm is attached. You need to
have Python, wxPython and python-xml to run it.
Fairly easy to install, at least on my Debian GNU/Linux.

I have also attached a screenshot for those who
don't want to deal with python right now.

The next step is to go thorugh several commands and
look for special behaviour and special types
of parameters. That will partly contribute to
the effort on harmonizing parameters.

Cheers

	Jan

-- 
Jan-Oliver Wagner               http://intevation.de/~jan/

Intevation GmbH	              	     http://intevation.de/
FreeGIS	                               http://freegis.org/
-------------- next part --------------
#! /usr/bin/python

from wxPython.wx import *
from xml.sax import saxexts
from xml.sax import saxlib
from os import system

ID_RUN   = 10
ID_CANCEL= 11
ID_PARAM_START = 900

ID_ABOUT = 101
ID_EXIT  = 102

VSPACE = 4
HSPACE = 4
MENU_HEIGHT = 30
STATUSBAR_HEIGHT = 30
ENTRY_HEIGHT = 20
STRING_ENTRY_WIDTH = 300
BUTTON_HEIGHT = 30
BUTTON_WIDTH = 100

grass_task = { 'name' : 'unknown', 'lines' : 0, 'params' : [] }

def normalize_whitespace(text):
    "Remove redundant whitespace from a string"
    return string.join( string.split(text), ' ')

class processTask(saxlib.HandlerBase):
    def __init__(self):
        self.inDescriptionContent = 0
        self.inDefaultContent = 0
        self.inValueContent = 0

    def startElement(self, name, attrs):
        if name == 'task':
            grass_task['name'] = attrs.get('name', None)

        if name == 'parameter':
            self.param_description = ''
            self.param_default = ''
            self.param_values = []
            # Look for the parameter name, type, requiredness
            self.param_name = attrs.get('name', None)
            self.param_type = attrs.get('type', None)
            if type == 'flag':
                grass_task['lines'] = grass_task['lines'] + 1
            else:
                grass_task['lines'] = grass_task['lines'] + 2
            self.param_required = attrs.get('required', None)
        if name == 'description':
            self.inDescriptionContent = 1
            self.param_description = ''
        if name == 'default':
            self.inDefaultContent = 1
            self.param_default = ''
        if name == 'value':
            self.inValueContent = 1
            self.value_tmp = ''

    def characters(self, ch, start, length):
        if self.inDescriptionContent:
            self.param_description = self.param_description + ch[start:start+length]
        if self.inDefaultContent:
            self.param_default = self.param_default + ch[start:start+length]
        if self.inValueContent:
            self.value_tmp = self.value_tmp + ch[start:start+length]

    def endElement(self, name): 
        # If it's not a parameter element, ignore it
        if name == 'parameter':
            grass_task['params'] = grass_task['params'] + [ { "name" : self.param_name, "type" : self.param_type, "required" : self.param_required, "description" : self.param_description, "default" : self.param_default, "values" : self.param_values, "value" : '' } ]

        if name == 'description':
            self.param_description = normalize_whitespace(self.param_description)
            self.inDescriptionContent = 0
        if name == 'default':
            self.param_default = normalize_whitespace(self.param_default)
            self.inDefaultContent = 0
        if name == 'value':
            v = normalize_whitespace(self.value_tmp)
            self.param_values = self.param_values + [ normalize_whitespace(self.value_tmp) ]
            self.inValueContent = 0


class mainFrame(wxFrame):
    def __init__(self, parent, ID, w, h):
        wxFrame.__init__(self, parent, ID, grass_task['name'],
            wxDefaultPosition, wxSize(w, h))

        self.CreateStatusBar()
        self.SetStatusText('Enter parameters for ' + grass_task['name'])

        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About",
                    "Information about GRASS-GUI")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")

        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");

        self.SetMenuBar(menuBar)

        self.panel = wxPanel(self, -1)

        p_count = 0
        l_count = 0
        while p_count < len(grass_task['params']):
            title = grass_task['params'][p_count]['description']
            if grass_task['params'][p_count]['required'] == 'no':
                title = "[optional] " + title
            grass_task['params'][p_count]['value'] = grass_task['params'][p_count]['default'] 
            if (len(grass_task['params'][p_count]['values']) > 0):
                wxStaticText(self.panel, -1, title + ':',
                    wxPoint(HSPACE, l_count * ENTRY_HEIGHT + VSPACE + p_count * VSPACE), wxSize(-1, -1))
                l_count = l_count + 1
                wxComboBox(self.panel, ID_PARAM_START + p_count, grass_task['params'][p_count]['default'],
                    wxPoint(HSPACE, l_count * ENTRY_HEIGHT + VSPACE + p_count * VSPACE),
                    wxSize(STRING_ENTRY_WIDTH, -1),
                    grass_task['params'][p_count]['values'], wxCB_DROPDOWN)
                EVT_COMBOBOX(self, ID_PARAM_START + p_count, self.EvtComboBox)

            if ((grass_task['params'][p_count]['type'] == 'string' or
                grass_task['params'][p_count]['type'] == 'integer' or
                grass_task['params'][p_count]['type'] == 'float') and
                len(grass_task['params'][p_count]['values']) == 0):
                wxStaticText(self.panel, -1, title + ':',
                    wxPoint(HSPACE, l_count * ENTRY_HEIGHT + VSPACE + p_count * VSPACE), wxSize(-1, -1))
                l_count = l_count + 1
                wxTextCtrl(self.panel, ID_PARAM_START + p_count,
                    grass_task['params'][p_count]['default'], wxPoint(HSPACE, l_count * ENTRY_HEIGHT + VSPACE + p_count * VSPACE),
                    wxSize(STRING_ENTRY_WIDTH, ENTRY_HEIGHT))
                EVT_TEXT(self, ID_PARAM_START + p_count, self.EvtText)

            if (grass_task['params'][p_count]['type'] == 'flag'):
                wxCheckBox(self.panel,ID_PARAM_START + p_count, title,
                    wxPoint(HSPACE, l_count * ENTRY_HEIGHT + VSPACE + p_count * VSPACE),
                    wxSize(-1, -1), wxNO_BORDER)
                EVT_CHECKBOX(self, ID_PARAM_START + p_count, self.EvtCheckBox)

            p_count = p_count + 1
            l_count = l_count + 1

        wxButton(self.panel, ID_CANCEL, "Cancel",
            wxPoint(2 * HSPACE, VSPACE + l_count * ENTRY_HEIGHT + p_count * VSPACE + 3 * VSPACE))
        wxButton(self.panel, ID_RUN, "Run",
            wxPoint(2 * HSPACE + BUTTON_WIDTH + HSPACE, VSPACE + l_count * ENTRY_HEIGHT + p_count * VSPACE + 3 * VSPACE)).SetDefault()

        EVT_MENU(self, ID_ABOUT, self.OnAbout)
        EVT_MENU(self, ID_EXIT,  self.OnCancel)
        EVT_BUTTON(self.panel, ID_CANCEL, self.OnCancel)
        EVT_BUTTON(self.panel, ID_RUN, self.OnRun)

    def EvtText(self, event):
        grass_task['params'][event.GetId()-ID_PARAM_START]['value'] = event.GetString()

    def EvtCheckBox(self, event):
        if (event.Checked()):
            grass_task['params'][event.GetId()-ID_PARAM_START]['value'] = 'checked'
        else:
            grass_task['params'][event.GetId()-ID_PARAM_START]['value'] = 'not checked'

    def EvtComboBox(self, event):
        grass_task['params'][event.GetId()-ID_PARAM_START]['value'] = event.GetString()


    def OnRun(self, event):
        cmd = grass_task['name']
        p_count = 0
        errors = 0
        errStr = ""
        while p_count < len(grass_task['params']):
            if (grass_task['params'][p_count]['type'] != 'flag' and grass_task['params'][p_count]['value'] == '' and grass_task['params'][p_count]['required'] != 'no'):
                errStr = errStr + "Parameter " + grass_task['params'][p_count]['name'] + "(" +grass_task['params'][p_count]['description']  + ") is missing\n"
                errors = errors + 1

            if (grass_task['params'][p_count]['type'] == 'flag'):
                if (grass_task['params'][p_count]['value'] == 'checked'):
                    cmd = cmd + ' -' + grass_task['params'][p_count]['name']
            if (grass_task['params'][p_count]['type'] != 'flag' and grass_task['params'][p_count]['value'] != ''):
                cmd = cmd + ' ' + grass_task['params'][p_count]['name'] + '=' + grass_task['params'][p_count]['value']
            p_count = p_count + 1

        if errors:
            self.OnError(errStr)
        else:
            system(cmd)

    def OnError(self, errMsg):
        dlg = wxMessageDialog(self, errMsg, "Error", wxOK | wxICON_ERROR)
        dlg.ShowModal()
        dlg.Destroy()

    def OnCancel(self, event):
        self.Close(false)

    def OnAbout(self, event):
        dlg = wxMessageDialog(self, "This is a sample program for\n"
                              "GRASS command interface parsing\n"
                              "and automatic GUI building.",
                              "About", wxOK | wxICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()



class GrassGUIApp(wxApp):
    def OnInit(self):
        self.w = HSPACE + STRING_ENTRY_WIDTH + HSPACE
        self.h = MENU_HEIGHT + VSPACE + grass_task['lines'] * ENTRY_HEIGHT + VSPACE  + BUTTON_HEIGHT + VSPACE + STATUSBAR_HEIGHT
        frame = mainFrame(NULL, -1, self.w, self.h)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

# find out the command to run
if len(sys.argv) > 1:
    print "usage: <grass command> --task-description | " + sys.argv[0]
else:
    # parse the interface decription
    parser = saxexts.make_parser()
    dh = processTask()
    parser.setDocumentHandler(dh)
    parser.parseFile(sys.stdin)
    parser.close()
    # Create the application
    app = GrassGUIApp(0)
    app.MainLoop()
-------------- next part --------------
A non-text attachment was scrubbed...
Name: d.rast.png
Type: image/png
Size: 8807 bytes
Desc: not available
Url : http://lists.osgeo.org/pipermail/grass-dev/attachments/20001024/472bf178/d.rast.png


More information about the grass-dev mailing list