001    /////////////////////////////////////////////////
002    // This file is part of Sears project.
003    // Subtitle Editor And Re-Synch
004    // A tool to easily modify and resynch movies subtitles.
005    /////////////////////////////////////////////////
006    //This program is free software; 
007    //you can redistribute it and/or modify it under the terms 
008    //of the GNU General Public License 
009    //as published by the Free Software Foundation; 
010    //either version 2 of the License, or (at your option) any later version.
011    /////////////////////////////////////////////////
012    //Sears project is available under sourceforge
013    // at adress: http://sourceforge.net/projects/sears/
014    //Copyright (C) 2005 Booba Skaya
015    //Mail: booba.skaya@gmail.com
016    ////////////////////////////////////////////////
017    
018    package sears.gui.resources;
019    
020    import java.awt.Toolkit;
021    import java.awt.event.InputEvent;
022    import java.awt.event.KeyEvent;
023    import java.io.File;
024    import java.net.URL;
025    import java.util.HashMap;
026    
027    import javax.swing.ImageIcon;
028    import javax.swing.KeyStroke;
029    
030    import sears.gui.JDialogOptions;
031    import sears.gui.MainWindow;
032    import sears.tools.JarResources;
033    import sears.tools.SearsProperties;
034    import sears.tools.Trace;
035    import sears.tools.Utils;
036    
037    /**
038     * Class SearsResourceBundle.
039     * <br><b>Summary:</b><br>
040     * This class contains resources for Sears GUI.
041     */
042    public class SearsResources {
043        private static Object[][] resources = { 
044            //General stuff
045            // 'favicon' :) displayed by Windows and Linux OS
046            // [ 20x20 size is good for a nice icon view ]
047            { "SearsGUIFavicon", "searsFavicon.png" },
048            { "SearsGUIIcon", "sears.png" },
049            { "SearsGUITitle", "Sears Beta V" },
050            { "BrowseIcon", "browse.png" },
051            // used by ArrowButton class
052            { "ArrowDown", "arrowDown.png" },
053            { "ArrowUp", "arrowUp.png" },
054            
055            //Open Action
056            { "OpenIcon", "open.png"},
057            { "OpenKey" , KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK)},
058            { "OpenKeyMac", KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.META_MASK)},
059            
060            //Save Action
061            { "SaveIcon", "save.png"},
062            { "SaveKey" , KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)},
063            { "SaveKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.META_MASK)},
064            
065            //SaveAs Action
066            { "SaveAsIcon", "saveAs.png"},
067            { "SaveAsKey" , KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_MASK)},
068            { "SaveAsKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.META_MASK | InputEvent.SHIFT_MASK)},
069            
070            //Quit Action
071            { "QuitIcon", "quit.png"},
072            //{ "QuitKey" , KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)},
073            //{ "QuitKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.META_MASK)},
074    
075            //Delay Action
076            { "DelayIcon", "delay.png"},
077            { "DelayKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F1, InputEvent.CTRL_DOWN_MASK)},
078            { "DelayKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.META_MASK | InputEvent.ALT_DOWN_MASK)},
079            
080            //Resynch Action
081            { "ResynchIcon", "resynch.png"},
082            { "ResynchKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_DOWN_MASK)},
083            { "ResynchKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.META_MASK | InputEvent.ALT_DOWN_MASK)},
084            
085            //Split Action
086            { "SplitIcon", "split.png"},
087            { "SplitKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F3, InputEvent.CTRL_DOWN_MASK)},
088            { "SplitKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.META_MASK | InputEvent.ALT_DOWN_MASK)},
089            
090            //Append Action
091            { "AppendIcon", "append.png"},
092            { "AppendKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.CTRL_DOWN_MASK)},
093            { "AppendKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.META_MASK | InputEvent.ALT_DOWN_MASK)},
094            
095            //ChainRepair Action
096            { "ChainRepairIcon", "chainRepair.png"},
097            { "ChainRepairKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F5, InputEvent.CTRL_DOWN_MASK)},
098            { "ChainRepairKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.META_MASK | InputEvent.ALT_DOWN_MASK)},
099            
100            //AccentRepair Action
101            { "AccentRepairIcon", "accentRepair.png"},
102            { "AccentRepairKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F6, InputEvent.CTRL_DOWN_MASK)},
103            { "AccentRepairKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.META_MASK | InputEvent.SHIFT_DOWN_MASK)},
104            
105            //HtmlRepair Action
106            { "HtmlRepairIcon", "htmlRepair.png"},
107            { "HtmlRepairKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F7, InputEvent.CTRL_DOWN_MASK)},
108            { "HtmlRepairKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.META_MASK | InputEvent.SHIFT_DOWN_MASK)},
109            
110            //OrderRepair Action
111            { "OrderRepairIcon", "orderRepair.png"},
112            { "OrderRepairKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F8, InputEvent.CTRL_DOWN_MASK)},
113            { "OrderRepairKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.META_MASK | InputEvent.SHIFT_DOWN_MASK)},
114            
115            //TimeRepair Action
116            { "TimeRepairIcon", "timeRepair.png"},
117            { "TimeRepairKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F9, InputEvent.CTRL_DOWN_MASK)},
118            { "TimeRepairKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.META_MASK | InputEvent.SHIFT_DOWN_MASK)},
119    
120            //Undo Action
121            { "UndoIcon", "undo.png"},
122            { "UndoKey" , KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK)},
123            { "UndoKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.META_MASK | InputEvent.SHIFT_DOWN_MASK)},
124    
125            //Redo Action
126            { "RedoIcon", "redo.png"},
127            { "RedoKey" , KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK)},
128            { "RedoKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.META_MASK | InputEvent.SHIFT_DOWN_MASK)},
129    
130            
131            //NormalizeDuration Action
132            { "NormalizeDurationIcon", "normalizeDuration.png"},
133            { "NormalizeDurationKey" , null},
134            
135            //Split GUI stuff
136            { "SplitGUIBanner", "splitBanner.png"},
137            
138            //SelectVideo Action
139            { "SelectVideoIcon", "openVideo.png"},
140            { "SelectVideoKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F10, InputEvent.CTRL_DOWN_MASK)},      
141            { "SelectVideoKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.META_DOWN_MASK | InputEvent.SHIFT_MASK)}, 
142            
143            //Options Action
144            { "OptionsIcon", "options.png"},
145            { "OptionsKey" , KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK)},
146            { "OptionsKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_COMMA, InputEvent.META_MASK)},
147            
148            //Play Action
149            { "PlayIcon", "play.png"},
150            { "PlayKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F11, InputEvent.CTRL_DOWN_MASK)},
151            { "PlayKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.META_DOWN_MASK | InputEvent.SHIFT_MASK)},
152            
153            //Pause Action
154            { "PauseIcon", "pause.png"},
155            
156            //Stop Action
157            { "StopIcon", "stop.png"},
158            
159            //Previous Action
160            { "PreviousIcon", "reward.png"},
161    
162            //Next Action
163            { "NextIcon", "forward.png"},
164     
165            //GotoSub Action
166            { "GotoSubIcon", "gotoSub.png"},
167    
168            //MagicResynchro Action
169            { "MagicResynchroIcon", "magicResynchro.png"},
170     
171            //RemoveAllAnchors Action
172            { "RemoveAllAnchorsIcon", "removeAllAnchors.png"},
173     
174            //RecentFile Action
175            { "RecentFileIcon", "openRecent.png"},
176     
177            //Anchor icon
178            { "AnchorIcon", "anchor.png"},
179            
180            //Dot icon
181            { "DotIcon", "dot.png"},
182            
183            //About Action
184            { "AboutIcon", "about.png"},
185            
186            //Help
187            { "HelpIcon", "help.png"},
188            // no question_mark keyEvent...
189            
190            //Find Action
191            { "FindIcon", "find.png"},
192            { "FindKey" , KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK)},
193            { "FindKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.META_DOWN_MASK)},
194    
195            { "TinyFindIcon", "tinyFind.png" },
196            
197            //Mix Action
198            { "MixIcon", "mix.png"},
199            { "MixKey" , KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK)},
200            { "MixKeyMac" , KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.META_DOWN_MASK | InputEvent.ALT_DOWN_MASK)},
201       
202            // Error icon, use in JDialogErrorMessage
203            { "ErrorIcon", "error.png" },
204            
205            // Flag:
206            { "fr", "flag/fr.png" },
207            { "en", "flag/us.png" },
208            { "it", "flag/it.png" },
209            { "es", "flag/es.png" },
210            { "nl", "flag/nl.png" },
211            
212            { "delete", "s_delete.png"},
213            { "deletePressed", "s_delete_pressed.png"},
214            
215            { "blank","blank.png"}
216        
217        };
218    
219        private static HashMap<String, Object> resourcesMap;
220    
221            private static JarResources jarResources;
222            
223            private static String iconFolder;
224        
225    
226        /**
227         * Method getString.
228         * <br><b>Summary:</b><br>
229         * This method return the value that correspond to the given key.
230         * @param key       The key to search.
231         * @return          The <b>String</b> searched value, or "" if does not found.
232         */
233        public static String getString(String key) {
234            //the result of the method.
235            String result = "";
236            if (resourcesMap == null) {
237                constructMap();
238            }
239            String value = (String) resourcesMap.get(key);
240            //return value only if non null
241            if (value != null) {
242                result = value;
243            }
244            //return the result
245            return result;
246        }
247    
248        /**
249         * Method getIcon.
250         * <br><b>Summary:</b><br>
251         * This method return the icon that correspond to the given key.
252         * @param key       The key to search.
253         * @return          The <b>ImageIcon</b> searched icon, or blankIcon if does not found.
254         */
255        public static ImageIcon getIcon(String key) {
256            //the result of the method.
257            ImageIcon result = null;
258            String iconFile = getString(key);
259            if (!iconFile.equals("")) {
260                //retrieve icon URL.
261                //check if a skin is precised.
262                String iconSetFile = SearsProperties.getProperty(SearsProperties.ICON_SET);
263                if(iconSetFile != null && !iconSetFile.equals("")){
264                    //We have to reach the icon in the jar file using the jarResources.
265                    //create the jarResources if not already set.
266                    if(jarResources == null){
267                            jarResources = new JarResources(getIconFolder()+File.separator+iconSetFile);
268                    }
269                    //Reach the icon in it.
270                    byte[] byteImage = jarResources.getResource(iconFile);
271                    if(byteImage != null){
272                            result = new ImageIcon(Toolkit.getDefaultToolkit().createImage(byteImage));
273                    }else{
274                            Trace.warning("Can't find resource "+iconFile+" in jar resources "+iconSetFile+". Using default icon.");
275                    }
276                }
277                //If can not find resource, use default icon.
278                if(result == null){
279                    URL url = MainWindow.instance.getClass().getResource("/sears/gui/resources/" + iconFile);
280                    if(url != null){
281                        result = new ImageIcon(url);
282                    }
283                }
284            }
285            //if could not find icon, return blank icon
286            if(result == null){
287                result = new ImageIcon(MainWindow.instance.getClass().getResource("/sears/gui/resources/blank.png"));
288            }
289            //return the result
290            return result;
291        }
292        
293        /**
294         * Method getKey.
295         * <br><b>Summary:</b><br>
296         * This method return the Key accelerator that correspond to the given key.
297         * @param key       The key to search.
298         * @return          The <b>KeyStroke</b> searched key, or null if does not found.
299         */
300        public static KeyStroke getKey(String key) {
301            // if we are running on Mac OS:
302            if(Utils.isMacPlatform){
303                    key = key + "Mac";
304            } 
305            //the result of the method.
306            KeyStroke result = (KeyStroke) resourcesMap.get(key);
307            //return the result
308            return result;
309        }
310    
311        /**
312         * Method constructMap.
313         * <br><b>Summary:</b><br>
314         * This contruct the HashMap of resources.
315         */
316        private static void constructMap() {
317            resourcesMap = new HashMap<String, Object>();
318            for (int i = 0; i < resources.length; i++) {
319                resourcesMap.put((String) resources[i][0], resources[i][1]);
320            }
321        }
322        
323            /**
324             * Method getIconFolder.
325             * <br><b>Summary:</b><br>
326             * This method return the Icon folder.
327             * @return  (<b>String</b>)   the Icon folder.
328             */
329            public static String getIconFolder() {
330                    if (iconFolder == null) {
331                            // To do that retrieve the location of the JDialogOption class
332                            String classResource = JDialogOptions.class.getResource(
333                                            "JDialogOptions.class").getFile();
334                            // DEVELOPER:
335                            // spaces are not allowed in URL and replaced by %20
336                            // there's a maybe a better solution to correct this
337                            // than the one under:
338                            classResource = classResource.replace("%20", " ");
339                            // Then retrieve the index of the "file:" string, which indicate we
340                            // are executing from a jar file.
341                            int indexOfFile = classResource.indexOf("file:");
342                            // the beginning of the jar file contain, if it exists:
343                            int indexOfJar = classResource.indexOf("!");
344                            // if we are in a jar file:
345                            if (indexOfFile != -1 && indexOfJar != -1) {
346                                    // we get the parent file of the jar file:
347                                    File parent = new File(classResource.substring(0, indexOfJar)).getParentFile();
348                                    // and with the parent of the parent, we get back the icon directory path:
349                                    iconFolder = new File(parent.getParent()) + System.getProperty("file.separator") + "icons";
350                                    //remove begining "file:" pattern
351                                    iconFolder = iconFolder.substring(5);
352                            } else {
353                                    // we are not in a jar file, let's assume we are in eclipse.
354                                    // And eclipse project does export the icons folder.
355                                    // search for the last sears pattern, which is the root for the
356                                    // sears class.
357                                    int indexOfSearsPackage = classResource.lastIndexOf("sears");
358                                    if (indexOfSearsPackage != -1) {
359                                            // we have retrieved the sears folder, go up, and find the
360                                            // icon folder.
361                                            iconFolder = classResource
362                                                            .substring(0, indexOfSearsPackage);
363                                            iconFolder += "icons";
364                                    }
365                            }
366                    }
367                    return iconFolder;
368            }
369            
370            /**
371             * Sets to null all utilized variables
372             * <br>Useful when an icon change request is launched
373             */
374            public static void dispose() {
375                    //resourcesMap = null;
376                    jarResources = null;
377                    //iconFolder = null;
378            }
379    }