mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[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:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
-303
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user