5bd74399530292ad5fe113fbea2903076842f295
[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.actionSystem.DataContext;
21 import com.intellij.openapi.progress.ProgressIndicator;
22 import com.intellij.openapi.progress.ProgressManager;
23 import com.intellij.openapi.progress.Task;
24 import com.intellij.openapi.project.DumbAwareAction;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.ui.DialogWrapper;
27 import com.intellij.openapi.util.text.StringUtil;
28 import com.intellij.openapi.vcs.*;
29 import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
30 import com.intellij.openapi.vfs.VirtualFile;
31 import com.intellij.vcsUtil.ActionExecuteHelper;
32 import com.intellij.vcsUtil.ActionStateConsumer;
33 import com.intellij.vcsUtil.ActionUpdateHelper;
34 import com.intellij.vcsUtil.VcsUtil;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.idea.svn.SvnBundle;
37 import org.jetbrains.idea.svn.SvnPropertyKeys;
38 import org.jetbrains.idea.svn.SvnVcs;
39 import org.jetbrains.idea.svn.api.ClientFactory;
40 import org.jetbrains.idea.svn.api.Depth;
41 import org.jetbrains.idea.svn.api.ProgressEvent;
42 import org.jetbrains.idea.svn.api.ProgressTracker;
43 import org.jetbrains.idea.svn.commandLine.CommandUtil;
44 import org.jetbrains.idea.svn.dialogs.SelectCreateExternalTargetDialog;
45 import org.jetbrains.idea.svn.properties.ExternalsDefinitionParser;
46 import org.jetbrains.idea.svn.properties.PropertyValue;
47 import org.jetbrains.idea.svn.update.UpdateClient;
48 import org.tmatesoft.svn.core.SVNCancelException;
49 import org.tmatesoft.svn.core.SVNException;
50 import org.tmatesoft.svn.core.wc.SVNRevision;
51 import org.tmatesoft.svn.core.wc2.SvnTarget;
52
53 import java.io.File;
54 import java.util.Map;
55
56 /**
57  * Created with IntelliJ IDEA.
58  * User: Irina.Chernushina
59  * Date: 7/6/12
60  * Time: 7:21 PM
61  */
62 public class CreateExternalAction extends DumbAwareAction {
63   public CreateExternalAction() {
64     super(SvnBundle.message("svn.create.external.below.action"), SvnBundle.message("svn.create.external.below.description"), null);
65   }
66
67   @Override
68   public void actionPerformed(AnActionEvent e) {
69     final ActionExecuteHelper helper = new ActionExecuteHelper();
70     checkState(e, helper);
71     if (! helper.isOk()) return;
72
73     final DataContext dc = e.getDataContext();
74     final Project project = CommonDataKeys.PROJECT.getData(dc);
75     final VirtualFile vf = CommonDataKeys.VIRTUAL_FILE.getData(dc);
76
77     //1 select target
78     final SelectCreateExternalTargetDialog dialog = new SelectCreateExternalTargetDialog(project, vf);
79     dialog.show();
80     if (DialogWrapper.OK_EXIT_CODE != dialog.getExitCode()) return;
81
82     final String url = dialog.getSelectedURL();
83     final boolean checkout = dialog.isCheckout();
84     final String target = dialog.getLocalTarget().trim();
85
86     ProgressManager.getInstance().run(new Task.Backgroundable(project, "Creating External", true, null) {
87       @Override
88       public void run(@NotNull ProgressIndicator indicator) {
89         doInBackground(project, vf, url, checkout, target);
90       }
91     });
92   }
93
94   private void doInBackground(Project project, VirtualFile vf, String url, boolean checkout, String target) {
95     final SvnVcs vcs = SvnVcs.getInstance(project);
96     try {
97       final File ioFile = new File(vf.getPath());
98       if (addToExternalProperty(vcs, ioFile, target, url)) return;
99       final VcsDirtyScopeManager dirtyScopeManager = VcsDirtyScopeManager.getInstance(project);
100       final FilePath filePath = VcsUtil.getFilePath(ioFile, true);
101       dirtyScopeManager.fileDirty(filePath);
102       if (checkout) {
103         // +-
104         final UpdateClient client = vcs.getFactory(ioFile).createUpdateClient();
105         client.setEventHandler(new ProgressTracker() {
106           @Override
107           public void consume(ProgressEvent event) throws SVNException {
108           }
109
110           @Override
111           public void checkCancelled() throws SVNCancelException {
112             final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
113             if (pi != null && pi.isCanceled()) throw new SVNCancelException();
114           }
115         });
116         client.doUpdate(ioFile, SVNRevision.HEAD, Depth.UNKNOWN, false, false);
117         vf.refresh(true, true, new Runnable() {
118           @Override
119           public void run() {
120             dirtyScopeManager.dirDirtyRecursively(filePath);
121           }
122         });
123       }
124     }
125     catch (SVNException e1) {
126       AbstractVcsHelper.getInstance(project).showError(new VcsException(e1), "Create External");
127     }
128     catch (VcsException e1) {
129       AbstractVcsHelper.getInstance(project).showError(e1, "Create External");
130     }
131   }
132
133   public static boolean addToExternalProperty(@NotNull SvnVcs vcs, @NotNull File ioFile, String target, String url)
134     throws SVNException, VcsException {
135     ClientFactory factory = vcs.getFactory(ioFile);
136     PropertyValue propertyValue = factory.createPropertyClient().getProperty(SvnTarget.fromFile(ioFile), SvnPropertyKeys.SVN_EXTERNALS,
137                                                                               false, SVNRevision.UNDEFINED);
138     String newValue;
139     if (propertyValue != null && !StringUtil.isEmptyOrSpaces(propertyValue.toString())) {
140       Map<String, String> externalsMap = ExternalsDefinitionParser.parseExternalsProperty(propertyValue.toString());
141       String externalsForTarget = externalsMap.get(target);
142
143       if (externalsForTarget != null) {
144         AbstractVcsHelper.getInstance(vcs.getProject()).showError(
145           new VcsException("Selected destination conflicts with existing: " + externalsForTarget), "Create External");
146         return true;
147       }
148       final String string = createExternalDefinitionString(url, target);
149       newValue = propertyValue.toString().trim() + "\n" + string;
150     } else {
151       newValue = createExternalDefinitionString(url, target);
152     }
153     factory.createPropertyClient().setProperty(ioFile, SvnPropertyKeys.SVN_EXTERNALS, PropertyValue.create(newValue), Depth.EMPTY, false);
154     return false;
155   }
156
157   public static String createExternalDefinitionString(String url, String target) {
158     return CommandUtil.escape(url) + " " + target;
159   }
160
161   @Override
162   public void update(AnActionEvent e) {
163     final ActionUpdateHelper helper = new ActionUpdateHelper();
164     checkState(e, helper);
165     helper.apply(e);
166   }
167
168   private void checkState(AnActionEvent e, final ActionStateConsumer sc) {
169     final DataContext dc = e.getDataContext();
170     final Project project = CommonDataKeys.PROJECT.getData(dc);
171     if (project == null) {
172       sc.hide();
173       return;
174     }
175     final ProjectLevelVcsManager manager = ProjectLevelVcsManager.getInstance(project);
176     if (!manager.checkVcsIsActive(SvnVcs.getKey().getName())) {
177       sc.hide();
178       return;
179     }
180
181     final VirtualFile vf = CommonDataKeys.VIRTUAL_FILE.getData(dc);
182     final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dc);
183     if (vf == null || files == null || files.length != 1 || ! vf.isDirectory()) {
184       sc.disable();
185       return;
186     }
187
188     final AbstractVcs vcsFor = manager.getVcsFor(vf);
189     if (vcsFor == null || ! SvnVcs.getKey().equals(vcsFor.getKeyInstanceMethod())) {
190       sc.disable();
191       return;
192     }
193
194     final FileStatus status = FileStatusManager.getInstance(project).getStatus(vf);
195     if (status == null || FileStatus.DELETED.equals(status) || FileStatus.IGNORED.equals(status) ||
196         FileStatus.MERGED_WITH_PROPERTY_CONFLICTS.equals(status) || FileStatus.OBSOLETE.equals(status) || FileStatus.UNKNOWN.equals(status)) {
197       sc.disable();
198       return;
199     }
200     sc.enable();
201   }
202 }