/* * $Id$ * * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.interview.wizard; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Frame; import java.awt.Insets; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Properties; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSplitPane; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.UIManager; import javax.swing.WindowConstants; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.filechooser.FileFilter; import com.sun.interview.Interview; import com.sun.interview.Question; import com.sun.interview.WizPrint; import com.sun.javatest.tool.jthelp.HelpBroker; import com.sun.javatest.tool.jthelp.HelpSet; import com.sun.javatest.tool.jthelp.JTHelpBroker; /** * A wizard to present an {@link Interview interview} consisting of * a series of {@link Question questions}. * *

The tool can be started as an application itself, * by using the {@link #main main} * method. This requires that the class name of the interview * be supplied as the first argument; the class itself must be on * the tool's class path. This technique allows any interview * to be run by this tool. *

An alternative technique is to provide a small default main method * inside each interview, which creates an instance of the interview * and starts up a tool such as this one to run the interview. *

 *    import javasoft.sqe.wizard.Interview;
 *    import javasoft.sqe.wizard.swing.Wizard;
 *
 *    public class Demo extends Interview {
 *        public static void main(String[] args) {
 *          Demo d = new Demo();
 *          Wizard w = new Wizard(d);
 *          w.showInFrame(true);
 *        }
 *    }
 *
*/ public class Wizard extends JComponent { /** * A minimal main program to invoke the wizard on a specified interview. * @param args Only one argument is accepted: the name of a class which is * a subtype of {@link Interview}. */ public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); Class ic = Class.forName(args[0], true, ClassLoader.getSystemClassLoader()); Interview i = (Interview)(ic.newInstance()); Wizard w = new Wizard(i); w.showInFrame(true); } catch (Throwable e) { e.printStackTrace(); System.exit(1); } } /** * Create a wizard to present an interview. * @param i The interview to be presented. */ public Wizard(Interview i) { this(i, null); } /** * Create a wizard to present an interview. * @param i The interview to be presented. * @param e An array of exporters to which the interview can be exported. */ public Wizard(Interview i, Exporter[] e) { interview = i; exporters = e; } /** * Open a file and load it into the interview for this wizard. * This does not affect the name of the current file. * @param f The file to be loaded. * @throws IOException if any problems occur while reading the file. * @throws Interview.Fault if the checksum is missing or incorrect in the file * @see Interview#load * @see #setFile */ public void open(File f) throws Interview.Fault, IOException { try (InputStream in = new BufferedInputStream(new FileInputStream(f))) { Map stringProps = com.sun.javatest.util.Properties.load(in); interview.load(stringProps); interview.setEdited(false); String info = stringProps.get("INFO"); if (info == null) { info = "true"; } initialInfoVisible = info.equals("true"); } } /** * Save the current responses to the interview's questions in a file.. * @param f The file in which to save the responses. * @throws IOException if any problems occur while reading the file. * @see Interview#save */ public void save(File f) throws IOException { try (OutputStream out = new BufferedOutputStream(new FileOutputStream(f))) { Properties p = new Properties(); if (infoPanel != null) p.put("INFO", String.valueOf(infoPanel.isShowing())); interview.save(com.sun.javatest.util.Properties.convertToStringProps(p)); interview.setEdited(false); p.save(out, "Wizard data file: " + interview.getTitle()); } } /** * Get the name of the current file associated with this interview. * @return the file for the interview * @see #setFile */ public File getFile() { return currFile; } /** * Set the name of the current file associated with this interview. * The file may be used as a default in open/save operations. * @param f The file to be associated with this interview. * @see #getFile * @see #setDefaultFile */ public void setFile(File f) { currFile = new File(f.getAbsolutePath()); if (window != null) updateTitle(window); } /** * Set the name of a default file associated with this interview. * The default file is used for the name of the current value * if the user performs a File>New operation. In addition, if the * default file is set, and the current file matches the default file, * it will not be shown in the title bar. * @param f The default file to be associated with this interview. */ public void setDefaultFile(File f) { defaultFile = f; if (window != null) updateTitle(window); } /** * Set the help broker in which context sensitive help and default menu help * is displayed. If not set, a default help broker will be created. * @param helpBroker The help broker to use for context sensitive and menu help. */ public void setHelpBroker(HelpBroker helpBroker) { helpHelpBroker = helpBroker; } /** * Set the help set to be used for context sensitive help and the default menu help. * If not set, the interview's help set will be used. * @param helpSet The help set to use for context sensitive and menu help. * */ public void setHelpSet(HelpSet helpSet) { helpHelpSet = helpSet; } /** * Set the prefix string for the help IDs for context sensitive help and default menu help. * If not set, the default is "wizard.". * @param helpPrefix A prefix to be used for all context sentive help and menu entries. */ public void setHelpSetPrefix(String helpPrefix) { helpHelpPrefix = helpPrefix; } /** * Set the help menu to be used on the wizard. If not set, the default is a menu * containing a single "Help" entry. * @param helpMenu The help menu to be used. */ public void setHelpMenu(JMenu helpMenu) { this.helpMenu = helpMenu; } /** * Show the wizard in a frame centered on the screen. * @param exitOnClose Set to true if the JVM should be exited when the frame is closed. */ public void showInFrame(final boolean exitOnClose) { if (window != null && !(window instanceof JFrame)) throw new IllegalStateException(); if (!EventQueue.isDispatchThread()) { EventQueue.invokeLater(new Runnable() { public void run() { showInFrame(exitOnClose); } }); return; } initGUI(); okBtn.setVisible(false); cancelBtn.setVisible(false); final JFrame f = new JFrame(); initMenuBar(f); updateTitle(f); f.setName("interview.wizard"); f.setJMenuBar(menuBar); f.setContentPane(main); f.pack(); f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { if (interview.isEdited() && !okToContinue()) return; e.getWindow().dispose(); } public void windowClosed(WindowEvent e) { if (exitOnClose) System.exit(0); } }); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension size = f.getSize(); f.setLocation(screenSize.width/2 - size.width/2, screenSize.height/2 - size.height/2); f.show(); window = f; } /** * Action command for the okListener for {@link #showInDialog}. */ public static final String OK = "OK"; /** * Show the wizard in a dialog. * @param parent The parent frame for this dialog. * @param okListener A listener to e notified when the dialog is dismissed. */ public void showInDialog(final Frame parent, final ActionListener okListener) { if (window != null && !(window instanceof JDialog)) throw new IllegalStateException(); if (!EventQueue.isDispatchThread()) { EventQueue.invokeLater(new Runnable() { public void run() { showInDialog(parent, okListener); } }); return; } this.okListener = okListener; initGUI(); okBtn.setVisible(true); okBtn.setEnabled(interview.isFinishable()); cancelBtn.setVisible(true); final JDialog d = new JDialog(parent); initMenuBar(d); updateTitle(d); d.setJMenuBar(menuBar); d.setContentPane(main); d.pack(); d.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); d.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { if (!interview.isEdited() || okToContinue()) e.getWindow().dispose(); } public void windowClosed(WindowEvent e) { } }); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension size = d.getSize(); d.setLocation(screenSize.width/2 - size.width/2, screenSize.height/2 - size.height/2); d.show(); window = d; } /** * Check if this object is being displayed on the screen. * @return true if the wizard is currently being displayed, * and false otherwise. */ public boolean isShowing() { return (window != null && window.isShowing()); } /** * Ensure that this object is showing in front of all other windows * on the screen. If the object is not currently visible, the call * has no effect. */ public void toFront() { if (window != null) window.toFront(); } /** * Initialize the frame's GUI components */ private void initGUI() { title = interview.getTitle(); if (title == null || title.equals("")) title = i18n.getString("wizard.defaultTitle"); //main = new JPanel(new BorderLayout()); setLayout(new BorderLayout()); main = this; questionPanel = new QuestionPanel(interview); questionPanel.setBorder(BorderFactory.createLoweredBevelBorder()); pathPanel = new PathPanel(questionPanel, interview); if (interview.getHelpSet() != null) infoPanel = new InfoPanel(interview); buttonPanel = new JToolBar(); buttonPanel.setFloatable(false); //buttonPanel.setBorder(BorderFactory.createRaisedBevelBorder()); buttonPanel.add(Box.createHorizontalGlue()); backBtn = createButton("back", "performBack", performer); buttonPanel.add(backBtn); nextBtn = createButton("next", "performNext", performer); buttonPanel.add(nextBtn); buttonPanel.addSeparator(); okBtn = createButton("ok", "performOk", performer); buttonPanel.add(okBtn); cancelBtn = createButton("cancel", "performCancel", performer); buttonPanel.add(cancelBtn); if (infoPanel != null) { buttonPanel.addSeparator(); infoBtn = createToggle("info", "performInfo", performer); infoBtn.setSelected(initialInfoVisible); buttonPanel.add(infoBtn); } buttonPanel.addAncestorListener(new Listener()); body = new JPanel(new BorderLayout()); body.add(pathPanel, BorderLayout.WEST); body.add(questionPanel, BorderLayout.CENTER); body.add(buttonPanel, BorderLayout.SOUTH); body.registerKeyboardAction(performer, "performFindNext", KeyStroke.getKeyStroke("F3"), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); if (helpHelpPrefix == null) helpHelpPrefix = "wizard."; if (helpHelpSet == null && infoPanel != null) helpHelpSet = infoPanel.getHelpSet(); if (helpHelpBroker == null && helpHelpSet != null) helpHelpBroker = new JTHelpBroker(); if (helpHelpBroker != null && helpHelpSet != null) helpHelpBroker.enableHelpKey(main, helpHelpPrefix + "window.csh"); if (infoPanel == null) main.add(body); else update(infoBtn.isSelected()); } private void initMenuBar(Window w) { menuBar = new JMenuBar(); fileMenu = createMenu("file", fileMenuData, performer); if (w instanceof JFrame) { fileMenu.addSeparator(); fileMenu.add(createMenuItem("file", "exit", "performExit", performer)); } else { fileMenu.addSeparator(); fileMenu.add(createMenuItem("file", "close", "performCancel", performer)); } if (exporters != null) { // replace the default "export log" item with a full export submenu for (int i = 0; i < fileMenu.getItemCount(); i++) { JMenuItem mi = fileMenu.getItem(i); if (mi != null && mi.getActionCommand().equals("performExportLog")) { fileMenu.remove(i); JMenu exportMenu = new ExportMenu(exporters); exportMenu.add(createMenuItem("export", "log", "performExportLog", performer)); fileMenu.insert(exportMenu, i); break; } } } menuBar.add(fileMenu); JMenu searchMenu = createMenu("search", searchMenuData, performer); menuBar.add(searchMenu); if (helpHelpBroker != null) { if (helpMenu == null) helpMenu = createMenu("help", helpMenuData, performer); menuBar.add(helpMenu); } } private void update(boolean showInfoPanel) { Dimension bodySize = body.getSize(); if (bodySize.width == 0) bodySize = body.getPreferredSize(); Dimension infoSize = infoPanel.getSize(); if (infoSize.width == 0) infoSize = infoPanel.getPreferredSize(); // need to capture the next value before we remove everything from main boolean infoPanelIsShowing = infoPanel.isShowing(); main.removeAll(); if (showInfoPanel) { // body-help JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, body, infoPanel); sp.setDividerLocation(bodySize.width + 2); main.add(sp); infoPanel.setCurrentID(interview.getCurrentQuestion()); } else { // body main.add(body); } if (window != null) { int divWidth = new JSplitPane().getDividerSize(); Dimension winSize = window.getSize(); int newWidth = winSize.width; if (showInfoPanel != infoPanelIsShowing) newWidth += (showInfoPanel ? +1 : -1) * (infoSize.width + divWidth + 4); window.setSize(newWidth, winSize.height); } if (infoBtn.isSelected() != showInfoPanel) infoBtn.setSelected(showInfoPanel); } private void updateTitle(Window w) { String t; if (currFile == null || (defaultFile != null && currFile.equals(defaultFile))) t = title; else t = i18n.getString("wizard.titleAndFile", new Object[] {title, currFile.getPath()}); if (w instanceof JFrame) ((JFrame) w).setTitle(t); else ((JDialog) w).setTitle(t); } /** * Invoke a performXXX method via reflection * @param s The name of the method to be invoked. */ private void perform(String s) { try { Method m = Wizard.class.getDeclaredMethod(s, new Class[] { }); m.invoke(Wizard.this, new Object[] { }); } catch (IllegalAccessException ex) { System.err.println(s); ex.printStackTrace(); } catch (InvocationTargetException ex) { System.err.println(s); ex.getTargetException().printStackTrace(); } catch (NoSuchMethodException ex) { System.err.println(s); } } /** * Handle the "back" action */ private void performBack() { try { questionPanel.saveCurrentResponse(); interview.prev(); } catch (Interview.Fault e) { // exception normally means no more questions // e.printStackTrace(); } catch (RuntimeException e) { // typically NumberFormatError // SEE ALSO QuestionPanel.showInetAddressQuestion // which wants to throw Interview.Fault from // the value saver, but can't questionPanel.getToolkit().beep(); } } /** * Handle the "cancel" action */ private void performCancel() { questionPanel.saveCurrentResponse(); if (interview.isEdited() && !okToContinue()) return; window.dispose(); } /** * Handle the "exit" action */ private void performExit() { questionPanel.saveCurrentResponse(); if (interview.isEdited() && !okToContinue()) return; // setVisible(false); System.exit(0); // uugh } /** * Handle the "exportLog" action */ private void performExportLog() { questionPanel.saveCurrentResponse(); JFileChooser chooser = new JFileChooser(); if (currFile != null) { // setCurrentDirectory required chooser.setCurrentDirectory(new File(currFile.getParent())); int dot = currFile.getName().lastIndexOf("."); if (dot != -1) { File f = new File(currFile.getName().substring(0, dot) + ".html"); chooser.setSelectedFile(f); } } else { chooser.setCurrentDirectory(getUserDir()); } chooser.setFileFilter(htmlFilter); //chooser.addChoosableFileFilter(txtFilter); int action = chooser.showDialog(main, i18n.getString("wizard.exportLog")); if (action != JFileChooser.APPROVE_OPTION) return; File f = ensureExtn(chooser.getSelectedFile(), ".html"); if (f.exists() && !okToOverwrite(f)) return; try { Writer out = new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8); WizPrint w = new WizPrint(interview, interview.getPath()); w.setShowResponses(true); w.write(out); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.fileNotFound.txt", e.getMessage()), i18n.getString("wizard.fileNotFound.title"), JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.badFile.txt", e.getMessage()), i18n.getString("wizard.badFile.title"), JOptionPane.ERROR_MESSAGE); } } /** * Handle the "find" action */ private void performFind() { if (searchDialog == null) searchDialog = SearchDialog.create(window, interview, helpHelpBroker, helpHelpPrefix); searchDialog.setVisible(true); } /** * Handle the "find" action */ private void performFindNext() { if (searchDialog == null) searchDialog = SearchDialog.create(window, interview, helpHelpBroker, helpHelpPrefix); searchDialog.find(); } /** * Handle the "help" action */ private void performHelp() { helpHelpBroker.displayCurrentID(helpHelpPrefix + "intro.csh"); } /** * Handle the "info" action */ private void performInfo() { boolean infoOn = infoBtn.isSelected(); if (infoPanel.isShowing() != infoOn) { update(infoOn); window.validate(); } } /** * Handle the "new" action */ private void performNew() { questionPanel.saveCurrentResponse(); if (interview.isEdited() && !okToContinue()) return; interview.clear(); interview.setEdited(false); setFile(defaultFile); } /** * Handle the "next" action */ private void performNext() { try { questionPanel.saveCurrentResponse(); interview.next(); } catch (Interview.Fault e) { // exception normally means no more questions // e.printStackTrace(); questionPanel.getToolkit().beep(); } catch (RuntimeException e) { // typically NumberFormatError questionPanel.getToolkit().beep(); } } /** * Handle the "ok" action */ private void performOk() { try { questionPanel.saveCurrentResponse(); window.dispose(); okListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, OK)); } catch (RuntimeException e) { // typically NumberFormatError questionPanel.getToolkit().beep(); } } /** * Handle the "open" action */ private void performOpen() { questionPanel.saveCurrentResponse(); if (interview.isEdited() && !okToContinue()) return; JFileChooser chooser = new JFileChooser(); // set current directory from file or user.dir if (currFile != null) { // setCurrentDirectory required chooser.setCurrentDirectory(new File(currFile.getParent())); chooser.setSelectedFile(new File(currFile.getName())); } else { chooser.setCurrentDirectory(getUserDir()); } chooser.setFileFilter(jtiFilter); int action = chooser.showOpenDialog(main); if (action != JFileChooser.APPROVE_OPTION) return; File f = ensureExtn(chooser.getSelectedFile(), ".jti"); try { open(f); setFile(f); } catch (Interview.Fault e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.badInterview.txt", e.getMessage()), i18n.getString("wizard.badInterview.title"), JOptionPane.ERROR_MESSAGE); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.fileNotFound.txt", e.getMessage()), i18n.getString("wizard.fileNotFound.title"), JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.badFile.txt", e.getMessage()), i18n.getString("wizard.badFile.title"), JOptionPane.ERROR_MESSAGE); } } /** * Handle the "save" action */ private void performSave() { questionPanel.saveCurrentResponse(); // save with current file if (currFile == null) performSaveAs(); else performSaveInternal(currFile); } /** * Handle the "save as" action */ private void performSaveAs() { questionPanel.saveCurrentResponse(); JFileChooser chooser = new JFileChooser(); if (currFile != null) { // setCurrentDirectory required chooser.setCurrentDirectory(new File(currFile.getParent())); chooser.setSelectedFile(new File(currFile.getName())); } else { chooser.setCurrentDirectory(getUserDir()); } chooser.setFileFilter(jtiFilter); int action = chooser.showSaveDialog(main); if (action != JFileChooser.APPROVE_OPTION) return; File f = ensureExtn(chooser.getSelectedFile(), ".jti"); if (f.exists() && !okToOverwrite(f)) return; performSaveInternal(f); } /** * Internal common routine for the save/saveAs actions */ private void performSaveInternal(File f) { try { save(f); setFile(f); } catch (FileNotFoundException e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.fileNotFound.txt", e.getMessage()), i18n.getString("wizard.fileNotFound.title"), JOptionPane.ERROR_MESSAGE); } catch (IOException e) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.badFile.txt", e.getMessage()), i18n.getString("wizard.badFile.title"), JOptionPane.ERROR_MESSAGE); } } /** * Get the user's current directory */ private File getUserDir() { return new File(System.getProperty("user.dir")); } private JButton createButton(String uiKey, String actionCommand, ActionListener l) { JButton b = new JButton(createIcon(uiKey)); b.setToolTipText(i18n.getString("wizard." + uiKey + ".tip")); b.setActionCommand(actionCommand); b.addActionListener(l); b.registerKeyboardAction(l, actionCommand, enterKey, JComponent.WHEN_FOCUSED); return b; } private Icon createIcon(String uiKey) { String iconResource = i18n.getString("wizard." + uiKey + ".icon"); URL url = getClass().getResource(iconResource); return (url == null ? null : new ImageIcon(url)); } /** * Create a menu according to an array of data * @title the title for the menu * @menuData the data for the menu; one element per menu item; an element can be * one of *
*
null *
a separator *
an array of two strings *
a menu item, whose name is the first string, and whose action is the second *
*/ private JMenu createMenu(String uiKey, String[][] menuData, ActionListener l) { JMenu m = new JMenu(i18n.getString("wizard." + uiKey + ".menu")); m.setName("wizard." + uiKey); m.setMnemonic(i18n.getString("wizard." + uiKey + ".mne").charAt(0)); for (int i = 0; i < menuData.length; i++) { String[] data = menuData[i]; if (data == null) m.addSeparator(); else { JMenuItem mi = createMenuItem(uiKey, data[0], data[1], l); if (data.length > 2) { KeyStroke accel = KeyStroke.getKeyStroke(data[2]); mi.setAccelerator(accel); } m.add(mi); } } return m; } private JMenuItem createMenuItem(String uiKey, String name, String actionCommand, ActionListener l) { JMenuItem item = new JMenuItem(i18n.getString("wizard." + uiKey + "." + name + ".mit")); item.setName(name); item.setMnemonic(i18n.getString("wizard." + uiKey + "." + name + ".mne").charAt(0)); item.setActionCommand(actionCommand); item.addActionListener(l); return item; } private JToggleButton createToggle(String uiKey, String actionCommand, ActionListener l) { JToggleButton b = new JToggleButton(createIcon(uiKey)) { public Insets getInsets() { return (nextBtn == null ? super.getInsets() : nextBtn.getInsets()); // !! } }; b.setToolTipText(i18n.getString("wizard." + uiKey + ".tip")); b.setActionCommand(actionCommand); b.addActionListener(l); b.registerKeyboardAction(l, actionCommand, enterKey, JComponent.WHEN_FOCUSED); return b; } private File ensureExtn(File f, String extn) { if (f.getName().endsWith(extn)) return f; else return new File(f.getPath() + extn); } private boolean okToContinue() { int response = JOptionPane.showConfirmDialog(main, i18n.getString("wizard.unsavedAnswers.txt"), i18n.getString("wizard.unsavedAnswers.title"), JOptionPane.YES_NO_OPTION); return (response == JOptionPane.YES_OPTION); } private boolean okToOverwrite(File f) { int response = JOptionPane.showConfirmDialog(main, i18n.getString("wizard.overwrite.txt", f), i18n.getString("wizard.overwrite.title"), JOptionPane.YES_NO_OPTION); return (response == JOptionPane.YES_OPTION); } private ActionListener performer = new ActionListener() { public void actionPerformed(ActionEvent e) { perform(e.getActionCommand()); } }; private Interview interview; private Exporter[] exporters; private String title; private JMenuBar menuBar; private JMenu fileMenu; //private JPanel main; private JComponent main; private JPanel body; private PathPanel pathPanel; private QuestionPanel questionPanel; private InfoPanel infoPanel; private JToolBar buttonPanel; private JButton cancelBtn; private JButton backBtn; private JButton nextBtn; private JButton okBtn; private JToggleButton infoBtn; private Window window; private ActionListener okListener; private SearchDialog searchDialog; private boolean initialInfoVisible = true; private Listener listener = new Listener(); // help for Help menu and context sensitive help (F1) private HelpSet helpHelpSet; private HelpBroker helpHelpBroker; private String helpHelpPrefix; private JMenu helpMenu; private File currFile; private File defaultFile; private boolean exitOnClose; private final FileFilter jtiFilter = new ExtensionFileFilter(".jti"); private final FileFilter htmlFilter = new ExtensionFileFilter(new String[] {".htm", ".html"}); private static final KeyStroke enterKey = KeyStroke.getKeyStroke("ENTER"); private static final I18NResourceBundle i18n = I18NResourceBundle.getDefaultBundle(); private static final String[][] fileMenuData = { {"new", "performNew"}, {"open", "performOpen"}, {"save", "performSave"}, {"saveAs", "performSaveAs"}, null, {"exportLog", "performExportLog"} }; private static final String[][] helpMenuData = { {"help", "performHelp", "F1"} }; private static final String[][] searchMenuData = { {"find", "performFind", "control F"}, {"findNext", "performFindNext", "F3"}, }; private class ExtensionFileFilter extends FileFilter { ExtensionFileFilter(String extn) { this.extns = new String[] {extn}; } ExtensionFileFilter(String[] extns) { this.extns = extns; } ExtensionFileFilter(String[] extns, String description) { this.extns = extns; this.description = description; } public boolean accept(File f) { if (f.isDirectory()) return true; for (int i = 0; i < extns.length; i++) if (f.getName().endsWith(extns[i])) return true; return false; } public String getDescription() { if (description == null) { StringBuffer sb = new StringBuffer("wizard.extn"); if (extns.length == 0) sb.append(".allFiles"); else { for (int i = 0; i < extns.length; i++) sb.append(extns[i]); } description = i18n.getString(sb.toString()); } return description; } private String[] extns; private String description; } private class ExportMenu extends JMenu implements ActionListener, PopupMenuListener { ExportMenu(Exporter[] exporters) { super(i18n.getString("wizard.export.menu")); setName("export"); setMnemonic(i18n.getString("wizard.export.mne").charAt(0)); for (int i = 0; i < exporters.length; i++) { JMenuItem mi = new JMenuItem(exporters[i].getName()); mi.putClientProperty("exporter", exporters[i]); mi.setActionCommand("performGenericExport"); mi.addActionListener(this); add(mi); } getPopupMenu().addPopupMenuListener(this); } public void actionPerformed(ActionEvent ev) { questionPanel.saveCurrentResponse(); JMenuItem mi = (JMenuItem)(ev.getSource()); Exporter e = (Exporter)(mi.getClientProperty("exporter")); export(e); } public void popupMenuCanceled(PopupMenuEvent e) { } public void popupMenuWillBecomeInvisible(PopupMenuEvent ev) { } public void popupMenuWillBecomeVisible(PopupMenuEvent ev) { JPopupMenu m = (JPopupMenu)(ev.getSource()); for (int i = 0; i < m.getComponentCount(); i++) { JMenuItem mi = (JMenuItem)(m.getComponent(i)); if (mi != null) { Exporter e = (Exporter)(mi.getClientProperty("exporter")); if (e != null) mi.setEnabled(e.isExportable()); } } } private void export(Exporter e) { JFileChooser exportChooser = new JFileChooser(); if (currFile != null) { // setCurrentDirectory required exportChooser.setCurrentDirectory(new File(currFile.getParent())); String[] extns = e.getFileExtensions(); int dot = currFile.getName().lastIndexOf("."); if (dot != -1 && extns != null && extns.length > 0) { File f = new File(currFile.getName().substring(0, dot) + extns[0]); exportChooser.setSelectedFile(f); } } else { exportChooser.setCurrentDirectory(getUserDir()); } exportChooser.setApproveButtonText(i18n.getString("wizard.exportChooser.export")); String[] extns = e.getFileExtensions(); String desc = e.getFileDescription(); exportChooser.setFileFilter(new ExtensionFileFilter(extns, desc)); int action = exportChooser.showSaveDialog(main); if (action != JFileChooser.APPROVE_OPTION) return; try { File f = ensureExtn(exportChooser.getSelectedFile(), extns[0]); if (f.exists() && !okToOverwrite(f)) return; e.export(f); } catch (IOException ex) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.exportError.txt", ex.getMessage()), i18n.getString("wizard.exportError.title"), JOptionPane.ERROR_MESSAGE); } catch (Interview.Fault ex) { JOptionPane.showMessageDialog(main, i18n.getString("wizard.exportError.txt", ex.getMessage()), i18n.getString("wizard.exportError.title"), JOptionPane.ERROR_MESSAGE); } } } private class Listener implements AncestorListener, Interview.Observer { // ---------- from AncestorListener ----------- public void ancestorAdded(AncestorEvent e) { interview.addObserver(this); pathUpdated(); currentQuestionChanged(interview.getCurrentQuestion()); } public void ancestorMoved(AncestorEvent e) { } public void ancestorRemoved(AncestorEvent e) { interview.removeObserver(this); } //----- from Interview.Observer ----------- public void pathUpdated() { okBtn.setEnabled(interview.isFinishable()); } public void currentQuestionChanged(Question q) { backBtn.setEnabled(!interview.isFirst(q)); nextBtn.setEnabled(!interview.isLast(q)); } } }