Index: src/org/openide/WizardDescriptor.java =================================================================== RCS file: /cvs/openide/src/org/openide/WizardDescriptor.java,v retrieving revision 1.77 diff -c -r1.77 WizardDescriptor.java *** src/org/openide/WizardDescriptor.java 29 Jan 2003 01:42:35 -0000 1.77 --- src/org/openide/WizardDescriptor.java 13 Feb 2003 17:02:03 -0000 *************** *** 40,45 **** --- 40,46 ---- import org.openide.awt.HtmlBrowser; import javax.accessibility.*; + import org.openide.DialogDisplayer; import org.openide.util.RequestProcessor; /** Implements a basic "wizard" GUI system. *************** *** 67,77 **** private final JButton cancelButton = new JButton (); private final JButton previousButton = new JButton (); ! private static final ActionListener CLOSE_PREVENTER = new ActionListener () { ! public void actionPerformed (ActionEvent evt) { ! } ! }; ! { // button init ResourceBundle b = NbBundle.getBundle ("org.openide.Bundle"); // NOI18N --- 68,76 ---- private final JButton cancelButton = new JButton (); private final JButton previousButton = new JButton (); ! private ActionListenerImpl buttonListener; ! ! { // button init ResourceBundle b = NbBundle.getBundle ("org.openide.Bundle"); // NOI18N *************** *** 196,202 **** private Iterator panels; /** Change listener that invokes method update state */ ! private Listener listener; /** current panel */ private Panel current; --- 195,201 ---- private Iterator panels; /** Change listener that invokes method update state */ ! private ChangeListenerImpl listener; /** current panel */ private Panel current; *************** *** 212,217 **** --- 211,219 ---- */ private Map properties; + /** Log everything happening in the wizard system. */ + private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.openide.wizards"); // NOI18N + /** Create a new wizard from a fixed list of panels, passing some settings to the panels. * @param wizardPanels the panels to use * @param settings the settings to pass to panels, or null *************** *** 228,235 **** * @see #WizardDescriptor(WizardDescriptor.Iterator, Object) */ public WizardDescriptor (Panel[] wizardPanels) { ! // passing CLOSE_PREVENTER which is treated especially ! this (wizardPanels, CLOSE_PREVENTER); } /** Create wizard for a sequence of panels, passing some settings to the panels. --- 230,236 ---- * @see #WizardDescriptor(WizardDescriptor.Iterator, Object) */ public WizardDescriptor (Panel[] wizardPanels) { ! this (wizardPanels, null); } /** Create wizard for a sequence of panels, passing some settings to the panels. *************** *** 239,253 **** * @see WizardDescriptor.Panel#storeSettings */ public WizardDescriptor (Iterator panels, Object settings) { ! super ("", "", true, DEFAULT_OPTION, null, CLOSE_PREVENTER); // NOI18N ! this.settings = settings == CLOSE_PREVENTER ? this : settings; ! ! listener = new Listener (); ! nextButton.addActionListener (listener); ! previousButton.addActionListener (listener); ! finishButton.addActionListener (listener); ! cancelButton.addActionListener (listener); super.setOptions (new Object[] { previousButton, nextButton, finishButton, cancelButton }); super.setClosingOptions (new Object[] { finishButton, cancelButton }); --- 240,251 ---- * @see WizardDescriptor.Panel#storeSettings */ public WizardDescriptor (Iterator panels, Object settings) { ! super ("", "", true, DEFAULT_OPTION, null, null); // NOI18N ! if (settings == null) { ! this.settings = this; ! } ! listener = new ChangeListenerImpl (); super.setOptions (new Object[] { previousButton, nextButton, finishButton, cancelButton }); super.setClosingOptions (new Object[] { finishButton, cancelButton }); *************** *** 263,270 **** * @param panels iterator over all {@link WizardDescriptor.Panel}s that can appear in the wizard */ public WizardDescriptor (Iterator panels) { ! // passing CLOSE_PREVENTER which is treated especially ! this (panels, CLOSE_PREVENTER); } /** Initializes settings. --- 261,267 ---- * @param panels iterator over all {@link WizardDescriptor.Panel}s that can appear in the wizard */ public WizardDescriptor (Iterator panels) { ! this (panels, null); } /** Initializes settings. *************** *** 275,280 **** --- 272,288 ---- updateState (); } + public ActionListener getButtonListener () { + ActionListener al = super.getButtonListener(); + if (buttonListener == null) { + buttonListener = new ActionListenerImpl(); + } + if (al != null) { + buttonListener.setDelegate(al); + } + return buttonListener; + } + /** Set a different list of panels. * Correctly updates the buttons. * @param panels the new list of {@link WizardDescriptor.Panel}s *************** *** 310,316 **** * @param options the options to set */ public void setClosingOptions (Object[] options) { ! super.setClosingOptions (convertOptions (options)); } /** Converts some options. --- 318,327 ---- * @param options the options to set */ public void setClosingOptions (Object[] options) { ! if (options != null) { ! options = convertOptions(options); ! } ! super.setClosingOptions (options); } /** Converts some options. *************** *** 475,485 **** // nextButton.setVisible (next); // finishButton.setVisible (!next || (current instanceof FinishPanel)); ! if (next) { ! setValue (nextButton); ! } else { ! // setValue (finishButton); ! } setHelpCtx (p.getHelp ()); --- 486,498 ---- // nextButton.setVisible (next); // finishButton.setVisible (!next || (current instanceof FinishPanel)); ! // I'm commenting out this code completely. It fires IMHO useless ! // events whenever there is a change in the state of the wizard ! // if (next) { ! // doSetValue (nextButton); ! // } else { ! // // setValue (finishButton); ! // } setHelpCtx (p.getHelp ()); *************** *** 682,704 **** /** Overrides superclass method. Adds reseting of wizard * for CLOSED_OPTION. */ public void setValue(Object value) { - //Bugfix #25820: Call resetWizard to make sure that storeSettings - //is called before propertyChange. - Object convertedValue = backConvertOption(value); - if (convertedValue == OK_OPTION) { - resetWizard(); - } - super.setValue(backConvertOption(value)); ! // #17360: Reset wizard on CLOSED_OPTION too. if(value == CLOSED_OPTION) { resetWizard(); } } /** Resets wizard when after closed/cancelled/finished the wizard dialog. */ private void resetWizard() { if(current != null) { current.storeSettings (settings); current.removeChangeListener(listener); current = null; --- 695,744 ---- /** Overrides superclass method. Adds reseting of wizard * for CLOSED_OPTION. */ public void setValue(Object value) { ! // WizardDescript handles buttons on its own. ! // This method is called from NbPresenter and ! // apart from CLOSED_OPTION case must be all ! // calls be ignored. if(value == CLOSED_OPTION) { + if (err.isLoggable(ErrorManager.UNKNOWN)) { + err.log("WD.setValue: CLOSED_OPTION received"); //NOI18N + } + doSetValue(value); + } else { + if (err.isLoggable(ErrorManager.UNKNOWN)) { + err.log("WD.setValue: ignoring value. The WD will handle it itself."); //NOI18N + } + } + + } + + /** This is internal implementaiton of setValue which is called + * directly from button handlers in this class. + */ + private void doSetValue(Object value) { + if (err.isLoggable(ErrorManager.UNKNOWN)) { + err.log("WD.doSetValue: value before conversion "+value); //NOI18N + } + if (Arrays.asList(getClosingOptions()).contains(value) || value == CLOSED_OPTION) { resetWizard(); } + + value = backConvertOption(value); + + if (err.isLoggable(ErrorManager.UNKNOWN)) { + err.log("WD.doSetValue: notify listeners with value "+value); //NOI18N + } + super.setValue(value); } + /** Resets wizard when after closed/cancelled/finished the wizard dialog. */ private void resetWizard() { if(current != null) { + if (err.isLoggable(ErrorManager.UNKNOWN)) { + err.log("WD.resetWizard: storeSettings() + removeListeners"); //NOI18N + } current.storeSettings (settings); current.removeChangeListener(listener); current = null; *************** *** 978,992 **** /** Listener to changes in the iterator and panels. */ ! private final class Listener implements ChangeListener, ActionListener { ! Listener() {} /** Change in the observed objects */ public void stateChanged (ChangeEvent ev) { updateState (); } /** Action listener */ public void actionPerformed (ActionEvent ev) { if (ev.getSource () == nextButton) { panels.nextPanel (); try { updateState (); --- 1018,1079 ---- /** Listener to changes in the iterator and panels. */ ! private final class ChangeListenerImpl implements ChangeListener { ! ChangeListenerImpl() {} ! /** Change in the observed objects */ public void stateChanged (ChangeEvent ev) { updateState (); } + } + + /** This is implementation of action listener which checks + * "WizardPanel_errorMessage" property and if it is set it + * shows error message. If it is not set then the next or finish + * buttons are executed. The next button is handled completely + * in WD so there is no problem with it. The problematic is Finish + * button which closes dialog. The solution depends on the implementation + * detail of NbPresenter which (quite logically) calls WD.getButtonListener + * first and notifies it about action and then it checks WD.getClosingOptions + * and if the button is in closing options it will close throws the dialog. The + * trik done here is that if wizard is invalid then Finish is removed from the + * getClosingOptions and vice versa. + */ + private final class ActionListenerImpl implements ActionListener { + + private ActionListener al; + + public ActionListenerImpl() { + } + + public void setDelegate(ActionListener al) { + this.al = al; + } + + private String getErrorMessage() { + return (String)getProperty("WizardPanel_errorMessage"); + } + + private void showErrorMessage() { + DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message( + getErrorMessage(), NotifyDescriptor.ERROR_MESSAGE)); + } + + private void resetErrorMessage() { + putProperty("WizardPanel_errorMessage", null); + } + /** Action listener */ public void actionPerformed (ActionEvent ev) { + + // Next button was pressed if (ev.getSource () == nextButton) { + + if (getErrorMessage() != null) { + showErrorMessage(); + return; + } + panels.nextPanel (); try { updateState (); *************** *** 1004,1029 **** } } if (ev.getSource () == previousButton) { panels.previousPanel (); updateState (); } if (ev.getSource () == finishButton) { ! if (Arrays.asList(getClosingOptions()).contains(finishButton)) { ! resetWizard(); } ! setValue (OK_OPTION); } if (ev.getSource () == cancelButton) { ! if (Arrays.asList(getClosingOptions()).contains(cancelButton)) { ! resetWizard(); } ! setValue (CANCEL_OPTION); } } } /** Listenes on a users client property changes */ --- 1091,1162 ---- } } + // Previous button was pressed if (ev.getSource () == previousButton) { + resetErrorMessage(); panels.previousPanel (); updateState (); } + // Finish button was pressed if (ev.getSource () == finishButton) { ! ! if (getErrorMessage() != null) { ! showErrorMessage(); ! // this is kind of trick. but if Finish button remains there ! // the NbPresenter would dispose this dialog. In order ! // to prevent it I have to temporarily remove Finish ! // button from allowed close options ! removeFinishButtonFromCloseOptions(); ! return; ! } else { ! // add Finish button into close options again ! // if it was removed. ! addFinishButtonToCloseOptions(); ! } ! ! if (err.isLoggable(ErrorManager.UNKNOWN)) { ! err.log("WD.ActionListenerImpl: everything shoul be OK - Finish it"); //NOI18N } ! doSetValue(finishButton); } + // Cancel button was pressed if (ev.getSource () == cancelButton) { ! if (err.isLoggable(ErrorManager.UNKNOWN)) { ! err.log("WD.ActionListenerImpl: Cancel it"); //NOI18N } ! doSetValue(cancelButton); ! } ! ! if (al != null) { ! al.actionPerformed(ev); ! } ! } ! } ! ! private void removeFinishButtonFromCloseOptions() { ! List list = new LinkedList(Arrays.asList(getClosingOptions())); ! if (list.contains(finishButton)) { ! if (err.isLoggable(ErrorManager.UNKNOWN)) { ! err.log("WD.removeFinishButtonFromCloseOptions: Finish button will be removed"); //NOI18N } + list.remove(finishButton); + setClosingOptions(list.toArray(new Object[list.size()])); } } + + private void addFinishButtonToCloseOptions() { + List list = new LinkedList(Arrays.asList(getClosingOptions())); + if (!list.contains(finishButton)) { + if (err.isLoggable(ErrorManager.UNKNOWN)) { + err.log("WD.addFinishButtonToCloseOptions: Finish button will be added"); //NOI18N + } + list.add(finishButton); + setClosingOptions(list.toArray(new Object[list.size()])); + } + } + /** Listenes on a users client property changes */ Index: src/org/openide/loaders/Bundle.properties =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/Bundle.properties,v retrieving revision 1.94 diff -c -r1.94 Bundle.properties *** src/org/openide/loaders/Bundle.properties 13 Jan 2003 17:56:38 -0000 1.94 --- src/org/openide/loaders/Bundle.properties 13 Feb 2003 17:02:03 -0000 *************** *** 197,199 **** --- 197,205 ---- MSG_renameError=This object cannot be renamed from {0} to {1}. MSG_NotValidName=Cannot give {0} an empty name. ERR_NoFilesystem=No enabled filesystem. Make sure that you have at least one filesystem that is not read-only and is not hidden. + + # TemplateWizardPanel2 + MSG_fs_or_folder_does_not_exist=Target filesystem or folder does not exist + MSG_fs_is_readonly=Target filesystem is readonly + # {0} - name of the existing file + MSG_file_already_exist=File {0} already exist \ No newline at end of file Index: src/org/openide/loaders/TemplateWizard2.java =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/TemplateWizard2.java,v retrieving revision 1.51 diff -c -r1.51 TemplateWizard2.java *** src/org/openide/loaders/TemplateWizard2.java 29 Jan 2003 01:42:48 -0000 1.51 --- src/org/openide/loaders/TemplateWizard2.java 13 Feb 2003 17:02:03 -0000 *************** *** 32,37 **** --- 32,38 ---- import org.openide.explorer.propertysheet.PropertyPanel; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; + import org.openide.util.NbBundle; import org.openide.util.Utilities; /** Dialog that can be used in create from template. *************** *** 220,242 **** /** Helper implementation of WizardDescription.Panel for TemplateWizard.Panel2. * Test whether the panel is finished and it is safe to proceed to the next one. * If the panel is valid, the "Next" (or "Finish") button will be enabled. ! * @return true if the user has entered satisfactory information */ ! boolean implIsValid () { ! // test whether the selected folder on selected filesystem already exists FileSystem fs = (FileSystem)fileSystemRef.get (); if (locationFolder == null || fs == null) ! return false; // target filesystem should be writable if (((FileSystem)fileSystemRef.get ()).isReadOnly ()) ! return false; // test whether the selected name already exists StringBuffer sb = new StringBuffer (); sb.append (locationFolder.getPrimaryFile ().getPath ()); ! sb.append (java.io.File.separatorChar); sb.append (newObjectName.getText ()); if ("" != extension) { // NOI18N sb.append ('.'); --- 221,243 ---- /** Helper implementation of WizardDescription.Panel for TemplateWizard.Panel2. * Test whether the panel is finished and it is safe to proceed to the next one. * If the panel is valid, the "Next" (or "Finish") button will be enabled. ! * @return null if the user has entered satisfactory information ! * or localized string describing the error. */ ! String implIsValid () { // test whether the selected folder on selected filesystem already exists FileSystem fs = (FileSystem)fileSystemRef.get (); if (locationFolder == null || fs == null) ! return NbBundle.getMessage(TemplateWizard2.class, "MSG_fs_or_folder_does_not_exist"); // target filesystem should be writable if (((FileSystem)fileSystemRef.get ()).isReadOnly ()) ! return NbBundle.getMessage(TemplateWizard2.class, "MSG_fs_is_readonly"); // test whether the selected name already exists StringBuffer sb = new StringBuffer (); sb.append (locationFolder.getPrimaryFile ().getPath ()); ! sb.append ("/"); sb.append (newObjectName.getText ()); if ("" != extension) { // NOI18N sb.append ('.'); *************** *** 244,254 **** } FileObject f = fs.findResource (sb.toString ()); if (f != null) { ! return false; } ! // all ok ! return true; } /** Gives notification that an attribute or set of attributes changed. --- 245,255 ---- } FileObject f = fs.findResource (sb.toString ()); if (f != null) { ! return NbBundle.getMessage(TemplateWizard2.class, "MSG_file_already_exist", sb.toString()); } ! // all ok ! return null; } /** Gives notification that an attribute or set of attributes changed. Index: src/org/openide/loaders/TemplateWizardPanel2.java =================================================================== RCS file: /cvs/openide/src/org/openide/loaders/TemplateWizardPanel2.java,v retrieving revision 1.2 diff -c -r1.2 TemplateWizardPanel2.java *** src/org/openide/loaders/TemplateWizardPanel2.java 3 Dec 2002 14:11:55 -0000 1.2 --- src/org/openide/loaders/TemplateWizardPanel2.java 13 Feb 2003 17:02:04 -0000 *************** *** 26,31 **** --- 26,33 ---- /** listener to changes in the wizard */ private ChangeListener listener; + private WizardDescriptor settings; + private TemplateWizard2 getPanelUI () { if (templateWizard2UI == null) { templateWizard2UI = new TemplateWizard2 (); *************** *** 82,88 **** public boolean isValid() { if (templateWizard2UI == null) return false; ! return getPanelUI ().implIsValid (); } /** Provides the wizard panel with the current data--either --- 84,97 ---- public boolean isValid() { if (templateWizard2UI == null) return false; ! ! // #28466 - hack to solve this issue. See issues for details. ! // Postpone validation of panel to Next/Finish button handlers. ! // This is temporary solution which must be solved by ! // redesign of templates. It is strongly recommended to ! // NOT USE this property outside of openide/core modules. ! settings.putProperty("WizardPanel_errorMessage", getPanelUI().implIsValid()); ! return true; } /** Provides the wizard panel with the current data--either *************** *** 97,102 **** --- 106,112 ---- * */ public void readSettings(Object settings) { + this.settings = (WizardDescriptor)settings; getPanelUI ().implReadSettings (settings); } *************** *** 116,121 **** --- 126,132 ---- */ public void storeSettings(Object settings) { getPanelUI ().implStoreSettings (settings); + this.settings = null; } }