/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.update;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.wm.IdeFocusManager;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.dialogs.SelectLocationDialog;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.jetbrains.idea.svn.history.SvnRepositoryLocation;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.wc.SVNRevision;
import javax.swing.*;
import java.awt.*;
import java.util.Collection;
public class SvnUpdateRootOptionsPanel implements SvnPanel{
private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.update.SvnUpdateRootOptionsPanel.SvnUpdateRootOptionsPanel");
private TextFieldWithBrowseButton myURLText;
private JCheckBox myRevisionBox;
private TextFieldWithBrowseButton myRevisionText;
private final SvnVcs myVcs;
private JPanel myPanel;
private final FilePath myRoot;
private JCheckBox myUpdateToSpecificUrl;
private TextFieldWithBrowseButton myBranchField;
private JLabel myBranchLabel;
private JLabel myUrlLabel;
private JLabel myCopyType;
@Nullable private SVNURL mySourceUrl;
public SvnUpdateRootOptionsPanel(FilePath root, final SvnVcs vcs, Collection<FilePath> roots) {
myRoot = root;
myVcs = vcs;
myURLText.setEditable(true);
myURLText.addActionListener(e -> chooseUrl());
myBranchField.setEditable(false);
myBranchField.addActionListener(e -> chooseBranch());
myBranchLabel.setLabelFor(myBranchField);
myUrlLabel.setLabelFor(myURLText);
myUpdateToSpecificUrl.addActionListener(e -> {
if (myUpdateToSpecificUrl.isSelected()) {
myURLText.setEnabled(true);
myBranchField.setEnabled(mySourceUrl != null);
}
else {
myURLText.setEnabled(false);
myBranchField.setEnabled(false);
}
});
myRevisionBox.addActionListener(e -> {
if (e.getSource() == myRevisionBox) {
myRevisionText.setEnabled(myRevisionBox.isSelected());
if (myRevisionBox.isSelected()) {
if (myRevisionText.getText().trim().isEmpty()) {
myRevisionText.setText("HEAD");
}
myRevisionText.getTextField().selectAll();
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
IdeFocusManager.getGlobalInstance().requestFocus(myRevisionText, true);
});
}
}
});
myRevisionText.addActionListener(e -> {
final Project project = vcs.getProject();
// todo check whether ok; rather shoudl be used if checkbox is turned on
final SvnRepositoryLocation location = new SvnRepositoryLocation(myURLText.getText());
final SvnChangeList repositoryVersion = SvnSelectRevisionUtil.chooseCommittedChangeList(project, location, myRoot.getVirtualFile());
if (repositoryVersion != null) {
myRevisionText.setText(String.valueOf(repositoryVersion.getNumber()));
}
});
myRevisionText.setText(SVNRevision.HEAD.toString());
myRevisionText.getTextField().selectAll();
myRevisionText.setEnabled(myRevisionBox.isSelected());
myURLText.setEnabled(myUpdateToSpecificUrl.isSelected());
myBranchField.setEnabled(myUpdateToSpecificUrl.isSelected() && (mySourceUrl != null));
final boolean revisionCanBeSpecifiedForRoot = !FilePathUtil.isNested(roots, myRoot) || isRevisionCanBeSpecifiedForRoot();
myRevisionBox.setEnabled(revisionCanBeSpecifiedForRoot);
myRevisionText.setEnabled(revisionCanBeSpecifiedForRoot);
myCopyType.setVisible(! revisionCanBeSpecifiedForRoot);
myCopyType.setFont(myCopyType.getFont().deriveFont(Font.ITALIC));
myUpdateToSpecificUrl.setEnabled(revisionCanBeSpecifiedForRoot);
}
private boolean isRevisionCanBeSpecifiedForRoot() {
final RootUrlInfo info = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myRoot.getIOFile());
if (info != null) {
boolean isExternalOrSwitched = NestedCopyType.external.equals(info.getType()) || NestedCopyType.switched.equals(info.getType());
if (isExternalOrSwitched) {
myCopyType.setText(info.getType().getName() + " copy");
}
return !isExternalOrSwitched;
}
return true;
}
private void chooseBranch() {
if (mySourceUrl == null) {
myBranchField.setEnabled(false);
return;
}
SelectBranchPopup.show(myVcs.getProject(), myRoot.getVirtualFile(), (project, configuration, url, revision) -> {
// TODO: It seems that we could reuse configuration passed as parameter to this callback
SvnBranchConfigurationNew branchConfiguration = getBranchConfiguration();
String branchRelativeUrl = branchConfiguration != null ? branchConfiguration.getRelativeUrl(mySourceUrl.toString()) : null;
if (mySourceUrl == null || branchRelativeUrl == null) {
myBranchField.setText("");
}
else {
try {
myURLText.setText(SVNURL.parseURIEncoded(url).appendPath(branchRelativeUrl, true).toDecodedString());
}
catch (SVNException e) {
LOG.error(e);
}
myBranchField.setText(SVNPathUtil.tail(url));
}
}, SvnBundle.message("select.branch.popup.general.title"), myPanel);
}
private void chooseUrl() {
SVNURL selected = SelectLocationDialog.selectLocation(myVcs.getProject(), myURLText.getText());
if (selected != null) {
myURLText.setText(selected.toDecodedString());
}
}
public JPanel getPanel() {
return myPanel;
}
@Nullable
private SVNURL getBranchForUrl(@Nullable SVNURL url) {
final RootUrlInfo rootInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myRoot.getIOFile());
return rootInfo != null && url != null ? SvnUtil.getBranchForUrl(myVcs, rootInfo.getVirtualFile(), url) : null;
}
@Nullable
private SvnBranchConfigurationNew getBranchConfiguration() {
final RootUrlInfo rootInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myRoot.getIOFile());
return rootInfo != null ? SvnBranchConfigurationManager.getInstance(myVcs.getProject()).get(rootInfo.getVirtualFile()) : null;
}
public void reset(final SvnConfiguration configuration) {
final UpdateRootInfo rootInfo = configuration.getUpdateRootInfo(myRoot.getIOFile(), myVcs);
mySourceUrl = rootInfo.getUrl();
SVNURL branchUrl = getBranchForUrl(mySourceUrl);
if (branchUrl != null) {
myBranchField.setText(SVNPathUtil.tail(branchUrl.toDecodedString()));
}
myURLText.setText(mySourceUrl != null ? mySourceUrl.toDecodedString() : "");
myRevisionBox.setSelected(rootInfo.isUpdateToRevision());
myRevisionText.setText(rootInfo.getRevision().toString());
myUpdateToSpecificUrl.setSelected(false);
myRevisionText.setEnabled(myRevisionBox.isSelected());
myURLText.setEnabled(myUpdateToSpecificUrl.isSelected());
myBranchField.setEnabled(myUpdateToSpecificUrl.isSelected() && (mySourceUrl != null));
}
public void apply(final SvnConfiguration configuration) throws ConfigurationException {
final UpdateRootInfo rootInfo = configuration.getUpdateRootInfo(myRoot.getIOFile(), myVcs);
if (myUpdateToSpecificUrl.isSelected()) {
try {
rootInfo.setUrl(SvnUtil.createUrl(myURLText.getText(), false));
}
catch (SvnBindException e) {
throw new ConfigurationException("Invalid url: " + myURLText.getText());
}
}
rootInfo.setUpdateToRevision(myRevisionBox.isSelected());
final SVNRevision revision = SVNRevision.parse(myRevisionText.getText());
if (!revision.isValid()) {
throw new ConfigurationException(SvnBundle.message("invalid.svn.revision.error.message", myRevisionText.getText()));
}
rootInfo.setRevision(revision);
}
public boolean canApply() {
return true;
}
}