/*
 * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
 *
 * http://www.izforge.com/izpack/ http://izpack.codehaus.org/
 *
 * Copyright 2002 Elmar Grom
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.izforge.izpack.panels;

import com.izforge.izpack.ExecutableFile;
import com.izforge.izpack.Pack;
import com.izforge.izpack.adaptator.*;
import com.izforge.izpack.adaptator.impl.XMLElementImpl;
import com.izforge.izpack.adaptator.impl.XMLParser;
import com.izforge.izpack.gui.ButtonFactory;
import com.izforge.izpack.gui.LabelFactory;
import com.izforge.izpack.installer.*;
import com.izforge.izpack.util.*;
import com.izforge.izpack.util.os.Shortcut;
import com.izforge.izpack.util.os.unix.UnixHelper;
import com.izforge.izpack.util.xml.XMLHelper;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;

//
// import com.izforge.izpack.panels.ShortcutData;

/*---------------------------------------------------------------------------*/

/**
 * This class implements a panel for the creation of shortcuts. The panel prompts the user to select
 * a program group for shortcuts, accept the creation of desktop shortcuts and actually creates the
 * shortcuts.
 * <p/>
 * Use LateShortcutInstallListener to create the Shortcuts after the Files have been installed.
 *
 * @version $Revision: 2563 $
 */
public class ShortcutPanel extends IzPanel implements ActionListener, ListSelectionListener // ,//
// ShortcutConstants

