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