001    /*
002     Copyright (C) 2003 Adam Olsen
003     This program is free software; you can redistribute it and/or modify
004     it under the terms of the GNU General Public License as published by
005     the Free Software Foundation; either version 1, or (at your option)
006     any later version.
007     This program is distributed in the hope that it will be useful,
008     but WITHOUT ANY WARRANTY; without even the implied warranty of
009     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
010     GNU General Public License for more details.
011     You should have received a copy of the GNU General Public License
012     along with this program; if not, write to the Free Software
013     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
014     */
015    package com.valhalla.jbother;
016    
017    import java.awt.AWTEvent;
018    import java.awt.Component;
019    import java.awt.Container;
020    import java.awt.Font;
021    import java.awt.Frame;
022    import java.awt.Toolkit;
023    import java.awt.Window;
024    import java.awt.event.AWTEventListener;
025    import java.awt.event.KeyEvent;
026    import java.io.File;
027    import java.io.FileInputStream;
028    import java.text.MessageFormat;
029    import java.util.ArrayList;
030    import java.util.Enumeration;
031    import java.util.Locale;
032    import java.util.Properties;
033    import java.util.ResourceBundle;
034    
035    import javax.swing.*;
036    import javax.swing.plaf.FontUIResource;
037    
038    import org.jivesoftware.smack.SmackConfiguration;
039    
040    import com.valhalla.gui.*;
041    import com.valhalla.jbother.plugins.events.InitEvent;
042    import com.valhalla.misc.GnuPG;
043    import com.valhalla.pluginmanager.PluginChain;
044    import com.valhalla.jbother.preferences.*;
045    import com.valhalla.pluginmanager.PluginLoader;
046    import com.valhalla.settings.Arguments;
047    import com.valhalla.settings.Settings;
048    
049    /**
050     * Sets default Settings (if this is the first run of JBother), loads command
051     * line arguments and settings from the settings file, sets the L&F.
052     *
053     * @author Adam Olsen (arolsen@gmail.com)
054     * @created November 30, 2004
055     * @version 1.0
056     */
057    public class JBotherLoader {
058        private static PluginLoader loader = PluginLoader.getInstance();
059        
060        private String profile;
061        
062        private static JFrame parentFrame = new JFrame();
063        
064        private static Properties discoveryCache = new Properties();
065        
066        private static boolean gnupgEnabled = false;
067        private boolean done = false;
068        
069        /**
070         * This is the main class, it basically just provides a loading point for
071         * the login screen - and also allows arguments to be passed from the
072         * command line.
073         *
074         * @param args
075         *            arguments passed via the command line
076         * @see com.valhalla.settings.Arguments
077         */
078        public void startJBother(String args[]) {
079            Toolkit.getDefaultToolkit().sync();
080            AWTEventListener listener = new AWTEventListener() {
081                public void eventDispatched(AWTEvent evt) {
082                    if (evt instanceof KeyEvent) {
083                        KeyEvent e = (KeyEvent) evt;
084                        if (e.getModifiers() == KeyEvent.CTRL_MASK
085                                && e.getKeyCode() == KeyEvent.VK_D) {
086                            com.valhalla.Logger.getDebugWindow().setVisible(true);
087                        } else if(e.getModifiers() == KeyEvent.CTRL_MASK
088                                && e.getKeyCode() == KeyEvent.VK_P) {
089                            if (!DialogTracker.containsDialog(PreferencesDialog.class))
090                                new PreferencesDialog().setVisible(true);
091                        }
092                        
093                    }
094                }
095            };
096            
097            Toolkit.getDefaultToolkit().addAWTEventListener(listener,
098                    AWTEvent.KEY_EVENT_MASK);
099            
100            Arguments.setArguments(args);
101            // initialize the argument holder
102            if (Arguments.getInstance().getBoolean("help")) {
103                showUsage();
104            }
105            
106            
107            if (!Arguments.getInstance().getBoolean("nosplash")) {
108                new SplashScreen(this);
109                doLaunch();
110            } else {
111                doLaunch();
112                afterSplash();
113            }
114        }
115        
116        protected void doLaunch() {
117            //setFocusManager();
118            
119            String smackTimeout = Arguments.getInstance().getProperty( "smacktimeout", "90000" );
120            int stimeout = 90000;
121            try {
122                stimeout = Integer.parseInt( smackTimeout );
123            } catch( Exception ex ) { }
124            
125            SmackConfiguration.setPacketReplyTimeout(stimeout);
126            
127            if (System.getProperty("mrj.version") != null) {
128                System.setProperty("apple.laf.useScreenMenuBar", "true");
129                System.setProperty(
130                        "com.apple.mrj.application.apple.menu.about.name",
131                        "JBother");
132            }
133            
134            // use custom directory for kiosk mode
135            if (Arguments.getInstance().getProperty("kiosk") != null) {
136                JBother.kiosk_mode = true;
137                JBother.settingsDir = System.getProperty("user.home")
138                + File.separatorChar + ".jbother_"
139                        + (String) Arguments.getInstance().getProperty("kiosk");
140                profile = ProfileManager.getOnlyProfile();
141            } else {
142                profile = ProfileManager.getDefaultProfile();            
143                
144                if(Arguments.getInstance().getProperty( "settingsdir" ) != null) {
145                    JBother.settingsDir = System.getProperty("user.home")
146                    + File.separatorChar + Arguments.getInstance().getProperty( "settingsdir" );
147                }
148            }
149            
150            if (profile == null || profile.equals("")) {
151                profile = "default";
152            }
153            
154            
155            com.valhalla.Logger.setLogFile(JBother.settingsDir + File.separatorChar
156                    + "jbother.log");
157            
158            JBother.profileDir = JBother.settingsDir + File.separatorChar
159                    + "profiles" + File.separatorChar + profile;
160            
161            File cache = new File(JBother.settingsDir + File.separatorChar
162                    + "discocache.properties");
163            try {
164                FileInputStream in = new FileInputStream(cache);
165                discoveryCache.load(in);
166                in.close();
167            } catch (Exception e) {
168            }
169            
170            Settings.loadSettings(JBother.profileDir, "settings.properties");
171            loadSettings();
172            
173            if (Arguments.getInstance().getProperty("webstart") == null
174                    && Arguments.getInstance().getProperty("noplugins") == null) {
175                loadPlugins();
176            }
177            
178            checkGPG();
179            
180            InitEvent event = new InitEvent(null);
181            PluginChain.fireEvent(event);
182            done = true;
183        }
184        
185        protected boolean done() { return done; }
186        
187        /**
188         * Checks if GPG is enabled.
189         */
190        public static void checkGPG() {
191            // check to make sure GnuPG is executable
192            GnuPG gnupg = new GnuPG();
193            gnupgEnabled = gnupg.listKeys("");
194        }
195        
196        /**
197         * Gets the discoveryCache attribute of the JBotherLoader class
198         *
199         * @return The discoveryCache value
200         */
201        public static Properties getDiscoveryCache() {
202            return discoveryCache;
203        }
204        
205        /**
206         * Gets the parentFrame attribute of the JBotherLoader class
207         *
208         * @return The parentFrame value
209         */
210        public static JFrame getParentFrame() {
211            return parentFrame;
212        }
213        
214        /**
215         * Gets called after the splash screen is done showing
216         */
217        protected void afterSplash() {
218            if (Settings.getInstance().getProperty("username") == null
219                    || Settings.getInstance().getProperty("defaultServer") == null) {
220                ProfileEditorDialog dialog = new ProfileEditorDialog(BuddyList.getInstance().getContainerFrame(),null, profile);
221                dialog.setExitOnClose(true);
222                dialog.getDefaultBox().setSelected(true);
223                dialog.setVisible(true);
224                
225                return;
226            }
227            
228            if (Arguments.getInstance().getProperty("prof") != null) {
229                ProfileManager m = new ProfileManager();
230                m.setExitOnClose(true);
231            } else {
232                launch();
233            }
234        }
235        
236        /**
237         * Loads some JBother settings
238         */
239        public static void loadSettings() {
240            UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();
241            
242            ArrayList list = new ArrayList();
243            for( int i = 0; i < lafs.length; i++ ) {
244                list.add( lafs[i] );
245            }
246            
247            list.add( new UIManager.LookAndFeelInfo( "InfoNode", "net.infonode.gui.laf.InfoNodeLookAndFeel" ) );
248            
249            UIManager.LookAndFeelInfo[] infos = new UIManager.LookAndFeelInfo[list.size()];
250            list.toArray( infos );
251            
252            UIManager.setInstalledLookAndFeels( infos );
253            
254            loadLAF();
255            
256            String fontString = Settings.getInstance().getProperty(
257                    "applicationFont");
258            if (fontString == null) {
259                fontString = "Default-PLAIN-12";
260            }
261            
262            Font newFont = Font.decode(fontString);
263            
264            setupFont(newFont);
265        }
266        
267        /**
268         * Description of the Method
269         */
270        public static void loadLAF() {
271            String laf = Settings.getInstance().getProperty("lookAndFeel");
272            if (Arguments.getInstance().getProperty("laf") != null) {
273                laf = Arguments.getInstance().getProperty(laf);
274            }
275            
276            loadLAF(laf);
277        }
278        
279        /**
280         * Loads the Look And Feel requested in the settings
281         *
282         * @param laf
283         *            Description of the Parameter
284         */
285        public static void loadLAF(String laf) {
286            UIManager.put("ClassLoader", loader);
287            if (laf != null
288                    && Arguments.getInstance().getProperty("notheme") == null) {
289                try {
290                    Class lafClass = loader.loadClass(laf);
291                    UIManager.setLookAndFeel((LookAndFeel) lafClass.newInstance());
292                } catch (Exception e) {
293                    com.valhalla.Logger
294                            .debug("Could not load look and feel settings.\n"
295                            + e.getMessage());
296                }
297            }
298            
299            Frame[] frames = Frame.getFrames();
300            for (int f = 0; f < frames.length; f++) {
301                SwingUtilities.updateComponentTreeUI(frames[f]);
302                frames[f].validate();
303                
304                Window[] windows = frames[f].getOwnedWindows();
305                for (int w = 0; w < windows.length; w++) {
306                    if( windows[w] instanceof SplashScreen ) { continue; }
307                    
308                    SwingUtilities.updateComponentTreeUI(windows[w]);
309                    windows[w].validate();
310                }
311            }
312        }
313        
314        /**
315         * Description of the Method
316         *
317         * @param con
318         *            Description of the Parameter
319         */
320        private static void recursivelyUpdate(Container con) {
321            Component[] comps = con.getComponents();
322            for (int i = 0; i < comps.length; i++) {
323                if (comps[i] instanceof Container) {
324                    recursivelyUpdate((Container) comps[i]);
325                }
326                SwingUtilities.updateComponentTreeUI(comps[i]);
327                comps[i].validate();
328            }
329        }
330        
331        /**
332         * Finds the available plugins and uses the PluginLoader to load them Once a
333         * plugin is loaded, it's init() method is called so it can execute initial
334         * code and register for various events in JBother
335         */
336        public static void loadPlugins() {
337            ResourceBundle resources = ResourceBundle.getBundle("JBotherBundle",
338                    Locale.getDefault());
339            
340            loader
341                    .findPlugins(JBother.settingsDir + File.separatorChar
342                    + "plugins");
343            loader.loadPlugins();
344            
345            ArrayList invalids = loader.getInvalidPlugins();
346            for (int i = 0; i < invalids.size(); i++) {
347                String name = (String) invalids.get(i);
348                Standard.warningMessage(null, resources.getString("pluginError"),
349                        MessageFormat.format(resources
350                        .getString("pluginErrorMessage"),
351                        new Object[] { name }));
352            }
353        }
354        
355        /**
356         * Sets the font for the entire application
357         *
358         * @param font
359         *            the font to use
360         */
361        public static void setupFont(Font font) {
362            LookAndFeel lf = javax.swing.UIManager.getLookAndFeel();
363            UIDefaults uid = lf.getDefaults();
364            Enumeration k = uid.keys();
365            while (k.hasMoreElements()) {
366                Object key = k.nextElement();
367                Object val = javax.swing.UIManager.get(key);
368                if (val instanceof FontUIResource) {
369                    FontUIResource fuir = (FontUIResource) val;
370                    javax.swing.UIManager.put(key, new FontUIResource(font));
371                }
372            }
373        }
374        
375        /**
376         * launches the profile defined as default
377         */
378        public void launch() {
379            String profile = ProfileManager.getDefaultProfile();
380            if (profile == null || profile.equals("")) {
381                profile = "default";
382            }
383            ProfileManager.loadProfile(profile);
384        }
385        
386        /**
387         * Description of the Method
388         *
389         * @param message
390         *            Description of the Parameter
391         */
392        private void line(String message) {
393            System.out.println(message);
394        }
395        
396        /**
397         * Description of the Method
398         */
399        private void showUsage() {
400            line("\nJBother v" + JBother.JBOTHER_VERSION + " (c)2005 Adam Olsen\n");
401            line("Usage Instructions:\n");
402            
403            line("java -jar JBother.jar [options]");
404            line("Options are:\n");
405            
406            line("\t--nosplash\t\tdon't show the splash screen");
407            line("\t--prof\t\t\topen profile manager at start");
408            line("\t--noplugins\t\tdisable plugin manager");
409            line("\t--debug\t\t\tenable debug messages");
410            line("\t--help\t\t\tshow this message");
411            line("\n");
412            
413            System.exit(0);
414        }
415        
416        /**
417         * Gets the gPGEnabled attribute of the JBotherLoader class
418         *
419         * @return The gPGEnabled value
420         */
421        public static boolean isGPGEnabled() {
422            return gnupgEnabled;
423        }
424        
425        public static void setGPGEnabled(boolean enabled) {
426            gnupgEnabled = enabled;
427        }
428        
429    }
430