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}