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 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *     
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020package com.izforge.izpack.uninstaller;
021
022import java.awt.Color;
023import java.awt.Cursor;
024import java.awt.Dimension;
025import java.awt.GridBagConstraints;
026import java.awt.GridBagLayout;
027import java.awt.Insets;
028import java.awt.Toolkit;
029import java.awt.Window;
030import java.awt.event.ActionEvent;
031import java.awt.event.ActionListener;
032import java.awt.event.KeyAdapter;
033import java.awt.event.MouseAdapter;
034import java.awt.event.MouseMotionAdapter;
035import java.awt.event.WindowAdapter;
036import java.awt.event.WindowEvent;
037import java.io.BufferedReader;
038import java.io.InputStream;
039import java.io.InputStreamReader;
040import java.net.URL;
041
042import javax.swing.ImageIcon;
043import javax.swing.JButton;
044import javax.swing.JCheckBox;
045import javax.swing.JFrame;
046import javax.swing.JLabel;
047import javax.swing.JOptionPane;
048import javax.swing.JPanel;
049import javax.swing.JProgressBar;
050import javax.swing.UIManager;
051
052import com.izforge.izpack.LocaleDatabase;
053import com.izforge.izpack.gui.ButtonFactory;
054import com.izforge.izpack.gui.IconsDatabase;
055import com.izforge.izpack.util.AbstractUIHandler;
056
057/**
058 * The uninstaller frame class.
059 * 
060 * @author Julien Ponge
061 */
062public class UninstallerFrame extends JFrame
063{
064
065    /**
066     * 
067     */
068    private static final long serialVersionUID = 3257281444152684850L;
069
070    /** The icons database. */
071    private IconsDatabase icons;
072
073    /** The language pack. */
074    protected static LocaleDatabase langpack;
075
076    /** The warning label. */
077    private JLabel warningLabel;
078
079    /** The target destroy checkbox. */
080    protected JCheckBox targetDestroyCheckbox;
081
082    /** The progress bar. */
083    protected JProgressBar progressBar;
084
085    /** The destroy button. */
086    protected JButton destroyButton;
087
088    /** The quit button. */
089    protected JButton quitButton;
090
091    /** The layout. */
092    private GridBagLayout layout;
093
094    /** the layout constraints. */
095    private GridBagConstraints gbConstraints;
096
097    /** The buttons hover color. */
098    private Color buttonsHColor = new Color(230, 230, 230);
099
100    /** The installation path. */
101    protected String installPath;
102
103    /**
104     * The constructor.
105     * 
106     * @exception Exception Description of the Exception
107     */
108    public UninstallerFrame() throws Exception
109    {
110        super("IzPack - Uninstaller");
111
112        // Initializations
113        langpack = new LocaleDatabase(UninstallerFrame.class.getResourceAsStream("/langpack.xml"));
114        getInstallPath();
115        icons = new IconsDatabase();
116        loadIcons();
117        UIManager.put("OptionPane.yesButtonText", langpack.getString("installer.yes"));
118        UIManager.put("OptionPane.noButtonText", langpack.getString("installer.no"));
119        UIManager.put("OptionPane.cancelButtonText", langpack.getString("installer.cancel"));
120
121        // Sets the frame icon
122        setIconImage(icons.getImageIcon("JFrameIcon").getImage());
123
124        // We build the GUI & show it
125        buildGUI();
126        addWindowListener(new WindowHandler());
127        pack();
128        centerFrame(this);
129        setResizable(false);
130        setVisible(true);
131    }
132
133    /** Builds the GUI. */
134    private void buildGUI()
135    {
136        // We initialize our layout
137        JPanel contentPane = (JPanel) getContentPane();
138        layout = new GridBagLayout();
139        contentPane.setLayout(layout);
140        gbConstraints = new GridBagConstraints();
141        gbConstraints.insets = new Insets(5, 5, 5, 5);
142
143        // We prepare our action handler
144        ActionsHandler handler = new ActionsHandler();
145
146        // Prepares the glass pane to block gui interaction when needed
147        JPanel glassPane = (JPanel) getGlassPane();
148        glassPane.addMouseListener(new MouseAdapter() {});
149        glassPane.addMouseMotionListener(new MouseMotionAdapter() {});
150        glassPane.addKeyListener(new KeyAdapter() {});
151
152        // We set-up the buttons factory
153        ButtonFactory.useButtonIcons();
154        ButtonFactory.useHighlightButtons();
155
156        // We put our components
157
158        warningLabel = new JLabel(langpack.getString("uninstaller.warning"), icons
159                .getImageIcon("warning"), JLabel.TRAILING);
160        buildConstraints(gbConstraints, 0, 0, 2, 1, 1.0, 0.0);
161        gbConstraints.anchor = GridBagConstraints.WEST;
162        gbConstraints.fill = GridBagConstraints.NONE;
163        layout.addLayoutComponent(warningLabel, gbConstraints);
164        contentPane.add(warningLabel);
165
166        targetDestroyCheckbox = new JCheckBox(langpack.getString("uninstaller.destroytarget")
167                + installPath, false);
168        buildConstraints(gbConstraints, 0, 1, 2, 1, 1.0, 0.0);
169        layout.addLayoutComponent(targetDestroyCheckbox, gbConstraints);
170        contentPane.add(targetDestroyCheckbox);
171        gbConstraints.fill = GridBagConstraints.HORIZONTAL;
172
173        progressBar = new JProgressBar();
174        progressBar.setStringPainted(true);
175        progressBar.setString(langpack.getString("InstallPanel.begin"));
176        buildConstraints(gbConstraints, 0, 2, 2, 1, 1.0, 0.0);
177        layout.addLayoutComponent(progressBar, gbConstraints);
178        contentPane.add(progressBar);
179
180        destroyButton = ButtonFactory.createButton(langpack.getString("uninstaller.uninstall"),
181                icons.getImageIcon("delete"), buttonsHColor);
182        destroyButton.addActionListener(handler);
183        buildConstraints(gbConstraints, 0, 3, 1, 1, 0.5, 0.0);
184        gbConstraints.fill = GridBagConstraints.NONE;
185        gbConstraints.anchor = GridBagConstraints.WEST;
186        layout.addLayoutComponent(destroyButton, gbConstraints);
187        contentPane.add(destroyButton);
188
189        quitButton = ButtonFactory.createButton(langpack.getString("installer.quit"), icons
190                .getImageIcon("stop"), buttonsHColor);
191        quitButton.addActionListener(handler);
192        buildConstraints(gbConstraints, 1, 3, 1, 1, 0.5, 0.0);
193        gbConstraints.anchor = GridBagConstraints.EAST;
194        layout.addLayoutComponent(quitButton, gbConstraints);
195        contentPane.add(quitButton);
196
197    }
198
199    /**
200     * Centers a window on screen.
201     * 
202     * @param frame The window to center.
203     */
204    private void centerFrame(Window frame)
205    {
206        Dimension frameSize = frame.getSize();
207        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
208        frame.setLocation((screenSize.width - frameSize.width) / 2,
209                (screenSize.height - frameSize.height) / 2 - 10);
210    }
211
212    /**
213     * Sets the parameters of a GridBagConstraints object.
214     * 
215     * @param gbc The constraints object.
216     * @param gx The x coordinates.
217     * @param gy The y coordinates.
218     * @param gw The width.
219     * @param wx The x wheight.
220     * @param wy The y wheight.
221     * @param gh Description of the Parameter
222     */
223    private void buildConstraints(GridBagConstraints gbc, int gx, int gy, int gw, int gh,
224            double wx, double wy)
225    {
226        gbc.gridx = gx;
227        gbc.gridy = gy;
228        gbc.gridwidth = gw;
229        gbc.gridheight = gh;
230        gbc.weightx = wx;
231        gbc.weighty = wy;
232    }
233
234    /**
235     * Gets the installation path from the log file.
236     * 
237     * @exception Exception Description of the Exception
238     */
239    private void getInstallPath() throws Exception
240    {
241        InputStream in = UninstallerFrame.class.getResourceAsStream("/install.log");
242        InputStreamReader inReader = new InputStreamReader(in);
243        BufferedReader reader = new BufferedReader(inReader);
244        installPath = reader.readLine();
245        reader.close();
246    }
247
248    /**
249     * Loads the icons.
250     * 
251     * @exception Exception Description of the Exception
252     */
253    private void loadIcons() throws Exception
254    {
255        // Initialisations
256        icons = new IconsDatabase();
257        URL url;
258        ImageIcon img;
259
260        // We load it
261        url = UninstallerFrame.class.getResource("/img/trash.png");
262        img = new ImageIcon(url);
263        icons.put("delete", img);
264
265        url = UninstallerFrame.class.getResource("/img/stop.png");
266        img = new ImageIcon(url);
267        icons.put("stop", img);
268
269        url = UninstallerFrame.class.getResource("/img/flag.png");
270        img = new ImageIcon(url);
271        icons.put("warning", img);
272
273        url = UninstallerFrame.class.getResource("/img/JFrameIcon.png");
274        img = new ImageIcon(url);
275        icons.put("JFrameIcon", img);
276    }
277
278    /** Blocks GUI interaction. */
279    public void blockGUI()
280    {
281        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
282        getGlassPane().setVisible(true);
283        getGlassPane().setEnabled(true);
284    }
285
286    /** Releases GUI interaction. */
287    public void releaseGUI()
288    {
289        getGlassPane().setEnabled(false);
290        getGlassPane().setVisible(false);
291        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
292    }
293
294    /**
295     * The window events handler.
296     * 
297     * @author Julien Ponge
298     */
299    private final class WindowHandler extends WindowAdapter
300    {
301
302        /**
303         * We can't avoid the exit here, so don't call exit elsewhere.
304         * 
305         * @param e The event.
306         */
307        public void windowClosing(WindowEvent e)
308        {
309            System.exit(0);
310        }
311    }
312
313    /**
314     * The destroyer handler.
315     * 
316     * This class also implements the InstallListener because the FileExecutor needs it. TODO: get
317     * rid of the InstallListener - implement generic Listener
318     * 
319     * @author Julien Ponge
320     * @author Tino Schwarze
321     */
322    private final class DestroyerHandler implements
323            com.izforge.izpack.util.AbstractUIProgressHandler
324    {
325
326        /**
327         * The destroyer starts.
328         * 
329         * @param name The name of the overall action. Not used here.
330         * @param max The maximum value of the progress.
331         */
332        public void startAction(String name, int max)
333        {
334            progressBar.setMinimum(0);
335            progressBar.setMaximum(max);
336            blockGUI();
337        }
338
339        /** The destroyer stops. */
340        public void stopAction()
341        {
342            progressBar.setString(langpack.getString("InstallPanel.finished"));
343            targetDestroyCheckbox.setEnabled(false);
344            destroyButton.setEnabled(false);
345            releaseGUI();
346        }
347
348        /**
349         * The destroyer progresses.
350         * 
351         * @param pos The actual position.
352         * @param message The message.
353         */
354        public void progress(int pos, String message)
355        {
356            progressBar.setValue(pos);
357            progressBar.setString(message);
358        }
359
360        public void nextStep(String step_name, int step_no, int no_of_substeps)
361        {
362        }
363
364        /**
365         * Output a notification.
366         * 
367         * Does nothing here.
368         * 
369         * @param text
370         */
371        public void emitNotification(String text)
372        {
373        }
374
375        /**
376         * Output a warning.
377         * 
378         * @param text
379         */
380        public boolean emitWarning(String title, String text)
381        {
382            return (JOptionPane.showConfirmDialog(null, text, title, JOptionPane.OK_CANCEL_OPTION,
383                    JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION);
384        }
385
386        /**
387         * The destroyer encountered an error.
388         * 
389         * @param error The error message.
390         */
391        public void emitError(String title, String error)
392        {
393            progressBar.setString(error);
394            JOptionPane.showMessageDialog(null, error, title, JOptionPane.OK_CANCEL_OPTION);
395        }
396
397        /**
398         * Ask the user a question.
399         * 
400         * @param title Message title.
401         * @param question The question.
402         * @param choices The set of choices to present.
403         * 
404         * @return The user's choice.
405         * 
406         * @see AbstractUIHandler#askQuestion(String, String, int)
407         */
408        public int askQuestion(String title, String question, int choices)
409        {
410            return askQuestion(title, question, choices, -1);
411        }
412
413        /**
414         * Ask the user a question.
415         * 
416         * @param title Message title.
417         * @param question The question.
418         * @param choices The set of choices to present.
419         * @param default_choice The default choice. (-1 = no default choice)
420         * 
421         * @return The user's choice.
422         * @see AbstractUIHandler#askQuestion(String, String, int, int)
423         */
424        public int askQuestion(String title, String question, int choices, int default_choice)
425        {
426            int jo_choices = 0;
427
428            if (choices == AbstractUIHandler.CHOICES_YES_NO)
429                jo_choices = JOptionPane.YES_NO_OPTION;
430            else if (choices == AbstractUIHandler.CHOICES_YES_NO_CANCEL)
431                jo_choices = JOptionPane.YES_NO_CANCEL_OPTION;
432
433            int user_choice = JOptionPane.showConfirmDialog(null, (Object) question, title,
434                    jo_choices, JOptionPane.QUESTION_MESSAGE);
435
436            if (user_choice == JOptionPane.CANCEL_OPTION) return AbstractUIHandler.ANSWER_CANCEL;
437
438            if (user_choice == JOptionPane.YES_OPTION) return AbstractUIHandler.ANSWER_YES;
439
440            if (user_choice == JOptionPane.NO_OPTION) return AbstractUIHandler.ANSWER_NO;
441
442            return default_choice;
443        }
444
445    }
446
447    /**
448     * The actions events handler.
449     * 
450     * @author Julien Ponge
451     */
452    class ActionsHandler implements ActionListener
453    {
454
455        /**
456         * Action handling method.
457         * 
458         * @param e The event.
459         */
460        public void actionPerformed(ActionEvent e)
461        {
462            Object src = e.getSource();
463            if (src == quitButton)
464                System.exit(0);
465            else if (src == destroyButton)
466            {
467                Destroyer destroyer = new Destroyer(installPath,
468                        targetDestroyCheckbox.isSelected(), new DestroyerHandler());
469                destroyer.start();
470            }
471        }
472    }
473
474    /**
475     * Returns the langpack.
476     * 
477     * @return Returns the langpack.
478     */
479    public static LocaleDatabase getLangpack()
480    {
481        return langpack;
482    }
483
484}