VCS: lazy file history

This commit is contained in:
irengrig
2010-02-23 21:59:16 +03:00
parent 29431729c6
commit 410d2174ce
18 changed files with 601 additions and 220 deletions
@@ -24,17 +24,17 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.UIBundle;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.ui.table.BaseTableView;
import com.intellij.ui.table.SelectionProvider;
import com.intellij.ui.table.TableView;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns;
import com.intellij.ui.treeStructure.treetable.TreeTableModel;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.config.Storage;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.ui.Table;
import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns;
import com.intellij.ui.treeStructure.treetable.TreeTableModel;
import org.jetbrains.annotations.NonNls;
import javax.swing.*;
@@ -392,8 +392,24 @@ public class DualView extends JPanel {
BaseTableView.store(myTreeStorage, myTreeView);
}
public void setRoot(TreeNode node) {
public void setRoot(final TreeNode node, final Object selection) {
ListTableModel model = myFlatView.getListTableModel();
final int column = model.getSortedColumnIndex();
final int sortingType = model.getSortingType();
final Object obj = myFlatView.getSelectedObject() != null ? myFlatView.getSelectedObject() : selection;
myTreeView.getTreeViewModel().setRoot(node);
if (column != -1) {
model.sortByColumn(column, sortingType);
}
if (obj != null) {
final List items = myFlatView.getItems();
if (items.contains(obj)) {
final int idx = items.indexOf(obj);
setSelectionInterval(idx, idx);
}
}
}
public void rebuild() {
@@ -73,7 +73,7 @@ public class TableView<Item> extends BaseTableView implements ItemsProvider, Sel
super.tableChanged(e);
}
private void setSelection(Collection<Item> selection) {
public void setSelection(Collection<Item> selection) {
clearSelection();
for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
addSelection(iterator.next());
@@ -20,14 +20,18 @@ import java.util.Collections;
import java.util.List;
public class BufferedListConsumer<T> implements Consumer<List<T>> {
private final int myInterval;
private long myTs;
private final int mySize;
private final List<T> myBuffer;
private final Consumer<List<T>> myConsumer;
public BufferedListConsumer(int size, Consumer<List<T>> consumer) {
public BufferedListConsumer(int size, Consumer<List<T>> consumer, int interval) {
mySize = size;
myBuffer = new ArrayList<T>();
myConsumer = consumer;
myInterval = interval;
myTs = System.currentTimeMillis();
}
public void consumeOne(final T t) {
@@ -36,10 +40,12 @@ public class BufferedListConsumer<T> implements Consumer<List<T>> {
public void consume(List<T> list) {
myBuffer.addAll(list);
if (mySize <= myBuffer.size()) {
final long ts = System.currentTimeMillis();
if ((mySize <= myBuffer.size()) || (myInterval > 0) && ((ts - myInterval) > myTs)) {
myConsumer.consume(new ArrayList<T>(myBuffer));
myBuffer.clear();
}
myTs = ts;
}
public void flush() {
@@ -0,0 +1,88 @@
/*
* Copyright 2000-2010 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.history;
import com.intellij.openapi.util.Comparing;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public abstract class VcsAbstractHistorySession implements VcsHistorySession {
private final List<VcsFileRevision> myRevisions;
private final Object myLock;
private VcsRevisionNumber myCachedRevisionNumber;
protected VcsRevisionNumber getCachedRevision() {
synchronized (myLock) {
return myCachedRevisionNumber;
}
}
protected void setCachedRevision(final VcsRevisionNumber number) {
synchronized (myLock) {
myCachedRevisionNumber = number;
}
}
public VcsAbstractHistorySession(List<VcsFileRevision> revisions) {
myLock = new Object();
myRevisions = new ArrayList<VcsFileRevision>(revisions);
myCachedRevisionNumber = calcCurrentRevisionNumber();
}
protected VcsAbstractHistorySession(List<VcsFileRevision> revisions, VcsRevisionNumber currentRevisionNumber) {
myLock = new Object();
myRevisions = new ArrayList<VcsFileRevision>(revisions);
myCachedRevisionNumber = currentRevisionNumber;
}
public List<VcsFileRevision> getRevisionList() {
return myRevisions;
}
/**
* This method should return actual value for current revision (it can be changed after submit for example)
* @return current file revision, null if file does not exist anymore
*/
@Nullable
protected abstract VcsRevisionNumber calcCurrentRevisionNumber();
public final VcsRevisionNumber getCurrentRevisionNumber() {
return getCachedRevision();
}
public boolean isCurrentRevision(VcsRevisionNumber rev) {
VcsRevisionNumber revNumber = getCurrentRevisionNumber();
return revNumber != null && revNumber.compareTo(rev) == 0;
}
public synchronized boolean shouldBeRefreshed() {
final VcsRevisionNumber oldValue = getCachedRevision();
final VcsRevisionNumber newNumber = calcCurrentRevisionNumber();
setCachedRevision(newNumber);
return !Comparing.equal(oldValue, newNumber);
}
public boolean allowAsyncRefresh() {
return false;
}
public boolean isContentAvailable(VcsFileRevision revision) {
return true;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2010 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.
@@ -15,6 +15,11 @@
*/
package com.intellij.openapi.vcs.history;
public interface FileHistoryPanel {
void refresh();
import com.intellij.openapi.vcs.VcsException;
public interface VcsAppendableHistorySessionPartner {
void reportCreatedEmptySession(VcsAbstractHistorySession session);
void acceptRevision(final VcsFileRevision revision);
void reportException(final VcsException exception);
void finished();
}
@@ -29,7 +29,7 @@ public interface VcsHistoryProvider extends VcsProviderMarker {
VcsDependentHistoryComponents getUICustomization(final VcsHistorySession session, final JComponent forShortcutRegistration);
AnAction[] getAdditionalActions(final FileHistoryPanel panel);
AnAction[] getAdditionalActions(final Runnable refresher);
/**
* Returns whether the history provider submits the custom-formatted date
@@ -53,9 +53,7 @@ public interface VcsHistoryProvider extends VcsProviderMarker {
@CalledInBackground
VcsHistorySession createSessionFor(FilePath filePath) throws VcsException;
//return null if your revisions cannot be tree
@Nullable
HistoryAsTreeProvider getTreeHistoryProvider();
void reportAppendableHistory(final FilePath path, final VcsAppendableHistorySessionPartner partner) throws VcsException;
boolean supportsHistoryForDirectories();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2010 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.
@@ -15,73 +15,17 @@
*/
package com.intellij.openapi.vcs.history;
import com.intellij.openapi.util.Comparing;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public abstract class VcsHistorySession {
private final List<VcsFileRevision> myRevisions;
private final Object myLock;
private VcsRevisionNumber myCachedRevisionNumber;
protected VcsRevisionNumber getCachedRevision() {
synchronized (myLock) {
return myCachedRevisionNumber;
}
}
protected void setCachedRevision(final VcsRevisionNumber number) {
synchronized (myLock) {
myCachedRevisionNumber = number;
}
}
public VcsHistorySession(List<VcsFileRevision> revisions) {
myLock = new Object();
myRevisions = revisions;
myCachedRevisionNumber = calcCurrentRevisionNumber();
}
protected VcsHistorySession(List<VcsFileRevision> revisions, VcsRevisionNumber currentRevisionNumber) {
myLock = new Object();
myRevisions = revisions;
myCachedRevisionNumber = currentRevisionNumber;
}
public List<VcsFileRevision> getRevisionList() {
return myRevisions;
}
/**
* This method should return actual value for current revision (it can be changed after submit for example)
* @return current file revision, null if file does not exist anymore
*/
public interface VcsHistorySession {
List<VcsFileRevision> getRevisionList();
VcsRevisionNumber getCurrentRevisionNumber();
boolean isCurrentRevision(VcsRevisionNumber rev);
boolean shouldBeRefreshed();
boolean allowAsyncRefresh();
boolean isContentAvailable(VcsFileRevision revision);
@Nullable
protected abstract VcsRevisionNumber calcCurrentRevisionNumber();
public final VcsRevisionNumber getCurrentRevisionNumber() {
return getCachedRevision();
}
public boolean isCurrentRevision(VcsRevisionNumber rev) {
VcsRevisionNumber revNumber = getCurrentRevisionNumber();
return revNumber != null && revNumber.compareTo(rev) == 0;
}
public synchronized boolean refresh() {
final VcsRevisionNumber oldValue = getCachedRevision();
final VcsRevisionNumber newNumber = calcCurrentRevisionNumber();
setCachedRevision(newNumber);
return !Comparing.equal(oldValue, newNumber);
}
public boolean allowAsyncRefresh() {
return false;
}
public boolean isContentAvailable(VcsFileRevision revision) {
return true;
}
HistoryAsTreeProvider getHistoryAsTreeProvider();
}
@@ -20,7 +20,10 @@ import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.diff.DiffProvider;
import com.intellij.openapi.vcs.history.*;
import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
@@ -115,7 +118,7 @@ public class CompareWithSelectedRevisionAction extends AbstractVcsAction {
public void consume(VcsHistorySession session) {
if (session == null) return;
final List<VcsFileRevision> revisions = session.getRevisionList();
final HistoryAsTreeProvider treeHistoryProvider = vcsHistoryProvider.getTreeHistoryProvider();
final HistoryAsTreeProvider treeHistoryProvider = session.getHistoryAsTreeProvider();
if (treeHistoryProvider != null) {
showTreePopup(treeHistoryProvider.createTreeOn(revisions), file, project, vcs.getDiffProvider());
}
@@ -20,18 +20,21 @@ import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.BackgroundableActionEnabledHandler;
import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.history.VcsHistoryProvider;
import com.intellij.openapi.vcs.history.VcsHistorySession;
import com.intellij.openapi.vcs.history.VcsHistoryProviderBackgroundableProxy;
import com.intellij.openapi.vcs.history.VcsHistorySession;
import com.intellij.openapi.vcs.history.impl.VcsBlockHistoryDialog;
import com.intellij.openapi.vcs.impl.BackgroundableActionEnabledHandler;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.vcsUtil.VcsSelection;
import com.intellij.vcsUtil.VcsSelectionUtil;
import com.intellij.util.Consumer;
public class SelectedBlockHistoryAction extends AbstractVcsAction {
@@ -152,7 +152,7 @@ public class CommittedChangesPanel extends JPanel implements TypeSafeDataProvide
}.callMe();
}
};
final BufferedListConsumer<CommittedChangeList> bufferedListConsumer = new BufferedListConsumer<CommittedChangeList>(30, appender);
final BufferedListConsumer<CommittedChangeList> bufferedListConsumer = new BufferedListConsumer<CommittedChangeList>(30, appender,-1);
myProvider.loadCommittedChanges(mySettings, myLocation, myMaxCount, new AsynchConsumer<CommittedChangeList>() {
public void finished() {
@@ -18,8 +18,8 @@ package com.intellij.openapi.vcs.history;
import com.intellij.history.LocalHistory;
import com.intellij.history.LocalHistoryAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.*;
@@ -45,6 +45,7 @@ import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.actions.CreatePatchFromChangesAction;
import com.intellij.openapi.vcs.changes.committed.AbstractCalledLater;
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer;
import com.intellij.openapi.vcs.changes.issueLinks.TableLinkMouseListener;
@@ -67,10 +68,7 @@ import com.intellij.ui.dualView.CellWrapper;
import com.intellij.ui.dualView.DualTreeElement;
import com.intellij.ui.dualView.DualView;
import com.intellij.ui.dualView.DualViewColumnInfo;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.util.Icons;
import com.intellij.util.TreeItem;
import com.intellij.util.*;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.SortableColumnModel;
import com.intellij.util.ui.TableViewModel;
@@ -106,7 +104,7 @@ import java.util.List;
/**
* author: lesya
*/
public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends ChangeBrowserSettings> extends PanelWithActionsAndCloseButton implements FileHistoryPanel {
public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends ChangeBrowserSettings> extends PanelWithActionsAndCloseButton {
private static final Logger LOG = Logger.getInstance("#com.intellij.cvsSupport2.ui.FileHistoryDialog");
private final JEditorPane myComments;
@@ -119,14 +117,18 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
private final VcsHistoryProvider myProvider;
private final AnnotationProvider myAnnotationProvider;
private VcsHistorySession myHistorySession;
private final CommittedChangesProvider<S, U> myCommittedChangesProvider;
private final FilePath myFilePath;
private final Runnable myRefresher;
private final DualView myDualView;
private final Alarm myUpdateAlarm;
private final String myRepositoryPath;
private boolean myInRefresh;
private Object myTargetSelection;
private final AsynchConsumer<VcsHistorySession> myHistoryPanelRefresh;
private static final String COMMIT_MESSAGE_TITLE = VcsBundle.message("label.selected.revision.commit.message");
@NonNls private static final String VCS_HISTORY_ACTIONS_GROUP = "VcsHistoryActionsGroup";
@@ -174,6 +176,8 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
return "author_author";
}
};
private JLabel myLoadingLabel;
private Splitter mySplitter;
private static class MessageRenderer extends ColoredTableCellRenderer {
@@ -255,14 +259,14 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
FilePath filePath, final String repositoryPath, VcsHistorySession session,
VcsHistoryProvider provider,
AnnotationProvider annotationProvider,
ContentManager contentManager, final CommittedChangesProvider<S, U> committedChangesProvider) {
ContentManager contentManager, final Runnable refresher) {
super(contentManager, provider.getHelpId() != null ? provider.getHelpId() : "reference.versionControl.toolwindow.history");
myProvider = provider;
myAnnotationProvider = annotationProvider;
myCommittedChangesProvider = committedChangesProvider;
myRepositoryPath = repositoryPath;
myProject = project;
myHistorySession = session;
myRefresher = refresher;
myHistorySession = session;
myFilePath = filePath;
COLUMNS = createColumnList(project, provider, session);
@@ -277,15 +281,15 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
myUpdateAlarm = new Alarm(session.allowAsyncRefresh() ? Alarm.ThreadToUse.SHARED_THREAD : Alarm.ThreadToUse.SWING_THREAD);
HistoryAsTreeProvider treeHistoryProvider = provider.getTreeHistoryProvider();
final HistoryAsTreeProvider treeHistoryProvider = myHistorySession.getHistoryAsTreeProvider();
@NonNls String storageKey = "FileHistory." + provider.getClass().getName();
if (treeHistoryProvider != null) {
myDualView = new DualView(new TreeNodeOnVcsRevision(null, treeHistoryProvider.createTreeOn(myHistorySession.getRevisionList())),
myDualView = new DualView(new TreeNodeOnVcsRevision(null, treeHistoryProvider.createTreeOn(new ArrayList<VcsFileRevision>(myHistorySession.getRevisionList()))),
COLUMNS, storageKey, project);
}
else {
myDualView = new DualView(new TreeNodeOnVcsRevision(null, wrapWithTreeElements(myHistorySession.getRevisionList())), COLUMNS,
myDualView = new DualView(new TreeNodeOnVcsRevision(null, wrapWithTreeElements(new ArrayList<VcsFileRevision>(myHistorySession.getRevisionList()))), COLUMNS,
storageKey, project);
myDualView.switchToTheFlatMode();
}
@@ -297,33 +301,31 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
myPopupActions = createPopupActions();
myHistoryPanelRefresh = new AsynchConsumer<VcsHistorySession>() {
public void finished() {
myInRefresh = false;
myTargetSelection = null;
myLoadingLabel.setVisible(false);
mySplitter.revalidate();
mySplitter.repaint();
}
public void consume(VcsHistorySession vcsHistorySession) {
FileHistoryPanelImpl.this.refresh(vcsHistorySession);
}
};
myUpdateAlarm.addRequest(new Runnable() {
public void run() {
if (myProject.isDisposed()) {
return;
}
final boolean refresh = myHistorySession.refresh();
final boolean refresh = (! myInRefresh) && myHistorySession.shouldBeRefreshed();
myUpdateAlarm.cancelAllRequests();
myUpdateAlarm.addRequest(this, 10000);
if (refresh) {
createSession(new Consumer<VcsHistorySession>() {
public void consume(final VcsHistorySession session) {
if (session != null) {
if (session.allowAsyncRefresh()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
refresh(session);
}
});
}
else {
refresh(session);
}
}
}
});
refreshImpl();
}
}
}, 10000);
@@ -333,20 +335,6 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
chooseView();
}
private void createSession(final Consumer<VcsHistorySession> consumer) {
final Runnable runnable = new Runnable() {
public void run() {
new VcsHistoryProviderBackgroundableProxy(myProject, getHistoryProvider()).createSessionFor(myFilePath, consumer, null, true);
}
};
final Application application = ApplicationManager.getApplication();
if (application.isDispatchThread()) {
runnable.run();
} else {
application.invokeLater(runnable);
}
}
private void replaceTransferable() {
final TransferHandler originalTransferHandler = myComments.getTransferHandler();
@@ -437,18 +425,19 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
return result;
}
private void refresh(VcsHistorySession session) {
private void refresh(final VcsHistorySession session) {
myHistorySession = session;
HistoryAsTreeProvider treeHistoryProvider = getHistoryProvider().getTreeHistoryProvider();
HistoryAsTreeProvider treeHistoryProvider = session.getHistoryAsTreeProvider();
if (treeHistoryProvider != null) {
myDualView.setRoot(new TreeNodeOnVcsRevision(null, treeHistoryProvider.createTreeOn(myHistorySession.getRevisionList())));
myDualView.setRoot(new TreeNodeOnVcsRevision(null,
treeHistoryProvider.createTreeOn(new ArrayList<VcsFileRevision>(myHistorySession.getRevisionList()))), myTargetSelection);
}
else {
myDualView.setRoot(new TreeNodeOnVcsRevision(null, wrapWithTreeElements(myHistorySession.getRevisionList())));
myDualView.setRoot(new TreeNodeOnVcsRevision(null,
wrapWithTreeElements(new ArrayList<VcsFileRevision>(myHistorySession.getRevisionList()))), myTargetSelection);
}
myDualView.rebuild();
myDualView.expandAll();
myDualView.repaint();
}
@@ -626,11 +615,11 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
protected JComponent createCenterPanel() {
Splitter splitter = new Splitter(true, getSplitterProportion());
splitter.setDividerWidth(4);
mySplitter = new Splitter(true, getSplitterProportion());
mySplitter.setDividerWidth(4);
//splitter.getDivider().setBackground(UIUtil.getBgFillColor(splitter.getDivider()).brighter());
splitter.addPropertyChangeListener(new PropertyChangeListener() {
mySplitter.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (Splitter.PROP_PROPORTION.equals(evt.getPropertyName())) {
setSplitterProportionTo((Float)evt.getNewValue());
@@ -651,9 +640,16 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
detailsSplitter.setFirstComponent(commentGroup);
detailsSplitter.setSecondComponent(myAdditionalDetails);
splitter.setFirstComponent(myDualView);
splitter.setSecondComponent(detailsSplitter);
return splitter;
final JPanel wrapper = new JPanel(new BorderLayout());
myLoadingLabel = new JLabel("Loading...");
//myLoadingLabel.setVisible(false);
myLoadingLabel.setBackground(UIUtil.getToolTipBackground());
wrapper.add(myLoadingLabel, BorderLayout.NORTH);
wrapper.add(myDualView, BorderLayout.CENTER);
mySplitter.setFirstComponent(wrapper);
mySplitter.setSecondComponent(detailsSplitter);
return mySplitter;
}
private void chooseView() {
@@ -722,7 +718,11 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
});
result.add(new MyGetVersionAction());
result.add(new MyAnnotateAction());
AnAction[] additionalActions = getHistoryProvider().getAdditionalActions(this);
AnAction[] additionalActions = myProvider.getAdditionalActions(new Runnable() {
public void run() {
refreshImpl();
}
});
if (additionalActions != null) {
for (AnAction additionalAction : additionalActions) {
result.add(additionalAction);
@@ -737,21 +737,28 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
return result;
}
public void refresh() {
createSession(new Consumer<VcsHistorySession>() {
public void consume(VcsHistorySession session) {
if (session == null) return;
refresh(session);
private void refreshImpl() {
new AbstractCalledLater(myProject, ModalityState.NON_MODAL) {
public void run() {
if (myInRefresh) return;
myInRefresh = true;
myTargetSelection = myDualView.getFlatView().getSelectedObject();
myLoadingLabel.setVisible(true);
mySplitter.revalidate();
mySplitter.repaint();
myRefresher.run();
}
});
}.callMe();
}
public AsynchConsumer<VcsHistorySession> getHistoryPanelRefresh() {
return myHistoryPanelRefresh;
}
private boolean supportsTree() {
return getHistoryProvider().getTreeHistoryProvider() != null;
}
private VcsHistoryProvider getHistoryProvider() {
return myProvider;
return myHistorySession != null && myHistorySession.getHistoryAsTreeProvider() != null;
}
private class MyShowAsTreeAction extends ToggleAction implements DumbAware {
@@ -1274,6 +1281,22 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
return myRevision != VcsFileRevision.NULL;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TreeNodeOnVcsRevision that = (TreeNodeOnVcsRevision)o;
if (myRevision != null ? !myRevision.getRevisionNumber().equals(that.myRevision.getRevisionNumber()) : that.myRevision != null) return false;
return true;
}
@Override
public int hashCode() {
return myRevision != null ? myRevision.getRevisionNumber().hashCode() : 0;
}
}
protected void dispose() {
@@ -1515,8 +1538,14 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
}
public void actionPerformed(AnActionEvent e) {
refresh();
if (myInRefresh) return;
refreshImpl();
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabled(! myInRefresh);
}
}
}
@@ -15,14 +15,24 @@
*/
package com.intellij.openapi.vcs.history;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.impl.VcsBackgroundableComputable;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.impl.BackgroundableActionEnabledHandler;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
import com.intellij.openapi.vcs.impl.VcsBackgroundableComputable;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class VcsHistoryProviderBackgroundableProxy {
@@ -53,4 +63,38 @@ public class VcsHistoryProviderBackgroundableProxy {
VcsBundle.message("message.title.could.not.load.file.history"), throwableComputable, continuation, null);
}
}
public void executeAppendableSession(final FilePath filePath, final VcsAppendableHistorySessionPartner partner,
@Nullable VcsBackgroundableActions actionKey, final boolean silent) {
final ProjectLevelVcsManagerImpl vcsManager = (ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myProject);
final VcsBackgroundableActions resultingActionKey = actionKey == null ? VcsBackgroundableActions.CREATE_HISTORY_SESSION : actionKey;
final BackgroundableActionEnabledHandler handler;
handler = vcsManager.getBackgroundableActionHandler(resultingActionKey);
// fo not start same action twice
if (handler.isInProgress(resultingActionKey)) return;
handler.register(resultingActionKey);
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, VcsBundle.message("loading.file.history.progress"),
true, BackgroundFromStartOption.getInstance()) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
myDelegate.reportAppendableHistory(filePath, partner);
}
catch (VcsException e) {
partner.reportException(e);
}
finally {
partner.finished();
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
handler.completed(resultingActionKey);
}
}, ModalityState.NON_MODAL);
}
}
});
}
}
@@ -35,6 +35,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
@@ -117,34 +118,111 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
showFileHistory(vcsHistoryProvider, null, path, repositoryPath, vcs);
}
public void showFileHistory(final VcsHistoryProvider vcsHistoryProvider, final AnnotationProvider annotationProvider, final FilePath path,
final String repositoryPath, final AbstractVcs vcs) {
try {
new VcsHistoryProviderBackgroundableProxy(myProject, vcsHistoryProvider).createSessionFor(path, new Consumer<VcsHistorySession>() {
public void consume(VcsHistorySession session) {
if (session == null) return;
List<VcsFileRevision> revisionsList = session.getRevisionList();
if (revisionsList.isEmpty()) return;
private static class MyVcsAppendableHistorySessionPartner implements VcsAppendableHistorySessionPartner {
private FileHistoryPanelImpl myFileHistoryPanel;
private final VcsHistoryProvider myVcsHistoryProvider;
private final AnnotationProvider myAnnotationProvider;
private final FilePath myPath;
private final String myRepositoryPath;
private final AbstractVcs myVcs;
private final Runnable myRefresher;
private VcsAbstractHistorySession mySession;
private BufferedListConsumer<VcsFileRevision> myBuffer;
String actionName = VcsBundle.message("action.name.file.history", path.getName());
private MyVcsAppendableHistorySessionPartner(final VcsHistoryProvider vcsHistoryProvider, final AnnotationProvider annotationProvider,
final FilePath path,
final String repositoryPath,
final AbstractVcs vcs,
final Runnable refresher) {
myVcsHistoryProvider = vcsHistoryProvider;
myAnnotationProvider = annotationProvider;
myPath = path;
myRepositoryPath = repositoryPath;
myVcs = vcs;
myRefresher = refresher;
myBuffer = new BufferedListConsumer<VcsFileRevision>(5, new Consumer<List<VcsFileRevision>>() {
public void consume(List<VcsFileRevision> vcsFileRevisions) {
mySession.getRevisionList().addAll(vcsFileRevisions);
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
myFileHistoryPanel.getHistoryPanelRefresh().consume(mySession);
}
});
}
}, 1000);
}
ContentManager contentManager = ProjectLevelVcsManagerEx.getInstanceEx(myProject).getContentManager();
public void acceptRevision(VcsFileRevision revision) {
myBuffer.consumeOne(revision);
}
FileHistoryPanelImpl fileHistoryPanel =
new FileHistoryPanelImpl(myProject, path, repositoryPath, session, vcsHistoryProvider, annotationProvider, contentManager,
vcs.getCommittedChangesProvider());
Content content = ContentFactory.SERVICE.getInstance().createContent(fileHistoryPanel, actionName, true);
public void reportCreatedEmptySession(final VcsAbstractHistorySession session) {
mySession = session;
if (myFileHistoryPanel != null) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
myFileHistoryPanel.getHistoryPanelRefresh().consume(mySession);
}
});
return;
}
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
String actionName = VcsBundle.message("action.name.file.history", myPath.getName());
ContentManager contentManager = ProjectLevelVcsManagerEx.getInstanceEx(myVcs.getProject()).getContentManager();
myFileHistoryPanel = new FileHistoryPanelImpl(myVcs.getProject(), myPath, myRepositoryPath, session, myVcsHistoryProvider,
myAnnotationProvider, contentManager, myRefresher);
Content content = ContentFactory.SERVICE.getInstance().createContent(myFileHistoryPanel, actionName, true);
ContentsUtil.addOrReplaceContent(contentManager, content, true);
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.VCS);
ToolWindow toolWindow = ToolWindowManager.getInstance(myVcs.getProject()).getToolWindow(ToolWindowId.VCS);
toolWindow.activate(null);
}
}, null, false);
}
catch (Exception exception) {
reportError(exception);
});
}
public void reportException(VcsException exception) {
ChangesViewBalloonProblemNotifier.showMe(myVcs.getProject(), VcsBundle.message("message.title.could.not.load.file.history") + ": " +
exception.getMessage(), MessageType.ERROR);
}
public void finished() {
myBuffer.flush();
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (myFileHistoryPanel != null) {
myFileHistoryPanel.getHistoryPanelRefresh().finished();
}
}
});
}
}
private static class MyRefresher implements Runnable {
private MyVcsAppendableHistorySessionPartner mySessionPartner;
private final VcsHistoryProvider myVcsHistoryProvider;
private final FilePath myPath;
private final AbstractVcs myVcs;
private MyRefresher(final VcsHistoryProvider vcsHistoryProvider, final AnnotationProvider annotationProvider, final FilePath path,
final String repositoryPath, final AbstractVcs vcs) {
myVcsHistoryProvider = vcsHistoryProvider;
myPath = path;
myVcs = vcs;
mySessionPartner = new MyVcsAppendableHistorySessionPartner(vcsHistoryProvider, annotationProvider, path, repositoryPath, vcs, this);
}
public void run() {
final VcsHistoryProviderBackgroundableProxy proxy = new VcsHistoryProviderBackgroundableProxy(myVcs.getProject(), myVcsHistoryProvider);
proxy.executeAppendableSession(myPath, mySessionPartner, null, false);
}
}
public void showFileHistory(final VcsHistoryProvider vcsHistoryProvider, final AnnotationProvider annotationProvider, final FilePath path,
final String repositoryPath, final AbstractVcs vcs) {
final MyRefresher refresher = new MyRefresher(vcsHistoryProvider, annotationProvider, path, repositoryPath, vcs);
refresher.run();
}
public void showRollbackChangesDialog(List<Change> changes) {
@@ -499,7 +577,6 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
}
}
else {
// todo
openCommittedChangesTab(provider, location, settings, 0, title);
}
}
@@ -626,7 +703,7 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
@Override
public void run(@NotNull final ProgressIndicator indicator) {
final AsynchConsumer<List<CommittedChangeList>> appender = myDlg.getAppender();
final BufferedListConsumer<CommittedChangeList> bufferedListConsumer = new BufferedListConsumer<CommittedChangeList>(10, appender);
final BufferedListConsumer<CommittedChangeList> bufferedListConsumer = new BufferedListConsumer<CommittedChangeList>(10, appender, -1);
final Application application = ApplicationManager.getApplication();
try {
@@ -17,9 +17,8 @@ package com.intellij.cvsSupport2.history;
import com.intellij.CvsBundle;
import com.intellij.cvsSupport2.CvsUtil;
import com.intellij.cvsSupport2.util.CvsVfsUtil;
import com.intellij.cvsSupport2.changeBrowser.CvsChangeList;
import com.intellij.cvsSupport2.application.CvsEntriesManager;
import com.intellij.cvsSupport2.changeBrowser.CvsChangeList;
import com.intellij.cvsSupport2.connections.CvsConnectionSettings;
import com.intellij.cvsSupport2.connections.CvsEnvironment;
import com.intellij.cvsSupport2.cvsExecution.CvsOperationExecutor;
@@ -28,9 +27,11 @@ import com.intellij.cvsSupport2.cvsExecution.ModalityContext;
import com.intellij.cvsSupport2.cvshandlers.CommandCvsHandler;
import com.intellij.cvsSupport2.cvsoperations.cvsLog.LocalPathIndifferentLogOperation;
import com.intellij.cvsSupport2.cvsoperations.cvsTagOrBranch.ui.TagsPanel;
import com.intellij.cvsSupport2.util.CvsVfsUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.history.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.TreeItem;
@@ -157,19 +158,19 @@ public class CvsHistoryProvider implements VcsHistoryProvider {
public VcsHistorySession createSessionFor(final FilePath filePath) {
final List<VcsFileRevision> fileRevisionList = createRevisions(filePath);
if (fileRevisionList == null) return null;
return new VcsHistorySession(fileRevisionList) {
return new VcsAbstractHistorySession(fileRevisionList) {
@Nullable
public VcsRevisionNumber calcCurrentRevisionNumber() {
return getCurrentRevision(filePath);
}
@Override
public synchronized boolean refresh() {
public synchronized boolean shouldBeRefreshed() {
//noinspection SimplifiableIfStatement
if (!CvsEntriesManager.getInstance().isActive()) {
return false;
}
return super.refresh();
return super.shouldBeRefreshed();
}
public boolean isContentAvailable(final VcsFileRevision revision) {
@@ -179,9 +180,19 @@ public class CvsHistoryProvider implements VcsHistoryProvider {
}
return super.isContentAvailable(revision);
}
public HistoryAsTreeProvider getHistoryAsTreeProvider() {
return MyHistoryAsTreeProvider.getInstance();
}
};
}
public void reportAppendableHistory(FilePath path, VcsAppendableHistorySessionPartner partner) throws VcsException {
// todo some time after ... this could be done
final VcsHistorySession session = createSessionFor(path);
partner.reportCreatedEmptySession((VcsAbstractHistorySession) session);
}
private static VcsRevisionNumber getCurrentRevision(FilePath filePath) {
Entry entryFor = CvsEntriesManager.getInstance().getEntryFor(filePath.getVirtualFileParent(),
filePath.getName());
@@ -238,19 +249,21 @@ public class CvsHistoryProvider implements VcsHistoryProvider {
return result;
}
public AnAction[] getAdditionalActions(final FileHistoryPanel panel) {
public AnAction[] getAdditionalActions(final Runnable refresher) {
return AnAction.EMPTY_ARRAY;
}
public HistoryAsTreeProvider getTreeHistoryProvider() {
return new MyHistoryAsTreeProvider();
}
public boolean supportsHistoryForDirectories() {
return false;
}
private static class MyHistoryAsTreeProvider implements HistoryAsTreeProvider {
private static MyHistoryAsTreeProvider ourInstance = new MyHistoryAsTreeProvider();
public static MyHistoryAsTreeProvider getInstance() {
return ourInstance;
}
public List<TreeItem<VcsFileRevision>> createTreeOn(List<VcsFileRevision> allRevisions) {
List<VcsFileRevision> sortedRevisions = sortRevisions(allRevisions);
@@ -112,6 +112,7 @@ public class GitLineHandler extends GitHandler {
* @param lineBuilder a line builder
*/
private void notifyLines(final Key outputType, final Iterator<String> lines, final StringBuilder lineBuilder) {
if (! lines.hasNext()) return;
if (lineBuilder.length() > 0) {
lineBuilder.append(lines.next());
if (lines.hasNext()) {
@@ -21,12 +21,15 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.history.*;
import com.intellij.util.Consumer;
import com.intellij.util.ui.ColumnInfo;
import git4idea.GitFileRevision;
import git4idea.actions.GitShowAllSubmittedFilesAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collections;
import java.util.List;
/**
@@ -60,8 +63,9 @@ public class GitHistoryProvider implements VcsHistoryProvider {
/**
* {@inheritDoc}
* @param refresher
*/
public AnAction[] getAdditionalActions(FileHistoryPanel panel) {
public AnAction[] getAdditionalActions(Runnable refresher) {
return new AnAction[]{new GitShowAllSubmittedFilesAction(), new GitCopyHistoryRevisionNumberAction()};
}
@@ -89,7 +93,7 @@ public class GitHistoryProvider implements VcsHistoryProvider {
return null;
}
List<VcsFileRevision> revisions = GitHistoryUtils.history(project, filePath);
return new VcsHistorySession(revisions) {
return new VcsAbstractHistorySession(revisions) {
@Nullable
protected VcsRevisionNumber calcCurrentRevisionNumber() {
try {
@@ -103,15 +107,43 @@ public class GitHistoryProvider implements VcsHistoryProvider {
return null;
}
}
public HistoryAsTreeProvider getHistoryAsTreeProvider() {
return null;
}
};
}
/**
* {@inheritDoc}
*/
@Nullable
public HistoryAsTreeProvider getTreeHistoryProvider() {
return null;
public void reportAppendableHistory(final FilePath path, final VcsAppendableHistorySessionPartner partner) throws VcsException {
final VcsAbstractHistorySession emptySession = new VcsAbstractHistorySession(Collections.<VcsFileRevision>emptyList()) {
@Nullable
protected VcsRevisionNumber calcCurrentRevisionNumber() {
try {
return GitHistoryUtils.getCurrentRevision(project, GitHistoryUtils.getLastCommitName(project, path));
}
catch (VcsException e) {
// likely the file is not under VCS anymore.
if (log.isDebugEnabled()) {
log.debug("Unable to retrieve the current revision number", e);
}
return null;
}
}
public HistoryAsTreeProvider getHistoryAsTreeProvider() {
return null;
}
};
partner.reportCreatedEmptySession(emptySession);
GitHistoryUtils.history(project, path, new Consumer<GitFileRevision>() {
public void consume(GitFileRevision gitFileRevision) {
partner.acceptRevision(gitFileRevision);
}
}, new Consumer<VcsException>() {
public void consume(VcsException e) {
partner.reportException(e);
}
});
}
/**
@@ -17,6 +17,7 @@ package git4idea.history;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
@@ -25,10 +26,14 @@ import com.intellij.openapi.vcs.diff.ItemLatestState;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.text.StringTokenizer;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.*;
import git4idea.commands.GitCommand;
import git4idea.commands.GitLineHandler;
import git4idea.commands.GitLineHandlerAdapter;
import git4idea.commands.GitSimpleHandler;
import org.jetbrains.annotations.Nullable;
@@ -115,6 +120,103 @@ public class GitHistoryUtils {
return new ItemLatestState(new GitRevisionNumber(hash, commitDate), lines[2].charAt(0) != 'D', false);
}
public static void history(final Project project, FilePath path, final Consumer<GitFileRevision> consumer,
final Consumer<VcsException> exceptionConsumer) throws VcsException {
// adjust path using change manager
path = getLastCommitName(project, path);
final VirtualFile root = GitUtil.getGitRoot(path);
GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
h.setNoSSH(true);
h.setStdoutSuppressed(true);
h.addParameters("-M", "--follow", "--name-only",
"--pretty=format:%H%x00%ct%x00%an%x20%x3C%ae%x3E%x00%cn%x20%x3C%ce%x3E%x00%s%n%n%b%x00", "--encoding=UTF-8");
h.endOptions();
h.addRelativePaths(path);
final String prefix = root.getPath() + "/";
final MyTokenAccomulator accomulator = new MyTokenAccomulator(6);
final Consumer<List<String>> resultAdapter = new Consumer<List<String>>() {
public void consume(List<String> result) {
final GitRevisionNumber revision = new GitRevisionNumber(result.get(0), GitUtil.parseTimestamp(result.get(1)));
final String author = GitUtil.adjustAuthorName(result.get(2), result.get(3));
final String message = result.get(4).trim();
String path = "";
try {
path = GitUtil.unescapePath(result.get(5));
}
catch (VcsException e) {
exceptionConsumer.consume(e);
}
final FilePath revisionPath = VcsUtil.getFilePathForDeletedFile(prefix + path, false);
consumer.consume(new GitFileRevision(project, revisionPath, revision, author, message, null));
}
};
final Semaphore semaphore = new Semaphore();
h.addLineListener(new GitLineHandlerAdapter() {
@Override
public void onLineAvailable(String line, Key outputType) {
final List<String> result = accomulator.acceptLine(line);
if (result != null) {
resultAdapter.consume(result);
}
}
@Override
public void startFailed(Throwable exception) {
exceptionConsumer.consume(new VcsException(exception));
}
@Override
public void processTerminated(int exitCode) {
super.processTerminated(exitCode);
semaphore.up();
}
});
semaphore.down();
h.start();
semaphore.waitFor();
}
private static class MyTokenAccomulator {
private int myCnt;
private List<String> mySb;
private final int myMax;
private MyTokenAccomulator(final int max) {
myMax = max;
mySb = new ArrayList<String>(6);
myCnt = 0;
}
@Nullable
public List<String> acceptLine(final String s) {
StringTokenizer tk = new StringTokenizer(s.trim(), "\u0000", false);
List<String> result = null;
while (tk.hasMoreElements()) {
final String token = tk.nextToken();
final List<String> curResult = acceptPieces(token);
if (curResult != null) {
result = curResult;
}
}
return result;
}
@Nullable
private List<String> acceptPieces(final String s) {
mySb.add(s);
++ myCnt;
if (myMax == myCnt) {
myCnt = 0;
final List<String> result = mySb;
mySb = new ArrayList<String>(6);
return result;
}
return null;
}
}
/**
* Get history for the file
@@ -33,6 +33,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.CollectConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.UIUtil;
@@ -75,10 +76,6 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
myDirectory = isDirectory;
}
public HistoryAsTreeProvider getTreeHistoryProvider() {
return null;
}
public boolean supportsHistoryForDirectories() {
return true;
}
@@ -133,7 +130,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
return new VcsDependentHistoryComponents(columns, listener, addComp);
}
private class MyHistorySession extends VcsHistorySession {
private class MyHistorySession extends VcsAbstractHistorySession {
private final FilePath myCommittedPath;
private final Map<Long, SvnChangeList> myListsMap;
private final boolean mySupports15;
@@ -143,13 +140,17 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
myCommittedPath = committedPath;
mySupports15 = supports15;
myListsMap = new HashMap<Long, SvnChangeList>();
refresh();
shouldBeRefreshed();
}
public Map<Long, SvnChangeList> getListsMap() {
return myListsMap;
}
public HistoryAsTreeProvider getHistoryAsTreeProvider() {
return null;
}
@Nullable
public VcsRevisionNumber calcCurrentRevisionNumber() {
if (myCommittedPath == null) {
@@ -176,17 +177,35 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
public VcsHistorySession createSessionFor(final FilePath filePath) throws VcsException {
final FilePath committedPath = ChangesUtil.getCommittedPath(myVcs.getProject(), filePath);
final Ref<Boolean> supports15Ref = new Ref<Boolean>();
final List<VcsFileRevision> revisions = getRevisionsList(committedPath, supports15Ref);
if (revisions == null) {
return null;
}
final List<VcsFileRevision> revisions = new ArrayList<VcsFileRevision>();
getRevisionsList(committedPath, supports15Ref, new CollectConsumer<VcsFileRevision>(revisions));
return new MyHistorySession(revisions, committedPath, Boolean.TRUE.equals(supports15Ref.get()));
}
public void reportAppendableHistory(FilePath path, final VcsAppendableHistorySessionPartner partner) throws VcsException {
final FilePath committedPath = ChangesUtil.getCommittedPath(myVcs.getProject(), path);
final Ref<Boolean> supports15Ref = new Ref<Boolean>();
final MyHistorySession historySession =
new MyHistorySession(Collections.<VcsFileRevision>emptyList(), committedPath, Boolean.TRUE.equals(supports15Ref.get()));
final Ref<Boolean> sessionReported = new Ref<Boolean>();
getRevisionsList(committedPath, supports15Ref, new Consumer<VcsFileRevision>() {
public void consume(VcsFileRevision vcsFileRevision) {
if (! Boolean.TRUE.equals(sessionReported.get())) {
partner.reportCreatedEmptySession(historySession);
sessionReported.set(true);
}
partner.acceptRevision(vcsFileRevision);
}
});
}
@Nullable
private List<VcsFileRevision> getRevisionsList(final FilePath file, final Ref<Boolean> supports15Ref) throws VcsException {
private void getRevisionsList(final FilePath file, final Ref<Boolean> supports15Ref,
final Consumer<VcsFileRevision> consumer) throws VcsException {
final SVNException[] exception = new SVNException[1];
final ArrayList<VcsFileRevision> result = new ArrayList<VcsFileRevision>();
Runnable command = new Runnable() {
public void run() {
@@ -196,9 +215,9 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
}
try {
if (myURL == null) {
collectLogEntries(indicator, file, exception, result, supports15Ref);
collectLogEntries(indicator, file, exception, consumer, supports15Ref);
} else {
collectLogEntriesForRepository(indicator, result, supports15Ref);
collectLogEntriesForRepository(indicator, consumer, supports15Ref);
}
}
catch(SVNCancelException ex) {
@@ -215,11 +234,10 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
if (exception[0] != null) {
throw new VcsException(exception[0]);
}
return result;
}
private void collectLogEntries(final ProgressIndicator indicator, FilePath file, SVNException[] exception,
final ArrayList<VcsFileRevision> result, final Ref<Boolean> supports15Ref) throws SVNException {
final Consumer<VcsFileRevision> result, final Ref<Boolean> supports15Ref) throws SVNException {
SVNWCClient wcClient = myVcs.createWCClient();
SVNInfo info = wcClient.doInfo(new File(file.getIOFile().getAbsolutePath()), SVNRevision.WORKING);
wcClient.setEventHandler(new ISVNEventHandler() {
@@ -255,7 +273,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
new MyLogEntryHandler(url, pegRevision, relativeUrl, result));
}
private void collectLogEntriesForRepository(final ProgressIndicator indicator, final ArrayList<VcsFileRevision> result,
private void collectLogEntriesForRepository(final ProgressIndicator indicator, final Consumer<VcsFileRevision> result,
final Ref<Boolean> supports15Ref) throws SVNException {
if (indicator != null) {
indicator.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", myURL.toString()));
@@ -299,7 +317,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
}
}
public AnAction[] getAdditionalActions(final FileHistoryPanel panel) {
public AnAction[] getAdditionalActions(final Runnable refresher) {
return new AnAction[]{new ShowAllSubmittedFilesAction(), new MergeSourceDetailsAction()};
}
@@ -310,12 +328,13 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
private class MyLogEntryHandler implements ISVNLogEntryHandler {
private final ProgressIndicator myIndicator;
private String myLastPath;
protected final ArrayList<VcsFileRevision> myResult;
protected final Consumer<VcsFileRevision> myResult;
private VcsFileRevision myPrevious;
private final SVNRevision myPegRevision;
private final String myUrl;
private int myMergeLevel;
public MyLogEntryHandler(final String url, final SVNRevision pegRevision, String lastPath, final ArrayList<VcsFileRevision> result) {
public MyLogEntryHandler(final String url, final SVNRevision pegRevision, String lastPath, final Consumer<VcsFileRevision> result) {
myLastPath = lastPath;
myIndicator = ProgressManager.getInstance().getProgressIndicator();
myResult = result;
@@ -361,9 +380,10 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
}
final SvnFileRevision revision = createRevision(logEntry, copyPath);
if (myMergeLevel >= 0) {
addToListByLevel((SvnFileRevision) myResult.get(myResult.size() - 1), revision, myMergeLevel);
addToListByLevel((SvnFileRevision) myPrevious, revision, myMergeLevel);
} else {
myResult.add(revision);
myResult.consume(revision);
myPrevious = revision;
}
if (logEntry.hasChildren()) {
++ myMergeLevel;
@@ -394,7 +414,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider {
}
private class RepositoryLogEntryHandler extends MyLogEntryHandler {
public RepositoryLogEntryHandler(final String url, final SVNRevision pegRevision, String lastPath, final ArrayList<VcsFileRevision> result) {
public RepositoryLogEntryHandler(final String url, final SVNRevision pegRevision, String lastPath, final Consumer<VcsFileRevision> result) {
super(url, pegRevision, lastPath, result);
}