Merge remote-tracking branch 'origin/master'
[idea/community.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / update / SvnUpdateRootOptionsPanel.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.idea.svn.update;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.options.ConfigurationException;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.ui.TextFieldWithBrowseButton;
22 import com.intellij.openapi.vcs.FilePath;
23 import org.jetbrains.annotations.Nullable;
24 import org.jetbrains.idea.svn.*;
25 import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup;
26 import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager;
27 import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
28 import org.jetbrains.idea.svn.commandLine.SvnBindException;
29 import org.jetbrains.idea.svn.dialogs.SelectLocationDialog;
30 import org.jetbrains.idea.svn.history.SvnChangeList;
31 import org.jetbrains.idea.svn.history.SvnRepositoryLocation;
32 import org.tmatesoft.svn.core.SVNException;
33 import org.tmatesoft.svn.core.SVNURL;
34 import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
35 import org.tmatesoft.svn.core.wc.SVNRevision;
36
37 import javax.swing.*;
38 import java.awt.*;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.util.Collection;
42
43 public class SvnUpdateRootOptionsPanel implements SvnPanel{
44   private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.update.SvnUpdateRootOptionsPanel.SvnUpdateRootOptionsPanel");
45   private TextFieldWithBrowseButton myURLText;
46   private JCheckBox myRevisionBox;
47   private TextFieldWithBrowseButton myRevisionText;
48
49   private final SvnVcs myVcs;
50   private JPanel myPanel;
51   private final FilePath myRoot;
52   private JCheckBox myUpdateToSpecificUrl;
53   private TextFieldWithBrowseButton myBranchField;
54   private JLabel myBranchLabel;
55   private JLabel myUrlLabel;
56   private JLabel myCopyType;
57   @Nullable private SVNURL mySourceUrl;
58
59   public SvnUpdateRootOptionsPanel(FilePath root, final SvnVcs vcs, Collection<FilePath> roots) {
60     myRoot = root;
61     myVcs = vcs;
62
63     myURLText.setEditable(true);
64     myURLText.addActionListener(new ActionListener() {
65       public void actionPerformed(ActionEvent e) {
66         chooseUrl();
67       }
68     });
69
70     myBranchField.setEditable(false);
71     myBranchField.addActionListener(new ActionListener() {
72       public void actionPerformed(final ActionEvent e) {
73         chooseBranch();
74       }
75     });
76     myBranchLabel.setLabelFor(myBranchField);
77     myUrlLabel.setLabelFor(myURLText);
78
79     myUpdateToSpecificUrl.addActionListener(new ActionListener() {
80       public void actionPerformed(ActionEvent e) {
81         if (myUpdateToSpecificUrl.isSelected()) {
82           myURLText.setEnabled(true);
83           myBranchField.setEnabled(mySourceUrl != null);
84         } else {
85           myURLText.setEnabled(false);
86           myBranchField.setEnabled(false);
87         }
88       }
89     });
90
91     myRevisionBox.addActionListener(new ActionListener() {
92       public void actionPerformed(ActionEvent e) {
93         if (e.getSource() == myRevisionBox) {
94           myRevisionText.setEnabled(myRevisionBox.isSelected());
95           if (myRevisionBox.isSelected()) {
96             if (myRevisionText.getText().trim().isEmpty()) {
97               myRevisionText.setText("HEAD");
98             }
99             myRevisionText.getTextField().selectAll();
100             myRevisionText.requestFocus();
101           }
102         }
103       }
104     });
105
106     myRevisionText.addActionListener(new ActionListener() {
107       public void actionPerformed(ActionEvent e) {
108         final Project project = vcs.getProject();
109         // todo check whether ok; rather shoudl be used if checkbox is turned on
110         final SvnRepositoryLocation location = new SvnRepositoryLocation(myURLText.getText());
111         final SvnChangeList repositoryVersion = SvnSelectRevisionUtil.chooseCommittedChangeList(project, location, myRoot.getVirtualFile());
112         if (repositoryVersion != null) {
113           myRevisionText.setText(String.valueOf(repositoryVersion.getNumber()));
114         }
115       }
116     });
117
118     myRevisionText.setText(SVNRevision.HEAD.toString());
119     myRevisionText.getTextField().selectAll();
120     myRevisionText.setEnabled(myRevisionBox.isSelected());
121     myURLText.setEnabled(myUpdateToSpecificUrl.isSelected());
122     myBranchField.setEnabled(myUpdateToSpecificUrl.isSelected() && (mySourceUrl != null));
123
124     final boolean revisionCanBeSpecifiedForRoot = !FilePathUtil.isNested(roots, myRoot) || isRevisionCanBeSpecifiedForRoot();
125     myRevisionBox.setEnabled(revisionCanBeSpecifiedForRoot);
126     myRevisionText.setEnabled(revisionCanBeSpecifiedForRoot);
127     myCopyType.setVisible(! revisionCanBeSpecifiedForRoot);
128     myCopyType.setFont(myCopyType.getFont().deriveFont(Font.ITALIC));
129     myUpdateToSpecificUrl.setEnabled(revisionCanBeSpecifiedForRoot);
130   }
131
132   private boolean isRevisionCanBeSpecifiedForRoot() {
133     final RootUrlInfo info = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myRoot.getIOFile());
134     if (info != null) {
135       boolean isExternalOrSwitched = NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType());
136       if (isExternalOrSwitched) {
137         myCopyType.setText(info.getType().getName() + " copy");
138       }
139       return !isExternalOrSwitched;
140     }
141     return true;
142   }
143
144   private void chooseBranch() {
145     if (mySourceUrl == null) {
146       myBranchField.setEnabled(false);
147       return;
148     }
149     SelectBranchPopup.show(myVcs.getProject(), myRoot.getVirtualFile(), new SelectBranchPopup.BranchSelectedCallback() {
150       public void branchSelected(final Project project, final SvnBranchConfigurationNew configuration, final String url, final long revision) {
151         // TODO: It seems that we could reuse configuration passed as parameter to this callback
152         SvnBranchConfigurationNew branchConfiguration = getBranchConfiguration();
153         String branchRelativeUrl = branchConfiguration != null ? branchConfiguration.getRelativeUrl(mySourceUrl.toString()) : null;
154
155         if (mySourceUrl == null || branchRelativeUrl == null) {
156           myBranchField.setText("");
157         }
158         else {
159           try {
160             myURLText.setText(SVNURL.parseURIEncoded(url).appendPath(branchRelativeUrl, true).toDecodedString());
161           }
162           catch (SVNException e) {
163             LOG.error(e);
164           }
165           myBranchField.setText(SVNPathUtil.tail(url));
166         }
167       }
168     }, SvnBundle.message("select.branch.popup.general.title"), myPanel);
169   }
170
171   private void chooseUrl() {
172     SVNURL selected = SelectLocationDialog.selectLocation(myVcs.getProject(), myURLText.getText());
173     if (selected != null) {
174       myURLText.setText(selected.toDecodedString());
175     }
176   }
177
178   public JPanel getPanel() {
179     return myPanel;
180   }
181
182   @Nullable
183   private SVNURL getBranchForUrl(@Nullable SVNURL url) {
184     final RootUrlInfo rootInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myRoot.getIOFile());
185
186     return rootInfo != null && url != null ? SvnUtil.getBranchForUrl(myVcs, rootInfo.getVirtualFile(), url) : null;
187   }
188
189   @Nullable
190   private SvnBranchConfigurationNew getBranchConfiguration() {
191     final RootUrlInfo rootInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myRoot.getIOFile());
192
193     return rootInfo != null ? SvnBranchConfigurationManager.getInstance(myVcs.getProject()).get(rootInfo.getVirtualFile()) : null;
194   }
195
196   public void reset(final SvnConfiguration configuration) {
197     final UpdateRootInfo rootInfo = configuration.getUpdateRootInfo(myRoot.getIOFile(), myVcs);
198
199     mySourceUrl = rootInfo.getUrl();
200     SVNURL branchUrl = getBranchForUrl(mySourceUrl);
201     if (branchUrl != null) {
202       myBranchField.setText(SVNPathUtil.tail(branchUrl.toDecodedString()));
203     }
204
205     myURLText.setText(mySourceUrl != null ? mySourceUrl.toDecodedString() : "");
206     myRevisionBox.setSelected(rootInfo.isUpdateToRevision());
207     myRevisionText.setText(rootInfo.getRevision().toString());
208     myUpdateToSpecificUrl.setSelected(false);
209     myRevisionText.setEnabled(myRevisionBox.isSelected());
210     myURLText.setEnabled(myUpdateToSpecificUrl.isSelected());
211     myBranchField.setEnabled(myUpdateToSpecificUrl.isSelected() && (mySourceUrl != null));
212   }
213
214   public void apply(final SvnConfiguration configuration) throws ConfigurationException {
215     final UpdateRootInfo rootInfo = configuration.getUpdateRootInfo(myRoot.getIOFile(), myVcs);
216     if (myUpdateToSpecificUrl.isSelected()) {
217       try {
218         rootInfo.setUrl(SvnUtil.createUrl(myURLText.getText(), false));
219       }
220       catch (SvnBindException e) {
221         throw new ConfigurationException("Invalid url: " + myURLText.getText());
222       }
223     }
224
225     rootInfo.setUpdateToRevision(myRevisionBox.isSelected());
226     final SVNRevision revision = SVNRevision.parse(myRevisionText.getText());
227      if (!revision.isValid()) {
228       throw new ConfigurationException(SvnBundle.message("invalid.svn.revision.error.message", myRevisionText.getText()));
229     }
230     rootInfo.setRevision(revision);
231   }
232
233   public boolean canApply() {
234     return true;
235   }
236 }