0001: /*
0002: * $Id: InstallerFrame.java 2072 2008-03-07 22:51:28Z jponge $
0003: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
0004: *
0005: * http://izpack.org/
0006: * http://izpack.codehaus.org/
0007: *
0008: * Copyright 2002 Jan Blok
0009: *
0010: * Licensed under the Apache License, Version 2.0 (the "License");
0011: * you may not use this file except in compliance with the License.
0012: * You may obtain a copy of the License at
0013: *
0014: * http://www.apache.org/licenses/LICENSE-2.0
0015: *
0016: * Unless required by applicable law or agreed to in writing, software
0017: * distributed under the License is distributed on an "AS IS" BASIS,
0018: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0019: * See the License for the specific language governing permissions and
0020: * limitations under the License.
0021: */
0022:
0023: package com.izforge.izpack.installer;
0024:
0025: import java.awt.BorderLayout;
0026: import java.awt.Color;
0027: import java.awt.Component;
0028: import java.awt.Cursor;
0029: import java.awt.Dimension;
0030: import java.awt.Font;
0031: import java.awt.GraphicsEnvironment;
0032: import java.awt.GridBagConstraints;
0033: import java.awt.GridLayout;
0034: import java.awt.Point;
0035: import java.awt.Window;
0036: import java.awt.event.ActionEvent;
0037: import java.awt.event.ActionListener;
0038: import java.awt.event.FocusAdapter;
0039: import java.awt.event.KeyAdapter;
0040: import java.awt.event.MouseAdapter;
0041: import java.awt.event.MouseMotionAdapter;
0042: import java.awt.event.WindowAdapter;
0043: import java.awt.event.WindowEvent;
0044: import java.io.BufferedWriter;
0045: import java.io.ByteArrayOutputStream;
0046: import java.io.File;
0047: import java.io.FileNotFoundException;
0048: import java.io.FileOutputStream;
0049: import java.io.IOException;
0050: import java.io.InputStream;
0051: import java.io.ObjectInputStream;
0052: import java.io.ObjectOutputStream;
0053: import java.io.OutputStream;
0054: import java.io.OutputStreamWriter;
0055: import java.lang.reflect.Constructor;
0056: import java.net.URL;
0057: import java.util.ArrayList;
0058: import java.util.HashSet;
0059: import java.util.Iterator;
0060: import java.util.List;
0061: import java.util.Map;
0062: import java.util.Vector;
0063: import java.util.zip.ZipEntry;
0064: import java.util.zip.ZipException;
0065: import java.util.zip.ZipOutputStream;
0066:
0067: import javax.swing.BorderFactory;
0068: import javax.swing.Box;
0069: import javax.swing.BoxLayout;
0070: import javax.swing.ImageIcon;
0071: import javax.swing.JButton;
0072: import javax.swing.JComponent;
0073: import javax.swing.JFrame;
0074: import javax.swing.JLabel;
0075: import javax.swing.JOptionPane;
0076: import javax.swing.JPanel;
0077: import javax.swing.JProgressBar;
0078: import javax.swing.JSeparator;
0079: import javax.swing.SwingUtilities;
0080: import javax.swing.UIManager;
0081: import javax.swing.WindowConstants;
0082: import javax.swing.border.TitledBorder;
0083: import javax.swing.text.JTextComponent;
0084:
0085: import net.n3.nanoxml.NonValidator;
0086: import net.n3.nanoxml.StdXMLParser;
0087: import net.n3.nanoxml.StdXMLReader;
0088: import net.n3.nanoxml.XMLElement;
0089: import net.n3.nanoxml.XMLWriter;
0090: import net.n3.nanoxml.XMLBuilderFactory;
0091:
0092: import com.izforge.izpack.CustomData;
0093: import com.izforge.izpack.ExecutableFile;
0094: import com.izforge.izpack.LocaleDatabase;
0095: import com.izforge.izpack.Panel;
0096: import com.izforge.izpack.compiler.DynamicVariable;
0097: import com.izforge.izpack.gui.ButtonFactory;
0098: import com.izforge.izpack.gui.EtchedLineBorder;
0099: import com.izforge.izpack.gui.IconsDatabase;
0100: import com.izforge.izpack.rules.RulesEngine;
0101: import com.izforge.izpack.util.AbstractUIProgressHandler;
0102: import com.izforge.izpack.util.Debug;
0103: import com.izforge.izpack.util.DebugConstants;
0104: import com.izforge.izpack.util.Housekeeper;
0105: import com.izforge.izpack.util.IoHelper;
0106: import com.izforge.izpack.util.Log;
0107: import com.izforge.izpack.util.OsConstraint;
0108: import com.izforge.izpack.util.VariableSubstitutor;
0109:
0110: /**
0111: * The IzPack installer frame.
0112: *
0113: * @author Julien Ponge created October 27, 2002
0114: * @author Fabrice Mirabile added fix for alert window on cross button, July 06 2005
0115: * @author Dennis Reil, added RulesEngine November 10 2006, several changes in January 2007
0116: */
0117: public class InstallerFrame extends JFrame {
0118:
0119: private static final long serialVersionUID = 3257852069162727473L;
0120:
0121: /**
0122: * VM version to use version dependent methods calls
0123: */
0124: private static final float JAVA_SPECIFICATION_VERSION = Float
0125: .parseFloat(System
0126: .getProperty("java.specification.version"));
0127:
0128: private static final String ICON_RESOURCE = "Installer.image";
0129:
0130: /**
0131: * Name of the variable where to find an extension to the resource name of the icon resource
0132: */
0133: private static final String ICON_RESOURCE_EXT_VARIABLE_NAME = "installerimage.ext";
0134:
0135: /**
0136: * Heading icon resource name.
0137: */
0138: private static final String HEADING_ICON_RESOURCE = "Heading.image";
0139:
0140: /**
0141: * The language pack.
0142: */
0143: public LocaleDatabase langpack;
0144:
0145: /**
0146: * The installation data.
0147: */
0148: protected InstallData installdata;
0149:
0150: /**
0151: * The icons database.
0152: */
0153: public IconsDatabase icons;
0154:
0155: /**
0156: * The panels container.
0157: */
0158: protected JPanel panelsContainer;
0159:
0160: /**
0161: * The frame content pane.
0162: */
0163: protected JPanel contentPane;
0164:
0165: /**
0166: * The previous button.
0167: */
0168: protected JButton prevButton;
0169:
0170: /**
0171: * The next button.
0172: */
0173: protected JButton nextButton;
0174:
0175: /**
0176: * The quit button.
0177: */
0178: protected JButton quitButton;
0179:
0180: /**
0181: * Mapping from "raw" panel number to visible panel number.
0182: */
0183: protected ArrayList<Integer> visiblePanelMapping;
0184:
0185: /**
0186: * Registered GUICreationListener.
0187: */
0188: protected ArrayList<GUIListener> guiListener;
0189:
0190: /**
0191: * Heading major text.
0192: */
0193: protected JLabel[] headingLabels;
0194:
0195: /**
0196: * Panel which contains the heading text and/or icon
0197: */
0198: protected JPanel headingPanel;
0199:
0200: /**
0201: * The heading counter component.
0202: */
0203: protected JComponent headingCounterComponent;
0204:
0205: /**
0206: * Image
0207: */
0208: private JLabel iconLabel;
0209:
0210: /**
0211: * Count for discarded interrupt trials.
0212: */
0213: private int interruptCount = 1;
0214:
0215: /**
0216: * Maximum of discarded interrupt trials.
0217: */
0218: private static final int MAX_INTERRUPT = 3;
0219:
0220: /**
0221: * conditions
0222: */
0223: protected RulesEngine rules;
0224:
0225: /**
0226: * Resource name of the conditions specification
0227: */
0228: private static final String CONDITIONS_SPECRESOURCENAME = "conditions.xml";
0229: /**
0230: * Resource name for custom icons
0231: */
0232: private static final String CUSTOM_ICONS_RESOURCEFILE = "customicons.xml";
0233:
0234: private Map<String, DynamicVariable> dynamicvariables;
0235: private VariableSubstitutor substitutor;
0236: private Debugger debugger;
0237:
0238: /**
0239: * The constructor (normal mode).
0240: *
0241: * @param title The window title.
0242: * @param installdata The installation data.
0243: * @throws Exception Description of the Exception
0244: */
0245: public InstallerFrame(String title, InstallData installdata)
0246: throws Exception {
0247: super (title);
0248: substitutor = new VariableSubstitutor(installdata.variables);
0249: guiListener = new ArrayList<GUIListener>();
0250: visiblePanelMapping = new ArrayList<Integer>();
0251: this .installdata = installdata;
0252: this .langpack = installdata.langpack;
0253:
0254: // Sets the window events handler
0255: addWindowListener(new WindowHandler());
0256: setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
0257:
0258: // initialize rules by loading the conditions
0259: loadConditions();
0260:
0261: // load dynamic variables
0262: loadDynamicVariables();
0263: // Builds the GUI
0264: loadIcons();
0265: loadCustomIcons();
0266: loadPanels();
0267: buildGUI();
0268:
0269: // We show the frame
0270: showFrame();
0271: switchPanel(0);
0272: }
0273:
0274: public Debugger getDebugger() {
0275: return this .debugger;
0276: }
0277:
0278: /**
0279: * Refreshes Dynamic Variables.
0280: *
0281: */
0282: private void refreshDynamicVariables() {
0283: if (dynamicvariables != null) {
0284: Iterator<String> iter = dynamicvariables.keySet()
0285: .iterator();
0286: while (iter.hasNext()) {
0287: String dynvarname = iter.next();
0288: DynamicVariable dynvar = dynamicvariables
0289: .get(dynvarname);
0290: boolean refresh = false;
0291: if (dynvar.getConditionid() != null) {
0292: if ((rules != null)
0293: && rules.isConditionTrue(dynvar
0294: .getConditionid())) {
0295: // condition for this rule is true
0296: refresh = true;
0297: }
0298: } else {
0299: refresh = true;
0300: }
0301: if (refresh) {
0302: String newvalue = substitutor.substitute(dynvar
0303: .getValue(), null);
0304: installdata.variables.setProperty(dynvar.getName(),
0305: newvalue);
0306: }
0307: }
0308: }
0309: }
0310:
0311: /**
0312: * Loads Dynamic Variables.
0313: *
0314: */
0315: private void loadDynamicVariables() {
0316: try {
0317: InputStream in = InstallerFrame.class
0318: .getResourceAsStream("/dynvariables");
0319: ObjectInputStream objIn = new ObjectInputStream(in);
0320: dynamicvariables = (Map<String, DynamicVariable>) objIn
0321: .readObject();
0322: objIn.close();
0323: } catch (Exception e) {
0324: Debug.trace("Cannot find optional dynamic variables");
0325: System.out.println(e);
0326: }
0327: }
0328:
0329: /**
0330: * Reads the conditions specification file and initializes the rules engine.
0331: */
0332: protected void loadConditions() {
0333: // try to load already parsed conditions
0334: try {
0335: InputStream in = InstallerFrame.class
0336: .getResourceAsStream("/rules");
0337: ObjectInputStream objIn = new ObjectInputStream(in);
0338: Map rules = (Map) objIn.readObject();
0339: if ((rules != null) && (rules.size() != 0)) {
0340: this .rules = new RulesEngine(rules, installdata);
0341: }
0342: objIn.close();
0343: } catch (Exception e) {
0344: Debug.trace("Can not find optional rules");
0345: }
0346: if (rules != null) {
0347: // rules already read
0348: return;
0349: }
0350: try {
0351: InputStream input = null;
0352: input = this .getResource(CONDITIONS_SPECRESOURCENAME);
0353: if (input == null) {
0354: this .rules = new RulesEngine((XMLElement) null,
0355: installdata);
0356: return;
0357: }
0358:
0359: StdXMLParser parser = new StdXMLParser();
0360: parser.setBuilder(XMLBuilderFactory.createXMLBuilder());
0361: parser.setValidator(new NonValidator());
0362: parser.setReader(new StdXMLReader(input));
0363:
0364: // get the data
0365: XMLElement conditionsxml = (XMLElement) parser.parse();
0366: this .rules = new RulesEngine(conditionsxml, installdata);
0367: } catch (Exception e) {
0368: Debug.trace("Can not find optional resource "
0369: + CONDITIONS_SPECRESOURCENAME);
0370: // there seem to be no conditions
0371: this .rules = new RulesEngine((XMLElement) null, installdata);
0372: }
0373: }
0374:
0375: /**
0376: * Loads the panels.
0377: *
0378: * @throws Exception Description of the Exception
0379: */
0380: private void loadPanels() throws Exception {
0381: // Initialisation
0382: java.util.List panelsOrder = installdata.panelsOrder;
0383: int i;
0384: int size = panelsOrder.size();
0385: String className;
0386: Class objectClass;
0387: Constructor constructor;
0388: Object object;
0389: IzPanel panel;
0390: Class[] paramsClasses = new Class[2];
0391: paramsClasses[0] = Class
0392: .forName("com.izforge.izpack.installer.InstallerFrame");
0393: paramsClasses[1] = Class
0394: .forName("com.izforge.izpack.installer.InstallData");
0395: Object[] params = { this , installdata };
0396:
0397: // We load each of them
0398: int curVisPanelNumber = 0;
0399: int lastVis = 0;
0400: int count = 0;
0401: for (i = 0; i < size; i++) {
0402: // We add the panel
0403: Panel p = (Panel) panelsOrder.get(i);
0404: if (!OsConstraint.oneMatchesCurrentSystem(p.osConstraints))
0405: continue;
0406: className = p.className;
0407: String praefix = "com.izforge.izpack.panels.";
0408: if (className.indexOf('.') > -1)
0409: // Full qualified class name
0410: praefix = "";
0411: objectClass = Class.forName(praefix + className);
0412: constructor = objectClass
0413: .getDeclaredConstructor(paramsClasses);
0414: installdata.currentPanel = p; // A hack to use meta data in IzPanel constructor
0415: // Do not call constructor of IzPanel or it's derived at an other place else
0416: // metadata will be not set.
0417: object = constructor.newInstance(params);
0418: panel = (IzPanel) object;
0419: installdata.panels.add(panel);
0420: if (panel.isHidden())
0421: visiblePanelMapping.add(count, -1);
0422: else {
0423: visiblePanelMapping.add(count, curVisPanelNumber);
0424: curVisPanelNumber++;
0425: lastVis = count;
0426: }
0427: count++;
0428: // We add the XML data panel root
0429: XMLElement panelRoot = new XMLElement(className);
0430: installdata.xmlData.addChild(panelRoot);
0431: }
0432: visiblePanelMapping.add(count, lastVis);
0433: }
0434:
0435: /**
0436: * Loads the icons.
0437: *
0438: * @throws Exception Description of the Exception
0439: */
0440: private void loadIcons() throws Exception {
0441: // Initialisations
0442: icons = new IconsDatabase();
0443: URL url;
0444: ImageIcon img;
0445: XMLElement icon;
0446: InputStream inXML = InstallerFrame.class
0447: .getResourceAsStream("/com/izforge/izpack/installer/icons.xml");
0448:
0449: // Initialises the parser
0450: StdXMLParser parser = new StdXMLParser();
0451: parser.setBuilder(XMLBuilderFactory.createXMLBuilder());
0452: parser.setReader(new StdXMLReader(inXML));
0453: parser.setValidator(new NonValidator());
0454:
0455: // We get the data
0456: XMLElement data = (XMLElement) parser.parse();
0457:
0458: // We load the icons
0459: Vector<XMLElement> children = data.getChildrenNamed("icon");
0460: int size = children.size();
0461: for (int i = 0; i < size; i++) {
0462: icon = children.get(i);
0463: url = InstallerFrame.class.getResource(icon
0464: .getAttribute("res"));
0465: img = new ImageIcon(url);
0466: icons.put(icon.getAttribute("id"), img);
0467: }
0468:
0469: // We load the Swing-specific icons
0470: children = data.getChildrenNamed("sysicon");
0471: size = children.size();
0472: for (int i = 0; i < size; i++) {
0473: icon = children.get(i);
0474: url = InstallerFrame.class.getResource(icon
0475: .getAttribute("res"));
0476: img = new ImageIcon(url);
0477: UIManager.put(icon.getAttribute("id"), img);
0478: }
0479: }
0480:
0481: /**
0482: * Loads custom icons into the installer.
0483: *
0484: * @throws Exception
0485: */
0486: protected void loadCustomIcons() throws Exception {
0487: // We try to load and add a custom langpack.
0488: InputStream inXML = null;
0489: try {
0490: inXML = ResourceManager.getInstance().getInputStream(
0491: CUSTOM_ICONS_RESOURCEFILE);
0492: } catch (Throwable exception) {
0493: Debug.trace("Resource " + CUSTOM_ICONS_RESOURCEFILE
0494: + " not defined. No custom icons available.");
0495: return;
0496: }
0497: Debug.trace("Custom icons available.");
0498: URL url;
0499: ImageIcon img;
0500: XMLElement icon;
0501:
0502: // Initialises the parser
0503: StdXMLParser parser = new StdXMLParser();
0504: parser.setBuilder(XMLBuilderFactory.createXMLBuilder());
0505: parser.setReader(new StdXMLReader(inXML));
0506: parser.setValidator(new NonValidator());
0507:
0508: // We get the data
0509: XMLElement data = (XMLElement) parser.parse();
0510:
0511: // We load the icons
0512: Vector<XMLElement> children = data.getChildrenNamed("icon");
0513: int size = children.size();
0514: for (int i = 0; i < size; i++) {
0515: icon = children.get(i);
0516: url = InstallerFrame.class.getResource(icon
0517: .getAttribute("res"));
0518: img = new ImageIcon(url);
0519: Debug.trace("Icon with id found: "
0520: + icon.getAttribute("id"));
0521: icons.put(icon.getAttribute("id"), img);
0522: }
0523:
0524: // We load the Swing-specific icons
0525: children = data.getChildrenNamed("sysicon");
0526: size = children.size();
0527: for (int i = 0; i < size; i++) {
0528: icon = children.get(i);
0529: url = InstallerFrame.class.getResource(icon
0530: .getAttribute("res"));
0531: img = new ImageIcon(url);
0532: UIManager.put(icon.getAttribute("id"), img);
0533: }
0534: }
0535:
0536: /**
0537: * Builds the GUI.
0538: */
0539: private void buildGUI() {
0540: this
0541: .setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // patch 06/07/2005,
0542: // Fabrice Mirabile
0543: // Sets the frame icon
0544: setIconImage(icons.getImageIcon("JFrameIcon").getImage());
0545:
0546: // Prepares the glass pane to block the gui interaction when needed
0547: JPanel glassPane = (JPanel) getGlassPane();
0548: glassPane.addMouseListener(new MouseAdapter() {/* Nothing todo */
0549: });
0550: glassPane.addMouseMotionListener(new MouseMotionAdapter() {/* Nothing todo */
0551: });
0552: glassPane.addKeyListener(new KeyAdapter() {/* Nothing todo */
0553: });
0554: glassPane.addFocusListener(new FocusAdapter() {/* Nothing todo */
0555: });
0556:
0557: // We set the layout & prepare the constraint object
0558: contentPane = (JPanel) getContentPane();
0559: contentPane.setLayout(new BorderLayout()); // layout);
0560:
0561: // We add the panels container
0562: panelsContainer = new JPanel();
0563: panelsContainer.setBorder(BorderFactory.createEmptyBorder(10,
0564: 10, 0, 10));
0565: panelsContainer.setLayout(new GridLayout(1, 1));
0566: contentPane.add(panelsContainer, BorderLayout.CENTER);
0567:
0568: // We put the first panel
0569: installdata.curPanelNumber = 0;
0570: IzPanel panel_0 = installdata.panels.get(0);
0571: panelsContainer.add(panel_0);
0572:
0573: // We add the navigation buttons & labels
0574:
0575: NavigationHandler navHandler = new NavigationHandler();
0576:
0577: JPanel navPanel = new JPanel();
0578: navPanel.setLayout(new BoxLayout(navPanel, BoxLayout.X_AXIS));
0579: navPanel.setBorder(BorderFactory.createCompoundBorder(
0580: BorderFactory.createEmptyBorder(8, 8, 8, 8),
0581: BorderFactory.createTitledBorder(
0582: new EtchedLineBorder(), langpack
0583: .getString("installer.madewith")
0584: + " ",
0585: TitledBorder.DEFAULT_JUSTIFICATION,
0586: TitledBorder.DEFAULT_POSITION, new Font(
0587: "Dialog", Font.PLAIN, 10))));
0588: navPanel.add(Box.createHorizontalGlue());
0589:
0590: prevButton = ButtonFactory.createButton(langpack
0591: .getString("installer.prev"), icons
0592: .getImageIcon("stepback"), installdata.buttonsHColor);
0593: navPanel.add(prevButton);
0594: prevButton.addActionListener(navHandler);
0595:
0596: navPanel.add(Box.createRigidArea(new Dimension(5, 0)));
0597:
0598: nextButton = ButtonFactory
0599: .createButton(langpack.getString("installer.next"),
0600: icons.getImageIcon("stepforward"),
0601: installdata.buttonsHColor);
0602: navPanel.add(nextButton);
0603: nextButton.addActionListener(navHandler);
0604:
0605: navPanel.add(Box.createRigidArea(new Dimension(5, 0)));
0606:
0607: quitButton = ButtonFactory.createButton(langpack
0608: .getString("installer.quit"), icons
0609: .getImageIcon("stop"), installdata.buttonsHColor);
0610: navPanel.add(quitButton);
0611: quitButton.addActionListener(navHandler);
0612: contentPane.add(navPanel, BorderLayout.SOUTH);
0613:
0614: // create a debug panel if TRACE is enabled
0615: if (Debug.isTRACE()) {
0616: debugger = new Debugger(installdata, icons, rules);
0617: JPanel debugpanel = debugger.getDebugPanel();
0618: if (installdata.guiPrefs.modifier
0619: .containsKey("showDebugWindow")) {
0620: if (Boolean.valueOf(installdata.guiPrefs.modifier
0621: .get("showDebugWindow"))) {
0622: JFrame debugframe = new JFrame("Debug information");
0623: debugframe.setContentPane(debugpanel);
0624: debugframe.setSize(new Dimension(400, 400));
0625: debugframe.setVisible(true);
0626: } else {
0627: debugpanel
0628: .setPreferredSize(new Dimension(200, 400));
0629: contentPane.add(debugpanel, BorderLayout.EAST);
0630: }
0631: }
0632: }
0633:
0634: try {
0635: ImageIcon icon = loadIcon(ICON_RESOURCE, 0, true);
0636: if (icon != null) {
0637: JPanel imgPanel = new JPanel();
0638: imgPanel.setLayout(new BorderLayout());
0639: imgPanel.setBorder(BorderFactory.createEmptyBorder(10,
0640: 10, 0, 0));
0641: iconLabel = new JLabel(icon);
0642: iconLabel.setBorder(BorderFactory
0643: .createLoweredBevelBorder());
0644: imgPanel.add(iconLabel, BorderLayout.NORTH);
0645: contentPane.add(imgPanel, BorderLayout.WEST);
0646: }
0647: } catch (Exception e) {
0648: // ignore
0649: }
0650:
0651: loadAndShowImage(0);
0652: getRootPane().setDefaultButton(nextButton);
0653: callGUIListener(GUIListener.GUI_BUILDED, navPanel);
0654: createHeading(navPanel);
0655: }
0656:
0657: private void callGUIListener(int what) {
0658: callGUIListener(what, null);
0659: }
0660:
0661: private void callGUIListener(int what, Object param) {
0662: Iterator<GUIListener> iter = guiListener.iterator();
0663: while (iter.hasNext())
0664: (iter.next()).guiActionPerformed(what, param);
0665: }
0666:
0667: /**
0668: * Loads icon for given panel.
0669: *
0670: * @param resPrefix resources prefix.
0671: * @param PanelNo panel id.
0672: * @param tryBaseIcon should try to fallback to base icon?
0673: * @return icon image
0674: * @throws ResourceNotFoundException
0675: * @throws IOException
0676: */
0677: private ImageIcon loadIcon(String resPrefix, int PanelNo,
0678: boolean tryBaseIcon) throws ResourceNotFoundException,
0679: IOException {
0680: ResourceManager rm = ResourceManager.getInstance();
0681: ImageIcon icon = null;
0682: String iconext = this .getIconResourceNameExtension();
0683: if (tryBaseIcon) {
0684: try {
0685: icon = rm.getImageIconResource(resPrefix);
0686: } catch (Exception e) // This is not that clean ...
0687: {
0688: icon = rm.getImageIconResource(resPrefix + "."
0689: + PanelNo + iconext);
0690: }
0691: } else
0692: icon = rm.getImageIconResource(resPrefix + "." + PanelNo
0693: + iconext);
0694: return (icon);
0695: }
0696:
0697: /**
0698: * Loads icon for given panel id.
0699: * @param resPrefix resource prefix.
0700: * @param panelid panel id.
0701: * @param tryBaseIcon should try to load base icon?
0702: * @return image icon
0703: * @throws ResourceNotFoundException
0704: * @throws IOException
0705: */
0706: private ImageIcon loadIcon(String resPrefix, String panelid,
0707: boolean tryBaseIcon) throws ResourceNotFoundException,
0708: IOException {
0709: ResourceManager rm = ResourceManager.getInstance();
0710: ImageIcon icon = null;
0711: String iconext = this .getIconResourceNameExtension();
0712: if (tryBaseIcon) {
0713: try {
0714: icon = rm.getImageIconResource(resPrefix);
0715: } catch (Exception e) // This is not that clean ...
0716: {
0717: icon = rm.getImageIconResource(resPrefix + "."
0718: + panelid + iconext);
0719: }
0720: } else
0721: icon = rm.getImageIconResource(resPrefix + "." + panelid
0722: + iconext);
0723: return (icon);
0724: }
0725:
0726: /**
0727: * Returns the current set extension to icon resource names. Can be used to change
0728: * the static installer image based on user input
0729: * @return a resource extension
0730: * or an empty string if the variable was not set.
0731: */
0732: private String getIconResourceNameExtension() {
0733: try {
0734: String iconext = this .installdata
0735: .getVariable(ICON_RESOURCE_EXT_VARIABLE_NAME);
0736: if (iconext == null) {
0737: iconext = "";
0738: } else {
0739:
0740: if ((iconext.length() > 0)
0741: && (iconext.charAt(0) != '.')) {
0742: iconext = "." + iconext;
0743: }
0744: }
0745: iconext = iconext.trim();
0746: return iconext;
0747: } catch (Exception e) {
0748: // in case of error, return an empty string
0749: return "";
0750: }
0751: }
0752:
0753: private void loadAndShowImage(int panelNo) {
0754: loadAndShowImage(iconLabel, ICON_RESOURCE, panelNo);
0755: }
0756:
0757: private void loadAndShowImage(int panelNo, String panelid) {
0758: loadAndShowImage(iconLabel, ICON_RESOURCE, panelNo, panelid);
0759: }
0760:
0761: private void loadAndShowImage(JLabel iLabel, String resPrefix,
0762: int panelno, String panelid) {
0763: ImageIcon icon = null;
0764: try {
0765: icon = loadIcon(resPrefix, panelid, false);
0766: } catch (Exception e) {
0767: try {
0768: icon = loadIcon(resPrefix, panelno, false);
0769: } catch (Exception ex) {
0770: try {
0771: icon = loadIcon(resPrefix, panelid, true);
0772: } catch (Exception e1) {
0773: // ignore
0774: }
0775: }
0776: }
0777: if (icon != null) {
0778: iLabel.setVisible(false);
0779: iLabel.setIcon(icon);
0780: iLabel.setVisible(true);
0781: }
0782: }
0783:
0784: private void loadAndShowImage(JLabel iLabel, String resPrefix,
0785: int panelNo) {
0786: ImageIcon icon = null;
0787: try {
0788: icon = loadIcon(resPrefix, panelNo, false);
0789: } catch (Exception e) {
0790: try {
0791: icon = loadIcon(resPrefix, panelNo, true);
0792: } catch (Exception e1) {
0793: // ignore
0794: }
0795: }
0796: if (icon != null) {
0797: iLabel.setVisible(false);
0798: iLabel.setIcon(icon);
0799: iLabel.setVisible(true);
0800: }
0801: }
0802:
0803: /**
0804: * Shows the frame.
0805: */
0806: private void showFrame() {
0807: pack();
0808: setSize(installdata.guiPrefs.width, installdata.guiPrefs.height);
0809: setResizable(installdata.guiPrefs.resizable);
0810: centerFrame(this );
0811: setVisible(true);
0812: }
0813:
0814: /**
0815: * Here is persisted the direction of panel traversing.
0816: */
0817: private boolean isBack = false;
0818:
0819: /**
0820: * Switches the current panel.
0821: *
0822: * @param last Description of the Parameter
0823: */
0824: protected void switchPanel(int last) {
0825: // refresh dynamic variables every time, a panel switch is done
0826: refreshDynamicVariables();
0827: try {
0828: if (installdata.curPanelNumber < last) {
0829: isBack = true;
0830: }
0831: panelsContainer.setVisible(false);
0832: IzPanel panel = installdata.panels
0833: .get(installdata.curPanelNumber);
0834: IzPanel l_panel = installdata.panels.get(last);
0835: if (Debug.isTRACE()) {
0836: debugger.switchPanel(panel.getMetadata(), l_panel
0837: .getMetadata());
0838: }
0839: Log
0840: .getInstance()
0841: .addDebugMessage(
0842: "InstallerFrame.switchPanel: try switching panel from {0} to {1} ({2} to {3})",
0843: new String[] {
0844: l_panel.getClass().getName(),
0845: panel.getClass().getName(),
0846: Integer.toString(last),
0847: Integer
0848: .toString(installdata.curPanelNumber) },
0849: DebugConstants.PANEL_TRACE, null);
0850:
0851: // instead of writing data here which leads to duplicated entries in
0852: // auto-installation script (bug # 4551), let's make data only immediately before
0853: // writing out that script.
0854: // l_panel.makeXMLData(installdata.xmlData.getChildAtIndex(last));
0855: // No previos button in the first visible panel
0856: if (visiblePanelMapping.get(installdata.curPanelNumber) == 0) {
0857: prevButton.setVisible(false);
0858: lockPrevButton();
0859: unlockNextButton(); // if we push the button back at the license
0860: // panel
0861: }
0862: // Only the exit button in the last panel.
0863: else if (visiblePanelMapping.get(installdata.panels.size()) == installdata.curPanelNumber) {
0864: prevButton.setVisible(false);
0865: nextButton.setVisible(false);
0866: lockNextButton();
0867: } else {
0868: prevButton.setVisible(true);
0869: nextButton.setVisible(true);
0870: unlockPrevButton();
0871: unlockNextButton();
0872: }
0873: // With VM version >= 1.5 setting default button one time will not work.
0874: // Therefore we set it every panel switch and that also later. But in
0875: // the moment it seems so that the quit button will not used as default button.
0876: // No idea why... (Klaus Bartz, 06.09.25)
0877: SwingUtilities.invokeLater(new Runnable() {
0878:
0879: public void run() {
0880: JButton cdb = null;
0881: String buttonName = "next";
0882: if (nextButton.isEnabled()) {
0883: cdb = nextButton;
0884: quitButton.setDefaultCapable(false);
0885: prevButton.setDefaultCapable(false);
0886: nextButton.setDefaultCapable(true);
0887: } else if (quitButton.isEnabled()) {
0888: cdb = quitButton;
0889: buttonName = "quit";
0890: quitButton.setDefaultCapable(true);
0891: prevButton.setDefaultCapable(false);
0892: nextButton.setDefaultCapable(false);
0893: }
0894: getRootPane().setDefaultButton(cdb);
0895: Log
0896: .getInstance()
0897: .addDebugMessage(
0898: "InstallerFrame.switchPanel: setting {0} as default button",
0899: new String[] { buttonName },
0900: DebugConstants.PANEL_TRACE, null);
0901: }
0902: });
0903:
0904: // Change panels container to the current one.
0905: panelsContainer.remove(l_panel);
0906: l_panel.panelDeactivate();
0907: panelsContainer.add(panel);
0908:
0909: if (panel.getInitialFocus() != null) { // Initial focus hint should be performed after current panel
0910: // was added to the panels container, else the focus hint will
0911: // be ignored.
0912: // Give a hint for the initial focus to the system.
0913: final Component inFoc = panel.getInitialFocus();
0914: if (JAVA_SPECIFICATION_VERSION < 1.35) {
0915: inFoc.requestFocus();
0916: } else { // On java VM version >= 1.5 it works only if
0917: // invoke later will be used.
0918: SwingUtilities.invokeLater(new Runnable() {
0919:
0920: public void run() {
0921: inFoc.requestFocusInWindow();
0922: }
0923: });
0924: }
0925: /*
0926: * On editable text components position the caret to the end of the cust existent
0927: * text.
0928: */
0929: if (inFoc instanceof JTextComponent) {
0930: JTextComponent inText = (JTextComponent) inFoc;
0931: if (inText.isEditable()
0932: && inText.getDocument() != null) {
0933: inText.setCaretPosition(inText.getDocument()
0934: .getLength());
0935: }
0936: }
0937: }
0938: performHeading(panel);
0939: performHeadingCounter(panel);
0940: panel.panelActivate();
0941: panelsContainer.setVisible(true);
0942: Panel metadata = panel.getMetadata();
0943: if ((metadata != null)
0944: && (!"UNKNOWN".equals(metadata.getPanelid()))) {
0945: loadAndShowImage(visiblePanelMapping
0946: .get(installdata.curPanelNumber), metadata
0947: .getPanelid());
0948: } else {
0949: loadAndShowImage(visiblePanelMapping
0950: .get(installdata.curPanelNumber));
0951: }
0952: isBack = false;
0953: callGUIListener(GUIListener.PANEL_SWITCHED);
0954: Log.getInstance().addDebugMessage(
0955: "InstallerFrame.switchPanel: switched", null,
0956: DebugConstants.PANEL_TRACE, null);
0957: } catch (Exception err) {
0958: err.printStackTrace();
0959: }
0960: }
0961:
0962: /**
0963: * Writes the uninstalldata.
0964: */
0965: private void writeUninstallData() {
0966: // Show whether a separated logfile should be also written or not.
0967: String logfile = installdata
0968: .getVariable("InstallerFrame.logfilePath");
0969: BufferedWriter extLogWriter = null;
0970: if (logfile != null) {
0971: if (logfile.toLowerCase().startsWith("default"))
0972: logfile = "$INSTALL_PATH/Uninstaller/install.log";
0973: logfile = IoHelper
0974: .translatePath(logfile, new VariableSubstitutor(
0975: installdata.getVariables()));
0976: File outFile = new File(logfile);
0977: if (!outFile.getParentFile().exists())
0978: outFile.getParentFile().mkdirs();
0979: FileOutputStream out = null;
0980: try {
0981: out = new FileOutputStream(outFile);
0982: } catch (FileNotFoundException e) {
0983: Debug.trace("Cannot create logfile!");
0984: Debug.error(e);
0985: }
0986: if (out != null)
0987: extLogWriter = new BufferedWriter(
0988: new OutputStreamWriter(out));
0989: }
0990: try {
0991: // We get the data
0992: UninstallData udata = UninstallData.getInstance();
0993: List files = udata.getUninstalableFilesList();
0994: ZipOutputStream outJar = installdata.uninstallOutJar;
0995:
0996: if (outJar == null)
0997: return;
0998:
0999: // We write the files log
1000: outJar.putNextEntry(new ZipEntry("install.log"));
1001: BufferedWriter logWriter = new BufferedWriter(
1002: new OutputStreamWriter(outJar));
1003: logWriter.write(installdata.getInstallPath());
1004: logWriter.newLine();
1005: Iterator iter = files.iterator();
1006: if (extLogWriter != null) { // Write intern (in uninstaller.jar) and extern log file.
1007: while (iter.hasNext()) {
1008: String txt = (String) iter.next();
1009: logWriter.write(txt);
1010: extLogWriter.write(txt);
1011: if (iter.hasNext()) {
1012: logWriter.newLine();
1013: extLogWriter.newLine();
1014: }
1015: }
1016: logWriter.flush();
1017: extLogWriter.flush();
1018: extLogWriter.close();
1019: } else {
1020: while (iter.hasNext()) {
1021: logWriter.write((String) iter.next());
1022: if (iter.hasNext())
1023: logWriter.newLine();
1024: }
1025: logWriter.flush();
1026: }
1027: outJar.closeEntry();
1028:
1029: // We write the uninstaller jar file log
1030: outJar.putNextEntry(new ZipEntry("jarlocation.log"));
1031: logWriter = new BufferedWriter(new OutputStreamWriter(
1032: outJar));
1033: logWriter.write(udata.getUninstallerJarFilename());
1034: logWriter.newLine();
1035: logWriter.write(udata.getUninstallerPath());
1036: logWriter.flush();
1037: outJar.closeEntry();
1038:
1039: // Write out executables to execute on uninstall
1040: outJar.putNextEntry(new ZipEntry("executables"));
1041: ObjectOutputStream execStream = new ObjectOutputStream(
1042: outJar);
1043: iter = udata.getExecutablesList().iterator();
1044: execStream.writeInt(udata.getExecutablesList().size());
1045: while (iter.hasNext()) {
1046: ExecutableFile file = (ExecutableFile) iter.next();
1047: execStream.writeObject(file);
1048: }
1049: execStream.flush();
1050: outJar.closeEntry();
1051:
1052: // Write out additional uninstall data
1053: // Do not "kill" the installation if there is a problem
1054: // with custom uninstall data. Therefore log it to Debug,
1055: // but do not throw.
1056: Map<String, Object> additionalData = udata
1057: .getAdditionalData();
1058: if (additionalData != null && !additionalData.isEmpty()) {
1059: Iterator<String> keys = additionalData.keySet()
1060: .iterator();
1061: HashSet<String> exist = new HashSet<String>();
1062: while (keys != null && keys.hasNext()) {
1063: String key = keys.next();
1064: Object contents = additionalData.get(key);
1065: if ("__uninstallLibs__".equals(key)) {
1066: Iterator nativeLibIter = ((List) contents)
1067: .iterator();
1068: while (nativeLibIter != null
1069: && nativeLibIter.hasNext()) {
1070: String nativeLibName = (String) ((List) nativeLibIter
1071: .next()).get(0);
1072: byte[] buffer = new byte[5120];
1073: long bytesCopied = 0;
1074: int bytesInBuffer;
1075: outJar.putNextEntry(new ZipEntry("native/"
1076: + nativeLibName));
1077: InputStream in = getClass()
1078: .getResourceAsStream(
1079: "/native/" + nativeLibName);
1080: while ((bytesInBuffer = in.read(buffer)) != -1) {
1081: outJar.write(buffer, 0, bytesInBuffer);
1082: bytesCopied += bytesInBuffer;
1083: }
1084: outJar.closeEntry();
1085: }
1086: } else if ("uninstallerListeners".equals(key)
1087: || "uninstallerJars".equals(key)) { // It is a ArrayList of ArrayLists which contains the
1088: // full
1089: // package paths of all needed class files.
1090: // First we create a new ArrayList which contains only
1091: // the full paths for the uninstall listener self; thats
1092: // the first entry of each sub ArrayList.
1093: ArrayList<String> subContents = new ArrayList<String>();
1094:
1095: // Secound put the class into uninstaller.jar
1096: Iterator listenerIter = ((List) contents)
1097: .iterator();
1098: while (listenerIter.hasNext()) {
1099: byte[] buffer = new byte[5120];
1100: long bytesCopied = 0;
1101: int bytesInBuffer;
1102: CustomData customData = (CustomData) listenerIter
1103: .next();
1104: // First element of the list contains the listener
1105: // class path;
1106: // remind it for later.
1107: if (customData.listenerName != null)
1108: subContents
1109: .add(customData.listenerName);
1110: Iterator<String> liClaIter = customData.contents
1111: .iterator();
1112: while (liClaIter.hasNext()) {
1113: String contentPath = liClaIter.next();
1114: if (exist.contains(contentPath))
1115: continue;
1116: exist.add(contentPath);
1117: try {
1118: outJar.putNextEntry(new ZipEntry(
1119: contentPath));
1120: } catch (ZipException ze) { // Ignore, or ignore not ?? May be it is a
1121: // exception because
1122: // a doubled entry was tried, then we should
1123: // ignore ...
1124: Debug
1125: .trace("ZipException in writing custom data: "
1126: + ze.getMessage());
1127: continue;
1128: }
1129: InputStream in = getClass()
1130: .getResourceAsStream(
1131: "/" + contentPath);
1132: if (in != null) {
1133: while ((bytesInBuffer = in
1134: .read(buffer)) != -1) {
1135: outJar.write(buffer, 0,
1136: bytesInBuffer);
1137: bytesCopied += bytesInBuffer;
1138: }
1139: } else
1140: Debug
1141: .trace("custom data not found: "
1142: + contentPath);
1143: outJar.closeEntry();
1144:
1145: }
1146: }
1147: // Third we write the list into the
1148: // uninstaller.jar
1149: outJar.putNextEntry(new ZipEntry(key));
1150: ObjectOutputStream objOut = new ObjectOutputStream(
1151: outJar);
1152: objOut.writeObject(subContents);
1153: objOut.flush();
1154: outJar.closeEntry();
1155:
1156: } else {
1157: outJar.putNextEntry(new ZipEntry(key));
1158: if (contents instanceof ByteArrayOutputStream) {
1159: ((ByteArrayOutputStream) contents)
1160: .writeTo(outJar);
1161: } else {
1162: ObjectOutputStream objOut = new ObjectOutputStream(
1163: outJar);
1164: objOut.writeObject(contents);
1165: objOut.flush();
1166: }
1167: outJar.closeEntry();
1168: }
1169: }
1170: }
1171: // write the files which should be deleted by root for another user
1172:
1173: outJar.putNextEntry(new ZipEntry(UninstallData.ROOTSCRIPT));
1174: ObjectOutputStream rootStream = new ObjectOutputStream(
1175: outJar);
1176:
1177: String rootScript = udata.getRootScript();
1178:
1179: rootStream.writeUTF(rootScript);
1180:
1181: rootStream.flush();
1182: outJar.closeEntry();
1183:
1184: // Cleanup
1185: outJar.flush();
1186: outJar.close();
1187: } catch (Exception err) {
1188: err.printStackTrace();
1189: }
1190: }
1191:
1192: /**
1193: * Gets the stream to a resource.
1194: *
1195: * @param res The resource id.
1196: * @return The resource value, null if not found
1197: * @throws Exception
1198: */
1199: public InputStream getResource(String res) throws Exception {
1200: InputStream result;
1201: String basePath = "";
1202: ResourceManager rm = null;
1203:
1204: try {
1205: rm = ResourceManager.getInstance();
1206: basePath = rm.resourceBasePath;
1207: } catch (Exception e) {
1208: e.printStackTrace();
1209: }
1210:
1211: result = this .getClass().getResourceAsStream(basePath + res);
1212:
1213: if (result == null) {
1214: throw new ResourceNotFoundException(
1215: "Warning: Resource not found: " + res);
1216: }
1217: return result;
1218: }
1219:
1220: /**
1221: * Centers a window on screen.
1222: *
1223: * @param frame The window tp center.
1224: */
1225: public void centerFrame(Window frame) {
1226: Point center = GraphicsEnvironment
1227: .getLocalGraphicsEnvironment().getCenterPoint();
1228: Dimension frameSize = frame.getSize();
1229: frame.setLocation(center.x - frameSize.width / 2, center.y
1230: - frameSize.height / 2 - 10);
1231: }
1232:
1233: /**
1234: * Returns the panels container size.
1235: *
1236: * @return The panels container size.
1237: */
1238: public Dimension getPanelsContainerSize() {
1239: return panelsContainer.getSize();
1240: }
1241:
1242: /**
1243: * Sets the parameters of a GridBagConstraints object.
1244: *
1245: * @param gbc The constraints object.
1246: * @param gx The x coordinates.
1247: * @param gy The y coordinates.
1248: * @param gw The width.
1249: * @param wx The x wheight.
1250: * @param wy The y wheight.
1251: * @param gh Description of the Parameter
1252: */
1253: public void buildConstraints(GridBagConstraints gbc, int gx,
1254: int gy, int gw, int gh, double wx, double wy) {
1255: gbc.gridx = gx;
1256: gbc.gridy = gy;
1257: gbc.gridwidth = gw;
1258: gbc.gridheight = gh;
1259: gbc.weightx = wx;
1260: gbc.weighty = wy;
1261: }
1262:
1263: /**
1264: * Makes a clean closing.
1265: */
1266: public void exit() {
1267: if (installdata.canClose
1268: || ((!nextButton.isVisible() || !nextButton.isEnabled()) && (!prevButton
1269: .isVisible() || !prevButton.isEnabled()))) {
1270: // this does nothing if the uninstaller was not included
1271: writeUninstallData();
1272: Housekeeper.getInstance().shutDown(0);
1273: } else {
1274: // The installation is not over
1275: if (Unpacker.isDiscardInterrupt()
1276: && interruptCount < MAX_INTERRUPT) { // But we should not interrupt.
1277: interruptCount++;
1278: return;
1279: }
1280: // Use a alternate message and title if defined.
1281: final String mkey = "installer.quit.reversemessage";
1282: final String tkey = "installer.quit.reversetitle";
1283: String message = langpack.getString(mkey);
1284: String title = langpack.getString(tkey);
1285: // message equal to key -> no alternate message defined.
1286: if (message.indexOf(mkey) > -1)
1287: message = langpack.getString("installer.quit.message");
1288: // title equal to key -> no alternate title defined.
1289: if (title.indexOf(tkey) > -1)
1290: title = langpack.getString("installer.quit.title");
1291: // Now replace variables in message or title.
1292: VariableSubstitutor vs = new VariableSubstitutor(
1293: installdata.getVariables());
1294: message = vs.substitute(message, null);
1295: title = vs.substitute(title, null);
1296: int res = JOptionPane.showConfirmDialog(this , message,
1297: title, JOptionPane.YES_NO_OPTION);
1298: if (res == JOptionPane.YES_OPTION) {
1299: wipeAborted();
1300: Housekeeper.getInstance().shutDown(0);
1301: }
1302: }
1303: }
1304:
1305: /**
1306: * Wipes the written files when you abort the installation.
1307: */
1308: protected void wipeAborted() {
1309: // We set interrupt to all running Unpacker and wait 40 sec for maximum.
1310: // If interrupt is discarded (return value false), return immediately:
1311: if (!Unpacker.interruptAll(40000))
1312: return;
1313:
1314: // Wipe the files that had been installed
1315: UninstallData u = UninstallData.getInstance();
1316: for (String p : u.getInstalledFilesList()) {
1317: File f = new File(p);
1318: f.delete();
1319: }
1320: }
1321:
1322: /**
1323: * Launches the installation.
1324: *
1325: * @param listener The installation listener.
1326: */
1327: public void install(AbstractUIProgressHandler listener) {
1328: IUnpacker unpacker = UnpackerFactory.getUnpacker(
1329: this .installdata.info.getUnpackerClassName(),
1330: installdata, listener);
1331: unpacker.setRules(this .rules);
1332: Thread unpackerthread = new Thread(unpacker,
1333: "IzPack - Unpacker thread");
1334: unpackerthread.start();
1335: }
1336:
1337: /**
1338: * Writes an XML tree.
1339: *
1340: * @param root The XML tree to write out.
1341: * @param out The stream to write on.
1342: * @throws Exception Description of the Exception
1343: */
1344: public void writeXMLTree(XMLElement root, OutputStream out)
1345: throws Exception {
1346: XMLWriter writer = new XMLWriter(out);
1347: // fix bug# 4551
1348: // writer.write(root);
1349: for (int i = 0; i < installdata.panels.size(); i++) {
1350: IzPanel panel = installdata.panels.get(i);
1351: panel.makeXMLData(installdata.xmlData.getChildAtIndex(i));
1352: }
1353: writer.write(installdata.xmlData);
1354: }
1355:
1356: /**
1357: * Changes the quit button text. If <tt>text</tt> is null, the default quit text is used.
1358: *
1359: * @param text text to be used for changes
1360: */
1361: public void setQuitButtonText(String text) {
1362: String text1 = text;
1363: if (text1 == null)
1364: text1 = langpack.getString("installer.quit");
1365: quitButton.setText(text1);
1366: }
1367:
1368: /**
1369: * Sets a new icon into the quit button if icons should be used, else nothing will be done.
1370: *
1371: * @param iconName name of the icon to be used
1372: */
1373: public void setQuitButtonIcon(String iconName) {
1374: String useButtonIcons = installdata.guiPrefs.modifier
1375: .get("useButtonIcons");
1376:
1377: if (useButtonIcons == null
1378: || "yes".equalsIgnoreCase(useButtonIcons)) {
1379: quitButton.setIcon(icons.getImageIcon(iconName));
1380: }
1381: }
1382:
1383: /**
1384: * FocusTraversalPolicy objects to handle keybord blocking; the declaration os Object allows to
1385: * use a pre version 1.4 VM.
1386: */
1387: private Object usualFTP = null;
1388:
1389: private Object blockFTP = null;
1390:
1391: /**
1392: * Blocks GUI interaction.
1393: */
1394: public void blockGUI() {
1395: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1396: getGlassPane().setVisible(true);
1397: getGlassPane().setEnabled(true);
1398: // No traversal handling before VM version 1.4
1399: if (JAVA_SPECIFICATION_VERSION < 1.35)
1400: return;
1401: if (usualFTP == null)
1402: usualFTP = getFocusTraversalPolicy();
1403: if (blockFTP == null)
1404: blockFTP = new BlockFocusTraversalPolicy();
1405: setFocusTraversalPolicy((java.awt.FocusTraversalPolicy) blockFTP);
1406: getGlassPane().requestFocus();
1407: callGUIListener(GUIListener.GUI_BLOCKED);
1408:
1409: }
1410:
1411: /**
1412: * Releases GUI interaction.
1413: */
1414: public void releaseGUI() {
1415: getGlassPane().setEnabled(false);
1416: getGlassPane().setVisible(false);
1417: setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1418: // No traversal handling before VM version 1.4
1419: if (JAVA_SPECIFICATION_VERSION < 1.35)
1420: return;
1421: setFocusTraversalPolicy((java.awt.FocusTraversalPolicy) usualFTP);
1422: callGUIListener(GUIListener.GUI_RELEASED);
1423: }
1424:
1425: /**
1426: * Locks the 'previous' button.
1427: */
1428: public void lockPrevButton() {
1429: prevButton.setEnabled(false);
1430: }
1431:
1432: /**
1433: * Locks the 'next' button.
1434: */
1435: public void lockNextButton() {
1436: nextButton.setEnabled(false);
1437: }
1438:
1439: /**
1440: * Unlocks the 'previous' button.
1441: */
1442: public void unlockPrevButton() {
1443: prevButton.setEnabled(true);
1444: }
1445:
1446: /**
1447: * Unlocks the 'next' button.
1448: */
1449: public void unlockNextButton() {
1450: unlockNextButton(true);
1451: }
1452:
1453: /**
1454: * Unlocks the 'next' button.
1455: * @param requestFocus if <code>true</code> focus goes to <code>nextButton</code>
1456: */
1457: public void unlockNextButton(boolean requestFocus) {
1458: nextButton.setEnabled(true);
1459: if (requestFocus)
1460: nextButton.requestFocus();
1461: }
1462:
1463: /**
1464: * Allows a panel to ask to be skipped.
1465: */
1466: public void skipPanel() {
1467: if (installdata.curPanelNumber < installdata.panels.size() - 1) {
1468: if (isBack) {
1469: navigatePrevious(installdata.curPanelNumber);
1470: } else {
1471: navigateNext(installdata.curPanelNumber, false);
1472: }
1473: }
1474: }
1475:
1476: /**
1477: * Method checks whether conditions are met to show the given panel.
1478: *
1479: * @param panelnumber the panel number to check
1480: * @return true or false
1481: */
1482: public boolean canShow(int panelnumber) {
1483: IzPanel panel = installdata.panels.get(panelnumber);
1484: Panel panelmetadata = panel.getMetadata();
1485: String panelid = panelmetadata.getPanelid();
1486: Debug.trace("Current Panel: " + panelid);
1487:
1488: if (panelmetadata.hasCondition()) {
1489: Debug.log("Checking panelcondition");
1490: return rules.isConditionTrue(panelmetadata.getCondition());
1491: } else {
1492: if (!rules
1493: .canShowPanel(panelid, this .installdata.variables)) {
1494: // skip panel, if conditions for panel aren't met
1495: Debug.log("Skip panel with panelid=" + panelid);
1496: // panel should be skipped, so we have to decrement panelnumber for skipping
1497: return false;
1498: } else {
1499: return true;
1500: }
1501: }
1502: }
1503:
1504: /**
1505: * This function moves to the next panel
1506: */
1507: public void navigateNext() {
1508: // If the button is inactive this indicates that we cannot move
1509: // so we don't do the move
1510: if (!nextButton.isEnabled())
1511: return;
1512: this .navigateNext(installdata.curPanelNumber);
1513: }
1514:
1515: /**
1516: * This function searches for the next available panel, the search
1517: * begins from given panel+1.
1518: * @param startPanel the starting panel number
1519: */
1520: public void navigateNext(int startPanel) {
1521: this .navigateNext(startPanel, true);
1522: }
1523:
1524: /**
1525: * This function searches for the next available panel, the search
1526: * begins from given panel+1.
1527: *
1528: * @param startPanel the starting panel number
1529: * @param doValidation whether to do panel validation
1530: */
1531: public void navigateNext(int startPanel, boolean doValidation) {
1532: if ((installdata.curPanelNumber < installdata.panels.size() - 1)) {
1533: // We must trasfer all fields into the variables before
1534: // panelconditions try to resolve the rules based on unassigned vars.
1535: boolean isValid = doValidation ? ((IzPanel) installdata.panels
1536: .get(startPanel)).isValidated()
1537: : true;
1538:
1539: // if this is not here, validation will
1540: // occur mutilple times while skipping panels through the recursion
1541: if (!isValid)
1542: return;
1543:
1544: installdata.curPanelNumber++;
1545: if (!canShow(installdata.curPanelNumber)) {
1546: this .navigateNext(startPanel, false);
1547: } else {
1548: switchPanel(startPanel);
1549: }
1550: }
1551: }
1552:
1553: /**
1554: * This function moves to the previous panel
1555: */
1556: public void navigatePrevious() {
1557: // If the button is inactive this indicates that we cannot move
1558: // so we don't do the move
1559: if (!prevButton.isEnabled())
1560: return;
1561: this .navigatePrevious(installdata.curPanelNumber);
1562: }
1563:
1564: /**
1565: * This function switches to available panel that is just before given one.
1566: *
1567: * @param endingPanel the panel is searched backwards, beginning from this.
1568: */
1569: public void navigatePrevious(int endingPanel) {
1570: if ((installdata.curPanelNumber > 0)) {
1571: installdata.curPanelNumber--;
1572: if (!canShow(installdata.curPanelNumber)) {
1573: this .navigatePrevious(endingPanel);
1574: } else {
1575: switchPanel(endingPanel);
1576: }
1577: }
1578: }
1579:
1580: /**
1581: * Handles the events from the navigation bar elements.
1582: *
1583: * @author Julien Ponge
1584: */
1585: class NavigationHandler implements ActionListener {
1586:
1587: /**
1588: * Actions handler.
1589: *
1590: * @param e The event.
1591: */
1592: public void actionPerformed(ActionEvent e) {
1593: Object source = e.getSource();
1594: if (source == prevButton) {
1595: navigatePrevious();
1596: } else if (source == nextButton) {
1597: navigateNext();
1598: } else if (source == quitButton)
1599: exit();
1600:
1601: }
1602: }
1603:
1604: /**
1605: * The window events handler.
1606: *
1607: * @author julien created October 27, 2002
1608: */
1609: class WindowHandler extends WindowAdapter {
1610:
1611: /**
1612: * Window close is pressed,
1613: *
1614: * @param e The event.
1615: */
1616: public void windowClosing(WindowEvent e) {
1617: // We ask for confirmation
1618: exit();
1619: }
1620:
1621: /**
1622: * OLD VERSION We can't avoid the exit here, so don't call exit anywhere else.
1623: *
1624: * @param e The event.
1625: *
1626: * public void windowClosing(WindowEvent e) { if (Unpacker.isDiscardInterrupt() &&
1627: * interruptCount < MAX_INTERRUPT) { // But we should not interrupt. interruptCount++;
1628: * return; } // We show an alert anyway if (!installdata.canClose)
1629: * JOptionPane.showMessageDialog(null, langpack.getString("installer.quit.message"),
1630: * langpack.getString("installer.warning"), JOptionPane.ERROR_MESSAGE); wipeAborted();
1631: * Housekeeper.getInstance().shutDown(0); }
1632: */
1633: }
1634:
1635: /**
1636: * A FocusTraversalPolicy that only allows the block panel to have the focus
1637: */
1638: private class BlockFocusTraversalPolicy extends
1639: java.awt.DefaultFocusTraversalPolicy {
1640:
1641: private static final long serialVersionUID = 3258413928261169209L;
1642:
1643: /**
1644: * Only accepts the block panel
1645: *
1646: * @param aComp the component to check
1647: * @return true if aComp is the block panel
1648: */
1649: protected boolean accept(Component aComp) {
1650: return aComp == getGlassPane();
1651: }
1652: }
1653:
1654: /**
1655: * Returns the gui creation listener list.
1656: *
1657: * @return the gui creation listener list
1658: */
1659: public List<GUIListener> getGuiListener() {
1660: return guiListener;
1661: }
1662:
1663: /**
1664: * Add a listener to the listener list.
1665: *
1666: * @param listener to be added as gui creation listener
1667: */
1668: public void addGuiListener(GUIListener listener) {
1669: guiListener.add(listener);
1670: }
1671:
1672: /**
1673: * Creates heading labels.
1674: *
1675: * @param headingLines the number of lines of heading labels
1676: * @param back background color (currently not used)
1677: */
1678: private void createHeadingLabels(int headingLines, Color back) {
1679: // headingLabels are an array which contains the labels for header (0),
1680: // description lines and the icon (last).
1681: headingLabels = new JLabel[headingLines + 1];
1682: headingLabels[0] = new JLabel("");
1683: // First line ist the "main heading" which should be bold.
1684: headingLabels[0].setFont(headingLabels[0].getFont().deriveFont(
1685: Font.BOLD));
1686:
1687: // Updated by Daniel Azarov, Exadel Inc.
1688: // start
1689: Color foreground = null;
1690: if (installdata.guiPrefs.modifier
1691: .containsKey("headingForegroundColor")) {
1692: foreground = Color.decode(installdata.guiPrefs.modifier
1693: .get("headingForegroundColor"));
1694: headingLabels[0].setForeground(foreground);
1695: }
1696: // end
1697:
1698: if (installdata.guiPrefs.modifier
1699: .containsKey("headingFontSize")) {
1700: float fontSize = Float
1701: .parseFloat(installdata.guiPrefs.modifier
1702: .get("headingFontSize"));
1703: if (fontSize > 0.0 && fontSize <= 5.0) {
1704: float currentSize = headingLabels[0].getFont()
1705: .getSize2D();
1706: headingLabels[0].setFont(headingLabels[0].getFont()
1707: .deriveFont(currentSize * fontSize));
1708: }
1709: }
1710: for (int i = 1; i < headingLines; ++i) {
1711: headingLabels[i] = new JLabel();
1712: // Minor headings should be a little bit more to the right.
1713: headingLabels[i].setBorder(BorderFactory.createEmptyBorder(
1714: 0, 30, 0, 0));
1715: }
1716:
1717: }
1718:
1719: /**
1720: * Creates heading panel counter.
1721: *
1722: * @param back background color
1723: * @param navPanel navi JPanel
1724: * @param leftHeadingPanel left heading JPanel
1725: */
1726: private void createHeadingCounter(Color back, JPanel navPanel,
1727: JPanel leftHeadingPanel) {
1728: int i;
1729: String counterPos = "inHeading";
1730: if (installdata.guiPrefs.modifier
1731: .containsKey("headingPanelCounterPos"))
1732: counterPos = installdata.guiPrefs.modifier
1733: .get("headingPanelCounterPos");
1734: // Do not create counter if it should be in the heading, but no heading should be used.
1735: if (leftHeadingPanel == null
1736: && "inHeading".equalsIgnoreCase(counterPos))
1737: return;
1738: if (installdata.guiPrefs.modifier
1739: .containsKey("headingPanelCounter")) {
1740: headingCounterComponent = null;
1741: if ("progressbar"
1742: .equalsIgnoreCase(installdata.guiPrefs.modifier
1743: .get("headingPanelCounter"))) {
1744: JProgressBar headingProgressBar = new JProgressBar();
1745: headingProgressBar.setStringPainted(true);
1746: headingProgressBar.setString("");
1747: headingProgressBar.setValue(0);
1748: headingCounterComponent = headingProgressBar;
1749: } else if ("text"
1750: .equalsIgnoreCase(installdata.guiPrefs.modifier
1751: .get("headingPanelCounter"))) {
1752: JLabel headingCountPanels = new JLabel(" ");
1753: headingCounterComponent = headingCountPanels;
1754: headingCounterComponent.setBorder(BorderFactory
1755: .createEmptyBorder(0, 30, 0, 0));
1756:
1757: // Updated by Daniel Azarov, Exadel Inc.
1758: // start
1759: Color foreground = null;
1760: if (installdata.guiPrefs.modifier
1761: .containsKey("headingForegroundColor")) {
1762: foreground = Color
1763: .decode(installdata.guiPrefs.modifier
1764: .get("headingForegroundColor"));
1765: headingCountPanels.setForeground(foreground);
1766: }
1767: // end
1768: }
1769: if ("inHeading".equals(counterPos)) {
1770: leftHeadingPanel.add(headingCounterComponent);
1771: } else if ("inNavigationPanel".equals(counterPos)) {
1772: Component[] comps = navPanel.getComponents();
1773: for (i = 0; i < comps.length; ++i) {
1774: if (comps[i].equals(prevButton))
1775: break;
1776: }
1777: if (i <= comps.length) {
1778: navPanel.add(Box.createHorizontalGlue(), i);
1779: navPanel.add(headingCounterComponent, i);
1780: }
1781:
1782: }
1783: }
1784: }
1785:
1786: /**
1787: * Creates heading icon.
1788: *
1789: * @param back the color of background around image.
1790: * @return a panel with heading image.
1791: */
1792: private JPanel createHeadingIcon(Color back) {
1793: // the icon
1794: ImageIcon icon = null;
1795: try {
1796: icon = loadIcon(HEADING_ICON_RESOURCE, 0, true);
1797: } catch (Exception e) {
1798: // ignore
1799: }
1800: JPanel imgPanel = new JPanel();
1801: imgPanel.setLayout(new BoxLayout(imgPanel, BoxLayout.Y_AXIS));
1802:
1803: // Updated by Daniel Azarov, Exadel Inc.
1804: // start
1805: int borderSize = 8;
1806: if (installdata.guiPrefs.modifier
1807: .containsKey("headingImageBorderSize")) {
1808: borderSize = Integer.parseInt(installdata.guiPrefs.modifier
1809: .get("headingImageBorderSize"));
1810: }
1811: imgPanel.setBorder(BorderFactory.createEmptyBorder(borderSize,
1812: borderSize, borderSize, borderSize));
1813: // end
1814:
1815: if (back != null)
1816: imgPanel.setBackground(back);
1817: JLabel iconLab = new JLabel(icon);
1818: imgPanel.add(iconLab, BorderLayout.EAST);
1819: headingLabels[headingLabels.length - 1] = iconLab;
1820: return (imgPanel);
1821:
1822: }
1823:
1824: /**
1825: * Creates a Heading in given Panel.
1826: * @param navPanel a panel
1827: */
1828: private void createHeading(JPanel navPanel) {
1829: headingPanel = null;
1830: int headingLines = 1;
1831: // The number of lines can be determined in the config xml file.
1832: // The first is the header, additonals are descriptions for the header.
1833: if (installdata.guiPrefs.modifier
1834: .containsKey("headingLineCount"))
1835: headingLines = Integer
1836: .parseInt(installdata.guiPrefs.modifier
1837: .get("headingLineCount"));
1838: Color back = null;
1839: int i = 0;
1840: // It is possible to determine the used background color of the heading panel.
1841: if (installdata.guiPrefs.modifier
1842: .containsKey("headingBackgroundColor"))
1843: back = Color.decode(installdata.guiPrefs.modifier
1844: .get("headingBackgroundColor"));
1845: // Try to create counter if no heading should be used.
1846: if (!isHeading(null)) {
1847: createHeadingCounter(back, navPanel, null);
1848: return;
1849: }
1850:
1851: // We create the text labels and the needed panels. From inner to outer.
1852: // Labels
1853: createHeadingLabels(headingLines, back);
1854: // Panel which contains the labels
1855: JPanel leftHeadingPanel = new JPanel();
1856: if (back != null)
1857: leftHeadingPanel.setBackground(back);
1858: leftHeadingPanel.setLayout(new BoxLayout(leftHeadingPanel,
1859: BoxLayout.Y_AXIS));
1860: for (i = 0; i < headingLines; ++i)
1861: leftHeadingPanel.add(headingLabels[i]);
1862: // HeadingPanel counter: this is a label or a progress bar which can be placed
1863: // in the leftHeadingPanel or in the navigation bar. It is facultative. If
1864: // exist, it shows the current panel number and the amount of panels.
1865: createHeadingCounter(back, navPanel, leftHeadingPanel);
1866: // It is possible to place an icon on the right side of the heading panel.
1867: JPanel imgPanel = createHeadingIcon(back);
1868:
1869: // The panel for text and icon.
1870: JPanel northPanel = new JPanel();
1871: if (back != null)
1872: northPanel.setBackground(back);
1873: northPanel
1874: .setLayout(new BoxLayout(northPanel, BoxLayout.X_AXIS));
1875: northPanel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0,
1876: 0));
1877: northPanel.add(leftHeadingPanel);
1878: northPanel.add(Box.createHorizontalGlue());
1879: northPanel.add(imgPanel);
1880: headingPanel = new JPanel(new BorderLayout());
1881: headingPanel.add(northPanel);
1882: headingPanel.add(new JSeparator(), BorderLayout.SOUTH);
1883:
1884: // contentPane.add(northPanel, BorderLayout.NORTH);
1885: contentPane.add(headingPanel, BorderLayout.NORTH);
1886:
1887: }
1888:
1889: /**
1890: * Returns whether this installer frame uses with the given panel a separated heading panel or
1891: * not. Be aware, this is an other heading as given by the IzPanel which will be placed in the
1892: * IzPanel. This heading will be placed if the gui preferences contains an modifier with the key
1893: * "useHeadingPanel" and the value "yes" and there is a message with the key "<class
1894: * name>.headline".
1895: *
1896: * @param caller the IzPanel for which heading should be resolved
1897: * @return whether an heading panel will be used or not
1898: */
1899: public boolean isHeading(IzPanel caller) {
1900: if (!installdata.guiPrefs.modifier
1901: .containsKey("useHeadingPanel")
1902: || !(installdata.guiPrefs.modifier
1903: .get("useHeadingPanel"))
1904: .equalsIgnoreCase("yes"))
1905: return (false);
1906: if (caller == null)
1907: return (true);
1908: return (caller.getI18nStringForClass("headline", null) != null);
1909:
1910: }
1911:
1912: private void performHeading(IzPanel panel) {
1913: int i;
1914: int headingLines = 1;
1915: if (installdata.guiPrefs.modifier
1916: .containsKey("headingLineCount"))
1917: headingLines = Integer
1918: .parseInt(installdata.guiPrefs.modifier
1919: .get("headingLineCount"));
1920:
1921: if (headingLabels == null)
1922: return;
1923: String headline = panel.getI18nStringForClass("headline");
1924: if (headline == null) {
1925: headingPanel.setVisible(false);
1926: return;
1927: }
1928: for (i = 0; i <= headingLines; ++i)
1929: if (headingLabels[i] != null)
1930: headingLabels[i].setVisible(false);
1931: String info;
1932: for (i = 0; i < headingLines - 1; ++i) {
1933: info = panel.getI18nStringForClass("headinfo"
1934: + Integer.toString(i));
1935: if (info == null)
1936: info = " ";
1937: if (info.endsWith(":")) {
1938: info = info.substring(0, info.length() - 1) + ".";
1939: }
1940: headingLabels[i + 1].setText(info);
1941: headingLabels[i + 1].setVisible(true);
1942: }
1943: // Do not forgett the first headline.
1944: headingLabels[0].setText(headline);
1945: headingLabels[0].setVisible(true);
1946: int curPanelNo = visiblePanelMapping
1947: .get(installdata.curPanelNumber);
1948: if (headingLabels[headingLines] != null) {
1949: loadAndShowImage(headingLabels[headingLines],
1950: HEADING_ICON_RESOURCE, curPanelNo);
1951: headingLabels[headingLines].setVisible(true);
1952: }
1953: headingPanel.setVisible(true);
1954:
1955: }
1956:
1957: private void performHeadingCounter(IzPanel panel) {
1958: if (headingCounterComponent != null) {
1959: int curPanelNo = visiblePanelMapping
1960: .get(installdata.curPanelNumber);
1961: int visPanelsCount = visiblePanelMapping
1962: .get((visiblePanelMapping.get(installdata.panels
1963: .size())).intValue());
1964:
1965: StringBuffer buf = new StringBuffer();
1966: buf.append(langpack.getString("installer.step"))
1967: .append(" ").append(curPanelNo + 1).append(" ")
1968: .append(langpack.getString("installer.of")).append(
1969: " ").append(visPanelsCount + 1);
1970: if (headingCounterComponent instanceof JProgressBar) {
1971: JProgressBar headingProgressBar = (JProgressBar) headingCounterComponent;
1972: headingProgressBar.setMaximum(visPanelsCount + 1);
1973: headingProgressBar.setValue(curPanelNo + 1);
1974: headingProgressBar.setString(buf.toString());
1975: } else
1976: ((JLabel) headingCounterComponent).setText(buf
1977: .toString());
1978: }
1979: }
1980:
1981: /**
1982: * @return the rules
1983: */
1984: public RulesEngine getRules() {
1985: return this .rules;
1986: }
1987:
1988: /**
1989: * @param rules the rules to set
1990: */
1991: public void setRules(RulesEngine rules) {
1992: this.rules = rules;
1993: }
1994: }
|