blob: f2678bd258d0fbfc821f57a4d252b78061dd9262 [file] [log] [blame]
/*
* Copyright 2000-2013 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 com.intellij.openapi.vcs.changes.actions;
import com.intellij.CommonBundle;
import com.intellij.diff.FileAwareSimpleContent;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.DiffContent;
import com.intellij.openapi.diff.FileContent;
import com.intellij.openapi.diff.SimpleContent;
import com.intellij.openapi.diff.SimpleDiffRequest;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.ex.FileTypeChooser;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ChangeDiffRequestPresentable implements DiffRequestPresentable {
private final Project myProject;
private final Change myChange;
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.actions.ChangeDiffRequestPresentable");
// I don't like that much
private boolean myIgnoreDirectoryFlag;
public ChangeDiffRequestPresentable(final Project project, final Change change) {
myChange = change;
myProject = project;
}
public Change getChange() {
return myChange;
}
public void setIgnoreDirectoryFlag(boolean ignoreDirectoryFlag) {
myIgnoreDirectoryFlag = ignoreDirectoryFlag;
}
public MyResult step(DiffChainContext context) {
final SimpleDiffRequest request = new SimpleDiffRequest(myProject, null);
final List<String> errSb = new ArrayList<String>();
if (! canShowChange(context, errSb)) {
return new MyResult(request, DiffPresentationReturnValue.removeFromList, StringUtil.join(errSb, "\n"));
}
if (! loadCurrentContents(request, myChange)) return new MyResult(request, DiffPresentationReturnValue.quit);
return new MyResult(request, DiffPresentationReturnValue.useRequest);
}
@Override
public String getPathPresentation() {
return ChangesUtil.getFilePath(myChange).getPath();
}
@Override
public void haveStuff() throws VcsException {
final List<String> errSb = new ArrayList<String>();
final boolean canShow = checkContentsAvailable(myChange.getBeforeRevision(), myChange.getAfterRevision(), errSb);
if (! canShow) {
throw new VcsException(StringUtil.join(errSb, "\n"));
}
}
public List<? extends AnAction> createActions(DiffExtendUIFactory uiFactory) {
return uiFactory.createActions(myChange);
}
private boolean loadCurrentContents(final SimpleDiffRequest request, final Change change) {
final ContentRevision bRev = change.getBeforeRevision();
final ContentRevision aRev = change.getAfterRevision();
String beforePath = bRev != null ? bRev.getFile().getPath() : null;
String afterPath = aRev != null ? aRev.getFile().getPath() : null;
String title;
if (beforePath != null && afterPath != null && !beforePath.equals(afterPath)) {
beforePath = FileUtil.toSystemDependentName(beforePath);
afterPath = FileUtil.toSystemDependentName(afterPath);
title = beforePath + " -> " + afterPath;
}
else if (beforePath != null) {
beforePath = FileUtil.toSystemDependentName(beforePath);
title = beforePath;
}
else if (afterPath != null) {
afterPath = FileUtil.toSystemDependentName(afterPath);
title = afterPath;
}
else {
title = VcsBundle.message("diff.unknown.path.title");
}
request.setWindowTitle(title);
boolean result = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
if (pi != null) {
pi.setIndeterminate(true);
}
request.setContents(createContent(bRev), createContent(aRev));
}
}, VcsBundle.message("progress.loading.diff.revisions"), true, myProject);
if (! result) return false;
String beforeRevisionTitle = (bRev != null) ? bRev.getRevisionNumber().asString() : "";
String afterRevisionTitle = (aRev != null) ? aRev.getRevisionNumber().asString() : "";
if ((beforeRevisionTitle == null) || (beforeRevisionTitle.length() == 0)) {
beforeRevisionTitle = "Base version";
}
if ((afterRevisionTitle == null) || (afterRevisionTitle.length() == 0)) {
afterRevisionTitle = "Your version";
}
request.setContentTitles(beforeRevisionTitle, afterRevisionTitle);
return true;
}
@NotNull
private DiffContent createContent(final ContentRevision revision) {
ProgressManager.checkCanceled();
if (revision == null) return SimpleContent.createEmpty();
if (revision instanceof CurrentContentRevision) {
final CurrentContentRevision current = (CurrentContentRevision)revision;
final VirtualFile vFile = current.getVirtualFile();
return vFile != null ? new FileContent(myProject, vFile) : new SimpleContent("");
}
FilePath filePath = revision.getFile();
if (revision instanceof BinaryContentRevision) {
final String name = filePath.getName();
try {
return FileContent.createFromTempFile(myProject, name, name, ((BinaryContentRevision)revision).getBinaryContent());
}
catch (IOException e) {
LOG.info(e);
try {
return FileContent.createFromTempFile(myProject, name, name, ArrayUtil.EMPTY_BYTE_ARRAY);
}
catch (IOException e1) {
LOG.info(e1);
return null;
}
}
catch (VcsException e) {
LOG.info(e);
try {
return FileContent.createFromTempFile(myProject, name, name, ArrayUtil.EMPTY_BYTE_ARRAY);
}
catch (IOException e1) {
LOG.info(e1);
return null;
}
}
}
String revisionContent;
try {
revisionContent = revision.getContent();
}
catch(VcsException ex) {
LOG.info(ex);
// TODO: correct exception handling
revisionContent = null;
}
SimpleContent content = revisionContent == null
? new SimpleContent("")
: new FileAwareSimpleContent(myProject, filePath, revisionContent, filePath.getFileType());
VirtualFile vFile = filePath.getVirtualFile();
if (vFile != null) {
content.setCharset(vFile.getCharset());
content.setBOM(vFile.getBOM());
}
content.setReadOnly(true);
return content;
}
private boolean canShowChange(DiffChainContext context, List<String> errSb) {
final ContentRevision bRev = myChange.getBeforeRevision();
final ContentRevision aRev = myChange.getAfterRevision();
if (myIgnoreDirectoryFlag) {
if (! checkContentsAvailable(bRev, aRev, errSb)) return false;
return true;
}
boolean isOk = checkContentRevision(bRev, context, errSb);
isOk &= checkContentRevision(aRev, context, errSb);
return isOk;
}
private boolean checkContentRevision(ContentRevision rev, final DiffChainContext context, final List<String> errSb) {
if (rev == null) return true;
if (rev.getFile().isDirectory()) return false;
if (! hasContents(rev, errSb)) {
return false;
}
final FileType type = rev.getFile().getFileType();
if (! type.isBinary()) return true;
if (FileTypes.UNKNOWN.equals(type)) {
final boolean associatedToText = checkAssociate(myProject, rev.getFile(), context);
}
return true;
}
private static boolean hasContents(@Nullable final ContentRevision rev, final List<String> errSb) {
if (rev == null) return false;
try {
if (rev instanceof BinaryContentRevision) {
return ((BinaryContentRevision) rev).getBinaryContent() != null;
} else {
return rev.getContent() != null;
}
}
catch (VcsException e) {
LOG.info(e);
errSb.add(e.getMessage());
return false;
}
}
private static boolean checkContentsAvailable(@Nullable final ContentRevision bRev, @Nullable final ContentRevision aRev, final List<String> errSb) {
if (hasContents(bRev, errSb)) return true;
return hasContents(aRev, errSb);
}
public static boolean checkAssociate(final Project project, final FilePath file, DiffChainContext context) {
final String pattern = FileUtilRt.getExtension(file.getName()).toLowerCase();
if (context.contains(pattern)) return false;
int rc = Messages.showOkCancelDialog(project,
VcsBundle.message("diff.unknown.file.type.prompt", file.getName()),
VcsBundle.message("diff.unknown.file.type.title"),
VcsBundle.message("diff.unknown.file.type.associate"),
CommonBundle.getCancelButtonText(),
Messages.getQuestionIcon());
if (rc == Messages.OK) {
FileType fileType = FileTypeChooser.associateFileType(file.getName());
return fileType != null && !fileType.isBinary();
} else {
context.add(pattern);
}
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChangeDiffRequestPresentable that = (ChangeDiffRequestPresentable)o;
if (myChange != null ? !myChange.equals(that.myChange) : that.myChange != null) return false;
return true;
}
@Override
public int hashCode() {
return myChange != null ? myChange.hashCode() : 0;
}
}