blob: bd3cef970846be204d3893789659ab3c2d2ea9c8 [file] [log] [blame]
/*
* Copyright 2000-2009 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.history.integration.ui.models;
import com.intellij.history.core.LocalHistoryFacade;
import com.intellij.history.core.RevisionsCollector;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
import com.intellij.history.integration.IdeaGateway;
import com.intellij.history.integration.patches.PatchCreator;
import com.intellij.history.integration.revertion.Reverter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public abstract class HistoryDialogModel {
protected final Project myProject;
protected LocalHistoryFacade myVcs;
protected VirtualFile myFile;
protected IdeaGateway myGateway;
private String myFilter;
private List<RevisionItem> myRevisionsCache;
private Revision myCurrentRevisionCache;
private int myRightRevisionIndex;
private int myLeftRevisionIndex;
private Entry[] myLeftEntryCache;
private Entry[] myRightEntryCache;
public HistoryDialogModel(Project p, IdeaGateway gw, LocalHistoryFacade vcs, VirtualFile f) {
myProject = p;
myVcs = vcs;
myFile = f;
myGateway = gw;
}
public String getTitle() {
return FileUtil.toSystemDependentName(myFile.getPath());
}
public List<RevisionItem> getRevisions() {
if (myRevisionsCache == null) {
Pair<Revision, List<RevisionItem>> revs = calcRevisionsCache();
myCurrentRevisionCache = revs.first;
myRevisionsCache = revs.second;
}
return myRevisionsCache;
}
public Revision getCurrentRevision() {
getRevisions();
return myCurrentRevisionCache;
}
protected Pair<Revision, List<RevisionItem>> calcRevisionsCache() {
return ApplicationManager.getApplication().runReadAction(new Computable<Pair<Revision, List<RevisionItem>>>() {
public Pair<Revision, List<RevisionItem>> compute() {
myGateway.registerUnsavedDocuments(myVcs);
String path = myFile.getPath();
RootEntry root = myGateway.createTransientRootEntry();
RevisionsCollector collector = new RevisionsCollector(myVcs, root, path, myProject.getLocationHash(), myFilter);
List<Revision> all = collector.getResult();
return Pair.create(all.get(0), groupRevisions(all.subList(1, all.size())));
}
});
}
private List<RevisionItem> groupRevisions(List<Revision> revs) {
LinkedList<RevisionItem> result = new LinkedList<RevisionItem>();
for (Revision each : ContainerUtil.iterateBackward(revs)) {
if (each.isLabel() && !result.isEmpty()) {
result.getFirst().labels.addFirst(each);
} else {
result.addFirst(new RevisionItem(each));
}
}
return result;
}
public void setFilter(@Nullable String filter) {
myFilter = StringUtil.isEmptyOrSpaces(filter) ? null : filter;
clearRevisions();
}
public void clearRevisions() {
myRevisionsCache = null;
resetEntriesCache();
}
private void resetEntriesCache() {
myLeftEntryCache = null;
myRightEntryCache = null;
}
public Revision getLeftRevision() {
if (getRevisions().isEmpty()) return getCurrentRevision();
return getRevisions().get(myLeftRevisionIndex).revision;
}
public Revision getRightRevision() {
if (isCurrentRevisionSelected() || getRevisions().isEmpty()) {
return getCurrentRevision();
}
return getRevisions().get(myRightRevisionIndex).revision;
}
protected Entry getLeftEntry() {
if (myLeftEntryCache == null) {
// array is used because entry itself can be null
myLeftEntryCache = new Entry[]{getLeftRevision().findEntry()};
}
return myLeftEntryCache[0];
}
protected Entry getRightEntry() {
if (myRightEntryCache == null) {
// array is used because entry itself can be null
myRightEntryCache = new Entry[]{getRightRevision().findEntry()};
}
return myRightEntryCache[0];
}
public void selectRevisions(int first, int second) {
if (first == second) {
myRightRevisionIndex = -1;
myLeftRevisionIndex = first == -1 ? 0 : first;
}
else {
myRightRevisionIndex = first;
myLeftRevisionIndex = second;
}
resetEntriesCache();
}
public void resetSelection() {
selectRevisions(0, 0);
}
public boolean isCurrentRevisionSelected() {
return myRightRevisionIndex == -1;
}
public List<Change> getChanges() {
List<Difference> dd = getDifferences();
List<Change> result = new ArrayList<Change>();
for (Difference d : dd) {
result.add(createChange(d));
}
return result;
}
protected List<Difference> getDifferences() {
return getLeftRevision().getDifferencesWith(getRightRevision());
}
protected Change createChange(Difference d) {
return new Change(d.getLeftContentRevision(myGateway), d.getRightContentRevision(myGateway));
}
public void createPatch(String path, boolean isReverse) throws VcsException, IOException {
PatchCreator.create(myProject, getChanges(), path, isReverse, null);
}
public abstract Reverter createReverter();
public boolean isRevertEnabled() {
return isCorrectSelectionForRevertAndPatch();
}
public boolean isCreatePatchEnabled() {
return isCorrectSelectionForRevertAndPatch();
}
private boolean isCorrectSelectionForRevertAndPatch() {
return myLeftRevisionIndex != -1;
}
public boolean canPerformCreatePatch() {
return !getLeftEntry().hasUnavailableContent() && !getRightEntry().hasUnavailableContent();
}
}