mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[vcs-log] extract PostponableLogRefresher from VcsLogTabsRefresher that does not know about tabs; incapsulate filterer + tab name via VcsLogWindow
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.VcsLogRefresher;
|
||||
import com.intellij.vcs.log.data.DataPack;
|
||||
import com.intellij.vcs.log.data.DataPackChangeListener;
|
||||
import com.intellij.vcs.log.data.VcsLogDataManager;
|
||||
import com.intellij.vcs.log.data.VcsLogFilterer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class PostponableLogRefresher implements VcsLogRefresher {
|
||||
@NotNull protected final VcsLogDataManager myDataManager;
|
||||
@NotNull private final Set<VirtualFile> myRootsToRefresh = ContainerUtil.newHashSet();
|
||||
@NotNull private final Set<VcsLogWindow> myLogWindows = ContainerUtil.newHashSet();
|
||||
|
||||
public PostponableLogRefresher(@NotNull VcsLogDataManager dataManager) {
|
||||
myDataManager = dataManager;
|
||||
myDataManager.addDataPackChangeListener(new DataPackChangeListener() {
|
||||
@Override
|
||||
public void onDataPackChange(@NotNull DataPack dataPack) {
|
||||
for (VcsLogWindow window : myLogWindows) {
|
||||
dataPackArrived(window.getFilterer(), window.isVisible());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Disposable addLogWindow(@NotNull VcsLogWindow window) {
|
||||
myLogWindows.add(window);
|
||||
filtererActivated(window.getFilterer(), true);
|
||||
return new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myLogWindows.remove(window);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Disposable addLogWindow(@NotNull VcsLogFilterer filterer) {
|
||||
return addLogWindow(new VcsLogWindow(filterer));
|
||||
}
|
||||
|
||||
private static boolean keepUpToDate() {
|
||||
return Registry.is("vcs.log.keep.up.to.date");
|
||||
}
|
||||
|
||||
protected boolean canRefreshNow() {
|
||||
if (keepUpToDate()) return true;
|
||||
for (VcsLogWindow window : myLogWindows) {
|
||||
if (window.isVisible()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void filtererActivated(@NotNull VcsLogFilterer filterer, boolean firstTime) {
|
||||
if (!myRootsToRefresh.isEmpty()) {
|
||||
refreshPostponedRoots();
|
||||
}
|
||||
else {
|
||||
if (!filterer.isValid() || firstTime) {
|
||||
filterer.onRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void dataPackArrived(@NotNull VcsLogFilterer filterer, boolean canRefreshNow) {
|
||||
if (canRefreshNow) {
|
||||
filterer.onRefresh();
|
||||
}
|
||||
else {
|
||||
filterer.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh(@NotNull final VirtualFile root) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (canRefreshNow()) {
|
||||
myDataManager.refresh(Collections.singleton(root));
|
||||
}
|
||||
else {
|
||||
myRootsToRefresh.add(root);
|
||||
}
|
||||
}
|
||||
}, ModalityState.any());
|
||||
}
|
||||
|
||||
protected void refreshPostponedRoots() {
|
||||
Set<VirtualFile> toRefresh = new HashSet<VirtualFile>(myRootsToRefresh);
|
||||
myRootsToRefresh.removeAll(toRefresh); // clear the set, but keep roots which could possibly arrive after collecting them in the var.
|
||||
myDataManager.refresh(toRefresh);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<VcsLogWindow> getLogWindows() {
|
||||
return myLogWindows;
|
||||
}
|
||||
|
||||
public static class VcsLogWindow {
|
||||
@NotNull private final VcsLogFilterer myFilterer;
|
||||
|
||||
public VcsLogWindow(@NotNull VcsLogFilterer filterer) {
|
||||
myFilterer = filterer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VcsLogFilterer getFilterer() {
|
||||
return myFilterer;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,11 @@ import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.vcs.log.VcsLogProvider;
|
||||
import com.intellij.vcs.log.data.*;
|
||||
import com.intellij.vcs.log.VcsLogRefresher;
|
||||
import com.intellij.vcs.log.data.VcsLogDataManager;
|
||||
import com.intellij.vcs.log.data.VcsLogFiltererImpl;
|
||||
import com.intellij.vcs.log.data.VcsLogTabsProperties;
|
||||
import com.intellij.vcs.log.data.VcsLogUiProperties;
|
||||
import com.intellij.vcs.log.graph.PermanentGraph;
|
||||
import com.intellij.vcs.log.ui.VcsLogColorManagerImpl;
|
||||
import com.intellij.vcs.log.ui.VcsLogUiImpl;
|
||||
@@ -59,6 +63,7 @@ public class VcsLogManager implements Disposable {
|
||||
private VcsLogDataManager myDataManager;
|
||||
private VcsLogColorManagerImpl myColorManager;
|
||||
private VcsLogTabsRefresher myTabsLogRefresher;
|
||||
private PostponableLogRefresher myPostponableRefresher;
|
||||
|
||||
public VcsLogManager(@NotNull Project project, @NotNull VcsLogTabsProperties uiProperties) {
|
||||
myProject = project;
|
||||
@@ -74,40 +79,12 @@ public class VcsLogManager implements Disposable {
|
||||
return Arrays.asList(ProjectLevelVcsManager.getInstance(myProject).getAllVcsRoots());
|
||||
}
|
||||
|
||||
public void watchTab(@NotNull final String contentTabName, @NotNull VcsLogUiImpl logUi) {
|
||||
myTabsLogRefresher.addTabToWatch(contentTabName, logUi.getFilterer());
|
||||
Disposer.register(logUi, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
unwatchTab(contentTabName);
|
||||
}
|
||||
});
|
||||
public void watchTab(@NotNull String contentTabName, @NotNull VcsLogUiImpl logUi) {
|
||||
Disposer.register(logUi, myTabsLogRefresher.addTabToWatch(contentTabName, logUi.getFilterer()));
|
||||
}
|
||||
|
||||
public void unwatchTab(@NotNull String contentTabName) {
|
||||
if (myTabsLogRefresher != null) myTabsLogRefresher.removeTabFromWatch(contentTabName);
|
||||
}
|
||||
|
||||
private void watch(@NotNull final VcsLogUiImpl ui) {
|
||||
final DataPackChangeListener listener = new DataPackChangeListener() {
|
||||
@Override
|
||||
public void onDataPackChange(@NotNull DataPack dataPack) {
|
||||
ui.getFilterer().onRefresh();
|
||||
}
|
||||
};
|
||||
myDataManager.addDataPackChangeListener(listener);
|
||||
Disposer.register(ui, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myDataManager.removeDataPackChangeListener(listener);
|
||||
}
|
||||
});
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ui.getFilterer().onRefresh();
|
||||
}
|
||||
});
|
||||
private void watch(@NotNull VcsLogUiImpl ui) {
|
||||
Disposer.register(ui, myPostponableRefresher.addLogWindow(ui.getFilterer()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -138,9 +115,10 @@ public class VcsLogManager implements Disposable {
|
||||
|
||||
Map<VirtualFile, VcsLogProvider> logProviders = findLogProviders(getVcsRoots(), myProject);
|
||||
myDataManager = new VcsLogDataManager(myProject, logProviders, new MyFatalErrorsConsumer());
|
||||
myTabsLogRefresher = new VcsLogTabsRefresher(myProject, myDataManager);
|
||||
myPostponableRefresher = new PostponableLogRefresher(myDataManager);
|
||||
myTabsLogRefresher = new VcsLogTabsRefresher(myProject, myPostponableRefresher, myDataManager);
|
||||
|
||||
refreshLogOnVcsEvents(logProviders, myTabsLogRefresher);
|
||||
refreshLogOnVcsEvents(logProviders, myPostponableRefresher, myDataManager);
|
||||
|
||||
myColorManager = new VcsLogColorManagerImpl(logProviders.keySet());
|
||||
|
||||
@@ -149,7 +127,8 @@ public class VcsLogManager implements Disposable {
|
||||
}
|
||||
|
||||
private static void refreshLogOnVcsEvents(@NotNull Map<VirtualFile, VcsLogProvider> logProviders,
|
||||
@NotNull VcsLogTabsRefresher refresher) {
|
||||
@NotNull VcsLogRefresher refresher,
|
||||
@NotNull Disposable disposableParent) {
|
||||
MultiMap<VcsLogProvider, VirtualFile> providers2roots = MultiMap.create();
|
||||
for (Map.Entry<VirtualFile, VcsLogProvider> entry : logProviders.entrySet()) {
|
||||
providers2roots.putValue(entry.getValue(), entry.getKey());
|
||||
@@ -157,7 +136,7 @@ public class VcsLogManager implements Disposable {
|
||||
|
||||
for (Map.Entry<VcsLogProvider, Collection<VirtualFile>> entry : providers2roots.entrySet()) {
|
||||
Disposable disposable = entry.getKey().subscribeToRootRefreshEvents(entry.getValue(), refresher);
|
||||
Disposer.register(refresher, disposable);
|
||||
Disposer.register(disposableParent, disposable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,6 +179,7 @@ public class VcsLogManager implements Disposable {
|
||||
|
||||
myDataManager = null;
|
||||
myTabsLogRefresher = null;
|
||||
myPostponableRefresher = null;
|
||||
myColorManager = null;
|
||||
myUi = null;
|
||||
}
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
package com.intellij.vcs.log.impl;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.ToolWindowManager;
|
||||
import com.intellij.openapi.wm.ex.ToolWindowManagerListener;
|
||||
import com.intellij.openapi.wm.impl.ToolWindowImpl;
|
||||
@@ -33,111 +30,33 @@ import com.intellij.ui.content.ContentManagerEvent;
|
||||
import com.intellij.ui.content.TabbedContent;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.VcsLogRefresher;
|
||||
import com.intellij.vcs.log.data.DataPack;
|
||||
import com.intellij.vcs.log.data.DataPackChangeListener;
|
||||
import com.intellij.vcs.log.data.VcsLogDataManager;
|
||||
import com.intellij.vcs.log.data.VcsLogFilterer;
|
||||
import com.intellij.vcs.log.impl.PostponableLogRefresher.VcsLogWindow;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class VcsLogTabsRefresher implements VcsLogRefresher, Disposable {
|
||||
public class VcsLogTabsRefresher implements Disposable {
|
||||
private static final String TOOLWINDOW_ID = ChangesViewContentManager.TOOLWINDOW_ID;
|
||||
|
||||
@NotNull private final VcsLogDataManager myDataManager;
|
||||
@NotNull private final PostponableLogRefresher myRefresher;
|
||||
|
||||
@NotNull private final ToolWindowManagerImpl myToolWindowManager;
|
||||
@NotNull private final ToolWindowImpl myToolWindow;
|
||||
@NotNull private final MyRefreshPostponedEventsListener myPostponedEventsListener;
|
||||
|
||||
@NotNull private final Map<String, VcsLogFilterer> myTabToFiltererMap = ContainerUtil.newHashMap();
|
||||
@NotNull private final Set<VirtualFile> myRootsToRefresh = ContainerUtil.newHashSet();
|
||||
|
||||
public VcsLogTabsRefresher(@NotNull Project project, @NotNull VcsLogDataManager dataManager) {
|
||||
myDataManager = dataManager;
|
||||
public VcsLogTabsRefresher(@NotNull Project project, @NotNull PostponableLogRefresher refresher, @NotNull Disposable parentDisposable) {
|
||||
myRefresher = refresher;
|
||||
myToolWindowManager = (ToolWindowManagerImpl)ToolWindowManager.getInstance(project);
|
||||
myToolWindow = ObjectUtils.assertNotNull((ToolWindowImpl)myToolWindowManager.getToolWindow(TOOLWINDOW_ID));
|
||||
|
||||
Disposer.register(dataManager, this);
|
||||
|
||||
myPostponedEventsListener = new MyRefreshPostponedEventsListener();
|
||||
myToolWindow.getContentManager().addContentManagerListener(myPostponedEventsListener);
|
||||
myToolWindowManager.addToolWindowManagerListener(myPostponedEventsListener);
|
||||
|
||||
myDataManager.addDataPackChangeListener(new DataPackChangeListener() {
|
||||
@Override
|
||||
public void onDataPackChange(@NotNull DataPack dataPack) {
|
||||
for (Map.Entry<String, VcsLogFilterer> tabAndFilterer : myTabToFiltererMap.entrySet()) {
|
||||
dataPackArrived(tabAndFilterer.getValue(), isTabVisible(tabAndFilterer.getKey()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void tabActivated(@NotNull VcsLogFilterer filterer, boolean firstTime) {
|
||||
if (!myRootsToRefresh.isEmpty()) {
|
||||
refreshPostponedRoots();
|
||||
}
|
||||
else {
|
||||
if (!filterer.isValid() || firstTime) {
|
||||
filterer.onRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void dataPackArrived(@NotNull VcsLogFilterer filterer, boolean visible) {
|
||||
if (visible) {
|
||||
filterer.onRefresh();
|
||||
}
|
||||
else {
|
||||
filterer.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(@NotNull final VirtualFile root) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (canRefreshNow()) {
|
||||
myDataManager.refresh(Collections.singleton(root));
|
||||
}
|
||||
else {
|
||||
myRootsToRefresh.add(root);
|
||||
}
|
||||
}
|
||||
}, ModalityState.any());
|
||||
}
|
||||
|
||||
private void refreshPostponedRoots() {
|
||||
Set<VirtualFile> toRefresh = new HashSet<VirtualFile>(myRootsToRefresh);
|
||||
myRootsToRefresh.removeAll(toRefresh); // clear the set, but keep roots which could possibly arrive after collecting them in the var.
|
||||
myDataManager.refresh(toRefresh);
|
||||
}
|
||||
|
||||
private static boolean keepUpToDate() {
|
||||
return Registry.is("vcs.log.keep.up.to.date");
|
||||
}
|
||||
|
||||
private boolean canRefreshNow() {
|
||||
return isOneOfTabsVisible(myTabToFiltererMap.keySet()) || keepUpToDate();
|
||||
}
|
||||
|
||||
protected boolean isTabVisible(@NotNull String tab) {
|
||||
return isOneOfTabsVisible(Collections.singleton(tab));
|
||||
}
|
||||
|
||||
private boolean isOneOfTabsVisible(@NotNull Set<String> tabs) {
|
||||
if (tabs.isEmpty()) return true;
|
||||
// probably, each log ui should determine where it is located (not necessarily in Log window tool tabs) and when it is visible
|
||||
String selectedTab = getSelectedTabName();
|
||||
return selectedTab != null && tabs.contains(selectedTab);
|
||||
Disposer.register(parentDisposable, this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -151,13 +70,9 @@ public class VcsLogTabsRefresher implements VcsLogRefresher, Disposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addTabToWatch(@NotNull String contentTabName, @NotNull VcsLogFilterer filterer) {
|
||||
myTabToFiltererMap.put(contentTabName, filterer);
|
||||
tabActivated(filterer, true);
|
||||
}
|
||||
|
||||
public void removeTabFromWatch(@NotNull String contentTabName) {
|
||||
myTabToFiltererMap.remove(contentTabName);
|
||||
@NotNull
|
||||
public Disposable addTabToWatch(@NotNull String contentTabName, @NotNull VcsLogFilterer filterer) {
|
||||
return myRefresher.addLogWindow(new VcsLogTab(filterer, contentTabName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,6 +87,21 @@ public class VcsLogTabsRefresher implements VcsLogRefresher, Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public class VcsLogTab extends PostponableLogRefresher.VcsLogWindow {
|
||||
@NotNull private final String myTabName;
|
||||
|
||||
public VcsLogTab(@NotNull VcsLogFilterer filterer, @NotNull String tabName) {
|
||||
super(filterer);
|
||||
myTabName = tabName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
String selectedTab = getSelectedTabName();
|
||||
return selectedTab != null && myTabName.equals(selectedTab);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyRefreshPostponedEventsListener extends ContentManagerAdapter
|
||||
implements ToolWindowManagerListener, PropertyChangeListener {
|
||||
|
||||
@@ -183,9 +113,14 @@ public class VcsLogTabsRefresher implements VcsLogRefresher, Disposable {
|
||||
}
|
||||
|
||||
private void selectionChanged(String tabName) {
|
||||
VcsLogFilterer filterer = myTabToFiltererMap.get(tabName);
|
||||
if (filterer != null) {
|
||||
tabActivated(filterer, false);
|
||||
VcsLogWindow logWindow = ContainerUtil.find(myRefresher.getLogWindows(), new Condition<VcsLogWindow>() {
|
||||
@Override
|
||||
public boolean value(VcsLogWindow window) {
|
||||
return window instanceof VcsLogTab && ((VcsLogTab)window).myTabName.equals(tabName);
|
||||
}
|
||||
});
|
||||
if (logWindow != null) {
|
||||
myRefresher.filtererActivated(logWindow.getFilterer(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user