mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
VCS: lazy file history
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -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();
|
||||
}
|
||||
|
||||
+5
-2
@@ -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());
|
||||
}
|
||||
|
||||
+9
-6
@@ -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 {
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+45
-1
@@ -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 {
|
||||
|
||||
+23
-10
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user