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"); you may not use this file except
010 * in compliance with the License. You may obtain a copy of the License at
011 * 
012 * http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing, software distributed under the License
015 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
016 * or implied. See the License for the specific language governing permissions and limitations under
017 * the License.
018 */
019
020package com.izforge.izpack.panels;
021
022import java.awt.Dimension;
023import java.awt.GridBagConstraints;
024import java.awt.GridBagLayout;
025import java.awt.GridLayout;
026import java.awt.Insets;
027import java.awt.event.ActionEvent;
028import java.awt.event.ActionListener;
029import java.io.File;
030import java.io.FileWriter;
031import java.io.InputStream;
032import java.util.ArrayList;
033import java.util.Iterator;
034import java.util.Vector;
035
036import javax.swing.ButtonGroup;
037import javax.swing.JButton;
038import javax.swing.JCheckBox;
039import javax.swing.JFileChooser;
040import javax.swing.JLabel;
041import javax.swing.JList;
042import javax.swing.JPanel;
043import javax.swing.JRadioButton;
044import javax.swing.JScrollPane;
045import javax.swing.JTextField;
046import javax.swing.ListSelectionModel;
047import javax.swing.border.Border;
048import javax.swing.border.EmptyBorder;
049import javax.swing.border.TitledBorder;
050import javax.swing.event.ListSelectionEvent;
051import javax.swing.event.ListSelectionListener;
052
053import net.n3.nanoxml.NonValidator;
054import net.n3.nanoxml.StdXMLBuilder;
055import net.n3.nanoxml.StdXMLParser;
056import net.n3.nanoxml.StdXMLReader;
057import net.n3.nanoxml.XMLElement;
058
059import com.izforge.izpack.ExecutableFile;
060import com.izforge.izpack.Pack;
061import com.izforge.izpack.gui.ButtonFactory;
062import com.izforge.izpack.gui.LabelFactory;
063import com.izforge.izpack.installer.InstallData;
064import com.izforge.izpack.installer.InstallerFrame;
065import com.izforge.izpack.installer.IzPanel;
066import com.izforge.izpack.installer.ResourceNotFoundException;
067import com.izforge.izpack.installer.UninstallData;
068import com.izforge.izpack.util.FileExecutor;
069import com.izforge.izpack.util.MultiLineLabel;
070import com.izforge.izpack.util.OsConstraint;
071import com.izforge.izpack.util.OsVersion;
072import com.izforge.izpack.util.StringTool;
073import com.izforge.izpack.util.TargetFactory;
074import com.izforge.izpack.util.UnixHelper;
075import com.izforge.izpack.util.VariableSubstitutor;
076import com.izforge.izpack.util.os.Shortcut;
077
078//
079//import com.izforge.izpack.panels.ShortcutData;
080
081/*---------------------------------------------------------------------------*/
082
083/**
084 * This class implements a panel for the creation of shortcuts. The panel prompts the user to select
085 * a program group for shortcuts, accept the creation of desktop shortcuts and actually creates the
086 * shortcuts.
087 * 
088 * <h4>Important</h4>
089 * It is neccesary that the installation has been completed before this panel is called. To
090 * successfully create shortcuts this panel needs to have the following in place: <br>
091 * <br>
092 * 
093 * <ul>
094 * <li>the launcher files that the shortcuts point to must exist</li>
095 * <li>it must be known which packs are installed</li>
096 * <li>where the launcher for the uninstaller is located</li>
097 * </ul>
098 * 
099 * It is ok to present other panels after this one, as long as these conditions are met.
100 * 
101 * @author Elmar Grom
102 * @version 0.0.1 / 2/26/02
103 * 
104 * @see com.izforge.izpack.util.os.ShellLink
105 * 
106 * @version 0.0.1 / 2/26/02
107 * @author Elmar Grom
108 */
109
110/*---------------------------------------------------------------------------*/
111
112// !!! To Do !
113//
114// - see if I can't get multiple instances of the shortcut to work
115// - need a clean way to get pack name
116public class ShortcutPanel extends IzPanel implements ActionListener, ListSelectionListener
117{
118    /**          
119     *   
120     */          
121    private static final long serialVersionUID = 3256722870838112311L;
122    
123    /** a VectorList of Files wich should be make executable */
124    private Vector execFiles = new Vector();
125
126    /** SPEC_ATTRIBUTE_KDE_SUBST_UID = "KdeSubstUID" */
127    private final static String SPEC_ATTRIBUTE_KDE_SUBST_UID = "KdeSubstUID";
128
129    /** SPEC_ATTRIBUTE_URL = "url" */
130    private final static String SPEC_ATTRIBUTE_URL = "url";
131
132    /** SPEC_ATTRIBUTE_TYPE = "type" */
133    private final static String SPEC_ATTRIBUTE_TYPE = "type";
134
135    /** SPEC_ATTRIBUTE_TERMINAL_OPTIONS = "terminalOptions" */
136    private final static String SPEC_ATTRIBUTE_TERMINAL_OPTIONS = "terminalOptions";
137
138    /** SPEC_ATTRIBUTE_TERMINAL = "terminal" */
139    private final static String SPEC_ATTRIBUTE_TERMINAL = "terminal";
140
141    /** SPEC_ATTRIBUTE_MIMETYPE = "mimetype" */
142    private final static String SPEC_ATTRIBUTE_MIMETYPE = "mimetype";
143
144    /** SPEC_ATTRIBUTE_ENCODING = "encoding" */
145    private final static String SPEC_ATTRIBUTE_ENCODING = "encoding";
146
147    /** LOCATION_APPLICATIONS=applications */
148    private static final String LOCATION_APPLICATIONS = "applications";
149
150    /** LOCATION_START_MENU = "startMenu" */
151    private static final String LOCATION_START_MENU = "startMenu";
152
153    /**
154     * SEPARATOR_LINE =
155     * "--------------------------------------------------------------------------------";
156     */
157    private static final String SEPARATOR_LINE = "--------------------------------------------------------------------------------";
158
159    /**
160     * The default file name for the text file in which the shortcut information should be stored,
161     * in case shortcuts can not be created on a particular target system. TEXT_FILE_NAME =
162     * "Shortcuts.txt"
163     */
164    private static final String TEXT_FILE_NAME = "Shortcuts.txt";
165
166    /** The name of the XML file that specifies the shortcuts SPEC_FILE_NAME = "shortcutSpec.xml"; */
167    private static final String SPEC_FILE_NAME = "shortcutSpec.xml";
168
169    // ------------------------------------------------------
170    // spec file section keys
171    // ------------------------------------------------------
172    private static final String SPEC_KEY_SKIP_IFNOT_SUPPORTED = "skipIfNotSupported";
173
174    /** SPEC_KEY_NOT_SUPPORTED = "notSupported" */
175    private static final String SPEC_KEY_NOT_SUPPORTED = "notSupported";
176
177    /** SPEC_KEY_PROGRAM_GROUP = "programGroup" */
178    private static final String SPEC_KEY_PROGRAM_GROUP = "programGroup";
179
180    /** SPEC_KEY_SHORTCUT = "shortcut" */
181    private static final String SPEC_KEY_SHORTCUT = "shortcut";
182
183    /** SPEC_KEY_PACKS = "createForPack" */
184    private static final String SPEC_KEY_PACKS = "createForPack";
185
186    // ------------------------------------------------------
187    // spec file key attributes
188    // ------------------------------------------------------
189
190    /** SPEC_ATTRIBUTE_DEFAULT_GROUP = "defaultName" */
191    private static final String SPEC_ATTRIBUTE_DEFAULT_GROUP = "defaultName";
192
193    /** SPEC_ATTRIBUTE_LOCATION = "location" */
194    private static final String SPEC_ATTRIBUTE_LOCATION = "location";
195
196    /** SPEC_ATTRIBUTE_NAME = "name" */
197    private static final String SPEC_ATTRIBUTE_NAME = "name";
198
199    /** SPEC_ATTRIBUTE_SUBGROUP = "subgroup" */
200    private static final String SPEC_ATTRIBUTE_SUBGROUP = "subgroup";
201
202    /** SPEC_ATTRIBUTE_DESCRIPTION = "description" */
203    private static final String SPEC_ATTRIBUTE_DESCRIPTION = "description";
204
205    /** SPEC_ATTRIBUTE_TARGET = "target" */
206    private static final String SPEC_ATTRIBUTE_TARGET = "target";
207
208    /** SPEC_ATTRIBUTE_COMMAND = "commandLine" */
209    private static final String SPEC_ATTRIBUTE_COMMAND = "commandLine";
210
211    /** SPEC_ATTRIBUTE_ICON "iconFile" */
212    private static final String SPEC_ATTRIBUTE_ICON = "iconFile";
213
214    /** SPEC_ATTRIBUTE_ICON_INDEX "iconIndex" */
215    private static final String SPEC_ATTRIBUTE_ICON_INDEX = "iconIndex";
216
217    /** SPEC_ATTRIBUTE_WORKING_DIR = "workingDirectory" */
218    private static final String SPEC_ATTRIBUTE_WORKING_DIR = "workingDirectory";
219
220    /** SPEC_ATTRIBUTE_INITIAL_STATE = "initialState" */
221    private static final String SPEC_ATTRIBUTE_INITIAL_STATE = "initialState";
222
223    /** SPEC_ATTRIBUTE_DESKTOP = "desktop" */
224    private static final String SPEC_ATTRIBUTE_DESKTOP = "desktop";
225
226    /** SPEC_ATTRIBUTE_APPLICATIONS = "applications" */
227    private static final String SPEC_ATTRIBUTE_APPLICATIONS = "applications";
228
229    /** SPEC_ATTRIBUTE_START_MENU = "startMenu" */
230    private static final String SPEC_ATTRIBUTE_START_MENU = "startMenu";
231
232    /** SPEC_ATTRIBUTE_STARTUP = "startup" */
233    private static final String SPEC_ATTRIBUTE_STARTUP = "startup";
234
235    /** SPEC_ATTRIBUTE_PROGRAM_GROUP = "programGroup" */
236    private static final String SPEC_ATTRIBUTE_PROGRAM_GROUP = "programGroup";
237
238    // ------------------------------------------------------
239    // spec file attribute values
240    // ------------------------------------------------------
241
242    /** SPEC_VALUE_APPLICATIONS = "applications" */
243    private static final String SPEC_VALUE_APPLICATIONS = "applications";
244
245    /** SPEC_VALUE_START_MENU = "startMenu" */
246    private static final String SPEC_VALUE_START_MENU = "startMenu";
247
248    /** SPEC_VALUE_NO_SHOW = "noShow" */
249    private static final String SPEC_VALUE_NO_SHOW = "noShow";
250
251    /** SPEC_VALUE_NORMAL = "normal" */
252    private static final String SPEC_VALUE_NORMAL = "normal";
253
254    /** SPEC_VALUE_MAXIMIZED = "maximized" */
255    private static final String SPEC_VALUE_MAXIMIZED = "maximized";
256
257    /** SPEC_VALUE_MINIMIZED = "minimized" */
258    private static final String SPEC_VALUE_MINIMIZED = "minimized";
259
260    // ------------------------------------------------------
261    // automatic script section keys
262    // ------------------------------------------------------
263
264    /**   */
265
266    /** AUTO_KEY_PROGRAM_GROUP = "programGroup" */
267    private static final String AUTO_KEY_PROGRAM_GROUP = "programGroup";
268
269    /** AUTO_KEY_SHORTCUT = "shortcut" */
270    private static final String AUTO_KEY_SHORTCUT = "shortcut";
271
272    // ------------------------------------------------------
273    // automatic script keys attributes
274    // ------------------------------------------------------
275
276    /** AUTO_ATTRIBUTE_NAME = "name" */
277    private static final String AUTO_ATTRIBUTE_NAME = "name";
278
279    /** AUTO_ATTRIBUTE_GROUP = "group" */
280    private static final String AUTO_ATTRIBUTE_GROUP = "group";
281
282    /** AUTO_ATTRIBUTE_TYPE "type" */
283    private static final String AUTO_ATTRIBUTE_TYPE = "type";
284
285    /** AUTO_ATTRIBUTE_COMMAND = "commandLine" */
286    private static final String AUTO_ATTRIBUTE_COMMAND = "commandLine";
287
288    /** AUTO_ATTRIBUTE_DESCRIPTION = "description" */
289    private static final String AUTO_ATTRIBUTE_DESCRIPTION = "description";
290
291    /** AUTO_ATTRIBUTE_ICON = "icon" */
292    private static final String AUTO_ATTRIBUTE_ICON = "icon";
293
294    /** AUTO_ATTRIBUTE_ICON_INDEX = "iconIndex" */
295    private static final String AUTO_ATTRIBUTE_ICON_INDEX = "iconIndex";
296
297    /** AUTO_ATTRIBUTE_INITIAL_STATE = "initialState" */
298    private static final String AUTO_ATTRIBUTE_INITIAL_STATE = "initialState";
299
300    /** AUTO_ATTRIBUTE_TARGET = "target" */
301    private static final String AUTO_ATTRIBUTE_TARGET = "target";
302
303    /** AUTO_ATTRIBUTE_WORKING_DIR = "workingDirectory" */
304    private static final String AUTO_ATTRIBUTE_WORKING_DIR = "workingDirectory";
305
306    // permission flags
307    private static final String CREATE_FOR_ALL = "createForAll";
308
309    // ------------------------------------------------------------------------
310    // Variable Declarations
311    // ------------------------------------------------------------------------
312
313    /** UI element to label the list of existing program groups */
314    private JLabel listLabel;
315
316    /** UI element to present the list of existing program groups for selection */
317    private JList groupList;
318
319    /** UI element for listing the intended shortcut targets */
320    private JList targetList;
321
322    /**
323     * UI element to present the default name for the program group and to support editing of this
324     * name.
325     */
326    private JTextField programGroup;
327
328    /**
329     * UI element to allow the user to revert to the default name of the program group
330     */
331    private JButton defaultButton;
332
333    /**
334     * UI element to allow the user to save a text file with the shortcut information
335     */
336    private JButton saveButton;
337
338    /**
339     * UI element to allow the user to decide if shortcuts should be placed on the desktop or not.
340     */
341    private JCheckBox allowDesktopShortcut;
342
343    private JCheckBox createShortcuts;
344
345    /**
346     * UI element instruct this panel to create shortcuts for the current user only
347     */
348    private JRadioButton currentUser;
349
350    /** UI element instruct this panel to create shortcuts for all users */
351    private JRadioButton allUsers;
352
353    /** The layout for this panel */
354    private GridBagLayout layout;
355
356    /** The contraints object to use whan creating the layout */
357    private GridBagConstraints constraints;
358
359    /**
360     * The default name to use for the program group. This comes from the XML specification.
361     */
362    private String suggestedProgramGroup;
363
364    /** The name chosen by the user for the program group, */
365    private String groupName;
366
367    /**
368     * The location for placign the program group. This is the same as the location (type) of a
369     * shortcut, only that it applies to the program group. Note that there are only two locations
370     * that make sense as location for a program group: <br>
371     * 
372     * <ul>
373     * <li>applications</li>
374     * <li>start manu</li>
375     * </ul>
376     *  
377     */
378    private int groupLocation;
379
380    /** The parsed result from reading the XML specification from the file */
381    private XMLElement spec;
382
383    /**
384     * Set to <code>true</code> by <code>analyzeShortcutSpec()</code> if there are any desktop
385     * shortcuts to create.
386     */
387    private boolean hasDesktopShortcuts = false;
388
389    /** Tells wether to skip if the platform is not supported. */
390    private boolean skipIfNotSupported = false;
391
392    /** the one shortcut instance for reuse in many locations */
393    private Shortcut shortcut;
394
395    /**
396     * A list of <code>ShortcutData</code> objects. Each object is the complete specification for
397     * one shortcut that must be created.
398     */
399    private Vector shortcuts = new Vector();
400
401    /**
402     * Holds a list of all the shortcut files that have been created. <b>Note: </b> this variable
403     * contains valid data only after <code>createShortcuts()</code> has been called. This list is
404     * created so that the files can be added to the uninstaller.
405     */
406    private Vector files = new Vector();
407
408    /**
409     * If <code>true</code> it indicates that there are shortcuts to create. The value is set by
410     * <code>analyzeShortcutSpec()</code>
411     */
412    private boolean shortcutsToCreate = false;
413
414    /**
415     * If <code>true</code> it indicates that the spec file is existing and could be read.
416     */
417    private boolean haveShortcutSpec = false;
418
419    /**
420     * This is set to true if the shortcut spec instructs to simulate running on an operating system
421     * that is not supported.
422     */
423    private boolean simulteNotSupported = false;
424
425    /**
426     * Avoids bogus behaviour when the user goes back then returns to this panel.
427     */
428    private boolean firstTime = true;
429
430    private File itsProgramFolder;
431
432    private int itsUserType;
433
434    static boolean create;
435    
436    private static boolean isRootUser;
437
438    /*
439     * --------------------------------------------------------------------------
440     */
441    /**
442     * Constructor.
443     * 
444     * @param parent reference to the application frame
445     * @param installData shared information about the installation
446     */
447    /*
448     * --------------------------------------------------------------------------
449     */
450    public ShortcutPanel(InstallerFrame parent, InstallData installData)
451    {
452        super(parent, installData, "link16x16");
453        
454        try
455        {
456            readShortcutSpec();
457        }
458        catch (Throwable exception)
459        {
460            System.out.println("could not read shortcut spec!");
461            exception.printStackTrace();
462        }
463
464        layout = new GridBagLayout();
465        constraints = new GridBagConstraints();
466        setLayout(layout);
467
468        // Create the UI elements
469        try
470        {
471            shortcut = (Shortcut) (TargetFactory.getInstance()
472                    .makeObject("com.izforge.izpack.util.os.Shortcut"));
473            shortcut.initialize(Shortcut.APPLICATIONS, "-");
474        }
475        catch (Throwable exception)
476        {
477            System.out.println("could not create shortcut instance");
478            exception.printStackTrace();
479        }
480    }
481
482    //~ Methods
483    // **************************************************************************************************************************************************
484
485    /*--------------------------------------------------------------------------*/
486    /**
487     * This method represents the <code>ActionListener</code> interface, invoked when an action
488     * occurs.
489     * 
490     * @param event the action event.
491     */
492    /*--------------------------------------------------------------------------*/
493    public void actionPerformed(ActionEvent event)
494    {
495        Object eventSource = event.getSource();
496
497        // ----------------------------------------------------
498        // create shortcut for the current user was selected
499        // refresh the list of program groups accordingly and
500        // reset the program group to the default setting.
501        // ----------------------------------------------------
502        if (eventSource.equals(currentUser))
503        {
504            groupList.setListData(shortcut.getProgramGroups(Shortcut.CURRENT_USER));
505            programGroup.setText(suggestedProgramGroup);
506            shortcut.setUserType(itsUserType = Shortcut.CURRENT_USER);
507        }
508        // ----------------------------------------------------
509        // create shortcut for all users was selected
510        // refresh the list of program groups accordingly and
511        // reset the program group to the default setting.
512        // ----------------------------------------------------
513        else if (eventSource.equals(allUsers))
514        {
515            groupList.setListData(shortcut.getProgramGroups(Shortcut.ALL_USERS));
516            programGroup.setText(suggestedProgramGroup);
517            shortcut.setUserType(itsUserType = Shortcut.ALL_USERS);
518        }
519        // ----------------------------------------------------
520        // The reset button was pressed.
521        // - clear the selection in the list box, because the
522        //   selection is no longer valid
523        // - refill the program group edit control with the
524        //   suggested program group name
525        // ----------------------------------------------------
526        else if (eventSource.equals(defaultButton))
527        {
528            groupList.getSelectionModel().clearSelection();
529            programGroup.setText(suggestedProgramGroup);
530        }
531        // ----------------------------------------------------
532        // the save button was pressed. This is a request to
533        // save shortcut information to a text file.
534        // ----------------------------------------------------
535        else if (eventSource.equals(saveButton))
536        {
537            saveToFile();
538
539            // add the file to the uninstaller
540            addToUninstaller();
541        }
542        else if (eventSource.equals(createShortcuts))
543        {
544            create = createShortcuts.isSelected();
545
546            groupList.setEnabled(create);
547            programGroup.setEnabled(create);
548            currentUser.setEnabled(create);            
549            defaultButton.setEnabled(create);
550            allowDesktopShortcut.setEnabled(create);
551            if( isRootUser )
552                allUsers.setEnabled(create);
553        }
554    }
555
556    /*--------------------------------------------------------------------------*/
557    /**
558     * Returns <code>true</code> when all selections have valid settings. This indicates that it
559     * is legal to procede to the next panel.
560     * 
561     * @return <code>true</code> if it is legal to procede to the next panel, otherwise
562     * <code>false</code>.
563     */
564    /*--------------------------------------------------------------------------*/
565    public boolean isValidated()
566    {
567        try
568        {
569            groupName = programGroup.getText();
570        }
571        catch (Throwable exception)
572        {
573            groupName = "";
574        }
575        create = createShortcuts.isSelected();
576
577        createShortcuts();
578
579        // add files and directories to the uninstaller
580        addToUninstaller();
581
582        return (true);
583    }
584
585    /*--------------------------------------------------------------------------*/
586    /**
587     * Called when the panel is shown to the user.
588     */
589    /*--------------------------------------------------------------------------*/
590    public void panelActivate()
591    {
592        if (firstTime)
593            firstTime = false;
594        else
595            return;
596
597        analyzeShortcutSpec();
598
599        if (shortcutsToCreate && !OsVersion.IS_OSX)
600        {
601            if (shortcut.supported() && !simulteNotSupported)
602            {
603                File allUsersProgramsFolder = getProgramsFolder(Shortcut.ALL_USERS);
604
605                isRootUser = allUsersProgramsFolder.canWrite();
606
607                if (isRootUser)
608                    itsUserType = Shortcut.ALL_USERS;
609                else
610                    itsUserType = Shortcut.CURRENT_USER;
611
612                buildUI( getProgramsFolder(isRootUser ? Shortcut.ALL_USERS : Shortcut.CURRENT_USER) );
613            }
614            else
615            {
616                if (skipIfNotSupported)
617                {
618                    parent.skipPanel();
619                }
620                else
621                {
622                    buildAlternateUI();
623                    parent.unlockNextButton();
624                    parent.lockPrevButton();
625                }
626            }
627        }
628        else
629        {
630          parent.skipPanel ();
631        }
632    }
633
634    /**
635     * Returns the ProgramsFolder for the current User
636     * 
637     * @return The Basedir
638     */
639    private File getProgramsFolder(int userType)
640    {
641        String path = shortcut.getProgramsFolder(userType);
642        return (new File(path));
643        //}
644        //else
645        //{
646        // TODO
647        // 0pt. Test if KDE is installed.
648        //boolean isKdeInstalled = UnixHelper.kdeIsInstalled();
649        // 1. Test if User can write into
650        // File kdeRootShareApplinkDir = getKDERootShareApplinkDir();
651        //   if so: return getKDERootShareApplinkDir()
652        //   else
653        //   return getKDEUsersShareApplinkDir() +
654        //}
655        //return(result);
656    }
657
658    /**
659     * This method is called by the <code>groupList</code> when the user makes a selection. It
660     * updates the content of the <code>programGroup</code> with the result of the selection.
661     * 
662     * @param event the list selection event
663     */
664
665    /*--------------------------------------------------------------------------*/
666    public void valueChanged(ListSelectionEvent event)
667    {
668        if (programGroup == null) { return; }
669
670        String value = "";
671
672        try
673        {
674            value = (String) groupList.getSelectedValue();
675        }
676        catch (ClassCastException exception)
677        {}
678
679        if (value == null)
680        {
681            value = "";
682        }
683
684        programGroup.setText(value + File.separator + suggestedProgramGroup);
685    }
686
687    /*--------------------------------------------------------------------------*/
688
689    /**
690     * Reads the XML specification for the shortcuts to create. The result is stored in spec.
691     * 
692     * @exception Exception for any problems in reading the specification
693     */
694
695    /*--------------------------------------------------------------------------*/
696    private void readShortcutSpec() throws Exception
697    {
698        // open an input stream
699        InputStream input = null;
700
701        try
702        {
703            input = parent.getResource(TargetFactory.getCurrentOSPrefix() + SPEC_FILE_NAME);
704        }
705        catch (ResourceNotFoundException rnfE)
706        {
707            input = parent.getResource(SPEC_FILE_NAME);
708
709            if (input == null)
710            {
711                haveShortcutSpec = false;
712
713                return;
714            }
715        }
716
717        //    if( input == null )
718        //    {
719        //      haveShortcutSpec = false;
720        //      return;
721        //    }
722        // initialize the parser
723        StdXMLParser parser = new StdXMLParser();
724        parser.setBuilder(new StdXMLBuilder());
725        parser.setValidator(new NonValidator());
726        parser.setReader(new StdXMLReader(input));
727
728        // get the data
729        spec = (XMLElement) parser.parse();
730
731        // close the stream
732        input.close();
733        haveShortcutSpec = true;
734    }
735
736    /*--------------------------------------------------------------------------*/
737
738    /**
739     * This method analyzes the specifications for creating shortcuts and builds a list of all the
740     * Shortcuts that need to be created.
741     */
742
743    /*--------------------------------------------------------------------------*/
744    private void analyzeShortcutSpec()
745    {
746        if (!haveShortcutSpec)
747        {
748            shortcutsToCreate = false;
749
750            return;
751        }
752
753        XMLElement skipper = spec.getFirstChildNamed(SPEC_KEY_SKIP_IFNOT_SUPPORTED);
754        skipIfNotSupported = (skipper != null);
755
756        // ----------------------------------------------------
757        // find out if we should simulate a not supported
758        // scenario
759        // ----------------------------------------------------
760        XMLElement support = spec.getFirstChildNamed(SPEC_KEY_NOT_SUPPORTED);
761
762        if (support != null)
763        {
764            simulteNotSupported = true;
765        }
766
767        // ----------------------------------------------------
768        // find out in which program group the shortcuts should
769        // be placed and where this program group should be
770        // located
771        // ----------------------------------------------------
772        XMLElement group = spec.getFirstChildNamed(SPEC_KEY_PROGRAM_GROUP);
773        String location = null;
774        hasDesktopShortcuts = false;
775
776        if (group != null)
777        {
778            suggestedProgramGroup = group.getAttribute(SPEC_ATTRIBUTE_DEFAULT_GROUP, "");
779            location = group.getAttribute(SPEC_ATTRIBUTE_LOCATION, SPEC_VALUE_APPLICATIONS);
780        }
781        else
782        {
783            suggestedProgramGroup = "";
784            location = SPEC_VALUE_APPLICATIONS;
785        }
786
787        if (location.equals(SPEC_VALUE_APPLICATIONS))
788        {
789            groupLocation = Shortcut.APPLICATIONS;
790        }
791        else if (location.equals(SPEC_VALUE_START_MENU))
792        {
793            groupLocation = Shortcut.START_MENU;
794        }
795
796        // ----------------------------------------------------
797        // create a list of all shortcuts that need to be
798        // created, containing all details about each shortcut
799        // ----------------------------------------------------
800        VariableSubstitutor substitutor = new VariableSubstitutor(idata.getVariables());
801        String temp;
802        Vector shortcutSpecs = spec.getChildrenNamed(SPEC_KEY_SHORTCUT);
803        XMLElement shortcutSpec;
804        ShortcutData data;
805
806        for (int i = 0; i < shortcutSpecs.size(); i++)
807        {
808            shortcutSpec = (XMLElement) shortcutSpecs.elementAt(i);
809
810            if (!OsConstraint.oneMatchesCurrentSystem(shortcutSpec)) continue;
811
812            data = new ShortcutData();
813
814            data.name = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_NAME);
815            data.subgroup = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_SUBGROUP);
816            data.description = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_DESCRIPTION, "");
817
818            //** Linux **//
819            data.deskTopEntryLinux_Encoding = shortcutSpec
820                    .getAttribute(SPEC_ATTRIBUTE_ENCODING, "");
821            data.deskTopEntryLinux_MimeType = shortcutSpec
822                    .getAttribute(SPEC_ATTRIBUTE_MIMETYPE, "");
823            data.deskTopEntryLinux_Terminal = shortcutSpec
824                    .getAttribute(SPEC_ATTRIBUTE_TERMINAL, "");
825            data.deskTopEntryLinux_TerminalOptions = shortcutSpec.getAttribute(
826                    SPEC_ATTRIBUTE_TERMINAL_OPTIONS, "");
827            data.deskTopEntryLinux_Type = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_TYPE, "");
828
829            data.deskTopEntryLinux_URL = substitutor.substitute(shortcutSpec.getAttribute(
830                    SPEC_ATTRIBUTE_URL, ""), null);
831
832            data.deskTopEntryLinux_X_KDE_SubstituteUID = shortcutSpec.getAttribute(
833                    SPEC_ATTRIBUTE_KDE_SUBST_UID, "");
834
835            data.createForAll = new Boolean(shortcutSpec.getAttribute(CREATE_FOR_ALL, "false"));
836            //** EndOf LINUX **//
837            temp = fixSeparatorChar(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_TARGET, ""));
838            data.target = substitutor.substitute(temp, null);
839
840            temp = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_COMMAND, "");
841            data.commandLine = substitutor.substitute(temp, null);
842
843            temp = fixSeparatorChar(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_ICON, ""));
844            data.iconFile = substitutor.substitute(temp, null);
845            data.iconIndex = Integer.parseInt(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_ICON_INDEX,
846                    "0"));
847
848            temp = fixSeparatorChar(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_WORKING_DIR, ""));
849            data.workingDirectory = substitutor.substitute(temp, null);
850
851            String initialState = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_INITIAL_STATE, "");
852
853            if (initialState.equals(SPEC_VALUE_NO_SHOW))
854            {
855                data.initialState = Shortcut.HIDE;
856            }
857            else if (initialState.equals(SPEC_VALUE_NORMAL))
858            {
859                data.initialState = Shortcut.NORMAL;
860            }
861            else if (initialState.equals(SPEC_VALUE_MAXIMIZED))
862            {
863                data.initialState = Shortcut.MAXIMIZED;
864            }
865            else if (initialState.equals(SPEC_VALUE_MINIMIZED))
866            {
867                data.initialState = Shortcut.MINIMIZED;
868            }
869            else
870            {
871                data.initialState = Shortcut.NORMAL;
872            }
873
874            // --------------------------------------------------
875            // if the minimal data requirements are met to create
876            // the shortcut, create one entry each for each of
877            // the requested types.
878            // Eventually this will cause the creation of one
879            // shortcut in each of the associated locations.
880            // --------------------------------------------------
881            // without a name we can not create a shortcut
882            if (data.name == null)
883            {
884                continue;
885            }
886
887            //1. Elmar: "Without a target we can not create a shortcut."
888            //2. Marc: "No, Even on Linux a Link can be an URL and has no target."
889            if (data.target == null)
890            {
891                continue;
892            }
893
894            // the shortcut is not actually required for any of the selected packs
895            Vector forPacks = shortcutSpec.getChildrenNamed(SPEC_KEY_PACKS);
896
897            if (!shortcutRequiredFor(forPacks))
898            {
899                continue;
900            }
901            // --------------------------------------------------
902            // This section is executed if we don't skip.
903            // --------------------------------------------------
904            // For each of the categories set the type and if
905            // the link should be placed in the program group,
906            // then clone the data set to obtain an independent
907            // instance and add this to the list of shortcuts
908            // to be created. In this way, we will set up an
909            // identical copy for each of the locations at which
910            // a shortcut should be placed. Therefore you must
911            // not use 'else if' statements!
912            // --------------------------------------------------
913            {
914                if (attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_DESKTOP))
915                {
916                    hasDesktopShortcuts = true;
917                    data.addToGroup = false;
918                    data.type = Shortcut.DESKTOP;
919                    shortcuts.add(data.clone());
920                }
921
922                if (attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_APPLICATIONS))
923                {
924                    data.addToGroup = false;
925                    data.type = Shortcut.APPLICATIONS;
926                    shortcuts.add(data.clone());
927                }
928
929                if (attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_START_MENU))
930                {
931                    data.addToGroup = false;
932                    data.type = Shortcut.START_MENU;
933                    shortcuts.add(data.clone());
934                }
935
936                if (attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_STARTUP))
937                {
938                    data.addToGroup = false;
939                    data.type = Shortcut.START_UP;
940                    shortcuts.add(data.clone());
941                }
942
943                if (attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_PROGRAM_GROUP))
944                {
945                    data.addToGroup = true;
946                    data.type = Shortcut.APPLICATIONS;
947                    shortcuts.add(data.clone());
948                }
949            }
950        }
951
952        // ----------------------------------------------------
953        // signal if there are any shortcuts to create
954        // ----------------------------------------------------
955        if (shortcuts.size() > 0)
956        {
957            shortcutsToCreate = true;
958        }
959    }
960
961    /*--------------------------------------------------------------------------*/
962
963    /**
964     * Creates all shortcuts based on the information in <code>shortcuts</code>.
965     */
966
967    /*--------------------------------------------------------------------------*/
968    private void createShortcuts()
969    {
970        if (!create) return;
971        ShortcutData data;
972
973        for (int i = 0; i < shortcuts.size(); i++)
974        {
975            data = (ShortcutData) shortcuts.elementAt(i);
976
977            try
978            {
979                groupName = groupName + data.subgroup;
980                shortcut.setUserType(itsUserType);
981                shortcut.setLinkName(data.name);
982                shortcut.setLinkType(data.type);
983                shortcut.setArguments(data.commandLine);
984                shortcut.setDescription(data.description);
985                shortcut.setIconLocation(data.iconFile, data.iconIndex);
986
987                shortcut.setShowCommand(data.initialState);
988                shortcut.setTargetPath(data.target);
989                shortcut.setWorkingDirectory(data.workingDirectory);
990                shortcut.setEncoding(data.deskTopEntryLinux_Encoding);
991                shortcut.setMimetype(data.deskTopEntryLinux_MimeType);
992
993                shortcut.setTerminal(data.deskTopEntryLinux_Terminal);
994                shortcut.setTerminalOptions(data.deskTopEntryLinux_TerminalOptions);
995                shortcut.setType(data.deskTopEntryLinux_Type);
996                shortcut.setKdeSubstUID(data.deskTopEntryLinux_X_KDE_SubstituteUID);
997                shortcut.setURL(data.deskTopEntryLinux_URL);
998                shortcut.setCreateForAll(data.createForAll);
999
1000                if (data.addToGroup)
1001                {
1002                    shortcut.setProgramGroup(groupName);
1003                }
1004                else
1005                {
1006                    shortcut.setProgramGroup("");
1007                }
1008
1009                try
1010                {
1011                    // ----------------------------------------------
1012                    // save the shortcut only if it is either not on
1013                    // the desktop or if it is on the desktop and
1014                    // the user has signalled that it is ok to place
1015                    // shortcuts on the desktop.
1016                    // ----------------------------------------------
1017                    if ((data.type != Shortcut.DESKTOP)
1018                            || ((data.type == Shortcut.DESKTOP) && allowDesktopShortcut
1019                                    .isSelected()))
1020                    {
1021                        // save the shortcut
1022                        shortcut.save();
1023
1024                        // add the file and directory name to the file list
1025                        String fileName = shortcut.getFileName();
1026                        files.add(0, fileName);
1027
1028                        File file = new File(fileName);
1029                        File base = new File(shortcut.getBasePath());
1030                        Vector intermediates = new Vector();
1031
1032                        //String directoryName = shortcut.getDirectoryCreated ();
1033                        execFiles.add(new ExecutableFile(fileName, 2, ExecutableFile.WARN,
1034                                new ArrayList(), false));
1035
1036                        files.add(fileName);
1037
1038                        while ((file = file.getParentFile()) != null)
1039                        {
1040                            if (file.equals(base)) break;
1041                            intermediates.add(file);
1042                        }
1043                        if (file != null)
1044                        {
1045                            for (Iterator iter = intermediates.iterator(); iter.hasNext();)
1046                                files.add(0, iter.next().toString());
1047                        }
1048                    }
1049                }
1050                catch (Exception exception)
1051                {}
1052            }
1053            catch (Throwable exception)
1054            {
1055                continue;
1056            }
1057        }
1058
1059        
1060        //
1061        try
1062        {
1063
1064            if (execFiles != null)
1065            {
1066                FileExecutor executor = new FileExecutor(execFiles);
1067                // 
1068                // TODO: Hi Guys,
1069                // TODO The following commented-out line sometimes produces an uncatchable
1070                // nullpointer Exception!
1071                // TODO evaluate for what reason the files should exec.
1072                // TODO if there is a serious explanation, why to do that,
1073                // TODO the code must be more robust
1074
1075                //evaluate executor.executeFiles( ExecutableFile.NEVER, null );
1076            }
1077        }
1078        catch (NullPointerException nep)
1079        {
1080            nep.printStackTrace();
1081        }
1082        catch (RuntimeException cannot)
1083        {
1084            cannot.printStackTrace();
1085        }
1086
1087        parent.unlockNextButton();
1088    }
1089
1090    /*--------------------------------------------------------------------------*/
1091
1092    /**
1093     * Verifies if the shortcut is required for any of the packs listed. The shortcut is required
1094     * for a pack in the list if that pack is actually selected for installation. <br>
1095     * <br>
1096     * <b>Note: </b> <br>
1097     * If the list of selected packs is empty then <code>true</code> is always returnd. The same
1098     * is true if the <code>packs</code> list is empty.
1099     * 
1100     * @param packs a <code>Vector</code> of <code>String</code>s. Each of the strings denotes
1101     * a pack for which the schortcut should be created if the pack is actually installed.
1102     * 
1103     * @return <code>true</code> if the shortcut is required for at least on pack in the list,
1104     * otherwise returns <code>false</code>.
1105     */
1106
1107    /*--------------------------------------------------------------------------*/
1108    /*
1109     * $ @design
1110     * 
1111     * The information about the installed packs comes from InstallData.selectedPacks. This assumes
1112     * that this panel is presented to the user AFTER the PacksPanel.
1113     * --------------------------------------------------------------------------
1114     */
1115    private boolean shortcutRequiredFor(Vector packs)
1116    {
1117        String selected;
1118        String required;
1119
1120        if (packs.size() == 0) { return (true); }
1121
1122        for (int i = 0; i < idata.selectedPacks.size(); i++)
1123        {
1124            selected = ((Pack) idata.selectedPacks.get(i)).name;
1125
1126            for (int k = 0; k < packs.size(); k++)
1127            {
1128                required = (String) ((XMLElement) packs.elementAt(k)).getAttribute(
1129                        SPEC_ATTRIBUTE_NAME, "");
1130
1131                if (selected.equals(required)) { return (true); }
1132            }
1133        }
1134
1135        return (false);
1136    }
1137
1138    /*--------------------------------------------------------------------------*/
1139
1140    /**
1141     * Determines if the named attribute in true. True is represented by any of the following
1142     * strings and is not case sensitive. <br>
1143     * 
1144     * <ul>
1145     * <li>yes</li>
1146     * <li>1</li>
1147     * <li>true</li>
1148     * <li>on</li>
1149     * </ul>
1150     * 
1151     * <br>
1152     * Every other string, including the empty string as well as the non-existence of the attribute
1153     * will cuase <code>false</code> to be returned.
1154     * 
1155     * @param element the <code>XMLElement</code> to search for the attribute.
1156     * @param name the name of the attribute to test.
1157     * 
1158     * @return <code>true</code> if the attribute value equals one of the pre-defined strings,
1159     * <code>false</code> otherwise.
1160     */
1161
1162    /*--------------------------------------------------------------------------*/
1163    private boolean attributeIsTrue(XMLElement element, String name)
1164    {
1165        String value = element.getAttribute(name, "").toUpperCase();
1166
1167        if (value.equals("YES"))
1168        {
1169            return (true);
1170        }
1171        else if (value.equals("TRUE"))
1172        {
1173            return (true);
1174        }
1175        else if (value.equals("ON"))
1176        {
1177            return (true);
1178        }
1179        else if (value.equals("1")) { return (true); }
1180
1181        return (false);
1182    }
1183
1184    /*--------------------------------------------------------------------------*/
1185
1186    /**
1187     * Replaces any ocurrence of '/' or '\' in a path string with the correct version for the
1188     * operating system.
1189     * 
1190     * @param path a system path
1191     * 
1192     * @return a path string that uniformely uses the proper version of the separator character.
1193     */
1194
1195    /*--------------------------------------------------------------------------*/
1196    private String fixSeparatorChar(String path)
1197    {
1198        String newPath = path.replace('/', File.separatorChar);
1199        newPath = newPath.replace('\\', File.separatorChar);
1200
1201        return (newPath);
1202    }
1203
1204    /*--------------------------------------------------------------------------*/
1205
1206    /**
1207     * This method creates the UI for this panel.
1208     * 
1209     * @param groups A <code>Vector</code> that contains <code>Strings</code> with all the names
1210     * of the existing program groups. These will be placed in the <code>groupList</code>.
1211     */
1212
1213    /*--------------------------------------------------------------------------*/
1214    private void buildUI(File groups)
1215    {
1216        itsProgramFolder = groups;        
1217         
1218        constraints.gridx = 0;
1219        constraints.gridy = 0;
1220        constraints.gridwidth = 3;
1221        constraints.gridheight = 1;
1222        constraints.weightx = 1.0;
1223        constraints.weighty = 1.0;        
1224        constraints.fill = GridBagConstraints.HORIZONTAL;
1225        constraints.anchor = GridBagConstraints.WEST;
1226        /**/
1227        
1228
1229        // Add a CheckBox which enables the user to entirely supress shortcut creation.  
1230        String menuKind = parent.langpack.getString("ShortcutPanel.regular.StartMenu:Start-Menu");
1231        if( OsVersion.IS_UNIX && UnixHelper.kdeIsInstalled() )
1232            menuKind = parent.langpack.getString("ShortcutPanel.regular.StartMenu:K-Menu");
1233        
1234        createShortcuts = new JCheckBox( StringTool.replace( parent.langpack.getString("ShortcutPanel.regular.create"), "StartMenu", menuKind ),
1235                true);
1236        createShortcuts.addActionListener(this);
1237        constraints.gridx = 0;
1238        constraints.gridy = 1;
1239        constraints.gridwidth = 2;
1240        constraints.gridheight = 1;   
1241        constraints.weighty = 0.2;
1242        layout.addLayoutComponent(createShortcuts, constraints);
1243        add(createShortcuts);
1244        
1245        // ----------------------------------------------------
1246        // check box to allow the user to decide if a desktop
1247        // shortcut should be created.
1248        // this should only be created if needed and requested
1249        // in the definition file.
1250        // ----------------------------------------------------
1251        if (hasDesktopShortcuts)
1252        {
1253          String initialAllowedValue = idata.getVariable( "DesktopShortcutCheckboxEnabled" );
1254          boolean initialAllowedFlag = false;
1255          if( initialAllowedValue==null) 
1256            initialAllowedFlag= false;
1257          else if( Boolean.TRUE.toString().equals(initialAllowedValue) ) 
1258            initialAllowedFlag=true;
1259                     
1260          allowDesktopShortcut = new JCheckBox(parent.langpack
1261                .getString("ShortcutPanel.regular.desktop"), initialAllowedFlag);
1262          constraints.gridx = 0;
1263          constraints.gridy = 2;
1264          constraints.gridwidth = 3;
1265          constraints.gridheight = 1;
1266          constraints.weighty = 0.2;
1267        
1268          layout.addLayoutComponent(allowDesktopShortcut, constraints);
1269          add(allowDesktopShortcut);
1270        }
1271        
1272        listLabel = LabelFactory.create(parent.langpack.getString("ShortcutPanel.regular.list"),
1273                JLabel.LEADING);
1274        
1275        constraints.gridx = 0;
1276        constraints.gridy = 3;
1277        constraints.gridwidth = 1;
1278        constraints.gridheight = 1;
1279        constraints.weightx = 0.2;
1280        constraints.weighty = 0.2;
1281        constraints.fill = GridBagConstraints.NONE;
1282        constraints.anchor = GridBagConstraints.WEST;
1283        
1284        layout.addLayoutComponent(listLabel, constraints);
1285        add(listLabel);
1286        // ----------------------------------------------------
1287        // list box to list all of already existing folders as program groups
1288        // at the intended destination
1289        // ----------------------------------------------------
1290        addSelectionList( groups, 0, 4, 2, 1, GridBagConstraints.BOTH ); 
1291
1292        // ----------------------------------------------------
1293        // radio buttons to select current user or all users.
1294        // ----------------------------------------------------
1295        if (shortcut.multipleUsers())
1296        {
1297            JPanel usersPanel = new JPanel(new GridLayout(2, 1));
1298            ButtonGroup usersGroup = new ButtonGroup();
1299            currentUser = new JRadioButton(parent.langpack
1300                    .getString("ShortcutPanel.regular.currentUser"), !isRootUser);
1301            currentUser.addActionListener(this);
1302            usersGroup.add(currentUser);
1303            usersPanel.add(currentUser);
1304            allUsers = new JRadioButton(
1305                    parent.langpack.getString("ShortcutPanel.regular.allUsers"), isRootUser);
1306            if (!isRootUser) allUsers.setEnabled(false);
1307            allUsers.addActionListener(this);
1308            usersGroup.add(allUsers);
1309            usersPanel.add(allUsers);
1310
1311            TitledBorder border = new TitledBorder(new EmptyBorder(2, 2, 2, 2), parent.langpack
1312                    .getString("ShortcutPanel.regular.userIntro"));
1313            usersPanel.setBorder(border);
1314
1315            constraints.gridx = 2;
1316            constraints.gridy = 4;
1317            constraints.gridwidth = 1;
1318            constraints.gridheight = 1;
1319            constraints.weighty = 1.0;
1320            constraints.weightx = 1.0;
1321            constraints.fill = GridBagConstraints.NONE;
1322            layout.addLayoutComponent(usersPanel, constraints);
1323            add(usersPanel);
1324        }
1325
1326        // ----------------------------------------------------
1327        // edit box that contains the suggested program group
1328        // name, which can be modfied or substituted from the
1329        // list by the user
1330        // ----------------------------------------------------
1331        programGroup = new JTextField(suggestedProgramGroup, 40); // 40?
1332
1333        constraints.gridx = 0;
1334        constraints.gridy = 5;
1335        constraints.gridwidth = 2;
1336        constraints.gridheight = 1;
1337        constraints.weighty = 1.0;
1338        constraints.weightx = 10.0;
1339        constraints.fill = GridBagConstraints.HORIZONTAL;
1340        layout.addLayoutComponent(programGroup, constraints);
1341        add(programGroup);
1342
1343        // ----------------------------------------------------
1344        // reset button that allows the user to revert to the
1345        // original suggestion for the program group
1346        // ----------------------------------------------------
1347        defaultButton = ButtonFactory.createButton(parent.langpack
1348                .getString("ShortcutPanel.regular.default"), idata.buttonsHColor);
1349        defaultButton.addActionListener(this);
1350
1351        constraints.gridx = 2;
1352        constraints.gridy = 5;
1353        constraints.gridwidth = 1;
1354        constraints.gridheight = 1;       
1355        constraints.fill = GridBagConstraints.NONE;
1356        layout.addLayoutComponent(defaultButton, constraints);
1357        add(defaultButton);
1358    }
1359    
1360    /**
1361     * 
1362     * @param groups
1363     */
1364    private void addSelectionList(File groups, int aGridx, int aGridy, int aGridwidth, int aGridheight, int aFill)
1365    {
1366        Vector dirEntries = new Vector();
1367
1368        File[] entries = groups.listFiles();
1369        
1370        // Quickfix prevent NullPointer on non default compliant Linux - KDEs
1371        // i.e Mandrake 2005 LE stores from now also in "applnk" instead in prior "applnk-mdk": 
1372        if( entries != null )        
1373        for (int idx = 0; idx < entries.length; idx++)
1374        {
1375            if (entries[idx].isDirectory())
1376            {
1377                dirEntries.add(entries[idx].getName());
1378            }
1379        }
1380        groupList = new JList(dirEntries);
1381        groupList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
1382        groupList.getSelectionModel().addListSelectionListener(this);
1383
1384        JScrollPane scrollPane = new JScrollPane(groupList);
1385
1386        constraints.gridx = aGridx;
1387        constraints.gridy = aGridy;
1388        constraints.gridwidth = aGridwidth;
1389        constraints.gridheight = aGridheight;
1390        constraints.weightx = 10.0;
1391        constraints.weighty = 1.5;
1392        constraints.insets = new Insets(5, 5, 5, 5);
1393        constraints.fill = aFill;
1394        layout.addLayoutComponent(scrollPane, constraints);
1395        add(scrollPane);
1396    }
1397
1398
1399    /*--------------------------------------------------------------------------*/
1400
1401    /**
1402     * This method creates an alternative UI for this panel. This UI can be used when the creation
1403     * of shortcuts is not supported on the target system. It displays an apology for the inability
1404     * to create shortcuts on this system, along with information about the intended targets. In
1405     * addition, there is a button that allows the user to save more complete information in a text
1406     * file. Based on this information the user might be able to create the necessary shortcut him
1407     * or herself. At least there will be information about how to launch the application.
1408     */
1409
1410    /*--------------------------------------------------------------------------*/
1411    private void buildAlternateUI()
1412    {
1413        layout = new GridBagLayout();
1414        constraints = new GridBagConstraints();
1415        setLayout(layout);
1416
1417        // ----------------------------------------------------
1418        // static text a the top of the panel, that apologizes
1419        // about the fact that we can not create shortcuts on
1420        // this particular target OS.
1421        // ----------------------------------------------------
1422        MultiLineLabel apologyLabel = new MultiLineLabel(parent.langpack
1423                .getString("ShortcutPanel.alternate.apology"), 0, 0);
1424
1425        constraints.gridx = 0;
1426        constraints.gridy = 0;
1427        constraints.gridwidth = 1;
1428        constraints.gridheight = 1;
1429        constraints.weightx = 1.0;
1430        constraints.weighty = 1.0;
1431        constraints.insets = new Insets(5, 5, 5, 5);
1432        constraints.fill = GridBagConstraints.HORIZONTAL;
1433        constraints.anchor = GridBagConstraints.WEST;
1434        layout.addLayoutComponent(apologyLabel, constraints);
1435        add(apologyLabel);
1436
1437        // ----------------------------------------------------
1438        // label that explains the significance ot the list box
1439        // ----------------------------------------------------
1440        MultiLineLabel listLabel = new MultiLineLabel(parent.langpack
1441                .getString("ShortcutPanel.alternate.targetsLabel"), 0, 0);
1442
1443        constraints.gridx = 0;
1444        constraints.gridy = 1;
1445        constraints.gridwidth = 1;
1446        constraints.gridheight = 1;
1447        constraints.weightx = 1.0;
1448        constraints.weighty = 1.0;
1449        layout.addLayoutComponent(listLabel, constraints);
1450        add(listLabel);
1451
1452        // ----------------------------------------------------
1453        // list box to list all of the intended shortcut targets
1454        // ----------------------------------------------------
1455        Vector targets = new Vector();
1456
1457        for (int i = 0; i < shortcuts.size(); i++)
1458        {
1459            targets.add(((ShortcutData) shortcuts.elementAt(i)).target);
1460        }
1461
1462        targetList = new JList(targets);
1463
1464        JScrollPane scrollPane = new JScrollPane(targetList);
1465
1466        constraints.gridx = 0;
1467        constraints.gridy = 2;
1468        constraints.fill = GridBagConstraints.BOTH;
1469        layout.addLayoutComponent(scrollPane, constraints);
1470        add(scrollPane);
1471
1472        // ----------------------------------------------------
1473        // static text that explains about the text file
1474        // ----------------------------------------------------
1475        MultiLineLabel fileExplanation = new MultiLineLabel(parent.langpack
1476                .getString("ShortcutPanel.alternate.textFileExplanation"), 0, 0);
1477
1478        constraints.gridx = 0;
1479        constraints.gridy = 3;
1480        constraints.weightx = 1.0;
1481        constraints.weighty = 1.0;
1482        constraints.fill = GridBagConstraints.HORIZONTAL;
1483        layout.addLayoutComponent(fileExplanation, constraints);
1484        add(fileExplanation);
1485
1486        // ----------------------------------------------------
1487        // button to save the text file
1488        // ----------------------------------------------------
1489        saveButton = ButtonFactory.createButton(parent.langpack
1490                .getString("ShortcutPanel.alternate.saveButton"), idata.buttonsHColor);
1491        saveButton.addActionListener(this);
1492
1493        constraints.gridx = 0;
1494        constraints.gridy = 4;
1495        constraints.gridwidth = 1;
1496        constraints.gridheight = 1;
1497        constraints.fill = GridBagConstraints.NONE;
1498        constraints.anchor = GridBagConstraints.CENTER;
1499        layout.addLayoutComponent(saveButton, constraints);
1500        add(saveButton);
1501    }
1502
1503    /*--------------------------------------------------------------------------*/
1504
1505    /**
1506     * Overriding the superclass implementation. This method returns the size of the container.
1507     * 
1508     * @return the size of the container
1509     */
1510
1511    /*--------------------------------------------------------------------------*/
1512    public Dimension getSize()
1513    {
1514        Dimension size = getParent().getSize();
1515        Insets insets = getInsets();
1516        Border border = getBorder();
1517        Insets borderInsets = new Insets(0, 0, 0, 0);
1518
1519        if (border != null)
1520        {
1521            borderInsets = border.getBorderInsets(this);
1522        }
1523
1524        size.height = size.height - insets.top - insets.bottom - borderInsets.top
1525                - borderInsets.bottom - 50;
1526        size.width = size.width - insets.left - insets.right - borderInsets.left
1527                - borderInsets.right - 50;
1528
1529        return (size);
1530    }
1531
1532    /*--------------------------------------------------------------------------*/
1533
1534    /**
1535     * This method saves all shortcut information to a text file.
1536     */
1537
1538    /*--------------------------------------------------------------------------*/
1539    private void saveToFile()
1540    {
1541        File file = null;
1542
1543        // ----------------------------------------------------
1544        // open a file chooser dialog to get a path / file name
1545        // ----------------------------------------------------
1546        JFileChooser fileDialog = new JFileChooser(idata.getInstallPath());
1547        fileDialog.setSelectedFile(new File(TEXT_FILE_NAME));
1548
1549        if (fileDialog.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
1550        {
1551            file = fileDialog.getSelectedFile();
1552        }
1553        else
1554        {
1555            return;
1556        }
1557
1558        // ----------------------------------------------------
1559        // save to the file
1560        // ----------------------------------------------------
1561        FileWriter output = null;
1562        StringBuffer buffer = new StringBuffer();
1563        String header = parent.langpack.getString("ShortcutPanel.textFile.header");
1564
1565        String newline = System.getProperty("line.separator", "\n");
1566
1567        try
1568        {
1569            output = new FileWriter(file);
1570        }
1571        catch (Throwable exception)
1572        {
1573            // !!! show an error dialog
1574            return;
1575        }
1576
1577        // ----------------------------------------------------
1578        // break the header down into multiple lines based
1579        // on '\n' line breaks.
1580        // ----------------------------------------------------
1581        int nextIndex = 0;
1582        int currentIndex = 0;
1583
1584        do
1585        {
1586            nextIndex = header.indexOf("\\n", currentIndex);
1587
1588            if (nextIndex > -1)
1589            {
1590                buffer.append(header.substring(currentIndex, nextIndex));
1591                buffer.append(newline);
1592                currentIndex = nextIndex + 2;
1593            }
1594            else
1595            {
1596                buffer.append(header.substring(currentIndex, header.length()));
1597                buffer.append(newline);
1598            }
1599        }
1600        while (nextIndex > -1);
1601
1602        buffer.append(SEPARATOR_LINE);
1603        buffer.append(newline);
1604        buffer.append(newline);
1605
1606        for (int i = 0; i < shortcuts.size(); i++)
1607        {
1608            ShortcutData data = (ShortcutData) shortcuts.elementAt(i);
1609
1610            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.name"));
1611            buffer.append(data.name);
1612            buffer.append(newline);
1613
1614            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.location"));
1615
1616            switch (data.type)
1617            {
1618            case Shortcut.DESKTOP: {
1619                buffer.append(parent.langpack.getString("ShortcutPanel.location.desktop"));
1620
1621                break;
1622            }
1623
1624            case Shortcut.APPLICATIONS: {
1625                buffer.append(parent.langpack.getString("ShortcutPanel.location.applications"));
1626
1627                break;
1628            }
1629
1630            case Shortcut.START_MENU: {
1631                buffer.append(parent.langpack.getString("ShortcutPanel.location.startMenu"));
1632
1633                break;
1634            }
1635
1636            case Shortcut.START_UP: {
1637                buffer.append(parent.langpack.getString("ShortcutPanel.location.startup"));
1638
1639                break;
1640            }
1641            }
1642
1643            buffer.append(newline);
1644
1645            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.description"));
1646            buffer.append(data.description);
1647            buffer.append(newline);
1648
1649            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.target"));
1650            buffer.append(data.target);
1651            buffer.append(newline);
1652
1653            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.command"));
1654            buffer.append(data.commandLine);
1655            buffer.append(newline);
1656
1657            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.iconName"));
1658            buffer.append(data.iconFile);
1659            buffer.append(newline);
1660
1661            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.iconIndex"));
1662            buffer.append(data.iconIndex);
1663            buffer.append(newline);
1664
1665            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.work"));
1666            buffer.append(data.workingDirectory);
1667            buffer.append(newline);
1668
1669            buffer.append(newline);
1670            buffer.append(SEPARATOR_LINE);
1671            buffer.append(newline);
1672            buffer.append(newline);
1673        }
1674
1675        try
1676        {
1677            output.write(buffer.toString());
1678        }
1679        catch (Throwable exception)
1680        {}
1681        finally
1682        {
1683            try
1684            {
1685                output.flush();
1686                output.close();
1687                files.add(file.getPath());
1688            }
1689            catch (Throwable exception)
1690            {
1691                // not really anything I can do here, maybe should show a dialog that
1692                // tells the user that data might not have been saved completely!?
1693            }
1694        }
1695    }
1696
1697    /*--------------------------------------------------------------------------*/
1698
1699    /**
1700     * Adds all files and directories to the uninstaller.
1701     */
1702
1703    /*--------------------------------------------------------------------------*/
1704    private void addToUninstaller()
1705    {
1706        UninstallData uninstallData = UninstallData.getInstance();
1707
1708        for (int i = 0; i < files.size(); i++)
1709        {
1710            uninstallData.addFile((String) files.elementAt(i));
1711        }
1712    }
1713
1714    /*--------------------------------------------------------------------------*/
1715
1716    /**
1717     * Adds iformation about the shortcuts that have been created during the installation to the XML
1718     * tree.
1719     * 
1720     * @param panelRoot the root of the XML tree
1721     */
1722
1723    /*--------------------------------------------------------------------------*/
1724    /*
1725     * $ @design
1726     * 
1727     * The information needed to create shortcuts has been collected in the Vector 'shortcuts'. Take
1728     * the data from there and package it in XML form for storage by the installer. The group name
1729     * is only stored once in a separate XML element, since there is only one.
1730     * --------------------------------------------------------------------------
1731     */
1732    public void makeXMLData(XMLElement panelRoot)
1733    {
1734        // ----------------------------------------------------
1735        // if there are no shortcuts to create, shortcuts are
1736        // not supported, or we should simulate that they are
1737        // not supported, then we have nothing to add. Just
1738        // return
1739        // ----------------------------------------------------
1740        if (!shortcutsToCreate || !shortcut.supported() || groupName == null || simulteNotSupported) { return; }
1741
1742        ShortcutData data;
1743        XMLElement dataElement;
1744
1745        // ----------------------------------------------------
1746        // add the item that defines the name of the program group
1747        // ----------------------------------------------------
1748        dataElement = new XMLElement(AUTO_KEY_PROGRAM_GROUP);
1749        dataElement.setAttribute(AUTO_ATTRIBUTE_NAME, groupName);
1750        panelRoot.addChild(dataElement);
1751
1752        // ----------------------------------------------------
1753        // add the details for each of the shortcuts
1754        // ----------------------------------------------------
1755        for (int i = 0; i < shortcuts.size(); i++)
1756        {
1757            data = (ShortcutData) shortcuts.elementAt(i);
1758            dataElement = new XMLElement(AUTO_KEY_SHORTCUT);
1759
1760            dataElement.setAttribute(AUTO_ATTRIBUTE_NAME, data.name);
1761            dataElement.setAttribute(AUTO_ATTRIBUTE_GROUP, Boolean.valueOf(data.addToGroup)
1762                    .toString());
1763            dataElement.setAttribute(AUTO_ATTRIBUTE_TYPE, Integer.toString(data.type));
1764            dataElement.setAttribute(AUTO_ATTRIBUTE_COMMAND, data.commandLine);
1765            dataElement.setAttribute(AUTO_ATTRIBUTE_DESCRIPTION, data.description);
1766            dataElement.setAttribute(AUTO_ATTRIBUTE_ICON, data.iconFile);
1767            dataElement.setAttribute(AUTO_ATTRIBUTE_ICON_INDEX, Integer.toString(data.iconIndex));
1768            dataElement.setAttribute(AUTO_ATTRIBUTE_INITIAL_STATE, Integer
1769                    .toString(data.initialState));
1770            dataElement.setAttribute(AUTO_ATTRIBUTE_TARGET, data.target);
1771            dataElement.setAttribute(AUTO_ATTRIBUTE_WORKING_DIR, data.workingDirectory);
1772
1773            // ----------------------------------------------
1774            // add the shortcut only if it is either not on
1775            // the desktop or if it is on the desktop and
1776            // the user has signalled that it is ok to place
1777            // shortcuts on the desktop.
1778            // ----------------------------------------------
1779            if ((data.type != Shortcut.DESKTOP)
1780                    || ((data.type == Shortcut.DESKTOP) && allowDesktopShortcut.isSelected()))
1781            {
1782                panelRoot.addChild(dataElement);
1783            }
1784        }
1785    }
1786
1787    /*--------------------------------------------------------------------------*/
1788
1789    /**
1790     * Creates shortcuts based on teh information in <code>panelRoot</code> without UI.
1791     * 
1792     * @param panelRoot the root of the XML tree
1793     */
1794
1795    /*--------------------------------------------------------------------------*/
1796    /*
1797     * $ @design
1798     * 
1799     * Reconstitute the information needed to create shortcuts from XML data that was previously
1800     * stored by the installer through makeXMLData(). Create a new Vector containing this data and
1801     * stroe it in 'shortcuts' for use by createShortcuts(). Once this has been completed, call
1802     * createShortcuts() to complete the operation.
1803     * --------------------------------------------------------------------------
1804     */
1805    public void runAutomated(XMLElement panelRoot)
1806    {
1807        // ----------------------------------------------------
1808        // if shortcuts are not supported, then we can not
1809        // create shortcuts, even if there was any install
1810        // data. Just return.
1811        // ----------------------------------------------------
1812        if (!shortcut.supported()) { return; }
1813
1814        if (!OsConstraint.oneMatchesCurrentSystem(panelRoot)) { return; }
1815
1816        shortcuts = new Vector();
1817        Vector shortcutElements;
1818        ShortcutData data;
1819        XMLElement dataElement;
1820
1821        // ----------------------------------------------------
1822        // set the name of the program group
1823        // ----------------------------------------------------
1824        dataElement = panelRoot.getFirstChildNamed(AUTO_KEY_PROGRAM_GROUP);
1825        groupName = dataElement.getAttribute(AUTO_ATTRIBUTE_NAME);
1826
1827        if (groupName == null)
1828        {
1829            groupName = "";
1830        }
1831
1832        // ----------------------------------------------------
1833        // add the details for each of the shortcuts
1834        // ----------------------------------------------------
1835        shortcutElements = panelRoot.getChildrenNamed(AUTO_KEY_SHORTCUT);
1836
1837        for (int i = 0; i < shortcutElements.size(); i++)
1838        {
1839            data = new ShortcutData();
1840            dataElement = (XMLElement) shortcutElements.elementAt(i);
1841
1842            data.name = dataElement.getAttribute(AUTO_ATTRIBUTE_NAME);
1843            data.addToGroup = Boolean.valueOf(dataElement.getAttribute(AUTO_ATTRIBUTE_GROUP))
1844                    .booleanValue();
1845            data.type = Integer.valueOf(dataElement.getAttribute(AUTO_ATTRIBUTE_TYPE)).intValue();
1846            data.commandLine = dataElement.getAttribute(AUTO_ATTRIBUTE_COMMAND);
1847            data.description = dataElement.getAttribute(AUTO_ATTRIBUTE_DESCRIPTION);
1848            data.iconFile = dataElement.getAttribute(AUTO_ATTRIBUTE_ICON);
1849            data.iconIndex = Integer.valueOf(dataElement.getAttribute(AUTO_ATTRIBUTE_ICON_INDEX))
1850                    .intValue();
1851            data.initialState = Integer.valueOf(
1852                    dataElement.getAttribute(AUTO_ATTRIBUTE_INITIAL_STATE)).intValue();
1853            data.target = dataElement.getAttribute(AUTO_ATTRIBUTE_TARGET);
1854            data.workingDirectory = dataElement.getAttribute(AUTO_ATTRIBUTE_WORKING_DIR);
1855
1856            shortcuts.add(data);
1857        }
1858
1859        createShortcuts();
1860    }
1861
1862
1863}
1864
1865/*---------------------------------------------------------------------------*/