001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: package com.sshtools.common.ui;
027:
028: import com.sshtools.common.mru.MRUList;
029: import com.sshtools.common.mru.MRUListModel;
030: import com.sshtools.common.util.BrowserLauncher;
031:
032: import com.sshtools.j2ssh.configuration.ConfigurationLoader;
033: import com.sshtools.j2ssh.io.IOUtil;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037:
038: import java.awt.Color;
039: import java.awt.Component;
040: import java.awt.Cursor;
041: import java.awt.Font;
042: import java.awt.GridBagConstraints;
043: import java.awt.GridBagLayout;
044: import java.awt.Insets;
045: import java.awt.event.MouseAdapter;
046: import java.awt.event.MouseEvent;
047:
048: import java.io.File;
049: import java.io.FileInputStream;
050: import java.io.FileOutputStream;
051: import java.io.FilePermission;
052: import java.io.IOException;
053: import java.io.InputStream;
054: import java.io.PrintWriter;
055:
056: import java.security.AccessControlException;
057: import java.security.AccessController;
058:
059: import java.util.Iterator;
060: import java.util.Vector;
061:
062: import javax.swing.BorderFactory;
063: import javax.swing.Icon;
064: import javax.swing.JLabel;
065: import javax.swing.JOptionPane;
066: import javax.swing.JPanel;
067: import javax.swing.LookAndFeel;
068: import javax.swing.UIManager;
069:
070: /**
071: * An abstract application class that provides container management, look
072: * and feel configuration and most recently used menus.
073: *
074: * @author Brett Smith
075: * @version $Revision: 1.19 $
076: */
077: public abstract class SshToolsApplication {
078: /** */
079: public final static String PREF_CONNECTION_LAST_HOST = "apps.connection.lastHost";
080:
081: /** */
082: public final static String PREF_CONNECTION_LAST_USER = "apps.connection.lastUser";
083:
084: /** */
085: public final static String PREF_CONNECTION_LAST_PORT = "apps.connection.lastPort";
086:
087: /** */
088: public final static String PREF_CONNECTION_LAST_KEY = "apps.connection.lastKey";
089:
090: /** */
091: public final static String PREF_LAF = "apps.laf";
092:
093: /** */
094: public final static String CROSS_PLATFORM_LAF = "CROSS_PLATFORM";
095:
096: /** */
097: public final static String DEFAULT_LAF = "DEFAULT";
098:
099: /** */
100: public final static String SYSTEM_LAF = "SYSTEM";
101:
102: /** */
103: protected static Vector containers = new Vector();
104:
105: /** */
106: protected static Log log = LogFactory
107: .getLog(SshToolsApplication.class);
108:
109: /** */
110: protected static MRUListModel mruModel;
111: private static UIManager.LookAndFeelInfo[] allLookAndFeelInfo;
112:
113: static {
114: UIManager.LookAndFeelInfo[] i;
115:
116: try {
117: i = UIManager.getInstalledLookAndFeels();
118: } catch (Throwable t) {
119: i = new UIManager.LookAndFeelInfo[0];
120: }
121:
122: allLookAndFeelInfo = new UIManager.LookAndFeelInfo[i.length + 3];
123: System.arraycopy(i, 0, allLookAndFeelInfo, 0, i.length);
124: allLookAndFeelInfo[i.length] = new UIManager.LookAndFeelInfo(
125: "Default", DEFAULT_LAF);
126:
127: allLookAndFeelInfo[i.length + 1] = new UIManager.LookAndFeelInfo(
128: "Cross Platform", CROSS_PLATFORM_LAF);
129: allLookAndFeelInfo[i.length + 2] = new UIManager.LookAndFeelInfo(
130: "System", SYSTEM_LAF);
131: }
132:
133: /** */
134: protected Class panelClass;
135:
136: /** */
137: protected Class defaultContainerClass;
138:
139: /** */
140: protected java.util.List additionalOptionsTabs;
141:
142: /**
143: * Creates a new SshToolsApplication object.
144: *
145: * @param panelClass
146: * @param defaultContainerClass
147: */
148: public SshToolsApplication(Class panelClass,
149: Class defaultContainerClass) {
150: this .panelClass = panelClass;
151: this .defaultContainerClass = defaultContainerClass;
152: additionalOptionsTabs = new java.util.ArrayList();
153:
154: try {
155: if (System.getSecurityManager() != null) {
156: AccessController.checkPermission(new FilePermission(
157: "<<ALL FILES>>", "write"));
158: }
159:
160: File a = getApplicationPreferencesDirectory();
161:
162: if (a == null) {
163: throw new AccessControlException(
164: "Application preferences directory not specified.");
165: }
166:
167: InputStream in = null;
168: MRUList mru = new MRUList();
169:
170: try {
171: File f = new File(a, getApplicationName() + ".mru");
172:
173: if (f.exists()) {
174: if (log.isDebugEnabled()) {
175: log.debug("Loading MRU from "
176: + f.getAbsolutePath());
177: }
178:
179: in = new FileInputStream(f);
180: mru.reload(in);
181: } else {
182: if (log.isDebugEnabled()) {
183: log
184: .debug("MRU file "
185: + f.getAbsolutePath()
186: + " doesn't exist, creating empty list");
187: }
188: }
189: } catch (Exception e) {
190: log.error("Could not load MRU list.", e);
191: } finally {
192: IOUtil.closeStream(in);
193: }
194:
195: mruModel = new MRUListModel();
196: mruModel.setMRUList(mru);
197: } catch (AccessControlException ace) {
198: log.error("Could not load MRU.", ace);
199: }
200: }
201:
202: /**
203: *
204: *
205: * @return
206: */
207: public static UIManager.LookAndFeelInfo[] getAllLookAndFeelInfo() {
208: return allLookAndFeelInfo;
209: }
210:
211: /**
212: *
213: *
214: * @return
215: */
216: public MRUListModel getMRUModel() {
217: return mruModel;
218: }
219:
220: /**
221: *
222: *
223: * @return
224: */
225: public abstract String getApplicationName();
226:
227: /**
228: *
229: *
230: * @return
231: */
232: public abstract String getApplicationVersion();
233:
234: /**
235: *
236: *
237: * @return
238: */
239: public abstract Icon getApplicationLargeIcon();
240:
241: /**
242: *
243: *
244: * @return
245: */
246: public abstract String getAboutLicenseDetails();
247:
248: /**
249: *
250: *
251: * @return
252: */
253: public abstract String getAboutURL();
254:
255: /**
256: *
257: *
258: * @return
259: */
260: public abstract String getAboutAuthors();
261:
262: /**
263: *
264: *
265: * @return
266: */
267: public abstract File getApplicationPreferencesDirectory();
268:
269: /**
270: *
271: *
272: * @return
273: */
274: public OptionsTab[] getAdditionalOptionsTabs() {
275: OptionsTab[] t = new OptionsTab[additionalOptionsTabs.size()];
276: additionalOptionsTabs.toArray(t);
277:
278: return t;
279: }
280:
281: /**
282: *
283: *
284: * @param tab
285: */
286: public void addAdditionalOptionsTab(OptionsTab tab) {
287: if (!additionalOptionsTabs.contains(tab)) {
288: additionalOptionsTabs.add(tab);
289: }
290: }
291:
292: /**
293: *
294: *
295: * @param tab
296: */
297: public void removeAdditionalOptionsTab(OptionsTab tab) {
298: additionalOptionsTabs.remove(tab);
299: }
300:
301: /**
302: *
303: *
304: * @param title
305: */
306: public void removeAdditionalOptionsTab(String title) {
307: OptionsTab t = getOptionsTab(title);
308:
309: if (t != null) {
310: removeAdditionalOptionsTab(t);
311: }
312: }
313:
314: /**
315: *
316: *
317: * @param title
318: *
319: * @return
320: */
321: public OptionsTab getOptionsTab(String title) {
322: for (Iterator i = additionalOptionsTabs.iterator(); i.hasNext();) {
323: OptionsTab t = (OptionsTab) i.next();
324:
325: if (t.getTabTitle().equals(title)) {
326: return t;
327: }
328: }
329:
330: return null;
331: }
332:
333: /**
334: *
335: */
336: public void exit() {
337: log.debug("Exiting application");
338: PreferencesStore.savePreferences();
339:
340: FileOutputStream out = null;
341: File a = getApplicationPreferencesDirectory();
342:
343: if (a != null) {
344: try {
345: File f = new File(getApplicationPreferencesDirectory(),
346: getApplicationName() + ".mru");
347: ;
348:
349: if (log.isDebugEnabled()) {
350: log.debug("Saving MRU to " + f.getAbsolutePath());
351: }
352:
353: out = new FileOutputStream(f);
354:
355: PrintWriter w = new PrintWriter(out, true);
356: w.println(mruModel.getMRUList().toString());
357: } catch (IOException ioe) {
358: log.error("Could not save MRU. ", ioe);
359: } finally {
360: IOUtil.closeStream(out);
361: }
362: } else {
363: log
364: .debug("Not saving preferences because no preferences directory is available.");
365: }
366:
367: System.exit(0);
368: }
369:
370: /**
371: *
372: *
373: * @return
374: */
375: public int getContainerCount() {
376: return containers.size();
377: }
378:
379: /**
380: *
381: *
382: * @param idx
383: *
384: * @return
385: */
386: public SshToolsApplicationContainer getContainerAt(int idx) {
387: return (SshToolsApplicationContainer) containers.elementAt(idx);
388: }
389:
390: /**
391: *
392: *
393: * @param panel
394: *
395: * @return
396: */
397: public SshToolsApplicationContainer getContainerForPanel(
398: SshToolsApplicationPanel panel) {
399: for (Iterator i = containers.iterator(); i.hasNext();) {
400: SshToolsApplicationContainer c = (SshToolsApplicationContainer) i
401: .next();
402:
403: if (c.getApplicationPanel() == panel) {
404: return c;
405: }
406: }
407:
408: return null;
409: }
410:
411: /**
412: *
413: *
414: * @param container
415: */
416: public void closeContainer(SshToolsApplicationContainer container) {
417: if (log.isDebugEnabled()) {
418: log.debug("Asking " + container + " if it can close");
419: }
420:
421: if (container.getApplicationPanel().canClose()) {
422: if (log.isDebugEnabled()) {
423: log.debug("Closing");
424:
425: for (Iterator i = containers.iterator(); i.hasNext();) {
426: log.debug(i.next() + " is currently open");
427: }
428: }
429:
430: container.getApplicationPanel().close();
431: container.closeContainer();
432: containers.removeElement(container);
433:
434: if (containers.size() == 0) {
435: exit();
436: } else {
437: log
438: .debug("Not closing completely because there are containers still open");
439:
440: for (Iterator i = containers.iterator(); i.hasNext();) {
441: log.debug(i.next() + " is still open");
442: }
443: }
444: }
445: }
446:
447: /**
448: * Show an 'About' dialog
449: *
450: *
451: */
452: public void showAbout(Component parent) {
453: JPanel p = new JPanel(new GridBagLayout());
454: p.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
455:
456: GridBagConstraints gBC = new GridBagConstraints();
457: gBC.anchor = GridBagConstraints.CENTER;
458: gBC.fill = GridBagConstraints.HORIZONTAL;
459: gBC.insets = new Insets(1, 1, 1, 1);
460:
461: JLabel a = new JLabel(getApplicationName());
462: a.setFont(a.getFont().deriveFont(24f));
463: UIUtil.jGridBagAdd(p, a, gBC, GridBagConstraints.REMAINDER);
464:
465: JLabel v = new JLabel(ConfigurationLoader.getVersionString(
466: getApplicationName(), getApplicationVersion()));
467: v.setFont(v.getFont().deriveFont(10f));
468: UIUtil.jGridBagAdd(p, v, gBC, GridBagConstraints.REMAINDER);
469:
470: MultilineLabel x = new MultilineLabel(getAboutAuthors());
471: x.setBorder(BorderFactory.createEmptyBorder(8, 0, 8, 0));
472: x.setFont(x.getFont().deriveFont(12f));
473: UIUtil.jGridBagAdd(p, x, gBC, GridBagConstraints.REMAINDER);
474:
475: MultilineLabel c = new MultilineLabel(getAboutLicenseDetails());
476: c.setFont(c.getFont().deriveFont(10f));
477: UIUtil.jGridBagAdd(p, c, gBC, GridBagConstraints.REMAINDER);
478:
479: final JLabel h = new JLabel(getAboutURL());
480: h.setForeground(Color.blue);
481: h.setFont(new Font(h.getFont().getName(), Font.BOLD, 10));
482: h.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
483: h.addMouseListener(new MouseAdapter() {
484: public void mouseClicked(MouseEvent evt) {
485: try {
486: BrowserLauncher.openURL(getAboutURL());
487: } catch (IOException ioe) {
488: ioe.printStackTrace();
489: }
490: }
491: });
492: UIUtil.jGridBagAdd(p, h, gBC, GridBagConstraints.REMAINDER);
493: JOptionPane.showMessageDialog(parent, p, "About",
494: JOptionPane.PLAIN_MESSAGE, getApplicationLargeIcon());
495: }
496:
497: /**
498: *
499: *
500: * @return
501: *
502: * @throws SshToolsApplicationException
503: */
504: public SshToolsApplicationContainer newContainer()
505: throws SshToolsApplicationException {
506: SshToolsApplicationContainer container = null;
507:
508: try {
509: container = (SshToolsApplicationContainer) defaultContainerClass
510: .newInstance();
511: newContainer(container);
512:
513: return container;
514: } catch (Throwable t) {
515: throw new SshToolsApplicationException(t);
516: }
517: }
518:
519: /**
520: *
521: *
522: * @param container
523: *
524: * @throws SshToolsApplicationException
525: */
526: public void newContainer(SshToolsApplicationContainer container)
527: throws SshToolsApplicationException {
528: try {
529: SshToolsApplicationPanel panel = (SshToolsApplicationPanel) panelClass
530: .newInstance();
531: panel.init(this );
532: panel.rebuildActionComponents();
533: panel.setAvailableActions();
534: container.init(this , panel);
535: panel.setContainer(container);
536:
537: if (!container.isContainerVisible()) {
538: container.setContainerVisible(true);
539: }
540:
541: containers.addElement(container);
542: } catch (Throwable t) {
543: throw new SshToolsApplicationException(t);
544: }
545: }
546:
547: /**
548: *
549: *
550: * @param container
551: * @param newContainerClass
552: *
553: * @return
554: *
555: * @throws SshToolsApplicationException
556: */
557: public SshToolsApplicationContainer convertContainer(
558: SshToolsApplicationContainer container,
559: Class newContainerClass)
560: throws SshToolsApplicationException {
561: log.info("Converting container of class "
562: + container.getClass().getName() + " to "
563: + newContainerClass.getName());
564:
565: int idx = containers.indexOf(container);
566:
567: if (idx == -1) {
568: throw new SshToolsApplicationException(
569: "Container is not being manager by the application.");
570: }
571:
572: SshToolsApplicationContainer newContainer = null;
573:
574: try {
575: container.closeContainer();
576:
577: SshToolsApplicationPanel panel = container
578: .getApplicationPanel();
579: newContainer = (SshToolsApplicationContainer) newContainerClass
580: .newInstance();
581: newContainer.init(this , panel);
582: panel.setContainer(newContainer);
583:
584: if (!newContainer.isContainerVisible()) {
585: newContainer.setContainerVisible(true);
586: }
587:
588: containers.setElementAt(newContainer, idx);
589:
590: return newContainer;
591: } catch (Throwable t) {
592: throw new SshToolsApplicationException(t);
593: }
594: }
595:
596: /**
597: *
598: *
599: * @param args
600: *
601: * @throws SshToolsApplicationException
602: */
603: public void init(String[] args) throws SshToolsApplicationException {
604: File f = getApplicationPreferencesDirectory();
605:
606: if (f != null) {
607: //
608: PreferencesStore.init(new File(f, getApplicationName()
609: + ".properties"));
610: log.info("Preferences will be saved to "
611: + f.getAbsolutePath());
612: } else {
613: log.warn("No preferences can be saved.");
614: }
615:
616: try {
617: setLookAndFeel(PreferencesStore.get(PREF_LAF, SYSTEM_LAF));
618: UIManager.put("OptionPane.errorIcon", new ResourceIcon(
619: SshToolsApplication.class, "dialog-error4.png"));
620: UIManager.put("OptionPane.informationIcon",
621: new ResourceIcon(SshToolsApplication.class,
622: "dialog-information.png"));
623: UIManager.put("OptionPane.warningIcon", new ResourceIcon(
624: SshToolsApplication.class, "dialog-warning2.png"));
625: UIManager.put("OptionPane.questionIcon", new ResourceIcon(
626: SshToolsApplication.class, "dialog-question3.png"));
627: } catch (Throwable t) {
628: log.error(t);
629: }
630: }
631:
632: /**
633: *
634: *
635: * @param className
636: *
637: * @throws Exception
638: */
639: public static void setLookAndFeel(String className)
640: throws Exception {
641: LookAndFeel laf = null;
642:
643: if (!className.equals(DEFAULT_LAF)) {
644: if (className.equals(SYSTEM_LAF)) {
645: String systemLaf = UIManager
646: .getSystemLookAndFeelClassName();
647: log.debug("System Look And Feel is " + systemLaf);
648: laf = (LookAndFeel) Class.forName(systemLaf)
649: .newInstance();
650: } else if (className.equals(CROSS_PLATFORM_LAF)) {
651: String crossPlatformLaf = UIManager
652: .getCrossPlatformLookAndFeelClassName();
653: log.debug("Cross Platform Look And Feel is "
654: + crossPlatformLaf);
655: laf = (LookAndFeel) Class.forName(crossPlatformLaf)
656: .newInstance();
657: } else {
658: laf = (LookAndFeel) Class.forName(className)
659: .newInstance();
660: }
661: }
662:
663: // Now actually set the look and feel
664: if (laf != null) {
665: log.info("Setting look and feel " + laf.getName() + " ("
666: + laf.getClass().getName() + ")");
667: UIManager.setLookAndFeel(laf);
668: UIManager.put("EditorPane.font", UIManager
669: .getFont("TextArea.font"));
670: }
671: }
672: }
|