2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
41
package org.netbeans.modules.mercurial.ui.wizards;
43
import java.net.MalformedURLException;
44
import java.awt.Component;
45
import java.awt.BorderLayout;
46
import java.beans.PropertyChangeListener;
47
import java.beans.PropertyChangeEvent;
48
import javax.swing.event.ChangeEvent;
49
import javax.swing.event.ChangeListener;
50
import javax.swing.JPanel;
52
import java.util.HashSet;
53
import java.util.Iterator;
54
import java.util.logging.Level;
57
import java.net.HttpURLConnection;
58
import java.net.URISyntaxException;
60
import java.io.IOException;
61
import org.openide.WizardDescriptor;
62
import org.openide.WizardValidationException;
63
import org.openide.util.HelpCtx;
64
import org.openide.util.NbBundle;
65
import org.openide.util.RequestProcessor;
66
import org.netbeans.modules.mercurial.Mercurial;
67
import org.netbeans.modules.mercurial.HgModuleConfig;
68
import org.netbeans.modules.mercurial.HgException;
69
import org.netbeans.modules.mercurial.util.HgCommand;
70
import org.netbeans.modules.mercurial.ui.repository.Repository;
71
import org.netbeans.modules.mercurial.ui.repository.RepositoryConnection;
72
import org.netbeans.modules.mercurial.ui.repository.HgURL;
74
public class CloneRepositoryWizardPanel implements WizardDescriptor.AsynchronousValidatingPanel, PropertyChangeListener {
77
* The visual component that displays this panel. If you need to access the
78
* component from this class, just use getComponent().
80
private CloneRepositoryPanel component;
81
private Repository repository;
82
private int repositoryModeMask;
83
private boolean valid;
84
private String errorMessage;
85
private WizardStepProgressSupport support;
87
// Get the visual component for the panel. In this template, the component
88
// is kept separate. This can be more efficient: if the wizard is created
89
// but never displayed, or not all panels are displayed, it is better to
90
// create only those which really need to be visible.
91
public Component getComponent() {
92
if (component == null) {
93
component = new CloneRepositoryPanel();
94
if (repository == null) {
95
repositoryModeMask = repositoryModeMask | Repository.FLAG_URL_EDITABLE | Repository.FLAG_URL_ENABLED | Repository.FLAG_SHOW_HINTS | Repository.FLAG_SHOW_PROXY;
96
String title = org.openide.util.NbBundle.getMessage(CloneRepositoryWizardPanel.class, "CTL_Repository_Location"); // NOI18N
97
repository = new Repository(repositoryModeMask, title);
98
repository.addPropertyChangeListener(this);
99
CloneRepositoryPanel panel = (CloneRepositoryPanel)component;
100
panel.repositoryPanel.setLayout(new BorderLayout());
101
panel.repositoryPanel.add(repository.getPanel());
108
public HelpCtx getHelp() {
109
return new HelpCtx(CloneRepositoryWizardPanel.class);
112
//public boolean isValid() {
113
// If it is always OK to press Next or Finish, then:
115
// If it depends on some condition (form filled out...), then:
116
// return someCondition();
117
// and when this condition changes (last form field filled in...) then:
118
// fireChangeEvent();
119
// and uncomment the complicated stuff below.
122
public void propertyChange(PropertyChangeEvent evt) {
123
if(evt.getPropertyName().equals(Repository.PROP_VALID)) {
124
if(repository.isValid()) {
125
valid(repository.getMessage());
127
invalid(repository.getMessage());
132
private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(1); // or can use ChangeSupport in NB 6.0
133
public final void addChangeListener(ChangeListener l) {
134
synchronized (listeners) {
138
public final void removeChangeListener(ChangeListener l) {
139
synchronized (listeners) {
143
protected final void fireChangeEvent() {
144
Iterator<ChangeListener> it;
145
synchronized (listeners) {
146
it = new HashSet<ChangeListener>(listeners).iterator();
148
ChangeEvent ev = new ChangeEvent(this);
149
while (it.hasNext()) {
150
it.next().stateChanged(ev);
154
protected final void valid() {
155
setValid(true, null);
158
protected final void valid(String extErrorMessage) {
159
setValid(true, extErrorMessage);
162
protected final void invalid(String message) {
163
setValid(false, message);
166
public final boolean isValid() {
170
public final String getErrorMessage() {
174
private void setValid(boolean valid, String errorMessage) {
175
boolean fire = this.valid != valid;
176
fire |= errorMessage != null && (errorMessage.equals(this.errorMessage) == false);
178
this.errorMessage = errorMessage;
184
protected void validateBeforeNext() {
186
support = new RepositoryStepProgressSupport(component.progressPanel);
188
String url = getUrl();
189
support.setRepositoryRoot(url);
190
RequestProcessor rp = Mercurial.getInstance().getRequestProcessor(url);
191
RequestProcessor.Task task = support.start(rp, url, NbBundle.getMessage(CloneRepositoryWizardPanel.class, "BK2012"));
199
// comes on next or finish
200
public final void validate () throws WizardValidationException {
201
validateBeforeNext();
202
if (isValid() == false || errorMessage != null) {
203
throw new WizardValidationException (
204
(javax.swing.JComponent) component,
211
// You can use a settings object to keep track of state. Normally the
212
// settings object will be the WizardDescriptor, so you can use
213
// WizardDescriptor.getProperty & putProperty to store information entered
215
public void readSettings(Object settings) {}
216
public void storeSettings(Object settings) {
217
if (settings instanceof WizardDescriptor) {
218
((WizardDescriptor) settings).putProperty("repository", repository.getSelectedRC().getUrl()); // NOI18N
219
((WizardDescriptor) settings).putProperty("username", repository.getSelectedRC().getUsername()); // NOI18N
220
((WizardDescriptor) settings).putProperty("password", repository.getSelectedRC().getPassword()); // NOI18N
224
public void prepareValidation() {
227
private String getUrl() {
228
return getSelectedRepositoryConnection().getUrl();
231
private void storeHistory() {
232
RepositoryConnection rc = getSelectedRepositoryConnection();
234
HgModuleConfig.getDefault().insertRecentUrl(rc);
238
private RepositoryConnection getSelectedRepositoryConnection() {
240
return repository.getSelectedRC();
241
} catch (Exception ex) {
242
invalid(ex.getLocalizedMessage());
248
if(support != null) {
253
private class RepositoryStepProgressSupport extends WizardStepProgressSupport {
255
public RepositoryStepProgressSupport(JPanel panel) {
259
public void perform() {
260
final RepositoryConnection rc = getSelectedRepositoryConnection();
264
String invalidMsg = null;
268
// This command validates the url
270
String urlStr = rc.getUrl();
271
URI uri = new URI(urlStr);
272
String uriSch = uri.getScheme();
273
if(uriSch.equals("file")){
274
File f = new File(urlStr.substring("file://".length()));
275
if(!f.exists() || !f.canRead()){
276
invalidMsg = NbBundle.getMessage(CloneRepositoryWizardPanel.class,
277
"MSG_Progress_Clone_CannotAccess_Err");
280
}else if(uriSch.equals("http") || uriSch.equals("https")) {
281
URL url = new URL(urlStr);
282
HttpURLConnection con = (HttpURLConnection) url.openConnection();
283
// Note: valid repository returns con.getContentLength() = -1
284
// so no way to reliably test if this url exists, without using hg
286
String userInfo = uri.getUserInfo();
287
boolean bNoUserAndOrPasswordInURL = userInfo == null;
288
// If username or username:password is in the URL the con.getResponseCode() returns -1 and this check would fail
289
if (bNoUserAndOrPasswordInURL && con.getResponseCode() != HttpURLConnection.HTTP_OK){
290
invalidMsg = NbBundle.getMessage(CloneRepositoryWizardPanel.class,
291
"MSG_Progress_Clone_CannotAccess_Err");
294
}else if (userInfo != null){
295
Mercurial.LOG.log(Level.FINE,
296
"RepositoryStepProgressSupport.perform(): UserInfo - {0}", new Object[]{userInfo}); // NOI18N
301
} catch (java.lang.IllegalArgumentException ex) {
302
invalidMsg = NbBundle.getMessage(CloneRepositoryWizardPanel.class,
303
"MSG_Progress_Clone_InvalidURL_Err");
305
} catch (IOException ex) {
306
invalidMsg = NbBundle.getMessage(CloneRepositoryWizardPanel.class,
307
"MSG_Progress_Clone_CannotAccess_Err");
309
} catch (URISyntaxException ex) {
310
invalidMsg = NbBundle.getMessage(CloneRepositoryWizardPanel.class,
311
"MSG_Progress_Clone_InvalidURL_Err");
315
valid(org.openide.util.NbBundle.getMessage(CloneRepositoryWizardPanel.class, "CTL_Repository_Canceled")); // NOI18N
316
} else if(invalidMsg == null) {
325
public void setEditable(boolean editable) {
326
repository.setEditable(editable);