001/*
002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved.
003 * 
004 * http://www.izforge.com/izpack/
005 * http://developer.berlios.de/projects/izpack/
006 * 
007 * Copyright 2002 Elmar Grom
008 * 
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *     http://www.apache.org/licenses/LICENSE-2.0
014 *     
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 */
021
022package com.izforge.izpack.util.os;
023
024import java.io.File;
025import java.io.UnsupportedEncodingException;
026import java.util.Vector;
027
028import com.izforge.izpack.util.Debug;
029import com.izforge.izpack.util.StringTool;
030
031/*---------------------------------------------------------------------------*/
032/**
033 * This is the Microsoft Windows specific implementation of <code>Shortcut</code>.
034 * 
035 * @version 0.0.1 / 3/4/02
036 * @author Elmar Grom
037 */
038/*---------------------------------------------------------------------------*/
039public class Win_Shortcut extends Shortcut 
040{
041
042    // ------------------------------------------------------------------------
043    // Constant Definitions
044    // ------------------------------------------------------------------------
045
046    // ------------------------------------------------------------------------
047    // Variable Declarations
048    // ------------------------------------------------------------------------
049    private ShellLink shortcut;
050    
051    private static String myClass = Win_Shortcut.class.getName() + ": ";
052    
053    private static final String CLASS = "Class: ";
054
055    /** SUPPORTED = true */
056    private static final boolean SUPPORTED = true;
057
058    /*--------------------------------------------------------------------------*/
059    /**
060     * This method initializes the object. It is used as a replacement for the constructor because
061     * of the way it is instantiated through the <code>TargetFactory</code>.
062     * 
063     * @param type the type or classification of the program group in which the link should exist.
064     * The following types are recognized: <br>
065     * <ul>
066     * <li>{@link com.izforge.izpack.util.os.Shortcut#APPLICATIONS}
067     * <li>{@link com.izforge.izpack.util.os.Shortcut#START_MENU}
068     * <li>{@link com.izforge.izpack.util.os.Shortcut#DESKTOP}
069     * <li>{@link com.izforge.izpack.util.os.Shortcut#START_UP}
070     * </ul>
071     * @param name the name of the shortcut.
072     */
073    public void initialize(int type, String name) throws Exception
074    {
075        Debug.log( CLASS + myClass + ".initialize() '" + Integer.toString(type)+ "', '" + name + "'" );
076        switch (type)
077        {
078        case APPLICATIONS: {
079            shortcut = new ShellLink(ShellLink.PROGRAM_MENU, name);
080            break;
081        }
082        case START_MENU: {
083            shortcut = new ShellLink(ShellLink.START_MENU, name);
084            break;
085        }
086        case DESKTOP: {
087            shortcut = new ShellLink(ShellLink.DESKTOP, name);
088            break;
089        }
090        case START_UP: {
091            shortcut = new ShellLink(ShellLink.STARTUP, name);
092            break;
093        }
094        default: {
095            shortcut = new ShellLink(ShellLink.PROGRAM_MENU, name);
096            break;
097        }
098        }
099    }
100
101    /*--------------------------------------------------------------------------*/
102    /**
103     * Returns the base path of the shortcut depending on type. The base path is the directory that
104     * the short cut, (or its program group) will be created in. For instance, on Windows NT, a
105     * shortcut with user-type ALL_USERS, and link-type DESKTOP might have the base path
106     * "C:\Program&nbsp;Files\All&nbsp;Users\Desktop"
107     * 
108     * @see #setLinkType(int)
109     * @see #setUserType(int)
110     * 
111     * translates from ShellLink-UserTypes to Shortcut-UserTypes.
112     */
113    public String getBasePath() throws Exception
114    {
115      String result = shortcut.getLinkPath(shortcut.getUserType());
116      Debug.log( CLASS + myClass + ".getBasePath() '" + result + "'" );
117      return result;
118    }
119
120    /**
121     * Returns a list of currently existing program groups, based on the requested type. For example
122     * if the type is <code>APPLICATIONS</code> then all the names of the program groups in the
123     * Start Menu\Programs menu would be returned.
124     * 
125     * @param userType the type of user for the program group set. (as Shortcut.utype)
126     * 
127     * @return a <code>Vector</code> of <code>String</code> objects that represent the names of
128     * the existing program groups. It is theoretically possible that this list is empty.
129     * 
130     * @see #APPLICATIONS
131     * @see #START_MENU
132     */
133    public Vector getProgramGroups(int userType)
134    {
135        int logentry = 0;
136        Debug.log( CLASS + myClass + ".getProgramGroups()-" + logentry++ + " '" + Integer.toString(userType) + "'" );
137        // ----------------------------------------------------
138        // translate the user type
139        // ----------------------------------------------------
140        int type = ShellLink.CURRENT_USER;
141
142        if (userType == ALL_USERS)
143        {
144            type = ShellLink.ALL_USERS;
145        }
146        else
147        {
148            type = ShellLink.CURRENT_USER;
149        }
150
151        // ----------------------------------------------------
152        // get a list of all files and directories that are
153        // located at the link path.
154        // ----------------------------------------------------
155        String linkPath = shortcut.getLinkPath(type);
156        
157        Debug.log( CLASS + myClass + ".getProgramGroups()-" + logentry++ + " '" + linkPath + "'" );
158
159        // in case there is a problem obtaining a path return
160        // an empty vector (there are no preexisting program
161        // groups)
162        if (linkPath == null) { return (new Vector()); }
163
164        File path = new File(linkPath);
165        File[] file = path.listFiles();
166
167        // ----------------------------------------------------
168        // build a vector that contains only the names of
169        // the directories.
170        // ----------------------------------------------------
171        Vector groups = new Vector();
172
173        if (file != null)
174        {
175            for (int i = 0; i < file.length; i++)
176            {
177                File aFile = file[i];
178                String aFilename = aFile.getName();
179                if (aFile.isDirectory())
180                {
181                    
182                    Debug.log( CLASS + myClass + ".getProgramGroups()-" + logentry++ + " '" + aFilename + "'" );
183                    groups.add( aFilename );
184                }
185                else
186                    Debug.log( CLASS + myClass + ".getProgramGroups()-" + logentry++ + " Skip (NoDirectory): '" + aFilename + "'" );  
187            }
188        }
189
190        return (groups);
191    }
192
193    /*--------------------------------------------------------------------------*/
194    /**
195     * Returns the fully qualified file name under which the link is saved on disk. <b>Note: </b>
196     * this method returns valid results only if the instance was created from a file on disk or
197     * after a successful save operation.
198     * 
199     * @return the fully qualified file name for the shell link
200     */
201    public String getFileName()
202    {
203      String aFilename = shortcut.getFileName();  
204      Debug.log( CLASS + myClass + ".getFileName() '" + aFilename + "'" );
205      return( aFilename );
206    }
207
208    /*--------------------------------------------------------------------------*/
209    /**
210     * Returns the path of the directory where the link file is stored, if it was necessary during
211     * the previous save operation to create the directory. This method returns <code>null</code>
212     * if no save operation was carried out or there was no need to create a directory during the
213     * previous save operation.
214     * 
215     * @return the path of the directory where the link file is stored or <code>null</code> if no
216     * save operation was carried out or there was no need to create a directory during the previous
217     * save operation.
218     */
219    public String getDirectoryCreated()
220    {
221      String directoryCreated = shortcut.getDirectoryCreated();
222      Debug.log( CLASS + myClass + ".getDirectoryCreated() '" + directoryCreated + "'" );
223      return( directoryCreated );
224    }
225
226    /*--------------------------------------------------------------------------*/
227    /**
228     * Returns <code>true</code> if the target OS supports current user and all users.
229     * 
230     * @return <code>true</code> if the target OS supports current and all users.
231     */
232    public boolean multipleUsers()
233    {
234        boolean result = false;
235        // Win NT4 won't have PROGRAMS for CURRENT_USER.
236        // Win 98 may not have 'Start Menu\Programs' for ALL_USERS
237        String allUsers = shortcut.getallUsersLinkPath();
238        
239        Debug.log( CLASS + myClass + ".multipleUsers()-1 '" + allUsers + "'" );
240        
241        String currentUsers = shortcut.getcurrentUserLinkPath();
242        Debug.log( CLASS + myClass + ".multipleUsers()-2 '" + currentUsers + "'" );
243
244        if( allUsers == null || currentUsers == null ) 
245            result = false;
246        else 
247          result = allUsers.length() > 0 && currentUsers.length() > 0;
248
249        Debug.log( CLASS + myClass + ".multipleUsers()-3 '" + result + "'" );  
250        return (result);
251    }
252
253    /*--------------------------------------------------------------------------*/
254    /**
255     * Signals that this flavor of <code>{@link com.izforge.izpack.util.os.Shortcut}</code>
256     * supports the creation of shortcuts.
257     * 
258     * @return always <code>true</code>
259     */
260    public boolean supported()
261    { 
262      Debug.log( CLASS + myClass + ".supported() '" + SUPPORTED + "'" );
263      return( SUPPORTED );
264    }
265
266    /*--------------------------------------------------------------------------*/
267    /**
268     * Sets the command line arguments that will be passed to the target when the link is activated.
269     * 
270     * @param arguments the command line arguments
271     */
272    public void setArguments(String arguments)
273    {
274      Debug.log( CLASS + myClass + ".setArguments() '" + arguments + "'" );
275      shortcut.setArguments(arguments);
276    }
277
278    /*--------------------------------------------------------------------------*/
279    /**
280     * Sets the description string that is used to identify the link in a menu or on the desktop.
281     * 
282     * @param description the descriptiojn string
283     */
284    public void setDescription(String description)
285    {
286      Debug.log( CLASS + myClass + ".setDescription() '" + description + "'" );
287      shortcut.setDescription( description );
288    }
289
290    /*--------------------------------------------------------------------------*/
291    /**
292     * Sets the location of the icon that is shown for the shortcut on the desktop.
293     * 
294     * @param path a fully qualified file name of a file that contains the icon.
295     * @param index the index of the specific icon to use in the file. If there is only one icon in
296     * the file, use an index of 0.
297     */
298    public void setIconLocation(String path, int index)
299    {
300        Debug.log( CLASS + myClass + ".setIconLocation() '" + path + "', '" + Integer.toString(index) + "'" );  
301      shortcut.setIconLocation(path, index);
302    }
303
304    /*--------------------------------------------------------------------------*/
305    /**
306     * returns icon Location
307     * 
308     * @return iconLocation
309     */
310    public String getIconLocation()
311    {
312      String result = shortcut.getIconLocation();
313        Debug.log( CLASS + myClass + ".getIconLocation() '" + result + "'" );
314      return result;
315    }
316
317    /*--------------------------------------------------------------------------*/
318    /**
319     * Sets the name of the program group this ShellLinbk should be placed in.
320     * 
321     * @param groupName the name of the program group
322     */
323    public void setProgramGroup(String groupName)
324    {
325        Debug.log( CLASS + myClass + ".setProgramGroup() '" + groupName + "'" );
326      shortcut.setProgramGroup(groupName);
327    }
328
329    /*--------------------------------------------------------------------------*/
330    /**
331     * Sets the show command that is passed to the target application when the link is activated.
332     * The show command determines if the the window will be restored to the previous size,
333     * minimized, maximized or visible at all. <br>
334     * <br>
335     * <b>Note: </b> <br>
336     * Using <code>HIDE</code> will cause the target window not to show at all. There is not even
337     * a button on the taskbar. This is a very useful setting when batch files are used to launch a
338     * Java application as it will then appear to run just like any native Windows application. <br>
339     * 
340     * 
341     * @param show the show command. Valid settings are: <br>
342     * <ul>
343     * <li>{@link com.izforge.izpack.util.os.Shortcut#HIDE}
344     * <li>{@link com.izforge.izpack.util.os.Shortcut#NORMAL}
345     * <li>{@link com.izforge.izpack.util.os.Shortcut#MINIMIZED}
346     * <li>{@link com.izforge.izpack.util.os.Shortcut#MAXIMIZED}
347     * </ul>
348     * 
349     * @see #getShowCommand internally maps from Shortcut. to ShellLink.
350     */
351    public void setShowCommand(int show) throws IllegalArgumentException
352    {
353        Debug.log( CLASS + myClass + ".setShowCommand() '" + Integer.toString(show) + "'" );
354        switch (show)
355        {
356        case HIDE: {
357            shortcut.setShowCommand(ShellLink.MINNOACTIVE);
358            break;
359        }
360        case NORMAL: {
361            shortcut.setShowCommand(ShellLink.NORMAL);
362            break;
363        }
364        case MINIMIZED: {
365            shortcut.setShowCommand(ShellLink.MINNOACTIVE);
366            break;
367        }
368        case MAXIMIZED: {
369            shortcut.setShowCommand(ShellLink.MAXIMIZED);
370            break;
371        }
372        default: {
373            throw (new IllegalArgumentException(show + "is not recognized as a show command"));
374        }
375        }
376    }
377
378    /*
379     * returns current showCommand. internally maps from ShellLink. to Shortcut.
380     *  
381     */
382    public int getShowCommand()
383    {        
384        int showCommand = shortcut.getShowCommand();
385        
386        Debug.log( CLASS + myClass + ".getShowCommand() '" + Integer.toString(showCommand) + "'" );
387
388        switch (showCommand)
389        {
390        case ShellLink.NORMAL:
391            showCommand = NORMAL;
392            break;
393        // both MINNOACTIVE and MINIMIZED map to Shortcut.MINIMIZED
394        case ShellLink.MINNOACTIVE:
395        case ShellLink.MINIMIZED:
396            showCommand = MINIMIZED;
397            break;
398        case ShellLink.MAXIMIZED:
399            showCommand = MAXIMIZED;
400            break;
401        default:
402            break;
403        }
404
405        return showCommand;
406    }
407
408    /*--------------------------------------------------------------------------*/
409    /**
410     * Sets the absolute path to the shortcut target.
411     * 
412     * @param path the fully qualified file name of the target
413     */
414    public void setTargetPath(String path)
415    {
416        Debug.log( CLASS + myClass + ".setTargetPath() '" + path + "'" );
417        shortcut.setTargetPath(path);
418    }
419
420    /*--------------------------------------------------------------------------*/
421    /**
422     * Sets the working directory for the link target.
423     * 
424     * @param dir the working directory
425     */
426    public void setWorkingDirectory(String dir)
427    {
428        Debug.log( CLASS + myClass + ".setWorkingDirectory() '" + dir + "'" );
429        shortcut.setWorkingDirectory(dir);
430    }
431
432    /*--------------------------------------------------------------------------*/
433    /**
434     * Gets the working directory for the link target.
435     * 
436     * @return the working directory.
437     */
438    public String getWorkingDirectory()
439    {
440        String result = shortcut.getWorkingDirectory();
441          Debug.log( CLASS + myClass + ".getWorkingDirectory() '" + result + "'" );
442        return result;
443    }
444
445    /*--------------------------------------------------------------------------*/
446    /**
447     * Sets the name shown in a menu or on the desktop for the link.
448     * 
449     * @param name The name that the link should display on a menu or on the desktop. Do not include
450     * a file extension.
451     */
452    public void setLinkName(String name)
453    {
454        Debug.log( CLASS + myClass + ".setLinkName() '" + name + "'" );
455        shortcut.setLinkName(name);
456    }
457
458    /*--------------------------------------------------------------------------*/
459    /**
460     * Gets the type of link types are: <br>
461     * <ul>
462     * <li>{@link com.izforge.izpack.util.os.Shortcut#DESKTOP}
463     * <li>{@link com.izforge.izpack.util.os.Shortcut#APPLICATIONS}
464     * <li>{@link com.izforge.izpack.util.os.Shortcut#START_MENU}
465     * <li>{@link com.izforge.izpack.util.os.Shortcut#START_UP}
466     * </ul>
467     * maps from ShellLink-types to Shortcut-types.
468     */
469    public int getLinkType()
470    {
471        int typ = shortcut.getLinkType();
472          Debug.log( CLASS + myClass + ".getLinkType() '" + typ + "'" );
473        switch (typ)
474        {
475        case ShellLink.DESKTOP:
476            typ = DESKTOP;
477            break;
478        case ShellLink.PROGRAM_MENU:
479            typ = APPLICATIONS;
480            break;
481        case ShellLink.START_MENU:
482            typ = START_MENU;
483            break;
484        case ShellLink.STARTUP:
485            typ = START_UP;
486            break;
487        default:
488            break;
489        }
490
491        return typ;
492    }
493
494    /*--------------------------------------------------------------------------*/
495    /**
496     * Sets the type of link
497     * 
498     * @param type The type of link desired. The following values can be set: <br>
499     * (note APPLICATION on Windows is 'Start Menu\Programs') APPLICATION is a Mac term.
500     * <ul>
501     * <li>{@link com.izforge.izpack.util.os.Shortcut#DESKTOP}
502     * <li>{@link com.izforge.izpack.util.os.Shortcut#APPLICATIONS}
503     * <li>{@link com.izforge.izpack.util.os.Shortcut#START_MENU}
504     * <li>{@link com.izforge.izpack.util.os.Shortcut#START_UP}
505     * </ul>
506     * 
507     * @exception IllegalArgumentException if an an invalid type is passed
508     * @throws UnsupportedEncodingException 
509     */
510    public void setLinkType(int type) throws IllegalArgumentException, UnsupportedEncodingException
511    {
512        Debug.log( CLASS + myClass + ".setLinkType() '" + type + "'" );
513        switch (type)
514        {
515        case DESKTOP: {
516            shortcut.setLinkType(ShellLink.DESKTOP);
517            break;
518        }
519        case APPLICATIONS: {
520            shortcut.setLinkType(ShellLink.PROGRAM_MENU);
521            break;
522        }
523        case START_MENU: {
524            shortcut.setLinkType(ShellLink.START_MENU);
525            break;
526        }
527        case START_UP: {
528            shortcut.setLinkType(ShellLink.STARTUP);
529            break;
530        }
531        default: {
532            throw (new IllegalArgumentException(type + "is not recognized as a valid link type"));
533        }
534        }
535    }
536
537    /*--------------------------------------------------------------------------*/
538    /**
539     * Gets the user type for the link
540     * 
541     * @return userType
542     * @see #CURRENT_USER
543     * @see #ALL_USERS
544     */
545    public int getUserType()
546    {
547        int utype = shortcut.getUserType();
548        
549          Debug.log( CLASS + myClass + ".getUserType() '" + utype + "'" );
550
551        switch (utype)
552        {
553        case ShellLink.ALL_USERS:
554            utype = ALL_USERS;
555            break;
556
557        case ShellLink.CURRENT_USER:
558            utype = CURRENT_USER;
559            break;
560        }
561
562        return utype;
563    }
564
565    /*--------------------------------------------------------------------------*/
566    /**
567     * Sets the user type for the link
568     * 
569     * @param type the type of user for the link.
570     * 
571     * @see Shortcut#CURRENT_USER
572     * @see Shortcut#ALL_USERS
573     * 
574     * if the linkPath for that type is empty, refuse to set.
575     */
576    /*--------------------------------------------------------------------------*/
577    public void setUserType(int type)
578    {
579        Debug.log( CLASS + myClass + ".setUserType() '" + type + "'" );
580        if (type == CURRENT_USER)
581        {
582            if (shortcut.getcurrentUserLinkPath().length() > 0)
583            {
584                shortcut.setUserType(ShellLink.CURRENT_USER);
585            }
586        }
587        else if (type == ALL_USERS)
588        {
589            if (shortcut.getallUsersLinkPath().length() > 0)
590            {
591                shortcut.setUserType(ShellLink.ALL_USERS);
592            }
593        }
594    }
595
596    /*--------------------------------------------------------------------------*/
597    /**
598     * Saves this link.
599     * 
600     * @exception Exception if problems are encountered
601     */
602    public void save() throws Exception
603    {
604        
605        shortcut.save();
606    }
607
608    /*--------------------------------------------------------------------------*/
609    /**
610     * Gets the link hotKey
611     * 
612     * @return int hotKey
613     */
614    public int getHotkey()
615    {
616        int result = shortcut.getHotkey();  
617        Debug.log( CLASS + myClass + ".getHotkey() '" + result + "'" );
618        return result;
619    }
620
621    /*--------------------------------------------------------------------------*/
622    /**
623     * Sets the link hotKey
624     * 
625     * @param hotkey
626     * 
627     * incoming 2 byte hotkey is: high byte modifier: SHIFT = 0x01 CONTROL= 0x02 ALT = 0x04 EXT =
628     * 0x08
629     * 
630     * lower byte contains ascii letter. ie 0x0278 represents CTRL+x 0x068a represents CTRL+ALT+z
631     */
632    public void setHotkey(int hotkey)
633    {
634        Debug.log( CLASS + myClass + ".setHotkey() '" + hotkey + "'" );
635        shortcut.setHotkey(hotkey);
636    }
637
638    /**
639     * Gets the Folders where to place the program-groups and their shortcuts, for the given
640     * usertype.
641     * @throws UnsupportedEncodingException 
642     * 
643     * @see com.izforge.izpack.util.os.Shortcut#getProgramsFolder(int)
644     */
645    public String getProgramsFolder(int current_user) 
646    {
647        String result = null;
648        try
649        {
650            result = new String( shortcut.getLinkPath(current_user).getBytes( StringTool.getPlatformEncoding() ), StringTool.getPlatformEncoding() );
651        }
652        catch (UnsupportedEncodingException e)
653        {
654            // TODO Auto-generated catch block
655            e.printStackTrace();
656        }
657        Debug.log( CLASS + myClass + ".getProgramsFolder() '" + current_user + "', '" + result + "'" );
658        return result; 
659    }
660}
661/*---------------------------------------------------------------------------*/
662