1 /*
2 * (C) 2002 David Carr david@carr.name
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20 package net.sourceforge.mflow.skin;
21
22 import java.awt;
23 import java.awt.event;
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.Vector;
27 import java.util.ResourceBundle;
28 import javax.swing;
29 import java.lang.reflect;
30
31 /**
32 * A dialog to select a skin using the SkinLookAndFeel API if available
33 * Also provides a method to determine whether the SkinLookAndFeel is installed
34 *
35 * @author <a href="mailto:david@carr.name">David Carr</a>
36 */
37 public class SkinChooser extends JDialog {
38 /**
39 * Private reference to the list of skins
40 */
41 private JList mSkinList = new JList();
42 /**
43 * Private storage for the directories to search for skins
44 */
45 private String[] mDirectories = null;
46 /**
47 * Private storage of components to update
48 */
49 private Vector mComponentsToUpdate = new Vector();
50
51 /**
52 * Constructor to initialize the dialog's user interface
53 *
54 * @param parent the parent of this dialog
55 */
56 public SkinChooser(Frame parent) {
57 super(parent);
58 setTitle("Skin Chooser");
59 getContentPane().setLayout(new BorderLayout(3,3));
60
61 JPanel buttonPane = new JPanel(new GridLayout(1, 4, 3, 3));
62
63 SelectSkinAction ssa = new SelectSkinAction();
64 buttonPane.add(new JButton(ssa));
65
66 PreviewAction pa = new PreviewAction();
67 buttonPane.add(new JButton(pa));
68
69 RefreshAction ra = new RefreshAction();
70 buttonPane.add(new JButton(ra));
71
72 CancelAction ca = new CancelAction();
73 buttonPane.add(new JButton(ca));
74
75 getContentPane().add(new JScrollPane(mSkinList), BorderLayout.CENTER);
76 getContentPane().add(buttonPane, BorderLayout.SOUTH);
77 }
78
79 /**
80 * Refresh the skin list.
81 *
82 * @see #setSkinLocations
83 */
84 public void refreshList() {
85 if(mDirectories != null) {
86 Vector skins = new Vector();
87 for (int i = 0, c = mDirectories.length; i < c; i++) {
88 buildSkinList(skins, new File(mDirectories[i]));
89 }
90 mSkinList.setListData(skins);
91 }
92 }
93
94 /**
95 * Adds a component to be updated
96 *
97 * @param c the Component to add to the update list
98 */
99 public void addComponentToUpdate(Component c) {
100 mComponentsToUpdate.add(c);
101 }
102
103 /**
104 * Set search paths
105 *
106 * @param directories search paths
107 */
108 public void setSkinLocations(String[] directories) {
109 mDirectories = directories;
110 refreshList();
111 }
112
113 /**
114 * Gets the directories that are searched for skins
115 *
116 * @return search paths
117 */
118 public String[] getSkinLocations() {
119 return mDirectories;
120 }
121
122 /**
123 * Recursively traverse <code>directory</code> and add skin files to <code>v</code>.
124 * <br>
125 * Skin files are added if <code>accept(skinFile)</code> returns <code>true</code>
126 *
127 * @param v vector to store skin list
128 * @param directory the directory to list for skin files
129 */
130 protected void buildSkinList(Vector v, File directory) {
131 if (!directory.isDirectory() || !directory.exists()) {
132 return;
133 }
134
135 String[] files = directory.list();
136 File f;
137 for (int i = 0, c = files.length; i < c; i++) {
138 f = new File(directory, files[i]);
139 if (f.isDirectory()) {
140 buildSkinList(v, f);
141 } else if (accept(f)) {
142 try {
143 v.addElement(f.getCanonicalPath());
144 } catch (IOException e) {}
145 }
146 }
147 }
148
149 /**
150 * Check if a given file is a skin file.
151 * <br/>
152 * The default implementation checks if the file ends with zip.
153 *
154 * @param f the file to check
155 * @return true if the file is a valid skin file
156 */
157 protected boolean accept(File f) {
158 return f.isDirectory() == false && f.getName().endsWith(".zip");
159 }
160
161 /**
162 * Returns an array of the currently selected skins
163 *
164 * @return the currently selected skins
165 */
166 public String[] getSelectedSkins() {
167 return (String[])mSkinList.getSelectedValues();
168 }
169
170 /**
171 * Action to refresh the list of skins
172 */
173 private class RefreshAction extends AbstractAction {
174 /**
175 * Sets the text for the Action
176 */
177 public RefreshAction() {
178 super("Refresh");
179 }
180
181 /**
182 * Refreshes the list of skins
183 *
184 * @param event the event
185 */
186 public void actionPerformed(ActionEvent event) {
187 refreshList();
188 }
189 }
190
191 /**
192 * Action to cancel a skin choice
193 */
194 private class CancelAction extends AbstractAction {
195 /**
196 * Sets the text for the Action
197 */
198 public CancelAction() {
199 super("Cancel");
200 }
201
202 /**
203 * Cancels the dialog
204 *
205 * @param event the event
206 */
207 public void actionPerformed(ActionEvent event) {
208 processWindowEvent(new WindowEvent(SkinChooser.this, WindowEvent.WINDOW_CLOSING));
209 }
210 }
211
212 /**
213 * Action to preview a skin
214 */
215 private class PreviewAction extends AbstractAction {
216 /**
217 * Sets the text for the Action
218 */
219 public PreviewAction() {
220 super("Preview");
221 }
222
223 /**
224 * Previews the skin
225 *
226 * @param event the event
227 */
228 public void actionPerformed(ActionEvent event) {
229 Object oldSkin = null;
230 Method setSkin = null;
231 LookAndFeel oldLAF = UIManager.getLookAndFeel();
232 try {
233 Object nullObject = null;
234 Class slafClass = Class.forName("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
235 Method getSkin = slafClass.getMethod("getSkin", null);
236 oldSkin = getSkin.invoke(nullObject, null);//is of type com.l2fprod.gui.plaf.skin.Skin
237 Class skinClass = Class.forName("com.l2fprod.gui.plaf.skin.Skin");
238 Class[] skinParam = {
239 skinClass
240 };
241 setSkin = slafClass.getMethod("setSkin", skinParam);
242
243 Object[] values = mSkinList.getSelectedValues();
244 if(values == null) {
245 JOptionPane.showMessageDialog(SkinChooser.this, "No skins selected", "Invalid selection", JOptionPane.ERROR_MESSAGE);
246 return;
247 } else if(values.length > 1) {
248 JOptionPane.showMessageDialog(SkinChooser.this, "Too many skins selected", "Invalid selection", JOptionPane.ERROR_MESSAGE);
249 return;
250 }
251
252 Class[] stringParam = {
253 String.class
254 };
255 Method loadThemePack = slafClass.getMethod("loadThemePack", stringParam);
256 Object[] loadThemePackParam = {
257 (String)values[0]
258 };
259 Object skin = loadThemePack.invoke(nullObject, loadThemePackParam);
260 Object[] setSkinParam = {
261 skin
262 };
263 setSkin.invoke(nullObject, setSkinParam);
264 UIManager.setLookAndFeel("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
265
266 Class skinWindowClass = Class.forName("com.l2fprod.gui.plaf.skin.SkinPreviewWindow");
267 Object window = skinWindowClass.newInstance();
268 Class[] booleanParam = {
269 boolean.class
270 };
271 Method setVisible = skinWindowClass.getMethod("setVisible", booleanParam);
272 Object[] setVisibleParam = {
273 Boolean.TRUE
274 };
275 setVisible.invoke(window, setVisibleParam);
276 } catch (Exception e) {
277 e.printStackTrace();
278 } finally {
279 if(oldSkin != null && setSkin != null) {
280 Object[] setOldSkinParam = {
281 oldSkin
282 };
283 try{
284 setSkin.invoke(null, setOldSkinParam);
285 } catch(Exception ie) { }
286 }
287 if(oldLAF != null) {
288 try {
289 UIManager.setLookAndFeel(oldLAF);
290 } catch (UnsupportedLookAndFeelException e) { }
291 }
292 }
293 }
294 }
295
296 /**
297 * Action to select a skin
298 */
299 private class SelectSkinAction extends AbstractAction {
300 /**
301 * Sets the text for the Action
302 */
303 public SelectSkinAction() {
304 super("Select");
305 }
306
307 /**
308 * Selects the skin
309 *
310 * @param event the event
311 */
312 public void actionPerformed(ActionEvent event) {
313 try {
314 Object nullObject = null;
315 Class slafClass = Class.forName("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
316 Object[] values = mSkinList.getSelectedValues();
317 if(values == null) {
318 JOptionPane.showMessageDialog(SkinChooser.this, "No skins selected", "Invalid selection", JOptionPane.ERROR_MESSAGE);
319 return;
320 } else if(values.length > 1) {
321 JOptionPane.showMessageDialog(SkinChooser.this, "Too many skins selected", "Invalid selection", JOptionPane.ERROR_MESSAGE);
322 return;
323 }
324
325 // UIManager.put("JDesktopPane.backgroundEnabled", Boolean.TRUE);
326 // UIManager.put("ScrollBar.alternateLayout", Boolean.TRUE);
327
328 Class[] stringParam = {
329 String.class
330 };
331 Method loadThemePack = slafClass.getMethod("loadThemePack", stringParam);
332 Object[] loadThemePackParam = {
333 (String)values[0]
334 };
335 Object skin = loadThemePack.invoke(nullObject, loadThemePackParam);
336 Class skinClass = Class.forName("com.l2fprod.gui.plaf.skin.Skin");
337 Class[] skinParam = {
338 skinClass
339 };
340 Method setSkin = slafClass.getMethod("setSkin", skinParam);
341 Object[] setSkinParam = {
342 skin
343 };
344 setSkin.invoke(nullObject, setSkinParam);
345 UIManager.setLookAndFeel("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
346 } catch (Exception e) {
347 e.printStackTrace();
348 }
349 for(int i=0; i<mComponentsToUpdate.size(); i++) {
350 Component c = (Component) mComponentsToUpdate.get(i);
351 c.setVisible(false);
352 SwingUtilities.updateComponentTreeUI(c);
353 c.setVisible(true);
354 }
355 processWindowEvent(new WindowEvent(SkinChooser.this, WindowEvent.WINDOW_CLOSING));
356 }
357 }
358
359 /**
360 * Returns whether or not skin support is installed by testing to see whether SkinLookAndFeel can be loaded
361 *
362 * @return whether skin support is installed
363 */
364 public static boolean isSkinSupportInstalled() {
365 try{
366 Class slaf = Class.forName("com.l2fprod.gui.plaf.skin.SkinLookAndFeel");
367 return slaf != null;
368 } catch(Exception e) {
369 return false;
370 }
371 }
372 }