Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2013-11-10 22:52:14 +01:00
24 changed files with 364 additions and 126 deletions
@@ -48,7 +48,7 @@ public class SLRUMap<K,V> {
myProtectedQueueSize = protectedQueueSize * FACTOR;
myProbationalQueueSize = probationalQueueSize * FACTOR;
myProtectedQueue = new LinkedHashMap<K,V>(10, 0.6f, hashingStrategy) {
myProtectedQueue = new LinkedHashMap<K,V>(10, 0.6f, hashingStrategy, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest, K key, V value) {
if (size() > myProtectedQueueSize) {
@@ -58,15 +58,9 @@ public class SLRUMap<K,V> {
return false;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
};
myProbationalQueue = new LinkedHashMap<K,V>(10, 0.6f, hashingStrategy) {
myProbationalQueue = new LinkedHashMap<K,V>(10, 0.6f, hashingStrategy, true) {
@Override
protected boolean removeEldestEntry(final Map.Entry<K, V> eldest, K key, V value) {
if (size() > myProbationalQueueSize) {
@@ -75,12 +69,6 @@ public class SLRUMap<K,V> {
}
return false;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
};
}
@@ -29,7 +29,7 @@ public class LinkedHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>
private int size;
private final float loadFactor;
private final EqualityPolicy<K> hashingStrategy;
private final boolean accessOrder;
public LinkedHashMap() {
this(0);
@@ -38,19 +38,30 @@ public class LinkedHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>
public LinkedHashMap(int capacity) {
this(capacity, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LinkedHashMap(int capacity, boolean accessOrder) {
this(capacity, HashUtil.DEFAULT_LOAD_FACTOR, accessOrder);
}
public LinkedHashMap(int capacity, float loadFactor) {
this(capacity, loadFactor, (EqualityPolicy)EqualityPolicy.CANONICAL);
}
public LinkedHashMap(int capacity, float loadFactor, boolean accessOrder) {
this(capacity, loadFactor, (EqualityPolicy)EqualityPolicy.CANONICAL, accessOrder);
}
public LinkedHashMap(EqualityPolicy hashingStrategy) {
this(0, HashUtil.DEFAULT_LOAD_FACTOR, hashingStrategy);
}
public LinkedHashMap(int capacity, float loadFactor, EqualityPolicy<K> hashingStrategy) {
this(capacity, loadFactor, hashingStrategy, false);
}
public LinkedHashMap(int capacity, float loadFactor, EqualityPolicy<K> hashingStrategy, boolean accessOrder) {
this.loadFactor = loadFactor;
this.hashingStrategy = hashingStrategy;
clear(capacity);
this.accessOrder = accessOrder;
}
@Override
@@ -200,12 +211,8 @@ public class LinkedHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>
size = 0;
}
protected boolean shouldMoveEntryToTopWhenReading() {
return false;
}
private void moveToTop(final Entry<K, V> e) {
if (!shouldMoveEntryToTopWhenReading()) {
if (!accessOrder) {
return;
}
@@ -45,7 +45,7 @@ public class PagePool {
private PoolPageKey lastFinalizedKey = null;
public PagePool(final int protectedPagesLimit, final int probationalPagesLimit) {
myProbationalQueue = new LinkedHashMap<PoolPageKey,Page>(probationalPagesLimit * 2, 0.6f) {
myProbationalQueue = new LinkedHashMap<PoolPageKey,Page>(probationalPagesLimit * 2, 0.6f, true) {
@Override
protected boolean removeEldestEntry(final Map.Entry<PoolPageKey, Page> eldest) {
if (size() > probationalPagesLimit) {
@@ -54,14 +54,9 @@ public class PagePool {
}
return false;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
};
myProtectedQueue = new LinkedHashMap<PoolPageKey, Page>(protectedPagesLimit, 0.6f) {
myProtectedQueue = new LinkedHashMap<PoolPageKey, Page>(protectedPagesLimit, 0.6f, true) {
@Override
protected boolean removeEldestEntry(final Map.Entry<PoolPageKey, Page> eldest) {
if (size() > protectedPagesLimit) {
@@ -70,10 +65,6 @@ public class PagePool {
}
return false;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
};
}
@@ -484,17 +484,12 @@ public class PagedFileStorage implements Forceable {
myDefaultStorageLockContext = new StorageLockContext(this, checkThreadAccess);
mySizeLimit = UPPER_LIMIT;
mySegments = new LinkedHashMap<Integer, ByteBufferWrapper>(10, 0.75f) {
mySegments = new LinkedHashMap<Integer, ByteBufferWrapper>(10, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, ByteBufferWrapper> eldest) {
return mySize > mySizeLimit;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
@Nullable
@Override
public ByteBufferWrapper remove(Object key) {
@@ -135,17 +135,11 @@ public class LinkedHashMapTest {
@Test
public void lru2() {
final LinkedHashMap<Integer, String> tested = new LinkedHashMap<Integer, String>() {
final LinkedHashMap<Integer, String> tested = new LinkedHashMap<Integer, String>(0, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
return size() > 1000;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
};
for (int i = 0; i < 1000; ++i) {
tested.put(i, Integer.toString(i));
@@ -161,17 +155,11 @@ public class LinkedHashMapTest {
@Test
public void lru3() {
final LinkedHashMap<Integer, String> tested = new LinkedHashMap<Integer, String>() {
final LinkedHashMap<Integer, String> tested = new LinkedHashMap<Integer, String>(0, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
return size() > 1000;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
};
for (int i = 0; i < 1000; ++i) {
tested.put(i, Integer.toString(i));
@@ -18,6 +18,7 @@ package com.intellij.vcs.log;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.Collection;
import java.util.List;
@@ -54,4 +55,27 @@ public interface VcsLog {
@Nullable
Collection<String> getContainingBranches(@NotNull Hash commitHash);
/**
* Returns all {@link VcsRef commit references} available in the log.
*/
@NotNull
Collection<VcsRef> getAllReferences();
/**
* Selects the commit node defined by the given reference (commit hash, branch or tag).
*/
void jumpToReference(String reference);
/**
* Returns the VCS log toolbar component.
*/
@NotNull
Component getToolbar();
/**
* Returns {@link VcsLogProvider VcsLogProviders} which are active in this log, i.e. which VCS roots are shown in the log.
*/
@NotNull
Collection<VcsLogProvider> getLogProviders();
}
@@ -18,11 +18,14 @@
<action class="com.intellij.vcs.log.ui.VcsLogCopyHashAction" id="Vcs.Log.CopyHash"
icon="AllIcons.Actions.Copy" text="Copy Hash" description="Copy hash value of the selected commit to clipboard" />
<action class="com.intellij.vcs.log.ui.VcsLogCreatePatchAction" id="Vcs.Log.CreatePatch" />
<action class="com.intellij.vcs.log.ui.GoToRefAction" id="Vcs.Log.GoToRef" icon="AllIcons.Actions.Menu_find" use-shortcut-of="Find"
text="Go To Reference" description="Specify hash or name of a branch or a tag to navigate to the commit it points"/>
<action class="com.intellij.vcs.log.ui.VcsLogQuickSettingsActions" id="Vcs.Log.QuickSettings"
icon="AllIcons.General.Gear" text="Quick Settings" description="Quick Settings" />
<group id="Vcs.Log.Toolbar">
<reference id="Vcs.Log.CopyHash"/>
<reference id="Vcs.Log.GoToRef" />
<reference id="Vcs.Log.QuickSettings" />
</group>
<group id="Vcs.Log.ContextMenu">
@@ -135,6 +135,18 @@ public class DataPack {
return null;
}
@Nullable
public Node getNodeByPartOfHash(@NotNull String hash) {
Graph graph = getGraphModel().getGraph();
for (int i = 0; i < graph.getNodeRows().size(); i++) {
Node node = graph.getCommitNodeInRow(i);
if (node != null && node.getCommitHash().asString().startsWith(hash.toLowerCase())) {
return node;
}
}
return null;
}
@Nullable
public Node getCommonParent(Node a, Node b) {
List<Node> commitDiff = getCommitsDownToCommon(a, b);
@@ -58,4 +58,10 @@ public class RefsModel {
public Collection<VcsRef> getBranches() {
return myBranches;
}
@NotNull
public Collection<VcsRef> getAllRefs() {
return new ArrayList<VcsRef>(myRefsToHashes.values());
}
}
@@ -305,6 +305,10 @@ public class VcsLogDataHolder implements Disposable {
}, "Building full log...");
}
public boolean isFullLogShowing() {
return myFullLogShowing;
}
/**
* Queries the VCS for the number of recent unordered commits, orders them and connects to the existing log structure.
* This is done after refresh, when the whole log skeleton has been loaded.
@@ -487,6 +491,11 @@ public class VcsLogDataHolder implements Disposable {
return myLogProviders.keySet();
}
@NotNull
public Collection<VcsLogProvider> getLogProviders() {
return myLogProviders.values();
}
private static class RecentCommitsInfo {
List<TimedVcsCommit> firstBlockCommits;
Collection<VcsRef> newRefs;
@@ -15,17 +15,17 @@
*/
package com.intellij.vcs.log.impl;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.table.JBTable;
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.*;
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;
import java.awt.*;
import java.util.Collection;
import java.util.List;
@@ -84,4 +84,39 @@ public class VcsLogImpl implements VcsLog {
return null;
}
@NotNull
@Override
public Collection<VcsRef> getAllReferences() {
return myDataHolder.getDataPack().getRefsModel().getAllRefs();
}
@Override
public void jumpToReference(final String reference) {
Collection<VcsRef> references = getAllReferences();
VcsRef ref = ContainerUtil.find(references, new Condition<VcsRef>() {
@Override
public boolean value(VcsRef ref) {
return ref.getName().startsWith(reference);
}
});
if (ref != null) {
myUi.jumpToCommit(ref.getCommitHash());
}
else {
myUi.jumpToCommitByPartOfHash(reference);
}
}
@NotNull
@Override
public Component getToolbar() {
return myUi.getToolbar();
}
@NotNull
@Override
public Collection<VcsLogProvider> getLogProviders() {
return myDataHolder.getLogProviders();
}
}
@@ -1,6 +1,9 @@
package com.intellij.vcs.log.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.DataSink;
import com.intellij.openapi.actionSystem.TypeSafeDataProvider;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
@@ -124,7 +127,7 @@ public class VcsLogManager implements Disposable {
public void dispose() {
}
private static class VcsLogContainer extends JPanel {
private class VcsLogContainer extends JPanel implements TypeSafeDataProvider {
private final JBLoadingPanel myLoadingPanel;
@@ -139,6 +142,14 @@ public class VcsLogManager implements Disposable {
myLoadingPanel.add(mainComponent);
myLoadingPanel.stopLoading();
}
@Override
public void calcData(DataKey key, DataSink sink) {
if (myUi != null) {
myUi.getMainFrame().calcData(key, sink);
}
}
}
private static class PostponeableLogRefresher implements VcsLogRefresher, Disposable {
@@ -0,0 +1,67 @@
/*
* 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.ui;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupListener;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogDataKeys;
import com.intellij.vcs.log.VcsRef;
import java.util.Collection;
public class GoToRefAction extends DumbAwareAction {
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
final VcsLog log = e.getData(VcsLogDataKeys.VSC_LOG);
if (project == null || log == null) {
return;
}
Collection<String> refs = ContainerUtil.map(log.getAllReferences(), new Function<VcsRef, String>() {
@Override
public String fun(VcsRef ref) {
return ref.getName();
}
});
final PopupWithTextFieldWithAutoCompletion textField = new PopupWithTextFieldWithAutoCompletion(project, refs);
JBPopup popup = textField.createPopup();
popup.addListener(new JBPopupListener.Adapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
if (event.isOk()) {
log.jumpToReference(textField.getText());
}
}
});
popup.showUnderneathOf(log.getToolbar());
}
@Override
public void update(AnActionEvent e) {
VcsLog log = e.getData(VcsLogDataKeys.VSC_LOG);
getTemplatePresentation().setEnabledAndVisible(e.getProject() != null && log != null);
}
}
@@ -0,0 +1,78 @@
/*
* 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.ui;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.spellchecker.ui.SpellCheckingEditorCustomization;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.ui.components.JBTextField;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.Collection;
public class PopupWithTextFieldWithAutoCompletion extends TextFieldWithAutoCompletion<String> {
@Nullable private JBPopup myPopup;
public PopupWithTextFieldWithAutoCompletion(@NotNull Project project, @NotNull Collection<String> variants) {
super(project, new StringsCompletionProvider(variants, null), false, null);
// this hack is needed, because the preferred size is requested before createEditor(),
// and EditorTextField#getPreferredSize() hardcodes unacceptable (100, 20)
setPreferredSize(new JBTextField(20).getPreferredSize());
}
public JBPopup createPopup() {
myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(this, this)
.setCancelOnClickOutside(true)
.setCancelOnWindowDeactivation(true)
.setCancelKeyEnabled(true)
.setRequestFocus(true)
.createPopup();
return myPopup;
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (myPopup != null) {
myPopup.closeOk(e);
}
return true;
}
else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (myPopup != null) {
myPopup.cancel(e);
}
return true;
}
return false;
}
@Override
protected EditorEx createEditor() {
// spell check is not needed
EditorEx editor = super.createEditor();
SpellCheckingEditorCustomization.getInstance(false).customize(editor);
return editor;
}
}
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.table.TableModel;
import java.awt.*;
import java.util.Collection;
/**
@@ -205,6 +206,21 @@ public class VcsLogUI {
}
}
public void jumpToCommitByPartOfHash(final String hash) {
Node node = myLogDataHolder.getDataPack().getNodeByPartOfHash(hash);
if (node != null) {
jumpToRow(node.getRowIndex());
}
else if (!myLogDataHolder.isFullLogShowing()) {
myLogDataHolder.showFullLog(new Runnable() {
@Override
public void run() {
jumpToCommitByPartOfHash(hash);
}
});
}
}
@NotNull
public VcsLogColorManager getColorManager() {
return myColorManager;
@@ -255,4 +271,7 @@ public class VcsLogUI {
myMainFrame.setBranchesPanelVisible(visible);
}
public Component getToolbar() {
return myMainFrame.getToolbar();
}
}
@@ -18,16 +18,10 @@ package com.intellij.vcs.log.ui.filter;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.spellchecker.ui.SpellCheckingEditorCustomization;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.VcsLogFilter;
@@ -35,10 +29,9 @@ import com.intellij.vcs.log.VcsUser;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VcsLogUiProperties;
import com.intellij.vcs.log.data.VcsLogUserFilter;
import com.intellij.vcs.log.ui.PopupWithTextFieldWithAutoCompletion;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.List;
@@ -104,15 +97,8 @@ class UserFilterPopupComponent extends FilterPopupComponent {
}
});
final UserTextField textField = new UserTextField(e.getProject(), users);
JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(textField, textField)
.setCancelOnClickOutside(true)
.setCancelOnWindowDeactivation(true)
.setCancelKeyEnabled(true)
.setRequestFocus(true)
.createPopup();
textField.myPopup = popup;
final PopupWithTextFieldWithAutoCompletion textField = new PopupWithTextFieldWithAutoCompletion(e.getProject(), users);
JBPopup popup = textField.createPopup();
popup.addListener(new JBPopupAdapter() {
@Override
@@ -127,39 +113,5 @@ class UserFilterPopupComponent extends FilterPopupComponent {
popup.showUnderneathOf(UserFilterPopupComponent.this);
}
private class UserTextField extends TextFieldWithAutoCompletion<String> {
private JBPopup myPopup;
public UserTextField(Project project, Collection<String> users) {
super(project, new StringsCompletionProvider(users, null), false, null);
// this hack is needed, because the preferred size is requested before createEditor(),
// and EditorTextField#getPreferredSize() hardcodes unacceptable (100, 20)
setPreferredSize(new JBTextField(20).getPreferredSize());
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
myPopup.closeOk(e);
return true;
}
else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
myPopup.cancel(e);
return true;
}
return false;
}
@Override
protected EditorEx createEditor() {
// spell check is not needed
EditorEx editor = super.createEditor();
SpellCheckingEditorCustomization.getInstance(false).customize(editor);
return editor;
}
}
}
}
@@ -49,6 +49,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider {
@NotNull private final BranchesPanel myBranchesPanel;
@NotNull private final DetailsPanel myDetailsPanel;
@NotNull private final Splitter myDetailsSplitter;
private final JComponent myToolbar;
public MainFrame(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, @NotNull Project project,
@NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLog log) {
@@ -78,14 +79,14 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider {
updateWhenDetailsAreLoaded(selectionChangeListener);
// layout
JComponent toolbar = createActionsToolbar();
myToolbar = createActionsToolbar();
myDetailsSplitter = new Splitter(true, 0.7f);
myDetailsSplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myGraphTable));
setupDetailsSplitter(myUiProperties.isShowDetails());
JComponent toolbars = new JPanel(new BorderLayout());
toolbars.add(toolbar, BorderLayout.NORTH);
toolbars.add(myToolbar, BorderLayout.NORTH);
toolbars.add(myBranchesPanel, BorderLayout.CENTER);
JComponent toolbarsAndTable = new JPanel(new BorderLayout());
toolbarsAndTable.add(toolbars, BorderLayout.NORTH);
@@ -234,6 +235,10 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider {
}
}
public Component getToolbar() {
return myToolbar;
}
private class CommitSelectionListener implements ListSelectionListener {
private final ChangesBrowser myChangesBrowser;
@@ -96,6 +96,9 @@
<psi.referenceContributor implementation="org.jetbrains.idea.devkit.references.IconsReferencesContributor"/>
<referencesSearch implementation="org.jetbrains.idea.devkit.references.IconsReferencesContributor"/>
<unusedDeclarationFixProvider implementation="org.jetbrains.idea.devkit.inspections.quickfix.RegisterExtensionFixProvider"/>
<stacktrace.fold substring="at com.intellij.testFramework."/>
</extensions>
<module-components>
@@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -37,7 +38,10 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.VcsLog;
import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.branch.GitBranchUtil;
@@ -951,4 +955,16 @@ public class GitUtil {
repositoryManager.getRepositories()));
}
/**
* Checks if there are Git roots in the VCS log.
*/
public static boolean logHasGitRoot(@NotNull VcsLog log) {
return ContainerUtil.find(log.getLogProviders(), new Condition<VcsLogProvider>() {
@Override
public boolean value(VcsLogProvider logProvider) {
return logProvider.getSupportedVcs().equals(GitVcs.getKey());
}
}) != null;
}
}
@@ -83,7 +83,7 @@ public abstract class GitLogSingleCommitAction extends DumbAwareAction {
}
boolean isValid() {
return project != null && log != null;
return project != null && log != null && GitUtil.logHasGitRoot(log);
}
}
@@ -29,6 +29,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
import git4idea.GitLocalBranch;
import git4idea.GitPlatformFacade;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.commands.Git;
import git4idea.config.GitVcsSettings;
@@ -131,7 +132,13 @@ public class GitCherryPickAction extends DumbAwareAction {
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabled(enabled(e));
final VcsLog log = getVcsLog(e);
if (log != null && !GitUtil.logHasGitRoot(log)) {
e.getPresentation().setEnabledAndVisible(false);
}
else {
e.getPresentation().setEnabled(enabled(e));
}
}
private boolean enabled(AnActionEvent e) {
@@ -16,8 +16,11 @@
package git4idea.repo;
import com.intellij.dvcs.repo.Repository;
import git4idea.GitBranch;
import git4idea.GitLocalBranch;
import git4idea.GitRemoteBranch;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -97,8 +100,8 @@ public class GitRepoInfo {
if (myCurrentBranch != null ? !myCurrentBranch.equals(info.myCurrentBranch) : info.myCurrentBranch != null) return false;
if (!myRemotes.equals(info.myRemotes)) return false;
if (!myBranchTrackInfos.equals(info.myBranchTrackInfos)) return false;
if (!myLocalBranches.equals(info.myLocalBranches)) return false;
if (!myRemoteBranches.equals(info.myRemoteBranches)) return false;
if (!areEqual(myLocalBranches, info.myLocalBranches)) return false;
if (!areEqual(myRemoteBranches, info.myRemoteBranches)) return false;
return true;
}
@@ -120,4 +123,32 @@ public class GitRepoInfo {
return String.format("GitRepoInfo{current=%s, remotes=%s, localBranches=%s, remoteBranches=%s, trackInfos=%s}",
myCurrentBranch, myRemotes, myLocalBranches, myRemoteBranches, myBranchTrackInfos);
}
private static <T extends GitBranch> boolean areEqual(Collection<T> c1, Collection<T> c2) {
// GitBranch has perverted equals contract (see the comment there)
// until GitBranch is created only from a single place with correctly defined Hash, we can't change its equals
THashSet<GitBranch> set1 = new THashSet<GitBranch>(c1, new BranchesComparingStrategy());
THashSet<GitBranch> set2 = new THashSet<GitBranch>(c2, new BranchesComparingStrategy());
return set1.equals(set2);
}
private static class BranchesComparingStrategy implements TObjectHashingStrategy<GitBranch> {
@Override
public int computeHashCode(@NotNull GitBranch branch) {
return 31 * branch.getName().hashCode() + branch.getHash().hashCode();
}
@Override
public boolean equals(@NotNull GitBranch b1, @NotNull GitBranch b2) {
if (b1 == b2) {
return true;
}
if (b1.getClass() != b2.getClass()) {
return false;
}
return b1.getName().equals(b2.getName()) && b1.getHash().equals(b2.getHash());
}
}
}
@@ -56,15 +56,10 @@ public class YouTrackIntellisense {
private final int myMaxSize;
private SizeLimitedCache(int max) {
super((int)(max / 0.75) + 1);
super((int)(max / 0.75) + 1, true);
myMaxSize = max;
}
@Override
protected boolean shouldMoveEntryToTopWhenReading() {
return true;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest, K key, V value) {
return size() > myMaxSize;
+4 -8
View File
@@ -983,16 +983,14 @@
<langCodeStyleSettingsProvider implementation="com.intellij.ide.JavaLanguageCodeStyleSettingsProvider"/>
<stacktrace.fold substring="at java.awt.EventDispatchThread.pumpEventsForFilter("/>
<stacktrace.fold substring="at java.awt.EventDispatchThread.pumpEventsForHierarchy("/>
<stacktrace.fold substring="at java.awt.EventDispatchThread.pumpEvents("/>
<stacktrace.fold substring="at java.awt.EventDispatchThread"/>
<stacktrace.fold substring="at java.awt.Window.dispatchEventImpl("/>
<stacktrace.fold substring="at java.awt.Container.dispatchEventImpl("/>
<stacktrace.fold substring="at java.awt.LightweightDispatcher."/>
<stacktrace.fold substring="at java.awt.Component.dispatchEvent("/>
<stacktrace.fold substring="at java.awt.EventQueue.dispatchEvent("/>
<stacktrace.fold substring="at java.awt.event.InvocationEvent.dispatch("/>
<stacktrace.fold substring="at java.awt.EventQueue"/>
<stacktrace.fold substring="at java.awt.Component.dispatchEventImpl("/>
<stacktrace.fold substring="at java.awt.EventDispatchThread.pumpOneEventForFilters("/>
<stacktrace.fold substring="at java.awt.Container.processEvent("/>
<stacktrace.fold substring="at javax.swing.JComponent.processMouseEvent("/>
<stacktrace.fold substring="at javax.swing.plaf.basic.BasicMenuItemUI"/>
@@ -1004,12 +1002,10 @@
<stacktrace.fold substring="at javax.swing.DefaultButtonModel.setPressed("/>
<stacktrace.fold substring="at javax.swing.AbstractButton.fireActionPerformed("/>
<stacktrace.fold substring="at javax.swing.AbstractButton$Handler.actionPerformed("/>
<stacktrace.fold substring="at java.awt.EventQueue$1.run("/>
<stacktrace.fold substring="at java.security.AccessControlContext$1.doIntersectionPrivilege("/>
<stacktrace.fold substring="at java.awt.EventQueue.dispatchEventImpl("/>
<stacktrace.fold substring="at java.security.AccessController.doPrivileged(Native Method)"/>
<stacktrace.fold substring="at java.awt.EventQueue$2.run("/>
<stacktrace.fold substring="at java.awt.EventQueue.access$000("/>
<stacktrace.fold substring="at java.security.ProtectionDomain$1.doIntersectionPrivilege("/>
<stacktrace.fold substring="at com.jgoodies.binding.beans.ExtendedPropertyChangeSupport.firePropertyChange0("/>
<stacktrace.fold substring="at javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased("/>