[log] Don't load the log on startup: wait until user opens it

* Make VcsLogManager a service instead of component.
* Introduce VcsLogContentProvider implementing the ChangesView EP
  which initializes the component only when it is selected for the
  first time.
This commit is contained in:
Kirill Likhodedov
2013-10-30 19:32:48 +04:00
parent 013f787caa
commit a9eacb0f76
4 changed files with 97 additions and 78 deletions
@@ -1,17 +1,15 @@
<idea-plugin>
<project-components>
<component>
<interface-class>com.intellij.vcs.log.impl.VcsLogManager</interface-class>
<implementation-class>com.intellij.vcs.log.impl.VcsLogManager</implementation-class>
</component>
</project-components>
<extensionPoints>
<extensionPoint name="logProvider" interface="com.intellij.vcs.log.VcsLogProvider" area="IDEA_PROJECT"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<changesViewContent tabName="Log" className="com.intellij.vcs.log.impl.VcsLogContentProvider"
predicateClassName="com.intellij.vcs.log.impl.VcsLogContentProvider"/>
<applicationService serviceInterface="com.intellij.vcs.log.VcsLogObjectsFactory" serviceImplementation="com.intellij.vcs.log.impl.VcsLogObjectsFactoryImpl" />
<projectService serviceInterface="com.intellij.vcs.log.impl.VcsLogManager" serviceImplementation="com.intellij.vcs.log.impl.VcsLogManager"/>
<projectService serviceInterface="com.intellij.vcs.log.VcsLogSettings" serviceImplementation="com.intellij.vcs.log.impl.VcsLogSettingsImpl"/>
<projectService serviceInterface="com.intellij.vcs.log.data.VcsLogUiProperties" serviceImplementation="com.intellij.vcs.log.data.VcsLogUiProperties"/>
<projectService serviceInterface="com.intellij.vcs.log.VcsLog" serviceImplementation="com.intellij.vcs.log.impl.VcsLogImpl" />
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2013 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.project.Project;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentProvider;
import com.intellij.util.NotNullFunction;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* Provides the Content tab to the ChangesView log toolwindow.
*
* Delegates to the VcsLogManager.
*/
public class VcsLogContentProvider implements ChangesViewContentProvider, NotNullFunction<Project, Boolean> {
@NotNull private final VcsLogManager myLogManager;
public VcsLogContentProvider(@NotNull VcsLogManager logManager) {
myLogManager = logManager;
}
@NotNull
@Override
public Boolean fun(Project project) {
if (!Registry.is("git.new.log")) {
return false;
}
return !myLogManager.findLogProviders().isEmpty();
}
@Override
public JComponent initContent() {
return myLogManager.initContent();
}
@Override
public void disposeContent() {
}
}
@@ -20,8 +20,6 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.ui.VcsLogUI;
import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,12 +32,10 @@ import java.util.List;
*/
public class VcsLogImpl implements VcsLog {
private final VcsLogDataHolder myDataHolder;
private final VcsLogUI myUi;
private final VcsLogManager myLogManager;
public VcsLogImpl(VcsLogManager vcsLogManager) {
myDataHolder = vcsLogManager.getDataHolder();
myUi = vcsLogManager.getLogUi();
myLogManager = vcsLogManager;
}
/**
@@ -47,14 +43,14 @@ public class VcsLogImpl implements VcsLog {
* TODO Temporary method until the old Git log is switched off and removed
*/
public boolean isReady() {
return myDataHolder != null && myUi != null;
return myLogManager.getDataHolder() != null && myLogManager.getLogUi() != null;
}
@Override
@NotNull
public List<Hash> getSelectedCommits() {
List<Hash> hashes = ContainerUtil.newArrayList();
JBTable table = myUi.getTable();
JBTable table = myLogManager.getLogUi().getTable();
for (int row : table.getSelectedRows()) {
Hash hash = ((AbstractVcsLogTableModel)table.getModel()).getHashAtRow(row);
if (hash != null) {
@@ -67,7 +63,7 @@ public class VcsLogImpl implements VcsLog {
@Override
@Nullable
public VcsFullCommitDetails getDetailsIfAvailable(@NotNull final Hash hash) {
return myDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash);
return myLogManager.getDataHolder().getCommitDetailsGetter().getCommitDataIfAvailable(hash);
}
@Nullable
@@ -1,17 +1,12 @@
package com.intellij.vcs.log.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentI;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowManager;
@@ -22,11 +17,9 @@ import com.intellij.ui.components.JBLoadingPanel;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManagerAdapter;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.ui.content.impl.ContentImpl;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.VcsLogObjectsFactory;
import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcs.log.VcsLogRefresher;
@@ -46,10 +39,11 @@ import java.util.Set;
/**
* @author Kirill Likhodedov
*/
public class VcsLogManager extends AbstractProjectComponent {
public class VcsLogManager {
public static final ExtensionPointName<VcsLogProvider> LOG_PROVIDER_EP = ExtensionPointName.create("com.intellij.logProvider");
@NotNull private final Project myProject;
@NotNull private final ProjectLevelVcsManager myVcsManager;
@NotNull private final VcsLogObjectsFactory myLogObjectsFactory;
@NotNull private final VcsLogSettings mySettings;
@@ -59,63 +53,34 @@ public class VcsLogManager extends AbstractProjectComponent {
private VcsLogDataHolder myLogDataHolder;
private VcsLogUI myUi;
protected VcsLogManager(@NotNull Project project, @NotNull ProjectLevelVcsManager vcsManagerInitializedFirst,
@NotNull VcsLogObjectsFactory logObjectsFactory, @NotNull VcsLogSettings settings,
@NotNull VcsLogUiProperties uiProperties) {
super(project);
myVcsManager = vcsManagerInitializedFirst;
public VcsLogManager(@NotNull Project project, @NotNull ProjectLevelVcsManager vcsManager,
@NotNull VcsLogObjectsFactory logObjectsFactory, @NotNull VcsLogSettings settings,
@NotNull VcsLogUiProperties uiProperties) {
myProject = project;
myVcsManager = vcsManager;
myLogObjectsFactory = logObjectsFactory;
mySettings = settings;
myUiProperties = uiProperties;
}
@Override
public void initComponent() {
super.initComponent();
@NotNull
public JComponent initContent() {
final Map<VirtualFile, VcsLogProvider> logProviders = findLogProviders();
final VcsLogContainer mainPanel = new VcsLogContainer(myProject);
if (!Registry.is("git.new.log")) {
return;
}
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
ChangesViewContentManager changesView = (ChangesViewContentManager)ChangesViewContentManager.getInstance(myProject);
changesView.executeWhenInitialized(new DumbAwareRunnable() {
@Override
public void run() {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
final Map<VirtualFile, VcsLogProvider> logProviders = findLogProviders();
if (logProviders.isEmpty()) {
return;
}
final VcsLogContainer mainPanel = new VcsLogContainer(myProject);
final Content content = new ContentImpl(mainPanel, "Log", true);
ChangesViewContentI changesView = ChangesViewContentManager.getInstance(myProject);
changesView.addContent(content);
content.setCloseable(false);
VcsLogDataHolder.init(myProject, myLogObjectsFactory, logProviders, mySettings, new Consumer<VcsLogDataHolder>() {
@Override
public void consume(VcsLogDataHolder vcsLogDataHolder) {
Disposer.register(myProject, vcsLogDataHolder);
VcsLogUI logUI = new VcsLogUI(vcsLogDataHolder, myProject, mySettings,
new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties);
myLogDataHolder = vcsLogDataHolder;
myUi = logUI;
mainPanel.init(logUI.getMainFrame().getMainComponent());
myLogRefresher = new PostponeableLogRefresher(myProject, vcsLogDataHolder, content);
refreshLogOnVcsEvents(logProviders);
}
});
}
});
}
});
VcsLogDataHolder.init(myProject, myLogObjectsFactory, logProviders, mySettings, new Consumer<VcsLogDataHolder>() {
@Override
public void consume(VcsLogDataHolder vcsLogDataHolder) {
VcsLogUI logUI = new VcsLogUI(vcsLogDataHolder, myProject, mySettings,
new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties);
myLogDataHolder = vcsLogDataHolder;
myUi = logUI;
mainPanel.init(logUI.getMainFrame().getMainComponent());
myLogRefresher = new PostponeableLogRefresher(myProject, vcsLogDataHolder);
refreshLogOnVcsEvents(logProviders);
}
});
return mainPanel;
}
private void refreshLogOnVcsEvents(@NotNull Map<VirtualFile, VcsLogProvider> logProviders) {
@@ -130,7 +95,7 @@ public class VcsLogManager extends AbstractProjectComponent {
}
@NotNull
private Map<VirtualFile, VcsLogProvider> findLogProviders() {
public Map<VirtualFile, VcsLogProvider> findLogProviders() {
Map<VirtualFile, VcsLogProvider> logProviders = ContainerUtil.newHashMap();
VcsLogProvider[] allLogProviders = Extensions.getExtensions(LOG_PROVIDER_EP, myProject);
for (AbstractVcs vcs : myVcsManager.getAllActiveVcss()) {
@@ -174,9 +139,9 @@ public class VcsLogManager extends AbstractProjectComponent {
private static class PostponeableLogRefresher implements VcsLogRefresher, Disposable {
private static final String TOOLWINDOW_ID = ChangesViewContentManager.TOOLWINDOW_ID;
private static final String TAB_NAME = "Log";
@NotNull private final VcsLogDataHolder myDataHolder;
@NotNull private final Content myContentPane;
@NotNull private final ToolWindowManagerImpl myToolWindowManager;
@NotNull private final ToolWindowImpl myToolWindow;
@NotNull private final MyRefreshPostponedEventsListener myPostponedEventsListener;
@@ -185,9 +150,8 @@ public class VcsLogManager extends AbstractProjectComponent {
@NotNull private final Set<VirtualFile> myRootsToRefresh = ContainerUtil.newHashSet();
@NotNull private final Object REFRESH_LOCK = new Object();
public PostponeableLogRefresher(@NotNull Project project, @NotNull VcsLogDataHolder dataHolder, @NotNull Content contentPane) {
public PostponeableLogRefresher(@NotNull Project project, @NotNull VcsLogDataHolder dataHolder) {
myDataHolder = dataHolder;
myContentPane = contentPane;
myToolWindowManager = (ToolWindowManagerImpl)ToolWindowManager.getInstance(project);
myToolWindow = (ToolWindowImpl)myToolWindowManager.getToolWindow(TOOLWINDOW_ID);
@@ -229,8 +193,11 @@ public class VcsLogManager extends AbstractProjectComponent {
}
private boolean isOurContentPaneShowing() {
return myToolWindowManager.isToolWindowRegistered(TOOLWINDOW_ID) &&
myToolWindow.isVisible() && myContentPane.equals(myToolWindow.getContentManager().getSelectedContent());
if (myToolWindowManager.isToolWindowRegistered(TOOLWINDOW_ID) && myToolWindow.isVisible()) {
Content content = myToolWindow.getContentManager().getSelectedContent();
return content != null && content.getTabName().equals(TAB_NAME);
}
return false;
}
private void refreshPostponedRoots() {