Tuesday, November 27, 2012

A little script driven two stage dialog with zenity

On Solaris and Linux there is a little utility called zenity which displays a dialog window. It has various options from simply displaying a string to showing a file dialog progress. I sometimes use it if I write a script but don't want the user to follow the output of the script in a terminal, especially if the script is going to be used by a larger group of mainly non-technical users one needs a GUI dialog. zenity is not very fancy in its capabilities, configurability or design but it serves its purpose.

In this article I want to show how to use zenity several times in a script.

  • At first the users are presented with a list of servers to choose from and
  • secondly there is a list of applications to be selected. The list of applications and the geometry of the zenity window depend on the previous selection.
  • Finally in a third invocation of zenity there is a summary window shown.

    The task has been split into two files.
    One is a config file which contains the definitions of the various lists.
    The second file is the actual script. Since I'm using arrays to define the lists I'm using bash in this example.
    (Note: originally the script ran on Solaris 10 in ksh but the 'echo ... | zenity' construct somehow did not on Linux.)

    Here is the config file

    #!/bin/echo Error:_this_needs_to_be_sourced_in:
    #
    
    # A set of arrays (for ksh)
    # (server and domain names are fake of course)
    
      ALIAS[1]="Japan server"
    MACHINE[1]="server1.japan"
       MENU[1]='Finance
    Logistics
    Sales'
      MSIZE[1]="--height=220 --width=330"
    
      ALIAS[2]="UK server"
    MACHINE[2]="serv2a.uk"
       MENU[2]='Finance
    Sales'
      MSIZE[2]="--height=190 --width=330"
    
      ALIAS[3]="US server"
    MACHINE[3]="newserv.us"
       MENU[3]='Finance
    Logistics
    Marketing
    Sales'
      MSIZE[3]="--height=220 --width=330"
    
    # Set the number of array elements
    numElements=3
    
    The config file defines four arrays:
  • ALIAS is nickname of the actual server and will be displayed in the first menu
  • MACHINE is the actual machine name
  • MENU is the list of choices in the second zenity window
  • MSIZE is the geometry setting for this menu. Height varies. Finally there is a variable numElements which defines the length of the arrays, 3 in this case.

    Here is the script:

    #!/bin/bash 
    
    # The config file 
    #   Should be in the same directory as the script.
    #   Could of course be passed as an argument too.
    ########################################
    CONFIGFILE=`/usr/bin/dirname $0`/zenity.config
    
    # Check if the config file exists
    ########################################
    [ -r $CONFIGFILE ] || { zenity --error --text "Config file does not exist: $CONFIGFILE" ; exit 1 ; }
      
    # Source the config file
    ########################################
    . $CONFIGFILE   || { zenity --error --text "Error while sourcing config file: $CONFIGFILE" ; exit 1 ; }
    
    # Step 1: select an option out of the list of aliases
    ########################################
    selection=`\
    ind=1
    while [ $ind -le $numElements ] ; do
            echo "${ALIAS[$ind]}"   # Piped to zenity
            ind=$((ind+1))
    done | zenity --list --height=200 --width=350 \
    --column="Choose your Server (highlight and press OK)" \
    --title="Remote Server Launcher" \
    `
       
    # If zenity has been canceled or nothing selected then exit
    ########################################
    [ $? -eq 0 -a "x$selection" != "x" ] || exit 1
      
    # Now map the user selection to a machine name
    # and show the machine specific menu
    ########################################
    ind=1
    while [ $ind -le $numElements ] ; do
            if [ "x$selection" = "x${ALIAS[$ind]}" ] ; then
                    server=${MACHINE[$ind]}
    
                    # Stage 2: select the window size and a specific application
                    ########################################
                    selection=`\
                    echo "${MENU[ind]}" | zenity --list ${MSIZE[$ind]} \
                    --column="Application (highlight one and press OK)" \
                    --title="Remote Server Launcher" \
                    `
                    # If zenity has been canceled then exit
                    [ $? -eq 0 ] || exit 1
                    break
            fi
            ind=$((ind+1))
    done
    
    # Just for information purposes
    ########################################
    zenity --info --text "You chose:\nServer: ${ALIAS[$ind]} (${MACHINE[$ind]})\nApplication:  $selection  "
    

    A few notes:

  • zenity is also used to display error messages
  • the while loops could be replaced by for ind in {1..$numElements} in ksh but this does not work in bash
  • the zenity windows are invoked inside backticks in order to capture their output
  • the script shows various options of zenity and how to use them.
  • after having gone through these choices of course something real should be done rather than just displaying the choices (but that is beyond this article).
  • this array technique allows you to dynamically set the content of zenity dialogs, to set variables which are hidden to the user and to separate the logic from the content (and there even could be done more e.g. define all geometries in the config file)

    Here is the first zenity window (on Ubuntu 11) after having clicked one server.

    Here is the second zenity window with the appropriate menu and geometry

    And finally here is the last zenity window to recap the selections

  • No comments:

    Post a Comment