[log] IDEA-115638, IDEA-124768 Rewrite "Show external log" action

Introduce external repositories to the RepositoryManager.

Let VcsLogManager refresh "simply" if "Show repository log" is called
without a toolwindow (from the welcome screen).
This commit is contained in:
Kirill Likhodedov
2014-10-15 16:54:01 +04:00
parent a0b32a9303
commit 2d79d2e908
9 changed files with 394 additions and 321 deletions
@@ -30,8 +30,11 @@ import java.util.List;
public interface RepositoryManager<T extends Repository> {
/**
* Returns the {@link Repository} which tracks the Git or Hg repository located in the given directory,
* or {@code null} if the given file is not a vcs root known to this {@link com.intellij.openapi.project.Project}.
* Returns the Repository instance which tracks the VCS repository located in the given root directory,
* or {@code null} if the given root is not a valid registered vcs root.
* <p/>
* The method checks both project roots and external roots previously registered
* via {@link #addExternalRepository(VirtualFile, Repository)}.
*/
@Nullable
T getRepositoryForRoot(@Nullable VirtualFile root);
@@ -54,6 +57,16 @@ public interface RepositoryManager<T extends Repository> {
@NotNull
List<T> getRepositories();
/**
* Registers a repository which doesn't belong to the project.
*/
void addExternalRepository(@NotNull VirtualFile root, @NotNull T repository);
/**
* Removes the repository not from the project, when it is not interesting anymore.
*/
void removeExternalRepository(@NotNull VirtualFile root);
boolean moreThanOneRoot();
/**
@@ -8,6 +8,7 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,7 +31,8 @@ public abstract class AbstractRepositoryManager<T extends Repository> extends Ab
@NotNull private final AbstractVcs myVcs;
@NotNull private final String myRepoDirName;
@NotNull protected final Map<VirtualFile, T> myRepositories = new HashMap<VirtualFile, T>();
@NotNull protected final Map<VirtualFile, T> myRepositories = ContainerUtil.newHashMap();
@NotNull protected final Map<VirtualFile, T> myExternalRepositories = ContainerUtil.newHashMap();
@NotNull protected final ReentrantReadWriteLock REPO_LOCK = new ReentrantReadWriteLock();
@NotNull private final CountDownLatch myInitializationWaiter = new CountDownLatch(1);
@@ -73,13 +75,36 @@ public abstract class AbstractRepositoryManager<T extends Repository> extends Ab
}
try {
REPO_LOCK.readLock().lock();
return myRepositories.get(root);
T repo = myRepositories.get(root);
return repo != null ? repo : myExternalRepositories.get(root);
}
finally {
REPO_LOCK.readLock().unlock();
}
}
@Override
public void addExternalRepository(@NotNull VirtualFile root, @NotNull T repository) {
REPO_LOCK.writeLock().lock();
try {
myExternalRepositories.put(root, repository);
}
finally {
REPO_LOCK.writeLock().unlock();
}
}
@Override
public void removeExternalRepository(@NotNull VirtualFile root) {
REPO_LOCK.writeLock().lock();
try {
myExternalRepositories.remove(root);
}
finally {
REPO_LOCK.writeLock().unlock();
}
}
@Override
@Nullable
public T getRepositoryForFile(@NotNull VirtualFile file) {
@@ -340,7 +340,7 @@ public class FrameWrapper implements Disposable, DataProvider {
myTitle = title;
}
public void addDisposable(Disposable disposable) {
public void addDisposable(@NotNull Disposable disposable) {
Disposer.register(this, disposable);
}
@@ -1,8 +1,10 @@
package com.intellij.openapi.diff.impl.dir;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.FrameWrapper;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,15 +41,22 @@ public abstract class FrameDialogWrapper {
return Mode.MODAL;
}
@Nullable
protected Disposable getDisposable() {
return null;
}
public void show() {
switch (getMode()) {
case FRAME:
new MyFrameWrapper(getProject(), getMode(), getPanel(), getPreferredFocusedComponent(), getTitle(), getDimensionServiceKey())
new MyFrameWrapper(getProject(), getMode(), getPanel(), getPreferredFocusedComponent(), getTitle(), getDimensionServiceKey(),
getDisposable())
.show();
return;
case MODAL:
case NON_MODAL:
new MyDialogWrapper(getProject(), getMode(), getPanel(), getPreferredFocusedComponent(), getTitle(), getDimensionServiceKey())
new MyDialogWrapper(getProject(), getMode(), getPanel(), getPreferredFocusedComponent(), getTitle(), getDimensionServiceKey(),
getDisposable())
.show();
return;
default:
@@ -65,7 +74,8 @@ public abstract class FrameDialogWrapper {
@NotNull JComponent component,
@Nullable JComponent preferredFocusedComponent,
@Nullable String title,
@Nullable String dimensionServiceKey) {
@Nullable String dimensionServiceKey,
@Nullable Disposable disposable) {
super(project, true);
myComponent = component;
myPreferredFocusedComponent = preferredFocusedComponent;
@@ -85,6 +95,10 @@ public abstract class FrameDialogWrapper {
throw new IllegalArgumentException(mode.toString());
}
if (disposable != null) {
Disposer.register(getDisposable(), disposable);
}
init();
}
@@ -119,7 +133,8 @@ public abstract class FrameDialogWrapper {
@NotNull JComponent component,
@Nullable JComponent preferredFocusedComponent,
@Nullable String title,
@Nullable String dimensionServiceKey) {
@Nullable String dimensionServiceKey,
@Nullable Disposable disposable) {
super(project, dimensionServiceKey);
assert mode == Mode.FRAME;
@@ -130,6 +145,9 @@ public abstract class FrameDialogWrapper {
setComponent(component);
setPreferredFocusedComponent(preferredFocusedComponent);
closeOnEsc();
if (disposable != null) {
addDisposable(disposable);
}
}
}
}
@@ -91,9 +91,6 @@ public class VcsLogContentProvider implements ChangesViewContentProvider, NotNul
@NotNull
@Override
public Boolean fun(Project project) {
if (!Registry.is("git.new.log")) {
return false;
}
return !myLogManager.findLogProviders(Arrays.asList(myVcsManager.getAllVcsRoots())).isEmpty();
}
@@ -47,7 +47,7 @@ public class VcsLogManager implements Disposable {
@NotNull private final VcsLogSettings mySettings;
@NotNull private final VcsLogUiProperties myUiProperties;
private PostponeableLogRefresher myLogRefresher;
private VcsLogRefresher myLogRefresher;
private volatile VcsLogUiImpl myUi;
public VcsLogManager(@NotNull Project project,
@@ -60,7 +60,7 @@ public class VcsLogManager implements Disposable {
}
@NotNull
public JComponent initContent(@NotNull Collection<VcsRoot> roots, @NotNull String contentTabName) {
public JComponent initContent(@NotNull Collection<VcsRoot> roots, @Nullable String contentTabName) {
final Map<VirtualFile, VcsLogProvider> logProviders = findLogProviders(roots);
Consumer<VisiblePack> visiblePackConsumer = new Consumer<VisiblePack>() {
@@ -76,10 +76,20 @@ public class VcsLogManager implements Disposable {
});
}
};
VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, myUiProperties, visiblePackConsumer);
final VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, myUiProperties, visiblePackConsumer);
myUi = new VcsLogUiImpl(logDataHolder, myProject, mySettings,
new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties, logDataHolder.getFilterer());
myLogRefresher = new PostponeableLogRefresher(myProject, logDataHolder, contentTabName);
if (contentTabName != null) {
myLogRefresher = new PostponeableLogRefresher(myProject, logDataHolder, contentTabName);
}
else {
myLogRefresher = new VcsLogRefresher() {
@Override
public void refresh(@NotNull VirtualFile root) {
logDataHolder.refresh(Collections.singletonList(root));
}
};
}
refreshLogOnVcsEvents(logProviders);
logDataHolder.initialize();
@@ -143,7 +153,7 @@ public class VcsLogManager implements Disposable {
private static class PostponeableLogRefresher implements VcsLogRefresher, Disposable {
private static final String TOOLWINDOW_ID = ChangesViewContentManager.TOOLWINDOW_ID;
private static final String TOOLWINDOW_ID = ChangesViewContentManager.TOOLWINDOW_ID;
@NotNull private final VcsLogDataHolder myDataHolder;
@NotNull private final ToolWindowManagerImpl myToolWindowManager;
+1 -1
View File
@@ -28,7 +28,7 @@
<add-to-group group-id="Vcs.Import"/>
</action>
<action id="Git.Log" class="git4idea.history.wholeTree.SelectRepositoryAndShowLogAction">
<action id="Git.Log" class="git4idea.log.GitShowExternalLogAction" text="Show Git Repository Log...">
<add-to-group group-id="Vcs.Browse"/>
</action>
@@ -1,303 +0,0 @@
/*
* Copyright 2000-2012 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 git4idea.history.wholeTree;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
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.project.ProjectManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.ui.AdjustComponentWhenShown;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.config.GitVersion;
import git4idea.history.browser.GitProjectLogManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.Arrays;
import java.util.List;
/**
* @author irengrig
*/
public class SelectRepositoryAndShowLogAction extends AnAction {
public static final String ourTitle = "Show Git Repository Log";
public static final int MAX_REPOS = 10;
public SelectRepositoryAndShowLogAction() {
super(ourTitle + "...");
}
@Override
public void actionPerformed(AnActionEvent e) {
Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
project = project == null ? ProjectManager.getInstance().getDefaultProject() : project;
final Project finalProject = project;
final FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, true, false, true);
final VirtualFile[] virtualFiles = FileChooser.chooseFiles(descriptor, project, null);
if (virtualFiles.length == 0) return;
if (virtualFiles.length > MAX_REPOS) {
VcsBalloonProblemNotifier.showOverVersionControlView(project, "Too many roots (more than " + MAX_REPOS +
") selected.", MessageType.ERROR);
return;
}
final List<VirtualFile> wrongRoots = new SmartList<VirtualFile>();
final List<VirtualFile> correctRoots = new SmartList<VirtualFile>();
for (VirtualFile vf : virtualFiles) {
if (! GitUtil.isGitRoot(new File(vf.getPath()))) {
wrongRoots.add(vf);
} else {
correctRoots.add(vf);
}
}
if (! wrongRoots.isEmpty()) {
VcsBalloonProblemNotifier.showOverVersionControlView(project, "These files are not Git repository roots:\n" +
StringUtil.join(wrongRoots, new Function<VirtualFile, String>() {
@Override
public String fun(VirtualFile virtualFile) {
return virtualFile.getPath();
}
}, "\n"), MessageType.ERROR);
}
if (wrongRoots.size() != virtualFiles.length) {
if (project == null || project.isDefault()) {
ProgressManager.getInstance().run(new MyPrepareToShowForDefaultProject(null, correctRoots));
return;
}
final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ChangesViewContentManager.TOOLWINDOW_ID);
final Runnable showContent = new Runnable() {
@Override
public void run() {
ContentManager cm = window.getContentManager();
if (checkForProjectScope(cm, finalProject, correctRoots)) return;
int cnt = 0;
Content[] contents = cm.getContents();
for (Content content : contents) {
final JComponent component = content.getComponent();
if (component instanceof MyContentComponent) {
cnt = Math.max(cnt, ((MyContentComponent)component).getCount());
List<VirtualFile> roots = ((MyContentComponent)component).getRoots();
if (Comparing.equal(roots, correctRoots)) {
cm.setSelectedContent(content);
alreadyOpened(finalProject);
return;
}
}
}
LogFactoryService logFactoryService = LogFactoryService.getInstance(finalProject);
final GitLog gitLog = logFactoryService.createComponent(false);
gitLog.rootsChanged(correctRoots);
final ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
++cnt;
MyContentComponent contentComponent = new MyContentComponent(new BorderLayout(), cnt);
contentComponent.setRoots(correctRoots);
contentComponent.add(gitLog.getVisualComponent(), BorderLayout.CENTER);
final Content content = contentFactory.createContent(contentComponent, "Log (" + cnt + ")", false);
content.setDescription("Log for " + StringUtil.join(correctRoots, new Function<VirtualFile, String>() {
@Override
public String fun(VirtualFile file) {
return file.getPath();
}
}, "\n"));
content.setCloseable(true);
Disposer.register(content, gitLog);
cm.addContent(content);
cm.setSelectedContent(content);
}
};
ProgressManager.getInstance().run(new MyCheckVersion(project) {
@Override
public void onSuccess() {
if (myVersion == null) return;
if (! window.isVisible()) {
window.activate(showContent, true);
} else {
showContent.run();
}
}
});
}
}
private static void alreadyOpened(final Project project) {
VcsBalloonProblemNotifier.showOverChangesView(project, "Already opened", MessageType.INFO);
}
private boolean checkForProjectScope(ContentManager cm, Project project, List<VirtualFile> correctRoots) {
VirtualFile[] rootsUnderVcs = ProjectLevelVcsManager.getInstance(project).getRootsUnderVcs(GitVcs.getInstance(project));
if (Comparing.equal(correctRoots, Arrays.asList(rootsUnderVcs))) {
Content[] contents = cm.getContents();
for (Content content : contents) {
if (GitProjectLogManager.CONTENT_KEY.equals(content.getDisplayName())) {
cm.setSelectedContent(content);
alreadyOpened(project);
return true;
}
}
}
return false;
}
private static class MyContentComponent extends JPanel {
private List<VirtualFile> myRoots;
private int myCount;
private MyContentComponent(LayoutManager layout, boolean isDoubleBuffered, int count) {
super(layout, isDoubleBuffered);
myCount = count;
}
private MyContentComponent(LayoutManager layout, int count) {
super(layout);
myCount = count;
}
private MyContentComponent(boolean isDoubleBuffered, int count) {
super(isDoubleBuffered);
myCount = count;
}
public int getCount() {
return myCount;
}
private MyContentComponent(int count) {
myCount = count;
}
public void setRoots(List<VirtualFile> roots) {
myRoots = roots;
}
public List<VirtualFile> getRoots() {
return myRoots;
}
}
private static class MyPrepareToShowForDefaultProject extends Task.Backgroundable {
private Project myProject;
private final List<VirtualFile> myCorrectRoots;
private MyCheckVersion myVersion;
private MyPrepareToShowForDefaultProject(@Nullable Project project, List<VirtualFile> correctRoots) {
super(project, ourTitle, true, BackgroundFromStartOption.getInstance());
myCorrectRoots = correctRoots;
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
myProject = ProjectManager.getInstance().getDefaultProject();
myVersion = new MyCheckVersion(myProject);
myVersion.run(indicator);
}
@Override
public void onSuccess() {
if (myVersion.myVersion.isNull()) return;
if (myProject.isDisposed()) return;
new MyDialog(myProject, myCorrectRoots).show();
}
}
private static class MyCheckVersion extends Task.Backgroundable {
protected GitVersion myVersion;
private MyCheckVersion(@Nullable Project project) {
super(project, ourTitle, true, BackgroundFromStartOption.getInstance());
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
GitVcs vcs = GitVcs.getInstance(myProject);
if (vcs == null) { return; }
myVersion = vcs.getVersion();
if (myVersion.isNull()) {
vcs.checkVersion();
myVersion = vcs.getVersion();
}
}
}
private static class MyDialog extends DialogWrapper {
private GitLog myGitLog;
private final Project myProject;
private final List<VirtualFile> myVirtualFiles;
private MyDialog(Project project, final List<VirtualFile> virtualFiles) {
super(project, true);
myProject = project;
myVirtualFiles = virtualFiles;
myGitLog = new LogFactoryService(myProject, ServiceManager.getService(GitCommitsSequentially.class)).createComponent(false);
myGitLog.rootsChanged(myVirtualFiles);
Disposer.register(getDisposable(), myGitLog);
new AdjustComponentWhenShown() {
@Override
protected boolean init() {
myGitLog.setModalityState(ModalityState.current());
return true;
}
}.install(myGitLog.getVisualComponent());
setTitle("Git Log");
init();
}
@Override
protected JComponent createCenterPanel() {
return myGitLog.getVisualComponent();
}
@NotNull
@Override
protected Action[] createActions() {
return new Action[0];
}
}
}
@@ -0,0 +1,313 @@
/*
* Copyright 2000-2012 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 git4idea.log;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.dir.FrameDialogWrapper;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
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.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsRoot;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.intellij.util.Function;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.VcsLogSettings;
import com.intellij.vcs.log.data.VcsLogUiProperties;
import com.intellij.vcs.log.impl.VcsLogContentProvider;
import com.intellij.vcs.log.impl.VcsLogManager;
import git4idea.GitPlatformFacade;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.config.GitVersion;
import git4idea.repo.GitRepositoryImpl;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class GitShowExternalLogAction extends AnAction {
private static final Logger LOG = Logger.getInstance(GitShowExternalLogAction.class);
@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabledAndVisible(e.getProject() != null && GitVcs.getInstance(e.getProject()) != null);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
final Project project = e.getRequiredData(CommonDataKeys.PROJECT);
final GitVcs vcs = ObjectUtils.assertNotNull(GitVcs.getInstance(project));
final List<VirtualFile> roots = getGitRootsFromUser(project);
if (roots.isEmpty()) {
return;
}
if (project.isDefault() || !ProjectLevelVcsManager.getInstance(project).hasActiveVcss()) {
ProgressManager.getInstance().run(new ShowLogInDialogTask(project, roots, vcs));
return;
}
final ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ChangesViewContentManager.TOOLWINDOW_ID);
final Runnable showContent = new Runnable() {
@Override
public void run() {
ContentManager cm = window.getContentManager();
if (checkIfProjectLogMatches(project, vcs, cm, roots) || checkIfAlreadyOpened(cm, roots)) {
return;
}
String tabName = calcTabName(cm, roots);
MyContentComponent component = createManagerAndContent(project, vcs, roots, tabName);
Content content = ContentFactory.SERVICE.getInstance().createContent(component, tabName, false);
content.setDisposer(component.myDisposable);
content.setDescription("Log for " + StringUtil.join(roots, new Function<VirtualFile, String>() {
@Override
public String fun(VirtualFile file) {
return file.getPath();
}
}, "\n"));
content.setCloseable(true);
cm.addContent(content);
cm.setSelectedContent(content);
}
};
if (!window.isVisible()) {
window.activate(showContent, true);
}
else {
showContent.run();
}
}
@NotNull
private static MyContentComponent createManagerAndContent(@NotNull Project project,
@NotNull final GitVcs vcs,
@NotNull final List<VirtualFile> roots,
@Nullable String tabName) {
final GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class);
GitPlatformFacade facade = ServiceManager.getService(GitPlatformFacade.class);
for (VirtualFile root : roots) {
repositoryManager.addExternalRepository(root, GitRepositoryImpl.getFullInstance(root, project, facade, project));
}
VcsLogManager manager = new VcsLogManager(project, ServiceManager.getService(project, VcsLogSettings.class),
ServiceManager.getService(project, VcsLogUiProperties.class));
Collection<VcsRoot> vcsRoots = ContainerUtil.map(roots, new Function<VirtualFile, VcsRoot>() {
@Override
public VcsRoot fun(VirtualFile root) {
return new VcsRoot(vcs, root);
}
});
return new MyContentComponent(manager.initContent(vcsRoots, tabName), roots, new Disposable() {
@Override
public void dispose() {
for (VirtualFile root : roots) {
repositoryManager.removeExternalRepository(root);
}
}
});
}
@NotNull
private static String calcTabName(@NotNull ContentManager cm, @NotNull List<VirtualFile> roots) {
String name = VcsLogContentProvider.TAB_NAME + " (" + roots.get(0).getName();
if (roots.size() > 1) {
name += "+";
}
name += ")";
String candidate = name;
int cnt = 1;
while (hasContentsWithName(cm, candidate)) {
candidate = name + "-" + cnt;
cnt++;
}
return candidate;
}
private static boolean hasContentsWithName(@NotNull ContentManager cm, @NotNull final String candidate) {
return ContainerUtil.exists(cm.getContents(), new Condition<Content>() {
@Override
public boolean value(Content content) {
return content.getDisplayName().equals(candidate);
}
});
}
@NotNull
private static List<VirtualFile> getGitRootsFromUser(@NotNull Project project) {
FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, true, false, true);
VirtualFile[] virtualFiles = FileChooser.chooseFiles(descriptor, project, null);
if (virtualFiles.length == 0) {
return Collections.emptyList();
}
List<VirtualFile> correctRoots = ContainerUtil.newArrayList();
for (VirtualFile vf : virtualFiles) {
if (GitUtil.isGitRoot(new File(vf.getPath()))) {
correctRoots.add(vf);
}
}
return correctRoots;
}
private static boolean checkIfProjectLogMatches(@NotNull Project project,
@NotNull GitVcs vcs,
@NotNull ContentManager cm,
@NotNull List<VirtualFile> requestedRoots) {
VirtualFile[] projectRoots = ProjectLevelVcsManager.getInstance(project).getRootsUnderVcs(vcs);
if (Comparing.haveEqualElements(requestedRoots, Arrays.asList(projectRoots))) {
Content[] contents = cm.getContents();
for (Content content : contents) {
if (VcsLogContentProvider.TAB_NAME.equals(content.getDisplayName())) {
cm.setSelectedContent(content);
return true;
}
}
}
return false;
}
private static boolean checkIfAlreadyOpened(@NotNull ContentManager cm, @NotNull Collection<VirtualFile> roots) {
for (Content content : cm.getContents()) {
final JComponent component = content.getComponent();
if (component instanceof MyContentComponent) {
if (Comparing.haveEqualElements(roots, ((MyContentComponent)component).myRoots)) {
cm.setSelectedContent(content);
return true;
}
}
}
return false;
}
private static class MyContentComponent extends JPanel {
@NotNull private final Collection<VirtualFile> myRoots;
@NotNull private final Disposable myDisposable;
MyContentComponent(@NotNull JComponent actualComponent, @NotNull Collection<VirtualFile> roots, @NotNull Disposable disposable) {
super(new BorderLayout());
myDisposable = disposable;
myRoots = roots;
add(actualComponent);
}
}
private static class ShowLogInDialogTask extends Task.Backgroundable {
@NotNull private final Project myProject;
@NotNull private final List<VirtualFile> myRoots;
@NotNull private final GitVcs myVcs;
private GitVersion myVersion;
private ShowLogInDialogTask(@NotNull Project project, @NotNull List<VirtualFile> roots, @NotNull GitVcs vcs) {
super(project, "Loading Git Log...", true, BackgroundFromStartOption.getInstance());
myProject = project;
myRoots = roots;
myVcs = vcs;
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
myVersion = myVcs.getVersion();
if (myVersion.isNull()) {
myVcs.checkVersion();
myVersion = myVcs.getVersion();
}
}
@Override
public void onSuccess() {
if (!myVersion.isNull() && !myProject.isDisposed()) {
new MyDialog(myProject, myVcs, myRoots).show();
}
}
}
private static class MyDialog extends FrameDialogWrapper {
@NotNull private final MyContentComponent myContent;
@NotNull private final Project myProject;
private MyDialog(@NotNull Project project, @NotNull GitVcs vcs, @NotNull final List<VirtualFile> roots) {
myProject = project;
myContent = createManagerAndContent(project, vcs, roots, null);
}
@NotNull
@Override
protected Mode getMode() {
return Mode.FRAME;
}
@NotNull
@Override
public Project getProject() {
return myProject;
}
@Nullable
@Override
protected String getTitle() {
return "Git Log";
}
@NotNull
@Override
protected JComponent getPanel() {
return myContent;
}
@Nullable
@Override
protected JComponent getPreferredFocusedComponent() {
return myContent;
}
@Nullable
@Override
protected Disposable getDisposable() {
return myContent.myDisposable;
}
}
}