[log] Send refresh events only to the proper instance of the log

Instead of two event mechanism, introduce a single one: post evens
when the VisiblePack is updated. Some clients need to know, whether
the VisiblePack update was triggered by refresh or not, so supply a
flag for them.
This commit is contained in:
Kirill Likhodedov
2014-10-15 16:54:01 +04:00
parent 2d79d2e908
commit 73a800daa5
9 changed files with 83 additions and 115 deletions
@@ -1,22 +0,0 @@
/*
* Copyright 2000-2014 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.vcs.log;
public interface VcsLogFilterChangeListener {
void filtersPossiblyChanged();
}
@@ -13,15 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.vcs.log.data;
package com.intellij.vcs.log;
import org.jetbrains.annotations.NotNull;
/**
* This listener is notified about VCS log refresh procedure.
* Listens to changes in the log, both in Permanent and Visible parts.
*/
public interface VcsLogRefreshListener {
public interface VcsLogListener {
void refresh(@NotNull DataPack dataPack);
/**
* This method is called whether a refresh happened, or filter changed, or the VisibleGraph was rebuilt.
* <p/>
* It is called on the EDT thread.
*
* @param dataPack new VcsLogDataPack which was just applied to the UI.
* @param refreshHappened true if a refresh initiated this log change, i.e. PermanentGraph changed.
*/
void onChange(@NotNull VcsLogDataPack dataPack, boolean refreshHappened);
}
@@ -28,8 +28,8 @@ public interface VcsLogUi {
void addHighlighter(@NotNull VcsLogHighlighter highlighter);
void removeHighlighter(@NotNull VcsLogHighlighter highlighter);
void addFilterChangeListener(@NotNull VcsLogFilterChangeListener listener);
void removeFilterChangeListener(@NotNull VcsLogFilterChangeListener listener);
void addLogListener(@NotNull VcsLogListener listener);
void removeLogListener(@NotNull VcsLogListener listener);
void setBranchesPanelVisible(boolean visible);
@@ -18,12 +18,13 @@ package com.intellij.vcs.log.data;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ThrowableConsumer;
import com.intellij.util.containers.SLRUMap;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogDataPack;
import com.intellij.vcs.log.VcsLogListener;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.util.SequentialLimitedLifoExecutor;
import org.jetbrains.annotations.NotNull;
@@ -38,7 +39,7 @@ import java.util.List;
/**
* Provides capabilities to asynchronously calculate "contained in branches" information.
*/
public class ContainingBranchesGetter {
public class ContainingBranchesGetter implements VcsLogListener {
private static final Logger LOG = Logger.getInstance(ContainingBranchesGetter.class);
@@ -48,7 +49,7 @@ public class ContainingBranchesGetter {
@Nullable private Runnable myLoadingFinishedListener; // access only from EDT
private int myCurrentBranchesChecksum;
ContainingBranchesGetter(@NotNull Project project, @NotNull VcsLogDataHolder dataHolder, @NotNull Disposable parentDisposable) {
ContainingBranchesGetter(@NotNull VcsLogDataHolder dataHolder, @NotNull Disposable parentDisposable) {
myDataHolder = dataHolder;
myTaskExecutor = new SequentialLimitedLifoExecutor<Task>(parentDisposable, 10, new ThrowableConsumer<Task, Throwable>() {
@Override
@@ -65,17 +66,18 @@ public class ContainingBranchesGetter {
});
}
});
project.getMessageBus().connect(parentDisposable).subscribe(VcsLogDataHolder.REFRESH_COMPLETED, new VcsLogRefreshListener() {
@Override
public void refresh(@NotNull DataPack dataPack) {
Collection<VcsRef> currentBranches = dataPack.getRefs().getBranches();
int checksum = currentBranches.hashCode();
if (myCurrentBranchesChecksum != 0 && myCurrentBranchesChecksum != checksum) { // clear cache if branches set changed after refresh
clearCache();
}
myCurrentBranchesChecksum = checksum;
}
@Override
public void onChange(@NotNull VcsLogDataPack dataPack, boolean refreshHappened) {
if (refreshHappened) {
Collection<VcsRef> currentBranches = dataPack.getRefs().getBranches();
int checksum = currentBranches.hashCode();
if (myCurrentBranchesChecksum != 0 && myCurrentBranchesChecksum != checksum) { // clear cache if branches set changed after refresh
clearCache();
}
});
myCurrentBranchesChecksum = checksum;
}
}
private void clearCache() {
@@ -28,7 +28,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.ThrowableConsumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.Topic;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.graph.PermanentGraph;
import com.intellij.vcs.log.util.StopWatch;
@@ -42,8 +41,6 @@ import java.util.Set;
public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
public static final Topic<VcsLogRefreshListener> REFRESH_COMPLETED = Topic.create("Vcs.Log.Completed", VcsLogRefreshListener.class);
private static final Logger LOG = Logger.getInstance(VcsLogDataHolder.class);
@NotNull private final Project myProject;
@@ -97,7 +94,7 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
catch (IOException e) {
throw new RuntimeException(e); // TODO: show a message to the user & fallback to using in-memory Hashes
}
myContainingBranchesGetter = new ContainingBranchesGetter(project, this, this);
myContainingBranchesGetter = new ContainingBranchesGetter(this, this);
myFilterer = new VcsLogFiltererImpl(myProject, myLogProviders, myHashMap, myTopCommitsDetailsCache, myDetailsGetter,
uiProperties.isBek() ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal,
@@ -107,7 +104,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
@Override
public void consume(DataPack dataPack) {
myFilterer.onRefresh(dataPack);
myProject.getMessageBus().syncPublisher(REFRESH_COMPLETED).refresh(dataPack);
}
};
@@ -79,6 +79,7 @@ public class VcsLogManager implements Disposable {
final VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, myUiProperties, visiblePackConsumer);
myUi = new VcsLogUiImpl(logDataHolder, myProject, mySettings,
new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties, logDataHolder.getFilterer());
myUi.addLogListener(logDataHolder.getContainingBranchesGetter()); // TODO: remove this after VcsLogDataHolder vs VcsLoUi dependency cycle is solved
if (contentTabName != null) {
myLogRefresher = new PostponeableLogRefresher(myProject, logDataHolder, contentTabName);
}
@@ -46,7 +46,7 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
@NotNull private final VcsLogUiProperties myUiProperties;
@NotNull private final VcsLogFilterer myFilterer;
@NotNull private final Collection<VcsLogFilterChangeListener> myFilterChangeListeners = ContainerUtil.newArrayList();
@NotNull private final Collection<VcsLogListener> myLogListeners = ContainerUtil.newArrayList();
@NotNull private VisiblePack myVisiblePack;
@@ -69,13 +69,16 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
TIntHashSet previouslySelected = getSelectedCommits();
PermanentGraph<Integer> previousPermGraph = myVisiblePack.getPermanentGraph();
myVisiblePack = pack;
boolean permGraphChanged = previousPermGraph != myVisiblePack.getPermanentGraph();
GraphTableModel newModel = new GraphTableModel(myVisiblePack, myLogDataHolder, this);
setModel(newModel, myVisiblePack.getVisibleGraph(), previouslySelected);
myMainFrame.updateDataPack(myVisiblePack);
setLongEdgeVisibility(myUiProperties.areLongEdgesVisible());
fireFilterChangeEvent();
fireFilterChangeEvent(myVisiblePack, permGraphChanged);
repaintUI();
}
@@ -376,18 +379,18 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
}
@Override
public void addFilterChangeListener(@NotNull VcsLogFilterChangeListener listener) {
myFilterChangeListeners.add(listener);
public void addLogListener(@NotNull VcsLogListener listener) {
myLogListeners.add(listener);
}
@Override
public void removeFilterChangeListener(@NotNull VcsLogFilterChangeListener listener) {
myFilterChangeListeners.remove(listener);
public void removeLogListener(@NotNull VcsLogListener listener) {
myLogListeners.remove(listener);
}
private void fireFilterChangeEvent() {
for (VcsLogFilterChangeListener listener : myFilterChangeListeners) {
listener.filtersPossiblyChanged();
private void fireFilterChangeEvent(@NotNull VisiblePack visiblePack, boolean refresh) {
for (VcsLogListener listener : myLogListeners) {
listener.onChange(visiblePack, refresh);
}
}
@@ -1,7 +1,6 @@
package com.intellij.vcs.log.ui.frame;
import com.google.common.collect.Ordering;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.vfs.VirtualFile;
@@ -12,14 +11,9 @@ import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.RefGroup;
import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcs.log.VcsLogRefManager;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.data.DataPack;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.RefsModel;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VcsLogRefreshListener;
import com.intellij.vcs.log.impl.SingletonRefGroup;
import com.intellij.vcs.log.impl.VcsLogUtil;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
@@ -84,11 +78,12 @@ public class BranchesPanel extends JPanel {
}
});
Project project = dataHolder.getProject();
project.getMessageBus().connect(project).subscribe(VcsLogDataHolder.REFRESH_COMPLETED, new VcsLogRefreshListener() {
myUI.addLogListener(new VcsLogListener() {
@Override
public void refresh(@NotNull DataPack dataPack) {
rebuild(dataPack.getRefsModel());
public void onChange(@NotNull VcsLogDataPack dataPack, boolean refresh) {
if (refresh) {
rebuild(dataPack.getRefs());
}
}
});
}
@@ -119,13 +114,13 @@ public class BranchesPanel extends JPanel {
}
}
public void rebuild(@NotNull RefsModel refsModel) {
public void rebuild(@NotNull VcsLogRefs refsModel) {
myRefGroups = getRefsToDisplayOnPanel(refsModel);
getParent().repaint();
}
@NotNull
private List<RefGroup> getRefsToDisplayOnPanel(@NotNull RefsModel refsModel) {
private List<RefGroup> getRefsToDisplayOnPanel(@NotNull VcsLogRefs refsModel) {
Collection<VcsRef> allRefs = refsModel.getBranches();
List<RefGroup> groups = ContainerUtil.newArrayList();
@@ -28,11 +28,7 @@ import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.DataPack;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VcsLogRefreshListener;
import com.intellij.vcs.log.impl.HashImpl;
import git4idea.GitBranch;
import git4idea.commands.GitCommand;
@@ -54,7 +50,7 @@ public class DeepComparator implements Disposable {
@NotNull private final Project myProject;
@NotNull private final GitRepositoryManager myRepositoryManager;
@NotNull private final VcsLogUi myUi;
@NotNull private final VcsLogFilterChangeListener myFilterChangeListener;
@NotNull private final VcsLogListener myLogListener;
@Nullable private VcsLogHighlighter myHighlighter;
@Nullable private MyTask myTask;
@@ -71,64 +67,53 @@ public class DeepComparator implements Disposable {
myUi = ui;
Disposer.register(parent, this);
myFilterChangeListener = new VcsLogFilterChangeListener() {
myLogListener = new VcsLogListener() {
@Override
public void filtersPossiblyChanged() {
if (myTask == null) { // no task in progress => not interested in filter changes
return;
}
VcsLogBranchFilter branchFilter = myUi.getFilterUi().getFilters().getBranchFilter();
if (branchFilter == null ||
branchFilter.getBranchNames().size() != 1 ||
!branchFilter.getBranchNames().iterator().next().equals(myTask.myComparedBranch)) {
stopAndUnhighlight();
}
}
};
myUi.addFilterChangeListener(myFilterChangeListener);
project.getMessageBus().connect(project).subscribe(VcsLogDataHolder.REFRESH_COMPLETED, new VcsLogRefreshListener() {
@Override
public void refresh(@NotNull DataPack dataPack) {
public void onChange(@NotNull VcsLogDataPack dataPack, boolean refreshHappened) {
if (myTask == null) { // no task in progress => not interested in refresh events
return;
}
// collect data
String comparedBranch = myTask.myComparedBranch;
Map<GitRepository, GitBranch> repositoriesWithCurrentBranches = myTask.myRepositoriesWithCurrentBranches;
VcsLogDataProvider provider = myTask.myProvider;
if (refreshHappened) {
// collect data
String comparedBranch = myTask.myComparedBranch;
Map<GitRepository, GitBranch> repositoriesWithCurrentBranches = myTask.myRepositoriesWithCurrentBranches;
VcsLogDataProvider provider = myTask.myProvider;
stopAndUnhighlight();
stopAndUnhighlight();
// highlight again
Map<GitRepository, GitBranch> repositories = getRepositories(dataPack.getLogProviders(), comparedBranch);
if (repositories.equals(repositoriesWithCurrentBranches)) { // but not if current branch changed
highlightInBackground(comparedBranch, provider);
// highlight again
Map<GitRepository, GitBranch> repositories = getRepositories(myUi.getDataPack().getLogProviders(), comparedBranch);
if (repositories.equals(repositoriesWithCurrentBranches)) { // but not if current branch changed
highlightInBackground(comparedBranch, provider);
}
}
else {
VcsLogBranchFilter branchFilter = myUi.getFilterUi().getFilters().getBranchFilter();
if (branchFilter == null ||
branchFilter.getBranchNames().size() != 1 ||
!branchFilter.getBranchNames().iterator().next().equals(myTask.myComparedBranch)) {
stopAndUnhighlight();
}
}
}
});
};
myUi.addLogListener(myLogListener);
}
public void highlightInBackground(@NotNull final String branchToCompare, @NotNull final VcsLogDataProvider dataProvider) {
public void highlightInBackground(@NotNull String branchToCompare, @NotNull VcsLogDataProvider dataProvider) {
if (myTask != null) {
LOG.error("Shouldn't be possible");
return;
}
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
Map<GitRepository, GitBranch> repositories = getRepositories(myUi.getDataPack().getLogProviders(), branchToCompare);
if (repositories.isEmpty()) {
return;
}
Map<GitRepository, GitBranch> repositories = getRepositories(myUi.getDataPack().getLogProviders(), branchToCompare);
if (repositories.isEmpty()) {
return;
}
myTask = new MyTask(myProject, myUi, repositories, dataProvider, branchToCompare);
myTask.queue();
}
});
myTask = new MyTask(myProject, myUi, repositories, dataProvider, branchToCompare);
myTask.queue();
}
@NotNull
@@ -159,7 +144,7 @@ public class DeepComparator implements Disposable {
@Override
public void dispose() {
stopAndUnhighlight();
myUi.removeFilterChangeListener(myFilterChangeListener);
myUi.removeLogListener(myLogListener);
}
public boolean hasHighlightingOrInProgress() {