001/*
002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved.
003 * 
004 * http://www.izforge.com/izpack/
005 * http://developer.berlios.de/projects/izpack/
006 * 
007 * Copyright 2002 Jan Blok
008 * 
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *     http://www.apache.org/licenses/LICENSE-2.0
014 *     
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 */
021
022package com.izforge.izpack.installer;
023
024import java.awt.BorderLayout;
025import java.awt.Component;
026import java.awt.Cursor;
027import java.awt.Dimension;
028import java.awt.Font;
029import java.awt.GridBagConstraints;
030import java.awt.GridLayout;
031import java.awt.Toolkit;
032import java.awt.Window;
033import java.awt.event.ActionEvent;
034import java.awt.event.ActionListener;
035import java.awt.event.FocusAdapter;
036import java.awt.event.KeyAdapter;
037import java.awt.event.MouseAdapter;
038import java.awt.event.MouseMotionAdapter;
039import java.awt.event.WindowAdapter;
040import java.awt.event.WindowEvent;
041import java.io.BufferedWriter;
042import java.io.ByteArrayOutputStream;
043import java.io.File;
044import java.io.InputStream;
045import java.io.ObjectOutputStream;
046import java.io.OutputStream;
047import java.io.OutputStreamWriter;
048import java.lang.reflect.Constructor;
049import java.net.URL;
050import java.util.ArrayList;
051import java.util.HashSet;
052import java.util.Iterator;
053import java.util.List;
054import java.util.Map;
055import java.util.Vector;
056import java.util.zip.ZipEntry;
057import java.util.zip.ZipException;
058import java.util.zip.ZipOutputStream;
059
060import javax.swing.BorderFactory;
061import javax.swing.Box;
062import javax.swing.BoxLayout;
063import javax.swing.ImageIcon;
064import javax.swing.JButton;
065import javax.swing.JFrame;
066import javax.swing.JLabel;
067import javax.swing.JOptionPane;
068import javax.swing.JPanel;
069import javax.swing.UIManager;
070import javax.swing.WindowConstants;
071import javax.swing.border.TitledBorder;
072import javax.swing.text.JTextComponent;
073
074import net.n3.nanoxml.NonValidator;
075import net.n3.nanoxml.StdXMLBuilder;
076import net.n3.nanoxml.StdXMLParser;
077import net.n3.nanoxml.StdXMLReader;
078import net.n3.nanoxml.XMLElement;
079import net.n3.nanoxml.XMLWriter;
080
081import com.izforge.izpack.CustomData;
082import com.izforge.izpack.ExecutableFile;
083import com.izforge.izpack.LocaleDatabase;
084import com.izforge.izpack.Panel;
085import com.izforge.izpack.gui.ButtonFactory;
086import com.izforge.izpack.gui.EtchedLineBorder;
087import com.izforge.izpack.gui.IconsDatabase;
088import com.izforge.izpack.util.AbstractUIProgressHandler;
089import com.izforge.izpack.util.Debug;
090import com.izforge.izpack.util.Housekeeper;
091import com.izforge.izpack.util.OsConstraint;
092
093/**
094 * The IzPack installer frame.
095 * 
096 * @author Julien Ponge created October 27, 2002
097 * @author Fabrice Mirabile added fix for alert window on cross button, July 06 2005
098 */
099public class InstallerFrame extends JFrame
100{
101
102    private static final long serialVersionUID = 3257852069162727473L;
103
104    /** VM version to use version dependent methods calls */
105    private static final float JAVA_SPECIFICATION_VERSION = Float.parseFloat(System
106            .getProperty("java.specification.version"));
107
108    /** The language pack. */
109    public LocaleDatabase langpack;
110
111    /** The installation data. */
112    protected InstallData installdata;
113
114    /** The icons database. */
115    public IconsDatabase icons;
116
117    /** The panels container. */
118    protected JPanel panelsContainer;
119
120    /** The frame content pane. */
121    protected JPanel contentPane;
122
123    /** The previous button. */
124    protected JButton prevButton;
125
126    /** The next button. */
127    protected JButton nextButton;
128
129    /** The quit button. */
130    protected JButton quitButton;
131
132    /** Image */
133    private JLabel iconLabel;
134
135    /** Count for discarded interrupt trials. */
136    private int interruptCount = 1;
137
138    /** Maximum of discarded interrupt trials. */
139    private static final int MAX_INTERRUPT = 3;
140
141    /**
142     * The constructor (normal mode).
143     * 
144     * @param title The window title.
145     * @param installdata The installation data.
146     * @exception Exception Description of the Exception
147     */
148    public InstallerFrame(String title, InstallData installdata) throws Exception
149    {
150        super(title);
151        this.installdata = installdata;
152        this.langpack = installdata.langpack;
153
154        // Sets the window events handler
155        addWindowListener(new WindowHandler());
156        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
157        // Builds the GUI
158        loadIcons();
159        loadPanels();
160        buildGUI();
161
162        // We show the frame
163        showFrame();
164        switchPanel(0);
165    }
166
167    /**
168     * Loads the panels.
169     * 
170     * @exception Exception Description of the Exception
171     */
172    private void loadPanels() throws Exception
173    {
174        // Initialisation
175        java.util.List panelsOrder = installdata.panelsOrder;
176        int i;
177        int size = panelsOrder.size();
178        String className;
179        Class objectClass;
180        Constructor constructor;
181        Object object;
182        IzPanel panel;
183        Class[] paramsClasses = new Class[2];
184        paramsClasses[0] = Class.forName("com.izforge.izpack.installer.InstallerFrame");
185        paramsClasses[1] = Class.forName("com.izforge.izpack.installer.InstallData");
186        Object[] params = { this, installdata};
187
188        // We load each of them
189        for (i = 0; i < size; i++)
190        {
191            // We add the panel
192            Panel p = (Panel) panelsOrder.get(i);
193
194            if (!OsConstraint.oneMatchesCurrentSystem(p.osConstraints)) continue;
195            className = (String) p.className;
196            String praefix = "com.izforge.izpack.panels.";
197            if (className.compareTo(".") > -1)
198            // Full qualified class name
199                praefix = "";
200            objectClass = Class.forName(praefix + className);
201            constructor = objectClass.getDeclaredConstructor(paramsClasses);
202            object = constructor.newInstance(params);
203            panel = (IzPanel) object;
204            installdata.panels.add(panel);
205
206            // We add the XML data panel root
207            XMLElement panelRoot = new XMLElement(className);
208            installdata.xmlData.addChild(panelRoot);
209        }
210    }
211
212    /**
213     * Loads the icons.
214     * 
215     * @exception Exception Description of the Exception
216     */
217    private void loadIcons() throws Exception
218    {
219        // Initialisations
220        icons = new IconsDatabase();
221        URL url;
222        ImageIcon img;
223        XMLElement icon;
224        InputStream inXML = InstallerFrame.class
225                .getResourceAsStream("/com/izforge/izpack/installer/icons.xml");
226
227        // Initialises the parser
228        StdXMLParser parser = new StdXMLParser();
229        parser.setBuilder(new StdXMLBuilder());
230        parser.setReader(new StdXMLReader(inXML));
231        parser.setValidator(new NonValidator());
232
233        // We get the data
234        XMLElement data = (XMLElement) parser.parse();
235
236        // We load the icons
237        Vector children = data.getChildrenNamed("icon");
238        int size = children.size();
239        for (int i = 0; i < size; i++)
240        {
241            icon = (XMLElement) children.get(i);
242            url = InstallerFrame.class.getResource(icon.getAttribute("res"));
243            img = new ImageIcon(url);
244            icons.put(icon.getAttribute("id"), img);
245        }
246
247        // We load the Swing-specific icons
248        children = data.getChildrenNamed("sysicon");
249        size = children.size();
250        for (int i = 0; i < size; i++)
251        {
252            icon = (XMLElement) children.get(i);
253            url = InstallerFrame.class.getResource(icon.getAttribute("res"));
254            img = new ImageIcon(url);
255            UIManager.put(icon.getAttribute("id"), img);
256        }
257    }
258
259    /** Builds the GUI. */
260    private void buildGUI()
261    {
262        this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); //patch 06/07/2005, Fabrice Mirabile
263            // Sets the frame icon
264        setIconImage(icons.getImageIcon("JFrameIcon").getImage());
265
266        // Prepares the glass pane to block the gui interaction when needed
267        JPanel glassPane = (JPanel) getGlassPane();
268        glassPane.addMouseListener(new MouseAdapter() {});
269        glassPane.addMouseMotionListener(new MouseMotionAdapter() {});
270        glassPane.addKeyListener(new KeyAdapter() {});
271        glassPane.addFocusListener(new FocusAdapter() {});
272
273        // We set the layout & prepare the constraint object
274        contentPane = (JPanel) getContentPane();
275        contentPane.setLayout(new BorderLayout()); // layout);
276
277        // We add the panels container
278        panelsContainer = new JPanel();
279        panelsContainer.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10));
280        panelsContainer.setLayout(new GridLayout(1, 1));
281        contentPane.add(panelsContainer, BorderLayout.CENTER);
282
283        // We put the first panel
284        installdata.curPanelNumber = 0;
285        IzPanel panel_0 = (IzPanel) installdata.panels.get(0);
286        panelsContainer.add(panel_0);
287
288        // We add the navigation buttons & labels
289
290        NavigationHandler navHandler = new NavigationHandler();
291
292        JPanel navPanel = new JPanel();
293        navPanel.setLayout(new BoxLayout(navPanel, BoxLayout.X_AXIS));
294        navPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(8, 8,
295                8, 8), BorderFactory.createTitledBorder(new EtchedLineBorder(), langpack
296                .getString("installer.madewith")
297                + " ", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION,
298                new Font("Dialog", Font.PLAIN, 10))));
299        navPanel.add(Box.createHorizontalGlue());
300
301        prevButton = ButtonFactory.createButton(langpack.getString("installer.prev"), icons
302                .getImageIcon("stepback"), installdata.buttonsHColor);
303        navPanel.add(prevButton);
304        prevButton.addActionListener(navHandler);
305
306        navPanel.add(Box.createRigidArea(new Dimension(5, 0)));
307
308        nextButton = ButtonFactory.createButton(langpack.getString("installer.next"), icons
309                .getImageIcon("stepforward"), installdata.buttonsHColor);
310        navPanel.add(nextButton);
311        nextButton.addActionListener(navHandler);
312
313        navPanel.add(Box.createRigidArea(new Dimension(5, 0)));
314
315        quitButton = ButtonFactory.createButton(langpack.getString("installer.quit"), icons
316                .getImageIcon("stop"), installdata.buttonsHColor);
317        navPanel.add(quitButton);
318        quitButton.addActionListener(navHandler);
319        contentPane.add(navPanel, BorderLayout.SOUTH);
320
321        try
322        {
323            ResourceManager rm = ResourceManager.getInstance();
324            ImageIcon icon;
325            try
326            {
327                icon = rm.getImageIconResource("Installer.image");
328            }
329            catch (Exception e) // This is not that clean ...
330            {
331                icon = rm.getImageIconResource("Installer.image.0");
332            }
333            if (icon != null)
334            {
335                JPanel imgPanel = new JPanel();
336                imgPanel.setLayout(new BorderLayout());
337                imgPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 0));
338                iconLabel = new JLabel(icon);
339                iconLabel.setBorder(BorderFactory.createLoweredBevelBorder());
340                imgPanel.add(iconLabel, BorderLayout.NORTH);
341                contentPane.add(imgPanel, BorderLayout.WEST);
342            }
343        }
344        catch (Exception e)
345        {
346            // ignore
347        }
348
349        loadImage(0);
350        getRootPane().setDefaultButton(nextButton);
351    }
352
353    private void loadImage(int panelNo)
354    {
355        try
356        {
357            ResourceManager rm = ResourceManager.getInstance();
358            ImageIcon icon = rm.getImageIconResource("Installer.image." + panelNo);
359            if (icon != null)
360            {
361                iconLabel.setVisible(false);
362                iconLabel.setIcon(icon);
363                iconLabel.setVisible(true);
364            }
365        }
366        catch (Exception e)
367        {
368            // ignore
369        }
370    }
371
372    /** Shows the frame. */
373    private void showFrame()
374    {
375        pack();
376        setSize(installdata.guiPrefs.width, installdata.guiPrefs.height);
377        setResizable(installdata.guiPrefs.resizable);
378        centerFrame(this);
379        setVisible(true);
380    }
381
382    private boolean isBack = false;
383
384    /**
385     * Switches the current panel.
386     * 
387     * @param last Description of the Parameter
388     */
389    protected void switchPanel(int last)
390    {
391        try
392        {
393            if (installdata.curPanelNumber < last)
394            {
395                isBack = true;
396            }
397            panelsContainer.setVisible(false);
398            IzPanel panel = (IzPanel) installdata.panels.get(installdata.curPanelNumber);
399            IzPanel l_panel = (IzPanel) installdata.panels.get(last);
400            l_panel.makeXMLData(installdata.xmlData.getChildAtIndex(last));
401
402            if (installdata.curPanelNumber == 0)
403            {
404                prevButton.setVisible(false);
405                lockPrevButton();
406                unlockNextButton(); // if we push the button back at the license
407                // panel
408            }
409            else if (installdata.curPanelNumber == installdata.panels.size() - 1)
410            {
411                prevButton.setVisible(false);
412                nextButton.setVisible(false);
413                lockNextButton();
414
415                // Set the default button to the only visible button.
416                getRootPane().setDefaultButton(quitButton);
417            }
418            else
419            {
420                prevButton.setVisible(true);
421                nextButton.setVisible(true);
422                unlockPrevButton();
423                unlockNextButton();
424            }
425
426            // Change panels container to the current one.
427            panelsContainer.remove(l_panel);
428            l_panel.panelDeactivate();
429            panelsContainer.add(panel);
430
431            if (panel.getInitialFocus() != null)
432            { // Initial focus hint should be performed after current panel
433                // was added to the panels container, else the focus hint will
434                // be ignored.
435                // Give a hint for the initial focus to the system.
436                Component inFoc = panel.getInitialFocus();
437                if (JAVA_SPECIFICATION_VERSION < 1.35)
438                {
439                    inFoc.requestFocus();
440                }
441                else
442                {
443                    inFoc.requestFocusInWindow();
444                }
445
446                /*
447                 * On editable text components position the caret to the end of the cust existent
448                 * text.
449                 */
450                if (inFoc instanceof JTextComponent)
451                {
452                    JTextComponent inText = (JTextComponent) inFoc;
453                    if (inText.isEditable() && inText.getDocument() != null)
454                    {
455                        inText.setCaretPosition(inText.getDocument().getLength());
456                    }
457                }
458            }
459            panel.panelActivate();
460            panelsContainer.setVisible(true);
461            loadImage(installdata.curPanelNumber);
462            isBack = false;
463        }
464        catch (Exception err)
465        {
466            err.printStackTrace();
467        }
468    }
469
470    /** Writes the uninstalldata. */
471    private void writeUninstallData()
472    {
473        try
474        {
475            // We get the data
476            UninstallData udata = UninstallData.getInstance();
477            List files = udata.getFilesList();
478            ZipOutputStream outJar = installdata.uninstallOutJar;
479
480            if (outJar == null) return;
481
482            // We write the files log
483            outJar.putNextEntry(new ZipEntry("install.log"));
484            BufferedWriter logWriter = new BufferedWriter(new OutputStreamWriter(outJar));
485            logWriter.write(installdata.getInstallPath());
486            logWriter.newLine();
487            Iterator iter = files.iterator();
488            while (iter.hasNext())
489            {
490                logWriter.write((String) iter.next());
491                if (iter.hasNext()) logWriter.newLine();
492            }
493            logWriter.flush();
494            outJar.closeEntry();
495
496            // We write the uninstaller jar file log
497            outJar.putNextEntry(new ZipEntry("jarlocation.log"));
498            logWriter = new BufferedWriter(new OutputStreamWriter(outJar));
499            logWriter.write(udata.getUninstallerJarFilename());
500            logWriter.newLine();
501            logWriter.write(udata.getUninstallerPath());
502            logWriter.flush();
503            outJar.closeEntry();
504
505            // Write out executables to execute on uninstall
506            outJar.putNextEntry(new ZipEntry("executables"));
507            ObjectOutputStream execStream = new ObjectOutputStream(outJar);
508            iter = udata.getExecutablesList().iterator();
509            execStream.writeInt(udata.getExecutablesList().size());
510            while (iter.hasNext())
511            {
512                ExecutableFile file = (ExecutableFile) iter.next();
513                execStream.writeObject(file);
514            }
515            execStream.flush();
516            outJar.closeEntry();
517
518            // Write out additional uninstall data
519            // Do not "kill" the installation if there is a problem
520            // with custom uninstall data. Therefore log it to Debug,
521            // but do not throw.
522            Map additionalData = udata.getAdditionalData();
523            if (additionalData != null && !additionalData.isEmpty())
524            {
525                Iterator keys = additionalData.keySet().iterator();
526                HashSet exist = new HashSet();
527                while (keys != null && keys.hasNext())
528                {
529                    String key = (String) keys.next();
530                    Object contents = additionalData.get(key);
531                    if (key.equals("__uninstallLibs__"))
532                    {
533                        Iterator nativeLibIter = ((List) contents).iterator();
534                        while (nativeLibIter != null && nativeLibIter.hasNext())
535                        {
536                            String nativeLibName = (String) ((List) nativeLibIter.next()).get(0);
537                            byte[] buffer = new byte[5120];
538                            long bytesCopied = 0;
539                            int bytesInBuffer;
540                            outJar.putNextEntry(new ZipEntry("native/" + nativeLibName));
541                            InputStream in = getClass().getResourceAsStream(
542                                    "/native/" + nativeLibName);
543                            while ((bytesInBuffer = in.read(buffer)) != -1)
544                            {
545                                outJar.write(buffer, 0, bytesInBuffer);
546                                bytesCopied += bytesInBuffer;
547                            }
548                            outJar.closeEntry();
549                        }
550                    }
551                    else if (key.equals("uninstallerListeners") || key.equals("uninstallerJars"))
552                    { // It is a ArrayList of ArrayLists which contains the
553                        // full
554                        // package paths of all needed class files.
555                        // First we create a new ArrayList which contains only
556                        // the full paths for the uninstall listener self; thats
557                        // the first entry of each sub ArrayList.
558                        ArrayList subContents = new ArrayList();
559
560                        // Secound put the class into uninstaller.jar
561                        Iterator listenerIter = ((List) contents).iterator();
562                        while (listenerIter.hasNext())
563                        {
564                            byte[] buffer = new byte[5120];
565                            long bytesCopied = 0;
566                            int bytesInBuffer;
567                            CustomData customData = (CustomData) listenerIter.next();
568                            // First element of the list contains the listener
569                            // class path;
570                            // remind it for later.
571                            if (customData.listenerName != null)
572                                subContents.add(customData.listenerName);
573                            Iterator liClaIter = customData.contents.iterator();
574                            while (liClaIter.hasNext())
575                            {
576                                String contentPath = (String) liClaIter.next();
577                                if (exist.contains(contentPath)) continue;
578                                exist.add(contentPath);
579                                try
580                                {
581                                    outJar.putNextEntry(new ZipEntry(contentPath));
582                                }
583                                catch (ZipException ze)
584                                { // Ignore, or ignore not ?? May be it is a
585                                    // exception because
586                                    // a doubled entry was tried, then we should
587                                    // ignore ...
588                                    Debug.trace("ZipException in writing custom data: "
589                                            + ze.getMessage());
590                                    continue;
591                                }
592                                InputStream in = getClass().getResourceAsStream("/" + contentPath);
593                                if (in != null)
594                                {
595                                    while ((bytesInBuffer = in.read(buffer)) != -1)
596                                    {
597                                        outJar.write(buffer, 0, bytesInBuffer);
598                                        bytesCopied += bytesInBuffer;
599                                    }
600                                }
601                                else
602                                    Debug.trace("custom data not found: " + contentPath);
603                                outJar.closeEntry();
604
605                            }
606                        }
607                        // Third we write the list into the
608                        // uninstaller.jar
609                        outJar.putNextEntry(new ZipEntry(key));
610                        ObjectOutputStream objOut = new ObjectOutputStream(outJar);
611                        objOut.writeObject(subContents);
612                        objOut.flush();
613                        outJar.closeEntry();
614
615                    }
616                    else
617                    {
618                        outJar.putNextEntry(new ZipEntry(key));
619                        if (contents instanceof ByteArrayOutputStream)
620                        {
621                            ((ByteArrayOutputStream) contents).writeTo(outJar);
622                        }
623                        else
624                        {
625                            ObjectOutputStream objOut = new ObjectOutputStream(outJar);
626                            objOut.writeObject(contents);
627                            objOut.flush();
628                        }
629                        outJar.closeEntry();
630                    }
631                }
632            }
633
634            // Cleanup
635            outJar.flush();
636            outJar.close();
637        }
638        catch (Exception err)
639        {
640            err.printStackTrace();
641        }
642    }
643
644    /**
645     * Gets the stream to a resource.
646     * 
647     * @param res The resource id.
648     * @return The resource value, null if not found
649     */
650    public InputStream getResource(String res) throws Exception
651    {
652        InputStream result;
653        String basePath = "";
654        ResourceManager rm = null;
655
656        try
657        {
658            rm = ResourceManager.getInstance();
659            basePath = rm.resourceBasePath;
660        }
661        catch (Exception e)
662        {
663            e.printStackTrace();
664        }
665
666        result = this.getClass().getResourceAsStream(basePath + res);
667
668        if (result == null) { throw new ResourceNotFoundException("Warning: Resource not found: "
669                + res); }
670        return result;
671    }
672
673    /**
674     * Centers a window on screen.
675     * 
676     * @param frame The window tp center.
677     */
678    public void centerFrame(Window frame)
679    {
680        Dimension frameSize = frame.getSize();
681        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
682        frame.setLocation((screenSize.width - frameSize.width) / 2,
683                (screenSize.height - frameSize.height) / 2 - 10);
684    }
685
686    /**
687     * Returns the panels container size.
688     * 
689     * @return The panels container size.
690     */
691    public Dimension getPanelsContainerSize()
692    {
693        return panelsContainer.getSize();
694    }
695
696    /**
697     * Sets the parameters of a GridBagConstraints object.
698     * 
699     * @param gbc The constraints object.
700     * @param gx The x coordinates.
701     * @param gy The y coordinates.
702     * @param gw The width.
703     * @param wx The x wheight.
704     * @param wy The y wheight.
705     * @param gh Description of the Parameter
706     */
707    public void buildConstraints(GridBagConstraints gbc, int gx, int gy, int gw, int gh, double wx,
708            double wy)
709    {
710        gbc.gridx = gx;
711        gbc.gridy = gy;
712        gbc.gridwidth = gw;
713        gbc.gridheight = gh;
714        gbc.weightx = wx;
715        gbc.weighty = wy;
716    }
717
718    /** Makes a clean closing. */
719    public void exit()
720    {
721        if (installdata.canClose)
722        {
723            // this does nothing if the uninstaller was not included
724            writeUninstallData();
725            Housekeeper.getInstance().shutDown(0);
726        }
727        else
728        {
729            // The installation is not over
730            if (Unpacker.isDiscardInterrupt() && interruptCount < MAX_INTERRUPT)
731            { // But we should not interrupt.
732                interruptCount++;
733                return;
734            }
735            int res = JOptionPane.showConfirmDialog(this, langpack
736                    .getString("installer.quit.message"), langpack
737                    .getString("installer.quit.title"), JOptionPane.YES_NO_OPTION);
738            if (res == JOptionPane.YES_OPTION)
739            {
740                wipeAborted();
741                Housekeeper.getInstance().shutDown(0);
742            }
743        }
744    }
745
746    /** Wipes the written files when you abort the installation. */
747    protected void wipeAborted()
748    {
749        Iterator it;
750
751        // We set interrupt to all running Unpacker and wait 40 sec for maximum.
752        // If interrupt is discarded (return value false), return immediately:
753        if (!Unpacker.interruptAll(40000)) return;
754
755        // Wipes them all in 2 stages
756        UninstallData u = UninstallData.getInstance();
757        it = u.getFilesList().iterator();
758        if (!it.hasNext()) return;
759        while (it.hasNext())
760        {
761            String p = (String) it.next();
762            File f = new File(p);
763            f.delete();
764        }
765        String fullCleanup = installdata.getVariable("InstallerFrame.cleanAllAtInterrupt");
766        if (fullCleanup == null || !fullCleanup.equalsIgnoreCase("no"))
767            cleanWipe(new File(installdata.getInstallPath()));
768    }
769
770    /**
771     * Recursive files wiper.
772     * 
773     * @param file The file to wipe.
774     */
775    private void cleanWipe(File file)
776    {
777        if (file.isDirectory())
778        {
779            File[] files = file.listFiles();
780            int size = files.length;
781            for (int i = 0; i < size; i++)
782                cleanWipe(files[i]);
783        }
784        file.delete();
785    }
786
787    /**
788     * Launches the installation.
789     * 
790     * @param listener The installation listener.
791     */
792    public void install(AbstractUIProgressHandler listener)
793    {
794        Unpacker unpacker = new Unpacker(installdata, listener);
795        unpacker.start();
796    }
797
798    /**
799     * Writes an XML tree.
800     * 
801     * @param root The XML tree to write out.
802     * @param out The stream to write on.
803     * @exception Exception Description of the Exception
804     */
805    public void writeXMLTree(XMLElement root, OutputStream out) throws Exception
806    {
807        XMLWriter writer = new XMLWriter(out);
808        writer.write(root);
809    }
810
811    /**
812     * Changes the quit button text. If <tt>text</tt> is null, the default quit text is used.
813     */
814    public void setQuitButtonText(String text)
815    {
816        if (text == null) text = langpack.getString("installer.quit");
817        quitButton.setText(text);
818    }
819
820    /*
821     * FocusTraversalPolicy objects to handle keybord blocking; the declaration os Object allows to
822     * use a pre version 1.4 VM.
823     */
824    private Object usualFTP = null;
825
826    private Object blockFTP = null;
827
828    /** Blocks GUI interaction. */
829    public void blockGUI()
830    {
831        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
832        getGlassPane().setVisible(true);
833        getGlassPane().setEnabled(true);
834        // No traversal handling before VM version 1.4
835        if (JAVA_SPECIFICATION_VERSION < 1.35) return;
836        if (usualFTP == null) usualFTP = getFocusTraversalPolicy();
837        if (blockFTP == null) blockFTP = new BlockFocusTraversalPolicy();
838        setFocusTraversalPolicy((java.awt.FocusTraversalPolicy) blockFTP);
839        getGlassPane().requestFocus();
840    }
841
842    /** Releases GUI interaction. */
843    public void releaseGUI()
844    {
845        getGlassPane().setEnabled(false);
846        getGlassPane().setVisible(false);
847        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
848        // No traversal handling before VM version 1.4
849        if (JAVA_SPECIFICATION_VERSION < 1.35) return;
850        setFocusTraversalPolicy((java.awt.FocusTraversalPolicy) usualFTP);
851    }
852
853    /** Locks the 'previous' button. */
854    public void lockPrevButton()
855    {
856        prevButton.setEnabled(false);
857    }
858
859    /** Locks the 'next' button. */
860    public void lockNextButton()
861    {
862        nextButton.setEnabled(false);
863    }
864
865    /** Unlocks the 'previous' button. */
866    public void unlockPrevButton()
867    {
868        prevButton.setEnabled(true);
869    }
870
871    /** Unlocks the 'next' button. */
872    public void unlockNextButton()
873    {
874        nextButton.setEnabled(true);
875        nextButton.requestFocus();
876    }
877
878    /** Allows a panel to ask to be skipped. */
879    public void skipPanel()
880    {
881        if (installdata.curPanelNumber < installdata.panels.size() - 1)
882        {
883            if (isBack)
884            {
885                installdata.curPanelNumber--;
886                switchPanel(installdata.curPanelNumber + 1);
887            }
888            else
889            {
890                installdata.curPanelNumber++;
891                switchPanel(installdata.curPanelNumber - 1);
892            }
893
894        }
895    }
896
897    /** This function moves to the next panel */
898    public void navigateNext()
899    {
900        // If the button is inactive this indicates that we cannot move
901        // so we don't do the move
902        if (!nextButton.isEnabled()) return;
903        if ((installdata.curPanelNumber < installdata.panels.size() - 1)
904                && ((IzPanel) installdata.panels.get(installdata.curPanelNumber)).isValidated())
905        {
906            installdata.curPanelNumber++;
907            switchPanel(installdata.curPanelNumber - 1);
908        }
909    }
910
911    /** This function moves to the previous panel */
912    public void navigatePrevious()
913    {
914        // If the button is inactive this indicates that we cannot move
915        // so we don't do the move
916        if (!prevButton.isEnabled()) return;
917        if ((installdata.curPanelNumber > 0))
918        {
919            installdata.curPanelNumber--;
920            switchPanel(installdata.curPanelNumber + 1);
921        }
922    }
923
924    /**
925     * Handles the events from the navigation bar elements.
926     * 
927     * @author Julien Ponge
928     */
929    class NavigationHandler implements ActionListener
930    {
931
932        /**
933         * Actions handler.
934         * 
935         * @param e The event.
936         */
937        public void actionPerformed(ActionEvent e)
938        {
939            Object source = e.getSource();
940            if (source == prevButton)
941            {
942                navigatePrevious();
943            }
944            else if (source == nextButton)
945            {
946                navigateNext();
947            }
948            else if (source == quitButton) exit();
949
950        }
951    }
952
953    /**
954     * The window events handler.
955     * 
956     * @author julien created October 27, 2002
957     */
958        class WindowHandler extends WindowAdapter
959        {
960                /**
961                * Window close is pressed, 
962                * @param  e  The event.
963                */
964                public void windowClosing(WindowEvent e)
965                {
966                        // We ask for confirmation
967                        exit();
968                }
969                
970                /** OLD VERSION
971         * We can't avoid the exit here, so don't call exit anywhere else.
972         * 
973         * @param e The event.
974         
975        public void windowClosing(WindowEvent e)
976        {
977            if (Unpacker.isDiscardInterrupt() && interruptCount < MAX_INTERRUPT)
978            { // But we should not interrupt.
979                interruptCount++;
980                return;
981            }
982            // We show an alert anyway
983            if (!installdata.canClose)
984                JOptionPane.showMessageDialog(null, langpack.getString("installer.quit.message"),
985                        langpack.getString("installer.warning"), JOptionPane.ERROR_MESSAGE);
986            wipeAborted();
987            Housekeeper.getInstance().shutDown(0);
988        }*/
989        }
990
991    /**
992     * A FocusTraversalPolicy that only allows the block panel to have the focus
993     */
994    private class BlockFocusTraversalPolicy extends java.awt.DefaultFocusTraversalPolicy
995    {
996
997        private static final long serialVersionUID = 3258413928261169209L;
998
999        /**
1000         * Only accepts the block panel
1001         * 
1002         * @param aComp the component to check
1003         * @return true if aComp is the block panel
1004         */
1005        protected boolean accept(Component aComp)
1006        {
1007            return aComp == getGlassPane();
1008        }
1009    }
1010}