1 // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.vcs.changes.actions.diff;
4 import com.intellij.codeInsight.daemon.OutsidersPsiFileSupport;
5 import com.intellij.diff.DiffVcsDataKeys;
6 import com.intellij.diff.contents.DiffContent;
7 import com.intellij.diff.contents.DocumentContent;
8 import com.intellij.diff.contents.EmptyContent;
9 import com.intellij.diff.contents.FileContent;
10 import com.intellij.diff.requests.ContentDiffRequest;
11 import com.intellij.diff.requests.DiffRequest;
12 import com.intellij.diff.tools.util.DiffDataKeys;
13 import com.intellij.diff.util.DiffUserDataKeysEx;
14 import com.intellij.openapi.actionSystem.AnActionEvent;
15 import com.intellij.openapi.actionSystem.AnActionExtensionProvider;
16 import com.intellij.openapi.diff.DiffBundle;
17 import com.intellij.openapi.fileTypes.FileType;
18 import com.intellij.openapi.util.Pair;
19 import com.intellij.openapi.util.text.StringUtil;
20 import com.intellij.openapi.vcs.FilePath;
21 import com.intellij.openapi.vcs.changes.Change;
22 import com.intellij.openapi.vcs.changes.ContentRevision;
23 import com.intellij.openapi.vcs.changes.CurrentContentRevision;
24 import com.intellij.openapi.vcs.changes.SimpleContentRevision;
25 import com.intellij.openapi.vcs.changes.actions.CreatePatchFromChangesAction;
26 import com.intellij.openapi.vcs.history.VcsRevisionNumber;
27 import com.intellij.openapi.vfs.VirtualFile;
28 import com.intellij.util.ObjectUtils;
29 import com.intellij.util.PathUtil;
30 import com.intellij.vcsUtil.VcsUtil;
31 import org.jetbrains.annotations.Nls;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.Objects;
39 public class DiffViewerCreatePatchActionProvider implements AnActionExtensionProvider {
40 private final boolean mySilentClipboard;
42 private DiffViewerCreatePatchActionProvider(boolean silentClipboard) {
43 mySilentClipboard = silentClipboard;
46 public static class Dialog extends DiffViewerCreatePatchActionProvider {
52 public static class Clipboard extends DiffViewerCreatePatchActionProvider {
59 public boolean isActive(@NotNull AnActionEvent e) {
60 return e.getData(DiffDataKeys.DIFF_VIEWER) != null;
64 public void update(@NotNull AnActionEvent e) {
65 DiffRequest request = e.getData(DiffDataKeys.DIFF_REQUEST);
66 boolean isEnabled = request != null && isSupported(request);
67 e.getPresentation().setEnabledAndVisible(isEnabled);
71 public void actionPerformed(@NotNull AnActionEvent e) {
72 DiffRequest request = Objects.requireNonNull(e.getData(DiffDataKeys.DIFF_REQUEST));
73 Change change = createChange(request);
74 CreatePatchFromChangesAction.createPatch(e.getProject(), null, Collections.singletonList(change), mySilentClipboard);
77 private static boolean isSupported(@NotNull DiffRequest request) {
78 if (request.getUserData(ChangeDiffRequestProducer.CHANGE_KEY) != null) return true;
80 ContentDiffRequest contentRequest = ObjectUtils.tryCast(request, ContentDiffRequest.class);
81 if (contentRequest == null) return false;
83 List<DiffContent> contents = contentRequest.getContents();
84 if (contents.size() != 2) return false;
86 for (DiffContent content : contents) {
87 boolean canShow = content instanceof DocumentContent ||
88 content instanceof EmptyContent;
89 if (!canShow) return false;
95 private static Change createChange(@NotNull DiffRequest request) {
96 Change change = request.getUserData(ChangeDiffRequestProducer.CHANGE_KEY);
97 if (change != null) return change;
99 List<DiffContent> contents = ((ContentDiffRequest)request).getContents();
100 List<@Nls String> titles = ((ContentDiffRequest)request).getContentTitles();
101 assert contents.size() == 2;
102 String bTitle = ObjectUtils.chooseNotNull(titles.get(0), DiffBundle.message("diff.version.title.before"));
103 String aTitle = ObjectUtils.chooseNotNull(titles.get(1), DiffBundle.message("diff.version.title.after"));
104 ContentRevision bRev = createRevision(contents.get(0), bTitle);
105 ContentRevision aRev = createRevision(contents.get(1), aTitle);
106 return new Change(bRev, aRev);
110 private static ContentRevision createRevision(@NotNull DiffContent content, @NotNull String title) {
111 if (content instanceof EmptyContent) return null;
112 if (content instanceof FileContent) {
113 VirtualFile file = ((FileContent)content).getFile();
114 if (file.isInLocalFileSystem()) {
115 return new CurrentContentRevision(VcsUtil.getFilePath(file));
118 if (content instanceof DocumentContent) {
119 String text = ((DocumentContent)content).getDocument().getText();
121 Pair<FilePath, VcsRevisionNumber> info = content.getUserData(DiffVcsDataKeys.REVISION_INFO);
123 return new SimpleContentRevision(text, info.first, info.second.asString());
126 return new SimpleContentRevision(text, guessFilePath(content, title), "");
128 throw new IllegalStateException(content.toString());
132 private static FilePath guessFilePath(@NotNull DiffContent content, @NotNull String title) {
133 if (content instanceof FileContent) {
134 VirtualFile file = ((FileContent)content).getFile();
135 String path = OutsidersPsiFileSupport.getOriginalFilePath(file);
136 if (path != null) return VcsUtil.getFilePath(path);
139 String fileName = content.getUserData(DiffUserDataKeysEx.FILE_NAME);
140 if (fileName == null && content instanceof DocumentContent) {
141 VirtualFile highlightFile = ((DocumentContent)content).getHighlightFile();
142 fileName = highlightFile != null ? highlightFile.getName() : null;
144 if (fileName != null) return VcsUtil.getFilePath(fileName);
146 FileType fileType = content.getContentType();
147 String ext = fileType != null ? fileType.getDefaultExtension() : null;
148 if (StringUtil.isEmptyOrSpaces(ext)) ext = "tmp";
150 String path = PathUtil.suggestFileName(title + "." + ext, true, false);
151 return VcsUtil.getFilePath(path);