package ru.batrdmi.svnplugin.actions;
import com.intellij.history.LocalHistory;
import com.intellij.history.LocalHistoryAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsHistoryUtil;
import com.intellij.openapi.vcs.ui.ReplaceFileConfirmationDialog;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import ru.batrdmi.svnplugin.SVNRevisionGraph;
import ru.batrdmi.svnplugin.logic.Revision;
import java.io.FileOutputStream;
import java.io.IOException;
// This class is 'mostly' copied from com.intellij.openapi.vcs.history.FileHistoryPanelImpl
public class MyGetVersionAction extends AnAction implements DumbAware {
private static final Logger log = Logger.getInstance("ru.batrdmi.svnplugin.actions.MyGetVersionAction");
public MyGetVersionAction() {
super("Get", "Get version from repository", IconLoader.getIcon("/actions/get.png"));
}
public void update(@NotNull AnActionEvent e) {
Presentation presentation = e.getPresentation();
FilePath filePath = e.getData(SVNRevisionGraph.SRC_FILE);
Revision revision = e.getData(SVNRevisionGraph.SELECTED_REVISION);
boolean enabled = isEnabled(filePath, revision);
presentation.setEnabled(enabled);
presentation.setVisible(enabled || !ActionPlaces.isPopupPlace(e.getPlace()));
}
public boolean isEnabled(FilePath filePath, Revision revision) {
return filePath!= null && filePath.getVirtualFileParent() != null && !filePath.isDirectory()
&& revision != null && !revision.isDeleted();
}
@Override
public void actionPerformed(@NotNull AnActionEvent ae) {
Revision rev = ae.getData(SVNRevisionGraph.SELECTED_REVISION);
FilePath filePath = ae.getData(SVNRevisionGraph.SRC_FILE);
Project project = ae.getData(PlatformDataKeys.PROJECT);
VcsFileRevision revision = ae.getData(VcsDataKeys.VCS_FILE_REVISION);
if (!isEnabled(filePath, rev)) {
return;
}
if (ChangeListManager.getInstance(project).isFreezedWithNotification(null)) {
return;
}
//noinspection ConstantConditions
if (filePath.getVirtualFile() != null) {
if (!new ReplaceFileConfirmationDialog(project, "Get revision")
.confirmFor(new VirtualFile[]{filePath.getVirtualFile()})) {
return;
}
}
getVersion(project, filePath, revision);
refreshFile(project, filePath, revision);
}
private void refreshFile(Project project, final FilePath filePath, VcsFileRevision revision) {
Runnable refresh = null;
final VirtualFile vf = filePath.getVirtualFile();
if (vf == null) {
final LocalHistoryAction action = startLocalHistoryAction(filePath, revision);
final VirtualFile vp = filePath.getVirtualFileParent();
if (vp != null) {
refresh = new Runnable() {
public void run() {
vp.refresh(false, true, new Runnable() {
public void run() {
filePath.refresh();
action.finish();
}
});
}
};
}
} else {
refresh = new Runnable() {
public void run() {
vf.refresh(false, false);
}
};
}
if (refresh != null) {
ProgressManager.getInstance().runProcessWithProgressSynchronously(refresh, "Refreshing files...", false, project);
}
}
private void getVersion(final Project project, final FilePath filePath, final VcsFileRevision revision) {
final VirtualFile file = filePath.getVirtualFile();
if ((file != null) && !file.isWritable()) {
if (ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(file).hasReadonlyFiles()) {
return;
}
}
new Task.Backgroundable(project, "Loading content...") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
LocalHistoryAction action = file != null ? startLocalHistoryAction(filePath, revision) : LocalHistoryAction.NULL;
final byte[] revisionContent;
try {
revisionContent = VcsHistoryUtil.loadRevisionContent(revision);
} catch (final IOException e) {
log.info(e);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override public void run() {
Messages.showMessageDialog("Cannot load revision: " + e.getLocalizedMessage(),
"Get Revision Content", Messages.getInformationIcon());
}
});
return;
} catch (final VcsException e) {
log.info(e);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override public void run() {
Messages.showMessageDialog("Cannot load revision: " + e.getLocalizedMessage(),
"Get Revision Content", Messages.getInformationIcon());
}
});
return;
} catch (ProcessCanceledException ex) {
return;
}
try {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
public void run() {
try {
write(project, filePath, revisionContent);
} catch (IOException e) {
Messages.showMessageDialog("Cannot save content: " + e.getLocalizedMessage(),
"Get Revision Content", Messages.getErrorIcon());
}
}
}, createGetActionTitle(filePath, revision), null);
}
});
}
});
if (file != null) {
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
}
} finally {
action.finish();
}
}
}.queue();
}
private LocalHistoryAction startLocalHistoryAction(FilePath filePath, final VcsFileRevision revision) {
return LocalHistory.getInstance().startAction(createGetActionTitle(filePath, revision));
}
private String createGetActionTitle(FilePath filePath, final VcsFileRevision revision) {
return filePath.getIOFile().getAbsolutePath() + ": Get Version " + revision.getRevisionNumber();
}
private void write(Project project, FilePath filePath, byte[] revision) throws IOException {
if (filePath.getVirtualFile() == null) {
writeContentToIOFile(filePath, revision);
} else {
Document document = filePath.getDocument();
if (document == null) {
writeContentToFile(filePath, revision);
} else {
writeContentToDocument(project, filePath, document, revision);
}
}
}
private void writeContentToIOFile(FilePath filePath, byte[] revisionContent) throws IOException {
FileOutputStream outputStream = new FileOutputStream(filePath.getIOFile());
try {
outputStream.write(revisionContent);
} finally {
outputStream.close();
}
}
private void writeContentToFile(FilePath filePath, final byte[] revision) throws IOException {
//noinspection ConstantConditions
filePath.getVirtualFile().setBinaryContent(revision);
}
private void writeContentToDocument(Project project, FilePath filePath, final Document document,
byte[] revisionContent) throws IOException {
final String content = StringUtil.convertLineSeparators(new String(revisionContent, filePath.getCharset().name()));
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
public void run() {
document.replaceString(0, document.getTextLength(), content);
}
}, "Get Version", null);
}
}