001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.mercurial.ui.wizards;
042:
043: import java.io.File;
044: import java.util.Set;
045: import java.util.HashSet;
046: import java.util.Iterator;
047: import java.awt.Component;
048: import javax.swing.event.ChangeEvent;
049: import javax.swing.event.ChangeListener;
050: import javax.swing.SwingUtilities;
051: import javax.swing.event.DocumentEvent;
052: import javax.swing.event.DocumentListener;
053: import org.openide.WizardDescriptor;
054: import org.openide.util.HelpCtx;
055:
056: public class CloneDestinationDirectoryWizardPanel implements
057: WizardDescriptor.Panel, DocumentListener {
058:
059: /**
060: * The visual component that displays this panel. If you need to access the
061: * component from this class, just use getComponent().
062: */
063: private CloneDestinationDirectoryPanel component;
064: private boolean valid;
065: private String errorMessage;
066:
067: // Get the visual component for the panel. In this template, the component
068: // is kept separate. This can be more efficient: if the wizard is created
069: // but never displayed, or not all panels are displayed, it is better to
070: // create only those which really need to be visible.
071: public Component getComponent() {
072: if (component == null) {
073: component = new CloneDestinationDirectoryPanel();
074: component.directoryField.getDocument().addDocumentListener(
075: this );
076: component.nameField.getDocument().addDocumentListener(this );
077: valid();
078: }
079: return component;
080: }
081:
082: public HelpCtx getHelp() {
083: return new HelpCtx(CloneDestinationDirectoryWizardPanel.class);
084: }
085:
086: //public boolean isValid() {
087: // If it is always OK to press Next or Finish, then:
088: //return true;
089: // If it depends on some condition (form filled out...), then:
090: // return someCondition();
091: // and when this condition changes (last form field filled in...) then:
092: // fireChangeEvent();
093: // and uncomment the complicated stuff below.
094: //}
095:
096: public void insertUpdate(DocumentEvent e) {
097: textChanged(e);
098: }
099:
100: public void removeUpdate(DocumentEvent e) {
101: textChanged(e);
102: }
103:
104: public void changedUpdate(DocumentEvent e) {
105: textChanged(e);
106: }
107:
108: private void textChanged(final DocumentEvent e) {
109: // repost later to AWT otherwise it can deadlock because
110: // the document is locked while firing event and we try
111: // synchronously access its content
112: Runnable awt = new Runnable() {
113: public void run() {
114: if (e.getDocument() == component.nameField
115: .getDocument()
116: || e.getDocument() == component.directoryField
117: .getDocument()) {
118: if (component.isValid()) {
119: valid(component.getMessage());
120: } else {
121: invalid(component.getMessage());
122: }
123: }
124: }
125: };
126: SwingUtilities.invokeLater(awt);
127: }
128:
129: private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(
130: 1); // or can use ChangeSupport in NB 6.0
131:
132: public final void addChangeListener(ChangeListener l) {
133: synchronized (listeners) {
134: listeners.add(l);
135: }
136: }
137:
138: public final void removeChangeListener(ChangeListener l) {
139: synchronized (listeners) {
140: listeners.remove(l);
141: }
142: }
143:
144: protected final void fireChangeEvent() {
145: Iterator<ChangeListener> it;
146: synchronized (listeners) {
147: it = new HashSet<ChangeListener>(listeners).iterator();
148: }
149: ChangeEvent ev = new ChangeEvent(this );
150: while (it.hasNext()) {
151: it.next().stateChanged(ev);
152: }
153: }
154:
155: protected final void valid() {
156: setValid(true, null);
157: }
158:
159: protected final void valid(String extErrorMessage) {
160: setValid(true, extErrorMessage);
161: }
162:
163: protected final void invalid(String message) {
164: setValid(false, message);
165: }
166:
167: public final boolean isValid() {
168: return valid;
169: }
170:
171: public final String getErrorMessage() {
172: return errorMessage;
173: }
174:
175: private void setValid(boolean valid, String errorMessage) {
176: boolean fire = this .valid != valid;
177: fire |= errorMessage != null
178: && (errorMessage.equals(this .errorMessage) == false);
179: this .valid = valid;
180: this .errorMessage = errorMessage;
181: if (fire) {
182: fireChangeEvent();
183: }
184: }
185:
186: // You can use a settings object to keep track of state. Normally the
187: // settings object will be the WizardDescriptor, so you can use
188: // WizardDescriptor.getProperty & putProperty to store information entered
189: // by the user.
190: public void readSettings(Object settings) {
191: if (settings instanceof WizardDescriptor) {
192: String repository = (String) ((WizardDescriptor) settings)
193: .getProperty("repository"); // NOI18N
194:
195: component.nameField.setText(new File(repository).getName());
196: }
197: }
198:
199: public void storeSettings(Object settings) {
200: if (settings instanceof WizardDescriptor) {
201: ((WizardDescriptor) settings).putProperty("directory",
202: ((CloneDestinationDirectoryPanel) component)
203: .getDirectory()); // NOI18N
204: ((WizardDescriptor) settings).putProperty("cloneName",
205: ((CloneDestinationDirectoryPanel) component)
206: .getCloneName()); // NOI18N
207: }
208: }
209: }
|