svn: Refactored "CreateExternalAction" - code simplified
[idea/community.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / actions / CreateExternalAction.java
1 /*
2  * Copyright 2000-2012 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.actions;
17
18 import com.intellij.openapi.actionSystem.AnActionEvent;
19 import com.intellij.openapi.actionSystem.CommonDataKeys;
20 import com.intellij.openapi.progress.ProgressIndicator;
21 import com.intellij.openapi.progress.Task;
22 import com.intellij.openapi.project.DumbAwareAction;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.vcs.*;
25 import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
26 import com.intellij.openapi.vfs.VirtualFile;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29 import org.jetbrains.idea.svn.SvnProgressCanceller;
30 import org.jetbrains.idea.svn.SvnPropertyKeys;
31 import org.jetbrains.idea.svn.SvnVcs;
32 import org.jetbrains.idea.svn.api.ClientFactory;
33 import org.jetbrains.idea.svn.api.Depth;
34 import org.jetbrains.idea.svn.dialogs.SelectCreateExternalTargetDialog;
35 import org.jetbrains.idea.svn.properties.PropertyValue;
36 import org.jetbrains.idea.svn.update.UpdateClient;
37 import org.tmatesoft.svn.core.wc.SVNRevision;
38 import org.tmatesoft.svn.core.wc2.SvnTarget;
39
40 import java.io.File;
41
42 import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces;
43 import static com.intellij.openapi.vcs.changes.ChangesUtil.getVcsForFile;
44 import static com.intellij.openapi.vfs.VfsUtilCore.virtualToIoFile;
45 import static com.intellij.util.ObjectUtils.notNull;
46 import static com.intellij.util.containers.UtilKt.getIfSingle;
47 import static org.jetbrains.idea.svn.SvnBundle.message;
48 import static org.jetbrains.idea.svn.commandLine.CommandUtil.escape;
49 import static org.jetbrains.idea.svn.properties.ExternalsDefinitionParser.parseExternalsProperty;
50
51 public class CreateExternalAction extends DumbAwareAction {
52   public CreateExternalAction() {
53     super(message("svn.create.external.below.action"), message("svn.create.external.below.description"), null);
54   }
55
56   @Override
57   public void actionPerformed(@NotNull AnActionEvent e) {
58     Project project = e.getRequiredData(CommonDataKeys.PROJECT);
59     VirtualFile file = notNull(getIfSingle(e.getData(VcsDataKeys.VIRTUAL_FILE_STREAM)));
60     SelectCreateExternalTargetDialog dialog = new SelectCreateExternalTargetDialog(project, file);
61
62     if (dialog.showAndGet()) {
63       String url = dialog.getSelectedURL();
64       boolean checkout = dialog.isCheckout();
65       String target = dialog.getLocalTarget().trim();
66
67       new Task.Backgroundable(project, "Creating External") {
68         @Override
69         public void run(@NotNull ProgressIndicator indicator) {
70           doInBackground(project, file, url, checkout, target);
71         }
72       }.queue();
73     }
74   }
75
76   private static void doInBackground(@NotNull Project project, @NotNull VirtualFile file, String url, boolean checkout, String target) {
77     SvnVcs vcs = SvnVcs.getInstance(project);
78     VcsDirtyScopeManager dirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
79     File ioFile = virtualToIoFile(file);
80
81     try {
82       addToExternalProperty(vcs, ioFile, target, url);
83       dirtyScopeManager.fileDirty(file);
84
85       if (checkout) {
86         UpdateClient client = vcs.getFactory(ioFile).createUpdateClient();
87         client.setEventHandler(new SvnProgressCanceller());
88         client.doUpdate(ioFile, SVNRevision.HEAD, Depth.UNKNOWN, false, false);
89         file.refresh(true, true, () -> dirtyScopeManager.dirDirtyRecursively(file));
90       }
91     }
92     catch (VcsException e) {
93       AbstractVcsHelper.getInstance(project).showError(e, "Create External");
94     }
95   }
96
97   public static void addToExternalProperty(@NotNull SvnVcs vcs, @NotNull File ioFile, String target, String url) throws VcsException {
98     ClientFactory factory = vcs.getFactory(ioFile);
99     PropertyValue propertyValue =
100       factory.createPropertyClient().getProperty(SvnTarget.fromFile(ioFile), SvnPropertyKeys.SVN_EXTERNALS, false, SVNRevision.UNDEFINED);
101     boolean hasExternals = propertyValue != null && !isEmptyOrSpaces(propertyValue.toString());
102     String newExternals = "";
103
104     if (hasExternals) {
105       String externalsForTarget = parseExternalsProperty(propertyValue.toString()).get(target);
106
107       if (externalsForTarget != null) {
108         throw new VcsException("Selected destination conflicts with existing: " + externalsForTarget);
109       }
110
111       newExternals = propertyValue.toString().trim() + "\n";
112     }
113
114     newExternals += escape(url) + " " + target;
115     factory.createPropertyClient()
116       .setProperty(ioFile, SvnPropertyKeys.SVN_EXTERNALS, PropertyValue.create(newExternals), Depth.EMPTY, false);
117   }
118
119   @Override
120   public void update(@NotNull AnActionEvent e) {
121     Project project = e.getProject();
122     boolean visible = project != null && isSvnActive(project);
123     boolean enabled = visible && isEnabled(project, getIfSingle(e.getData(VcsDataKeys.VIRTUAL_FILE_STREAM)));
124
125     e.getPresentation().setVisible(visible);
126     e.getPresentation().setEnabled(enabled);
127   }
128
129   private static boolean isSvnActive(@NotNull Project project) {
130     return ProjectLevelVcsManager.getInstance(project).checkVcsIsActive(SvnVcs.VCS_NAME);
131   }
132
133   private static boolean isEnabled(@NotNull Project project, @Nullable VirtualFile file) {
134     return file != null &&
135            file.isDirectory() &&
136            getVcsForFile(file, project) instanceof SvnVcs &&
137            isEnabled(FileStatusManager.getInstance(project).getStatus(file));
138   }
139
140   private static boolean isEnabled(@Nullable FileStatus status) {
141     return status != null &&
142            !FileStatus.DELETED.equals(status) &&
143            !FileStatus.IGNORED.equals(status) &&
144            !FileStatus.MERGED_WITH_PROPERTY_CONFLICTS.equals(status) &&
145            !FileStatus.OBSOLETE.equals(status) &&
146            !FileStatus.UNKNOWN.equals(status);
147   }
148 }