001: /*
002: * $Id: GUIInstaller.java 2061 2008-02-25 20:05:31Z jponge $
003: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
004: *
005: * http://izpack.org/
006: * http://izpack.codehaus.org/
007: *
008: * Licensed under the Apache License, Version 2.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: */
020:
021: package com.izforge.izpack.installer;
022:
023: import java.awt.Color;
024: import java.awt.Component;
025: import java.awt.Dimension;
026: import java.awt.Font;
027: import java.awt.GraphicsEnvironment;
028: import java.awt.GridBagConstraints;
029: import java.awt.GridBagLayout;
030: import java.awt.Insets;
031: import java.awt.Point;
032: import java.awt.Toolkit;
033: import java.awt.event.ActionEvent;
034: import java.awt.event.ActionListener;
035: import java.awt.event.WindowAdapter;
036: import java.awt.event.WindowEvent;
037: import java.io.InputStream;
038: import java.io.ObjectInputStream;
039: import java.lang.reflect.Method;
040: import java.util.HashMap;
041: import java.util.Iterator;
042: import java.util.List;
043: import java.util.Locale;
044: import java.util.Map;
045: import java.util.TreeMap;
046:
047: import javax.swing.GrayFilter;
048: import javax.swing.ImageIcon;
049: import javax.swing.JButton;
050: import javax.swing.JComboBox;
051: import javax.swing.JDialog;
052: import javax.swing.JFrame;
053: import javax.swing.JLabel;
054: import javax.swing.JList;
055: import javax.swing.JOptionPane;
056: import javax.swing.JPanel;
057: import javax.swing.ListCellRenderer;
058: import javax.swing.LookAndFeel;
059: import javax.swing.SwingConstants;
060: import javax.swing.SwingUtilities;
061: import javax.swing.UIManager;
062: import javax.swing.plaf.metal.MetalLookAndFeel;
063: import javax.swing.plaf.metal.MetalTheme;
064:
065: import com.izforge.izpack.GUIPrefs;
066: import com.izforge.izpack.LocaleDatabase;
067: import com.izforge.izpack.gui.ButtonFactory;
068: import com.izforge.izpack.gui.IzPackMetalTheme;
069: import com.izforge.izpack.gui.LabelFactory;
070: import com.izforge.izpack.util.Debug;
071: import com.izforge.izpack.util.OsVersion;
072: import com.izforge.izpack.util.VariableSubstitutor;
073: import com.izforge.izpack.util.FileExecutor;
074:
075: /**
076: * The IzPack graphical installer class.
077: *
078: * @author Julien Ponge
079: */
080: public class GUIInstaller extends InstallerBase {
081:
082: /** The installation data. */
083: private InstallData installdata;
084:
085: /** The L&F. */
086: protected String lnf;
087:
088: /** defined modifier for language display type. */
089: private static final String[] LANGUAGE_DISPLAY_TYPES = { "iso3",
090: "native", "default" };
091:
092: private static final String[][] LANG_CODES = { { "cat", "ca" },
093: { "chn", "zh" }, { "cze", "cs" }, { "dan", "da" },
094: { "deu", "de" }, { "eng", "en" }, { "fin", "fi" },
095: { "fra", "fr" }, { "hun", "hu" }, { "ita", "it" },
096: { "jpn", "ja" }, { "mys", "ms" }, { "ned", "nl" },
097: { "nor", "no" }, { "pol", "pl" }, { "por", "pt" },
098: { "rom", "or" }, { "rus", "ru" }, { "spa", "es" },
099: { "svk", "sk" }, { "swe", "sv" }, { "tur", "tr" },
100: { "ukr", "uk" } };
101:
102: /** holds language to ISO-3 language code translation */
103: private static HashMap isoTable;
104:
105: /**
106: * The constructor.
107: *
108: * @exception Exception Description of the Exception
109: */
110: public GUIInstaller() throws Exception {
111: this .installdata = new InstallData();
112:
113: // Loads the installation data
114: loadInstallData(installdata);
115:
116: // add the GUI install data
117: loadGUIInstallData();
118:
119: // Sets up the GUI L&F
120: loadLookAndFeel();
121:
122: // Checks the Java version
123: checkJavaVersion();
124: checkJDKAvailable();
125:
126: // Loads the suitable langpack
127: SwingUtilities.invokeAndWait(new Runnable() {
128:
129: public void run() {
130: try {
131: loadLangPack();
132: } catch (Exception e) {
133: e.printStackTrace();
134: }
135: }
136: });
137:
138: // create the resource manager (after the language selection!)
139: ResourceManager.create(this .installdata);
140:
141: // Load custom langpack if exist.
142: addCustomLangpack(installdata);
143:
144: // We launch the installer GUI
145: SwingUtilities.invokeLater(new Runnable() {
146:
147: public void run() {
148: try {
149: loadGUI();
150: } catch (Exception e) {
151: e.printStackTrace();
152: }
153: }
154: });
155: }
156:
157: /**
158: * Load GUI preference information.
159: *
160: * @throws Exception
161: */
162: public void loadGUIInstallData() throws Exception {
163: InputStream in = GUIInstaller.class
164: .getResourceAsStream("/GUIPrefs");
165: ObjectInputStream objIn = new ObjectInputStream(in);
166: this .installdata.guiPrefs = (GUIPrefs) objIn.readObject();
167: objIn.close();
168: }
169:
170: /**
171: * Checks the Java version.
172: *
173: * @exception Exception Description of the Exception
174: */
175: private void checkJavaVersion() throws Exception {
176: String version = System.getProperty("java.version");
177: String required = this .installdata.info.getJavaVersion();
178: if (version.compareTo(required) < 0) {
179: StringBuffer msg = new StringBuffer();
180: msg
181: .append("The application that you are trying to install requires a ");
182: msg.append(required);
183: msg.append(" version or later of the Java platform.\n");
184: msg.append("You are running a ");
185: msg.append(version);
186: msg.append(" version of the Java platform.\n");
187: msg.append("Please upgrade to a newer version.");
188:
189: System.out.println(msg.toString());
190: JOptionPane.showMessageDialog(null, msg.toString(),
191: "Error", JOptionPane.ERROR_MESSAGE);
192: System.exit(1);
193: }
194: }
195:
196: /**
197: * Checks if a JDK is available.
198: */
199: private void checkJDKAvailable() {
200: if (!this .installdata.info.isJdkRequired()) {
201: return;
202: }
203:
204: FileExecutor exec = new FileExecutor();
205: String[] output = new String[2];
206: String[] params = { "javac", "-help" };
207: if (exec.executeCommand(params, output) != 0) {
208: String[] message = {
209: "It looks like your system does not have a Java Development Kit (JDK) available.",
210: "The software that you plan to install requires a JDK for both its installation and execution.",
211: "\n",
212: "Do you still want to proceed with the installation process?" };
213: int status = JOptionPane.showConfirmDialog(null, message,
214: "Warning", JOptionPane.YES_NO_OPTION,
215: JOptionPane.WARNING_MESSAGE);
216: if (status == JOptionPane.NO_OPTION) {
217: System.exit(1);
218: }
219: }
220: }
221:
222: /**
223: * Loads the suitable langpack.
224: *
225: * @exception Exception Description of the Exception
226: */
227: private void loadLangPack() throws Exception {
228: // Initialisations
229: List availableLangPacks = getAvailableLangPacks();
230: int npacks = availableLangPacks.size();
231: if (npacks == 0)
232: throw new Exception("no language pack available");
233: String selectedPack;
234:
235: // Dummy Frame
236: JFrame frame = new JFrame();
237: frame.setIconImage(new ImageIcon(this .getClass().getResource(
238: "/img/JFrameIcon.png")).getImage());
239:
240: Dimension frameSize = frame.getSize();
241: Dimension screenSize = Toolkit.getDefaultToolkit()
242: .getScreenSize();
243: frame.setLocation((screenSize.width - frameSize.width) / 2,
244: (screenSize.height - frameSize.height) / 2 - 10);
245:
246: // We get the langpack name
247: if (npacks != 1) {
248: LanguageDialog picker = new LanguageDialog(frame,
249: availableLangPacks.toArray());
250: picker.setSelection(Locale.getDefault().getISO3Language()
251: .toLowerCase());
252: picker.setModal(true);
253: picker.toFront();
254: // frame.setVisible(true);
255: frame.setVisible(false);
256: picker.setVisible(true);
257:
258: selectedPack = (String) picker.getSelection();
259: if (selectedPack == null)
260: throw new Exception("installation canceled");
261: } else
262: selectedPack = (String) availableLangPacks.get(0);
263:
264: // We add an xml data information
265: this .installdata.xmlData.setAttribute("langpack", selectedPack);
266:
267: // We load the langpack
268: installdata.localeISO3 = selectedPack;
269: installdata.setVariable(ScriptParser.ISO3_LANG,
270: installdata.localeISO3);
271: InputStream in = getClass().getResourceAsStream(
272: "/langpacks/" + selectedPack + ".xml");
273: this .installdata.langpack = new LocaleDatabase(in);
274:
275: }
276:
277: /**
278: * Returns an ArrayList of the available langpacks ISO3 codes.
279: *
280: * @return The available langpacks list.
281: * @exception Exception Description of the Exception
282: */
283: private List getAvailableLangPacks() throws Exception {
284: // We read from the langpacks file in the jar
285: InputStream in = getClass().getResourceAsStream(
286: "/langpacks.info");
287: ObjectInputStream objIn = new ObjectInputStream(in);
288: List available = (List) objIn.readObject();
289: objIn.close();
290:
291: return available;
292: }
293:
294: /**
295: * Loads the suitable L&F.
296: *
297: * @exception Exception Description of the Exception
298: */
299: protected void loadLookAndFeel() throws Exception {
300: // Do we have any preference for this OS ?
301: String syskey = "unix";
302: if (OsVersion.IS_WINDOWS) {
303: syskey = "windows";
304: } else if (OsVersion.IS_OSX) {
305: syskey = "mac";
306: }
307: String laf = null;
308: if (installdata.guiPrefs.lookAndFeelMapping.containsKey(syskey)) {
309: laf = installdata.guiPrefs.lookAndFeelMapping.get(syskey);
310: }
311:
312: // Let's use the system LAF
313: // Resolve whether button icons should be used or not.
314: boolean useButtonIcons = true;
315: if (installdata.guiPrefs.modifier.containsKey("useButtonIcons")
316: && "no".equalsIgnoreCase(installdata.guiPrefs.modifier
317: .get("useButtonIcons")))
318: useButtonIcons = false;
319: ButtonFactory.useButtonIcons(useButtonIcons);
320: boolean useLabelIcons = true;
321: if (installdata.guiPrefs.modifier.containsKey("useLabelIcons")
322: && "no".equalsIgnoreCase(installdata.guiPrefs.modifier
323: .get("useLabelIcons")))
324: useLabelIcons = false;
325: LabelFactory.setUseLabelIcons(useLabelIcons);
326: if (laf == null) {
327: if (!"mac".equals(syskey)) {
328: // In Linux we will use the English locale, because of a bug in
329: // JRE6. In Korean, Persian, Chinese, japanese and some other
330: // locales the installer throws and exception and doesn't load
331: // at all. See http://jira.jboss.com/jira/browse/JBINSTALL-232.
332: // This is a workaround until this bug gets fixed.
333: if ("unix".equals(syskey))
334: Locale.setDefault(Locale.ENGLISH);
335: String syslaf = UIManager
336: .getSystemLookAndFeelClassName();
337: UIManager.setLookAndFeel(syslaf);
338: if (UIManager.getLookAndFeel() instanceof MetalLookAndFeel) {
339: MetalLookAndFeel
340: .setCurrentTheme(new IzPackMetalTheme());
341: ButtonFactory.useHighlightButtons();
342: // Reset the use button icons state because
343: // useHighlightButtons
344: // make it always true.
345: ButtonFactory.useButtonIcons(useButtonIcons);
346: installdata.buttonsHColor = new Color(182, 182, 204);
347: }
348: }
349: lnf = "swing";
350: return;
351: }
352:
353: // Kunststoff (http://www.incors.org/)
354: if ("kunststoff".equals(laf)) {
355: ButtonFactory.useHighlightButtons();
356: // Reset the use button icons state because useHighlightButtons
357: // make it always true.
358: ButtonFactory.useButtonIcons(useButtonIcons);
359: installdata.buttonsHColor = new Color(255, 255, 255);
360: Class<LookAndFeel> lafClass = (Class<LookAndFeel>) Class
361: .forName("com.incors.plaf.kunststoff.KunststoffLookAndFeel");
362: Class mtheme = Class
363: .forName("javax.swing.plaf.metal.MetalTheme");
364: Class[] params = { mtheme };
365: Class<MetalTheme> theme = (Class<MetalTheme>) Class
366: .forName("com.izforge.izpack.gui.IzPackKMetalTheme");
367: Method setCurrentThemeMethod = lafClass.getMethod(
368: "setCurrentTheme", params);
369:
370: // We invoke and place Kunststoff as our L&F
371: LookAndFeel kunststoff = lafClass.newInstance();
372: MetalTheme ktheme = theme.newInstance();
373: Object[] kparams = { ktheme };
374: UIManager.setLookAndFeel(kunststoff);
375: setCurrentThemeMethod.invoke(kunststoff, kparams);
376:
377: lnf = "kunststoff";
378: return;
379: }
380:
381: // Liquid (http://liquidlnf.sourceforge.net/)
382: if ("liquid".equals(laf)) {
383: UIManager
384: .setLookAndFeel("com.birosoft.liquid.LiquidLookAndFeel");
385: lnf = "liquid";
386:
387: Map<String, String> params = installdata.guiPrefs.lookAndFeelParams
388: .get(laf);
389: if (params.containsKey("decorate.frames")) {
390: String value = params.get("decorate.frames");
391: if ("yes".equals(value)) {
392: JFrame.setDefaultLookAndFeelDecorated(true);
393: }
394: }
395: if (params.containsKey("decorate.dialogs")) {
396: String value = params.get("decorate.dialogs");
397: if ("yes".equals(value)) {
398: JDialog.setDefaultLookAndFeelDecorated(true);
399: }
400: }
401:
402: return;
403: }
404:
405: // Metouia (http://mlf.sourceforge.net/)
406: if ("metouia".equals(laf)) {
407: UIManager
408: .setLookAndFeel("net.sourceforge.mlf.metouia.MetouiaLookAndFeel");
409: lnf = "metouia";
410: return;
411: }
412:
413: // Nimbus (http://nimbus.dev.java.net/)
414: if ("nimbus".equals(laf)) {
415: UIManager
416: .setLookAndFeel("org.jdesktop.swingx.plaf.nimbus.NimbusLookAndFeel");
417: return;
418: }
419:
420: // JGoodies Looks (http://looks.dev.java.net/)
421: if ("looks".equals(laf)) {
422: Map<String, String> variants = new TreeMap<String, String>();
423: variants.put("windows",
424: "com.jgoodies.looks.windows.WindowsLookAndFeel");
425: variants.put("plastic",
426: "com.jgoodies.looks.plastic.PlasticLookAndFeel");
427: variants.put("plastic3D",
428: "com.jgoodies.looks.plastic.Plastic3DLookAndFeel");
429: variants.put("plasticXP",
430: "com.jgoodies.looks.plastic.Plastic3DLookAndFeel");
431: String variant = variants.get("plasticXP");
432:
433: Map<String, String> params = installdata.guiPrefs.lookAndFeelParams
434: .get(laf);
435: if (params.containsKey("variant")) {
436: String param = params.get("variant");
437: if (variants.containsKey(param)) {
438: variant = variants.get(param);
439: }
440: }
441:
442: UIManager.setLookAndFeel(variant);
443: return;
444: }
445:
446: // Substance (http://substance.dev.java.net/)
447: if ("substance".equals(laf)) {
448: Map<String, String> variants = new TreeMap<String, String>();
449: variants.put("default",
450: "org.jvnet.substance.SubstanceLookAndFeel"); // Ugly!!!
451: variants
452: .put("business",
453: "org.jvnet.substance.skin.SubstanceBusinessLookAndFeel");
454: variants
455: .put("business-blue",
456: "org.jvnet.substance.skin.SubstanceBusinessBlueSteelLookAndFeel");
457: variants
458: .put("business-black",
459: "org.jvnet.substance.skin.SubstanceBusinessBlackSteelLookAndFeel");
460: variants
461: .put("creme",
462: "org.jvnet.substance.skin.SubstanceCremeLookAndFeel");
463: variants
464: .put("sahara",
465: "org.jvnet.substance.skin.SubstanceSaharaLookAndFeel");
466: variants
467: .put("moderate",
468: "org.jvnet.substance.skin.SubstanceModerateLookAndFeel");
469: variants
470: .put("officesilver",
471: "org.jvnet.substance.skin.SubstanceOfficeSilver2007LookAndFeel");
472: String variant = variants.get("default");
473:
474: Map<String, String> params = installdata.guiPrefs.lookAndFeelParams
475: .get(laf);
476: if (params.containsKey("variant")) {
477: String param = params.get("variant");
478: if (variants.containsKey(param)) {
479: variant = variants.get(param);
480: }
481: }
482:
483: UIManager.setLookAndFeel(variant);
484: }
485: }
486:
487: /**
488: * Loads the GUI.
489: *
490: * @exception Exception Description of the Exception
491: */
492: private void loadGUI() throws Exception {
493: UIManager.put("OptionPane.yesButtonText", installdata.langpack
494: .getString("installer.yes"));
495: UIManager.put("OptionPane.noButtonText", installdata.langpack
496: .getString("installer.no"));
497: UIManager.put("OptionPane.cancelButtonText",
498: installdata.langpack.getString("installer.cancel"));
499: String title;
500: // Use a alternate message if defined.
501: final String key = "installer.reversetitle";
502: String message = installdata.langpack.getString(key);
503: // message equal to key -> no message defined.
504: if (message.indexOf(key) > -1)
505: title = installdata.langpack.getString("installer.title")
506: + installdata.info.getAppName();
507: else { // Attention! The alternate message has to contain the hole message including
508: // $APP_NAME and may be $APP_VER.
509: VariableSubstitutor vs = new VariableSubstitutor(
510: installdata.getVariables());
511: title = vs.substitute(message, null);
512: }
513: new InstallerFrame(title, this .installdata);
514: }
515:
516: /**
517: * Returns whether flags should be used in the language selection dialog or not.
518: *
519: * @return whether flags should be used in the language selection dialog or not
520: */
521: protected boolean useFlags() {
522: if (installdata.guiPrefs.modifier.containsKey("useFlags")
523: && "no".equalsIgnoreCase(installdata.guiPrefs.modifier
524: .get("useFlags")))
525: return (false);
526: return (true);
527: }
528:
529: /**
530: * Returns the type in which the language should be displayed in the language selction dialog.
531: * Possible are "iso3", "native" and "usingDefault".
532: *
533: * @return language display type
534: */
535: protected String getLangType() {
536: if (installdata.guiPrefs.modifier
537: .containsKey("langDisplayType")) {
538: String val = installdata.guiPrefs.modifier
539: .get("langDisplayType");
540: val = val.toLowerCase();
541: // Verify that the value is valid, else return the default.
542: for (String aLANGUAGE_DISPLAY_TYPES : LANGUAGE_DISPLAY_TYPES) {
543: if (val.equalsIgnoreCase(aLANGUAGE_DISPLAY_TYPES)) {
544: return (val);
545: }
546: }
547: Debug
548: .trace("Value for language display type not valid; value: "
549: + val);
550: }
551: return (LANGUAGE_DISPLAY_TYPES[0]);
552: }
553:
554: /**
555: * Used to prompt the user for the language. Languages can be displayed in iso3 or the native
556: * notation or the notation of the default locale. Revising to native notation is based on code
557: * from Christian Murphy (patch #395).
558: *
559: * @author Julien Ponge
560: * @author Christian Murphy
561: * @author Klaus Bartz
562: */
563: private final class LanguageDialog extends JDialog implements
564: ActionListener {
565:
566: private static final long serialVersionUID = 3256443616359887667L;
567:
568: /** The combo box. */
569: private JComboBox comboBox;
570:
571: /** The ISO3 to ISO2 HashMap */
572: private HashMap<String, String> iso3Toiso2 = null;
573:
574: /** iso3Toiso2 expanded ? */
575: private boolean isoMapExpanded = false;
576:
577: /**
578: * The constructor.
579: *
580: * @param items The items to display in the box.
581: */
582: public LanguageDialog(JFrame frame, Object[] items) {
583: super (frame);
584:
585: try {
586: loadLookAndFeel();
587: } catch (Exception err) {
588: err.printStackTrace();
589: }
590:
591: // We build the GUI
592: addWindowListener(new WindowHandler());
593: JPanel contentPane = (JPanel) getContentPane();
594: setTitle("Language selection");
595: GridBagLayout layout = new GridBagLayout();
596: contentPane.setLayout(layout);
597: GridBagConstraints gbConstraints = new GridBagConstraints();
598: gbConstraints.anchor = GridBagConstraints.CENTER;
599: gbConstraints.insets = new Insets(5, 5, 5, 5);
600: gbConstraints.fill = GridBagConstraints.HORIZONTAL;
601: gbConstraints.gridx = 0;
602: gbConstraints.weightx = 1.0;
603: gbConstraints.weighty = 1.0;
604: gbConstraints.ipadx = 0;
605: gbConstraints.ipady = 6;
606:
607: ImageIcon img = getImage();
608: JLabel imgLabel = new JLabel(img);
609: gbConstraints.gridy = 0;
610: contentPane.add(imgLabel);
611:
612: String firstMessage = "Please select your language";
613: if (getLangType().equals(LANGUAGE_DISPLAY_TYPES[0]))
614: // iso3
615: firstMessage = "Please select your language below";
616:
617: JLabel label1 = new JLabel(firstMessage,
618: SwingConstants.LEADING);
619: gbConstraints.gridy = 1;
620: gbConstraints.insets = new Insets(15, 5, 5, 5);
621: layout.addLayoutComponent(label1, gbConstraints);
622: contentPane.add(label1);
623:
624: gbConstraints.insets = new Insets(5, 5, 5, 5);
625: items = reviseItems(items);
626:
627: comboBox = new JComboBox(items);
628: if (useFlags())
629: comboBox.setRenderer(new FlagRenderer());
630: gbConstraints.gridy = 3;
631: layout.addLayoutComponent(comboBox, gbConstraints);
632: contentPane.add(comboBox);
633:
634: gbConstraints.insets = new Insets(15, 5, 15, 5);
635: JButton okButton = new JButton("Ok");
636: okButton.addActionListener(this );
637: gbConstraints.fill = GridBagConstraints.NONE;
638: gbConstraints.gridy = 4;
639: gbConstraints.anchor = GridBagConstraints.CENTER;
640: layout.addLayoutComponent(okButton, gbConstraints);
641: contentPane.add(okButton);
642: getRootPane().setDefaultButton(okButton);
643:
644: // Packs and centers
645: // Fix for bug "Installer won't show anything on OSX"
646: if (System.getProperty("mrj.version") == null) {
647: pack();
648: }
649: setSize(getPreferredSize());
650:
651: Dimension frameSize = getSize();
652: Point center = GraphicsEnvironment
653: .getLocalGraphicsEnvironment().getCenterPoint();
654: setLocation(center.x - frameSize.width / 2, center.y
655: - frameSize.height / 2 - 10);
656: setResizable(true);
657: }
658:
659: /**
660: * Revises iso3 language items depending on the language display type.
661: *
662: * @param items item array to be revised
663: * @return the revised array
664: */
665: private Object[] reviseItems(Object[] items) {
666: String langType = getLangType();
667: // iso3: nothing todo.
668: if (langType.equals(LANGUAGE_DISPLAY_TYPES[0]))
669: return (items);
670: // native: get the names as they are written in that language.
671: if (langType.equals(LANGUAGE_DISPLAY_TYPES[1]))
672: return (expandItems(items, (new JComboBox()).getFont()));
673: // default: get the names as they are written in the default
674: // language.
675: if (langType.equals(LANGUAGE_DISPLAY_TYPES[2]))
676: return (expandItems(items, null));
677: // Should never be.
678: return (items);
679: }
680:
681: /**
682: * Expands the given iso3 codes to language names. If a testFont is given, the codes are
683: * tested whether they can displayed or not. If not, or no font given, the language name
684: * will be returned as written in the default language of this VM.
685: *
686: * @param items item array to be expanded to the language name
687: * @param testFont font to test wheter a name is displayable
688: * @return aray of expanded items
689: */
690: private Object[] expandItems(Object[] items, Font testFont) {
691: int i;
692: if (iso3Toiso2 == null) { // Loasd predefined langs into HashMap.
693: iso3Toiso2 = new HashMap<String, String>(32);
694: isoTable = new HashMap();
695: for (i = 0; i < LANG_CODES.length; ++i)
696: iso3Toiso2.put(LANG_CODES[i][0], LANG_CODES[i][1]);
697: }
698: for (i = 0; i < items.length; i++) {
699: Object it = expandItem(items[i], testFont);
700: isoTable.put(it, items[i]);
701: items[i] = it;
702: }
703: return items;
704: }
705:
706: /**
707: * Expands the given iso3 code to a language name. If a testFont is given, the code will be
708: * tested whether it is displayable or not. If not, or no font given, the language name will
709: * be returned as written in the default language of this VM.
710: *
711: * @param item item to be expanded to the language name
712: * @param testFont font to test wheter the name is displayable
713: * @return expanded item
714: */
715: private Object expandItem(Object item, Font testFont) {
716: Object iso2Str = iso3Toiso2.get(item);
717: int i;
718: if (iso2Str == null && !isoMapExpanded) { // Expand iso3toiso2 only if needed because it needs some time.
719: isoMapExpanded = true;
720: Locale[] loc = Locale.getAvailableLocales();
721: for (i = 0; i < loc.length; ++i)
722: iso3Toiso2.put(loc[i].getISO3Language(), loc[i]
723: .getLanguage());
724: iso2Str = iso3Toiso2.get(item);
725: }
726: if (iso2Str == null)
727: // Unknown item, return it self.
728: return (item);
729: Locale locale = new Locale((String) iso2Str);
730: if (testFont == null)
731: // Return the language name in the spelling of the default locale.
732: return (locale.getDisplayLanguage());
733: // Get the language name in the spelling of that language.
734: String str = locale.getDisplayLanguage(locale);
735: int cdut = testFont.canDisplayUpTo(str);
736: if (cdut > -1)
737: // Test font cannot render it;
738: // use language name in the spelling of the default locale.
739: str = locale.getDisplayLanguage();
740: return (str);
741: }
742:
743: /**
744: * Loads an image.
745: *
746: * @return The image icon.
747: */
748: public ImageIcon getImage() {
749: ImageIcon img;
750: try {
751: img = new ImageIcon(LanguageDialog.class
752: .getResource("/res/installer.langsel.img"));
753: } catch (NullPointerException err) {
754: img = null;
755: }
756: return img;
757: }
758:
759: /**
760: * Gets the selected object.
761: *
762: * @return The selected item.
763: */
764: public Object getSelection() {
765: Object retval = null;
766: if (isoTable != null)
767: retval = isoTable.get(comboBox.getSelectedItem());
768: return (retval != null) ? retval : comboBox
769: .getSelectedItem();
770: }
771:
772: /**
773: * Sets the selection.
774: *
775: * @param item The item to be selected.
776: */
777: public void setSelection(Object item) {
778: Object mapped = null;
779: if (isoTable != null) {
780: Iterator iter = isoTable.keySet().iterator();
781: while (iter.hasNext()) {
782: Object key = iter.next();
783: if (isoTable.get(key).equals(item)) {
784: mapped = key;
785: break;
786: }
787: }
788: }
789: if (mapped == null)
790: mapped = item;
791: comboBox.setSelectedItem(mapped);
792: }
793:
794: /**
795: * Closer.
796: *
797: * @param e The event.
798: */
799: public void actionPerformed(ActionEvent e) {
800: dispose();
801: }
802:
803: /**
804: * The window events handler.
805: *
806: * @author Julien Ponge
807: */
808: private class WindowHandler extends WindowAdapter {
809:
810: /**
811: * We can't avoid the exit here, so don't call exit anywhere else.
812: *
813: * @param e the event.
814: */
815: public void windowClosing(WindowEvent e) {
816: System.exit(0);
817: }
818: }
819: }
820:
821: /**
822: * A list cell renderer that adds the flags on the display.
823: *
824: * @author Julien Ponge
825: */
826: private static class FlagRenderer extends JLabel implements
827: ListCellRenderer {
828:
829: private static final long serialVersionUID = 3832899961942782769L;
830:
831: /** Icons cache. */
832: private TreeMap<String, ImageIcon> icons = new TreeMap<String, ImageIcon>();
833:
834: /** Grayed icons cache. */
835: private TreeMap<String, ImageIcon> grayIcons = new TreeMap<String, ImageIcon>();
836:
837: public FlagRenderer() {
838: setOpaque(true);
839: }
840:
841: /**
842: * Returns a suitable cell.
843: *
844: * @param list The list.
845: * @param value The object.
846: * @param index The index.
847: * @param isSelected true if it is selected.
848: * @param cellHasFocus Description of the Parameter
849: * @return The cell.
850: */
851: public Component getListCellRendererComponent(JList list,
852: Object value, int index, boolean isSelected,
853: boolean cellHasFocus) {
854: // We put the label
855: String iso3 = (String) value;
856: setText(iso3);
857: if (isoTable != null)
858: iso3 = (String) isoTable.get(iso3);
859: if (isSelected) {
860: setForeground(list.getSelectionForeground());
861: setBackground(list.getSelectionBackground());
862: } else {
863: setForeground(list.getForeground());
864: setBackground(list.getBackground());
865: }
866: // We put the icon
867:
868: if (!icons.containsKey(iso3)) {
869: ImageIcon icon;
870: icon = new ImageIcon(this .getClass().getResource(
871: "/res/flag." + iso3));
872: icons.put(iso3, icon);
873: icon = new ImageIcon(GrayFilter
874: .createDisabledImage(icon.getImage()));
875: grayIcons.put(iso3, icon);
876: }
877: if (isSelected || index == -1)
878: setIcon(icons.get(iso3));
879: else
880: setIcon(grayIcons.get(iso3));
881:
882: // We return
883: return this;
884: }
885: }
886: }
|