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.*;
018    import java.awt.event.*;
019    import java.io.File;
020    import java.io.FileInputStream;
021    import java.io.FileOutputStream;
022    import java.io.FilenameFilter;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.OutputStream;
026    import java.util.Locale;
027    import java.util.Properties;
028    import java.util.ResourceBundle;
029    
030    import javax.swing.*;
031    
032    import org.jivesoftware.smack.packet.Presence;
033    
034    import com.valhalla.gui.Standard;
035    import com.valhalla.misc.GnuPG;
036    import com.valhalla.misc.MiscUtils;
037    import com.valhalla.misc.SimpleXOR;
038    import com.valhalla.settings.Arguments;
039    import com.valhalla.settings.Settings;
040    
041    /**
042     * Shows a graphical chooser for different JBother profiles
043     *
044     * @author Adam Olsen
045     * @created Oct 28, 2004
046     * @version 1.0
047     */
048    public class ProfileManager extends JFrame {
049        private static ResourceBundle resources = ResourceBundle.getBundle(
050                "JBotherBundle", Locale.getDefault());
051    
052        private JList profileList = new JList();
053    
054        private JButton newButton = new JButton(resources.getString("newButton"));
055    
056        private JButton editButton = new JButton(resources.getString("editButton"));
057    
058        private JButton deleteButton = new JButton(resources
059                .getString("deleteButton"));
060    
061        private JButton openButton = new JButton(resources.getString("openButton"));
062    
063        private JButton cancelButton = new JButton(resources
064                .getString("cancelButton"));
065    
066        private JPanel main = null;
067    
068        private String defaultString = "     <-";
069    
070        private static File profDir = new File(JBother.settingsDir, "profiles");
071    
072        private ProfileListModel model = null;
073    
074        private boolean exitOnClose = false;
075    
076        private static String currentProfile = "default";
077    
078        private static boolean isShowing = false;
079        private static Object selected = null;
080    
081        /**
082         * Default constructor
083         */
084        public ProfileManager() {
085            super("JBother");
086    
087            setIconImage(Standard.getImage("frameicon.png"));
088            profileList.setCellRenderer(new ListRenderer());
089    
090            loadProfileList();
091    
092            main = (JPanel) getContentPane();
093            main.setBorder(BorderFactory.createTitledBorder(resources
094                    .getString("profileManager")));
095            main.setLayout(new BorderLayout(5, 5));
096    
097            JPanel rightPanel = new JPanel();
098            rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
099    
100            newButton.setMaximumSize(new Dimension(100, 100));
101            editButton.setMaximumSize(new Dimension(100, 100));
102            deleteButton.setMaximumSize(new Dimension(100, 100));
103            rightPanel.add(newButton);
104            rightPanel.add(editButton);
105            rightPanel.add(deleteButton);
106    
107            rightPanel.add(Box.createVerticalGlue());
108    
109            JPanel bottomPanel = new JPanel();
110            bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
111            bottomPanel.add(Box.createHorizontalGlue());
112            bottomPanel.add(cancelButton);
113            bottomPanel.add(openButton);
114            main.add(new JScrollPane(profileList), BorderLayout.CENTER);
115            main.add(rightPanel, BorderLayout.WEST);
116            main.add(bottomPanel, BorderLayout.SOUTH);
117    
118            addListeners();
119            pack();
120            setSize(350, 200);
121            setLocationRelativeTo(null);
122            isShowing = true;
123            setVisible(true);
124            addWindowListener(new WindowAdapter() {
125                public void windowClosing(WindowEvent e) {
126                    cancelHandler();
127                }
128            });
129        }
130    
131        class MouseClickListener extends MouseAdapter {
132            public void mouseClicked(MouseEvent e) {
133                if (e.getClickCount() >= 2) {
134                    openHandler();
135                }
136            }
137        }
138    
139        public static boolean isCurrentlyShowing() {
140            return isShowing;
141        }
142    
143        public static String getCurrentProfile() {
144            return currentProfile;
145        }
146    
147        public static void setCurrentProfile(String profile) {
148            currentProfile = profile;
149        }
150    
151        /**
152         * @param exitOnClose
153         *            set to true to have this dialog close the app on close
154         */
155        public void setExitOnClose(boolean exitOnClose) {
156            this.exitOnClose = exitOnClose;
157        }
158    
159        /**
160         * cancels this dialog, and if exitOnClose is set, the application quits
161         */
162        private void cancelHandler() {
163            if (exitOnClose) {
164                System.exit(0);
165            } else {
166                isShowing = false;
167                dispose();
168                BuddyList.getInstance().getContainerFrame().setVisible(true);
169            }
170        }
171    
172        /**
173         * Adds event listeners
174         */
175        private void addListeners() {
176            cancelButton.addActionListener(new ActionListener() {
177                public void actionPerformed(ActionEvent e) {
178                    cancelHandler();
179                }
180            });
181    
182            editButton.addActionListener(new ActionListener() {
183                public void actionPerformed(ActionEvent e) {
184                    String string = (String) profileList.getSelectedValue();
185                    
186                    selected = string;
187                    if (string != null && string.endsWith(defaultString)) {
188                        int index = string.indexOf(defaultString);
189                        string = string.substring(0, index);
190                    }
191    
192                    new ProfileEditorDialog(ProfileManager.this,
193                        ProfileManager.this, string).setVisible(true);
194                }
195            });
196    
197            newButton.addActionListener(new ActionListener() {
198                public void actionPerformed(ActionEvent e) {
199                    new ProfileEditorDialog(ProfileManager.this,
200                        ProfileManager.this, null).setVisible(true);
201                }
202            });
203    
204            deleteButton.addActionListener(new ActionListener() {
205                public void actionPerformed(ActionEvent e) {
206                    String string = (String) profileList.getSelectedValue();
207                    if (string != null && string.endsWith(defaultString)) {
208                        int index = string.indexOf(defaultString);
209                        string = string.substring(0, index);
210                    }
211    
212                    int result = JOptionPane.showConfirmDialog(null, resources
213                            .getString("deleteProfile"), "JBother",
214                            JOptionPane.YES_NO_OPTION);
215    
216                    if (result == 0) {
217                        try {
218                            MiscUtils.recursivelyDeleteDirectory(profDir.getPath()
219                                    + File.separatorChar + string);
220                        } catch (Exception ex) {
221                            Standard.warningMessage(ProfileManager.this, "JBother",
222                                    resources.getString("errorDeletingProfile"));
223                            com.valhalla.Logger.logException(ex);
224                            return;
225                        }
226    
227                        loadProfileList();
228                    }
229                }
230            });
231    
232            openButton.addActionListener(new ActionListener() {
233                public void actionPerformed(ActionEvent e) {
234                    openHandler();
235                }
236            });
237    
238            profileList.addMouseListener(new MouseClickListener());
239        }
240    
241        public void openHandler() {
242            String string = (String) profileList.getSelectedValue();
243            if (string != null && string.endsWith(defaultString)) {
244                int index = string.indexOf(defaultString);
245                string = string.substring(0, index);
246            }
247    
248            loadProfile(string);
249            isShowing = false;
250            dispose();
251        }
252    
253        /**
254         * Loads a profile
255         *
256         * @param profile
257         *            the profile to load
258         */
259        public static void loadProfile(String profile) {
260            Settings.loadSettings(profDir.getPath() + File.separatorChar + profile,
261                    "settings.properties");
262            if (JBother.kiosk_mode
263                    && Arguments.getInstance().getProperty("kiosk_roomservice") != null) {
264                Settings.createKioskRoom();
265            }
266            JBother.profileDir = JBother.settingsDir + File.separatorChar
267                    + "profiles" + File.separatorChar + profile;
268    
269            GnuPG gnupg = new GnuPG();
270            JBotherLoader.setGPGEnabled(gnupg.listKeys(""));
271    
272            String fontString = Settings.getInstance().getProperty(
273                    "applicationFont");
274            if (fontString == null) {
275                fontString = "Default-PLAIN-12";
276            }
277    
278            Font newFont = Font.decode(fontString);
279            com.valhalla.jbother.preferences.AppearancePreferencesPanel
280                    .updateApplicationFonts(newFont, null);
281            ConversationFormatter.getInstance().switchTheme(
282                    Settings.getInstance().getProperty("emoticonTheme"));
283            StatusIconCache.clearStatusIconCache();
284    
285            BuddyList.getInstance().loadSettings();
286            JBotherLoader.loadSettings();
287    
288            if (JBotherLoader.isGPGEnabled()
289                    && Settings.getInstance().getBoolean("gnupgSavePassphrase")
290                    && Settings.getInstance().getProperty("gnupgSecretKeyID") != null) {
291                String pass = Settings.getInstance().getProperty("gnupgPassPhrase");
292                if (pass == null)
293                    pass = "";
294                pass = SimpleXOR.decrypt(pass, "86753099672539");
295    
296                gnupg = new GnuPG();
297    
298                String gnupgSecretKeyID = Settings.getInstance().getProperty(
299                        "gnupgSecretKeyID");
300    
301                if (gnupg.sign("1", gnupgSecretKeyID, pass)) {
302                    BuddyList.getInstance().setGnuPGPassword(pass);
303                } else {
304                    BuddyList.getInstance().setGnuPGPassword(null);
305                    Standard.warningMessage(null, "GnuPG", resources
306                            .getString("gnupgBadSavedPassword"));
307                }
308            }
309    
310            if (Settings.getInstance().getBoolean("autoLogin")) {
311                ConnectorThread.getInstance().setCancelled(false);
312                ConnectorThread.getInstance().init(Presence.Mode.AVAILABLE, "Available", false).start();
313            }
314    
315            if (Settings.getInstance().getBoolean("useProxy"))
316            {
317                Properties sysProperties = System.getProperties();
318                sysProperties.setProperty("proxySet", "true");
319                sysProperties.setProperty("proxyHost", Settings.getInstance().getProperty("proxyHost"));
320                sysProperties.setProperty("proxyPort", Settings.getInstance().getProperty("proxyPort"));
321            }
322    
323            currentProfile = profile;
324        }
325    
326        /**
327         * Loads a list of profiles
328         */
329        protected void loadProfileList() {
330            if (!profDir.isDirectory() && !profDir.mkdirs()) {
331                com.valhalla.Logger
332                        .debug("Could not create profile directory!  Please check permissions on ~/.jbother");
333                System.exit(-1);
334            }
335    
336            model = new ProfileListModel();
337    
338            String list[] = profDir.list(new FilenameFilter() {
339                public boolean accept(File dir, String name) {
340                    if (new File(dir, name).isDirectory()) {
341                        return true;
342                    } else {
343                        return false;
344                    }
345                }
346            });
347    
348            for (int i = 0; i < list.length; i++) {
349                model.addElement(list[i]);
350            }
351    
352            profileList.setModel(model);
353    
354            selectDefault();
355        }
356    
357        /**
358         * Selects the default profile and labels it (default)
359         */
360        private void selectDefault() {
361            String defaultProfile = getDefaultProfile();
362            if (defaultProfile == null) {
363                setDefaultProfile(defaultProfile);
364                return;
365            }
366            
367            boolean def = true;
368            
369            if(selected != null && model.indexOf(selected) != -1) 
370                defaultProfile = (String)selected;
371                
372                    
373    
374            int index = model.indexOf(defaultProfile);
375            if (index != -1) {
376                profileList.setSelectedIndex(index);
377            } else {
378                profileList.setSelectedIndex(0);
379            }
380        }
381    
382        /**
383         * Gets the current default profile, or the first profile in the profiles
384         * directory
385         *
386         * @return The default profile
387         */
388        public static String getDefaultProfile() {
389            File file = new File(profDir, "default.properties");
390            if (!file.exists()) {
391                return getOnlyProfile();
392            }
393    
394            Properties def = new Properties();
395            try {
396                InputStream stream = new FileInputStream(file);
397    
398                def.load(stream);
399                stream.close();
400            } catch (IOException e) {
401                com.valhalla.Logger.logException(e);
402                return getOnlyProfile();
403            }
404    
405            return def.getProperty("defaultProfile");
406        }
407    
408        /**
409         * Gets the first profile in the profile directory
410         *
411         * @return The first profile in the profile directory, or <tt>null</tt> if
412         *         there are no profiles
413         */
414        public static String getOnlyProfile() {
415            if (JBother.kiosk_mode)
416                return Arguments.getInstance().getProperty("kiosk_user");
417    
418            String[] list = profDir.list();
419            if (list != null && list.length > 0) {
420                return list[0];
421            } else {
422                return null;
423            }
424        }
425    
426        /**
427         * Sets the default profile
428         *
429         * @param profile
430         *            The profile to set
431         */
432        public static void setDefaultProfile(String profile) {
433            File file = new File(profDir, "default.properties");
434    
435            try {
436                OutputStream stream = new FileOutputStream(file);
437                Properties def = new Properties();
438                def.setProperty("defaultProfile", profile);
439                def.store(stream, "default profile setting");
440                stream.close();
441            } catch (Exception e) {
442                com.valhalla.Logger.logException(e);
443            }
444        }
445        
446        class ListRenderer extends JLabel implements ListCellRenderer
447        {
448            public ListRenderer()
449            {
450                setOpaque(true);
451            }
452            
453            public Component getListCellRendererComponent(
454                JList list,
455                Object value,
456                int index,
457                boolean isSelected,
458                boolean cellHasFocus)
459            {
460                String def = getDefaultProfile();
461                setSelected(isSelected);
462                String val = (String)value;
463                if(def.equals(val)) val += defaultString;
464                setText(val);
465                
466    
467                return this;
468            }
469            
470            public void setSelected(boolean selected)
471            {
472                if(selected) setBackground(profileList.getSelectionBackground());
473                else setBackground(Color.WHITE);
474            }
475        }
476    
477        /**
478         * The JList model for the profiles list
479         *
480         * @author synic
481         * @created November 30, 2004
482         */
483        class ProfileListModel extends DefaultListModel {
484            /**
485             * Sets the valueAt attribute of the ProfileListModel object
486             *
487             * @param index
488             *            The new valueAt value
489             * @param value
490             *            The new valueAt value
491             */
492            public void setValueAt(int index, String value) {
493                model.removeElementAt(index);
494                model.insertElementAt(value, index);
495                fireContentsChanged(model, index, index + 1);
496            }
497        }
498    }
499