{

    // ~ Static fields/initializers *********************************************************
    /**
     * serialVersionUID = 3256722870838112311L
     */
    private static final long serialVersionUID = 3256722870838112311L;

    // ~ Static fields/initializers *********************************************************

    public final static String SPEC_ATTRIBUTE_CONDITION="condition";
    
    /**
     * SPEC_ATTRIBUTE_KDE_USERNAME ="KdeUsername"
     */
    public final static String SPEC_ATTRIBUTE_KDE_USERNAME = "KdeUsername";

    /**
     * SPEC_ATTRIBUTE_KDE_SUBST_UID = "KdeSubstUID"
     */
    public final static String SPEC_ATTRIBUTE_KDE_SUBST_UID = "KdeSubstUID";

    /**
     * SPEC_ATTRIBUTE_URL = "url"
     */
    public final static String SPEC_ATTRIBUTE_URL = "url";

    /**
     * SPEC_ATTRIBUTE_TYPE = "type"
     */
    public final static String SPEC_ATTRIBUTE_TYPE = "type";

    /**
     * SPEC_ATTRIBUTE_TERMINAL_OPTIONS = "terminalOptions"
     */
    public final static String SPEC_ATTRIBUTE_TERMINAL_OPTIONS = "terminalOptions";

    /**
     * SPEC_ATTRIBUTE_TERMINAL = "terminal"
     */
    public final static String SPEC_ATTRIBUTE_TERMINAL = "terminal";

    /**
     * SPEC_ATTRIBUTE_MIMETYPE = "mimetype"
     */
    public final static String SPEC_ATTRIBUTE_MIMETYPE = "mimetype";

    /**
     * SPEC_ATTRIBUTE_ENCODING = "encoding"
     */
    public final static String SPEC_ATTRIBUTE_ENCODING = "encoding";

    /**
     * LOCATION_APPLICATIONS=applications
     */
    private static final String LOCATION_APPLICATIONS = "applications";

    /**
     * LOCATION_START_MENU = "startMenu"
     */
    private static final String LOCATION_START_MENU = "startMenu";

    /**
     * SPEC_CATEGORIES = "categories"
     */
    public static final String SPEC_CATEGORIES = "categories";

    /**
     * SPEC_TRYEXEC = "tryexec"
     */
    public static final String SPEC_TRYEXEC = "tryexec";


    /**
     * SEPARATOR_LINE =
     * "--------------------------------------------------------------------------------";
     */
    private static final String SEPARATOR_LINE = "--------------------------------------------------------------------------------";

    /**
     * The default file name for the text file in which the shortcut information should be stored,
     * in case shortcuts can not be created on a particular target system. TEXT_FILE_NAME =
     * "Shortcuts.txt"
     */
    private static final String TEXT_FILE_NAME = "Shortcuts.txt";

    /**
     * The name of the XML file that specifies the shortcuts SPEC_FILE_NAME = "shortcutSpec.xml";
     */
    private static final String SPEC_FILE_NAME = "shortcutSpec.xml";

    // ------------------------------------------------------
    // spec file section keys
    // -----------------------------------------------------

    /**
     * SPEC_KEY_SKIP_IFNOT_SUPPORTED = "skipIfNotSupported"
     */
    private static final String SPEC_KEY_SKIP_IFNOT_SUPPORTED = "skipIfNotSupported";

    /**
     * SPEC_KEY_NOT_SUPPORTED = "notSupported"
     */
    private static final String SPEC_KEY_NOT_SUPPORTED = "notSupported";

    /**
     * SPEC_KEY_DEF_CUR_USER = "defaultCurrentUser"
     */
    private static final String SPEC_KEY_DEF_CUR_USER = "defaultCurrentUser";

    /**
     * SPEC_KEY_PROGRAM_GROUP = "programGroup"
     */
    private static final String SPEC_KEY_PROGRAM_GROUP = "programGroup";

    /**
     * SPEC_KEY_SHORTCUT = "shortcut"
     */
    private static final String SPEC_KEY_SHORTCUT = "shortcut";

    /**
     * SPEC_KEY_PACKS = "createForPack"
     */
    private static final String SPEC_KEY_PACKS = "createForPack";

    // ------------------------------------------------------
    // spec file key attributes
    // ------------------------------------------------------
    /**
     * SPEC_ATTRIBUTE_DEFAULT_GROUP = "defaultName"
     */
    private static final String SPEC_ATTRIBUTE_DEFAULT_GROUP = "defaultName";

    /**
     * Support the InstallGroups like in Packs.
     * SPEC_ATTRIBUTE_INSTALLGROUP = "installGroup"
     */
    private static final String SPEC_ATTRIBUTE_INSTALLGROUP = "installGroup";

    /**
     * SPEC_ATTRIBUTE_LOCATION = "location"
     */
    private static final String SPEC_ATTRIBUTE_LOCATION = "location";

    /**
     * SPEC_ATTRIBUTE_NAME = "name"
     */
    private static final String SPEC_ATTRIBUTE_NAME = "name";

    /**
     * SPEC_ATTRIBUTE_SUBGROUP = "subgroup"
     */
    private static final String SPEC_ATTRIBUTE_SUBGROUP = "subgroup";

    /**
     * SPEC_ATTRIBUTE_DESCRIPTION = "description"
     */
    private static final String SPEC_ATTRIBUTE_DESCRIPTION = "description";

    /**
     * SPEC_ATTRIBUTE_TARGET = "target"
     */
    private static final String SPEC_ATTRIBUTE_TARGET = "target";

    /**
     * SPEC_ATTRIBUTE_COMMAND = "commandLine"
     */
    private static final String SPEC_ATTRIBUTE_COMMAND = "commandLine";

    /**
     * SPEC_ATTRIBUTE_ICON "iconFile"
     */
    private static final String SPEC_ATTRIBUTE_ICON = "iconFile";

    /**
     * SPEC_ATTRIBUTE_ICON_INDEX "iconIndex"
     */
    private static final String SPEC_ATTRIBUTE_ICON_INDEX = "iconIndex";

    /**
     * SPEC_ATTRIBUTE_WORKING_DIR = "workingDirectory"
     */
    private static final String SPEC_ATTRIBUTE_WORKING_DIR = "workingDirectory";

    /**
     * SPEC_ATTRIBUTE_INITIAL_STATE = "initialState"
     */
    private static final String SPEC_ATTRIBUTE_INITIAL_STATE = "initialState";

    /**
     * SPEC_ATTRIBUTE_DESKTOP = "desktop"
     */
    private static final String SPEC_ATTRIBUTE_DESKTOP = "desktop";

    /**
     * SPEC_ATTRIBUTE_APPLICATIONS = "applications"
     */
    private static final String SPEC_ATTRIBUTE_APPLICATIONS = "applications";

    /**
     * SPEC_ATTRIBUTE_START_MENU = "startMenu"
     */
    private static final String SPEC_ATTRIBUTE_START_MENU = "startMenu";

    /**
     * SPEC_ATTRIBUTE_STARTUP = "startup"
     */
    private static final String SPEC_ATTRIBUTE_STARTUP = "startup";

    /**
     * SPEC_ATTRIBUTE_PROGRAM_GROUP = "programGroup"
     */
    private static final String SPEC_ATTRIBUTE_PROGRAM_GROUP = "programGroup";

    // ------------------------------------------------------
    // spec file attribute values
    // ------------------------------------------------------

    /**
     * SPEC_VALUE_APPLICATIONS = "applications"
     */
    private static final String SPEC_VALUE_APPLICATIONS = "applications";

    /**
     * SPEC_VALUE_START_MENU = "startMenu"
     */
    private static final String SPEC_VALUE_START_MENU = "startMenu";

    /**
     * SPEC_VALUE_NO_SHOW = "noShow"
     */
    private static final String SPEC_VALUE_NO_SHOW = "noShow";

    /**
     * SPEC_VALUE_NORMAL = "normal"
     */
    private static final String SPEC_VALUE_NORMAL = "normal";

    /**
     * SPEC_VALUE_MAXIMIZED = "maximized"
     */
    private static final String SPEC_VALUE_MAXIMIZED = "maximized";

    /**
     * SPEC_VALUE_MINIMIZED = "minimized"
     */
    private static final String SPEC_VALUE_MINIMIZED = "minimized";

    // ------------------------------------------------------
    // automatic script section keys
    // ------------------------------------------------------

    /**
     * AUTO_KEY_PROGRAM_GROUP = SPEC_KEY_PROGRAM_GROUP = "programGroup"
     */
    public static final String AUTO_KEY_PROGRAM_GROUP = SPEC_KEY_PROGRAM_GROUP;

    /**
     * AUTO_KEY_SHORTCUT = SPEC_KEY_SHORTCUT = "shortcut"
     */
    public static final String AUTO_KEY_SHORTCUT = SPEC_KEY_SHORTCUT;

    // ------------------------------------------------------
    // automatic script keys attributes
    // ------------------------------------------------------

    /**
     * AUTO_ATTRIBUTE_NAME = "name"
     */
    public static final String AUTO_ATTRIBUTE_NAME = "name";

    /**
     * AUTO_ATTRIBUTE_GROUP = "group"
     */
    public static final String AUTO_ATTRIBUTE_GROUP = "group";

    /**
     * AUTO_ATTRIBUTE_TYPE "type"
     */
    public static final String AUTO_ATTRIBUTE_TYPE = "type";

    /**
     * AUTO_ATTRIBUTE_COMMAND = "commandLine"
     */
    public static final String AUTO_ATTRIBUTE_COMMAND = "commandLine";

    /**
     * AUTO_ATTRIBUTE_DESCRIPTION = "description"
     */
    public static final String AUTO_ATTRIBUTE_DESCRIPTION = "description";

    /**
     * AUTO_ATTRIBUTE_ICON = "icon"
     */
    public static final String AUTO_ATTRIBUTE_ICON = "icon";

    /**
     * AUTO_ATTRIBUTE_ICON_INDEX = "iconIndex"
     */
    public static final String AUTO_ATTRIBUTE_ICON_INDEX = "iconIndex";

    /**
     * AUTO_ATTRIBUTE_INITIAL_STATE = "initialState"
     */
    public static final String AUTO_ATTRIBUTE_INITIAL_STATE = "initialState";

    /**
     * AUTO_ATTRIBUTE_TARGET = "target"
     */
    public static final String AUTO_ATTRIBUTE_TARGET = "target";

    /**
     * AUTO_ATTRIBUTE_WORKING_DIR = "workingDirectory"
     */
    public static final String AUTO_ATTRIBUTE_WORKING_DIR = "workingDirectory";

    // permission flags

    /**
     * CREATE_FOR_ALL = "createForAll"
     */
    public static final String CREATE_FOR_ALL = "createForAll";

    private static ShortcutPanel self = null;

    private static boolean firstTime = true;

    /**
     * internal flag: create
     */
    static boolean create;

    /**
     * May be switched by an installerlistener to false.
     * Installerlistener may then perform the creation of the shortcuts after the files have been installed...
     * Default is true.
     */
    public static boolean createImmediately = true;

    /**
     * internal flag isRootUser
     */
    private static boolean isRootUser;

    // ~ Instance fields ********************************************************************

    // ~ Instance fields ********************************************************************

    /**
     * a VectorList of Files wich should be make executable
     */
    private Vector<ExecutableFile> execFiles = new Vector<ExecutableFile>();

    // ------------------------------------------------------------------------
    // Variable Declarations
    // ------------------------------------------------------------------------

    /**
     * UI element to label the list of existing program groups
     */
    private JLabel listLabel;

    /**
     * UI element to present the list of existing program groups for selection
     */
    private JList groupList;

    /**
     * UI element for listing the intended shortcut targets
     */
    private JList targetList;

    /**
     * UI element to present the default name for the program group and to support editing of this
     * name.
     */
    private JTextField programGroup;

    /**
     * UI element to allow the user to revert to the default name of the program group
     */
    private JButton defaultButton;

    /**
     * UI element to allow the user to save a text file with the shortcut information
     */
    private JButton saveButton;

    /**
     * UI element to allow the user to decide if shortcuts should be placed on the desktop or not.
     */
    private JCheckBox allowDesktopShortcut;

    /**
     * Checkbox to enable/disable to chreate ShortCuts
     */
    private JCheckBox createShortcuts;

    /**
     * UI element instruct this panel to create shortcuts for the current user only
     */
    private JRadioButton currentUser;

    /**
     * UI element instruct this panel to create shortcuts for all users
     */
    private JRadioButton allUsers;


    /**
     * UI Element to show the shortcut creation Progress
     */
    JProgressBar progressbar;

    /**
     * The layout for this panel
     */
    private GridBagLayout layout;

    /**
     * The contraints object to use whan creating the layout
     */
    private GridBagConstraints constraints;

    /**
     * The default name to use for the program group. This comes from the XML specification.
     */
    private String suggestedProgramGroup;

    /**
     * The name chosen by the user for the program group,
     */
    private String groupName;

    /**
     * The icon for the group in XDG/unix menu
     */
    private String programGroupIconFile;

    /**
     * Comment for XDG/unix group
     */
    private String programGroupComment;

    /**
     * The location for placign the program group. This is the same as the location (type) of a
     * shortcut, only that it applies to the program group. Note that there are only two locations
     * that make sense as location for a program group: <br>
     * applications start menu
     */
    private int groupLocation;

    /**
     * The parsed result from reading the XML specification from the file
     */
    private IXMLElement spec;

    /**
     * Set to true by analyzeShortcutSpec() if there are any desktop shortcuts to create.
     */
    private boolean hasDesktopShortcuts = false;

    /**
     * Tells wether to skip if the platform is not supported.
     */
    private boolean skipIfNotSupported = false;

    /**
     * Set 'true' to force current-user icons as default.
     */
    private boolean defaultCurrentUserFlag = false;

    /**
     * the one shortcut instance for reuse in many locations
     */
    private Shortcut shortcut;

    /**
     * A list of ShortcutData> objects. Each object is the complete specification for one shortcut
     * that must be created.
     */
    private Vector shortcuts = new Vector();

    /**
     * Holds a list of all the shortcut files that have been created. Note: this variable contains
     * valid data only after createShortcuts() has been called. This list is created so that the
     * files can be added to the uninstaller.
     */
    private Vector<String> files = new Vector<String>();

    /**
     * If true it indicates that there are shortcuts to create. The value is set by
     * analyzeShortcutSpec()
     */
    private boolean shortcutsToCreate = false;

    /**
     * If true it indicates that the spec file is existing and could be read.
     */
    private boolean haveShortcutSpec = false;

    /**
     * This is set to true if the shortcut spec instructs to simulate running on an operating system
     * that is not supported.
     */
    private boolean simulteNotSupported = false;

    /**
     * Avoids bogus behaviour when the user goes back then returns to this panel.
     */

    // private boolean firstTime = true;
    private File itsProgramFolder;

    /**
     * itsUserType
     */
    private int itsUserType;

    /**
     * USER_TYPE = "usertype" to store this information in the automated.xml
     */
    public final static String USER_TYPE = "usertype";

    /**
     * shortCuts
     */
    private Vector<String> shortCuts;

    /**
     * internal line counter
     */
    int line;

    /**
     * internal column counter
     */
    int col;

    // ~ Constructors ***********************************************************************

    // ~ Constructors ***********************************************************************

    /*
     * --------------------------------------------------------------------------
     */

    /**
     * Constructor.
     *
     * @param parent      reference to the application frame
     * @param installData shared information about the installation
     */

    /*
     * --------------------------------------------------------------------------
     */
    public ShortcutPanel(InstallerFrame parent, InstallData installData)
    {
        super(parent, installData, "link16x16");

        layout = (GridBagLayout) super.getLayout();
        Object con = getLayoutHelper().getDefaultConstraints();
        if (con instanceof GridBagConstraints)
        {
            constraints = (GridBagConstraints) con;
        }
        else
        {
            con = new GridBagConstraints();
        }
        setLayout(super.getLayout());

        if (self != null)
        {
            throw new RuntimeException(this.getClass().getName() + " is not allowed to instantiate more than once!");
        }

        self = this;
    }

    // ~ Methods ****************************************************************************

    // ~ Methods ****************************************************************************
    // **************************************************************************************************************************************************

    /*--------------------------------------------------------------------------*/

    /**
     * This method represents the ActionListener interface, invoked when an action occurs.
     *
     * @param event the action event.
     */

    /*--------------------------------------------------------------------------*/
    public void actionPerformed(ActionEvent event)
    {
        Object eventSource = event.getSource();

        /*
         * if (eventSource != null) { System.out.println("Instance Of : " +
         * eventSource.getClass().getName()); }
         */

        // ----------------------------------------------------
        // create shortcut for the current user was selected
        // refresh the list of program groups accordingly and
        // reset the program group to the default setting.
        // ----------------------------------------------------
        if (eventSource.equals(currentUser))
        {
            if (groupList != null)
            {
                groupList.setListData(shortcut.getProgramGroups(Shortcut.CURRENT_USER));
            }
            programGroup.setText(suggestedProgramGroup);
            shortcut.setUserType(itsUserType = Shortcut.CURRENT_USER);

        }

        // ----------------------------------------------------
        // create shortcut for all users was selected
        // refresh the list of program groups accordingly and
        // reset the program group to the default setting.
        // ----------------------------------------------------
        else if (eventSource.equals(allUsers))
        {
            if (groupList != null)
            {
                groupList.setListData(shortcut.getProgramGroups(Shortcut.ALL_USERS));
            }
            programGroup.setText(suggestedProgramGroup);
            shortcut.setUserType(itsUserType = Shortcut.ALL_USERS);

        }

        // ----------------------------------------------------
        // The reset button was pressed.
        // - clear the selection in the list box, because the
        // selection is no longer valid
        // - refill the program group edit control with the
        // suggested program group name
        // ----------------------------------------------------
        else if (eventSource.equals(defaultButton))
        {
            if (groupList != null && groupList.getSelectionModel() != null)
            {
                groupList.getSelectionModel().clearSelection();
            }
            programGroup.setText(suggestedProgramGroup);

        }

        // ----------------------------------------------------
        // the save button was pressed. This is a request to
        // save shortcut information to a text file.
        // ----------------------------------------------------
        else if (eventSource.equals(saveButton))
        {
            saveToFile();

            // add the file to the uninstaller
            addToUninstaller();

        }
        else if (eventSource.equals(createShortcuts))
        {
            create = createShortcuts.isSelected();

            if (groupList != null)
            {
                groupList.setEnabled(create);
            }

            programGroup.setEnabled(create);
            currentUser.setEnabled(create);
            defaultButton.setEnabled(create);

            // ** There where no Desktop Links or not allowed, this may be null: **//
            if (allowDesktopShortcut != null)
            {
                allowDesktopShortcut.setEnabled(create);
            }

            if (isRootUser)
            {
                allUsers.setEnabled(create);
            }
        }
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Returns true when all selections have valid settings. This indicates that it is legal to
     * procede to the next panel.
     *
     * @return true if it is legal to procede to the next panel, otherwise false.
     */

    /*--------------------------------------------------------------------------*/
    public boolean isValidated()
    {
        try
        {
            groupName = programGroup.getText();
        }
        catch (Throwable exception)
        {
            groupName = "";
        }

        create = createShortcuts.isSelected();

        if (createImmediately)
        {
            createAndRegisterShortcuts();
        }

        return (true);
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Called when the panel is shown to the user.
     */

    /*--------------------------------------------------------------------------*/
    public void panelActivate()
    {
        try
        {
            readShortcutSpec();
        }
        catch (Throwable exception)
        {
            System.out.println("could not read shortcut spec!");
            exception.printStackTrace();
        }

        // Create the UI elements
        try
        {
            shortcut = (Shortcut) (TargetFactory.getInstance()
                    .makeObject("com.izforge.izpack.util.os.Shortcut"));
            shortcut.initialize(Shortcut.APPLICATIONS, "-");
        }
        catch (Throwable exception)
        {
            System.out.println("could not create shortcut instance");
            exception.printStackTrace();
        }

        analyzeShortcutSpec();

        if (shortcutsToCreate && !OsVersion.IS_OSX)
        {
            if (shortcut.supported() && !simulteNotSupported)
            {
                File allUsersProgramsFolder = getProgramsFolder(Shortcut.ALL_USERS);

                Debug.log("All UsersProgramsFolder: '" + allUsersProgramsFolder + "'");

                File forceTest = new File(allUsersProgramsFolder + File.separator
                        + System.getProperty("user.name") + System.currentTimeMillis());

                try
                {
                    isRootUser = forceTest.createNewFile();
                }
                catch (Exception e)
                {
                    isRootUser = false;
                    Debug.log("IOException: " + "'" + e.getLocalizedMessage() + "'");
                    Debug.log("You cannot create '" + forceTest + "'");

                }

                if (forceTest.exists())
                {
                    Debug.log("Delete temporary File: '" + forceTest + "'");
                    forceTest.delete();
                }

                String perm = isRootUser ? "can" : "cannot";

                Debug.log("You " + perm + " write into '" + allUsersProgramsFolder + "'");

                final boolean rUserFlag;
                if (defaultCurrentUserFlag)
                {  //'defaultCurrentUser' element was specified
                    rUserFlag = false;
                    Debug.log("Element '" + SPEC_KEY_DEF_CUR_USER +
                                                         "' was specified");
                }
                else
                {  //'defaultCurrentUser' element not specified
                    rUserFlag = isRootUser;
                }

                if (rUserFlag)
                {
                    itsUserType = Shortcut.ALL_USERS;
                }
                else
                {
                    itsUserType = Shortcut.CURRENT_USER;
                }

                if (firstTime)
                {
                    buildUI(getProgramsFolder(rUserFlag ? Shortcut.ALL_USERS : Shortcut.CURRENT_USER));
                }

                // addSelectionList();
                // add( shortCutsArea );
                // JList shortCutList = null;
                // addList( shortCuts, ListSelectionModel.SINGLE_SELECTION, shortCutList, col,
                // line+6, 1, 1, GridBagConstraints.BOTH );
            }
            else
            {
                // TODO MEP: Test
                if (firstTime)
                {
                    buildAlternateUI();
                }

                // parent.unlockNextButton();
                // parent.lockPrevButton();
            }
            firstTime = false;
        }
        else
        {
            // Skip on OS X
            parent.skipPanel();
        }
    }

    /**
     * Returns the ProgramsFolder for the current User
     *
     * @param userType DOCUMENT ME!
     * @return The Basedir
     */
    private File getProgramsFolder(int userType)
    {
        String path = shortcut.getProgramsFolder(userType);

        return (new File(path));

        // }
        // else
        // {
        // TODO
        // 0ptional: Test if KDE is installed.
        // boolean isKdeInstalled = UnixHelper.kdeIsInstalled();
        // 1. Test if User can write into
        // File kdeRootShareApplinkDir = getKDERootShareApplinkDir();
        // if so: return getKDERootShareApplinkDir()
        // else
        // return getKDEUsersShareApplinkDir() +
        // }
        // return(result);
    }

    /**
     * This method is called by the groupList when the user makes a selection. It updates the
     * content of the programGroup with the result of the selection.
     *
     * @param event the list selection event
     */

    /*--------------------------------------------------------------------------*/
    public void valueChanged(ListSelectionEvent event)
    {
        if (programGroup == null)
        {
            return;
        }

        String value = "";

        try
        {
            value = (String) groupList.getSelectedValue();
        }
        catch (ClassCastException exception)
        {
        }

        if (value == null)
        {
            value = "";
        }

        programGroup.setText(value + File.separator + suggestedProgramGroup);
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Reads the XML specification for the shortcuts to create. The result is stored in spec.
     *
     * @throws Exception for any problems in reading the specification
     */

    /*--------------------------------------------------------------------------*/
    private void readShortcutSpec() throws Exception
    {
        // open an input stream
        InputStream input = null;

        try
        {
            input = ResourceManager.getInstance().getInputStream(TargetFactory.getCurrentOSPrefix() + SPEC_FILE_NAME);
        }
        catch (ResourceNotFoundException rnfE)
        {
            input = ResourceManager.getInstance().getInputStream(SPEC_FILE_NAME);
        }
        if (input == null)
        {
            haveShortcutSpec = false;

            return;
        }

        VariableSubstitutor substitutor = new VariableSubstitutor(idata.getVariables());

        // input.
        String substitutedSpec = substitutor.substitute(input, "xml");
        /*
         * TODO: internal flag mapped if( idata.isDebug() ) { System.out.println( "SUBSTITUDED
         * SHORTCUT SPEC" ); System.out.println(
         * "==================================================================" );
         * System.out.println( "==================================================================" );
         * System.out.println( substitutedSpec ); System.out.println(
         * "==================================================================" );
         * System.out.println( "==================================================================" ); }
         */
        IXMLParser parser = new XMLParser();

        // get the data
        spec = parser.parse(substitutedSpec);

        // close the stream
        input.close();
        haveShortcutSpec = true;
    }

    /*--------------------------------------------------------------------------*/

    /**
     * This method analyzes the specifications for creating shortcuts and builds a list of all the
     * Shortcuts that need to be created.
     */

    /*--------------------------------------------------------------------------*/
    private void analyzeShortcutSpec()
    {
        if (!haveShortcutSpec)
        {
            shortcutsToCreate = false;

            return;
        }

        IXMLElement skipper = spec.getFirstChildNamed(SPEC_KEY_SKIP_IFNOT_SUPPORTED);
        skipIfNotSupported = (skipper != null);

              //set flag if 'defaultCurrentUser' element found:
        defaultCurrentUserFlag =
                   (spec.getFirstChildNamed(SPEC_KEY_DEF_CUR_USER) != null);

        // ----------------------------------------------------
        // find out if we should simulate a not supported
        // scenario
        // ----------------------------------------------------
        IXMLElement support = spec.getFirstChildNamed(SPEC_KEY_NOT_SUPPORTED);

        if (support != null)
        {
            simulteNotSupported = true;
        }

        // ----------------------------------------------------
        // find out in which program group the shortcuts should
        // be placed and where this program group should be
        // located
        // ----------------------------------------------------

        IXMLElement group = null;
        Vector<IXMLElement> groupSpecs = spec.getChildrenNamed(SPEC_KEY_PROGRAM_GROUP);
        String selectedInstallGroup = idata.getVariable("INSTALL_GROUP");
        if (selectedInstallGroup != null)
        {
            //The user selected an InstallGroup before.
            //We may have some restrictions on the Installationgroup
            //search all defined ProgramGroups for the given InstallGroup
            for (IXMLElement g : groupSpecs)
            {
                String instGrp = g.getAttribute(SPEC_ATTRIBUTE_INSTALLGROUP);
                if (instGrp != null && selectedInstallGroup.equalsIgnoreCase(instGrp))
                {
                    group = g;
                    break;
                }
            }
        }
        if (group == null)
        {
            //default (old) behavior
            group = spec.getFirstChildNamed(SPEC_KEY_PROGRAM_GROUP);
        }

        String location = null;
        hasDesktopShortcuts = false;

        if (group != null)
        {
            suggestedProgramGroup = group.getAttribute(SPEC_ATTRIBUTE_DEFAULT_GROUP, "");
            programGroupIconFile = group.getAttribute("iconFile", "");
            programGroupComment = group.getAttribute("comment", "");
            location = group.getAttribute(SPEC_ATTRIBUTE_LOCATION, SPEC_VALUE_APPLICATIONS);
        }
        else
        {
            suggestedProgramGroup = "";
            location = SPEC_VALUE_APPLICATIONS;
        }

        if (location.equals(SPEC_VALUE_APPLICATIONS))
        {
            groupLocation = Shortcut.APPLICATIONS;
        }
        else if (location.equals(SPEC_VALUE_START_MENU))
        {
            groupLocation = Shortcut.START_MENU;
        }

        // ----------------------------------------------------
        // create a list of all shortcuts that need to be
        // created, containing all details about each shortcut
        // ----------------------------------------------------
        // String temp;
        Vector<IXMLElement> shortcutSpecs = spec.getChildrenNamed(SPEC_KEY_SHORTCUT);
        IXMLElement shortcutSpec;
        ShortcutData data;

        shortCuts = new Vector<String>();

        for (int i = 0; i < shortcutSpecs.size(); i++)
        {
            // System.out.println( "Processing shortcut: " + i );
            shortcutSpec = shortcutSpecs.elementAt(i);

            if (!OsConstraint.oneMatchesCurrentSystem(shortcutSpec))
            {
                continue;
            }

            Debug.log("Checking Condition for " + shortcutSpec.getAttribute(SPEC_ATTRIBUTE_NAME));
            if (!checkConditions(shortcutSpec))
            {
                continue;
            }

            Debug.log("Checked Condition for " + shortcutSpec.getAttribute(SPEC_ATTRIBUTE_NAME));
            data = new ShortcutData();

            data.name = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_NAME);
            data.subgroup = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_SUBGROUP, "");
            data.description = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_DESCRIPTION, "");

            // ** Linux **//
            data.deskTopEntryLinux_Encoding = shortcutSpec
                    .getAttribute(SPEC_ATTRIBUTE_ENCODING, "");
            data.deskTopEntryLinux_MimeType = shortcutSpec
                    .getAttribute(SPEC_ATTRIBUTE_MIMETYPE, "");
            data.deskTopEntryLinux_Terminal = shortcutSpec
                    .getAttribute(SPEC_ATTRIBUTE_TERMINAL, "");
            data.deskTopEntryLinux_TerminalOptions = shortcutSpec.getAttribute(
                    SPEC_ATTRIBUTE_TERMINAL_OPTIONS, "");
            data.deskTopEntryLinux_Type = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_TYPE, "");

            data.deskTopEntryLinux_URL = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_URL, "");

            data.deskTopEntryLinux_X_KDE_SubstituteUID = shortcutSpec.getAttribute(
                    SPEC_ATTRIBUTE_KDE_SUBST_UID, "false");

            data.deskTopEntryLinux_X_KDE_UserName = shortcutSpec.getAttribute(
                    SPEC_ATTRIBUTE_KDE_USERNAME, "root");

            data.Categories = shortcutSpec.getAttribute(
                    SPEC_CATEGORIES, "");

            data.TryExec = shortcutSpec.getAttribute(
                    SPEC_TRYEXEC, "");

            data.createForAll = Boolean.valueOf(shortcutSpec.getAttribute(CREATE_FOR_ALL, "false"));

            // ** EndOf LINUX **//
            // temp =
            data.target = fixSeparatorChar(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_TARGET, ""));

            // temp =
            data.commandLine = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_COMMAND, "");

            // temp =
            data.iconFile = fixSeparatorChar(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_ICON, ""));
            data.iconIndex = Integer.parseInt(shortcutSpec.getAttribute(SPEC_ATTRIBUTE_ICON_INDEX,
                    "0"));

            // temp =
            data.workingDirectory = fixSeparatorChar(shortcutSpec.getAttribute(
                    SPEC_ATTRIBUTE_WORKING_DIR, ""));

            String initialState = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_INITIAL_STATE, "");

            if (initialState.equals(SPEC_VALUE_NO_SHOW))
            {
                data.initialState = Shortcut.HIDE;
            }
            else if (initialState.equals(SPEC_VALUE_NORMAL))
            {
                data.initialState = Shortcut.NORMAL;
            }
            else if (initialState.equals(SPEC_VALUE_MAXIMIZED))
            {
                data.initialState = Shortcut.MAXIMIZED;
            }
            else if (initialState.equals(SPEC_VALUE_MINIMIZED))
            {
                data.initialState = Shortcut.MINIMIZED;
            }
            else
            {
                data.initialState = Shortcut.NORMAL;
            }

            // LOG System.out.println("data.initialState: " + data.initialState);

            // --------------------------------------------------
            // if the minimal data requirements are met to create
            // the shortcut, create one entry each for each of
            // the requested types.
            // Eventually this will cause the creation of one
            // shortcut in each of the associated locations.
            // --------------------------------------------------
            // without a name we can not create a shortcut
            if (data.name == null)
            {
                continue;
            }

            // 1. Elmar: "Without a target we can not create a shortcut."
            // 2. Marc: "No, Even on Linux a Link can be an URL and has no target."
            if (data.target == null)
            {
                // TODO: write log info INFO.warn( "Shortcut: " + data + " has no target" );
                data.target = "";
            }
            // the shortcut is not actually required for any of the selected packs

            // the shortcut is not actually required for any of the selected packs // the shortcut
            // is not actually required for any of the selected packs
            Vector<IXMLElement> forPacks = shortcutSpec.getChildrenNamed(SPEC_KEY_PACKS);

            if (!shortcutRequiredFor(forPacks))
            {
                continue;
            }
            // --------------------------------------------------
            // This section is executed if we don't skip.
            // --------------------------------------------------
            // For each of the categories set the type and if
            // the link should be placed in the program group,
            // then clone the data set to obtain an independent
            // instance and add this to the list of shortcuts
            // to be created. In this way, we will set up an
            // identical copy for each of the locations at which
            // a shortcut should be placed. Therefore you must
            // not use 'else if' statements!
            // --------------------------------------------------
            {
                if (XMLHelper.attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_DESKTOP))
                {
                    hasDesktopShortcuts = true;
                    data.addToGroup = false;
                    data.type = Shortcut.DESKTOP;
                    shortcuts.add(data.clone());
                }

                if (XMLHelper.attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_APPLICATIONS))
                {
                    data.addToGroup = false;
                    data.type = Shortcut.APPLICATIONS;
                    shortcuts.add(data.clone());
                }

                if (XMLHelper.attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_START_MENU))
                {
                    data.addToGroup = false;
                    data.type = Shortcut.START_MENU;
                    shortcuts.add(data.clone());
                }

                if (XMLHelper.attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_STARTUP))
                {
                    data.addToGroup = false;
                    data.type = Shortcut.START_UP;
                    shortcuts.add(data.clone());
                }

                if (XMLHelper.attributeIsTrue(shortcutSpec, SPEC_ATTRIBUTE_PROGRAM_GROUP))
                {
                    data.addToGroup = true;
                    data.type = Shortcut.APPLICATIONS;
                    shortcuts.add(data.clone());
                }

                // / TODO: write log INFO.info( "data.name: " + data.name );
                shortCuts.add((data.name == null) ? "" : data.name); // + " -> " + data.target +

                // " Type: " + data.type );
            }
        }

        // ----------------------------------------------------
        // signal if there are any shortcuts to create
        // ----------------------------------------------------
        if (shortcuts.size() > 0)
        {
            shortcutsToCreate = true;
        }
    }

    /**
     * This returns true if a Shortcut should or can be created. Returns false to suppress Creation
     *
     * @param shortcutSpec
     * @return true if condtion is resolved positive - currently unimplemented: returns always true.
     */
    private boolean checkConditions(IXMLElement shortcutSpec)
    {
        boolean result = true;
         String conditionid = shortcutSpec.getAttribute(SPEC_ATTRIBUTE_CONDITION);
         if (conditionid != null){
             result = this.parent.getRules().isConditionTrue(conditionid);
         }
//          Vector conditions = shortcutSpec.getChildrenNamed( Condition.CONDITION );
//          
//          for( int i = 0; i < conditions.size(); i++ ) { Condition condition = new Condition(
//          conditions.elementAt( i ) );
//          
//          //System.out.println( "Readed: " + condition.toString( true ) ); boolean result =
//          condition.eval();
//          
//          if( result == false ) { System.out.println( "Unresolved Condition: " + condition );
//          
//          return result; } }
         
        return result; // If there is no Condition defined, just create the shortcut.
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Enables Shortcutcreation from outside, e.g. from an InstallerListener.
     * The Installerlistener can switch the flag "createImmediately" to false on initialisation, and call this method when afterpacks is performed.
     * This makes only sense, if the ShorcutPanel is displayed before the files are copied onto the disk.
     */
    public void createAndRegisterShortcuts()
    {
        createShortcuts();
        addToUninstaller();
    }

    private String createXDGMenu(ArrayList shortcuts, String menuName)
    {
        String menuConfigText = "<Menu>\n" +
                "<Name>Applications</Name>\n" +
                "<Menu>\n" +
                // Ubuntu can't handle spaces, replace with "-"
                "<Directory>" + menuName.replaceAll(" ", "-") + "-izpack.directory</Directory>\n" +
                "<Name>" + menuName + "</Name>\n" +
                "<Include>\n";

        for (Object shortcut1 : shortcuts)
        {
            String shortcutFile = (String) shortcut1;
            menuConfigText += "<Filename>" + shortcutFile + "</Filename>\n";
        }
        menuConfigText += "</Include>\n</Menu>\n</Menu>";
        return menuConfigText;

    }

    private String createXDGDirectory(String menuName, String icon, String comment)
    {
        String menuDirectoryDescriptor = "[Desktop Entry]\n" +
                "Name=$Name\n" +
                "Comment=$Comment\n" +
                "Icon=$Icon\n" +
                "Type=Directory\n" +
                "Encoding=UTF-8";
        menuDirectoryDescriptor =
                StringTool.replace(menuDirectoryDescriptor, "$Name", menuName);
        menuDirectoryDescriptor =
                StringTool.replace(menuDirectoryDescriptor, "$Comment", comment);
        menuDirectoryDescriptor =
                StringTool.replace(menuDirectoryDescriptor, "$Icon", icon);
        return menuDirectoryDescriptor;
    }

    private void writeXDGMenuFile(ArrayList desktopFileNames, String groupName, String icon, String comment)
    {
        if ("".equals(suggestedProgramGroup) || suggestedProgramGroup == null)
        {
            return; // No group name means the shortcuts
        }
        // will be placed by category
        if (OsVersion.IS_UNIX)
        {
            String menuFile = createXDGMenu(desktopFileNames, groupName);
            String dirFile = createXDGDirectory(groupName, icon, comment);
            String menuFolder;
            String directoryFolder;
            if (itsUserType == Shortcut.ALL_USERS)
            {
                menuFolder = "/etc/xdg/menus/applications-merged/";
                directoryFolder = "/usr/share/desktop-directories/";
            }
            else
            {
                menuFolder = System.getProperty("user.home") + File.separator
                        + ".config/menus/applications-merged/";
                directoryFolder = System.getProperty("user.home") + File.separator
                        + ".local/share/desktop-directories/";
            }
            File menuFolderFile = new File(menuFolder);
            File directoryFolderFile = new File(directoryFolder);
            String menuFilePath = menuFolder + groupName + ".menu";
            // Ubuntu can't handle spaces in the directory file name
            String dirFilePath = directoryFolder + groupName.replaceAll(" ", "-") + "-izpack.directory";
            menuFolderFile.mkdirs();
            directoryFolderFile.mkdirs();
            writeString(menuFile, menuFilePath);
            writeString(dirFile, dirFilePath);
        }


    }

    private void writeString(String str, String file)
    {
        boolean failed = false;
        try
        {
            FileWriter writer = new FileWriter(file);
            writer.write(str);
            writer.close();
        }
        catch (Exception ignore)
        {
            failed = true;
            Debug.log("Failed to create menu for gnome.");
        }
        if (!failed)
        {
            UninstallData.getInstance().addFile(file, true);
        }
    }
    /*--------------------------------------------------------------------------*/

    /**
     * Creates all shortcuts based on the information in shortcuts.
     */

    /*--------------------------------------------------------------------------*/
    private void createShortcuts()
    {
        if (!create)
        {
            Debug.log(this.getClass().getName() + "::createShortcuts():create=" + create);
            return;
        }

        ShortcutData data;

        //fix: don't influence other shortcuts when altering group name...
        String gn = groupName;
        setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );

        progressbar = new JProgressBar( JProgressBar.HORIZONTAL, 0,shortcuts.size() );

        constraints.gridx = col ;
        constraints.gridy = line + 7;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;
        constraints.fill = GridBagConstraints.BOTH;
        layout.addLayoutComponent(progressbar, constraints);
        add(progressbar);
        invalidate();

        progressbar.setStringPainted(true);
        invalidate();

        ArrayList startMenuShortcuts = new ArrayList();
        for (int i = 0; i < shortcuts.size(); i++)
        {
            data = (ShortcutData) shortcuts.elementAt(i);

            progressbar.setString( "create " + data.name + " [" + data.description + "]" );

            try
            {
                gn = groupName + data.subgroup;
                shortcut.setUserType(itsUserType);
                shortcut.setLinkName(data.name);
                shortcut.setLinkType(data.type);
                shortcut.setArguments(data.commandLine);
                shortcut.setDescription(data.description);
                shortcut.setIconLocation(data.iconFile, data.iconIndex);

                shortcut.setShowCommand(data.initialState);
                shortcut.setTargetPath(data.target);
                shortcut.setWorkingDirectory(data.workingDirectory);
                shortcut.setEncoding(data.deskTopEntryLinux_Encoding);
                shortcut.setMimetype(data.deskTopEntryLinux_MimeType);

                shortcut.setTerminal(data.deskTopEntryLinux_Terminal);
                shortcut.setTerminalOptions(data.deskTopEntryLinux_TerminalOptions);
                shortcut.setType(data.deskTopEntryLinux_Type);
                shortcut.setKdeSubstUID(data.deskTopEntryLinux_X_KDE_SubstituteUID);
                shortcut.setKdeUserName(data.deskTopEntryLinux_X_KDE_UserName);
                shortcut.setURL(data.deskTopEntryLinux_URL);
                shortcut.setTryExec(data.TryExec);
                shortcut.setCategories(data.Categories);
                shortcut.setCreateForAll(data.createForAll);

                shortcut.setUninstaller(UninstallData.getInstance());

                if (data.addToGroup)
                {
                    shortcut.setProgramGroup(gn);
                }
                else
                {
                    shortcut.setProgramGroup("");
                }

                try
                {
                    // ----------------------------------------------
                    // save the shortcut only if it is either not on
                    // the desktop or if it is on the desktop and
                    // the user has signalled that it is ok to place
                    // shortcuts on the desktop.
                    // ----------------------------------------------
                    if ((data.type != Shortcut.DESKTOP)
                            || ((data.type == Shortcut.DESKTOP) && allowDesktopShortcut
                            .isSelected()))
                    {

                        // save the shortcut
                        shortcut.save();

                        if (data.type == Shortcut.APPLICATIONS || data.addToGroup)
                        {
                            if (shortcut instanceof com.izforge.izpack.util.os.Unix_Shortcut)
                            {
                                com.izforge.izpack.util.os.Unix_Shortcut unixcut =
                                        (com.izforge.izpack.util.os.Unix_Shortcut) shortcut;
                                Object f = unixcut.getWrittenFileName();
                                if (f != null)
                                {
                                    startMenuShortcuts.add(f);
                                }
                            }
                        }
                        // add the file and directory name to the file list
                        String fileName = shortcut.getFileName();
                        files.add(0, fileName);

                        File file = new File(fileName);
                        File base = new File(shortcut.getBasePath());
                        Vector<File> intermediates = new Vector<File>();

                        // String directoryName = shortcut.getDirectoryCreated ();
                        execFiles.add(new ExecutableFile(fileName, ExecutableFile.UNINSTALL,
                                ExecutableFile.IGNORE, new ArrayList<OsConstraint>(), false));

                        files.add(fileName);

                        while ((file = file.getParentFile()) != null)
                        {
                            if (file.equals(base))
                            {
                                break;
                            }

                            intermediates.add(file);
                        }

                        if (file != null)
                        {
                            Enumeration<File> filesEnum = intermediates.elements();

                            while (filesEnum.hasMoreElements())
                            {
                                files.add(0, filesEnum.nextElement().toString());
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                }
            }
            catch (Throwable exception)
            {
            }
            progressbar.setValue( i );
            invalidate();
        }
        if (OsVersion.IS_UNIX)
        {
            writeXDGMenuFile(startMenuShortcuts,
                    groupName, programGroupIconFile, programGroupComment);
        }
        shortcut.execPostAction();

        try
        {
            if (execFiles != null)
            {
                FileExecutor executor = new FileExecutor(execFiles);

                // 
                // TODO: Hi Guys,
                // TODO The following commented-out line sometimes produces an uncatchable
                // nullpointer Exception!
                // TODO evaluate for what reason the files should exec.
                // TODO if there is a serious explanation, why to do that,
                // TODO the code must be more robust
                // evaluate executor.executeFiles( ExecutableFile.NEVER, null );
            }
        }
        catch (NullPointerException nep)
        {
            nep.printStackTrace();
        }
        catch (RuntimeException cannot)
        {
            cannot.printStackTrace();
        }


        shortcut.cleanUp();
        setCursor( Cursor.getDefaultCursor() );
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Verifies if the shortcut is required for any of the packs listed. The shortcut is required
     * for a pack in the list if that pack is actually selected for installation. Note: If the list
     * of selected packs is empty then true is always returnd. The same is true if the packs list is
     * empty.
     *
     * @param packs a Vector of Strings. Each of the strings denotes a pack for which the schortcut
     *              should be created if the pack is actually installed.
     * @return true if the shortcut is required for at least on pack in the list, otherwise returns
     *         false.
     */

    /*--------------------------------------------------------------------------*/
    /*
     * $ @design
     * 
     * The information about the installed packs comes from InstallData.selectedPacks. This assumes
     * that this panel is presented to the user AFTER the PacksPanel.
     * --------------------------------------------------------------------------
     */
    private boolean shortcutRequiredFor(Vector<IXMLElement> packs)
    {
        String selected;
        String required;

        if (packs.size() == 0)
        {
            return (true);
        }

        for (int i = 0; i < idata.selectedPacks.size(); i++)
        {
            selected = ((Pack) idata.selectedPacks.get(i)).name;

            for (int k = 0; k < packs.size(); k++)
            {
                required = (packs.elementAt(k)).getAttribute(
                        SPEC_ATTRIBUTE_NAME, "");

                if (selected.equals(required))
                {
                    return (true);
                }
            }
        }

        return (false);
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Replaces any ocurrence of '/' or '\' in a path string with the correct version for the
     * operating system.
     *
     * @param path a system path
     * @return a path string that uniformely uses the proper version of the separator character.
     */

    /*--------------------------------------------------------------------------*/
    private String fixSeparatorChar(String path)
    {
        String newPath = path.replace('/', File.separatorChar);
        newPath = newPath.replace('\\', File.separatorChar);

        return (newPath);
    }

    /*--------------------------------------------------------------------------*/

    /**
     * This method creates the UI for this panel.
     *
     * @param groups A Vector that contains Strings with all the names of the existing program
     *               groups. These will be placed in the groupList.
     */

    /*--------------------------------------------------------------------------*/
    private void buildUI(File groups)
    {
        constraints.insets = new Insets(10, 10, 0, 0);

        // Add a CheckBox which enables the user to entirely supress shortcut creation.
        String menuKind = parent.langpack.getString("ShortcutPanel.regular.StartMenu:Start-Menu");

        if (OsVersion.IS_UNIX && UnixHelper.kdeIsInstalled())
        {
            menuKind = parent.langpack.getString("ShortcutPanel.regular.StartMenu:K-Menu");
        }

        createShortcuts = new JCheckBox(StringTool.replace(parent.langpack
                .getString("ShortcutPanel.regular.create"), "StartMenu", menuKind), true);
        createShortcuts.addActionListener(this);
        constraints.gridx = col;
        constraints.gridy = line + 1;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;

        // constraints.weightx = 0.1;
        // constraints.weighty = 0.2;
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.anchor = GridBagConstraints.NORTHWEST;

        layout.addLayoutComponent(createShortcuts, constraints);
        add(createShortcuts);

        constraints.insets = new Insets(0, 10, 0, 0);

        // ----------------------------------------------------
        // check box to allow the user to decide if a desktop
        // shortcut should be created.
        // this should only be created if needed and requested
        // in the definition file.
        // ----------------------------------------------------
        if (hasDesktopShortcuts)
        {
            String initialAllowedValue = idata.getVariable("DesktopShortcutCheckboxEnabled");
            boolean initialAllowedFlag = false;

            if (initialAllowedValue == null)
            {
                initialAllowedFlag = false;
            }
            else if (Boolean.TRUE.toString().equals(initialAllowedValue))
            {
                initialAllowedFlag = true;
            }

            allowDesktopShortcut = new JCheckBox(parent.langpack
                    .getString("ShortcutPanel.regular.desktop"), initialAllowedFlag);
            constraints.gridx = col;
            constraints.gridy = line + 2;
            constraints.gridwidth = 1;
            constraints.gridheight = 1;

            // constraints.weighty = 0.2;
            // constraints.weighty = 1.0;
            // constraints.weighty = 0.5;
            layout.addLayoutComponent(allowDesktopShortcut, constraints);
            add(allowDesktopShortcut);
        }

        listLabel = LabelFactory.create(parent.langpack.getString("ShortcutPanel.regular.list"),
                JLabel.LEADING);
        if (OsVersion.IS_WINDOWS)
        {
            constraints.gridx = col;
            constraints.gridy = line + 3;

            constraints.gridwidth = 1;
            constraints.gridheight = 1;

            constraints.insets = new Insets(10, 10, 0, 0);

            constraints.fill = GridBagConstraints.HORIZONTAL;
            constraints.anchor = GridBagConstraints.NORTHWEST;
        }
        else
        {
            constraints.gridx = col;
            constraints.gridy = line + 4;

            constraints.gridwidth = 1;
            constraints.gridheight = 1;

            constraints.insets = new Insets(10, 10, 0, 0);

            constraints.fill = GridBagConstraints.HORIZONTAL;
            constraints.anchor = GridBagConstraints.SOUTHWEST;
        }
        layout.addLayoutComponent(listLabel, constraints);
        add(listLabel);

        // ----------------------------------------------------
        // list box to list all of already existing folders as program groups
        // at the intended destination
        // ----------------------------------------------------
        Vector<String> dirEntries = new Vector<String>();

        File[] entries = groups.listFiles();

        // Quickfix prevent NullPointer on non default compliant Linux - KDEs
        // i.e Mandrake 2005 LE stores from now also in "applnk" instead in prior "applnk-mdk":
        if (entries != null && !OsVersion.IS_UNIX)
        {
            for (File entry : entries)
            {
                if (entry.isDirectory())
                {
                    dirEntries.add(entry.getName());
                }
            }
        }
        if (OsVersion.IS_WINDOWS)
        {
            if (groupList == null)
            {
                groupList = new JList();
            }

            groupList = addList(dirEntries, ListSelectionModel.SINGLE_SELECTION, groupList, col,
                    line + 4, 1, 1, GridBagConstraints.BOTH);
        }

        // ----------------------------------------------------
        // radio buttons to select current user or all users.
        // ----------------------------------------------------
        if (shortcut.multipleUsers())
        {
              //if 'defaultCurrentUser' specified, default to current user:
            final boolean rUserFlag = defaultCurrentUserFlag ? false :
                                                                 isRootUser;

            JPanel usersPanel = new JPanel(new GridLayout(2, 1));
            ButtonGroup usersGroup = new ButtonGroup();
            currentUser = new JRadioButton(parent.langpack
                    .getString("ShortcutPanel.regular.currentUser"), !rUserFlag);
            currentUser.addActionListener(this);
            usersGroup.add(currentUser);
            usersPanel.add(currentUser);
            allUsers = new JRadioButton(
                    parent.langpack.getString("ShortcutPanel.regular.allUsers"), rUserFlag);

            Debug.log("allUsers.setEnabled(), I'm Root: " + isRootUser);

            allUsers.setEnabled(isRootUser);

            allUsers.addActionListener(this);
            usersGroup.add(allUsers);
            usersPanel.add(allUsers);

            TitledBorder border = new TitledBorder(new EmptyBorder(2, 2, 2, 2), parent.langpack
                    .getString("ShortcutPanel.regular.userIntro"));
            usersPanel.setBorder(border);
            if (OsVersion.IS_WINDOWS)
            {
                constraints.gridx = col + 1;
                constraints.gridy = line + 4;
                constraints.gridwidth = 1;
                constraints.gridheight = 1;
            }
            else
            {
                constraints.insets = new Insets(10, 10, 20, 0);
                constraints.gridx = col;
                constraints.gridy = line + 4;
                constraints.gridwidth = 2;
                constraints.gridheight = 1;
                constraints.anchor = GridBagConstraints.EAST;
            }

            // constraints.weighty = 1.0;
            // constraints.weightx = 1.0;
            constraints.fill = GridBagConstraints.HORIZONTAL;
            layout.addLayoutComponent(usersPanel, constraints);
            add(usersPanel);
        }

        // ----------------------------------------------------
        // edit box that contains the suggested program group
        // name, which can be modfied or substituted from the
        // list by the user
        // ----------------------------------------------------
        programGroup = new JTextField(suggestedProgramGroup, 40); // 40?

        constraints.gridx = col;
        constraints.gridy = line + 5;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;

        // constraints.weighty = 1.0;
        // constraints.weightx = 1.0;
        constraints.fill = GridBagConstraints.HORIZONTAL;
        layout.addLayoutComponent(programGroup, constraints);
        add(programGroup);

        // ----------------------------------------------------
        // reset button that allows the user to revert to the
        // original suggestion for the program group
        // ----------------------------------------------------
        defaultButton = ButtonFactory.createButton(parent.langpack
                .getString("ShortcutPanel.regular.default"), idata.buttonsHColor);
        defaultButton.addActionListener(this);

        constraints.gridx = col + 1;
        constraints.gridy = line + 5;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;
        constraints.fill = GridBagConstraints.HORIZONTAL;
        layout.addLayoutComponent(defaultButton, constraints);
        add(defaultButton);

        if (suggestedProgramGroup == null || "".equals(suggestedProgramGroup))
        {
            programGroup.setVisible(false);
            defaultButton.setVisible(false);
            listLabel.setVisible(false);
        }
    }

    /**
     * Adds the grouplist to the panel
     *
     * @param Entries     the entries to display
     * @param ListModel   the model to use
     * @param aJList      the JList to use
     * @param aGridx      The X position in the gridbag layout.
     * @param aGridy      The Y position in the gridbag layout.
     * @param aGridwidth  the gridwith to use in the gridbag layout.
     * @param aGridheight the gridheight to use in the gridbag layout.
     * @param aFill       the FILL to use in the gridbag layout.
     * @return the filled JList
     */
    private JList addList(Vector<String> Entries, int ListModel, JList aJList, int aGridx, int aGridy,
                          int aGridwidth, int aGridheight, int aFill)
    {
        if (aJList == null)
        {
            aJList = new JList(Entries);
        }
        else
        {
            aJList.setListData(Entries);
        }

        aJList.setSelectionMode(ListModel);
        aJList.getSelectionModel().addListSelectionListener(this);

        JScrollPane scrollPane = new JScrollPane(aJList);

        constraints.gridx = aGridx;
        constraints.gridy = aGridy;
        constraints.gridwidth = aGridwidth;
        constraints.gridheight = aGridheight;
        constraints.weightx = 2.0;
        constraints.weighty = 1.5;
        constraints.insets = new Insets(5, 5, 5, 5);
        constraints.fill = aFill;
        layout.addLayoutComponent(scrollPane, constraints);
        add(scrollPane);

        return aJList;
    }

    /**
     * This method creates an alternative UI for this panel. This UI can be used when the creation
     * of shortcuts is not supported on the target system. It displays an apology for the inability
     * to create shortcuts on this system, along with information about the intended targets. In
     * addition, there is a button that allows the user to save more complete information in a text
     * file. Based on this information the user might be able to create the necessary shortcut him
     * or herself. At least there will be information about how to launch the application.
     */

    /*--------------------------------------------------------------------------*/
    private void buildAlternateUI()
    {
        layout = new GridBagLayout();
        constraints = new GridBagConstraints();
        setLayout(layout);

        // ----------------------------------------------------
        // static text a the top of the panel, that apologizes
        // about the fact that we can not create shortcuts on
        // this particular target OS.
        // ----------------------------------------------------
        MultiLineLabel apologyLabel = new MultiLineLabel(parent.langpack
                .getString("ShortcutPanel.alternate.apology"), 0, 0);

        constraints.gridx = 0;
        constraints.gridy = 0;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;
        constraints.weightx = 1.0;
        constraints.weighty = 1.0;
        constraints.insets = new Insets(5, 5, 5, 5);
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.anchor = GridBagConstraints.WEST;
        layout.addLayoutComponent(apologyLabel, constraints);
        add(apologyLabel);

        // ----------------------------------------------------
        // label that explains the significance ot the list box
        // ----------------------------------------------------
        MultiLineLabel listLabel = new MultiLineLabel(parent.langpack
                .getString("ShortcutPanel.alternate.targetsLabel"), 0, 0);

        constraints.gridx = 0;
        constraints.gridy = 1;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;
        constraints.weightx = 1.0;
        constraints.weighty = 1.0;
        layout.addLayoutComponent(listLabel, constraints);
        add(listLabel);

        // ----------------------------------------------------
        // list box to list all of the intended shortcut targets
        // ----------------------------------------------------
        Vector<String> targets = new Vector<String>();

        for (int i = 0; i < shortcuts.size(); i++)
        {
            targets.add(((ShortcutData) shortcuts.elementAt(i)).target);
        }

        targetList = new JList(targets);

        JScrollPane scrollPane = new JScrollPane(targetList);

        constraints.gridx = 0;
        constraints.gridy = 2;
        constraints.fill = GridBagConstraints.BOTH;
        layout.addLayoutComponent(scrollPane, constraints);
        add(scrollPane);

        // ----------------------------------------------------
        // static text that explains about the text file
        // ----------------------------------------------------
        MultiLineLabel fileExplanation = new MultiLineLabel(parent.langpack
                .getString("ShortcutPanel.alternate.textFileExplanation"), 0, 0);

        constraints.gridx = 0;
        constraints.gridy = 3;
        constraints.weightx = 1.0;
        constraints.weighty = 1.0;
        constraints.fill = GridBagConstraints.HORIZONTAL;
        layout.addLayoutComponent(fileExplanation, constraints);
        add(fileExplanation);

        // ----------------------------------------------------
        // button to save the text file
        // ----------------------------------------------------
        saveButton = ButtonFactory.createButton(parent.langpack
                .getString("ShortcutPanel.alternate.saveButton"), idata.buttonsHColor);
        saveButton.addActionListener(this);

        constraints.gridx = 0;
        constraints.gridy = 4;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;
        constraints.fill = GridBagConstraints.NONE;
        constraints.anchor = GridBagConstraints.CENTER;
        layout.addLayoutComponent(saveButton, constraints);
        add(saveButton);
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Overriding the superclass implementation. This method returns the size of the container.
     *
     * @return the size of the container
     */

    /*--------------------------------------------------------------------------*/
    public Dimension getSize()
    {
        Dimension size = getParent().getSize();
        Insets insets = getInsets();
        Border border = getBorder();
        Insets borderInsets = new Insets(0, 0, 0, 0);

        if (border != null)
        {
            borderInsets = border.getBorderInsets(this);
        }

        size.height = size.height - insets.top - insets.bottom - borderInsets.top
                - borderInsets.bottom - 50;
        size.width = size.width - insets.left - insets.right - borderInsets.left
                - borderInsets.right - 50;

        return (size);
    }

    /*--------------------------------------------------------------------------*/

    /**
     * This method saves all shortcut information to a text file.
     */

    /*--------------------------------------------------------------------------*/
    private void saveToFile()
    {
        File file = null;

        // ----------------------------------------------------
        // open a file chooser dialog to get a path / file name
        // ----------------------------------------------------
        JFileChooser fileDialog = new JFileChooser(idata.getInstallPath());
        fileDialog.setSelectedFile(new File(TEXT_FILE_NAME));

        if (fileDialog.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
        {
            file = fileDialog.getSelectedFile();
        }
        else
        {
            return;
        }

        // ----------------------------------------------------
        // save to the file
        // ----------------------------------------------------
        FileWriter output = null;
        StringBuffer buffer = new StringBuffer();
        String header = parent.langpack.getString("ShortcutPanel.textFile.header");

        String newline = System.getProperty("line.separator", "\n");

        try
        {
            output = new FileWriter(file);
        }
        catch (Throwable exception)
        {
            // !!! show an error dialog
            return;
        }

        // ----------------------------------------------------
        // break the header down into multiple lines based
        // on '\n' line breaks.
        // ----------------------------------------------------
        int nextIndex = 0;
        int currentIndex = 0;

        do
        {
            nextIndex = header.indexOf("\\n", currentIndex);

            if (nextIndex > -1)
            {
                buffer.append(header.substring(currentIndex, nextIndex));
                buffer.append(newline);
                currentIndex = nextIndex + 2;
            }
            else
            {
                buffer.append(header.substring(currentIndex, header.length()));
                buffer.append(newline);
            }
        }
        while (nextIndex > -1);

        buffer.append(SEPARATOR_LINE);
        buffer.append(newline);
        buffer.append(newline);

        for (int i = 0; i < shortcuts.size(); i++)
        {
            ShortcutData data = (ShortcutData) shortcuts.elementAt(i);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.name"));
            buffer.append(data.name);
            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.location"));

            switch (data.type)
            {
                case Shortcut.DESKTOP:
                {
                    buffer.append(parent.langpack.getString("ShortcutPanel.location.desktop"));

                    break;
                }

                case Shortcut.APPLICATIONS:
                {
                    buffer.append(parent.langpack.getString("ShortcutPanel.location.applications"));

                    break;
                }

                case Shortcut.START_MENU:
                {
                    buffer.append(parent.langpack.getString("ShortcutPanel.location.startMenu"));

                    break;
                }

                case Shortcut.START_UP:
                {
                    buffer.append(parent.langpack.getString("ShortcutPanel.location.startup"));

                    break;
                }
            }

            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.description"));
            buffer.append(data.description);
            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.target"));
            buffer.append(data.target);
            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.command"));
            buffer.append(data.commandLine);
            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.iconName"));
            buffer.append(data.iconFile);
            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.iconIndex"));
            buffer.append(data.iconIndex);
            buffer.append(newline);

            buffer.append(parent.langpack.getString("ShortcutPanel.textFile.work"));
            buffer.append(data.workingDirectory);
            buffer.append(newline);

            buffer.append(newline);
            buffer.append(SEPARATOR_LINE);
            buffer.append(newline);
            buffer.append(newline);
        }

        try
        {
            output.write(buffer.toString());
        }
        catch (Throwable exception)
        {
        }
        finally
        {
            try
            {
                output.flush();
                output.close();
                files.add(file.getPath());
            }
            catch (Throwable exception)
            {
                // not really anything I can do here, maybe should show a dialog that
                // tells the user that data might not have been saved completely!?
            }
        }
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Adds all files and directories to the uninstaller.
     */

    /*--------------------------------------------------------------------------*/
    private void addToUninstaller()
    {
        UninstallData uninstallData = UninstallData.getInstance();

        for (int i = 0; i < files.size(); i++)
        {
            uninstallData.addFile(files.elementAt(i), true);
        }
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Returns Instance of themself
     */
    public static ShortcutPanel getInstance()
    {
        return self;
    }

    /*--------------------------------------------------------------------------*/
    /*
     * 
     * 
     * The information needed to create shortcuts has been collected in the Vector 'shortcuts'. Take
     * the data from there and package it in XML form for storage by the installer. The group name
     * is only stored once in a separate XML element, since there is only one.
     * --------------------------------------------------------------------------
     */
    public void makeXMLData(IXMLElement panelRoot)
    {
        // ----------------------------------------------------
        // if there are no shortcuts to create, shortcuts are
        // not supported, or we should simulate that they are
        // not supported, then we have nothing to add. Just
        // return
        // ----------------------------------------------------
        Debug.log("entering makeXMLData");


        if (!shortcutsToCreate || !shortcut.supported() || (groupName == null)
                || simulteNotSupported || !create)
        {
            Debug.log("abort makeXMLData!");
            return;
        }

        ShortcutData data;
        IXMLElement dataElement;

        // ----------------------------------------------------
        // add the item that defines the name of the program group
        // ----------------------------------------------------
        dataElement = new XMLElementImpl(AUTO_KEY_PROGRAM_GROUP,panelRoot);
        dataElement.setAttribute(AUTO_ATTRIBUTE_NAME, groupName);
        panelRoot.addChild(dataElement);

        // ----------------------------------------------------
        // add the details for each of the shortcuts
        // ----------------------------------------------------
        for (int i = 0; i < shortcuts.size(); i++)
        {
            Debug.log("entering makeXMLData");
            data = (ShortcutData) shortcuts.elementAt(i);
            dataElement = new XMLElementImpl(AUTO_KEY_SHORTCUT,panelRoot);

            dataElement.setAttribute(AUTO_ATTRIBUTE_NAME, data.name);
            dataElement.setAttribute(AUTO_ATTRIBUTE_GROUP, (data.addToGroup ? Boolean.TRUE
                    : Boolean.FALSE).toString());

            // Boolean.valueOf(data.addToGroup)
            if (OsVersion.IS_WINDOWS)

            {
                dataElement.setAttribute(AUTO_ATTRIBUTE_TYPE, Integer.toString(data.type));
            }
            dataElement.setAttribute(AUTO_ATTRIBUTE_COMMAND, data.commandLine);
            dataElement.setAttribute(AUTO_ATTRIBUTE_DESCRIPTION, data.description);
            dataElement.setAttribute(AUTO_ATTRIBUTE_ICON, data.iconFile);
            dataElement.setAttribute(AUTO_ATTRIBUTE_ICON_INDEX, Integer.toString(data.iconIndex));
            dataElement.setAttribute(AUTO_ATTRIBUTE_INITIAL_STATE, Integer
                    .toString(data.initialState));
            dataElement.setAttribute(AUTO_ATTRIBUTE_TARGET, data.target);
            dataElement.setAttribute(AUTO_ATTRIBUTE_WORKING_DIR, data.workingDirectory);


            dataElement.setAttribute(SPEC_ATTRIBUTE_ENCODING, data.deskTopEntryLinux_Encoding);
            dataElement.setAttribute(SPEC_ATTRIBUTE_MIMETYPE, data.deskTopEntryLinux_MimeType);
            dataElement.setAttribute(SPEC_ATTRIBUTE_TERMINAL, data.deskTopEntryLinux_Terminal);
            dataElement.setAttribute(SPEC_ATTRIBUTE_TERMINAL_OPTIONS, data.deskTopEntryLinux_TerminalOptions);
            if (!OsVersion.IS_WINDOWS)
            {
                dataElement.setAttribute(SPEC_ATTRIBUTE_TYPE, data.deskTopEntryLinux_Type);
            }

            dataElement.setAttribute(SPEC_ATTRIBUTE_URL, data.deskTopEntryLinux_URL);

            dataElement.setAttribute(SPEC_ATTRIBUTE_KDE_SUBST_UID, data.deskTopEntryLinux_X_KDE_SubstituteUID);
            dataElement.setAttribute(SPEC_CATEGORIES, data.Categories);
            dataElement.setAttribute(SPEC_TRYEXEC, data.TryExec);

            dataElement.setAttribute(CREATE_FOR_ALL, data.createForAll.toString());// ? Boolean.TRUE : Boolean.FALSE).toString() );
            dataElement.setAttribute(USER_TYPE, Integer.toString(data.userType));

            //TODO: Add Linux.Attibutes

            // ----------------------------------------------
            // add the shortcut only if it is either not on
            // the desktop or if it is on the desktop and
            // the user has signalled that it is ok to place
            // shortcuts on the desktop.
            // ----------------------------------------------
            if ((data.type != Shortcut.DESKTOP)
                    || ((data.type == Shortcut.DESKTOP) && allowDesktopShortcut.isSelected()))
            {
                panelRoot.addChild(dataElement);
            }
        }
    }

    /*--------------------------------------------------------------------------*/

    /**
     * Creates shortcuts based on teh information in panelRoot without UI.
     *
     * @param panelRoot the root of the XML tree
     */

    /*--------------------------------------------------------------------------*/
    /*
     * 
     * 
     * Reconstitute the information needed to create shortcuts from XML data that was previously
     * stored by the installer through makeXMLData(). Create a new Vector containing this data and
     * stroe it in 'shortcuts' for use by createShortcuts(). Once this has been completed, call
     * createShortcuts() to complete the operation.
     * --------------------------------------------------------------------------
     */


}

/*---------------------------------------------------------------------------*/
