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:
042: package org.netbeans.modules.versioning.system.cvss.ui.wizards;
043:
044: import org.openide.WizardDescriptor;
045: import org.openide.ErrorManager;
046: import org.openide.util.RequestProcessor;
047: import org.openide.util.NbBundle;
048: import org.openide.util.HelpCtx;
049: import org.netbeans.api.progress.ProgressHandle;
050: import org.netbeans.api.progress.ProgressHandleFactory;
051: import org.netbeans.api.options.OptionsDisplayer;
052: import org.netbeans.lib.cvsclient.connection.*;
053: import org.netbeans.lib.cvsclient.CVSRoot;
054: import org.netbeans.modules.versioning.system.cvss.CvsModuleConfig;
055: import org.netbeans.modules.versioning.system.cvss.SSHConnection;
056: import org.netbeans.modules.versioning.util.Utils;
057: import org.netbeans.modules.proxy.ProxySocketFactory;
058:
059: import javax.swing.event.DocumentListener;
060: import javax.swing.event.DocumentEvent;
061: import javax.swing.*;
062: import javax.swing.text.JTextComponent;
063: import javax.net.SocketFactory;
064: import java.awt.event.ActionListener;
065: import java.awt.event.ActionEvent;
066: import java.awt.*;
067: import java.util.*;
068: import java.net.Socket;
069: import java.net.SocketAddress;
070: import java.net.InetSocketAddress;
071: import java.io.IOException;
072: import java.lang.reflect.InvocationTargetException;
073:
074: /**
075: * UI for CvsRootSettings. After initialization data
076: * are taken directly from UI. These are propagated
077: * into CvsRootSettings on {@link #storeValidValues()}.
078: *
079: * @author Petr Kuzel
080: */
081: public final class RepositoryStep extends AbstractStep implements
082: WizardDescriptor.AsynchronousValidatingPanel, ActionListener,
083: DocumentListener {
084:
085: public static final String IMPORT_HELP_ID = "org.netbeans.modules.versioning.system.cvss.ui.wizards.RepositoryStep.import";
086: public static final String CHECKOUT_HELP_ID = "org.netbeans.modules.versioning.system.cvss.ui.wizards.RepositoryStep.checkout";
087: public static final String ROOT_CONF_HELP_ID = "org.netbeans.modules.versioning.system.cvss.ui.wizards.RepositoryStep.rootConf";
088:
089: private static final String USE_INTERNAL_SSH = "repositoryStep.useInternalSSH";
090: private static final String EXT_COMMAND = "repositoryStep.extCommand";
091: private static final String RECENT_ROOTS = "repositoryStep.recentRoots";
092:
093: private RequestProcessor.Task updatePasswordTask;
094: private volatile boolean passwordExpected;
095:
096: private ProgressHandle progress;
097: private JComponent progressComponent;
098: private JLabel progressLabel;
099:
100: private volatile boolean internalDocumentChange;
101: private Thread backgroundValidationThread;
102: private RepositoryPanel repositoryPanel;
103: private String scrambledPassword;
104: private final String initialCvsRoot;
105: private String preferedCvsRoot;
106:
107: private final String helpID;
108:
109: /**
110: * Creates multiple roots customizer.
111: */
112: public RepositoryStep(String helpID) {
113: initialCvsRoot = null;
114: this .helpID = helpID;
115: }
116:
117: /**
118: * Creates single root customizer
119: */
120: public RepositoryStep(String root, String helpID) {
121: initialCvsRoot = root;
122: this .helpID = helpID;
123: }
124:
125: public HelpCtx getHelp() {
126: return new HelpCtx(helpID);
127: }
128:
129: /**
130: * Preselected cvs root (first in list).
131: */
132: public void initPreferedCvsRoot(String root) {
133: preferedCvsRoot = root;
134: }
135:
136: protected JComponent createComponent() {
137: repositoryPanel = new RepositoryPanel();
138:
139: // password field, features automatic fill from ~/.cvspass
140:
141: repositoryPanel.extSshRadioButton.addActionListener(this );
142: repositoryPanel.internalSshRadioButton.addActionListener(this );
143: repositoryPanel.extCommandTextField.getDocument()
144: .addDocumentListener(this );
145: repositoryPanel.extPasswordField.getDocument()
146: .addDocumentListener(this );
147: repositoryPanel.passwordTextField.getDocument()
148: .addDocumentListener(this );
149: RequestProcessor requestProcessor = new RequestProcessor();
150: updatePasswordTask = requestProcessor.create(new Runnable() {
151: public void run() {
152: String cvsRoot = selectedCvsRoot();
153: String password = PasswordsFile.findPassword(cvsRoot);
154: if (password != null && passwordExpected) {
155: String fakePasswordWithProperLen = new String(
156: password).substring(1);
157: scrambledPassword = password;
158: internalDocumentChange = true;
159: repositoryPanel.passwordTextField
160: .setText(fakePasswordWithProperLen);
161: internalDocumentChange = false;
162: cancelPasswordUpdate();
163: }
164: }
165: });
166:
167: // roots combo setup, keeping history
168:
169: Set recentRoots = new LinkedHashSet();
170: if (preferedCvsRoot != null) {
171: recentRoots.add(preferedCvsRoot);
172: }
173: recentRoots.addAll(Utils.getStringList(CvsModuleConfig
174: .getDefault().getPreferences(), RECENT_ROOTS));
175: if (initialCvsRoot != null) {
176: // it's first => initially selected
177: recentRoots.add(initialCvsRoot);
178: }
179: Iterator cvsPassRoots = PasswordsFile.listRoots(":pserver:")
180: .iterator(); // NOI18N
181: while (cvsPassRoots.hasNext()) {
182: String next = (String) cvsPassRoots.next();
183: if (recentRoots.contains(next) == false) {
184: recentRoots.add(next);
185: }
186: }
187: // templates for supported connection methods
188: String user = System.getProperty("user.name", ""); // NOI18N
189: if (user.length() > 0)
190: user += "@"; // NOI18N
191: recentRoots.add(":pserver:" + user); // NOI18N
192: recentRoots.add(":ext:" + user); // NOI18N
193: recentRoots.add(":fork:"); // NOI18N
194: recentRoots.add(":local:"); // NOI18N
195:
196: ComboBoxModel rootsModel = new DefaultComboBoxModel(new Vector(
197: recentRoots));
198: repositoryPanel.rootComboBox.setModel(rootsModel);
199: repositoryPanel.rootComboBox.addActionListener(this );
200: Component editor = repositoryPanel.rootComboBox.getEditor()
201: .getEditorComponent();
202: JTextComponent textEditor = (JTextComponent) editor;
203: if (recentRoots.size() == 0) {
204: textEditor.setText(":pserver:" + user); // NOI18N
205: } else {
206: validateCvsRoot();
207: CVSRoot root = getCVSRoot();
208: schedulePasswordUpdate();
209: }
210: textEditor.selectAll();
211: textEditor.getDocument().addDocumentListener(this );
212:
213: boolean useInternalSsh = CvsModuleConfig.getDefault()
214: .getPreferences().getBoolean(USE_INTERNAL_SSH, true);
215: repositoryPanel.internalSshRadioButton
216: .setSelected(useInternalSsh);
217: repositoryPanel.extSshRadioButton.setSelected(!useInternalSsh);
218:
219: String extCommand = CvsModuleConfig.getDefault()
220: .getPreferences().get(EXT_COMMAND, "");
221: repositoryPanel.extCommandTextField.setText(extCommand);
222:
223: repositoryPanel.proxyConfigurationButton
224: .addActionListener(this );
225: repositoryPanel.editButton.addActionListener(this );
226:
227: valid();
228: onCvsRootChange();
229:
230: if (initialCvsRoot != null) {
231: boolean chooserVisible = false;
232: repositoryPanel.headerLabel.setVisible(chooserVisible);
233: repositoryPanel.rootsLabel.setVisible(chooserVisible);
234: repositoryPanel.rootComboBox.setVisible(chooserVisible);
235: repositoryPanel.descLabel.setVisible(chooserVisible);
236: repositoryPanel.editButton.setVisible(chooserVisible);
237: }
238:
239: return repositoryPanel;
240: }
241:
242: /**
243: * Heavy validation over network.
244: * Sets wizard as invalid to disable next button
245: * and starts. It's invoked in background validation thread.
246: */
247: protected void validateBeforeNext() {
248:
249: if (validateCvsRoot() == false) {
250: return;
251: }
252: final CVSRoot root = getCVSRoot();
253:
254: backgroundValidationThread = Thread.currentThread();
255:
256: final String invalidMsg[] = new String[1]; // ret value
257: Runnable worker = new Runnable() {
258:
259: private void fail(String msg) {
260: invalidMsg[0] = msg;
261: }
262:
263: public void run() {
264:
265: String host = root.getHostName();
266: String userName = root.getUserName();
267: int port = root.getPort();
268: Socket sock = null;
269: Connection connection = null;
270:
271: try {
272: if (root.isLocal()) {
273: LocalConnection lconnection = new LocalConnection();
274: lconnection.setRepository(root.getRepository());
275: lconnection.verify();
276: } else {
277: invalid(null);
278: progress(NbBundle.getMessage(
279: CheckoutWizard.class, "BK2011"));
280: ProxySocketFactory factory = ProxySocketFactory
281: .getDefault();
282:
283: // check raw network reachability
284:
285: if (CVSRoot.METHOD_PSERVER.equals(root
286: .getMethod())) {
287: port = port == 0 ? 2401 : port; // default port
288:
289: SocketAddress target = new InetSocketAddress(
290: host, port);
291: sock = factory.createSocket();
292: sock.connect(target, 5000);
293: sock.close();
294:
295: // try to login
296: progress(NbBundle.getMessage(
297: CheckoutWizard.class, "BK2010"));
298: PServerConnection pconnection = new PServerConnection(
299: root, factory);
300: String password = getScrambledPassword();
301: pconnection.setEncodedPassword(password);
302: pconnection.verify();
303: } else if (CVSRoot.METHOD_EXT.equals(root
304: .getMethod())) {
305: if (repositoryPanel.internalSshRadioButton
306: .isSelected()) {
307: port = port == 0 ? 22 : port; // default port
308: String password = repositoryPanel.extPasswordField
309: .getText();
310: SSHConnection sshConnection = new SSHConnection(
311: factory, host, port, userName,
312: password);
313: sshConnection.setRepository(root
314: .getRepository());
315: sshConnection.verify();
316: } else {
317: String command = repositoryPanel.extCommandTextField
318: .getText();
319: String userOption = ""; // NOI18N
320: if (userName != null) {
321: userOption = " -l " + userName; // NOI18N
322: }
323: String cvs_server = System
324: .getenv("CVS_SERVER") != null ? System
325: .getenv("CVS_SERVER")
326: + " server"
327: : "cvs server"; // NOI18N
328: command += " " + host + userOption
329: + " " + cvs_server; // NOI18N
330: ExtConnection econnection = new ExtConnection(
331: command);
332: econnection.setRepository(root
333: .getRepository());
334: econnection.verify();
335: }
336: } else {
337: assert false : "Login check implemented only for pserver"; // NOI18N
338: }
339: }
340:
341: } catch (IOException e) {
342: ErrorManager err = ErrorManager.getDefault();
343: err
344: .annotate(e, org.openide.util.NbBundle
345: .getMessage(RepositoryStep.class,
346: "BK2019")); // NOi18N
347: err.notify(ErrorManager.INFORMATIONAL, e);
348: String msg = NbBundle.getMessage(
349: CheckoutWizard.class, "BK1001", host);
350: fail(msg);
351: } catch (AuthenticationException e) {
352: ErrorManager err = ErrorManager.getDefault();
353: err
354: .annotate(e,
355: "Connection authentification verification failed."); // NOI18N
356: err.notify(ErrorManager.INFORMATIONAL, e);
357:
358: // enhanced contact, if getLocalizedMessage strts with "<" it contains our approved texts
359: String msg;
360: if (e.getLocalizedMessage() != null
361: && e.getLocalizedMessage().startsWith("<")) { // NOI18N
362: msg = e.getLocalizedMessage();
363: } else {
364: if (root.isLocal()) {
365: msg = NbBundle.getMessage(
366: CheckoutWizard.class, "BK1004");
367: } else {
368: msg = NbBundle.getMessage(
369: CheckoutWizard.class, "BK1002");
370: }
371: }
372: fail(msg);
373: } finally {
374: if (sock != null) {
375: try {
376: sock.close();
377: } catch (IOException e) {
378: // already closed
379: }
380: }
381: if (connection != null) {
382: try {
383: connection.close();
384: } catch (IOException e) {
385: // already closed
386: }
387: }
388: }
389: }
390: };
391:
392: Thread workerThread = new Thread(worker, "CVS I/O Probe "); // NOI18N
393: workerThread.start();
394: try {
395: workerThread.join();
396: if (invalidMsg[0] == null) {
397: valid();
398: storeValidValues();
399: } else {
400: valid(invalidMsg[0]);
401: }
402: } catch (InterruptedException e) {
403: invalid(org.openide.util.NbBundle.getMessage(
404: RepositoryStep.class, "BK2023"));
405: ErrorManager err = ErrorManager.getDefault();
406: err.annotate(e,
407: "Passing interrupt to possibly uninterruptible nested thread: "
408: + workerThread); // NOI18N
409: workerThread.interrupt();
410: err.notify(ErrorManager.INFORMATIONAL, e);
411: } finally {
412: backgroundValidationThread = null;
413: SwingUtilities.invokeLater(new Runnable() {
414: public void run() {
415: validationDone();
416: }
417: });
418: }
419:
420: }
421:
422: private void progress(String message) {
423: if (progressLabel != null) {
424: progressLabel.setText(message);
425: }
426: }
427:
428: private void validationDone() {
429: progress.finish();
430: repositoryPanel.jPanel1.remove(progressComponent);
431: repositoryPanel.jPanel1.revalidate();
432: repositoryPanel.jPanel1.repaint();
433: editable(true);
434: }
435:
436: private void editable(boolean editable) {
437: repositoryPanel.rootComboBox.setEditable(editable);
438: repositoryPanel.passwordTextField.setEditable(editable);
439: repositoryPanel.extCommandTextField.setEditable(editable);
440: repositoryPanel.extPasswordField.setEditable(editable);
441:
442: repositoryPanel.proxyConfigurationButton.setEnabled(editable);
443: repositoryPanel.extREmemberPasswordCheckBox
444: .setEnabled(editable);
445: repositoryPanel.internalSshRadioButton.setEnabled(editable);
446: repositoryPanel.extSshRadioButton.setEnabled(editable);
447: }
448:
449: void storeValidValues() {
450: String root = selectedCvsRoot();
451: CVSRoot cvsRoot = CVSRoot.parse(root);
452: if (root.startsWith(":pserver:")) { // NOI18N
453: try {
454: // CVSclient library reads password directly from .cvspass file
455: // store it here into the file. It's potentionally necessary for
456: // next step branch and module browsers
457:
458: PasswordsFile.storePassword(root,
459: getScrambledPassword());
460: } catch (IOException e) {
461: ErrorManager err = ErrorManager.getDefault();
462: err.annotate(e, org.openide.util.NbBundle.getMessage(
463: RepositoryStep.class, "BK2020"));
464: err.notify(e);
465: }
466: } else if (root.startsWith(":ext:")) { // NOI18N
467: boolean internalSsh = repositoryPanel.internalSshRadioButton
468: .isSelected();
469: CvsModuleConfig.ExtSettings extSettings = new CvsModuleConfig.ExtSettings();
470: extSettings.extUseInternalSsh = internalSsh;
471: extSettings.extPassword = repositoryPanel.extPasswordField
472: .getText();
473: extSettings.extRememberPassword = repositoryPanel.extREmemberPasswordCheckBox
474: .isSelected();
475: extSettings.extCommand = repositoryPanel.extCommandTextField
476: .getText();
477: CvsModuleConfig.getDefault().getPreferences().putBoolean(
478: USE_INTERNAL_SSH, internalSsh);
479: CvsModuleConfig.getDefault().getPreferences().put(
480: EXT_COMMAND, extSettings.extCommand);
481: CvsModuleConfig.getDefault().setExtSettingsFor(cvsRoot,
482: extSettings);
483: }
484:
485: Utils.insert(CvsModuleConfig.getDefault().getPreferences(),
486: RECENT_ROOTS, root, 8);
487: }
488:
489: /**
490: * Fast root syntax check. It can invalidate whole step
491: * but neder set it as valid.
492: */
493: private boolean validateCvsRoot() {
494: String cvsRoot = selectedCvsRoot();
495: String errorMessage = null;
496: boolean supportedMethod = false;
497: if (cvsRoot != null) {
498: supportedMethod |= cvsRoot.startsWith(":pserver:"); // NOI18N
499: supportedMethod |= cvsRoot.startsWith(":local:"); // NOI18N
500: supportedMethod |= cvsRoot.startsWith(":fork:"); // NOI18N
501: supportedMethod |= cvsRoot.startsWith(":ext:"); // NOI18N
502: }
503: if (supportedMethod == false) {
504: errorMessage = NbBundle.getMessage(CheckoutWizard.class,
505: "BK1000");
506: } else {
507: try {
508: CVSRoot.parse(cvsRoot);
509: } catch (IllegalArgumentException ex) {
510: errorMessage = org.openide.util.NbBundle.getMessage(
511: RepositoryStep.class, "BK2021")
512: + ex.getLocalizedMessage();
513: }
514: }
515: if (errorMessage != null) {
516: invalid(errorMessage);
517: }
518: return errorMessage == null;
519: }
520:
521: /**
522: * On valid CVS root loads UI fields from CvsRootSettings.
523: * Always updates UI fields visibility.
524: */
525: private void onCvsRootChange() {
526: if (validateCvsRoot()) {
527: valid();
528: CVSRoot root = getCVSRoot();
529: if (CVSRoot.METHOD_EXT.equals(root.getMethod())) {
530: if (CvsModuleConfig.getDefault()
531: .hasExtSettingsFor(root)) {
532: CvsModuleConfig.ExtSettings extSettings = CvsModuleConfig
533: .getDefault().getExtSettingsFor(root);
534: repositoryPanel.internalSshRadioButton
535: .setSelected(extSettings.extUseInternalSsh);
536: repositoryPanel.extPasswordField
537: .setText(extSettings.extPassword);
538: repositoryPanel.extREmemberPasswordCheckBox
539: .setSelected(extSettings.extRememberPassword);
540: repositoryPanel.extCommandTextField
541: .setText(extSettings.extCommand);
542: }
543: }
544: repositoryPanel.extPasswordField.setEditable(root
545: .getPassword() == null);
546: repositoryPanel.passwordTextField.setEditable(root
547: .getPassword() == null);
548: if (root.getPassword() != null) {
549: if (CVSRoot.METHOD_EXT.equals(root.getMethod())) {
550: repositoryPanel.extPasswordField.setText(root
551: .getPassword());
552: } else if (CVSRoot.METHOD_PSERVER.equals(root
553: .getMethod())) {
554: repositoryPanel.passwordTextField.setText(root
555: .getPassword());
556: }
557: } else {
558: schedulePasswordUpdate();
559: }
560: }
561: updateVisibility();
562: updateLabel();
563: }
564:
565: private void updateLabel() {
566: String cvsRoot = selectedCvsRoot();
567: if (cvsRoot.startsWith(":pserver:")) { // NOI18N
568: repositoryPanel.descLabel
569: .setText("(:pserver:username@hostname:/repository_path)"); // NOI18N
570: } else if (cvsRoot.startsWith(":local:")) { // NOI18N
571: repositoryPanel.descLabel
572: .setText("(:local:/repository_path)"); // NOI18N
573: } else if (cvsRoot.startsWith(":fork:")) { // NOI18N
574: repositoryPanel.descLabel
575: .setText("(:fork:/repository_path)"); // NOI18N
576: } else if (cvsRoot.startsWith(":ext:")) { // NOI18N
577: repositoryPanel.descLabel
578: .setText("(:ext:username@hostname:/repository_path)"); // NOI18N
579: } else {
580: repositoryPanel.descLabel.setText(NbBundle.getMessage(
581: CheckoutWizard.class, "BK1014"));
582: }
583:
584: }
585:
586: /** Shows proper fields depending on CVS root connection method. */
587: private void updateVisibility() {
588: String root = selectedCvsRoot();
589: boolean showPserverFields = root.startsWith(":pserver:"); // NOI18N
590: boolean showExtFields = root.startsWith(":ext:"); // NOI18N
591:
592: repositoryPanel.passwordTextField.setVisible(showPserverFields);
593: repositoryPanel.pPaswordLabel.setVisible(showPserverFields);
594:
595: repositoryPanel.internalSshRadioButton
596: .setVisible(showExtFields);
597: repositoryPanel.extSshRadioButton.setVisible(showExtFields);
598:
599: repositoryPanel.extPasswordLabel5.setVisible(showExtFields);
600: repositoryPanel.extPasswordField.setVisible(showExtFields);
601: repositoryPanel.extPasswordField
602: .setEnabled(repositoryPanel.internalSshRadioButton
603: .isSelected());
604: repositoryPanel.extREmemberPasswordCheckBox
605: .setVisible(showExtFields);
606: repositoryPanel.extREmemberPasswordCheckBox
607: .setEnabled(repositoryPanel.internalSshRadioButton
608: .isSelected());
609:
610: repositoryPanel.extCommandLabel.setVisible(showExtFields);
611: repositoryPanel.extCommandTextField.setVisible(showExtFields);
612: repositoryPanel.extCommandTextField
613: .setEnabled(repositoryPanel.extSshRadioButton
614: .isSelected());
615:
616: repositoryPanel.proxyConfigurationButton
617: .setVisible(showPserverFields || showExtFields);
618: repositoryPanel.proxyConfigurationButton
619: .setEnabled(showPserverFields
620: || !repositoryPanel.extSshRadioButton
621: .isSelected());
622: repositoryPanel.browseButton.setVisible(showExtFields);
623: repositoryPanel.browseButton
624: .setEnabled(repositoryPanel.extSshRadioButton
625: .isSelected());
626: }
627:
628: /**
629: * Load selected root from Swing structures (from arbitrary thread).
630: * @return null on failure
631: */
632: private String selectedCvsRoot() {
633: if (initialCvsRoot != null) {
634: return initialCvsRoot;
635: }
636: final String cvsRoot[] = new String[1];
637: try {
638: Runnable awt = new Runnable() {
639: public void run() {
640: cvsRoot[0] = (String) repositoryPanel.rootComboBox
641: .getEditor().getItem();
642: }
643: };
644: if (SwingUtilities.isEventDispatchThread()) {
645: awt.run();
646: } else {
647: SwingUtilities.invokeAndWait(awt);
648: }
649: String root = cvsRoot[0].trim();
650: try {
651: return CVSRoot.parse(root).toString();
652: } catch (Exception e) {
653: return root;
654: }
655: } catch (InterruptedException e) {
656: ErrorManager err = ErrorManager.getDefault();
657: err.notify(e);
658: } catch (InvocationTargetException e) {
659: ErrorManager err = ErrorManager.getDefault();
660: err.notify(e);
661: }
662: return null;
663: }
664:
665: private CVSRoot getCVSRoot() {
666: try {
667: String root = selectedCvsRoot();
668: return CVSRoot.parse(root);
669: } catch (IllegalArgumentException e) {
670: // expected, it means invalid root
671: }
672: return null;
673: }
674:
675: /**
676: * Visually notifies user about password length
677: */
678: private void schedulePasswordUpdate() {
679: String root = selectedCvsRoot();
680: if (root.startsWith(":pserver:")) { // NOI18N
681: passwordExpected = true;
682: updatePasswordTask.schedule(10);
683: }
684: }
685:
686: private void cancelPasswordUpdate() {
687: passwordExpected = false;
688: }
689:
690: private void onPasswordChange() {
691: cancelPasswordUpdate();
692: scrambledPassword = null;
693: if (validateCvsRoot()) {
694: valid();
695: }
696: }
697:
698: private void setValid() {
699: valid();
700: }
701:
702: private void onProxyConfiguration() {
703: OptionsDisplayer.getDefault().open("General");
704: if (validateCvsRoot()) {
705: valid();
706: }
707: }
708:
709: private void editRoot() {
710: String root = selectedCvsRoot();
711: root = RootWizard.editCvsRoot(root);
712: if (root != null) {
713: repositoryPanel.rootComboBox.setSelectedItem(root);
714: }
715: }
716:
717: // hooks
718:
719: public void actionPerformed(ActionEvent e) {
720: if (repositoryPanel.proxyConfigurationButton == e.getSource()) {
721: onProxyConfiguration();
722: } else if (repositoryPanel.rootComboBox == e.getSource()) {
723: onCvsRootChange();
724: } else if (repositoryPanel.editButton == e.getSource()) {
725: editRoot();
726: } else if (repositoryPanel.extSshRadioButton == e.getSource()) {
727: setValid();
728: validateCvsRoot();
729: updateVisibility();
730: } else if (repositoryPanel.internalSshRadioButton == e
731: .getSource()) {
732: setValid();
733: validateCvsRoot();
734: updateVisibility();
735: } else {
736: assert false : "Unexpected event source: " + e.getSource(); // NOI18N
737: }
738: }
739:
740: public void changedUpdate(DocumentEvent e) {
741: }
742:
743: public void insertUpdate(DocumentEvent e) {
744: textChanged(e);
745: }
746:
747: public void removeUpdate(DocumentEvent e) {
748: textChanged(e);
749: }
750:
751: private void textChanged(final DocumentEvent e) {
752: // repost later to AWT otherwise it can deadlock because
753: // the document is locked while firing event and we try
754: // synchronously access its content from selectedCvsRoot
755: if (internalDocumentChange)
756: return;
757: Runnable awt = new Runnable() {
758: public void run() {
759: if (e.getDocument() == repositoryPanel.passwordTextField
760: .getDocument()) {
761: onPasswordChange();
762: } else if (e.getDocument() == ((JTextComponent) repositoryPanel.rootComboBox
763: .getEditor().getEditorComponent())
764: .getDocument()) {
765: onCvsRootChange();
766: } else if (e.getDocument() == repositoryPanel.extPasswordField
767: .getDocument()) {
768: setValid();
769: validateCvsRoot();
770: } else if (e.getDocument() == repositoryPanel.extCommandTextField
771: .getDocument()) {
772: setValid();
773: validateCvsRoot();
774: }
775: }
776: };
777: SwingUtilities.invokeLater(awt);
778: }
779:
780: public void prepareValidation() {
781: progress = ProgressHandleFactory.createHandle(NbBundle
782: .getMessage(CheckoutWizard.class, "BK2012"));
783: JComponent bar = ProgressHandleFactory
784: .createProgressComponent(progress);
785: JButton stopButton = new JButton(org.openide.util.NbBundle
786: .getMessage(RepositoryStep.class, "BK2022"));
787: stopButton.addActionListener(new ActionListener() {
788: public void actionPerformed(ActionEvent e) {
789: if (backgroundValidationThread != null) {
790: backgroundValidationThread.interrupt();
791: }
792: }
793: });
794: progressComponent = new JPanel();
795: progressComponent.setLayout(new BorderLayout(6, 0));
796: progressLabel = new JLabel();
797: progressComponent.add(progressLabel, BorderLayout.NORTH);
798: progressComponent.add(bar, BorderLayout.CENTER);
799: progressComponent.add(stopButton, BorderLayout.LINE_END);
800: progress.start(/*2, 5*/);
801: repositoryPanel.jPanel1.setLayout(new BorderLayout());
802: repositoryPanel.jPanel1.add(progressComponent,
803: BorderLayout.SOUTH);
804: repositoryPanel.jPanel1.revalidate();
805:
806: editable(false);
807: }
808:
809: private String getPassword() {
810: return new String(repositoryPanel.passwordTextField
811: .getPassword());
812: }
813:
814: public String getCvsRoot() {
815: return selectedCvsRoot();
816: }
817:
818: public String getScrambledPassword() {
819: if (scrambledPassword == null) {
820: String plainPassword = getPassword();
821: scrambledPassword = StandardScrambler.getInstance()
822: .scramble(plainPassword);
823: }
824: return scrambledPassword;
825: }
826: }
|