1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.xnap.commons.gui;
22
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Component;
26 import java.awt.Cursor;
27 import java.awt.Dimension;
28 import java.awt.Font;
29 import java.util.Hashtable;
30 import java.util.Map;
31 import javax.swing.Icon;
32 import javax.swing.JComponent;
33 import javax.swing.JDialog;
34 import javax.swing.JEditorPane;
35 import javax.swing.JFrame;
36 import javax.swing.JLabel;
37 import javax.swing.JPanel;
38 import javax.swing.JScrollPane;
39 import javax.swing.JTabbedPane;
40 import javax.swing.JTextArea;
41 import javax.swing.border.EmptyBorder;
42 import javax.swing.event.HyperlinkEvent;
43 import javax.swing.event.HyperlinkListener;
44 import javax.swing.text.JTextComponent;
45 import org.xnap.commons.gui.util.GUIHelper;
46 import org.xnap.commons.i18n.I18nFactory;
47
48 /***
49 * Simple about dialog. A {@link JTabbedPane} is used as the main widget and
50 * methods are provided to add tabs that contain a file, e.g. the software
51 * license.
52 */
53 public class AboutDialog extends DefaultDialog {
54
55 private CloseableTabbedPane tabbedPane;
56 private Map<String, JComponent> tabByFilename = new Hashtable<String, JComponent>();
57
58 /***
59 * Constructs an empty dialog with a single close button.
60 *
61 * @param owner the dialog owner
62 */
63 public AboutDialog(JDialog owner)
64 {
65 super(owner, BUTTON_CLOSE);
66
67 initialize();
68 }
69
70 /***
71 * Constructs an empty dialog with a single close button.
72 *
73 * @param owner the dialog owner
74 */
75 public AboutDialog(JFrame owner)
76 {
77 super(owner, BUTTON_CLOSE);
78
79 initialize();
80 }
81
82 /***
83 * Constructs an empty dialog with a single close button.
84 */
85 public AboutDialog()
86 {
87 super(BUTTON_CLOSE);
88
89 initialize();
90 }
91
92 private void initialize()
93 {
94 tabbedPane = new CloseableTabbedPane();
95 tabbedPane.setPreferredSize(new Dimension(600, 300));
96 tabbedPane.setCloseListener(new CloseableTabbedPane.CloseListener() {
97 public void closeRequested(Component component)
98 {
99 tabbedPane.remove(component);
100 tabByFilename.values().remove(component);
101 }
102 });
103
104 setMainComponent(tabbedPane);
105 setButtonSeparatorVisible(false);
106 pack();
107 }
108
109 /***
110 * Adds a tab that displays an image that is followed by a file's content.
111 *
112 * @param title the title of the tab
113 * @param image the image
114 * @param filename the name of the file to display
115 * @param alternativeMessage the text that is displayed if
116 * <code>filename</code> can not be read
117 * @return the text area that was added to the created tab
118 * @see GUIHelper#showFile(JTextComponent, String, String)
119 */
120 public JTextArea addLogoTab(String title, Icon image, String filename, String alternativeMessage, boolean closeable)
121 {
122 JPanel panel = new JPanel();
123 panel.setBackground(Color.white);
124 panel.setLayout(new BorderLayout());
125 JLabel logoLabel = new JLabel(image);
126 logoLabel.setBorder(new EmptyBorder(5, 5, 5, 5));
127 panel.add(logoLabel, BorderLayout.NORTH);
128 JTextArea textArea = new JTextArea(5, 40);
129 textArea .setEditable (false);
130 textArea .setBorder(new EmptyBorder(5, 5, 5, 5));
131 panel.add(textArea , BorderLayout.CENTER);
132 addTabInternal(textArea, title, filename, alternativeMessage, closeable);
133 return textArea ;
134 }
135
136 /***
137 * Adds a tab that displays an image that is followed by a file's content.
138 *
139 * @param title the title of the tab
140 * @param image the image
141 * @param filename the name of the file to display
142 * @return the text area that was added to the created tab
143 * @see #addLogoTab(String, Icon, String, String, boolean)
144 */
145 public JTextArea addLogoTab(String title, Icon image, String filename)
146 {
147 return addLogoTab(title, image, filename, getFileNotFoundMessage(filename), false);
148 }
149
150 /***
151 * Adds a tab that displays a file's content.
152 *
153 * @param title the title of the tab
154 * @param filename the name of the file to display
155 * @param alternativeMessage the text that is displayed if
156 * <code>filename</code> can not be read
157 * @return the text area that was added to the created tab
158 * @see GUIHelper#showFile(JTextComponent, String, String)
159 */
160 public JTextArea addTab(String title, String filename, String alternativeMessage, boolean closeable)
161 {
162 JTextArea textArea = new JTextArea(15, 40);
163 textArea.setBorder(new EmptyBorder(5, 5, 5, 5));
164 textArea.setEditable (false);
165 addTabInternal(textArea, title, filename, alternativeMessage, closeable);
166 return textArea;
167 }
168
169 /***
170 * Adds a tab that displays a file's content.
171 *
172 * @param title the title of the tab
173 * @param filename the name of the file to display
174 * @return the text area that was added to the created tab
175 * @see #addTab(String, String, String, boolean)
176 */
177 public JTextArea addTab(String title, String filename)
178 {
179 return addTab(title, filename, getFileNotFoundMessage(filename), false);
180 }
181
182 public JEditorPane addHTMLTab(String title, String filename, String alternativeMessage, boolean closeable, boolean followHyperlinks)
183 {
184 JEditorPane editorPane = new JEditorPane();
185 editorPane.setContentType("text/html");
186 editorPane.setEditable(false);
187 if (followHyperlinks) {
188 editorPane.addHyperlinkListener(new LicenseLinkListener());
189
190 }
191 editorPane.setBorder(GUIHelper.createEmptyBorder(5));
192 addTabInternal(editorPane, title, filename, alternativeMessage, closeable);
193 return editorPane;
194 }
195
196 public JEditorPane addHTMLTab(String title, String filename, boolean followHyperlinks)
197 {
198 return addHTMLTab(title, filename, getFileNotFoundMessage(filename), false, followHyperlinks);
199 }
200
201 private void addTabInternal(JTextComponent component, String title, String filename, String alternativeMessage, boolean closeable)
202 {
203 JScrollPane scrollPane = new JScrollPane(component);
204 GUIHelper.showFile(component, filename, alternativeMessage);
205 getTabbedPane().addTab(title, scrollPane, null, closeable);
206 tabByFilename.put(filename, scrollPane);
207 }
208
209 /***
210 * Returns the main widget.
211 */
212 public CloseableTabbedPane getTabbedPane()
213 {
214 return tabbedPane;
215 }
216
217 public String getFileNotFoundMessage(String filename)
218 {
219 return I18nFactory.getI18n(AboutDialog.class).tr("File {0} not found",
220 filename);
221 }
222
223 /***
224 * Adds a new license tab.
225 *
226 * License files are supposed to be pure text files.
227 *
228 * @param name of the license
229 * @param filename filename of the license text to load
230 */
231 public Component getOrAddTab(String name, String filename)
232 {
233 JComponent c = tabByFilename.get(filename);
234 if (c == null) {
235 if (filename.endsWith("html") || filename.endsWith("htm")) {
236 addHTMLTab(name, filename, getFileNotFoundMessage(filename), true, false);
237 }
238 else {
239 JTextArea textArea = addTab(name, filename, getFileNotFoundMessage(filename), true);
240 textArea.setFont(new Font("Monospaced", Font.PLAIN, 10));
241 }
242
243 c = tabByFilename.get(filename);
244 }
245 return c;
246 }
247
248 /***
249 * Listens for hyperlink events and switches the panels of the tabbed pain
250 * when the link description matches a license displayed in one of the
251 * panels.
252 */
253 private class LicenseLinkListener implements HyperlinkListener
254 {
255 public void hyperlinkUpdate(HyperlinkEvent event)
256 {
257 if (event.getDescription() == null) {
258 return;
259 }
260
261 if (event.getEventType() == HyperlinkEvent.EventType.ENTERED) {
262 setCursor(event, Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
263 }
264 else if (event.getEventType() == HyperlinkEvent.EventType.EXITED) {
265 setCursor(event, null);
266 }
267 else if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
268 setCursor(event, null);
269
270 Component c = getOrAddTab(event.getDescription(), event.getDescription());
271 tabbedPane.setSelectedComponent(c);
272 }
273 }
274
275 private void setCursor(HyperlinkEvent event, Cursor cursor)
276 {
277 JEditorPane pane = (JEditorPane)event.getSource();
278
279
280 AboutDialog.this.setCursor(cursor);
281 }
282
283 }
284
285 }