vcs: do not create fake Changes to show diff from update dialog
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / update / ShowUpdatedDiffAction.java
1 /*
2  * Copyright 2000-2014 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 com.intellij.openapi.vcs.update;
17
18 import com.intellij.diff.*;
19 import com.intellij.diff.actions.impl.GoToChangePopupBuilder;
20 import com.intellij.diff.chains.DiffRequestChain;
21 import com.intellij.diff.chains.DiffRequestProducer;
22 import com.intellij.diff.chains.DiffRequestProducerException;
23 import com.intellij.diff.contents.DiffContent;
24 import com.intellij.diff.requests.DiffRequest;
25 import com.intellij.diff.requests.SimpleDiffRequest;
26 import com.intellij.history.ByteContent;
27 import com.intellij.history.Label;
28 import com.intellij.openapi.actionSystem.*;
29 import com.intellij.openapi.progress.ProcessCanceledException;
30 import com.intellij.openapi.progress.ProgressIndicator;
31 import com.intellij.openapi.project.DumbAware;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.util.Pair;
34 import com.intellij.openapi.util.UserDataHolder;
35 import com.intellij.openapi.util.UserDataHolderBase;
36 import com.intellij.openapi.util.io.FileUtil;
37 import com.intellij.openapi.vcs.FilePath;
38 import com.intellij.openapi.vcs.FileStatus;
39 import com.intellij.openapi.vcs.VcsDataKeys;
40 import com.intellij.openapi.vcs.changes.actions.diff.ChangeGoToChangePopupAction;
41 import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
42 import com.intellij.util.Consumer;
43 import com.intellij.vcsUtil.VcsUtil;
44 import org.jetbrains.annotations.NotNull;
45 import org.jetbrains.annotations.Nullable;
46
47 import java.io.IOException;
48 import java.util.ArrayList;
49 import java.util.List;
50
51 public class ShowUpdatedDiffAction extends AnAction implements DumbAware {
52   @Override
53   public void update(AnActionEvent e) {
54     final DataContext dc = e.getDataContext();
55
56     final Presentation presentation = e.getPresentation();
57
58     //presentation.setVisible(isVisible(dc));
59     presentation.setEnabled(isVisible(dc) && isEnabled(dc));
60   }
61
62   private boolean isVisible(final DataContext dc) {
63     final Project project = CommonDataKeys.PROJECT.getData(dc);
64     return (project != null) && (VcsDataKeys.LABEL_BEFORE.getData(dc) != null) && (VcsDataKeys.LABEL_AFTER.getData(dc) != null);
65   }
66
67   private boolean isEnabled(final DataContext dc) {
68     final Iterable<Pair<VirtualFilePointer, FileStatus>> iterable = VcsDataKeys.UPDATE_VIEW_FILES_ITERABLE.getData(dc);
69     return iterable != null;
70   }
71
72   public void actionPerformed(AnActionEvent e) {
73     final DataContext dc = e.getDataContext();
74     if ((!isVisible(dc)) || (!isEnabled(dc))) return;
75
76     final Project project = CommonDataKeys.PROJECT.getData(dc);
77     final Iterable<Pair<VirtualFilePointer, FileStatus>> iterable = e.getRequiredData(VcsDataKeys.UPDATE_VIEW_FILES_ITERABLE);
78     final Label before = (Label)e.getRequiredData(VcsDataKeys.LABEL_BEFORE);
79     final Label after = (Label)e.getRequiredData(VcsDataKeys.LABEL_AFTER);
80     final String selectedUrl = VcsDataKeys.UPDATE_VIEW_SELECTED_PATH.getData(dc);
81
82     MyDiffRequestChain requestChain = new MyDiffRequestChain(project, iterable, before, after, selectedUrl);
83     DiffManager.getInstance().showDiff(project, requestChain, DiffDialogHints.FRAME);
84   }
85
86   private static class MyDiffRequestChain extends UserDataHolderBase implements DiffRequestChain, GoToChangePopupBuilder.Chain {
87     @Nullable private final Project myProject;
88     @NotNull private final Label myBefore;
89     @NotNull private final Label myAfter;
90     @NotNull private final List<MyDiffRequestProducer> myRequests = new ArrayList<MyDiffRequestProducer>();
91
92     private int myIndex;
93
94     public MyDiffRequestChain(@Nullable Project project,
95                               @NotNull Iterable<Pair<VirtualFilePointer, FileStatus>> iterable,
96                               @NotNull Label before,
97                               @NotNull Label after,
98                               @Nullable String selectedUrl) {
99       myProject = project;
100       myBefore = before;
101       myAfter = after;
102
103       int selected = -1;
104       for (Pair<VirtualFilePointer, FileStatus> pair : iterable) {
105         if (selected == -1 && pair.first.getUrl().equals(selectedUrl)) selected = myRequests.size();
106         myRequests.add(new MyDiffRequestProducer(pair.first, pair.second));
107       }
108       if (selected != -1) myIndex = selected;
109     }
110
111     @NotNull
112     @Override
113     public List<MyDiffRequestProducer> getRequests() {
114       return myRequests;
115     }
116
117     @Override
118     public int getIndex() {
119       return myIndex;
120     }
121
122     @Override
123     public void setIndex(int index) {
124       myIndex = index;
125     }
126
127     @NotNull
128     @Override
129     public AnAction createGoToChangeAction(@NotNull Consumer<Integer> onSelected) {
130       return new ChangeGoToChangePopupAction.Fake<MyDiffRequestChain>(this, myIndex, onSelected) {
131         @NotNull
132         @Override
133         protected FilePath getFilePath(int index) {
134           return myRequests.get(index).getFilePath();
135         }
136
137         @NotNull
138         @Override
139         protected FileStatus getFileStatus(int index) {
140           return myRequests.get(index).getFileStatus();
141         }
142       };
143     }
144
145     private class MyDiffRequestProducer implements DiffRequestProducer {
146       @NotNull private final VirtualFilePointer myFilePointer;
147       @NotNull private final FileStatus myFileStatus;
148       @NotNull private final FilePath myFilePath;
149
150       public MyDiffRequestProducer(@NotNull VirtualFilePointer filePointer, @NotNull FileStatus fileStatus) {
151         myFilePointer = filePointer;
152         myFileStatus = fileStatus;
153
154         myFilePath = VcsUtil.getFilePath(myFilePointer.getPresentableUrl(), false);
155       }
156
157       @NotNull
158       @Override
159       public String getName() {
160         return myFilePointer.getUrl();
161       }
162
163       @NotNull
164       public FilePath getFilePath() {
165         return myFilePath;
166       }
167
168       @NotNull
169       public FileStatus getFileStatus() {
170         return myFileStatus;
171       }
172
173       @NotNull
174       @Override
175       public DiffRequest process(@NotNull UserDataHolder context, @NotNull ProgressIndicator indicator)
176         throws DiffRequestProducerException, ProcessCanceledException {
177         try {
178           DiffContent content1;
179           DiffContent content2;
180
181           if (FileStatus.ADDED.equals(myFileStatus)) {
182             content1 = DiffContentFactory.getInstance().createEmpty();
183           }
184           else {
185             byte[] bytes1 = loadContent(myFilePointer, myBefore);
186             content1 = DiffContentFactoryImpl.getInstanceImpl().createFromBytes(myProject, myFilePath, bytes1);
187           }
188
189           if (FileStatus.DELETED.equals(myFileStatus)) {
190             content2 = DiffContentFactory.getInstance().createEmpty();
191           }
192           else {
193             byte[] bytes2 = loadContent(myFilePointer, myAfter);
194             content2 = DiffContentFactoryImpl.getInstanceImpl().createFromBytes(myProject, myFilePath, bytes2);
195           }
196
197           String title = DiffRequestFactoryImpl.getContentTitle(myFilePath);
198           return new SimpleDiffRequest(title, content1, content2, "Before update", "After update");
199         }
200         catch (IOException e) {
201           throw new DiffRequestProducerException("Can't load content", e);
202         }
203       }
204     }
205
206     @NotNull
207     private static byte[] loadContent(@NotNull VirtualFilePointer filePointer, @NotNull Label label) throws DiffRequestProducerException {
208       String path = filePointer.getPresentableUrl();
209       ByteContent byteContent = label.getByteContent(FileUtil.toSystemIndependentName(path));
210
211       if (byteContent == null || byteContent.isDirectory() || byteContent.getBytes() == null) {
212         throw new DiffRequestProducerException("Can't load content");
213       }
214
215       return byteContent.getBytes();
216     }
217   }
218 }