From fc45939459a107a6586ddd455da0edea9d11de12 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 2 Nov 2013 00:26:14 +0100 Subject: [PATCH 01/21] avoid UnsupportedOperation exceptions --- .../intellij/debugger/engine/LambdaMethodFilter.java | 4 +++- .../debugger/engine/PositionManagerImpl.java | 12 ++++++++++-- .../debugger/ui/impl/watch/DebuggerTree.java | 9 ++++----- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java b/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java index 7e4fd940c772..32669347eb81 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java @@ -17,6 +17,7 @@ package com.intellij.debugger.engine; import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.psi.PsiCodeBlock; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLambdaExpression; @@ -76,7 +77,8 @@ public class LambdaMethodFilter implements BreakpointStepMethodFilter{ } public boolean locationMatches(DebugProcessImpl process, Location location) throws EvaluateException { + final VirtualMachineProxyImpl vm = process.getVirtualMachineProxy(); final Method method = location.method(); - return method.name().startsWith(LAMBDA_METHOD_PREFIX) && method.isSynthetic(); + return method.name().startsWith(LAMBDA_METHOD_PREFIX) && (!vm.canGetSyntheticAttribute() || method.isSynthetic()); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 771444af0868..6b55b4029e00 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -286,6 +286,8 @@ public class PositionManagerImpl implements PositionManager { return null; } + final boolean canGetSynthetic = vmProxy.canGetSyntheticAttribute(); + final boolean canReloadClasses = vmProxy.canRedefineClasses(); int rangeBegin = Integer.MAX_VALUE; int rangeEnd = Integer.MIN_VALUE; for (Location location : fromClass.allLineLocations()) { @@ -294,8 +296,14 @@ public class PositionManagerImpl implements PositionManager { continue; // should be a native method, skipping } final Method method = location.method(); - if (method == null || method.isSynthetic() || method.isBridge() || method.isObsolete()) { - continue; // do not take into account synthetic stuff + try { + if (method == null || (canGetSynthetic && method.isSynthetic()) || method.isBridge() || (canReloadClasses && method.isObsolete())) { + // do not take into account synthetic stuff + continue; + } + } + catch (Throwable ignored) { + LOG.info(ignored); } final int locationLine = lnumber - 1; rangeBegin = Math.min(rangeBegin, locationLine); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java index 32ace1064daf..39c2775df018 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTree.java @@ -32,10 +32,7 @@ import com.intellij.debugger.engine.events.SuspendContextCommandImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.jdi.LocalVariableProxyImpl; -import com.intellij.debugger.jdi.StackFrameProxyImpl; -import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl; -import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; +import com.intellij.debugger.jdi.*; import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.settings.ThreadsViewSettings; import com.intellij.debugger.ui.breakpoints.Breakpoint; @@ -462,8 +459,10 @@ public abstract class DebuggerTree extends DebuggerTreeBase implements DataProvi final ReferenceType thisRefType = thisObjectReference.referenceType(); if (thisRefType instanceof ClassType && thisRefType.equals(location.declaringType()) && thisRefType.name().contains("$")) { // makes sense for nested classes only final ClassType clsType = (ClassType)thisRefType; + final DebugProcessImpl debugProcess = getDebuggerContext().getDebugProcess(); + final VirtualMachineProxyImpl vm = debugProcess.getVirtualMachineProxy(); for (Field field : clsType.fields()) { - if (field.isSynthetic() && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) { + if ((!vm.canGetSyntheticAttribute() || field.isSynthetic()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) { final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(stackDescriptor, thisObjectReference, field); myChildren.add(myNodeManager.createNode(fieldDescriptor, evaluationContext)); } From 50e827775b6caf62b80fa51aab3b9e809576949b Mon Sep 17 00:00:00 2001 From: Oleg Sukhodolsky Date: Sat, 2 Nov 2013 08:26:42 +0400 Subject: [PATCH 02/21] EA-49101: getContainingFile() must not be called on invalid PsiElement --- .../com/intellij/openapi/module/ModuleUtilCore.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java index d3db67dfaeef..d466794efd00 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java +++ b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java @@ -79,13 +79,11 @@ public class ModuleUtilCore { @Nullable public static Module findModuleForPsiElement(@NotNull PsiElement element) { + if (!element.isValid()) { + return null; + } PsiFile containingFile = element.getContainingFile(); - if (containingFile == null) { - if (!element.isValid()) return null; - } - else { - if (!containingFile.isValid()) return null; - } + if (containingFile != null && !containingFile.isValid()) return null; Project project = (containingFile == null ? element : containingFile).getProject(); if (project.isDefault()) return null; From 553a88b8ec227e62733a1a99deadd346c7dec3a4 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 2 Nov 2013 15:43:20 +0100 Subject: [PATCH 03/21] do not check for obsolete --- .../debugger/engine/PositionManagerImpl.java | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 6b55b4029e00..151fc6f9bb6e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -268,18 +268,12 @@ public class PositionManagerImpl implements PositionManager { private ReferenceType findNested(final ReferenceType fromClass, final int currentDepth, final PsiClass classToFind, final int requiredDepth, final SourcePosition position) { final VirtualMachineProxyImpl vmProxy = myDebugProcess.getVirtualMachineProxy(); if (fromClass.isPrepared()) { - - try { - //final int lineNumber = position.getLine() + 1; - if (currentDepth < requiredDepth) { final List nestedTypes = vmProxy.nestedTypes(fromClass); for (ReferenceType nested : nestedTypes) { final ReferenceType found = findNested(nested, currentDepth + 1, classToFind, requiredDepth, position); if (found != null) { - // check if enclosing class also has executable code at the same line, and if yes, prefer enclosing class - //return fromClass.locationsOfLine(lineNumber).isEmpty()? found : fromClass; return found; } } @@ -287,7 +281,6 @@ public class PositionManagerImpl implements PositionManager { } final boolean canGetSynthetic = vmProxy.canGetSyntheticAttribute(); - final boolean canReloadClasses = vmProxy.canRedefineClasses(); int rangeBegin = Integer.MAX_VALUE; int rangeEnd = Integer.MIN_VALUE; for (Location location : fromClass.allLineLocations()) { @@ -296,14 +289,9 @@ public class PositionManagerImpl implements PositionManager { continue; // should be a native method, skipping } final Method method = location.method(); - try { - if (method == null || (canGetSynthetic && method.isSynthetic()) || method.isBridge() || (canReloadClasses && method.isObsolete())) { - // do not take into account synthetic stuff - continue; - } - } - catch (Throwable ignored) { - LOG.info(ignored); + if (method == null || (canGetSynthetic && method.isSynthetic()) || method.isBridge()) { + // do not take into account synthetic stuff + continue; } final int locationLine = lnumber - 1; rangeBegin = Math.min(rangeBegin, locationLine); From 840b9f540e5557616e887786e1b29dfe14d31c2e Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 2 Nov 2013 15:52:52 +0100 Subject: [PATCH 04/21] avoid IllegalThreadStateException --- .../com/intellij/debugger/engine/DebugProcessImpl.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 77f8afc227c2..dc9d1e9e1ec7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -424,8 +424,13 @@ public abstract class DebugProcessImpl implements DebugProcess { for (final StepRequest request : stepRequests) { ThreadReference threadReference = request.thread(); // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures - if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) { - toDelete.add(request); + try { + if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) { + toDelete.add(request); + } + } + catch (IllegalThreadStateException e) { + LOG.info(e); // undocumented by JDI: may be thrown when querying thread status } } requestManager.deleteEventRequests(toDelete); From e0f3ec342f9bcb889566b7dd1bc49e683d995427 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 2 Nov 2013 16:05:02 +0100 Subject: [PATCH 05/21] better error reporting --- .../debugger/impl/ReloadClassesWorker.java | 70 ++++++++----------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java b/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java index 2898e3f10dd9..796aab701765 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/ReloadClassesWorker.java @@ -26,11 +26,12 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.util.concurrency.Semaphore; import com.intellij.util.ui.MessageCategory; -import com.intellij.util.ui.UIUtil; import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.io.File; import java.io.IOException; import java.util.Collections; @@ -163,50 +164,41 @@ class ReloadClassesWorker { processException(e); } + final Semaphore waitSemaphore = new Semaphore(); + waitSemaphore.down(); //noinspection SSBasedInspection - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + SwingUtilities.invokeLater(new Runnable() { public void run() { - if (project.isDisposed()) { - return; - } - final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager(); - breakpointManager.reloadBreakpoints(); - debugProcess.getRequestsManager().clearWarnings(); - if (LOG.isDebugEnabled()) { - LOG.debug("requests updated"); - LOG.debug("time stamp set"); - } - myDebuggerSession.refresh(false); - - /* - debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { - protected void action() throws Exception { - try { - breakpointManager.enableBreakpoints(debugProcess); + try { + if (!project.isDisposed()) { + final BreakpointManager breakpointManager = (DebuggerManagerEx.getInstanceEx(project)).getBreakpointManager(); + breakpointManager.reloadBreakpoints(); + debugProcess.getRequestsManager().clearWarnings(); + if (LOG.isDebugEnabled()) { + LOG.debug("requests updated"); + LOG.debug("time stamp set"); } - catch (Exception e) { - processException(e); - } - //try { - // virtualMachineProxy.resume(); - //} - //catch (Exception e) { - // processException(e); - //} + myDebuggerSession.refresh(false); } - - public Priority getPriority() { - return Priority.HIGH; - } - }); - */ + } + catch (Throwable e) { + LOG.error(e); + } + finally { + waitSemaphore.up(); + } } }); - try { - breakpointManager.enableBreakpoints(debugProcess); - } - catch (Exception e) { - processException(e); + + waitSemaphore.waitFor(); + + if (!project.isDisposed()) { + try { + breakpointManager.enableBreakpoints(debugProcess); + } + catch (Exception e) { + processException(e); + } } } From b7dedf3e4bb800514000d8c2478182edcd3a4ded Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 2 Nov 2013 19:43:58 +0400 Subject: [PATCH 06/21] [log] cleanup --- .../intellij/vcs/log/data/VcsLogBranchFilter.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogBranchFilter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogBranchFilter.java index 49101372c4fb..aed9fe018920 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogBranchFilter.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogBranchFilter.java @@ -8,26 +8,22 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; -/** - * TODO use VcsRef instead of String - */ public class VcsLogBranchFilter implements VcsLogGraphFilter { @NotNull private final Collection myMatchingHeads; - private final String myBranchName; + @NotNull private final String myBranchName; - public VcsLogBranchFilter(Collection allRefs, final String branchName) { - myBranchName = branchName; + public VcsLogBranchFilter(@NotNull Collection allRefs, @NotNull final String selectedBranchName) { + myBranchName = selectedBranchName; myMatchingHeads = ContainerUtil.mapNotNull(allRefs, new Function() { @Override public Hash fun(VcsRef ref) { - if (ref.getName().equals(branchName)) { + if (ref.getName().equals(selectedBranchName)) { return ref.getCommitHash(); } return null; } }); - } @Override @@ -44,4 +40,5 @@ public class VcsLogBranchFilter implements VcsLogGraphFilter { public String getBranchName() { return myBranchName; } + } From 612c0758867410adca4ecfcf9b8dfb2c484d4121 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 2 Nov 2013 20:24:31 +0400 Subject: [PATCH 07/21] [log] Hide the Branches Panel by default, introduce log quick settings Motivation: The panel with branch labels and ability to navigate to the selected branch by clicking on it seems to be not designed well enough, especially when there are many local branches, and in the multi-repo case. Introduce "Quick Settings" button at the log toolbar. Add "Show Branches Panel" action there. --- .../com/intellij/vcs/log/VcsLogSettings.java | 7 ++ .../vcs-log/impl/src/META-INF/vcs-log.xml | 5 +- .../vcs/log/impl/VcsLogSettingsImpl.java | 11 +++ .../log/ui/VcsLogQuickSettingsActions.java | 87 +++++++++++++++++++ .../src/com/intellij/vcs/log/ui/VcsLogUI.java | 6 +- .../vcs/log/ui/frame/ActiveSurface.java | 9 +- .../intellij/vcs/log/ui/frame/MainFrame.java | 9 +- 7 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogQuickSettingsActions.java diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogSettings.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogSettings.java index 4d73ca6b2fa4..a370379b4d77 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogSettings.java +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogSettings.java @@ -18,4 +18,11 @@ public interface VcsLogSettings { */ int getRecentCommitsCount(); + /** + * Checks if the branches panel should be displayed or hidden. + */ + boolean isShowBranchesPanel(); + + void setShowBranchesPanel(boolean show); + } diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index d5596f2daf88..3ae9b30c7bcc 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -18,9 +18,12 @@ - + + + diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogSettingsImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogSettingsImpl.java index 42ac17687493..88b2b449ac69 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogSettingsImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogSettingsImpl.java @@ -17,6 +17,7 @@ public class VcsLogSettingsImpl implements VcsLogSettings, PersistentStateCompon public static class State { public int RECENT_COMMITS_COUNT = 1000; + public boolean SHOW_BRANCHES_PANEL = false; } @Nullable @@ -35,6 +36,16 @@ public class VcsLogSettingsImpl implements VcsLogSettings, PersistentStateCompon return myState.RECENT_COMMITS_COUNT; } + @Override + public boolean isShowBranchesPanel() { + return myState.SHOW_BRANCHES_PANEL; + } + + @Override + public void setShowBranchesPanel(boolean show) { + myState.SHOW_BRANCHES_PANEL = show; + } + public void setRecentCommitsBlockSize(int commitCount) { myState.RECENT_COMMITS_COUNT = commitCount; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogQuickSettingsActions.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogQuickSettingsActions.java new file mode 100644 index 000000000000..36ce6fdac616 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogQuickSettingsActions.java @@ -0,0 +1,87 @@ +/* + * 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.*; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.impl.content.ToolWindowContentUi; +import com.intellij.vcs.log.VcsLogSettings; +import com.intellij.vcs.log.impl.VcsLogManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; + +public class VcsLogQuickSettingsActions extends DumbAwareAction { + + @Override + public void actionPerformed(AnActionEvent e) { + Project project = e.getProject(); + if (project == null) { + return; + } + VcsLogSettings settings = ServiceManager.getService(project, VcsLogSettings.class); + VcsLogManager logManager = ServiceManager.getService(project, VcsLogManager.class); + if (settings == null || logManager == null) { + return; + } + VcsLogUI logUi = logManager.getLogUi(); + + ActionGroup settingsGroup = new MySettingsActionGroup(settings, logUi); + ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ToolWindowContentUi.POPUP_PLACE, settingsGroup); + int x = 0; + int y = 0; + InputEvent inputEvent = e.getInputEvent(); + if (inputEvent instanceof MouseEvent) { + x = ((MouseEvent)inputEvent).getX(); + y = ((MouseEvent)inputEvent).getY(); + } + popupMenu.getComponent().show(inputEvent.getComponent(), x, y); + } + + private static class MySettingsActionGroup extends ActionGroup { + + private final VcsLogSettings mySettings; + private final VcsLogUI myUi; + + public MySettingsActionGroup(VcsLogSettings settings, VcsLogUI ui) { + mySettings = settings; + myUi = ui; + } + + @NotNull + @Override + public AnAction[] getChildren(@Nullable AnActionEvent e) { + return new AnAction[] { + new ToggleAction("Show Branches Panel") { + @Override + public boolean isSelected(AnActionEvent e) { + return mySettings.isShowBranchesPanel(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + mySettings.setShowBranchesPanel(state); + myUi.setBranchesPanelVisible(state); + } + } + }; + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java index 14e01a5da6fd..a046355dda27 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java @@ -52,7 +52,7 @@ public class VcsLogUI { myColorManager = manager; myUiProperties = uiProperties; myFilterer = new VcsLogFilterer(logDataHolder, this); - myMainFrame = new MainFrame(myLogDataHolder, this, project, uiProperties); + myMainFrame = new MainFrame(myLogDataHolder, this, project, settings, uiProperties); project.getMessageBus().connect(project).subscribe(VcsLogDataHolder.REFRESH_COMPLETED, new Runnable() { @Override public void run() { @@ -247,4 +247,8 @@ public class VcsLogUI { ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, task, false, null, this.getMainFrame().getMainComponent()); } + public void setBranchesPanelVisible(boolean visible) { + myMainFrame.setBranchesPanelVisible(visible); + } + } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java index d31357198d63..ebbe543da928 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java @@ -12,6 +12,7 @@ import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.components.JBLoadingPanel; import com.intellij.util.ArrayUtil; +import com.intellij.vcs.log.VcsLogSettings; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.ui.VcsLogUI; import org.jetbrains.annotations.NotNull; @@ -38,10 +39,16 @@ public class ActiveSurface extends JPanel implements TypeSafeDataProvider { @NotNull private final Splitter myDetailsSplitter; @NotNull private final JBLoadingPanel myChangesLoadingPane; - ActiveSurface(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, @NotNull Project project) { + ActiveSurface(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, + @NotNull VcsLogSettings settings, @NotNull Project project) { myLogDataHolder = logDataHolder; myGraphTable = new VcsLogGraphTable(vcsLogUI, logDataHolder); myBranchesPanel = new BranchesPanel(logDataHolder, vcsLogUI); + + if (!settings.isShowBranchesPanel()) { + myBranchesPanel.setVisible(false); + } + myDetailsPanel = new DetailsPanel(logDataHolder, myGraphTable, vcsLogUI.getColorManager()); final ChangesBrowser changesBrowser = new ChangesBrowser(project, null, Collections.emptyList(), null, false, false, null, diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index f44746b10f9d..83970bec324a 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -8,6 +8,7 @@ import com.intellij.openapi.project.Project; import com.intellij.ui.JBColor; import com.intellij.ui.SeparatorComponent; import com.intellij.ui.SeparatorOrientation; +import com.intellij.vcs.log.VcsLogSettings; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.ui.VcsLogUI; @@ -33,13 +34,13 @@ public class MainFrame { @NotNull private final VcsLogFilterUi myFilterUi; public MainFrame(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, @NotNull Project project, - @NotNull VcsLogUiProperties uiProperties) { + @NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties) { myLogDataHolder = logDataHolder; myUI = vcsLogUI; myProject = project; myUiProperties = uiProperties; - myActiveSurface = new ActiveSurface(logDataHolder, vcsLogUI, project); + myActiveSurface = new ActiveSurface(logDataHolder, vcsLogUI, settings, project); myActiveSurface.setupDetailsSplitter(myUiProperties.isShowDetails()); JComponent toolbar = Box.createHorizontalBox(); @@ -135,4 +136,8 @@ public class MainFrame { myActiveSurface.getBranchesPanel().rebuild(); } + public void setBranchesPanelVisible(boolean visible) { + myActiveSurface.getBranchesPanel().setVisible(visible); + } + } From f92ce9af0629ee8dcc8743dcc2c1ca297aaacc7c Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 1 Nov 2013 19:47:00 +0100 Subject: [PATCH 08/21] add "pure" attribute to @Contract (IDEA-107864) --- .../dataFlow/ControlFlowAnalyzer.java | 2 +- .../dataFlow/DataFlowInspectionBase.java | 18 ++++++++++---- .../dataFlow/fixture/ContractAnnotation.java | 3 +++ .../DataFlowInspectionTest.java | 6 ----- java/mockJDK-1.7/jre/lib/annotations.jar | Bin 22054 -> 22252 bytes .../org/jetbrains/annotations/Contract.java | 12 +++++++-- .../IgnoreResultOfCallInspectionBase.java | 9 +++++++ ...> IgnoreResultOfCallInspectionTest.groovy} | 23 +++++++++++++++--- 8 files changed, 56 insertions(+), 17 deletions(-) rename plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/{IgnoreResultOfCallInspectionTest.java => IgnoreResultOfCallInspectionTest.groovy} (82%) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 3492a2b13b04..7a89381553f8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -42,7 +42,7 @@ import static com.intellij.codeInsight.ConditionChecker.Type.*; import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint; import static com.intellij.psi.CommonClassNames.*; -class ControlFlowAnalyzer extends JavaElementVisitor { +public class ControlFlowAnalyzer extends JavaElementVisitor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer"); public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName(); private boolean myIgnoreAssertions; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index eeb81ea22292..c6314f7d9bb1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -111,13 +111,21 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool { if (method == null) return; String text = AnnotationUtil.getStringAttributeValue(annotation, null); - if (text == null) return; + if (StringUtil.isNotEmpty(text)) { + String error = checkContract(method, text); + if (error != null) { + PsiAnnotationMemberValue value = annotation.findAttributeValue(null); + assert value != null; + holder.registerProblem(value, error); + return; + } + } - String error = checkContract(method, text); - if (error != null) { - PsiAnnotationMemberValue value = annotation.findAttributeValue(null); + if (Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(annotation, "pure")) && + PsiType.VOID.equals(method.getReturnType())) { + PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue("pure"); assert value != null; - holder.registerProblem(value, error); + holder.registerProblem(value, "Pure methods must return something, void is not allowed as a return type"); } } }; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java index a5c27dd21749..3d97047e240e 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractAnnotation.java @@ -46,4 +46,7 @@ public class AssertIsNotNull { @Contract("null -> _") void wrongParameterCount(Object a, boolean b) {} + + @Contract(pure=true) + void voidPureMethod() {} } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index f8707d97f9e3..02dcfc0072b3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -39,12 +39,6 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { return JAVA_1_7; } - @Override - protected void setUp() throws Exception { - super.setUp(); - myFixture.addClass("package org.jetbrains.annotations; public @interface Contract { String value(); }"); - } - @Override protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/"; diff --git a/java/mockJDK-1.7/jre/lib/annotations.jar b/java/mockJDK-1.7/jre/lib/annotations.jar index c1e4afba8bee96adb9c74fe1d02b30efe66c8ffb..72aa54c908ed997ee412ad6d256870a218f01f65 100644 GIT binary patch delta 2249 zcmaJ>c}$aM7=OR7T`BF?LR;v;XX#hY0;S+Y1RS_p&~gZc77vUuh~*M54mIw;BU_dw zsN~6(Ek<|7c}$&aTw<~%nwU7Q^8qFE`s53)e^2MqAq3LUnplC=hdP-I8E? zQ*3Q4*tWDTrY9~qD7u8A#98rz81Te;lJR>UpNtjtFBPuv>f5cy={qa;0N1+ zM2)+aD?gWMN@9Lq%Kb%T%nLq;hTpJe^{tg6A(V>nhFP$vO-kG-TF3Q5fm7VYuO;bP zW+|23;G(H=qhP`A4w?4t_1e&!k`FvpZpf=}z~!37soE_ggK_LPUqOck3qum!72N`C zEO&&Hu`smRG#%J^wBu;sNyLPw2g_*2GX+(&ags_Kg|e%O5XWvwQ&liwsVd{?grBIM zzFN(C&fI;nhcl}}QO=yMGm7G&PWW(XrE26s2+yaNgUYb%xQMa&gbQMthOY@K+Ypwk zzn_-%Z5oab4D|Km8c->zR)rOn`Ikzjf))XG>(czQ4d_akQK2VoUj9*opa5rzyoLW0 zfWFcL{b!)L-p$s{rg~XCCV)~k=aF!#4K!no=i9p{X?_YWBm>;5m)L7a4YGJ!hj1yZ zYLFD#sj7ic+3(PUMIVNV25$Q`+9nwgDu#(<8&oz*tkVZB-8c%94R-NaBV26^z(+<2 zUTd^^sPCt@S2U*Mpix?=^8Fip-q^rWayQ9hmzlX;lVgLOO;!f)NBB+(gTHE$S*A6U ze~jm&CrY&{Z!0WJ@i5w#T6D0hiD%rmOcrlhnaE=^X9T(iI){d4my70D{`bBS7>(G) zjx?sJG-tDDbb?(NiBh#H+Vym%c%V6xWqPJr7F!))aR;EqM+%`jSGfH&K?%lvNdk&Cz&D3z;R_Lnl{yK^m|i}DAO zqq4ZCj73^lCaLNx6N9_U3`g5|;z~>w zuT&wNoAOX2z*ZCq)hKeqiI{^u(cwSyrn2yPDCMhM2NyBL`!OebqKtM~JQ`$>95li0 j=?2__u(cN9IdH7q%``6~)VqX1fu(vdEVt{1!qoM@OyC2T delta 2081 zcmZWqdu-E19KXBPwd?z}NB7&-PR3Y)b!dZ zicNm)5yO>IK0qNY(`?xngH~E4=1)+c7(bvZ?Z}58I-$9+MoS2{Qm~nepny3Ii*;n7 zj+E%gA_%h8B@RlAiH64b=6G92EL^82rIc7|>*_-t&56y4P;5h8LQitw0&`Pe>MHw; z9mq{=?;G*%Opb2f)#Dvbj*blvdiQh>j3rAbp@gAn$X&!uwD?U)1{TAJ4(IxL^Guu@ z=FN>bH_e-yac-G6&m>wcC01f1^Z>D=OU(#zAmb!1j3J1PBnydbF1e}5K_XYBz*O8K zp**7CSd6LW<5+-u3X{Y`yrhW3F2a)JZnA)X72i50YhFvR%KMx;tbdZ~IX6)= zvmc%|22xSOYPmFF9F>5XcStZ~c~pXH*6kAX*k_qbj=hrUbsdxrFUQNLA)On5W7(!u zWwuW)KajIef(yC3C1}e#D#5SHQMvQqJ*l5yz!iY%LOZwy~$ zO3o>ay=%C)JQ|_QrI8nquT?ZE^cQGp%ooamMuoX3*v&3D)@Ty>mTteyA~-Ald8?uJ<85Y(l#Fjx^7B|9oc=y5?4^a-TK} z_vvCM)U-G}JeQ%K>{2HRxdm0?KG@yTC}MrwqOfmmV(W3c8@#Quy7E?qZE^^Dpx6SB zwaUz1K>EB>(4H(iJl`&9Q=7szW(gWEA8c)ty?A5L{=EldbE{Fs|0-LEPZn9>T$@9@ z2hU!vyaM*NY#IR?Z5FvjqY69e7D}t)hE!C#?O%L0v>aV>Yf`!0sLYB@P}nY>eW+>2 zW6Bpazuh-8ejDir3z1$5*Jg{b#1!`ULZrM9iRFpIJbTvq@|TPdZWXFX(#LG4FsrhJw%!soNfACSJWT+oGy zT%oK=C@j57P%j0HbHQ)DF!;Bn3Vt~N?M?ao&4G7gvVp-JVgFy)JZ=kAVr@`}Jsnx1 zq(diW>aL@RTZu}z<{lv&>X2DYbSP|mt)Q$S9UNSjfiIH!rAVXX#~L9?hb(veu@Contract("_, null -> null; _, !null -> !null") - method returns null if its second argument is null and not-null otherwise
* @Contract("true -> fail") - a typical assertFalse method which throws an exception if true is passed to it
* - * @author peter */ @Documented @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) public @interface Contract { - String value(); + /** + * Contains the contract clauses describing causal relations between call arguments and the returned value + */ + String value() default ""; + + /** + * Specifies if this method is pure, i.e. has no visible side effects. This may be used for more precise data flow analysis, and + * to check that the method's return value is actually used in the call place. + */ + boolean pure() default false; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java index da52a98e6d70..0da3ca3c2aa5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java @@ -15,6 +15,8 @@ */ package com.siyeh.ig.bugs; +import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; @@ -146,6 +148,13 @@ public class IgnoreResultOfCallInspectionBase extends BaseInspection { registerMethodCallError(call, aClass); return; } + + PsiAnnotation contractAnnotation = ControlFlowAnalyzer.findContractAnnotation(method); + if (contractAnnotation != null && Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(contractAnnotation, "pure"))) { + registerMethodCallError(call, aClass); + return; + } + final PsiReferenceExpression methodExpression = call.getMethodExpression(); final String methodName = methodExpression.getReferenceName(); if (methodName == null) { diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy similarity index 82% rename from plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.java rename to plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy index 922fedc676e0..a9175c14f9e4 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy @@ -12,15 +12,15 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase { @Override protected String[] getEnvironmentClasses() { - return new String[]{ + return [ "package java.util.regex; public class Pattern {" + " public static Pattern compile(String regex) {return null;}" + " public Matcher matcher(CharSequence input) {return null;}" + "}", "package java.util.regex; public class Matcher {" + " public boolean find() {return true;}" + - "}", - }; + "}" + ] as String[] } public void testObjectMethods() { @@ -41,4 +41,21 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase { " }\n" + "}\n"); } + + public void testPureMethod() { + doTest """ +import org.jetbrains.annotations.Contract; + +class Util { + @Contract(pure=true) + static Object util() { return null; } +} + +class C { + { + Util./*Result of 'Util.util()' is ignored*/util/**/(); + } +} +""" + } } \ No newline at end of file From f7ae406fefb1d0b861075108d769de4f7794b60f Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 1 Nov 2013 20:04:04 +0100 Subject: [PATCH 09/21] there's no need anymore to artificially move live template items to the second place in the autopopup --- .../completion/JavaAutoPopupTest.groovy | 14 +++++++------- .../completion/CompletionLookupArranger.java | 10 +--------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 052442f9a61e..04a73243dd91 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -116,7 +116,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { } """) type "r" - assertContains "iterable", "iter" + myFixture.assertPreferredCompletionItems 1, "iter", "iterable" type '\b' assertContains "iterable" @@ -131,7 +131,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { assertContains "iterable" type "r" - assertContains "iterable", "iter" + myFixture.assertPreferredCompletionItems 1, "iter", "iterable" } public void testExplicitSelectionShouldSurvive() { @@ -151,7 +151,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { assertEquals 'iterable2', lookup.currentItem.lookupString type "r" - myFixture.assertPreferredCompletionItems 2, "iterable", "iter", 'iterable2' + myFixture.assertPreferredCompletionItems 2, "iter", "iterable", 'iterable2' } @@ -172,7 +172,7 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { assertEquals 'iterable2', lookup.currentItem.lookupString type "r" - myFixture.assertPreferredCompletionItems 2, "iterable", "iter", 'iterable2' + myFixture.assertPreferredCompletionItems 2, "iter", "iterable", 'iterable2' } @@ -1305,7 +1305,7 @@ class Foo { type 'e' myFixture.assertPreferredCompletionItems 0, 'itera', 'itex' type 'r' - myFixture.assertPreferredCompletionItems 0, 'itera', 'iter' + myFixture.assertPreferredCompletionItems 1, 'iter', 'itera' type '\b' myFixture.assertPreferredCompletionItems 0, 'itera', 'itex' } @@ -1544,9 +1544,9 @@ class Foo { } ''' type 'tpl' - myFixture.assertPreferredCompletionItems 0, 'tplMn', 'tpl' + myFixture.assertPreferredCompletionItems 1, 'tpl', 'tplMn' - LookupElementPresentation p = LookupElementPresentation.renderElement(myFixture.lookupElements[1]) + LookupElementPresentation p = LookupElementPresentation.renderElement(myFixture.lookupElements[0]) assert p.itemText == 'tpl' assert !p.tailText def tabKeyPresentation = KeyEvent.getKeyText(TemplateSettings.TAB_CHAR as int) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java index 76416e74ef56..b460abe8b399 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java @@ -223,15 +223,7 @@ public class CompletionLookupArranger extends LookupArranger { ensureItemAdded(items, model, byRelevance, relevantSelection); ensureEverythingVisibleAdded(lookup, model, byRelevance); - ArrayList result = new ArrayList(model); - if (result.size() > 1) { - LookupElement first = result.get(0); - if (isLiveTemplate(first) && isPrefixItem(lookup, first, true) && CompletionServiceImpl.isStartMatch(result.get(1), lookup)) { - ContainerUtil.swapElements(result, 0, 1); - } - } - - return result; + return new ArrayList(model); } private static void ensureEverythingVisibleAdded(LookupImpl lookup, final LinkedHashSet model, Iterator byRelevance) { From 8353b38f9ea441919fa24b55b8decac4459d108e Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 1 Nov 2013 20:06:56 +0100 Subject: [PATCH 10/21] add a registry key to allow to preselect live templates in the autopopup --- .../template/impl/LiveTemplateCompletionContributor.java | 2 +- platform/platform-resources-en/src/misc/registry.properties | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java index 413835ffd48f..a6b0eba7730a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateCompletionContributor.java @@ -133,7 +133,7 @@ public class LiveTemplateCompletionContributor extends CompletionContributor { @Override public boolean skipElement(LookupElement element, CompletionLocation location) { - return element instanceof LiveTemplateLookupElement && ((LiveTemplateLookupElement)element).sudden; + return element instanceof LiveTemplateLookupElement && ((LiveTemplateLookupElement)element).sudden && !Registry.is("ide.completion.autopopup.select.live.templates"); } } diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index c2a3376be978..d4075008459a 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -213,6 +213,7 @@ ide.mac.fix.accessibleLeak=true projectView.showHierarchyErrors=true projectView.hide.dot.idea=true show.live.templates.in.completion=false +ide.completion.autopopup.select.live.templates=false documentation.component.editor.font=false ide.completion.show.better.matching.classes=true From 49e112c23c9fa99f524bec0786e5b38928cd2758 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Sun, 3 Nov 2013 12:52:52 +0100 Subject: [PATCH 11/21] api for (re)creating PHM that rewrites it if it is broken (IDEA-115334) --- .../api/indexer/CompilerOutputBaseIndex.java | 40 ++++++----- .../api/indexer/CompilerOutputIndexer.java | 66 +++++++++++-------- .../util/src/com/intellij/util/io/IOUtil.java | 23 +++++++ .../idea/maven/indices/MavenIndex.java | 10 ++- 4 files changed, 91 insertions(+), 48 deletions(-) diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java index cc315b646281..1c0231b97b11 100644 --- a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputBaseIndex.java @@ -5,10 +5,11 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.IOUtil; import com.intellij.util.io.KeyDescriptor; import com.intellij.util.io.PersistentHashMap; import org.jetbrains.asm4.tree.ClassNode; @@ -51,24 +52,32 @@ public abstract class CompilerOutputBaseIndex { if (!IndexInfrastructure.getIndexRootDir(indexId).exists()) { rewriteIndex.set(true); } - final File storageFile = IndexInfrastructure.getStorageFile(indexId); + final File storageFile = getStorageFile(indexId); final MapIndexStorage indexStorage = new MapIndexStorage(storageFile, myKeyDescriptor, myValueExternalizer, 1024); index = new MapReduceIndex(indexId, getIndexer(), indexStorage); index.setInputIdToDataKeysIndex(new Factory>>() { @Override public PersistentHashMap> create() { - Exception failCause = null; - for (int attempts = 0; attempts < 2; attempts++) { - try { - return FileBasedIndexImpl.createIdToDataKeysIndex(indexId, myKeyDescriptor, new MemoryIndexStorage(indexStorage)); - } - catch (IOException e) { - failCause = e; - FileUtil.delete(IndexInfrastructure.getInputIndexStorageFile(getIndexId())); - rewriteIndex.set(true); - } + try { + return IOUtil.openCleanOrResetBroken( + new ThrowableComputable>, IOException>() { + @Override + public PersistentHashMap> compute() throws IOException { + return FileBasedIndexImpl.createIdToDataKeysIndex(indexId, myKeyDescriptor, new MemoryIndexStorage(indexStorage)); + } + }, + new Runnable() { + @Override + public void run() { + FileUtil.delete(getInputIndexStorageFile(getIndexId())); + rewriteIndex.set(true); + } + } + ); + } + catch (IOException e) { + throw new RuntimeException("couldn't create index", e); } - throw new RuntimeException("couldn't create index", failCause); } }); final File versionFile = getVersionFile(indexId); @@ -144,9 +153,4 @@ public abstract class CompilerOutputBaseIndex { protected final ID generateIndexId(final String indexName) { return CompilerOutputIndexUtil.generateIndexId(indexName, myProject); } - - protected final ID generateIndexId(final Class aClass) { - final String className = StringUtil.getShortName(aClass); - return generateIndexId(StringUtil.trimEnd(className, "Index")); - } } diff --git a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java index 3c23306b8b53..fed4c02502b0 100644 --- a/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java +++ b/java/java-impl/src/com/intellij/compilerOutputIndex/api/indexer/CompilerOutputIndexer.java @@ -12,6 +12,7 @@ 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.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.RegistryValue; import com.intellij.openapi.util.registry.RegistryValueListener; @@ -153,16 +154,19 @@ public class CompilerOutputIndexer extends AbstractProjectComponent { private void doEnable() { if (myInitialized.compareAndSet(false, true)) { initTimestampIndex(); - File storageFile = + final File storageFile = IndexInfrastructure.getStorageFile(CompilerOutputIndexUtil.generateIndexId("compilerOutputIndexFileId.enum", myProject)); - for (int i = 0; i < 2; i++) { - try { - myFileEnumerator = new PersistentEnumeratorDelegate(storageFile, new EnumeratorStringDescriptor(), 2048); - } - catch (IOException e) { - if (i == 1) throw new RuntimeException(e); - IOUtil.deleteAllFilesStartingWith(storageFile); - } + + try { + myFileEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable, IOException>() { + @Override + public PersistentEnumeratorDelegate compute() throws IOException { + return new PersistentEnumeratorDelegate(storageFile, new EnumeratorStringDescriptor(), 2048); + } + }, storageFile); + } + catch (IOException e) { + throw new RuntimeException(e); } CompilerManager.getInstance(myProject).addCompilationStatusListener(new CompilationStatusAdapter() { @Override @@ -184,29 +188,35 @@ public class CompilerOutputIndexer extends AbstractProjectComponent { } private void initTimestampIndex() { - for (int attempts = 0; attempts < 2; attempts++) { - try { - myFileTimestampsIndex = new PersistentHashMap(IndexInfrastructure.getStorageFile(getFileTimestampsIndexId()), - new EnumeratorStringDescriptor(), new DataExternalizer() { + final File storageFile = IndexInfrastructure.getStorageFile(getFileTimestampsIndexId()); + try { + myFileTimestampsIndex = IOUtil.openCleanOrResetBroken( + new ThrowableComputable, IOException>() { @Override - public void save(final DataOutput out, final Long value) throws IOException { - out.writeLong(value); - } + public PersistentHashMap compute() throws IOException { + return new PersistentHashMap(storageFile, + new EnumeratorStringDescriptor(), new DataExternalizer() { + @Override + public void save(final DataOutput out, final Long value) throws IOException { + out.writeLong(value); + } - @Override - public Long read(final DataInput in) throws IOException { - return in.readLong(); + @Override + public Long read(final DataInput in) throws IOException { + return in.readLong(); + } + }); } - }); - } - catch (IOException e) { - FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId())); - } - if (myFileTimestampsIndex != null) { - return; - } + }, + new Runnable() { + public void run() { + FileUtil.delete(IndexInfrastructure.getIndexRootDir(getFileTimestampsIndexId())); + } + } + ); + } catch (IOException ex) { + throw new RuntimeException("Timestamps index not initialized", ex); } - throw new RuntimeException("Timestamps index not initialized"); } public void reindex(final FileVisitorService visitorService, final @NotNull ProgressIndicator indicator) { diff --git a/platform/util/src/com/intellij/util/io/IOUtil.java b/platform/util/src/com/intellij/util/io/IOUtil.java index 89496e5dac7f..c10f04a78dba 100644 --- a/platform/util/src/com/intellij/util/io/IOUtil.java +++ b/platform/util/src/com/intellij/util/io/IOUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.util.io; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.SystemProperties; @@ -184,4 +185,26 @@ public class IOUtil { throw new RuntimeException(e); } } + + public static T openCleanOrResetBroken(@NotNull ThrowableComputable factoryComputable, final File file) throws IOException { + return openCleanOrResetBroken(factoryComputable, new Runnable() { + @Override + public void run() { + deleteAllFilesStartingWith(file); + } + }); + } + + public static T openCleanOrResetBroken(@NotNull ThrowableComputable factoryComputable, Runnable cleanupCallback) throws IOException { + for(int i = 0; i < 2; ++i) { + try { + return factoryComputable.compute(); + } catch (IOException ex) { + if (i == 1) throw ex; + cleanupCallback.run(); + } + } + + return null; + } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java index dd1e26f55302..9a933d3bbfd7 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.maven.indices; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.*; import gnu.trove.THashMap; @@ -617,8 +618,13 @@ public class MavenIndex { } } - private PersistentHashMap> createPersistentMap(File f) throws IOException { - return new PersistentHashMap>(f, new EnumeratorStringDescriptor(), new SetDescriptor()); + private PersistentHashMap> createPersistentMap(final File f) throws IOException { + return IOUtil.openCleanOrResetBroken(new ThrowableComputable>, IOException>() { + @Override + public PersistentHashMap> compute() throws IOException { + return new PersistentHashMap>(f, new EnumeratorStringDescriptor(), new SetDescriptor()); + } + }, f); } public void close(boolean releaseIndexContext) throws MavenIndexException { From e06d91c0aa5fed400852549b25bb30a71281809d Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Sun, 3 Nov 2013 13:18:04 +0100 Subject: [PATCH 12/21] don't use editor highlighter from editor as it is built with other options --- .../lang-impl/src/com/intellij/find/impl/FindManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index fb8a7d8253f4..b35309e40b58 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -522,7 +522,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo try { if (editorHighlighter instanceof LayeredLexerEditorHighlighter) { - lexer = LexerEditorHighlighterLexer.getLexerBasedOnLexerHighlighter(text, file, myProject); + lexer = new LexerEditorHighlighterLexer(editorHighlighter, false); } else { lexer = highlighter.getHighlightingLexer(); } From f248ffc5a0e73a1aef197fc908f13822b6cce601 Mon Sep 17 00:00:00 2001 From: Vassiliy Date: Sun, 3 Nov 2013 16:49:08 +0400 Subject: [PATCH 13/21] http://ea.jetbrains.com/browser/ea_problems/51445 --- .../com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index b17dc292ca51..b515362b5024 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -213,7 +213,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark } private int fitLineToEditor(int visualLine) { - return Math.min(myEditor.getVisibleLineCount() - 1, Math.max(0, visualLine)); + return Math.max(0, Math.min(myEditor.getVisibleLineCount() - 1, visualLine)); } private int getOffset(int visualLine, boolean startLine) { From e5f84100c8e22ee686be64efcecb68d09ef03cd1 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sun, 3 Nov 2013 15:32:16 +0100 Subject: [PATCH 14/21] fix "not resumed" assertion --- .../events/SuspendContextCommandImpl.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java index f3ad39594d3a..739c96270cca 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/events/SuspendContextCommandImpl.java @@ -67,16 +67,23 @@ public abstract class SuspendContextCommandImpl extends DebuggerCommandImpl { } finally{ suspendContext.myInProgress = false; - SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand(); - if (postponed != null) { - final Stack stack = new Stack(); - while (postponed != null) { - stack.push(postponed); - postponed = suspendContext.pollPostponedCommand(); + if (suspendContext.isResumed()) { + for (SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand(); postponed != null; postponed = suspendContext.pollPostponedCommand()) { + postponed.notifyCancelled(); } - final DebuggerManagerThreadImpl managerThread = suspendContext.getDebugProcess().getManagerThread(); - while (!stack.isEmpty()) { - managerThread.pushBack(stack.pop()); + } + else { + SuspendContextCommandImpl postponed = suspendContext.pollPostponedCommand(); + if (postponed != null) { + final Stack stack = new Stack(); + while (postponed != null) { + stack.push(postponed); + postponed = suspendContext.pollPostponedCommand(); + } + final DebuggerManagerThreadImpl managerThread = suspendContext.getDebugProcess().getManagerThread(); + while (!stack.isEmpty()) { + managerThread.pushBack(stack.pop()); + } } } } From aef03d9f2d459e7160c33b8eb6c8ebe125d7ee55 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 18:47:33 +0400 Subject: [PATCH 15/21] [log] "Checkout Revision" action to the new log, some refactoring * Instead of making VcsLog a project service and acquiring an instance from the ServiceManager, provide it from the DataProvider via the defined DataKey. * Make the MainFrame the main Log component and the DataProvider. * Implement GitCheckoutRevisionAction (just delegate to the GitBrancher) * Introduce VcsLog#getSelectedDetails instead of getSelectedCommits + getDetailsIfAvailable, because it can be better for performance reasons: getting the Node by Hash in the GraphTableModel can be expensive. --- .../api/src/com/intellij/vcs/log/VcsLog.java | 7 ++ .../com/intellij/vcs/log/VcsLogDataKeys.java | 27 ++++++ .../vcs-log/impl/src/META-INF/vcs-log.xml | 1 - .../com/intellij/vcs/log/impl/VcsLogImpl.java | 38 ++++++--- .../src/com/intellij/vcs/log/ui/VcsLogUI.java | 6 +- .../intellij/vcs/log/ui/frame/MainFrame.java | 26 ++++-- .../ui/tables/AbstractVcsLogTableModel.java | 4 + .../vcs/log/ui/tables/GraphTableModel.java | 7 ++ .../vcs/log/ui/tables/NoGraphTableModel.java | 6 ++ plugins/git4idea/src/META-INF/plugin.xml | 4 + plugins/git4idea/src/git4idea/GitUtil.java | 12 +++ .../branch/GitCheckoutRevisionAction.java | 85 +++++++++++++++++++ .../cherrypick/GitCherryPickAction.java | 15 ++-- ...ithubShowCommitInBrowserFromLogAction.java | 10 +-- 14 files changed, 207 insertions(+), 41 deletions(-) create mode 100644 platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogDataKeys.java create mode 100644 plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java index ab79e3305b06..a90fad17baae 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLog.java @@ -32,6 +32,13 @@ public interface VcsLog { @NotNull List getSelectedCommits(); + /** + * Returns details of the selected commits if all of them have been loaded. + * To avoid data inconsistency, if at least one of the selected commits have no details loaded, empty list is returned. + */ + @NotNull + List getSelectedDetails(); + /** * Returns details of the given commit, if they have been already loaded. * In most cases they are already in the cache, and will be returned. diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogDataKeys.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogDataKeys.java new file mode 100644 index 000000000000..3f0efa30084f --- /dev/null +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogDataKeys.java @@ -0,0 +1,27 @@ +/* + * 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; + +import com.intellij.openapi.actionSystem.DataKey; + +/** + * Provides {@link DataKey DataKeys} which can be used by actions to access data available in the VCS log. + */ +public class VcsLogDataKeys { + + public static DataKey VSC_LOG = DataKey.create("Vcs.Log"); + +} diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index 3ae9b30c7bcc..9e7f1114570d 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -12,7 +12,6 @@ - diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java index 07da58e71db4..3489b5e5a2a7 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java @@ -20,6 +20,8 @@ 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; @@ -32,25 +34,19 @@ import java.util.List; */ public class VcsLogImpl implements VcsLog { - private final VcsLogManager myLogManager; + @NotNull private final VcsLogDataHolder myDataHolder; + @NotNull private final VcsLogUI myUi; - public VcsLogImpl(VcsLogManager vcsLogManager) { - myLogManager = vcsLogManager; - } - - /** - * Checks if the log is initialized. - * TODO Temporary method until the old Git log is switched off and removed - */ - public boolean isReady() { - return myLogManager.getDataHolder() != null && myLogManager.getLogUi() != null; + public VcsLogImpl(@NotNull VcsLogDataHolder holder, @NotNull VcsLogUI ui) { + myDataHolder = holder; + myUi = ui; } @Override @NotNull public List getSelectedCommits() { List hashes = ContainerUtil.newArrayList(); - JBTable table = myLogManager.getLogUi().getTable(); + JBTable table = myUi.getTable(); for (int row : table.getSelectedRows()) { Hash hash = ((AbstractVcsLogTableModel)table.getModel()).getHashAtRow(row); if (hash != null) { @@ -60,10 +56,26 @@ public class VcsLogImpl implements VcsLog { return hashes; } + @NotNull + @Override + public List getSelectedDetails() { + List details = ContainerUtil.newArrayList(); + JBTable table = myUi.getTable(); + for (int row : table.getSelectedRows()) { + AbstractVcsLogTableModel model = (AbstractVcsLogTableModel)table.getModel(); + VcsFullCommitDetails commitDetails = model.getFullCommitDetails(row); + if (commitDetails == null) { + return ContainerUtil.emptyList(); + } + details.add(commitDetails); + } + return details; + } + @Override @Nullable public VcsFullCommitDetails getDetailsIfAvailable(@NotNull final Hash hash) { - return myLogManager.getDataHolder().getCommitDetailsGetter().getCommitDataIfAvailable(hash); + return myDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash); } @Nullable diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java index a046355dda27..81ddba796957 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java @@ -5,6 +5,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsLog; import com.intellij.vcs.log.VcsLogFilter; import com.intellij.vcs.log.VcsLogSettings; import com.intellij.vcs.log.compressedlist.UpdateRequest; @@ -16,6 +17,7 @@ import com.intellij.vcs.log.graph.elements.GraphElement; import com.intellij.vcs.log.graph.elements.Node; import com.intellij.vcs.log.graphmodel.FragmentManager; import com.intellij.vcs.log.graphmodel.GraphFragment; +import com.intellij.vcs.log.impl.VcsLogImpl; import com.intellij.vcs.log.printmodel.SelectController; import com.intellij.vcs.log.ui.frame.MainFrame; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; @@ -42,6 +44,7 @@ public class VcsLogUI { @NotNull private final VcsLogColorManager myColorManager; @NotNull private final VcsLogUiProperties myUiProperties; @NotNull private final VcsLogFilterer myFilterer; + @NotNull private final VcsLog myLog; @Nullable private GraphElement prevGraphElement; @@ -52,7 +55,8 @@ public class VcsLogUI { myColorManager = manager; myUiProperties = uiProperties; myFilterer = new VcsLogFilterer(logDataHolder, this); - myMainFrame = new MainFrame(myLogDataHolder, this, project, settings, uiProperties); + myLog = new VcsLogImpl(myLogDataHolder, this); + myMainFrame = new MainFrame(myLogDataHolder, this, project, settings, uiProperties, myLog); project.getMessageBus().connect(project).subscribe(VcsLogDataHolder.REFRESH_COMPLETED, new Runnable() { @Override public void run() { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index 83970bec324a..b01cdf3f7e79 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -8,6 +8,8 @@ import com.intellij.openapi.project.Project; import com.intellij.ui.JBColor; import com.intellij.ui.SeparatorComponent; import com.intellij.ui.SeparatorOrientation; +import com.intellij.vcs.log.VcsLog; +import com.intellij.vcs.log.VcsLogDataKeys; import com.intellij.vcs.log.VcsLogSettings; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VcsLogUiProperties; @@ -23,22 +25,23 @@ import java.awt.*; /** * @author erokhins */ -public class MainFrame { +public class MainFrame extends JPanel implements TypeSafeDataProvider { @NotNull private final VcsLogDataHolder myLogDataHolder; @NotNull private final VcsLogUI myUI; @NotNull private final Project myProject; - @NotNull private final JPanel myMainPanel; @NotNull private final ActiveSurface myActiveSurface; @NotNull private final VcsLogUiProperties myUiProperties; + @NotNull private final VcsLog myLog; @NotNull private final VcsLogFilterUi myFilterUi; public MainFrame(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUI vcsLogUI, @NotNull Project project, - @NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties) { + @NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLog log) { myLogDataHolder = logDataHolder; myUI = vcsLogUI; myProject = project; myUiProperties = uiProperties; + myLog = log; myActiveSurface = new ActiveSurface(logDataHolder, vcsLogUI, settings, project); myActiveSurface.setupDetailsSplitter(myUiProperties.isShowDetails()); @@ -49,10 +52,9 @@ public class MainFrame { toolbar.add(new SeparatorComponent(JBColor.LIGHT_GRAY, SeparatorOrientation.VERTICAL)); toolbar.add(createActionsToolbar()); - myMainPanel = new JPanel(); - myMainPanel.setLayout(new BorderLayout()); - myMainPanel.add(toolbar, BorderLayout.NORTH); - myMainPanel.add(myActiveSurface, BorderLayout.CENTER); + setLayout(new BorderLayout()); + add(toolbar, BorderLayout.NORTH); + add(myActiveSurface, BorderLayout.CENTER); } public VcsLogGraphTable getGraphTable() { @@ -120,7 +122,7 @@ public class MainFrame { } }; - refreshAction.registerShortcutOn(myMainPanel); + refreshAction.registerShortcutOn(this); DefaultActionGroup toolbarGroup = new DefaultActionGroup(hideBranchesAction, showBranchesAction, showFullPatchAction, refreshAction, showDetailsAction); @@ -129,7 +131,7 @@ public class MainFrame { } public JComponent getMainComponent() { - return myMainPanel; + return this; } public void refresh() { @@ -140,4 +142,10 @@ public class MainFrame { myActiveSurface.getBranchesPanel().setVisible(visible); } + @Override + public void calcData(DataKey key, DataSink sink) { + if (VcsLogDataKeys.VSC_LOG == key) { + sink.put(key, myLog); + } + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java index bee2ed6e0ef7..b2b803b9895b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java @@ -5,6 +5,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile; import com.intellij.util.text.DateFormatUtil; import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsShortCommitDetails; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,6 +36,9 @@ public abstract class AbstractVcsLogTableModel extends AbstractTableModel { @Nullable protected abstract VcsShortCommitDetails getShortDetails(int rowIndex); + @Nullable + public abstract VcsFullCommitDetails getFullCommitDetails(int row); + @NotNull @Override public final Object getValueAt(int rowIndex, int columnIndex) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index 8cd09242275d..9ddd0c5d3879 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -54,6 +54,13 @@ public class GraphTableModel extends AbstractVcsLogTableModel { return commitNode == null ? null : myDataHolder.getMiniDetailsGetter().getCommitData(commitNode); } + @Nullable + @Override + public VcsFullCommitDetails getFullCommitDetails(int row) { + Node node = myDataPack.getGraphModel().getGraph().getCommitNodeInRow(row); + return node == null ? null : myDataHolder.getCommitDetailsGetter().getCommitData(node); + } + @Override public void requestToLoadMore() { myDataHolder.showFullLog(EmptyRunnable.INSTANCE); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/NoGraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/NoGraphTableModel.java index f39d548edd3d..842ad73ce3ef 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/NoGraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/NoGraphTableModel.java @@ -41,6 +41,12 @@ public class NoGraphTableModel extends AbstractVcsLogTableModel { @Nullable @Override protected VcsShortCommitDetails getShortDetails(int rowIndex) { + return getFullCommitDetails(rowIndex); + } + + @Nullable + @Override + public VcsFullCommitDetails getFullCommitDetails(int rowIndex) { VcsFullCommitDetails commits = myCommits.get(rowIndex); if (commits == null) { LOG.error("Couldn't identify details for commit at " + rowIndex, new Attachment("loaded_commits", myCommits.toString())); diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index ad09f73663a6..79aa72185c32 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -79,6 +79,10 @@
+ + + +
diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index fec8b0b8c2c6..42c8f1030d10 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -939,4 +939,16 @@ public class GitUtil { final String output = diff.run(); return !output.trim().isEmpty(); } + + /** + * Report a warning that the given root has no associated GitRepositories. + */ + public static void noRepositoryForRoot(@NotNull Logger log, @NotNull VirtualFile root, @NotNull Project project) { + GitRepositoryManager repositoryManager = getRepositoryManager(project); + ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project); + List roots = Arrays.asList(vcsManager.getRootsUnderVcs(GitVcs.getInstance(project))); + log.warn(String.format("Repository not found for root: %s. All roots: %s, all repositories: %s", root, roots, + repositoryManager.getRepositories())); + } + } diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java new file mode 100644 index 000000000000..f0b4dee02555 --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java @@ -0,0 +1,85 @@ +/* + * 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 git4idea.branch; + +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.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.vcs.log.VcsFullCommitDetails; +import com.intellij.vcs.log.VcsLog; +import com.intellij.vcs.log.VcsLogDataKeys; +import git4idea.GitUtil; +import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; + +import java.util.Collections; +import java.util.List; + +public class GitCheckoutRevisionAction extends DumbAwareAction { + + private static final Logger LOG = Logger.getInstance(GitCheckoutRevisionAction.class); + + @Override + public void actionPerformed(AnActionEvent e) { + Data data = Data.collect(e); + if (!data.isValid()) { + return; + } + + List details = data.log.getSelectedDetails(); + if (details.size() != 1) { + return; + } + VcsFullCommitDetails commit = details.get(0); + + GitRepositoryManager repositoryManager = ServiceManager.getService(data.project, GitRepositoryManager.class); + final GitRepository repository = repositoryManager.getRepositoryForRoot(commit.getRoot()); + if (repository == null) { + GitUtil.noRepositoryForRoot(LOG, commit.getRoot(), data.project); + return; + } + GitBrancher brancher = ServiceManager.getService(data.project, GitBrancher.class); + brancher.checkout(commit.getHash().asString(), Collections.singletonList(repository), null); + } + + @Override + public void update(AnActionEvent e) { + Data data = Data.collect(e); + boolean enabled = data.isValid() && data.log.getSelectedCommits().size() == 1; + getTemplatePresentation().setVisible(data.isValid()); + getTemplatePresentation().setEnabled(enabled); + } + + private static class Data { + Project project; + VcsLog log; + + static Data collect(AnActionEvent e) { + Data data = new Data(); + data.project = e.getData(CommonDataKeys.PROJECT); + data.log = e.getData(VcsLogDataKeys.VSC_LOG); + return data; + } + + boolean isValid() { + return project != null && log != null; + } + } + +} diff --git a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java index ffa399e93299..705e86169847 100644 --- a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java +++ b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java @@ -26,11 +26,7 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.util.Function; 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.VcsLogObjectsFactory; -import com.intellij.vcs.log.impl.VcsLogImpl; +import com.intellij.vcs.log.*; import git4idea.GitLocalBranch; import git4idea.GitPlatformFacade; import git4idea.GitVcs; @@ -175,7 +171,7 @@ public class GitCherryPickAction extends DumbAwareAction { if (commits != null) { return convertHeavyCommitToFullDetails(commits, project); } - final VcsLog log = getVcsLog(project); + final VcsLog log = getVcsLog(e); if (log == null) { return null; } @@ -218,9 +214,8 @@ public class GitCherryPickAction extends DumbAwareAction { }); } - private static VcsLog getVcsLog(@NotNull Project project) { - VcsLog logService = ServiceManager.getService(project, VcsLog.class); - return logService != null && ((VcsLogImpl)logService).isReady() ? logService : null; + private static VcsLog getVcsLog(@NotNull AnActionEvent event) { + return event.getData(VcsLogDataKeys.VSC_LOG); } // TODO remove after removing the old Vcs Log implementation @@ -233,7 +228,7 @@ public class GitCherryPickAction extends DumbAwareAction { if (event.getProject() == null) { return null; } - VcsLog log = getVcsLog(event.getProject()); + VcsLog log = getVcsLog(event); if (log == null) { return null; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShowCommitInBrowserFromLogAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShowCommitInBrowserFromLogAction.java index b3b2e12982f5..7b3d9a1b8c3e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShowCommitInBrowserFromLogAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShowCommitInBrowserFromLogAction.java @@ -22,11 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import com.intellij.vcs.log.Hash; -import com.intellij.vcs.log.VcsLog; -import com.intellij.vcs.log.VcsLogObjectsFactory; -import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.impl.VcsLogImpl; +import com.intellij.vcs.log.*; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.history.browser.GitHeavyCommit; @@ -84,8 +80,8 @@ public class GithubShowCommitInBrowserFromLogAction extends GithubShowCommitInBr return factory.createShortDetails(factory.createHash(heavyCommit.getHash().getValue()), parents, heavyCommit.getAuthorTime(), heavyCommit.getRoot(), heavyCommit.getSubject(), heavyCommit.getAuthor()); } - VcsLog log = ServiceManager.getService(e.getProject(), VcsLog.class); - if (log == null || !((VcsLogImpl)log).isReady()) { + VcsLog log = e.getData(VcsLogDataKeys.VSC_LOG); + if (log == null) { return null; } List selectedCommits = log.getSelectedCommits(); From 32c3c359697bb837cfa4e1a380a823d811797709 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 19:26:35 +0400 Subject: [PATCH 16/21] [log] Add "New Branch", "New Tag" actions to the log + refactor * Extract GitLogSingleCommitAction - the common class for all Git actions on the log, which operate on a single commit. * Implement "New Branch" and "New Tag" actions. Use GitBrancher for the first, reuse the existing CreateNewTag for the latter. * Regroup actions in plugin.xml so that they form a single group which is then added to the Vcs group. It lets add a separator, and also makes the code more clear. --- plugins/git4idea/src/META-INF/plugin.xml | 23 ++++++++--- .../actions/GitCheckoutRevisionAction.java | 34 +++++++++++++++ .../actions/GitCreateNewBranchAction.java | 41 +++++++++++++++++++ .../git4idea/actions/GitCreateTagAction.java | 31 ++++++++++++++ .../GitLogSingleCommitAction.java} | 17 +++++--- 5 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 plugins/git4idea/src/git4idea/actions/GitCheckoutRevisionAction.java create mode 100644 plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java create mode 100644 plugins/git4idea/src/git4idea/actions/GitCreateTagAction.java rename plugins/git4idea/src/git4idea/{branch/GitCheckoutRevisionAction.java => actions/GitLogSingleCommitAction.java} (85%) diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 79aa72185c32..da7d14a9117a 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -75,14 +75,27 @@ - + + + + + + + + + + + + + + + - + - - - diff --git a/plugins/git4idea/src/git4idea/actions/GitCheckoutRevisionAction.java b/plugins/git4idea/src/git4idea/actions/GitCheckoutRevisionAction.java new file mode 100644 index 000000000000..fc2451820fee --- /dev/null +++ b/plugins/git4idea/src/git4idea/actions/GitCheckoutRevisionAction.java @@ -0,0 +1,34 @@ +/* + * 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 git4idea.actions; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.vcs.log.VcsFullCommitDetails; +import git4idea.branch.GitBrancher; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +public class GitCheckoutRevisionAction extends GitLogSingleCommitAction { + + @Override + protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) { + GitBrancher brancher = ServiceManager.getService(repository.getProject(), GitBrancher.class); + brancher.checkout(commit.getHash().asString(), Collections.singletonList(repository), null); + } + +} diff --git a/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java b/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java new file mode 100644 index 000000000000..e53f243608fd --- /dev/null +++ b/plugins/git4idea/src/git4idea/actions/GitCreateNewBranchAction.java @@ -0,0 +1,41 @@ +/* + * 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 git4idea.actions; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.vcs.log.VcsFullCommitDetails; +import git4idea.branch.GitBranchUtil; +import git4idea.branch.GitBrancher; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +public class GitCreateNewBranchAction extends GitLogSingleCommitAction { + + @Override + protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) { + Project project = repository.getProject(); + String reference = commit.getHash().asString(); + final String name = GitBranchUtil.getNewBranchNameFromUser(project, Collections.singleton(repository), + "Checkout New Branch From " + reference); + if (name != null) { + GitBrancher brancher = ServiceManager.getService(project, GitBrancher.class); + brancher.checkoutNewBranchStartingFrom(name, reference, Collections.singletonList(repository), null); + } + } +} diff --git a/plugins/git4idea/src/git4idea/actions/GitCreateTagAction.java b/plugins/git4idea/src/git4idea/actions/GitCreateTagAction.java new file mode 100644 index 000000000000..344c236b3f37 --- /dev/null +++ b/plugins/git4idea/src/git4idea/actions/GitCreateTagAction.java @@ -0,0 +1,31 @@ +/* + * 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 git4idea.actions; + +import com.intellij.vcs.log.VcsFullCommitDetails; +import git4idea.history.wholeTree.GitCreateNewTag; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +public class GitCreateTagAction extends GitLogSingleCommitAction { + + @Override + protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) { + String reference = commit.getHash().asString(); + new GitCreateNewTag(repository.getProject(), repository, reference, null).execute(); + } + +} diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java b/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java similarity index 85% rename from plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java rename to plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java index f0b4dee02555..364b1f58b15e 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutRevisionAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package git4idea.branch; +package git4idea.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -27,13 +27,18 @@ import com.intellij.vcs.log.VcsLogDataKeys; import git4idea.GitUtil; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; +import org.jetbrains.annotations.NotNull; -import java.util.Collections; import java.util.List; -public class GitCheckoutRevisionAction extends DumbAwareAction { +/** + * @author Kirill Likhodedov + */ +public abstract class GitLogSingleCommitAction extends DumbAwareAction { - private static final Logger LOG = Logger.getInstance(GitCheckoutRevisionAction.class); + private static final Logger LOG = Logger.getInstance(GitLogSingleCommitAction.class); + + protected abstract void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit); @Override public void actionPerformed(AnActionEvent e) { @@ -54,8 +59,8 @@ public class GitCheckoutRevisionAction extends DumbAwareAction { GitUtil.noRepositoryForRoot(LOG, commit.getRoot(), data.project); return; } - GitBrancher brancher = ServiceManager.getService(data.project, GitBrancher.class); - brancher.checkout(commit.getHash().asString(), Collections.singletonList(repository), null); + + actionPerformed(repository, commit); } @Override From 279e5b6f398bb31a7e52f28648bcf494a48c45fa Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 19:31:31 +0400 Subject: [PATCH 17/21] [log] Add "Create Patch" action Reuse CreatePatchFromChangesAction with update() method overridden in the same matter, as it is done for GitLogUi: to respect the CHANGES data key. --- .../vcs-log/impl/src/META-INF/vcs-log.xml | 2 ++ .../vcs/log/ui/VcsLogCreatePatchAction.java | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogCreatePatchAction.java diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index 9e7f1114570d..377cc00e3f89 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -17,6 +17,7 @@ + @@ -26,6 +27,7 @@ + diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogCreatePatchAction.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogCreatePatchAction.java new file mode 100644 index 000000000000..08a713e99491 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogCreatePatchAction.java @@ -0,0 +1,31 @@ +/* + * 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.vcs.VcsDataKeys; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.actions.CreatePatchFromChangesAction; + +public class VcsLogCreatePatchAction extends CreatePatchFromChangesAction { + + @Override + public void update(AnActionEvent e) { + Change[] changes; + e.getPresentation().setEnabled((changes = e.getData(VcsDataKeys.CHANGES)) != null && changes.length > 0); + } + +} From ec630c64fb0db52db815ea6bdf8ba57168837b92 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 19:40:58 +0400 Subject: [PATCH 18/21] [log] "Revert" and other actions above the changes browser Just use RepositoryChangesBrowser instead of the simple ChangesBrowser. --- .../impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java index ebbe543da928..ff68984b8c64 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/ActiveSurface.java @@ -8,6 +8,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.committed.RepositoryChangesBrowser; import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.components.JBLoadingPanel; @@ -51,8 +52,7 @@ public class ActiveSurface extends JPanel implements TypeSafeDataProvider { myDetailsPanel = new DetailsPanel(logDataHolder, myGraphTable, vcsLogUI.getColorManager()); - final ChangesBrowser changesBrowser = new ChangesBrowser(project, null, Collections.emptyList(), null, false, false, null, - ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); + final ChangesBrowser changesBrowser = new RepositoryChangesBrowser(project, null, Collections.emptyList(), null); changesBrowser.getDiffAction().registerCustomShortcutSet(CommonShortcuts.getDiff(), myGraphTable); setDefaultEmptyText(changesBrowser); From 191576451b4c600dc688ac0baaa4307563b34be8 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 20:19:48 +0400 Subject: [PATCH 19/21] [log] Details panel: hide empty space if there are no refs on a commit --- .../impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index e092be5fc456..af427ac85ac9 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -190,6 +190,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { void setRefs(@NotNull List refs) { myRefs = refs; + setVisible(!myRefs.isEmpty()); repaint(); } } From 324a0f64921fc5f82db27af5f58a9f12030409fa Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 20:23:37 +0400 Subject: [PATCH 20/21] [log] Details panel: display author/commit date --- .../src/com/intellij/vcs/log/ui/frame/DetailsPanel.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index af427ac85ac9..f63a3633b34a 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -8,6 +8,7 @@ import com.intellij.ui.components.JBLoadingPanel; import com.intellij.ui.components.JBTextField; import com.intellij.ui.components.labels.LinkLabel; import com.intellij.ui.components.labels.LinkListener; +import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.GridBag; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; @@ -160,9 +161,10 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myHashLabel.setText(commit.getHash().toShortString()); myCommitMessage.setText(commit.getFullMessage()); - String authorText = commit.getAuthorName(); + String authorText = commit.getAuthorName() + " at " + DateFormatUtil.formatDateTime(commit.getAuthorTime()); if (!commit.getAuthorName().equals(commit.getCommitterName()) || !commit.getAuthorEmail().equals(commit.getCommitterEmail())) { - authorText += " (committed by " + commit.getCommitterName() + ")"; + authorText += " (committed by " + commit.getCommitterName() + + " at " + DateFormatUtil.formatDateTime(commit.getCommitTime()) + ")"; } myAuthor.setText(authorText); } From 956ede2c214296bcff6d108cbcadc452931cf3c7 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sun, 3 Nov 2013 21:32:23 +0400 Subject: [PATCH 21/21] [log] IDEA-115676 Don't scroll details panel to bottom on text update --- .../impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index f63a3633b34a..cc26a84aef29 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -160,6 +160,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { else { myHashLabel.setText(commit.getHash().toShortString()); myCommitMessage.setText(commit.getFullMessage()); + myCommitMessage.setCaretPosition(0); String authorText = commit.getAuthorName() + " at " + DateFormatUtil.formatDateTime(commit.getAuthorTime()); if (!commit.getAuthorName().equals(commit.getCommitterName()) || !commit.getAuthorEmail().equals(commit.getCommitterEmail())) {