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.
29 * Portions Copyright 2008 Alexander Coles (Ikonoklastik Productions).
31 * If you wish your version of this file to be governed by only the CDDL
32 * or only the GPL Version 2, indicate your decision by adding
33 * "[Contributor] elects to include this software in this distribution
34 * under the [CDDL or GPL Version 2] license." If you do not indicate a
35 * single choice of license, a recipient has the option to distribute
36 * your version of this file under either the CDDL, the GPL Version 2 or
37 * to extend the choice of license to its licensees as provided above.
38 * However, if you add GPL Version 2 code and therefore, elected the GPL
39 * Version 2 license, then the option applies only if the new code is
40 * made subject to such option by the copyright holder.
42 package org
.netbeans
.modules
.git
.ui
.wizards
;
44 import java
.awt
.BorderLayout
;
45 import java
.awt
.Component
;
46 import java
.beans
.PropertyChangeEvent
;
47 import java
.beans
.PropertyChangeListener
;
49 import java
.io
.IOException
;
50 import java
.net
.HttpURLConnection
;
52 import java
.net
.URISyntaxException
;
54 import java
.util
.HashSet
;
55 import java
.util
.Iterator
;
57 import java
.util
.logging
.Level
;
58 import javax
.swing
.JPanel
;
59 import javax
.swing
.event
.ChangeEvent
;
60 import javax
.swing
.event
.ChangeListener
;
61 import org
.netbeans
.modules
.git
.Git
;
62 import org
.netbeans
.modules
.git
.GitModuleConfig
;
63 import org
.netbeans
.modules
.git
.ui
.repository
.Repository
;
64 import org
.netbeans
.modules
.git
.ui
.repository
.RepositoryConnection
;
65 import org
.openide
.WizardDescriptor
;
66 import org
.openide
.WizardValidationException
;
67 import org
.openide
.util
.HelpCtx
;
68 import org
.openide
.util
.NbBundle
;
69 import org
.openide
.util
.RequestProcessor
;
71 public class CloneRepositoryWizardPanel
implements WizardDescriptor
.AsynchronousValidatingPanel
, PropertyChangeListener
{
74 * The visual component that displays this panel. If you need to access the
75 * component from this class, just use getComponent().
77 private CloneRepositoryPanel component
;
78 private Repository repository
;
79 private int repositoryModeMask
;
80 private boolean valid
;
81 private String errorMessage
;
82 private WizardStepProgressSupport support
;
84 // Get the visual component for the panel. In this template, the component
85 // is kept separate. This can be more efficient: if the wizard is created
86 // but never displayed, or not all panels are displayed, it is better to
87 // create only those which really need to be visible.
88 public Component
getComponent() {
89 if (component
== null) {
90 component
= new CloneRepositoryPanel();
91 if (repository
== null) {
92 repositoryModeMask
= repositoryModeMask
| Repository
.FLAG_URL_EDITABLE
| Repository
.FLAG_URL_ENABLED
| Repository
.FLAG_SHOW_HINTS
| Repository
.FLAG_SHOW_PROXY
;
93 String title
= org
.openide
.util
.NbBundle
.getMessage(CloneRepositoryWizardPanel
.class, "CTL_Repository_Location"); // NOI18N
94 repository
= new Repository(repositoryModeMask
, title
);
95 repository
.addPropertyChangeListener(this);
96 CloneRepositoryPanel panel
= (CloneRepositoryPanel
)component
;
97 panel
.repositoryPanel
.setLayout(new BorderLayout());
98 panel
.repositoryPanel
.add(repository
.getPanel());
105 public HelpCtx
getHelp() {
106 return new HelpCtx(CloneRepositoryWizardPanel
.class);
109 //public boolean isValid() {
110 // If it is always OK to press Next or Finish, then:
112 // If it depends on some condition (form filled out...), then:
113 // return someCondition();
114 // and when this condition changes (last form field filled in...) then:
115 // fireChangeEvent();
116 // and uncomment the complicated stuff below.
119 public void propertyChange(PropertyChangeEvent evt
) {
120 if(evt
.getPropertyName().equals(Repository
.PROP_VALID
)) {
121 if(repository
.isValid()) {
122 valid(repository
.getMessage());
124 invalid(repository
.getMessage());
129 private final Set
<ChangeListener
> listeners
= new HashSet
<ChangeListener
>(1); // or can use ChangeSupport in NB 6.0
130 public final void addChangeListener(ChangeListener l
) {
131 synchronized (listeners
) {
135 public final void removeChangeListener(ChangeListener l
) {
136 synchronized (listeners
) {
140 protected final void fireChangeEvent() {
141 Iterator
<ChangeListener
> it
;
142 synchronized (listeners
) {
143 it
= new HashSet
<ChangeListener
>(listeners
).iterator();
145 ChangeEvent ev
= new ChangeEvent(this);
146 while (it
.hasNext()) {
147 it
.next().stateChanged(ev
);
151 protected final void valid() {
152 setValid(true, null);
155 protected final void valid(String extErrorMessage
) {
156 setValid(true, extErrorMessage
);
159 protected final void invalid(String message
) {
160 setValid(false, message
);
163 public final boolean isValid() {
167 public final String
getErrorMessage() {
171 private void setValid(boolean valid
, String errorMessage
) {
172 boolean fire
= this.valid
!= valid
;
173 fire
|= errorMessage
!= null && (errorMessage
.equals(this.errorMessage
) == false);
175 this.errorMessage
= errorMessage
;
181 protected void validateBeforeNext() {
183 support
= new RepositoryStepProgressSupport(component
.progressPanel
);
185 String url
= getUrl();
186 support
.setRepositoryRoot(url
);
187 RequestProcessor rp
= Git
.getInstance().getRequestProcessor(url
);
188 RequestProcessor
.Task task
= support
.start(rp
, url
, NbBundle
.getMessage(CloneRepositoryWizardPanel
.class, "BK2012"));
196 // comes on next or finish
197 public final void validate () throws WizardValidationException
{
198 validateBeforeNext();
199 if (isValid() == false || errorMessage
!= null) {
200 throw new WizardValidationException (
201 (javax
.swing
.JComponent
) component
,
208 // You can use a settings object to keep track of state. Normally the
209 // settings object will be the WizardDescriptor, so you can use
210 // WizardDescriptor.getProperty & putProperty to store information entered
212 public void readSettings(Object settings
) {}
213 public void storeSettings(Object settings
) {
214 if (settings
instanceof WizardDescriptor
) {
215 ((WizardDescriptor
) settings
).putProperty("repository", repository
.getSelectedRC().getUrl()); // NOI18N
216 ((WizardDescriptor
) settings
).putProperty("username", repository
.getSelectedRC().getUsername()); // NOI18N
217 ((WizardDescriptor
) settings
).putProperty("password", repository
.getSelectedRC().getPassword()); // NOI18N
221 public void prepareValidation() {
224 private String
getUrl() {
225 return getSelectedRepositoryConnection().getUrl();
228 private void storeHistory() {
229 RepositoryConnection rc
= getSelectedRepositoryConnection();
231 GitModuleConfig
.getDefault().insertRecentUrl(rc
);
235 private RepositoryConnection
getSelectedRepositoryConnection() {
237 return repository
.getSelectedRC();
238 } catch (Exception ex
) {
239 invalid(ex
.getLocalizedMessage());
245 if(support
!= null) {
250 private class RepositoryStepProgressSupport
extends WizardStepProgressSupport
{
252 public RepositoryStepProgressSupport(JPanel panel
) {
256 public void perform() {
257 final RepositoryConnection rc
= getSelectedRepositoryConnection();
261 String invalidMsg
= null;
265 // This command validates the url
267 String urlStr
= rc
.getUrl();
268 URI uri
= new URI(urlStr
);
269 String uriSch
= uri
.getScheme();
270 if(uriSch
.equals("file")){
271 File f
= new File(urlStr
.substring("file://".length()));
272 if(!f
.exists() || !f
.canRead()){
273 invalidMsg
= NbBundle
.getMessage(CloneRepositoryWizardPanel
.class,
274 "MSG_Progress_Clone_CannotAccess_Err");
277 }else if(uriSch
.equals("http") || uriSch
.equals("https")) {
278 URL url
= new URL(urlStr
);
279 HttpURLConnection con
= (HttpURLConnection
) url
.openConnection();
280 // Note: valid repository returns con.getContentLength() = -1
281 // so no way to reliably test if this url exists, without using hg
283 String userInfo
= uri
.getUserInfo();
284 boolean bNoUserAndOrPasswordInURL
= userInfo
== null;
285 // If username or username:password is in the URL the con.getResponseCode() returns -1 and this check would fail
286 if (bNoUserAndOrPasswordInURL
&& con
.getResponseCode() != HttpURLConnection
.HTTP_OK
){
287 invalidMsg
= NbBundle
.getMessage(CloneRepositoryWizardPanel
.class,
288 "MSG_Progress_Clone_CannotAccess_Err");
291 }else if (userInfo
!= null){
292 Git
.LOG
.log(Level
.FINE
,
293 "RepositoryStepProgressSupport.perform(): UserInfo - {0}", new Object
[]{userInfo
}); // NOI18N
298 } catch (java
.lang
.IllegalArgumentException ex
) {
299 invalidMsg
= NbBundle
.getMessage(CloneRepositoryWizardPanel
.class,
300 "MSG_Progress_Clone_InvalidURL_Err");
302 } catch (IOException ex
) {
303 invalidMsg
= NbBundle
.getMessage(CloneRepositoryWizardPanel
.class,
304 "MSG_Progress_Clone_CannotAccess_Err");
306 } catch (URISyntaxException ex
) {
307 invalidMsg
= NbBundle
.getMessage(CloneRepositoryWizardPanel
.class,
308 "MSG_Progress_Clone_InvalidURL_Err");
312 valid(org
.openide
.util
.NbBundle
.getMessage(CloneRepositoryWizardPanel
.class, "CTL_Repository_Canceled")); // NOI18N
313 } else if(invalidMsg
== null) {
322 public void setEditable(boolean editable
) {
323 repository
.setEditable(editable
);