001/*
002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved.
003 * 
004 * http://www.izforge.com/izpack/
005 * http://developer.berlios.de/projects/izpack/
006 * 
007 * Copyright 2002 Elmar Grom
008 * 
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *     http://www.apache.org/licenses/LICENSE-2.0
014 *     
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 */
021
022package com.izforge.izpack.panels;
023
024import java.awt.Color;
025import java.awt.Font;
026import java.awt.event.ActionEvent;
027import java.awt.event.ActionListener;
028import java.io.File;
029import java.io.InputStream;
030import java.text.MessageFormat;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.Iterator;
034import java.util.Map;
035import java.util.StringTokenizer;
036import java.util.Vector;
037
038import javax.swing.BorderFactory;
039import javax.swing.ButtonGroup;
040import javax.swing.JButton;
041import javax.swing.JCheckBox;
042import javax.swing.JComboBox;
043import javax.swing.JComponent;
044import javax.swing.JFileChooser;
045import javax.swing.JLabel;
046import javax.swing.JOptionPane;
047import javax.swing.JPanel;
048import javax.swing.JPasswordField;
049import javax.swing.JRadioButton;
050import javax.swing.JTextField;
051
052import net.n3.nanoxml.NonValidator;
053import net.n3.nanoxml.StdXMLBuilder;
054import net.n3.nanoxml.StdXMLParser;
055import net.n3.nanoxml.StdXMLReader;
056import net.n3.nanoxml.XMLElement;
057
058import com.izforge.izpack.LocaleDatabase;
059import com.izforge.izpack.Pack;
060import com.izforge.izpack.gui.ButtonFactory;
061import com.izforge.izpack.gui.TwoColumnConstraints;
062import com.izforge.izpack.gui.TwoColumnLayout;
063import com.izforge.izpack.installer.InstallData;
064import com.izforge.izpack.installer.InstallerFrame;
065import com.izforge.izpack.installer.IzPanel;
066import com.izforge.izpack.installer.ResourceManager;
067import com.izforge.izpack.util.MultiLineLabel;
068import com.izforge.izpack.util.OsConstraint;
069import com.izforge.izpack.util.OsVersion;
070import com.izforge.izpack.util.VariableSubstitutor;
071
072/*---------------------------------------------------------------------------*/
073/**
074 * This panel is designed to collect user input during the installation process. The panel is
075 * initially blank and is populated with input elements based on the XML specification in a resource
076 * file.
077 * 
078 * 
079 * @version 0.0.1 / 10/19/02
080 * @author getDirectoryCreated
081 */
082/*---------------------------------------------------------------------------*/
083/*
084 * $ @design
085 * 
086 * Each field is specified in its own node, containing attributes and data. When this class is
087 * instantiated, the specification is read and analyzed. Each field node is processed based on its
088 * type. An specialized member function is called for each field type that creates the necessary UI
089 * elements. All UI elements are stored in the uiElements vector. Elements are packaged in an object
090 * array that must follow this pattern:
091 * 
092 * index 0 - a String object, that specifies the field type. This is identical to the string used to
093 * identify the field type in the XML file. index 1 - a String object that contains the variable
094 * name for substitution. index 2 - the constraints object that should be used for positioning the
095 * UI element index 3 - the UI element itself index 4 - a Vector containg a list of pack for which
096 * the item should be created. This is used by buildUI() to decide if the item should be added to
097 * the UI.
098 * 
099 * In some cases additional entries are used. The use depends on the specific needs of the type of
100 * input field.
101 * 
102 * When the panel is activated, the method buildUI() walks the list of UI elements adds them to the
103 * panel together with the matching constraint.
104 * 
105 * When an attempt is made to move on to another panel, the method readInput() walks the list of UI
106 * elements again and calls specialized methods that know how to read the user input from each of
107 * the UI elemnts and set the associated varaible.
108 * 
109 * The actual variable substitution is not performed by this panel but by the variable substitutor.
110 * 
111 * To Do: ------ * make sure all header documentation is complete and correct
112 * --------------------------------------------------------------------------
113 */
114public class UserInputPanel extends IzPanel
115{
116
117    // ------------------------------------------------------------------------
118    // Constant Definitions
119    // ------------------------------------------------------------------------
120
121    // The constants beginning with 'POS_' define locations in the object arrays
122    // that used to hold all information for the individual fields. Some data is
123    // not required for all field types. If this happens withing the array, that
124    // location must be padded with 'null'. At the end of the array it can be
125    // omitted. The data stored in this way is in most cases only known by
126    // convention between the add and the associated read method. the following
127    // positions are also used by other service methods in this class and must
128    // not be used for other purposes:
129    // - POS_DISPLAYED
130    // - POS_TYPE
131    // - POS_CONSTRAINTS
132    // - POS_PACKS
133
134    /**
135     * 
136     */
137    private static final long serialVersionUID = 3257850965439886129L;
138
139    private static final int POS_DISPLAYED = 0;
140
141    private static final int POS_TYPE = 1;
142
143    private static final int POS_VARIABLE = 2;
144
145    private static final int POS_CONSTRAINTS = 3;
146
147    private static final int POS_FIELD = 4;
148
149    private static final int POS_PACKS = 5;
150
151    private static final int POS_OS = 6;
152
153    private static final int POS_TRUE = 7;
154
155    private static final int POS_FALSE = 8;
156
157    private static final int POS_MESSAGE = 9;
158
159    private static final int POS_GROUP = 10;
160
161    /** The name of the XML file that specifies the panel layout */
162    private static final String SPEC_FILE_NAME = "userInputSpec.xml";
163
164    private static final String LANG_FILE_NAME = "userInputLang.xml";
165
166    /** how the spec node for a specific panel is identified */
167    private static final String NODE_ID = "panel";
168
169    private static final String FIELD_NODE_ID = "field";
170
171    private static final String INSTANCE_IDENTIFIER = "order";
172
173    private static final String TYPE = "type";
174
175    private static final String DESCRIPTION = "description";
176
177    private static final String VARIABLE = "variable";
178
179    private static final String TEXT = "txt";
180
181    private static final String KEY = "id";
182
183    private static final String SPEC = "spec";
184
185    private static final String SET = "set";
186
187    private static final String TRUE = "true";
188
189    private static final String FALSE = "false";
190
191    private static final String ALIGNMENT = "align";
192
193    private static final String LEFT = "left";
194
195    private static final String CENTER = "center";
196
197    private static final String RIGHT = "right";
198
199    private static final String TOP = "top";
200
201    private static final String ITALICS = "italic";
202
203    private static final String BOLD = "bold";
204
205    private static final String SIZE = "size";
206
207    private static final String VALIDATOR = "validator";
208
209    private static final String PROCESSOR = "processor";
210
211    private static final String CLASS = "class";
212
213    private static final String FIELD_LABEL = "label";
214
215    private static final String TITLE_FIELD = "title";
216
217    private static final String TEXT_FIELD = "text";
218
219    private static final String TEXT_SIZE = "size";
220
221    private static final String STATIC_TEXT = "staticText";
222
223    private static final String COMBO_FIELD = "combo";
224
225    private static final String COMBO_CHOICE = "choice";
226
227    private static final String COMBO_VALUE = "value";
228
229    private static final String RADIO_FIELD = "radio";
230
231    private static final String RADIO_CHOICE = "choice";
232
233    private static final String RADIO_VALUE = "value";
234
235    private static final String SPACE_FIELD = "space";
236
237    private static final String DIVIDER_FIELD = "divider";
238
239    private static final String CHECK_FIELD = "check";
240
241    private static final String RULE_FIELD = "rule";
242
243    private static final String RULE_LAYOUT = "layout";
244
245    private static final String RULE_SEPARATOR = "separator";
246
247    private static final String RULE_RESULT_FORMAT = "resultFormat";
248
249    private static final String RULE_PLAIN_STRING = "plainString";
250
251    private static final String RULE_DISPLAY_FORMAT = "displayFormat";
252
253    private static final String RULE_SPECIAL_SEPARATOR = "specialSeparator";
254
255    private static final String RULE_ENCRYPTED = "processed";
256
257    private static final String RULE_PARAM_NAME = "name";
258
259    private static final String RULE_PARAM_VALUE = "value";
260
261    private static final String RULE_PARAM = "param";
262
263    private static final String PWD_FIELD = "password";
264
265    private static final String PWD_INPUT = "pwd";
266
267    private static final String PWD_SIZE = "size";
268
269    private static final String SEARCH_FIELD = "search";
270
271    // internal value for the button used to trigger autodetection
272    private static final String SEARCH_BUTTON_FIELD = "autodetect";
273
274    private static final String SEARCH_CHOICE = "choice";
275
276    private static final String SEARCH_FILENAME = "filename";
277
278    private static final String SEARCH_RESULT = "result";
279
280    private static final String SEARCH_VALUE = "value";
281
282    private static final String SEARCH_TYPE = "type";
283
284    private static final String SEARCH_FILE = "file";
285
286    private static final String SEARCH_DIRECTORY = "directory";
287
288    private static final String SEARCH_PARENTDIR = "parentdir";
289
290    private static final String SEARCH_CHECKFILENAME = "checkfilename";
291
292    private static final String SELECTEDPACKS = "createForPack"; // renamed
293
294    private static final String UNSELECTEDPACKS = "createForUnselectedPack"; // new
295
296    // node
297
298    private static final String NAME = "name";
299
300    private static final String OS = "os";
301
302    private static final String FAMILY = "family";
303
304    // ------------------------------------------------------------------------
305    // Variable Declarations
306    // ------------------------------------------------------------------------
307    private static int instanceCount = 0;
308
309    protected int instanceNumber = 0;
310
311    /**
312     * If there is a possibility that some UI elements will not get added we can not allow to go
313     * back to the PacksPanel, because the process of building the UI is not reversable. This
314     * variable keeps track if any packs have been defined and will be used to make a decision for
315     * locking the 'previous' button.
316     */
317    private boolean packsDefined = false;
318
319    private InstallerFrame parentFrame;
320
321    /** The parsed result from reading the XML specification from the file */
322    private XMLElement spec;
323
324    private boolean haveSpec = false;
325
326    /** Holds the references to all of the UI elements */
327    private Vector uiElements = new Vector();
328
329    /** Holds the references to all radio button groups */
330    private Vector buttonGroups = new Vector();
331
332    /** Holds the references to all password field groups */
333    private Vector passwordGroups = new Vector();
334
335    /**
336     * used for temporary storage of references to password groups that have already been read in a
337     * given read cycle.
338     */
339    private Vector passwordGroupsRead = new Vector();
340
341    /** Used to track search fields. Contains SearchField references. */
342    private Vector searchFields = new Vector();
343
344    /** Holds all user inputs for use in automated installation */
345    private Vector entries = new Vector();
346
347    private TwoColumnLayout layout;
348
349    private LocaleDatabase langpack = null;
350
351    /*--------------------------------------------------------------------------*/
352    // This method can be used to search for layout problems. If this class is
353    // compiled with this method uncommented, the layout guides will be shown
354    // on the panel, making it possible to see if all components are placed
355    // correctly.
356    /*--------------------------------------------------------------------------*/
357    // public void paint (Graphics graphics)
358    // {
359    // super.paint (graphics);
360    // layout.showRules ((Graphics2D)graphics, Color.red);
361    // }
362    /*--------------------------------------------------------------------------*/
363    /**
364     * Constructs a <code>UserInputPanel</code>.
365     * 
366     * @param parent reference to the application frame
367     * @param installData shared information about the installation
368     */
369    /*--------------------------------------------------------------------------*/
370    public UserInputPanel(InstallerFrame parent, InstallData installData)
371
372    {
373        super(parent, installData);
374
375        instanceNumber = instanceCount++;
376        this.parentFrame = parent;
377
378        // ----------------------------------------------------
379        // ----------------------------------------------------
380        layout = new TwoColumnLayout(10, 5, 30, 25, TwoColumnLayout.LEFT);
381        setLayout(layout);
382
383        // ----------------------------------------------------
384        // get a locale database
385        // ----------------------------------------------------
386        try
387        {
388            // this.langpack = parent.langpack;
389
390            String resource = LANG_FILE_NAME + "_" + idata.localeISO3;
391            this.langpack = new LocaleDatabase(ResourceManager.getInstance().getInputStream(
392                    resource));
393        }
394        catch (Throwable exception)
395        {}
396
397        // ----------------------------------------------------
398        // read the specifications
399        // ----------------------------------------------------
400        try
401        {
402            readSpec();
403        }
404        catch (Throwable exception)
405        {
406            // log the problem
407            exception.printStackTrace();
408        }
409
410        if (!haveSpec)
411        {
412            // return if we could not read the spec. further
413            // processing will only lead to problems. In this
414            // case we must skip the panel when it gets activated.
415            return;
416        }
417
418        // ----------------------------------------------------
419        // process all field nodes. Each field node is analyzed
420        // for its type, then an appropriate memeber function
421        // is called that will create the correct UI elements.
422        // ----------------------------------------------------
423        Vector fields = spec.getChildrenNamed(FIELD_NODE_ID);
424
425        for (int i = 0; i < fields.size(); i++)
426        {
427            XMLElement field = (XMLElement) fields.elementAt(i);
428            String attribute = field.getAttribute(TYPE);
429
430            if (attribute != null)
431            {
432                if (attribute.equals(RULE_FIELD))
433                {
434                    addRuleField(field);
435                }
436                else if (attribute.equals(TEXT_FIELD))
437                {
438                    addTextField(field);
439                }
440                else if (attribute.equals(COMBO_FIELD))
441                {
442                    addComboBox(field);
443                }
444                else if (attribute.equals(RADIO_FIELD))
445                {
446                    addRadioButton(field);
447                }
448                else if (attribute.equals(PWD_FIELD))
449                {
450                    addPasswordField(field);
451                }
452                else if (attribute.equals(SPACE_FIELD))
453                {
454                    addSpace(field);
455                }
456                else if (attribute.equals(DIVIDER_FIELD))
457                {
458                    addDivider(field);
459                }
460                else if (attribute.equals(CHECK_FIELD))
461                {
462                    addCheckBox(field);
463                }
464                else if (attribute.equals(STATIC_TEXT))
465                {
466                    addText(field);
467                }
468                else if (attribute.equals(TITLE_FIELD))
469                {
470                    addTitle(field);
471                }
472                else if (attribute.equals(SEARCH_FIELD))
473                {
474                    addSearch(field);
475                }
476            }
477        }
478    }
479
480    /*--------------------------------------------------------------------------*/
481    /**
482     * Indicates wether the panel has been validated or not. The installer won't let the user go
483     * further through the installation process until the panel is validated. Default behavior is to
484     * return true.
485     * 
486     * @return A boolean stating wether the panel has been validated or not.
487     */
488    /*--------------------------------------------------------------------------*/
489    public boolean isValidated()
490    {
491        return (readInput());
492    }
493
494    /*--------------------------------------------------------------------------*/
495    /**
496     * This method is called when the panel becomes active.
497     */
498    /*--------------------------------------------------------------------------*/
499    public void panelActivate()
500    {
501        if (spec == null)
502        {
503            // TODO: translate
504            emitError("User input specification could not be found.",
505                    "The specification for the user input panel could not be found. Please contact the packager.");
506            parentFrame.skipPanel();
507        }
508
509        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
510        Vector forUnselectedPacks = spec.getChildrenNamed(UNSELECTEDPACKS);
511        Vector forOs = spec.getChildrenNamed(OS);
512
513        if (!itemRequiredFor(forPacks) || !itemRequiredForUnselected(forUnselectedPacks)
514                || !itemRequiredForOs(forOs))
515        {
516            parentFrame.skipPanel();
517            return;
518        }
519        if (!haveSpec)
520        {
521            parentFrame.skipPanel();
522            return;
523        }
524        // if (uiBuilt)
525        // {
526        // return;
527        // }
528
529        buildUI();
530        if (packsDefined)
531        {
532            parentFrame.lockPrevButton();
533        }
534    }
535
536    /*--------------------------------------------------------------------------*/
537    /**
538     * Asks the panel to set its own XML data that can be brought back for an automated installation
539     * process. Use it as a blackbox if your panel needs to do something even in automated mode.
540     * 
541     * @param panelRoot The XML root element of the panels blackbox tree.
542     */
543    /*--------------------------------------------------------------------------*/
544    public void makeXMLData(XMLElement panelRoot)
545    {
546        Map entryMap = new HashMap();
547
548        for (int i = 0; i < entries.size(); i++)
549        {
550            TextValuePair pair = (TextValuePair) entries.elementAt(i);
551            entryMap.put(pair.toString(), pair.getValue());
552        }
553
554        new UserInputPanelAutomationHelper(entryMap).makeXMLData(idata, panelRoot);
555    }
556
557    /*--------------------------------------------------------------------------*/
558    /**
559     * Builds the UI and makes it ready for display
560     */
561    /*--------------------------------------------------------------------------*/
562    private void buildUI()
563    {
564        Object[] uiElement;
565
566        for (int i = 0; i < uiElements.size(); i++)
567        {
568            uiElement = (Object[]) uiElements.elementAt(i);
569
570            if (itemRequiredFor((Vector) uiElement[POS_PACKS])
571                    && itemRequiredForOs((Vector) uiElement[POS_OS]))
572            {
573                try
574                {
575                    if (uiElement[POS_DISPLAYED] == null
576                            || uiElement[POS_DISPLAYED].toString().equals("false"))
577                    {
578                        add((JComponent) uiElement[POS_FIELD], uiElement[POS_CONSTRAINTS]);
579                    }
580
581                    uiElement[POS_DISPLAYED] = Boolean.valueOf(true);
582                    uiElements.remove(i);
583                    uiElements.add(i, uiElement);
584                }
585                catch (Throwable exception)
586                {
587                    System.out.println("Internal format error in field: "
588                            + uiElement[POS_TYPE].toString()); // !!! logging
589                }
590            }
591            else
592            {
593                try
594                {
595                    if (uiElement[POS_DISPLAYED] != null
596                            && uiElement[POS_DISPLAYED].toString().equals("true"))
597                    {
598                        remove((JComponent) uiElement[POS_FIELD]);
599                    }
600                }
601                catch (Throwable exception)
602                {
603                    System.out.println("Internal format error in field: "
604                            + uiElement[POS_TYPE].toString()); // !!! logging
605                }
606                uiElement[POS_DISPLAYED] = Boolean.valueOf(false);
607                uiElements.remove(i);
608                uiElements.add(i, uiElement);
609            }
610        }
611    }
612
613    /*--------------------------------------------------------------------------*/
614    /**
615     * Reads the input data from all UI elements and sets the associated variables.
616     * 
617     * @return <code>true</code> if the operation is successdul, otherwise <code>false</code>.
618     */
619    /*--------------------------------------------------------------------------*/
620    private boolean readInput()
621    {
622        boolean success;
623        String fieldType = null;
624        Object[] field = null;
625
626        passwordGroupsRead.clear();
627        // ----------------------------------------------------
628        // cycle through all but the password fields and read
629        // their contents
630        // ----------------------------------------------------
631        for (int i = 0; i < uiElements.size(); i++)
632        {
633            field = (Object[]) uiElements.elementAt(i);
634
635            if ((field != null) && (((Boolean) field[POS_DISPLAYED]).booleanValue()))
636            {
637                fieldType = (String) (field[POS_TYPE]);
638
639                // ------------------------------------------------
640                if (fieldType.equals(RULE_FIELD))
641                {
642                    success = readRuleField(field);
643                    if (!success) { return (false); }
644                }
645
646                // ------------------------------------------------
647                if (fieldType.equals(PWD_FIELD))
648                {
649                    success = readPasswordField(field);
650                    if (!success) { return (false); }
651                }
652
653                // ------------------------------------------------
654                else if (fieldType.equals(TEXT_FIELD))
655                {
656                    success = readTextField(field);
657                    if (!success) { return (false); }
658                }
659
660                // ------------------------------------------------
661                else if (fieldType.equals(COMBO_FIELD))
662                {
663                    success = readComboBox(field);
664                    if (!success) { return (false); }
665                }
666
667                // ------------------------------------------------
668                else if (fieldType.equals(RADIO_FIELD))
669                {
670                    success = readRadioButton(field);
671                    if (!success) { return (false); }
672                }
673
674                // ------------------------------------------------
675                else if (fieldType.equals(CHECK_FIELD))
676                {
677                    success = readCheckBox(field);
678                    if (!success) { return (false); }
679                }
680                else if (fieldType.equals(SEARCH_FIELD))
681                {
682                    success = readSearch(field);
683                    if (!success) { return (false); }
684                }
685            }
686        }
687
688        return (true);
689    }
690
691    /*--------------------------------------------------------------------------*/
692    /**
693     * Reads the XML specification for the panel layout. The result is stored in spec.
694     * 
695     * @exception Exception for any problems in reading the specification
696     */
697    /*--------------------------------------------------------------------------*/
698    private void readSpec() throws Exception
699    {
700        InputStream input = null;
701        XMLElement data;
702        Vector specElements;
703        String attribute;
704        String instance = Integer.toString(instanceNumber);
705
706        try
707        {
708            input = parentFrame.getResource(SPEC_FILE_NAME);
709        }
710        catch (Exception exception)
711        {
712            haveSpec = false;
713            return;
714        }
715        if (input == null)
716        {
717            haveSpec = false;
718            return;
719        }
720
721        // initialize the parser
722        StdXMLParser parser = new StdXMLParser();
723        parser.setBuilder(new StdXMLBuilder());
724        parser.setValidator(new NonValidator());
725        parser.setReader(new StdXMLReader(input));
726
727        // get the data
728        data = (XMLElement) parser.parse();
729
730        // extract the spec to this specific panel instance
731        if (data.hasChildren())
732        {
733            specElements = data.getChildrenNamed(NODE_ID);
734            for (int i = 0; i < specElements.size(); i++)
735            {
736                data = (XMLElement) specElements.elementAt(i);
737                attribute = data.getAttribute(INSTANCE_IDENTIFIER);
738
739                if (instance.equals(attribute))
740                {
741                    // use the current element as spec
742                    spec = data;
743                    // close the stream
744                    input.close();
745                    haveSpec = true;
746                    return;
747                }
748            }
749
750            haveSpec = false;
751            return;
752        }
753
754        haveSpec = false;
755    }
756
757    /*--------------------------------------------------------------------------*/
758    /**
759     * Adds the title to the panel. There can only be one title, if mutiple titles are defined, they
760     * keep overwriting what has already be defined, so that the last definition is the one that
761     * prevails.
762     * 
763     * @param spec a <code>XMLElement</code> containing the specification for the title.
764     */
765    /*--------------------------------------------------------------------------*/
766    private void addTitle(XMLElement spec)
767    {
768        String title = getText(spec);
769        boolean italic = getBoolean(spec, ITALICS, false);
770        boolean bold = getBoolean(spec, BOLD, false);
771        float multiplier = getFloat(spec, SIZE, 2.0f);
772        int justify = getAlignment(spec);
773
774        if (title != null)
775        {
776            JLabel label = new JLabel(title);
777            Font font = label.getFont();
778            float size = font.getSize();
779            int style = 0;
780
781            if (bold)
782            {
783                style = style + Font.BOLD;
784            }
785            if (italic)
786            {
787                style = style + Font.ITALIC;
788            }
789
790            font = font.deriveFont(style, (size * multiplier));
791            label.setFont(font);
792            label.setAlignmentX(0);
793
794            TwoColumnConstraints constraints = new TwoColumnConstraints();
795            constraints.align = justify;
796            constraints.position = TwoColumnConstraints.NORTH;
797
798            add(label, constraints);
799        }
800    }
801
802    /*--------------------------------------------------------------------------*/
803    /**
804     * Adds a rule field to the list of UI elements.
805     * 
806     * @param spec a <code>XMLElement</code> containing the specification for the rule field.
807     */
808    /*--------------------------------------------------------------------------*/
809    private void addRuleField(XMLElement spec)
810    {
811        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
812        Vector forOs = spec.getChildrenNamed(OS);
813        XMLElement element = spec.getFirstChildNamed(SPEC);
814        String variable = spec.getAttribute(VARIABLE);
815        RuleInputField field = null;
816        JLabel label;
817        String layout;
818        String set;
819        String separator;
820        String format;
821        String validator = null;
822        String message = null;
823        boolean hasParams = false;
824        String paramName = null;
825        String paramValue = null;
826        HashMap validateParamMap = null;
827        Vector validateParams = null;
828        String processor = null;
829        int resultFormat = RuleInputField.DISPLAY_FORMAT;
830
831        // ----------------------------------------------------
832        // extract the specification details
833        // ----------------------------------------------------
834        if (element != null)
835        {
836            label = new JLabel(getText(element));
837            layout = element.getAttribute(RULE_LAYOUT);
838            set = element.getAttribute(SET);
839
840            // retrieve value of variable if not specified
841            // (does not work here because of special format for set attribute)
842            // if (set == null)
843            // {
844            // set = idata.getVariable (variable);
845            // }
846
847            separator = element.getAttribute(RULE_SEPARATOR);
848            format = element.getAttribute(RULE_RESULT_FORMAT);
849
850            if (format != null)
851            {
852                if (format.equals(RULE_PLAIN_STRING))
853                {
854                    resultFormat = RuleInputField.PLAIN_STRING;
855                }
856                else if (format.equals(RULE_DISPLAY_FORMAT))
857                {
858                    resultFormat = RuleInputField.DISPLAY_FORMAT;
859                }
860                else if (format.equals(RULE_SPECIAL_SEPARATOR))
861                {
862                    resultFormat = RuleInputField.SPECIAL_SEPARATOR;
863                }
864                else if (format.equals(RULE_ENCRYPTED))
865                {
866                    resultFormat = RuleInputField.ENCRYPTED;
867                }
868            }
869        }
870        // ----------------------------------------------------
871        // if there is no specification element, return without
872        // doing anything.
873        // ----------------------------------------------------
874        else
875        {
876            return;
877        }
878
879        // ----------------------------------------------------
880        // get the description and add it to the list of UI
881        // elements if it exists.
882        // ----------------------------------------------------
883        element = spec.getFirstChildNamed(DESCRIPTION);
884        addDescription(element, forPacks, forOs);
885
886        // ----------------------------------------------------
887        // get the validator and processor if they are defined
888        // ----------------------------------------------------
889        element = spec.getFirstChildNamed(VALIDATOR);
890        if (element != null)
891        {
892            validator = element.getAttribute(CLASS);
893            message = getText(element);
894            // ----------------------------------------------------------
895            // check and see if we have any parameters for this validator.
896            // If so, then add them to validateParamMap.
897            // ----------------------------------------------------------
898            validateParams = element.getChildrenNamed(RULE_PARAM);
899            if (validateParams != null && validateParams.size() > 0 && validateParamMap == null)
900            {
901
902                validateParamMap = new HashMap();
903                hasParams = true;
904
905            }
906
907            for (Iterator it = validateParams.iterator(); it.hasNext();)
908            {
909                element = (XMLElement) it.next();
910                paramName = element.getAttribute(RULE_PARAM_NAME);
911                paramValue = element.getAttribute(RULE_PARAM_VALUE);
912                validateParamMap.put(paramName, paramValue);
913            }
914        }
915
916        element = spec.getFirstChildNamed(PROCESSOR);
917        if (element != null)
918        {
919            processor = element.getAttribute(CLASS);
920        }
921
922        // ----------------------------------------------------
923        // create an instance of RuleInputField based on the
924        // extracted specifications, then add it to the list
925        // of UI elements.
926        // ----------------------------------------------------
927        if (hasParams)
928        {
929            field = new RuleInputField(layout, set, separator, validator, validateParamMap,
930                    processor, resultFormat, getToolkit(), idata);
931        }
932        else
933        {
934            field = new RuleInputField(layout, set, separator, validator, processor, resultFormat,
935                    getToolkit(), idata);
936
937        }
938        TwoColumnConstraints constraints = new TwoColumnConstraints();
939        constraints.position = TwoColumnConstraints.WEST;
940
941        uiElements
942                .add(new Object[] { null, FIELD_LABEL, null, constraints, label, forPacks, forOs});
943
944        TwoColumnConstraints constraints2 = new TwoColumnConstraints();
945        constraints2.position = TwoColumnConstraints.EAST;
946
947        uiElements.add(new Object[] { null, RULE_FIELD, variable, constraints2, field, forPacks,
948                forOs, null, null, message});
949    }
950
951    /*--------------------------------------------------------------------------*/
952    /**
953     * Reads the data from the rule input field and sets the associated variable.
954     * 
955     * @param field the object array that holds the details of the field.
956     * 
957     * @return <code>true</code> if there was no problem reading the data or if there was an
958     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
959     * dialog is popped up and <code>false</code> is returned.
960     */
961    /*--------------------------------------------------------------------------*/
962    private boolean readRuleField(Object[] field)
963    {
964        RuleInputField ruleField = null;
965        String variable = null;
966
967        try
968        {
969            ruleField = (RuleInputField) field[POS_FIELD];
970            variable = (String) field[POS_VARIABLE];
971        }
972        catch (Throwable exception)
973        {
974            return (true);
975        }
976        if ((variable == null) || (ruleField == null)) { return (true); }
977
978        boolean success = ruleField.validateContents();
979        if (!success)
980        {
981            String message = "";
982            try
983            {
984                message = langpack.getString((String) field[POS_MESSAGE]);
985                if (message.equals(""))
986                {
987                    message = (String) field[POS_MESSAGE];
988                }
989            }
990            catch (Throwable t)
991            {
992                message = (String) field[POS_MESSAGE];
993            }
994            JOptionPane.showMessageDialog(parentFrame, message, parentFrame.langpack
995                    .getString("UserInputPanel.error.caption"), JOptionPane.WARNING_MESSAGE);
996            return (false);
997        }
998
999        idata.setVariable(variable, ruleField.getText());
1000        entries.add(new TextValuePair(variable, ruleField.getText()));
1001        return (true);
1002    }
1003
1004    /*--------------------------------------------------------------------------*/
1005    /**
1006     * Adds a text field to the list of UI elements
1007     * 
1008     * @param spec a <code>XMLElement</code> containing the specification for the text field.
1009     */
1010    /*--------------------------------------------------------------------------*/
1011    private void addTextField(XMLElement spec)
1012    {
1013        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1014        Vector forOs = spec.getChildrenNamed(OS);
1015        XMLElement element = spec.getFirstChildNamed(SPEC);
1016        JLabel label;
1017        String set;
1018        int size;
1019
1020        String variable = spec.getAttribute(VARIABLE);
1021        if ((variable == null) || (variable.length() == 0)) { return; }
1022
1023        // ----------------------------------------------------
1024        // extract the specification details
1025        // ----------------------------------------------------
1026        if (element != null)
1027        {
1028            label = new JLabel(getText(element));
1029            set = element.getAttribute(SET);
1030            if (set == null)
1031            {
1032                set = idata.getVariable(variable);
1033                if (set == null)
1034                {
1035                    set = "";
1036                }
1037            }else{
1038                if (set != null && !"".equals(set)){
1039                    VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1040                    set = vs.substitute(set, null);
1041                }
1042            }
1043                
1044            try
1045            {
1046                size = Integer.parseInt(element.getAttribute(TEXT_SIZE));
1047            }
1048            catch (Throwable exception)
1049            {
1050                size = 1;
1051            }
1052        }
1053        // ----------------------------------------------------
1054        // if there is no specification element, return without
1055        // doing anything.
1056        // ----------------------------------------------------
1057        else
1058        {
1059            return;
1060        }
1061
1062        // ----------------------------------------------------
1063        // get the description and add it to the list UI
1064        // elements if it exists.
1065        // ----------------------------------------------------
1066        element = spec.getFirstChildNamed(DESCRIPTION);
1067        addDescription(element, forPacks, forOs);
1068
1069        // ----------------------------------------------------
1070        // construct the UI element and add it to the list
1071        // ----------------------------------------------------
1072        JTextField field = new JTextField(set, size);
1073        field.setCaretPosition(0);
1074
1075        TwoColumnConstraints constraints = new TwoColumnConstraints();
1076        constraints.position = TwoColumnConstraints.WEST;
1077
1078        uiElements
1079                .add(new Object[] { null, FIELD_LABEL, null, constraints, label, forPacks, forOs});
1080
1081        TwoColumnConstraints constraints2 = new TwoColumnConstraints();
1082        constraints2.position = TwoColumnConstraints.EAST;
1083
1084        uiElements.add(new Object[] { null, TEXT_FIELD, variable, constraints2, field, forPacks,
1085                forOs});
1086    }
1087
1088    /*--------------------------------------------------------------------------*/
1089    /**
1090     * Reads data from the text field and sets the associated variable.
1091     * 
1092     * @param field the object array that holds the details of the field.
1093     * 
1094     * @return <code>true</code> if there was no problem reading the data or if there was an
1095     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
1096     * dialog is popped up and <code>false</code> is returned.
1097     */
1098    /*--------------------------------------------------------------------------*/
1099    private boolean readTextField(Object[] field)
1100    {
1101        JTextField textField = null;
1102        String variable = null;
1103        String value = null;
1104
1105        try
1106        {
1107            textField = (JTextField) field[POS_FIELD];
1108            variable = (String) field[POS_VARIABLE];
1109            value = textField.getText();
1110        }
1111        catch (Throwable exception)
1112        {
1113            return (true);
1114        }
1115        if ((variable == null) || (value == null)) { return (true); }
1116
1117        idata.setVariable(variable, value);
1118        entries.add(new TextValuePair(variable, value));
1119        return (true);
1120    }
1121
1122    /*--------------------------------------------------------------------------*/
1123    /**
1124     * Adds a combo box to the list of UI elements. <br>
1125     * This is a complete example of a valid XML specification
1126     * 
1127     * <pre>
1128     * 
1129     *  
1130     *   
1131     *    &lt;field type=&quot;combo&quot; variable=&quot;testVariable&quot;&gt;
1132     *      &lt;description text=&quot;Description for the combo box&quot; id=&quot;a key for translated text&quot;/&gt;
1133     *      &lt;spec text=&quot;label&quot; id=&quot;key for the label&quot;/&gt;
1134     *        &lt;choice text=&quot;choice 1&quot; id=&quot;&quot; value=&quot;combo box 1&quot;/&gt;
1135     *        &lt;choice text=&quot;choice 2&quot; id=&quot;&quot; value=&quot;combo box 2&quot; set=&quot;true&quot;/&gt;
1136     *        &lt;choice text=&quot;choice 3&quot; id=&quot;&quot; value=&quot;combo box 3&quot;/&gt;
1137     *        &lt;choice text=&quot;choice 4&quot; id=&quot;&quot; value=&quot;combo box 4&quot;/&gt;
1138     *      &lt;/spec&gt;
1139     *    &lt;/field&gt;
1140     *    
1141     *   
1142     *  
1143     * </pre>
1144     * 
1145     * @param spec a <code>XMLElement</code> containing the specification for the combo box.
1146     */
1147    /*--------------------------------------------------------------------------*/
1148    private void addComboBox(XMLElement spec)
1149    {
1150        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1151        Vector forOs = spec.getChildrenNamed(OS);
1152        XMLElement element = spec.getFirstChildNamed(SPEC);
1153        String variable = spec.getAttribute(VARIABLE);
1154        TextValuePair listItem = null;
1155        JComboBox field = new JComboBox();
1156        JLabel label;
1157
1158        // ----------------------------------------------------
1159        // extract the specification details
1160        // ----------------------------------------------------
1161        if (element != null)
1162        {
1163            label = new JLabel(getText(element));
1164
1165            Vector choices = element.getChildrenNamed(COMBO_CHOICE);
1166
1167            if (choices == null) { return; }
1168
1169            for (int i = 0; i < choices.size(); i++)
1170            {
1171                String processorClass = ((XMLElement) choices.elementAt(i))
1172                        .getAttribute("processor");
1173
1174                if (processorClass != null && !"".equals(processorClass))
1175                {
1176                    String choiceValues = "";
1177                    try
1178                    {
1179                        choiceValues = ((Processor) Class.forName(processorClass).newInstance())
1180                                .process(null);
1181                    }
1182                    catch (Throwable t)
1183                    {
1184                        t.printStackTrace();
1185                    }
1186                    String set = ((XMLElement) choices.elementAt(i)).getAttribute(SET);
1187                    if (set == null)
1188                    {
1189                        set = "";
1190                    }
1191                    if (set != null && !"".equals(set)){
1192                        VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1193                        set = vs.substitute(set, null);
1194                    }
1195                    
1196                    StringTokenizer tokenizer = new StringTokenizer(choiceValues, ":");
1197                    int counter = 0;
1198                    while (tokenizer.hasMoreTokens())
1199                    {
1200                        String token = tokenizer.nextToken();
1201                        listItem = new TextValuePair(token, token);
1202                        field.addItem(listItem);
1203                        if (set.equals(token))
1204                        {
1205                            field.setSelectedIndex(field.getItemCount() - 1);
1206                        }
1207                        counter++;
1208                    }
1209                }
1210                else
1211                {
1212                    listItem = new TextValuePair(getText((XMLElement) choices.elementAt(i)),
1213                            ((XMLElement) choices.elementAt(i)).getAttribute(COMBO_VALUE));
1214                    field.addItem(listItem);
1215                    String set = ((XMLElement) choices.elementAt(i)).getAttribute(SET);
1216                    if (set != null)
1217                    {
1218                        if (set != null && !"".equals(set)){
1219                            VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1220                            set = vs.substitute(set, null);
1221                        }
1222                        if (set.equals(TRUE))
1223                        {
1224                            field.setSelectedIndex(i);
1225                        }
1226                    }
1227                }
1228
1229            }
1230        }
1231        // ----------------------------------------------------
1232        // if there is no specification element, return without
1233        // doing anything.
1234        // ----------------------------------------------------
1235        else
1236        {
1237            return;
1238        }
1239
1240        // ----------------------------------------------------
1241        // get the description and add it to the list of UI
1242        // elements if it exists.
1243        // ----------------------------------------------------
1244        element = spec.getFirstChildNamed(DESCRIPTION);
1245        addDescription(element, forPacks, forOs);
1246
1247        TwoColumnConstraints constraints = new TwoColumnConstraints();
1248        constraints.position = TwoColumnConstraints.WEST;
1249
1250        uiElements
1251                .add(new Object[] { null, FIELD_LABEL, null, constraints, label, forPacks, forOs});
1252
1253        TwoColumnConstraints constraints2 = new TwoColumnConstraints();
1254        constraints2.position = TwoColumnConstraints.EAST;
1255
1256        uiElements.add(new Object[] { null, COMBO_FIELD, variable, constraints2, field, forPacks,
1257                forOs});
1258    }
1259
1260    /*--------------------------------------------------------------------------*/
1261    /**
1262     * Reads the content of the combobox field and substitutes the associated variable.
1263     * 
1264     * @param field the object array that holds the details of the field.
1265     * 
1266     * @return <code>true</code> if there was no problem reading the data or if there was an
1267     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
1268     * dialog is popped up and <code>false</code> is returned.
1269     */
1270    /*--------------------------------------------------------------------------*/
1271    private boolean readComboBox(Object[] field)
1272    {
1273        String variable;
1274        String value;
1275        JComboBox comboBox;
1276
1277        try
1278        {
1279            variable = (String) field[POS_VARIABLE];
1280            comboBox = (JComboBox) field[POS_FIELD];
1281            value = ((TextValuePair) comboBox.getSelectedItem()).getValue();
1282        }
1283        catch (Throwable exception)
1284        {
1285            return true;
1286        }
1287        if ((variable == null) || (value == null)) { return true; }
1288
1289        idata.setVariable(variable, value);
1290        entries.add(new TextValuePair(variable, value));
1291        return true;
1292    }
1293
1294    /*--------------------------------------------------------------------------*/
1295    /**
1296     * Adds a radio button set to the list of UI elements. <br>
1297     * This is a complete example of a valid XML specification
1298     * 
1299     * <pre>
1300     * 
1301     *  
1302     *   
1303     *    &lt;field type=&quot;radio&quot; variable=&quot;testVariable&quot;&gt;
1304     *      &lt;description text=&quot;Description for the radio buttons&quot; id=&quot;a key for translated text&quot;/&gt;
1305     *      &lt;spec text=&quot;label&quot; id=&quot;key for the label&quot;/&gt;
1306     *        &lt;choice text=&quot;radio 1&quot; id=&quot;&quot; value=&quot;&quot;/&gt;
1307     *        &lt;choice text=&quot;radio 2&quot; id=&quot;&quot; value=&quot;&quot; set=&quot;true&quot;/&gt;
1308     *        &lt;choice text=&quot;radio 3&quot; id=&quot;&quot; value=&quot;&quot;/&gt;
1309     *        &lt;choice text=&quot;radio 4&quot; id=&quot;&quot; value=&quot;&quot;/&gt;
1310     *        &lt;choice text=&quot;radio 5&quot; id=&quot;&quot; value=&quot;&quot;/&gt;
1311     *      &lt;/spec&gt;
1312     *    &lt;/field&gt;
1313     *    
1314     *   
1315     *  
1316     * </pre>
1317     * 
1318     * @param spec a <code>XMLElement</code> containing the specification for the radio button
1319     * set.
1320     */
1321    /*--------------------------------------------------------------------------*/
1322    private void addRadioButton(XMLElement spec)
1323    {
1324        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1325        Vector forOs = spec.getChildrenNamed(OS);
1326        String variable = spec.getAttribute(VARIABLE);
1327        String value = null;
1328
1329        XMLElement element = null;
1330        ButtonGroup group = new ButtonGroup();
1331
1332        TwoColumnConstraints constraints = new TwoColumnConstraints();
1333        constraints.position = TwoColumnConstraints.BOTH;
1334        constraints.indent = true;
1335        constraints.stretch = true;
1336
1337        // ----------------------------------------------------
1338        // get the description and add it to the list of UI
1339        // elements if it exists.
1340        // ----------------------------------------------------
1341        element = spec.getFirstChildNamed(DESCRIPTION);
1342        addDescription(element, forPacks, forOs);
1343
1344        // ----------------------------------------------------
1345        // extract the specification details
1346        // ----------------------------------------------------
1347        element = spec.getFirstChildNamed(SPEC);
1348
1349        if (element != null)
1350        {
1351            Vector choices = element.getChildrenNamed(RADIO_CHOICE);
1352
1353            if (choices == null) { return; }
1354
1355            // --------------------------------------------------
1356            // process each choice element
1357            // --------------------------------------------------
1358            for (int i = 0; i < choices.size(); i++)
1359            {
1360                JRadioButton choice = new JRadioButton();
1361                choice.setText(getText((XMLElement) choices.elementAt(i)));
1362                value = (((XMLElement) choices.elementAt(i)).getAttribute(RADIO_VALUE));
1363
1364                group.add(choice);
1365
1366                String set = ((XMLElement) choices.elementAt(i)).getAttribute(SET);
1367                if (set != null)
1368                {
1369                    if (set != null && !"".equals(set)){
1370                        VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1371                        set = vs.substitute(set, null);
1372                    }
1373                    if (set.equals(TRUE))
1374                    {
1375                        choice.setSelected(true);
1376                    }
1377                }
1378
1379                buttonGroups.add(group);
1380                uiElements.add(new Object[] { null, RADIO_FIELD, variable, constraints, choice,
1381                        forPacks, forOs, value, null, null, group});
1382            }
1383        }
1384    }
1385
1386    /*--------------------------------------------------------------------------*/
1387    /**
1388     * Reads the content of the radio button field and substitutes the associated variable.
1389     * 
1390     * @param field the object array that holds the details of the field.
1391     * 
1392     * @return <code>true</code> if there was no problem reading the data or if there was an
1393     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
1394     * dialog is popped up and <code>false</code> is returned.
1395     */
1396    /*--------------------------------------------------------------------------*/
1397    private boolean readRadioButton(Object[] field)
1398    {
1399        String variable = null;
1400        String value = null;
1401        JRadioButton button = null;
1402
1403        try
1404        {
1405            button = (JRadioButton) field[POS_FIELD];
1406
1407            if (!button.isSelected()) { return (true); }
1408
1409            variable = (String) field[POS_VARIABLE];
1410            value = (String) field[POS_TRUE];
1411        }
1412        catch (Throwable exception)
1413        {
1414            return (true);
1415        }
1416
1417        idata.setVariable(variable, value);
1418        entries.add(new TextValuePair(variable, value));
1419        return (true);
1420    }
1421
1422    /*--------------------------------------------------------------------------*/
1423    /**
1424     * Adds one or more password fields to the list of UI elements. <br>
1425     * This is a complete example of a valid XML specification
1426     * 
1427     * <pre>
1428     * 
1429     *  
1430     *   
1431     *    &lt;field type=&quot;password&quot; variable=&quot;testVariable&quot;&gt;
1432     *      &lt;description align=&quot;left&quot; txt=&quot;Please enter your password&quot; id=&quot;a key for translated text&quot;/&gt;
1433     *      &lt;spec&gt;
1434     *        &lt;pwd txt=&quot;Password&quot; id=&quot;key for the label&quot; size=&quot;10&quot; set=&quot;&quot;/&gt;
1435     *        &lt;pwd txt=&quot;Retype password&quot; id=&quot;another key for the label&quot; size=&quot;10&quot; set=&quot;&quot;/&gt;
1436     *      &lt;/spec&gt;
1437     *      &lt;validator class=&quot;com.izforge.sample.PWDValidator&quot; txt=&quot;Both versions of the password must match&quot; id=&quot;key for the error text&quot;/&gt;
1438     *      &lt;processor class=&quot;com.izforge.sample.PWDEncryptor&quot;/&gt;
1439     *    &lt;/field&gt;
1440     *    
1441     *   
1442     *  
1443     * </pre>
1444     * 
1445     * @param spec a <code>XMLElement</code> containing the specification for the set of password
1446     * fields.
1447     */
1448    /*--------------------------------------------------------------------------*/
1449    private void addPasswordField(XMLElement spec)
1450    {
1451        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1452        Vector forOs = spec.getChildrenNamed(OS);
1453        String variable = spec.getAttribute(VARIABLE);
1454        String validator = null;
1455        String message = null;
1456        String processor = null;
1457        XMLElement element = null;
1458        PasswordGroup group = null;
1459        int size = 0;
1460
1461        // ----------------------------------------------------
1462        // get the description and add it to the list of UI
1463        // elements if it exists.
1464        // ----------------------------------------------------
1465        element = spec.getFirstChildNamed(DESCRIPTION);
1466        addDescription(element, forPacks, forOs);
1467
1468        // ----------------------------------------------------
1469        // get the validator and processor if they are defined
1470        // ----------------------------------------------------
1471        element = spec.getFirstChildNamed(VALIDATOR);
1472        if (element != null)
1473        {
1474            validator = element.getAttribute(CLASS);
1475            message = getText(element);
1476        }
1477
1478        element = spec.getFirstChildNamed(PROCESSOR);
1479        if (element != null)
1480        {
1481            processor = element.getAttribute(CLASS);
1482        }
1483
1484        group = new PasswordGroup(validator, processor);
1485
1486        // ----------------------------------------------------
1487        // extract the specification details
1488        // ----------------------------------------------------
1489        element = spec.getFirstChildNamed(SPEC);
1490
1491        if (element != null)
1492        {
1493            Vector inputs = element.getChildrenNamed(PWD_INPUT);
1494
1495            if (inputs == null) { return; }
1496
1497            // --------------------------------------------------
1498            // process each input field
1499            // --------------------------------------------------
1500            XMLElement fieldSpec;
1501            for (int i = 0; i < inputs.size(); i++)
1502            {
1503                fieldSpec = (XMLElement) inputs.elementAt(i);
1504                String set = fieldSpec.getAttribute(SET);
1505                if (set != null && !"".equals(set)){
1506                    VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1507                    set = vs.substitute(set, null);
1508                }
1509                JLabel label = new JLabel(getText(fieldSpec));
1510                try
1511                {
1512                    size = Integer.parseInt(fieldSpec.getAttribute(PWD_SIZE));
1513                }
1514                catch (Throwable exception)
1515                {
1516                    size = 1;
1517                }
1518
1519                // ----------------------------------------------------
1520                // construct the UI element and add it to the list
1521                // ----------------------------------------------------
1522                JPasswordField field = new JPasswordField(set, size);
1523                field.setCaretPosition(0);
1524
1525                TwoColumnConstraints constraints = new TwoColumnConstraints();
1526                constraints.position = TwoColumnConstraints.WEST;
1527
1528                uiElements.add(new Object[] { null, FIELD_LABEL, null, constraints, label,
1529                        forPacks, forOs});
1530
1531                TwoColumnConstraints constraints2 = new TwoColumnConstraints();
1532                constraints2.position = TwoColumnConstraints.EAST;
1533
1534                uiElements.add(new Object[] { null, PWD_FIELD, variable, constraints2, field,
1535                        forPacks, forOs, null, null, message, group});
1536                group.addField(field);
1537            }
1538        }
1539
1540        passwordGroups.add(group);
1541    }
1542
1543    /*--------------------------------------------------------------------------*/
1544    /**
1545     * Reads the content of the password field and substitutes the associated variable.
1546     * 
1547     * @param field a password group that manages one or more passord fields.
1548     * 
1549     * @return <code>true</code> if there was no problem reading the data or if there was an
1550     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
1551     * dialog is popped up and <code>false</code> is returned.
1552     */
1553    /*--------------------------------------------------------------------------*/
1554    private boolean readPasswordField(Object[] field)
1555    {
1556        PasswordGroup group = null;
1557        String variable = null;
1558        String message = null;
1559
1560        try
1561        {
1562            group = (PasswordGroup) field[POS_GROUP];
1563            variable = (String) field[POS_VARIABLE];
1564            message = (String) field[POS_MESSAGE];
1565        }
1566        catch (Throwable exception)
1567        {
1568            return (true);
1569        }
1570        if ((variable == null) || (passwordGroupsRead.contains(group))) { return (true); }
1571        passwordGroups.add(group);
1572
1573        boolean success = group.validateContents();
1574
1575        if (!success)
1576        {
1577            JOptionPane.showMessageDialog(parentFrame, message, parentFrame.langpack
1578                    .getString("UserInputPanel.error.caption"), JOptionPane.WARNING_MESSAGE);
1579            return (false);
1580        }
1581
1582        idata.setVariable(variable, group.getPassword());
1583        entries.add(new TextValuePair(variable, group.getPassword()));
1584        return (true);
1585    }
1586
1587    /*--------------------------------------------------------------------------*/
1588    /**
1589     * Adds a chackbox to the list of UI elements.
1590     * 
1591     * @param spec a <code>XMLElement</code> containing the specification for the checkbox.
1592     */
1593    /*--------------------------------------------------------------------------*/
1594    private void addCheckBox(XMLElement spec)
1595    {
1596        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1597        Vector forOs = spec.getChildrenNamed(OS);
1598        String label = "";
1599        String set = null;
1600        String trueValue = null;
1601        String falseValue = null;
1602        String variable = spec.getAttribute(VARIABLE);
1603        XMLElement detail = spec.getFirstChildNamed(SPEC);
1604
1605        if (variable == null) { return; }
1606
1607        if (detail != null)
1608        {
1609            label = getText(detail);
1610            set = detail.getAttribute(SET);
1611            trueValue = detail.getAttribute(TRUE);
1612            falseValue = detail.getAttribute(FALSE);
1613        }
1614
1615        JCheckBox checkbox = new JCheckBox(label);
1616
1617        if (set != null)
1618        {
1619            if (set != null && !"".equals(set)){
1620                VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1621                set = vs.substitute(set, null);
1622            }
1623            if (set.equals(FALSE))
1624            {
1625                checkbox.setSelected(false);
1626            }
1627            if (set.equals(TRUE))
1628            {
1629                checkbox.setSelected(true);
1630            }
1631        }
1632
1633        // ----------------------------------------------------
1634        // get the description and add it to the list of UI
1635        // elements if it exists.
1636        // ----------------------------------------------------
1637        XMLElement element = spec.getFirstChildNamed(DESCRIPTION);
1638        addDescription(element, forPacks, forOs);
1639
1640        TwoColumnConstraints constraints = new TwoColumnConstraints();
1641        constraints.position = TwoColumnConstraints.BOTH;
1642        constraints.stretch = true;
1643        constraints.indent = true;
1644
1645        uiElements.add(new Object[] { null, CHECK_FIELD, variable, constraints, checkbox, forPacks,
1646                forOs, trueValue, falseValue});
1647    }
1648
1649    /*--------------------------------------------------------------------------*/
1650    /**
1651     * Reads the content of the checkbox field and substitutes the associated variable.
1652     * 
1653     * @param field the object array that holds the details of the field.
1654     * 
1655     * @return <code>true</code> if there was no problem reading the data or if there was an
1656     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
1657     * dialog is popped up and <code>false</code> is returned.
1658     */
1659    /*--------------------------------------------------------------------------*/
1660    private boolean readCheckBox(Object[] field)
1661    {
1662        String variable = null;
1663        String trueValue = null;
1664        String falseValue = null;
1665        JCheckBox box = null;
1666
1667        try
1668        {
1669            box = (JCheckBox) field[POS_FIELD];
1670            variable = (String) field[POS_VARIABLE];
1671            trueValue = (String) field[POS_TRUE];
1672            if (trueValue == null)
1673            {
1674                trueValue = "";
1675            }
1676
1677            falseValue = (String) field[POS_FALSE];
1678            if (falseValue == null)
1679            {
1680                falseValue = "";
1681            }
1682        }
1683        catch (Throwable exception)
1684        {
1685            return (true);
1686        }
1687
1688        if (box.isSelected())
1689        {
1690            idata.setVariable(variable, trueValue);
1691            entries.add(new TextValuePair(variable, trueValue));
1692        }
1693        else
1694        {
1695            idata.setVariable(variable, falseValue);
1696            entries.add(new TextValuePair(variable, falseValue));
1697        }
1698
1699        return (true);
1700    }
1701
1702    /*--------------------------------------------------------------------------*/
1703    /**
1704     * Adds a search field to the list of UI elements.
1705     * <p>
1706     * This is a complete example of a valid XML specification
1707     * 
1708     * <pre>
1709     * 
1710     *  
1711     *   
1712     *    &lt;field type=&quot;search&quot; variable=&quot;testVariable&quot;&gt;
1713     *      &lt;description text=&quot;Description for the search field&quot; id=&quot;a key for translated text&quot;/&gt;
1714     *      &lt;spec text=&quot;label&quot; id=&quot;key for the label&quot; filename=&quot;the_file_to_search&quot; result=&quot;directory&quot; /&gt; &lt;!-- values for result: directory, file --&gt;
1715     *        &lt;choice dir=&quot;directory1&quot; set=&quot;true&quot; /&gt; &lt;!-- default value --&gt;
1716     *        &lt;choice dir=&quot;dir2&quot; /&gt;
1717     *      &lt;/spec&gt;
1718     *    &lt;/field&gt;
1719     *    
1720     *   
1721     *  
1722     * </pre>
1723     * 
1724     * @param spec a <code>XMLElement</code> containing the specification for the search field
1725     */
1726    /*--------------------------------------------------------------------------*/
1727    private void addSearch(XMLElement spec)
1728    {
1729        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1730        Vector forOs = spec.getChildrenNamed(OS);
1731        XMLElement element = spec.getFirstChildNamed(SPEC);
1732        String variable = spec.getAttribute(VARIABLE);
1733        String filename = null;
1734        String check_filename = null;
1735        int search_type = 0;
1736        int result_type = 0;
1737        JComboBox combobox = new JComboBox();
1738        JLabel label = null;
1739
1740        // System.out.println ("adding search combobox, variable "+variable);
1741
1742        // allow the user to enter something
1743        combobox.setEditable(true);
1744
1745        // ----------------------------------------------------
1746        // extract the specification details
1747        // ----------------------------------------------------
1748        if (element != null)
1749        {
1750            label = new JLabel(getText(element));
1751
1752            // search type is optional (default: file)
1753            search_type = SearchField.TYPE_FILE;
1754
1755            String search_type_str = element.getAttribute(SEARCH_TYPE);
1756
1757            if (search_type_str != null)
1758            {
1759                if (search_type_str.equals(SEARCH_FILE))
1760                {
1761                    search_type = SearchField.TYPE_FILE;
1762                }
1763                else if (search_type_str.equals(SEARCH_DIRECTORY))
1764                {
1765                    search_type = SearchField.TYPE_DIRECTORY;
1766                }
1767            }
1768
1769            // result type is mandatory too
1770            String result_type_str = element.getAttribute(SEARCH_RESULT);
1771
1772            if (result_type_str == null)
1773            {
1774                return;
1775            }
1776            else if (result_type_str.equals(SEARCH_FILE))
1777            {
1778                result_type = SearchField.RESULT_FILE;
1779            }
1780            else if (result_type_str.equals(SEARCH_DIRECTORY))
1781            {
1782                result_type = SearchField.RESULT_DIRECTORY;
1783            }
1784            else if (result_type_str.equals(SEARCH_PARENTDIR))
1785            {
1786                result_type = SearchField.RESULT_PARENTDIR;
1787            }
1788            else
1789            {
1790                return;
1791            }
1792
1793            // might be missing - null is okay
1794            filename = element.getAttribute(SEARCH_FILENAME);
1795
1796            check_filename = element.getAttribute(SEARCH_CHECKFILENAME);
1797
1798            Vector choices = element.getChildrenNamed(SEARCH_CHOICE);
1799
1800            if (choices == null) { return; }
1801
1802            for (int i = 0; i < choices.size(); i++)
1803            {
1804                XMLElement choice_el = (XMLElement) choices.elementAt(i);
1805
1806                if (!OsConstraint.oneMatchesCurrentSystem(choice_el)) continue;
1807
1808                String value = choice_el.getAttribute(SEARCH_VALUE);
1809
1810                combobox.addItem(value);
1811
1812                String set = ((XMLElement) choices.elementAt(i)).getAttribute(SET);
1813                if (set != null)
1814                {
1815                    if (set != null && !"".equals(set)){
1816                        VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
1817                        set = vs.substitute(set, null);
1818                    }
1819                    if (set.equals(TRUE))
1820                    {
1821                        combobox.setSelectedIndex(i);
1822                    }
1823                }
1824            }
1825        }
1826        // ----------------------------------------------------
1827        // if there is no specification element, return without
1828        // doing anything.
1829        // ----------------------------------------------------
1830        else
1831        {
1832            return;
1833        }
1834
1835        // ----------------------------------------------------
1836        // get the description and add it to the list of UI
1837        // elements if it exists.
1838        // ----------------------------------------------------
1839        element = spec.getFirstChildNamed(DESCRIPTION);
1840        addDescription(element, forPacks, forOs);
1841
1842        TwoColumnConstraints westconstraint1 = new TwoColumnConstraints();
1843        westconstraint1.position = TwoColumnConstraints.WEST;
1844
1845        uiElements.add(new Object[] { null, FIELD_LABEL, null, westconstraint1, label, forPacks,
1846                forOs});
1847
1848        TwoColumnConstraints eastconstraint1 = new TwoColumnConstraints();
1849        eastconstraint1.position = TwoColumnConstraints.EAST;
1850
1851        StringBuffer tooltiptext = new StringBuffer();
1852
1853        if ((filename != null) && (filename.length() > 0))
1854        {
1855            tooltiptext.append(MessageFormat.format(parentFrame.langpack
1856                    .getString("UserInputPanel.search.location"), new String[] { filename}));
1857        }
1858
1859        boolean showAutodetect = (check_filename != null) && (check_filename.length() > 0);
1860        if (showAutodetect)
1861        {
1862            tooltiptext.append(MessageFormat.format(parentFrame.langpack
1863                    .getString("UserInputPanel.search.location.checkedfile"),
1864                    new String[] { check_filename}));
1865        }
1866
1867        if (tooltiptext.length() > 0) combobox.setToolTipText(tooltiptext.toString());
1868
1869        uiElements.add(new Object[] { null, SEARCH_FIELD, variable, eastconstraint1, combobox,
1870                forPacks, forOs});
1871
1872        JPanel buttonPanel = new JPanel();
1873        buttonPanel.setLayout(new com.izforge.izpack.gui.FlowLayout(
1874                com.izforge.izpack.gui.FlowLayout.LEADING));
1875
1876        JButton autodetectButton = ButtonFactory.createButton(parentFrame.langpack
1877                .getString("UserInputPanel.search.autodetect"), idata.buttonsHColor);
1878        autodetectButton.setVisible(showAutodetect);
1879
1880        autodetectButton.setToolTipText(parentFrame.langpack
1881                .getString("UserInputPanel.search.autodetect.tooltip"));
1882
1883        buttonPanel.add(autodetectButton);
1884
1885        JButton browseButton = ButtonFactory.createButton(parentFrame.langpack
1886                .getString("UserInputPanel.search.browse"), idata.buttonsHColor);
1887
1888        buttonPanel.add(browseButton);
1889
1890        TwoColumnConstraints eastonlyconstraint = new TwoColumnConstraints();
1891        eastonlyconstraint.position = TwoColumnConstraints.EASTONLY;
1892
1893        uiElements.add(new Object[] { null, SEARCH_BUTTON_FIELD, null, eastonlyconstraint,
1894                buttonPanel, forPacks, forOs});
1895
1896        searchFields.add(new SearchField(filename, check_filename, parentFrame, combobox,
1897                autodetectButton, browseButton, search_type, result_type));
1898    }
1899
1900    /*--------------------------------------------------------------------------*/
1901    /**
1902     * Reads the content of the search field and substitutes the associated variable.
1903     * 
1904     * @param field the object array that holds the details of the field.
1905     * 
1906     * @return <code>true</code> if there was no problem reading the data or if there was an
1907     * irrecovarable problem. If there was a problem that can be corrected by the operator, an error
1908     * dialog is popped up and <code>false</code> is returned.
1909     */
1910    /*--------------------------------------------------------------------------*/
1911    private boolean readSearch(Object[] field)
1912    {
1913        String variable = null;
1914        String value = null;
1915        JComboBox comboBox = null;
1916
1917        try
1918        {
1919            variable = (String) field[POS_VARIABLE];
1920            comboBox = (JComboBox) field[POS_FIELD];
1921            for (int i = 0; i < this.searchFields.size(); ++i)
1922            {
1923                SearchField sf = (SearchField) this.searchFields.elementAt(i);
1924                if (sf.belongsTo(comboBox))
1925                {
1926                    value = sf.getResult();
1927                    break;
1928                }
1929            }
1930        }
1931        catch (Throwable exception)
1932        {
1933            return (true);
1934        }
1935        if ((variable == null) || (value == null)) { return (true); }
1936
1937        idata.setVariable(variable, value);
1938        entries.add(new TextValuePair(variable, value));
1939        return (true);
1940    }
1941
1942    /*--------------------------------------------------------------------------*/
1943    /**
1944     * Adds text to the list of UI elements
1945     * 
1946     * @param spec a <code>XMLElement</code> containing the specification for the text.
1947     */
1948    /*--------------------------------------------------------------------------*/
1949    private void addText(XMLElement spec)
1950    {
1951        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1952        Vector forOs = spec.getChildrenNamed(OS);
1953
1954        addDescription(spec, forPacks, forOs);
1955    }
1956
1957    /*--------------------------------------------------------------------------*/
1958    /**
1959     * Adds a dummy field to the list of UI elements to act as spacer.
1960     * 
1961     * @param spec a <code>XMLElement</code> containing other specifications. At present this
1962     * information is not used but might be in future versions.
1963     */
1964    /*--------------------------------------------------------------------------*/
1965    private void addSpace(XMLElement spec)
1966    {
1967        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1968        Vector forOs = spec.getChildrenNamed(OS);
1969        JPanel panel = new JPanel();
1970
1971        TwoColumnConstraints constraints = new TwoColumnConstraints();
1972        constraints.position = TwoColumnConstraints.BOTH;
1973        constraints.stretch = true;
1974
1975        uiElements
1976                .add(new Object[] { null, SPACE_FIELD, null, constraints, panel, forPacks, forOs});
1977    }
1978
1979    /*--------------------------------------------------------------------------*/
1980    /**
1981     * Adds a dividing line to the list of UI elements act as separator.
1982     * 
1983     * @param spec a <code>XMLElement</code> containing additional specifications.
1984     */
1985    /*--------------------------------------------------------------------------*/
1986    private void addDivider(XMLElement spec)
1987    {
1988        Vector forPacks = spec.getChildrenNamed(SELECTEDPACKS);
1989        Vector forOs = spec.getChildrenNamed(OS);
1990        JPanel panel = new JPanel();
1991        String alignment = spec.getAttribute(ALIGNMENT);
1992
1993        if (alignment != null)
1994        {
1995            if (alignment.equals(TOP))
1996            {
1997                panel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.gray));
1998            }
1999            else
2000            {
2001                panel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.gray));
2002            }
2003        }
2004        else
2005        {
2006            panel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.gray));
2007        }
2008
2009        TwoColumnConstraints constraints = new TwoColumnConstraints();
2010        constraints.position = TwoColumnConstraints.BOTH;
2011        constraints.stretch = true;
2012
2013        uiElements.add(new Object[] { null, DIVIDER_FIELD, null, constraints, panel, forPacks,
2014                forOs});
2015    }
2016
2017    /*--------------------------------------------------------------------------*/
2018    /**
2019     * Adds a description to the list of UI elements.
2020     * 
2021     * @param spec a <code>XMLElement</code> containing the specification for the description.
2022     */
2023    /*--------------------------------------------------------------------------*/
2024    private void addDescription(XMLElement spec, Vector forPacks, Vector forOs)
2025    {
2026        String description;
2027        TwoColumnConstraints constraints = new TwoColumnConstraints();
2028        constraints.position = TwoColumnConstraints.BOTH;
2029        constraints.stretch = true;
2030
2031        if (spec != null)
2032        {
2033            description = getText(spec);
2034
2035            // if we have a description, add it to the UI elements
2036            if (description != null)
2037            {
2038                String alignment = spec.getAttribute(ALIGNMENT);
2039                int justify = MultiLineLabel.LEFT;
2040
2041                if (alignment != null)
2042                {
2043                    if (alignment.equals(LEFT))
2044                    {
2045                        justify = MultiLineLabel.LEFT;
2046                    }
2047                    else if (alignment.equals(CENTER))
2048                    {
2049                        justify = MultiLineLabel.CENTER;
2050                    }
2051                    else if (alignment.equals(RIGHT))
2052                    {
2053                        justify = MultiLineLabel.RIGHT;
2054                    }
2055                }
2056
2057                MultiLineLabel label = new MultiLineLabel(description, justify);
2058
2059                uiElements.add(new Object[] { null, DESCRIPTION, null, constraints, label,
2060                        forPacks, forOs});
2061            }
2062        }
2063    }
2064
2065    /*--------------------------------------------------------------------------*/
2066    /**
2067     * Retrieves the value of a boolean attribute. If the attribute is found and the values equals
2068     * the value of the constant <code>TRUE</code> then true is returned. If it equals
2069     * <code>FALSE</code> the false is returned. In all other cases, including when the attribute
2070     * is not found, the default value is returned.
2071     * 
2072     * @param element the <code>XMLElement</code> to search for the attribute.
2073     * @param attribute the attribute to search for
2074     * @param defaultValue the default value to use if the attribute does not exist or a illegal
2075     * value was discovered.
2076     * 
2077     * @return <code>true</code> if the attribute is found and the value equals the the constant
2078     * <code>TRUE</code>. <<code> if the
2079     *            attribute is <code>FALSE</code>. In all other cases the
2080     *            default value is returned.
2081     */
2082    /*--------------------------------------------------------------------------*/
2083    private boolean getBoolean(XMLElement element, String attribute, boolean defaultValue)
2084    {
2085        boolean result = defaultValue;
2086
2087        if ((attribute != null) && (attribute.length() > 0))
2088        {
2089            String value = element.getAttribute(attribute);
2090
2091            if (value != null)
2092            {
2093                if (value.equals(TRUE))
2094                {
2095                    result = true;
2096                }
2097                else if (value.equals(FALSE))
2098                {
2099                    result = false;
2100                }
2101            }
2102        }
2103
2104        return (result);
2105    }
2106
2107    /*--------------------------------------------------------------------------*/
2108    /**
2109     * Retrieves the value of an integer attribute. If the attribute is not found or the value is
2110     * non-numeric then the default value is returned.
2111     * 
2112     * @param element the <code>XMLElement</code> to search for the attribute.
2113     * @param attribute the attribute to search for
2114     * @param defaultValue the default value to use in case the attribute does not exist.
2115     * 
2116     * @return the value of the attribute. If the attribute is not found or the content is not a
2117     * legal integer, then the default value is returned.
2118     */
2119    /*--------------------------------------------------------------------------*/
2120//    private int getInt(XMLElement element, String attribute, int defaultValue)
2121//    {
2122//        int result = defaultValue;
2123//
2124//        if ((attribute != null) && (attribute.length() > 0))
2125//        {
2126//            try
2127//            {
2128//                result = Integer.parseInt(element.getAttribute(attribute));
2129//            }
2130//            catch (Throwable exception)
2131//            {}
2132//        }
2133//
2134//        return (result);
2135//    }
2136
2137    /*--------------------------------------------------------------------------*/
2138    /**
2139     * Retrieves the value of a floating point attribute. If the attribute is not found or the value
2140     * is non-numeric then the default value is returned.
2141     * 
2142     * @param element the <code>XMLElement</code> to search for the attribute.
2143     * @param attribute the attribute to search for
2144     * @param defaultValue the default value to use in case the attribute does not exist.
2145     * 
2146     * @return the value of the attribute. If the attribute is not found or the content is not a
2147     * legal integer, then the default value is returned.
2148     */
2149    /*--------------------------------------------------------------------------*/
2150    private float getFloat(XMLElement element, String attribute, float defaultValue)
2151    {
2152        float result = defaultValue;
2153
2154        if ((attribute != null) && (attribute.length() > 0))
2155        {
2156            try
2157            {
2158                result = Float.parseFloat(element.getAttribute(attribute));
2159            }
2160            catch (Throwable exception)
2161            {}
2162        }
2163
2164        return (result);
2165    }
2166
2167    /*--------------------------------------------------------------------------*/
2168    /**
2169     * Extracts the text from an <code>XMLElement</code>. The text must be defined in the
2170     * resource file under the key defined in the <code>id</code> attribute or as value of the
2171     * attribute <code>text</code>.
2172     * 
2173     * @param element the <code>XMLElement</code> from which to extract the text.
2174     * 
2175     * @return The text defined in the <code>XMLElement</code>. If no text can be located,
2176     * <code>null</code> is returned.
2177     */
2178    /*--------------------------------------------------------------------------*/
2179    private String getText(XMLElement element)
2180    {
2181        if (element == null) { return (null); }
2182
2183        String key = element.getAttribute(KEY);
2184        String text = null;
2185
2186        if ((key != null) && (langpack != null))
2187        {
2188            try
2189            {
2190                text = langpack.getString(key);
2191            }
2192            catch (Throwable exception)
2193            {
2194                text = null;
2195            }
2196        }
2197
2198        // if there is no text in the description, then
2199        // we were unable to retrieve it form the resource.
2200        // In this case try to get the text directly from
2201        // the XMLElement
2202        if (text == null)
2203        {
2204            text = element.getAttribute(TEXT);
2205        }
2206
2207        return (text);
2208    }
2209
2210    /*--------------------------------------------------------------------------*/
2211    /**
2212     * Retreives the alignment setting for the <code>XMLElement</code>. The default value in case
2213     * the <code>ALIGNMENT</code> attribute is not found or the value is illegal is
2214     * <code>TwoColumnConstraints.LEFT</code>.
2215     * 
2216     * @param element the <code>XMLElement</code> from which to extract the alignment setting.
2217     * 
2218     * @return the alignement setting for the <code>XMLElement</code>. The value is either
2219     * <code>TwoColumnConstraints.LEFT</code>, <code>TwoColumnConstraints.CENTER</code> or
2220     * <code>TwoColumnConstraints.RIGHT</code>.
2221     * 
2222     * @see com.izforge.izpack.gui.TwoColumnConstraints
2223     */
2224    /*--------------------------------------------------------------------------*/
2225    private int getAlignment(XMLElement element)
2226    {
2227        int result = TwoColumnConstraints.LEFT;
2228
2229        String value = element.getAttribute(ALIGNMENT);
2230
2231        if (value != null)
2232        {
2233            if (value.equals(LEFT))
2234            {
2235                result = TwoColumnConstraints.LEFT;
2236            }
2237            else if (value.equals(CENTER))
2238            {
2239                result = TwoColumnConstraints.CENTER;
2240            }
2241            else if (value.equals(RIGHT))
2242            {
2243                result = TwoColumnConstraints.RIGHT;
2244            }
2245        }
2246
2247        return (result);
2248    }
2249
2250    /**
2251     * Verifies if an item is required for the operating system the installer executed. The
2252     * configuration for this feature is: <br/> &lt;os family="unix"/&gt; <br>
2253     * <br>
2254     * <b>Note:</b><br>
2255     * If the list of the os is empty then <code>true</code> is always returnd.
2256     * 
2257     * @param os The <code>Vector</code> of <code>String</code>s. containing the os names
2258     * 
2259     * @return <code>true</code> if the item is required for the os, otherwise returns
2260     * <code>false</code>.
2261     */
2262    public boolean itemRequiredForOs(Vector os)
2263    {
2264        if (os.size() == 0) { return true; }
2265
2266        for (int i = 0; i < os.size(); i++)
2267        {
2268            String family = ((XMLElement) os.elementAt(i)).getAttribute(FAMILY);
2269            boolean match = false;
2270
2271            if (family.equals("windows"))
2272            {
2273                match = OsVersion.IS_WINDOWS;
2274            }
2275            else if (family.equals("mac"))
2276            {
2277                match = OsVersion.IS_OSX;
2278            }
2279            else if (family.equals("unix"))
2280            {
2281                match = OsVersion.IS_UNIX;
2282            }
2283            return match;
2284        }
2285        return false;
2286    }
2287
2288    /*--------------------------------------------------------------------------*/
2289    /**
2290     * Verifies if an item is required for any of the packs listed. An item is required for a pack
2291     * in the list if that pack is actually selected for installation. <br>
2292     * <br>
2293     * <b>Note:</b><br>
2294     * If the list of selected packs is empty then <code>true</code> is always returnd. The same
2295     * is true if the <code>packs</code> list is empty.
2296     * 
2297     * @param packs a <code>Vector</code> of <code>String</code>s. Each of the strings denotes
2298     * a pack for which an item should be created if the pack is actually installed.
2299     * 
2300     * @return <code>true</code> if the item is required for at least one pack in the list,
2301     * otherwise returns <code>false</code>.
2302     */
2303    /*--------------------------------------------------------------------------*/
2304    /*
2305     * $ @design
2306     * 
2307     * The information about the installed packs comes from InstallData.selectedPacks. This assumes
2308     * that this panel is presented to the user AFTER the PacksPanel.
2309     * --------------------------------------------------------------------------
2310     */
2311    private boolean itemRequiredFor(Vector packs)
2312    {
2313
2314        String selected;
2315        String required;
2316
2317        if (packs.size() == 0) { return (true); }
2318
2319        // ----------------------------------------------------
2320        // We are getting to this point if any packs have been
2321        // specified. This means that there is a possibility
2322        // that some UI elements will not get added. This
2323        // means that we can not allow to go back to the
2324        // PacksPanel, because the process of building the
2325        // UI is not reversable.
2326        // ----------------------------------------------------
2327        // packsDefined = true;
2328
2329        // ----------------------------------------------------
2330        // analyze if the any of the packs for which the item
2331        // is required have been selected for installation.
2332        // ----------------------------------------------------
2333        for (int i = 0; i < idata.selectedPacks.size(); i++)
2334        {
2335            selected = ((Pack) idata.selectedPacks.get(i)).name;
2336
2337            for (int k = 0; k < packs.size(); k++)
2338            {
2339                required = (String) ((XMLElement) packs.elementAt(k)).getAttribute(NAME, "");
2340                if (selected.equals(required)) { return (true); }
2341            }
2342        }
2343
2344        return (false);
2345    }
2346
2347    /*--------------------------------------------------------------------------*/
2348    /**
2349     * Verifies if an item is required for any of the packs listed. An item is required for a pack
2350     * in the list if that pack is actually NOT selected for installation. <br>
2351     * <br>
2352     * <b>Note:</b><br>
2353     * If the list of selected packs is empty then <code>true</code> is always returnd. The same
2354     * is true if the <code>packs</code> list is empty.
2355     * 
2356     * @param packs a <code>Vector</code> of <code>String</code>s. Each of the strings denotes
2357     * a pack for which an item should be created if the pack is actually installed.
2358     * 
2359     * @return <code>true</code> if the item is required for at least one pack in the list,
2360     * otherwise returns <code>false</code>.
2361     */
2362    /*--------------------------------------------------------------------------*/
2363    /*
2364     * $ @design
2365     * 
2366     * The information about the installed packs comes from InstallData.selectedPacks. This assumes
2367     * that this panel is presented to the user AFTER the PacksPanel.
2368     * --------------------------------------------------------------------------
2369     */
2370    private boolean itemRequiredForUnselected(Vector packs)
2371    {
2372
2373        String selected;
2374        String required;
2375
2376        if (packs.size() == 0) { return (true); }
2377
2378        // ----------------------------------------------------
2379        // analyze if the any of the packs for which the item
2380        // is required have been selected for installation.
2381        // ----------------------------------------------------
2382        for (int i = 0; i < idata.selectedPacks.size(); i++)
2383        {
2384            selected = ((Pack) idata.selectedPacks.get(i)).name;
2385
2386            for (int k = 0; k < packs.size(); k++)
2387            {
2388                required = (String) ((XMLElement) packs.elementAt(k)).getAttribute(NAME, "");
2389                if (selected.equals(required)) { return (false); }
2390            }
2391        }
2392
2393        return (true);
2394    }
2395
2396    // ----------- Inheritance stuff -----------------------------------------
2397    /**
2398     * Returns the uiElements.
2399     * 
2400     * @return Returns the uiElements.
2401     */
2402    protected Vector getUiElements()
2403    {
2404        return uiElements;
2405    }
2406
2407    // --------------------------------------------------------------------------
2408    // Inner Classes
2409    // --------------------------------------------------------------------------
2410
2411    /*---------------------------------------------------------------------------*/
2412    /**
2413     * This class can be used to associate a text string and a (text) value.
2414     */
2415    /*---------------------------------------------------------------------------*/
2416    private static class TextValuePair
2417    {
2418
2419        private String text = "";
2420
2421        private String value = "";
2422
2423        /*--------------------------------------------------------------------------*/
2424        /**
2425         * Constructs a new Text/Value pair, initialized with the text and a value.
2426         * 
2427         * @param text the text that this object should represent
2428         * @param value the value that should be associated with this object
2429         */
2430        /*--------------------------------------------------------------------------*/
2431        public TextValuePair(String text, String value)
2432        {
2433            this.text = text;
2434            this.value = value;
2435        }
2436
2437        /*--------------------------------------------------------------------------*/
2438        /**
2439         * Sets the text
2440         * 
2441         * @param text the text for this object
2442         */
2443        /*--------------------------------------------------------------------------*/
2444        public void setText(String text)
2445        {
2446            this.text = text;
2447        }
2448
2449        /*--------------------------------------------------------------------------*/
2450        /**
2451         * Sets the value of this object
2452         * 
2453         * @param value the value for this object
2454         */
2455        /*--------------------------------------------------------------------------*/
2456        public void setValue(String value)
2457        {
2458            this.value = value;
2459        }
2460
2461        /*--------------------------------------------------------------------------*/
2462        /**
2463         * This method returns the text that was set for the object
2464         * 
2465         * @return the object's text
2466         */
2467        /*--------------------------------------------------------------------------*/
2468        public String toString()
2469        {
2470            return (text);
2471        }
2472
2473        /*--------------------------------------------------------------------------*/
2474        /**
2475         * This method returns the value that was associated with this object
2476         * 
2477         * @return the object's value
2478         */
2479        /*--------------------------------------------------------------------------*/
2480        public String getValue()
2481        {
2482            return (value);
2483        }
2484    }
2485
2486    /*---------------------------------------------------------------------------*/
2487    /**
2488     * This class encapsulates a lot of search field functionality.
2489     * 
2490     * A search field supports searching directories and files on the target system. This is a
2491     * helper class to manage all data belonging to a search field.
2492     */
2493    /*---------------------------------------------------------------------------*/
2494
2495    private class SearchField implements ActionListener
2496    {
2497
2498        /** used in constructor - we search for a directory. */
2499        public static final int TYPE_DIRECTORY = 1;
2500
2501        /** used in constructor - we search for a file. */
2502        public static final int TYPE_FILE = 2;
2503
2504        /** used in constructor - result of search is the directory. */
2505        public static final int RESULT_DIRECTORY = 1;
2506
2507        /** used in constructor - result of search is the whole file name. */
2508        public static final int RESULT_FILE = 2;
2509
2510        /** used in constructor - result of search is the parent directory. */
2511        public static final int RESULT_PARENTDIR = 3;
2512
2513        private String filename = null;
2514
2515        private String checkFilename = null;
2516
2517        private JButton autodetectButton = null;
2518
2519        private JButton browseButton = null;
2520
2521        private JComboBox pathComboBox = null;
2522
2523        private int searchType = TYPE_DIRECTORY;
2524
2525        private int resultType = RESULT_DIRECTORY;
2526
2527        private InstallerFrame parent = null;
2528
2529        /*---------------------------------------------------------------------------*/
2530        /**
2531         * Constructor - initializes the object, adds it as action listener to the "autodetect"
2532         * button.
2533         * 
2534         * @param filename the name of the file to search for (might be null for searching
2535         * directories)
2536         * @param checkFilename the name of the file to check when searching for directories (the
2537         * checkFilename is appended to a found directory to figure out whether it is the right
2538         * directory)
2539         * @param combobox the <code>JComboBox</code> holding the list of choices; it should be
2540         * editable and contain only Strings
2541         * @param autobutton the autodetection button for triggering autodetection
2542         * @param browsebutton the browse button to look for the file
2543         * @param search_type what to search for - TYPE_FILE or TYPE_DIRECTORY
2544         * @param result_type what to return as the result - RESULT_FILE or RESULT_DIRECTORY or
2545         * RESULT_PARENTDIR
2546         */
2547        /*---------------------------------------------------------------------------*/
2548        public SearchField(String filename, String checkFilename, InstallerFrame parent,
2549                JComboBox combobox, JButton autobutton, JButton browsebutton, int search_type,
2550                int result_type)
2551        {
2552            this.filename = filename;
2553            this.checkFilename = checkFilename;
2554            this.parent = parent;
2555            this.autodetectButton = autobutton;
2556            this.browseButton = browsebutton;
2557            this.pathComboBox = combobox;
2558            this.searchType = search_type;
2559            this.resultType = result_type;
2560
2561            this.autodetectButton.addActionListener(this);
2562            this.browseButton.addActionListener(this);
2563
2564            autodetect();
2565        }
2566
2567        /**
2568         * Check whether the given combobox belongs to this searchfield. This is used when reading
2569         * the results.
2570         */
2571        public boolean belongsTo(JComboBox combobox)
2572        {
2573            return (this.pathComboBox == combobox);
2574        }
2575
2576        /** check whether the given path matches */
2577        private boolean pathMatches(String path)
2578        {
2579            if (path != null)
2580            { // Make sure, path is not null
2581                // System.out.println ("checking path " + path);
2582
2583                File file = null;
2584
2585                if ((this.filename == null) || (this.searchType == TYPE_DIRECTORY))
2586                {
2587                    file = new File(path);
2588                }
2589                else
2590                {
2591                    file = new File(path, this.filename);
2592                }
2593
2594                if (file.exists())
2595                {
2596
2597                    if (((this.searchType == TYPE_DIRECTORY) && (file.isDirectory()))
2598                            || ((this.searchType == TYPE_FILE) && (file.isFile())))
2599                    {
2600                        // no file to check for
2601                        if (this.checkFilename == null) return true;
2602
2603                        file = new File(file, this.checkFilename);
2604
2605                        return file.exists();
2606                    }
2607
2608                }
2609
2610                // System.out.println (path + " did not match");
2611            } // end if
2612            return false;
2613        }
2614
2615        /** perform autodetection */
2616        public boolean autodetect()
2617        {
2618            Vector items = new Vector();
2619
2620            /*
2621             * Check if the user has entered data into the ComboBox and add it to the Itemlist
2622             */
2623            String selected = (String) this.pathComboBox.getSelectedItem();
2624            boolean found = false;
2625            for (int x = 0; x < this.pathComboBox.getItemCount(); x++)
2626            {
2627                if (((String) this.pathComboBox.getItemAt(x)).equals(selected))
2628                {
2629                    found = true;
2630                }
2631            }
2632            if (!found)
2633            {
2634                // System.out.println("Not found in Itemlist");
2635                this.pathComboBox.addItem(this.pathComboBox.getSelectedItem());
2636            }
2637
2638            // Checks whether a placeholder item is in the combobox
2639            // and resolve the pathes automatically:
2640            // /usr/lib/* searches all folders in usr/lib to find
2641            // /usr/lib/*/lib/tools.jar
2642            for (int i = 0; i < this.pathComboBox.getItemCount(); ++i)
2643            {
2644                String path = (String) this.pathComboBox.getItemAt(i);
2645
2646                if (path.endsWith("*"))
2647                {
2648                    path = path.substring(0, path.length() - 1);
2649                    File dir = new File(path);
2650
2651                    if (dir.isDirectory())
2652                    {
2653                        File[] subdirs = dir.listFiles();
2654                        for (int x = 0; x < subdirs.length; x++)
2655                        {
2656                            String search = subdirs[x].getAbsolutePath();
2657                            if (this.pathMatches(search))
2658                            {
2659                                items.add(search);
2660                            }
2661                        }
2662                    }
2663                }
2664                else
2665                {
2666                    if (this.pathMatches(path))
2667                    {
2668                        items.add(path);
2669                    }
2670                }
2671            }
2672            // Make the enties in the vector unique
2673            items = new Vector(new HashSet(items));
2674
2675            // Now clear the combobox and add the items out of the newly
2676            // generated vector
2677            this.pathComboBox.removeAllItems();
2678            VariableSubstitutor vs = new VariableSubstitutor(idata.getVariables());
2679            for (int i = 0; i < items.size(); i++)
2680            {
2681                this.pathComboBox.addItem(vs.substitute((String) items.get(i), "plain"));
2682            }
2683
2684            // loop through all items
2685            for (int i = 0; i < this.pathComboBox.getItemCount(); ++i)
2686            {
2687                String path = (String) this.pathComboBox.getItemAt(i);
2688
2689                if (this.pathMatches(path))
2690                {
2691                    this.pathComboBox.setSelectedIndex(i);
2692                    return true;
2693                }
2694
2695            }
2696
2697            // if the user entered something else, it's not listed as an item
2698            if (this.pathMatches((String) this.pathComboBox.getSelectedItem())) { return true; }
2699
2700            return false;
2701        }
2702
2703        /*--------------------------------------------------------------------------*/
2704        /**
2705         * This is called if one of the buttons has bee pressed.
2706         * 
2707         * It checks, which button caused the action and acts accordingly.
2708         */
2709        /*--------------------------------------------------------------------------*/
2710        public void actionPerformed(ActionEvent event)
2711        {
2712            // System.out.println ("autodetection button pressed.");
2713
2714            if (event.getSource() == this.autodetectButton)
2715            {
2716                if (!autodetect())
2717                    JOptionPane.showMessageDialog(parent, parent.langpack
2718                            .getString("UserInputPanel.search.autodetect.failed.message"),
2719                            parent.langpack
2720                                    .getString("UserInputPanel.search.autodetect.failed.caption"),
2721                            JOptionPane.WARNING_MESSAGE);
2722            }
2723            else if (event.getSource() == this.browseButton)
2724            {
2725                JFileChooser chooser = new JFileChooser();
2726
2727                if (this.searchType == RESULT_DIRECTORY)
2728                    chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2729
2730                int result = chooser.showOpenDialog(this.parent);
2731
2732                if (result == JFileChooser.APPROVE_OPTION)
2733                {
2734                    File f = chooser.getSelectedFile();
2735
2736                    this.pathComboBox.setSelectedItem(f.getAbsolutePath());
2737
2738                    // use any given directory directly
2739                    if (!this.pathMatches(f.getAbsolutePath()))
2740                    {
2741                        JOptionPane.showMessageDialog(parent, parent.langpack
2742                                .getString("UserInputPanel.search.wrongselection.message"),
2743                                parent.langpack
2744                                        .getString("UserInputPanel.search.wrongselection.caption"),
2745                                JOptionPane.WARNING_MESSAGE);
2746                    }
2747                }
2748
2749            }
2750
2751            // we don't care for anything more here - getResult() does the rest
2752        }
2753
2754        /*--------------------------------------------------------------------------*/
2755        /**
2756         * Return the result of the search according to result type.
2757         * 
2758         * Sometimes, the whole path of the file is wanted, sometimes only the directory where the
2759         * file is in, sometimes the parent directory.
2760         * 
2761         * @return null on error
2762         */
2763        /*--------------------------------------------------------------------------*/
2764        public String getResult()
2765        {
2766            String item = (String) this.pathComboBox.getSelectedItem();
2767            if (item != null) item = item.trim();
2768            String path = item;
2769
2770            File f = new File(item);
2771
2772            if (!f.isDirectory())
2773            {
2774                path = f.getParent();
2775            }
2776
2777            // path now contains the final content of the combo box
2778            if (this.resultType == RESULT_DIRECTORY)
2779            {
2780                return path;
2781            }
2782            else if (this.resultType == RESULT_FILE)
2783            {
2784                if (this.filename != null)
2785                {
2786                    return path + File.separatorChar + this.filename;
2787                }
2788                else
2789                {
2790                    return item;
2791                }
2792            }
2793            else if (this.resultType == RESULT_PARENTDIR)
2794            {
2795                File dir = new File(path);
2796                return dir.getParent();
2797            }
2798
2799            return null;
2800        }
2801
2802    } // private class SearchFile
2803
2804} // public class UserInputPanel
2805/*---------------------------------------------------------------------------*/
2806