Merge remote branch 'origin/master'

This commit is contained in:
Dmitry Jemerov
2011-10-21 14:31:13 +02:00
65 changed files with 1726 additions and 534 deletions
@@ -292,7 +292,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
}
console.setActions(consoleActions, ActionPlaces.DEBUGGER_TOOLBAR, myConsole.getPreferredFocusableComponent());
initLogConsoles(myConfiguration, myRunContentDescriptor.getProcessHandler());
initLogConsoles(myConfiguration, myRunContentDescriptor.getProcessHandler(), myConsole);
DefaultActionGroup group = new DefaultActionGroup();
final Executor executor = DefaultDebugExecutor.getDebugExecutorInstance();
@@ -161,7 +161,8 @@ public class JavaInheritorsGetter extends CompletionProvider<CompletionParameter
if (methodCallExpression != null &&
ArrayUtil.find(methodCallExpression.getArgumentList().getExpressions(), newExpression) > -1) {
final JavaResolveResult resolveResult = methodCallExpression.resolveMethodGenerics();
return PsiUtil.getApplicabilityLevel((PsiMethod)resolveResult.getElement(), resolveResult.getSubstitutor(), types, PsiUtil.getLanguageLevel(originalPosition))
PsiMethod method = (PsiMethod)resolveResult.getElement();
return method == null || PsiUtil.getApplicabilityLevel(method, resolveResult.getSubstitutor(), types, PsiUtil.getLanguageLevel(originalPosition))
!= MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
}
}
@@ -437,8 +437,8 @@ public final class PsiUtil extends PsiUtilCore {
return getApplicabilityLevel(method, substitutorForMethod, argList.getExpressionTypes(), getLanguageLevel(argList));
}
public static int getApplicabilityLevel(final PsiMethod method, final PsiSubstitutor substitutorForMethod, @NotNull final PsiType[] args,
final LanguageLevel languageLevel) {
public static int getApplicabilityLevel(@NotNull final PsiMethod method, @NotNull final PsiSubstitutor substitutorForMethod, @NotNull final PsiType[] args,
@NotNull final LanguageLevel languageLevel) {
final PsiParameter[] parms = method.getParameterList().getParameters();
if (args.length < parms.length - 1) return ApplicabilityLevel.NOT_APPLICABLE;
@@ -472,7 +472,7 @@ public final class PsiUtil extends PsiUtilCore {
}
private static boolean areFirstArgumentsApplicable(final PsiType[] args, final PsiParameter[] parms, final LanguageLevel languageLevel,
final PsiSubstitutor substitutorForMethod) {
@NotNull final PsiSubstitutor substitutorForMethod) {
for (int i = 0; i < parms.length - 1; i++) {
final PsiType type = args[i];
@@ -488,7 +488,7 @@ public final class PsiUtil extends PsiUtilCore {
private static PsiType getParameterType(final PsiParameter parameter,
final LanguageLevel languageLevel,
final PsiSubstitutor substitutor) {
@NotNull final PsiSubstitutor substitutor) {
PsiType parmType = parameter.getType();
if (parmType instanceof PsiClassType) {
parmType = ((PsiClassType)parmType).setLanguageLevel(languageLevel);
@@ -68,7 +68,8 @@ public class PsiElementResolveResult implements ResolveResult{
@NonNls
public String toString() {
return "PsiElementResolveResult: " + (myElement instanceof PsiNamedElement ? ((PsiNamedElement)myElement).getName() : myElement.getText());
return "PsiElementResolveResult with " + myElement.getClass() + ": " +
(myElement instanceof PsiNamedElement ? ((PsiNamedElement)myElement).getName() : myElement.getText());
}
public static ResolveResult[] createResults(@Nullable Collection<? extends PsiElement> elements) {
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Collections;
import java.util.Set;
@@ -129,6 +130,18 @@ public class LookupElementBuilder extends LookupElement {
myAllLookupStrings, caseSensitive);
}
public LookupElementBuilder setItemTextForeground(@NotNull Color itemTextForeground) {
final LookupElementPresentation presentation = copyPresentation();
presentation.setItemTextForeground(itemTextForeground);
return new LookupElementBuilder(myLookupString, myObject, myInsertHandler, null, presentation, myAllLookupStrings, myCaseSensitive);
}
public LookupElementBuilder setItemTextUnderlined(boolean underlined) {
final LookupElementPresentation presentation = copyPresentation();
presentation.setItemTextUnderlined(underlined);
return new LookupElementBuilder(myLookupString, myObject, myInsertHandler, null, presentation, myAllLookupStrings, myCaseSensitive);
}
public LookupElementBuilder setTypeText(@Nullable String typeText) {
return setTypeText(typeText, false);
}
@@ -162,7 +175,7 @@ public class LookupElementBuilder extends LookupElement {
public LookupElementBuilder setStrikeout() {
return setStrikeout(true);
}
public LookupElementBuilder setStrikeout(boolean strikeout) {
final LookupElementPresentation presentation = copyPresentation();
presentation.setStrikeout(strikeout);
@@ -228,7 +241,7 @@ public class LookupElementBuilder extends LookupElement {
: myInsertHandler != insertHandler) return false;
if (!myLookupString.equals(that.myLookupString)) return false;
if (!myObject.equals(that.myObject)) return false;
final LookupElementRenderer<LookupElement> renderer = that.myRenderer;
if (myRenderer != null && renderer != null ? !myRenderer.getClass().equals(renderer.getClass()) : myRenderer != renderer) return false;
@@ -33,6 +33,7 @@ public class LookupElementPresentation {
private boolean myStrikeout;
private boolean myTailGrayed;
private Color myTailForeground;
private Color myItemTextForeground = Color.black;
private boolean myItemTextBold;
private boolean myItemTextUnderlined;
private boolean myTypeGrayed;
@@ -136,6 +137,14 @@ public class LookupElementPresentation {
myItemTextUnderlined = itemTextUnderlined;
}
@NotNull public Color getItemTextForeground() {
return myItemTextForeground;
}
public void setItemTextForeground(@NotNull Color itemTextForeground) {
myItemTextForeground = itemTextForeground;
}
public void copyFrom(@NotNull LookupElementPresentation presentation) {
myIcon = presentation.myIcon;
myTypeIcon = presentation.myTypeIcon;
@@ -147,6 +156,8 @@ public class LookupElementPresentation {
myTailForeground = presentation.myTailForeground;
myItemTextBold = presentation.myItemTextBold;
myTypeGrayed = presentation.myTypeGrayed;
myItemTextUnderlined = presentation.myItemTextUnderlined;
myItemTextForeground = presentation.myItemTextForeground;
}
public boolean isTypeGrayed() {
@@ -41,9 +41,16 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements
private ArrayList<LogFileOptions> myLogFiles = new ArrayList<LogFileOptions>();
private ArrayList<PredefinedLogFile> myPredefinedLogFiles = new ArrayList<PredefinedLogFile>();
@NonNls private static final String LOG_FILE = "log_file";
@NonNls private static final String PREDEFINED_LOG_FILE_ELEMENT = "predefined_log_file";
@NonNls private static final String FILE_OUTPUT = "output_file";
@NonNls private static final String SAVE = "is_save";
@NonNls private static final String OUTPUT_FILE = "path";
private final Icon myIcon;
private boolean mySaveOutput = false;
private String myFileOutputPath = null;
protected RunConfigurationBase(final Project project, final ConfigurationFactory factory, final String name) {
myProject = project;
@@ -97,6 +104,8 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements
final RunConfigurationBase runConfiguration = (RunConfigurationBase)super.clone();
runConfiguration.myLogFiles = new ArrayList<LogFileOptions>(myLogFiles);
runConfiguration.myPredefinedLogFiles = new ArrayList<PredefinedLogFile>(myPredefinedLogFiles);
runConfiguration.myFileOutputPath = myFileOutputPath;
runConfiguration.mySaveOutput = mySaveOutput;
copyCopyableDataTo(runConfiguration);
return runConfiguration;
}
@@ -167,6 +176,12 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements
logFile.readExternal((Element)fileElement);
myPredefinedLogFiles.add(logFile);
}
final Element fileOutputElement = element.getChild(FILE_OUTPUT);
if (fileOutputElement != null) {
myFileOutputPath = fileOutputElement.getAttributeValue(OUTPUT_FILE);
final String isSave = fileOutputElement.getAttributeValue(SAVE);
mySaveOutput = isSave != null && Boolean.parseBoolean(isSave);
}
}
public void writeExternal(Element element) throws WriteExternalException {
@@ -180,6 +195,34 @@ public abstract class RunConfigurationBase extends UserDataHolderBase implements
predefinedLogFile.writeExternal(fileElement);
element.addContent(fileElement);
}
final Element fileOutputPathElement = new Element(FILE_OUTPUT);
if (myFileOutputPath != null) {
fileOutputPathElement.setAttribute(OUTPUT_FILE, myFileOutputPath);
}
fileOutputPathElement.setAttribute(SAVE, String.valueOf(mySaveOutput));
if (myFileOutputPath != null || mySaveOutput) {
element.addContent(fileOutputPathElement);
}
}
public boolean isSaveOutputToFile() {
return mySaveOutput;
}
public void setSaveOutputToFile(boolean redirectOutput) {
mySaveOutput = redirectOutput;
}
public String getOutputFilePath() {
return myFileOutputPath;
}
public void setFileOutputPath(String fileOutputPath) {
myFileOutputPath = fileOutputPath;
}
public boolean collectOutputFromProcessHandler() {
return true;
}
public boolean excludeCompileBeforeLaunchOption() {
@@ -49,7 +49,7 @@ public class LookupCellRenderer implements ListCellRenderer {
private final FontMetrics myBoldMetrics;
public static final Color BACKGROUND_COLOR = new Color(235, 244, 254);
static final Color FOREGROUND_COLOR = Color.black;
private static final Color FOREGROUND_COLOR = Color.black;
private static final Color GRAYED_FOREGROUND_COLOR = new Color(160, 160, 160);
private static final Color SELECTED_BACKGROUND_COLOR = new Color(0, 82, 164);
private static final Color SELECTED_FOREGROUND_COLOR = Color.white;
@@ -126,7 +126,7 @@ public class LookupCellRenderer implements ListCellRenderer {
myNameComponent.clear();
myNameComponent.setIcon(augmentIcon(presentation.getIcon(), myEmptyIcon));
myNameComponent.setBackground(background);
allowedWidth -= setItemTextLabel(item, foreground, isSelected, presentation, allowedWidth);
allowedWidth -= setItemTextLabel(item, presentation.getItemTextForeground(), isSelected, presentation, allowedWidth);
myTypeLabel.clear();
if (allowedWidth > 0) {
@@ -24,7 +24,6 @@ import com.intellij.codeInsight.completion.OffsetMap;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.template.*;
import com.intellij.lang.ASTNode;
import com.intellij.lang.LanguageLiteralEscapers;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.Disposable;
@@ -64,10 +63,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.*;
import java.util.List;
import java.util.Map;
public class TemplateState implements Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.impl.TemplateState");
@@ -920,8 +917,10 @@ public class TemplateState implements Disposable {
}
private void initTabStopHighlighters() {
final Set<String> vars = new HashSet<String>();
for (int i = 0; i < myTemplate.getVariableCount(); i++) {
String variableName = myTemplate.getVariableNameAt(i);
if (!vars.add(variableName)) continue;
int segmentNumber = myTemplate.getVariableSegmentNumber(variableName);
if (segmentNumber < 0) continue;
RangeHighlighter segmentHighlighter = getSegmentHighlighter(segmentNumber, false, false);
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.diagnostic.logging.LogConfigurationPanel">
<grid id="57687" binding="myWholePanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="57687" binding="myWholePanel" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="25" y="74" width="392" height="210"/>
@@ -14,7 +14,7 @@
<grid id="93252" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="2" bottom="0" right="2"/>
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="3" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -52,12 +52,32 @@
</grid>
<grid id="faa06" binding="myScrollPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
<component id="37d5" class="com.intellij.ui.components.JBCheckBox" binding="myRedirectOutputCb" default-binding="true">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<margin top="7" left="3" bottom="2" right="3"/>
<text value="&amp;Save console output to file:"/>
</properties>
</component>
<hspacer id="9d463">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<component id="c07c6" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myOutputFile">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="1" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
</children>
</grid>
</form>
@@ -20,13 +20,18 @@ import com.intellij.diagnostic.DiagnosticBundle;
import com.intellij.execution.configurations.LogFileOptions;
import com.intellij.execution.configurations.PredefinedLogFile;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.BooleanTableCellRenderer;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.TableUtil;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.table.TableView;
import com.intellij.util.ui.AbstractTableCellEditor;
import com.intellij.util.ui.CellEditorComponentWithBrowseButton;
@@ -58,6 +63,8 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
private JButton myRemoveButton;
private JPanel myScrollPanel;
private JButton myEditButton;
private JBCheckBox myRedirectOutputCb;
private TextFieldWithBrowseButton myOutputFile;
private final Map<LogFileOptions, PredefinedLogFile> myLog2Predefined = new HashMap<LogFileOptions, PredefinedLogFile>();
private final List<PredefinedLogFile> myUnresolvedPredefined = new ArrayList<PredefinedLogFile>();
@@ -144,6 +151,15 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
myScrollPanel.add(scrollPane, BorderLayout.CENTER);
myWholePanel.setPreferredSize(new Dimension(-1, 150));
myOutputFile.addBrowseFolderListener("Choose File to Save Console Output", "Console output would be saved to the specified file", null,
FileChooserDescriptorFactory.createSingleFileOrFolderDescriptor(),
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
myRedirectOutputCb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myOutputFile.setEnabled(myRedirectOutputCb.isSelected());
}
});
}
private void setUpColumnWidth(final JTableHeader tableHeader, final int preferredWidth, int columnIdx) {
@@ -220,6 +236,11 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
}
}
myModel.setItems(list);
final boolean redirectOutputToFile = configuration.isSaveOutputToFile();
myRedirectOutputCb.setSelected(redirectOutputToFile);
final String fileOutputPath = configuration.getOutputFilePath();
myOutputFile.setText(fileOutputPath != null ? FileUtil.toSystemDependentName(fileOutputPath) : "");
myOutputFile.setEnabled(redirectOutputToFile);
}
protected void applyEditorTo(final RunConfigurationBase configuration) throws ConfigurationException {
@@ -244,7 +265,10 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
}
for (PredefinedLogFile logFile : myUnresolvedPredefined) {
configuration.addPredefinedLogFile(logFile);
}
}
final String text = myOutputFile.getText();
configuration.setFileOutputPath(StringUtil.isEmpty(text) ? null : FileUtil.toSystemIndependentName(text));
configuration.setSaveOutputToFile(myRedirectOutputCb.isSelected());
}
@NotNull
@@ -20,6 +20,7 @@ import com.intellij.execution.configurations.LogFileOptions;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
@@ -35,6 +36,8 @@ import java.util.*;
* Date: 01-Feb-2006
*/
public class LogFilesManager implements Disposable {
public static final Logger LOG = Logger.getInstance("#" + LogFilesManager.class.getName());
private static final int UPDATE_INTERVAL = 500;
private final Map<LogFileOptions, Set<String>> myLogFileManagerMap = new LinkedHashMap<LogFileOptions, Set<String>>();
@@ -0,0 +1,125 @@
/*
* Copyright 2000-2011 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.diagnostic.logging;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.filters.Filter;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* User: anna
* Date: 10/20/11
*/
public class OutputFileUtil {
private static final String CONSOLE_OUTPUT_FILE_MESSAGE = "Console output is saving to: ";
private OutputFileUtil() {
}
public static void attachDumpListener(final RunConfigurationBase base, final ProcessHandler startedProcess, ExecutionConsole console) {
if (base.isSaveOutputToFile()) {
final String outputFilePath = base.getOutputFilePath();
if (outputFilePath != null) {
final String filePath = FileUtil.toSystemDependentName(outputFilePath);
startedProcess.addProcessListener(new ProcessAdapter() {
private PrintStream myOutput;
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
if (base.collectOutputFromProcessHandler() && myOutput != null && outputType != ProcessOutputTypes.SYSTEM) {
myOutput.print(event.getText());
}
}
@Override
public void startNotified(ProcessEvent event) {
try {
myOutput = new PrintStream(new FileOutputStream(new File(filePath)));
}
catch (FileNotFoundException ignored) {
}
startedProcess.notifyTextAvailable(CONSOLE_OUTPUT_FILE_MESSAGE + filePath + "\n", ProcessOutputTypes.SYSTEM);
}
@Override
public void processTerminated(ProcessEvent event) {
startedProcess.removeProcessListener(this);
if (myOutput != null) {
myOutput.close();
}
}
});
if (console instanceof ConsoleView) {
((ConsoleView)console).addMessageFilter(new ShowOutputFileFilter());
}
}
}
}
private static class ShowOutputFileFilter implements Filter {
@Override
public Result applyFilter(String line, int entireLength) {
if (line.startsWith(CONSOLE_OUTPUT_FILE_MESSAGE)) {
final String filePath = StringUtil.trimEnd(line.substring(CONSOLE_OUTPUT_FILE_MESSAGE.length()), "\n");
return new Result(entireLength - filePath.length() - 1, entireLength, new HyperlinkInfo() {
@Override
public void navigate(final Project project) {
final VirtualFile file =
ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
@Nullable
@Override
public VirtualFile compute() {
return LocalFileSystem.getInstance().refreshAndFindFileByPath(FileUtil.toSystemIndependentName(filePath));
}
});
if (file != null) {
file.refresh(false, false);
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, file), true);
}
});
}
}
});
}
return null;
}
}
}
@@ -15,10 +15,7 @@
*/
package com.intellij.execution.runners;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
import com.intellij.diagnostic.logging.LogConsoleImpl;
import com.intellij.diagnostic.logging.LogConsoleManager;
import com.intellij.diagnostic.logging.LogFilesManager;
import com.intellij.diagnostic.logging.*;
import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
@@ -140,6 +137,7 @@ public class RunContentBuilder implements LogConsoleManager, Disposable {
}
if (profile instanceof RunConfigurationBase) {
myManager.initLogConsoles((RunConfigurationBase)profile, myExecutionResult.getProcessHandler());
OutputFileUtil.attachDumpListener((RunConfigurationBase)profile, myExecutionResult.getProcessHandler(), console);
}
}
MyRunContentDescriptor contentDescriptor = new MyRunContentDescriptor(profile, myExecutionResult, myReuseProhibited, myUi.getComponent(), this);
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.util.ui.update.Activatable;
import com.intellij.util.ui.update.UiNotifyConnector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -100,7 +101,7 @@ public class Alarm implements Disposable {
_addRequest(request, delay, ModalityState.stateForComponent(myActivationComponent));
}
public void addRequest(final Runnable request, int delayMillis, final ModalityState modalityState) {
public void addRequest(final Runnable request, int delayMillis, @Nullable final ModalityState modalityState) {
LOG.assertTrue(myThreadToUse == ThreadToUse.SWING_THREAD);
_addRequest(request, delayMillis, modalityState);
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.*;
@@ -30,6 +31,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.BalloonImpl;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PairFunction;
@@ -179,9 +181,6 @@ public class NotificationsManagerImpl extends NotificationsManager implements No
(toolWindowId == null || project == null || !Arrays.asList(ToolWindowManager.getInstance(project).getToolWindowIds()).contains(toolWindowId))) {
type = NotificationDisplayType.BALLOON;
}
if (type == NotificationDisplayType.BALLOON && ProjectManager.getInstance().getOpenProjects().length == 0) {
type = NotificationDisplayType.STICKY_BALLOON;
}
switch (type) {
case NONE:
@@ -219,10 +218,23 @@ public class NotificationsManagerImpl extends NotificationsManager implements No
Window window = findWindowForBalloon(project);
if (window instanceof IdeFrameImpl) {
boolean sticky = NotificationDisplayType.STICKY_BALLOON == displayType;
Balloon balloon = createBalloon(notification, false, !sticky, !sticky);
final ProjectManager projectManager = ProjectManager.getInstance();
boolean noProjects = projectManager.getOpenProjects().length == 0;
boolean sticky = NotificationDisplayType.STICKY_BALLOON == displayType || noProjects;
final Balloon balloon = createBalloon(notification, false, !sticky, !sticky);
Disposer.register(project != null ? project : ApplicationManager.getApplication(), balloon);
((IdeFrameImpl)window).getBalloonLayout().add(balloon);
if (noProjects && NotificationDisplayType.BALLOON == displayType) {
projectManager.addProjectManagerListener(new ProjectManagerAdapter() {
@Override
public void projectOpened(Project project) {
projectManager.removeProjectManagerListener(this);
if (!balloon.isDisposed()) {
((BalloonImpl)balloon).startFadeoutTimer(300);
}
}
});
}
}
}
@@ -569,7 +569,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
myFadedIn = true;
startFadeoutTimer();
startFadeoutTimer((int)BalloonImpl.this.myFadeoutTime);
}
else {
layeredPane.remove(myComp);
@@ -592,14 +592,13 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
myAnimator.resume();
}
private void startFadeoutTimer() {
if (myFadeoutTime > 0) {
Alarm fadeoutAlarm = new Alarm(this);
fadeoutAlarm.addRequest(new Runnable() {
public void startFadeoutTimer(final int fadeoutTime) {
if (fadeoutTime > 0) {
new Alarm(this).addRequest(new Runnable() {
public void run() {
hide();
}
}, (int)myFadeoutTime, null);
}, fadeoutTime, null);
}
}
@@ -112,6 +112,7 @@ public class SMTestRunnerResultsForm extends TestResultsPanel implements TestFra
//Create tests common suite root
//noinspection HardCodedStringLiteral
myTestsRootNode = new SMTestProxy.SMRootTestProxy();
//todo myTestsRootNode.setOutputFilePath(runConfiguration.getOutputFilePath());
// Fire selection changed and move focus on SHIFT+ENTER
//TODO[romeo] improve
@@ -40,6 +40,7 @@ public class CompositePrintable implements Printable, Disposable {
private final PrintablesWrapper myWrapper = new PrintablesWrapper();
protected int myExceptionMark;
private int myCurrentSize = 0;
private String myOutputFile = null;
private static final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
public void flush() {
@@ -119,6 +120,10 @@ public class CompositePrintable implements Printable, Disposable {
myExceptionMark = exceptionMark;
}
public void setOutputFilePath(String outputFile) {
myOutputFile = outputFile;
}
private static final Logger LOG = Logger.getInstance("#" + PrintablesWrapper.class.getName());
private class PrintablesWrapper {
@@ -167,6 +172,41 @@ public class CompositePrintable implements Printable, Disposable {
printable.printOn(myPrinter);
}
myPrinter.close();
if (myOutputFile != null) {
PrintStream printStream = null;
try {
printStream = new PrintStream(new FileOutputStream(new File(myOutputFile), true));
final PrintStream finalPrintStream = printStream;
for (Printable currentPrintable : currentPrintables) {
currentPrintable.printOn(new Printer() {
@Override
public void print(String text, ConsoleViewContentType contentType) {
if (contentType != ConsoleViewContentType.SYSTEM_OUTPUT) {
finalPrintStream.print(text);
}
}
@Override
public void printHyperlink(String text, HyperlinkInfo info) {
finalPrintStream.print(text);
}
@Override
public void onNewAvailable(@NotNull Printable printable) {}
@Override
public void mark() {}
});
}
}
catch (FileNotFoundException e) {
LOG.error(e);
}
finally {
if (printStream != null) {
printStream.close();
}
}
}
}
};
invokeInAlarm(request, ApplicationManager.getApplication().isUnitTestMode());
@@ -55,7 +55,7 @@ public abstract class GroupingMerger<T, S> {
// for group headers to not be left alone without its group
if (idx > 0 && (! filter(first.get(idx - 1)))) {
-- idx;
if (idx > 0) --idx;
//if (idx > 0) --idx; // todo whether its ok
}
final ReadonlyList<T> remergePart = first.cut(idx);
if (idx > 0) {
@@ -67,7 +67,7 @@ public abstract class GroupingMerger<T, S> {
public void consume(T t, Integer integer) {
doForGroup(t, first);
first.add(t);
int was = integer + finalIdx + 1;
int was = integer + finalIdx;
//System.out.println("was " + integer + "became " + (first.getSize() - 1));
oldBecame(was, first.getSize() - 1);
}
@@ -78,7 +78,6 @@ public abstract class GroupingMerger<T, S> {
final T wrapped = wrapItem(t);
first.add(wrapped);
// todo should more effectively compute size!!!
afterConsumed(wrapped, first.getSize() - 1);
}
});
@@ -87,14 +86,12 @@ public abstract class GroupingMerger<T, S> {
private void doForGroup(T t, StepList<T> first) {
final S newGroup = getGroup(t);
if (! Comparing.equal(newGroup, myCurrentGroup)) {
if (newGroup != null && ! Comparing.equal(newGroup, myCurrentGroup)) {
first.add(wrapGroup(newGroup, t));
myCurrentGroup = newGroup;
}
}
// todo here I doubt very much abt comparator usage, but seems like it doesn't reorder items from same repo
// todo which is essential
public void merge(final ReadonlyList<T> one,
final ReadonlyList<T> two,
final Comparator<T> comparator,
@@ -80,9 +80,10 @@ public abstract class DebuggerSessionTabBase implements DebuggerLogConsoleManage
}
}
protected void initLogConsoles(final RunProfile runConfiguration, final ProcessHandler processHandler) {
protected void initLogConsoles(final RunProfile runConfiguration, final ProcessHandler processHandler, ExecutionConsole console) {
if (runConfiguration instanceof RunConfigurationBase) {
myManager.initLogConsoles((RunConfigurationBase)runConfiguration, processHandler);
OutputFileUtil.attachDumpListener((RunConfigurationBase)runConfiguration, processHandler, console);
}
}
@@ -198,7 +198,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
if (env != null) {
final RunProfile runConfiguration = env.getRunProfile();
registerFileMatcher(runConfiguration);
initLogConsoles(runConfiguration, myRunContentDescriptor.getProcessHandler());
initLogConsoles(runConfiguration, myRunContentDescriptor.getProcessHandler(), myConsole);
}
rebuildViews();
@@ -18,6 +18,7 @@
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.intellij.testAssistant.TestDataLineMarkerProvider"/>
<fileEditorProvider implementation="com.intellij.testAssistant.TestDataGroupEditorProvider"/>
<gotoRelatedProvider implementation="com.intellij.testAssistant.TestDataAsRelatedFileProvider"/>
<gotoRelatedProvider implementation="com.intellij.testAssistant.GotoTestRelatedProvider"/>
</extensions>
<project-components>
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2011 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.testAssistant;
import com.intellij.navigation.GotoRelatedItem;
import com.intellij.navigation.GotoRelatedProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class GotoTestRelatedProvider extends GotoRelatedProvider {
@NotNull
@Override
public List<? extends GotoRelatedItem> getItems(@NotNull DataContext context) {
final VirtualFile file = PlatformDataKeys.VIRTUAL_FILE.getData(context);
final Project project = PlatformDataKeys.PROJECT.getData(context);
if (file != null && project != null) {
final String ext = file.getExtension();
String name = file.getNameWithoutExtension();
final String filename;
if (ext != null && ext.length() > 0 && name.length() > 0) {
if (name.endsWith("Test") && name.length() > 4) {
filename = name.substring(0, name.length() - 4) + "." + ext;
} else {
filename = name + "Test." + ext;
}
final PsiFile[] files = FilenameIndex.getFilesByName(project, filename, GlobalSearchScope.allScope(project));
if (files.length > 0) {
List<GotoRelatedItem> items = new ArrayList<GotoRelatedItem>();
for (PsiFile psiFile : files) {
items.add(new GotoRelatedItem(psiFile));
}
return items;
}
}
}
return super.getItems(context);
}
}
@@ -17,7 +17,7 @@ $member.name=")##
#if ($member.primitiveArray)
.append($member.name == null ? "null" : "");
for (int i = 0; $member.name != null && i < $member.name .length; ++i)
sb.append(i == 0 ? "" : ", ").append($member.name[i]);
sb.append(i == 0 ? "" : ", ").append($member.name[$i]);
#elseif ($member.objectArray)
.append($member.name == null ? "null" : Arrays.asList($member.name).toString());
#elseif ($member.string)
@@ -17,7 +17,7 @@ $member.name=")##
#if ($member.primitiveArray)
.append($member.name == null ? "null" : "");
for (int i = 0; $member.name != null && i < $member.name .length; ++i)
sb.append(i == 0 ? "" : ", ").append($member.name[i]);
sb.append(i == 0 ? "" : ", ").append($member.name[$i]);
#elseif ($member.objectArray)
.append($member.name == null ? "null" : Arrays.asList($member.name).toString());
#elseif ($member.string)
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -69,13 +69,22 @@ public class TemplatesManager implements PersistentStateComponent<TemplatesState
}
}
public Collection<TemplateResource> getAllTemplates() {
Collection<TemplateResource> templates = new LinkedHashSet<TemplateResource>(Arrays.asList(TemplateResourceLocator.getDefaultTemplates()));
templates.addAll(myState.templates);
return templates;
public Collection<TemplateResource> getAllTemplates() {
TemplateResource[] defaultTemplates = TemplateResourceLocator.getDefaultTemplates();
HashSet<String> names = new HashSet<String>();
for (TemplateResource defaultTemplate : defaultTemplates) {
names.add(defaultTemplate.getFileName());
}
Collection<TemplateResource> templates = new LinkedHashSet<TemplateResource>(Arrays.asList(defaultTemplates));
for (TemplateResource template : myState.templates) {
if (!names.contains(template.getFileName())) {
templates.add(template);
}
}
return templates;
}
public TemplateResource getDefaultTemplate() {
public TemplateResource getDefaultTemplate() {
for (TemplateResource template : getAllTemplates()) {
if (Comparing.equal(template.getFileName(), myState.defaultTempalteName)) {
return template;
@@ -20,9 +20,7 @@ import com.intellij.openapi.vcs.BigArray;
import com.intellij.openapi.vcs.GroupingMerger;
import com.intellij.openapi.vcs.changes.committed.DateChangeListGroupingStrategy;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.ReadonlyList;
import com.intellij.util.containers.StepList;
import com.intellij.util.containers.*;
import com.intellij.util.ui.ColumnInfo;
import git4idea.history.browser.GitCommit;
import org.jetbrains.annotations.NotNull;
@@ -30,6 +28,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.table.AbstractTableModel;
import java.util.*;
import java.util.HashMap;
/**
* @author irengrig
@@ -45,6 +44,12 @@ public class BigTableTableModel extends AbstractTableModel {
private List<VirtualFile> myOrder;
private Map<VirtualFile, Integer> myAdditions;
// end group
private final BidirectionalMap<InnerIdx, Integer> myIdxMap;
// for faster drawing
private final Map<VirtualFile, TreeSet<Integer>> myRepoIdxMap;
// index of NEXT
private final Map<VirtualFile, Integer> myRunningRepoIdxs;
@NotNull
private final List<ColumnInfo> myColumns;
@@ -63,6 +68,10 @@ public class BigTableTableModel extends AbstractTableModel {
public BigTableTableModel(@NotNull final List<ColumnInfo> columns, Runnable init) {
myColumns = columns;
myInit = init;
myIdxMap = new BidirectionalMap<InnerIdx, Integer>();
myRunningRepoIdxs = new HashMap<VirtualFile, Integer>();
myRepoIdxMap = new HashMap<VirtualFile, TreeSet<Integer>>();
myCurrentComparator = CommitIReorderingInsideOneRepoComparator.getInstance();
final DateChangeListGroupingStrategy delegate = new DateChangeListGroupingStrategy();
myStrategy = new CommitGroupingStrategy() {
@@ -131,8 +140,8 @@ public class BigTableTableModel extends AbstractTableModel {
public int getTotalWires() {
if (mySkeletonBuilder == null) return -1;
int wires = 0;
for (TreeNavigationImpl navigation : myNavigation.values()) {
wires += navigation.getMaximumWires();
for (SkeletonBuilder skeletonBuilder : mySkeletonBuilder.values()) {
wires += skeletonBuilder.getMaxWireNum();
}
return wires;
}
@@ -142,7 +151,7 @@ public class BigTableTableModel extends AbstractTableModel {
if (mySkeletonBuilder == null) return null;
final List<Integer> result = new ArrayList<Integer>(myOrder.size());
for (VirtualFile file : myOrder) {
result.add(myNavigation.get(file).getMaximumWires());
result.add(mySkeletonBuilder.get(file).getMaxWireNum());
}
return result;
}
@@ -153,32 +162,109 @@ public class BigTableTableModel extends AbstractTableModel {
return myAdditions.get(file) + commitI.getWireNumber();
}
public WiresGroupIterator getGroupIterator(final int firstRow) {
return new WiresGroupIterator(firstRow);
public Map<VirtualFile, WireEventsIterator> getGroupIterators(final int firstRow) {
final Map<VirtualFile, WireEventsIterator> map = new HashMap<VirtualFile, WireEventsIterator>();
for (VirtualFile virtualFile : mySkeletonBuilder.keySet()) {
map.put(virtualFile, new WiresGroupIterator(firstRow, virtualFile));
}
return map;
}
class WiresGroupIterator {
class WiresGroupIterator implements WireEventsIterator {
private final int myFirstIdx;
private List<Integer> myFirstUsed;
private final VirtualFile myRoot;
private final int myOffset;
private final Iterator<WireEvent> myWireEventsIterator;
private Integer myFloor;
WiresGroupIterator(int firstIdx) {
WiresGroupIterator(int firstIdx, VirtualFile root) {
myFirstIdx = firstIdx;
myRoot = root;
myOffset = myAdditions.get(myRoot);
myFirstUsed = new ArrayList<Integer>();
for (VirtualFile file : myOrder) {
TreeNavigationImpl navigation = myNavigation.get(file);
final List<Integer> used = navigation.getUsedWires(firstIdx, myLines, mySkeletonBuilder.get(file).getFutureConvertor()).getUsed();
myFirstUsed.addAll(used);
TreeNavigationImpl navigation = myNavigation.get(myRoot);
// get less idx
myFloor = myRepoIdxMap.get(myRoot).floor(firstIdx);
int idx;
final ReadonlyList<CommitI> wrapper = createWrapper(myRoot);
if (myFloor == null) {
myFloor = 0;
idx = 0;
} else {
final List<InnerIdx> keysByValue = myIdxMap.getKeysByValue(myFloor);
idx = -1;
for (InnerIdx innerIdx : keysByValue) {
if (innerIdx.getRoot().equals(myRoot)) {
idx = innerIdx.getInsideRepoIdx();
break;
}
}
assert idx != -1;
}
final List<Integer> used = navigation.getUsedWires(idx, wrapper, mySkeletonBuilder.get(myRoot).getFutureConvertor()).getUsed();
for (Integer integer : used) {
myFirstUsed.add(integer + myOffset);
}
myWireEventsIterator = navigation.createWireEventsIterator(idx);
}
@Override
public Integer getFloor() {
return myFloor;
}
@Override
public Iterator<WireEvent> getWireEventsIterator() {
return new Iterator<WireEvent>() {
@Override
public boolean hasNext() {
return myWireEventsIterator.hasNext();
}
@Override
public WireEvent next() {
final WireEvent next = myWireEventsIterator.next();
final Convertor<Integer, Integer> innerToOuter = new Convertor<Integer, Integer>() {
@Override
public Integer convert(Integer o) {
if (o == -1) return -1;
final int insideRepoIdx = o.intValue();
final Integer integer = myIdxMap.get(new InnerIdx(myRoot, insideRepoIdx));
assert integer != null;
return integer;
}
};
final Convertor<int[], int[]> arraysConvertor = new Convertor<int[], int[]>() {
@Override
public int[] convert(int[] o) {
if (o == null) return null;
final int[] result = new int[o.length];
for (int i = 0; i < o.length; i++) {
int i1 = o[i];
result[i] = innerToOuter.convert(i1);
}
return result;
}
};
final WireEvent wireEvent = new WireEvent(innerToOuter.convert(next.getCommitIdx()), arraysConvertor.convert(next.getCommitsEnds()));
wireEvent.setCommitsStarts(arraysConvertor.convert(next.getCommitsStarts()));
wireEvent.setWireEnds(arraysConvertor.convert(next.getWireEnds()));
return wireEvent;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public List<Integer> getFirstUsed() {
return myFirstUsed;
}
public WireEvent getEventForRow(final int row) {
assert row >= myFirstIdx;
return myNavigation.get(getCommitAt(row).selectRepository(myRootsHolder.getRoots())).getEventForRow(row);
}
}
@Override
@@ -211,8 +297,7 @@ public class BigTableTableModel extends AbstractTableModel {
}
public void clear(boolean noFilters) {
// todo uncomment for git log tree
/*if (noFilters) {
if (noFilters) {
myCurrentComparator = CommitIComparator.getInstance();
myNavigation = new HashMap<VirtualFile, TreeNavigationImpl>();
mySkeletonBuilder = new HashMap<VirtualFile, SkeletonBuilder>();
@@ -225,15 +310,19 @@ public class BigTableTableModel extends AbstractTableModel {
myNavigation.put(vf, navigation);
mySkeletonBuilder.put(vf, skeletonBuilder);
myAdditions.put(vf, 0);
myRepoIdxMap.put(vf, new TreeSet<Integer>());
myRunningRepoIdxs.put(vf, 0);
myIdxMap.clear();
}
} else {
myCurrentComparator = CommitIReorderingInsideOneRepoComparator.getInstance();
*/
myAdditions = null;
mySkeletonBuilder = null;
myNavigation = null;
myOrder = null;
//}
}
myLines = new BigArray<CommitI>(10);
myCutCount = -1;
}
@@ -251,17 +340,18 @@ public class BigTableTableModel extends AbstractTableModel {
Collections.sort(lines, myCurrentComparator);
}
final Integer[] parentsIdx = new Integer[1];
parentsIdx[0] = 0;
final Set<Integer> whatToRecount = mySkeletonBuilder == null ? null : new HashSet<Integer>();
final Map<Integer, Integer> indexRecalculation = new HashMap<Integer, Integer>();
myStrategy.beforeStart();
// find those ..... long awaited start idx by stupid long iteration since
// items can NOT be ordered by simple rule
final int[] parentsIdx = new int[1];
parentsIdx[0] = 0;
int idxFrom = findIdx(lines);
final CommitI commitI = lines.get(0);
final VirtualFile listRoot = commitI.selectRepository(myRootsHolder.getRoots());
final ReadonlyList<CommitI> wrapperList = createWrapper(listRoot);
int recountFrom = new GroupingMerger<CommitI, String>() {
@Override
protected CommitI wrapItem(CommitI commitI) {
@@ -274,9 +364,14 @@ public class BigTableTableModel extends AbstractTableModel {
@Override
protected void afterConsumed(CommitI commitI, int i) {
if (mySkeletonBuilder != null && ! commitI.holdsDecoration()) {
whatToRecount.add(i);
//mySkeletonBuilder.get(commitI.selectRepository(myRootsHolder.getRoots())).consume(commitI, parents.get(parentsIdx[0]), myLines, i);
//++parentsIdx[0];
final VirtualFile root = commitI.selectRepository(myRootsHolder.getRoots());
final Integer innerIdx = myRunningRepoIdxs.get(root);
myIdxMap.put(new InnerIdx(root, innerIdx), i);
myRepoIdxMap.get(root).add(i);
myRunningRepoIdxs.put(root, innerIdx + 1);
mySkeletonBuilder.get(root).consume(commitI, parents.get(parentsIdx[0]), wrapperList, innerIdx);
++ parentsIdx[0];
}
}
@@ -287,7 +382,7 @@ public class BigTableTableModel extends AbstractTableModel {
@Override
protected String getGroup(CommitI commitI) {
return mySkeletonBuilder != null ? "" : myStrategy.getGroupName(commitI);
return mySkeletonBuilder != null ? null : myStrategy.getGroupName(commitI);
}
@Override
@@ -298,42 +393,50 @@ public class BigTableTableModel extends AbstractTableModel {
@Override
protected void oldBecame(int was, int is) {
if (mySkeletonBuilder != null && was != is) {
indexRecalculation.put(was, is);
/*CommitI commitI = myLines.get(is);
if (! commitI.holdsDecoration()) {
mySkeletonBuilder.get(commitI.selectRepository(myRootsHolder.getRoots())).oldBecameNew(was, is);
}*/
final List<InnerIdx> keys = myIdxMap.getKeysByValue(was);
final VirtualFile root = myLines.get(is).selectRepository(myRootsHolder.getRoots());
assert ! root.equals(listRoot);
myRepoIdxMap.get(root).remove(was);
myRepoIdxMap.get(root).add(is);
InnerIdx found = null;
for (InnerIdx key : keys) {
if (key.getRoot().equals(root)) {
found = key;
break;
}
}
assert found != null;
myIdxMap.put(found, is);
}
// todo
//System.out.println("old: " + was + " became: " + is);
}
}.firstPlusSecond(myLines, new ReadonlyList.ArrayListWrapper<CommitI>(lines), myCurrentComparator, mySkeletonBuilder == null ? -1 : idxFrom);
if (mySkeletonBuilder != null) {
for (SkeletonBuilder skeletonBuilder : mySkeletonBuilder.values()) {
skeletonBuilder.oldBecameNew(indexRecalculation);
}
myNavigation.get(listRoot).recalcIndex(wrapperList, mySkeletonBuilder.get(listRoot).getFutureConvertor());
for (int i = recountFrom; i < myLines.getSize(); i++) {
final CommitI commitI = myLines.get(i);
if (mySkeletonBuilder != null && ! commitI.holdsDecoration() && whatToRecount.contains(i)) {
mySkeletonBuilder.get(commitI.selectRepository(myRootsHolder.getRoots())).consume(commitI, parents.get(parentsIdx[0]), myLines, i);
++parentsIdx[0];
}
}
for (Map.Entry<VirtualFile, TreeNavigationImpl> entry : myNavigation.entrySet()) {
final TreeNavigationImpl navigation = myNavigation.get(entry.getKey());
navigation.recalcIndex(myLines, mySkeletonBuilder.get(entry.getKey()).getFutureConvertor());
}
int size = 0;
for (VirtualFile file : myOrder) {
myAdditions.put(file, size);
size += myNavigation.get(file).getMaximumWires();
size += mySkeletonBuilder.get(file).getMaxWireNum();
}
}
}
private ReadonlyList<CommitI> createWrapper(final VirtualFile root) {
return new ReadonlyList<CommitI>() {
@Override
public CommitI get(int idx) {
return myLines.get(myIdxMap.get(new InnerIdx(root, idx)));
}
@Override
public int getSize() {
return myRunningRepoIdxs.get(root);
}
};
}
private int findIdx(List<CommitI> lines) {
final VirtualFile targetRepo = lines.get(0).selectRepository(myRootsHolder.getRoots());
final long time = lines.get(0).getTime();
@@ -344,7 +447,7 @@ public class BigTableTableModel extends AbstractTableModel {
return i + 1; // will be equal to list size sometimes, is that ok?
} else {
if (current.getTime() > time) {
return i + 1;
return i;
}
}
}
@@ -363,7 +466,6 @@ public class BigTableTableModel extends AbstractTableModel {
myStrategy = strategy;
}
// todo test
public void printNavigation() {
for (Map.Entry<VirtualFile, TreeNavigationImpl> entry : myNavigation.entrySet()) {
if (entry.getKey().getPath().contains("inner")) {
@@ -371,4 +473,42 @@ public class BigTableTableModel extends AbstractTableModel {
}
}
}
}
public static class InnerIdx {
private final VirtualFile myRoot;
private final int myInsideRepoIdx;
public InnerIdx(VirtualFile root, int insideRepoIdx) {
myRoot = root;
myInsideRepoIdx = insideRepoIdx;
}
public VirtualFile getRoot() {
return myRoot;
}
public int getInsideRepoIdx() {
return myInsideRepoIdx;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InnerIdx innerIdx = (InnerIdx)o;
if (myInsideRepoIdx != innerIdx.myInsideRepoIdx) return false;
if (!myRoot.equals(innerIdx.myRoot)) return false;
return true;
}
@Override
public int hashCode() {
int result = myRoot.hashCode();
result = 31 * result + myInsideRepoIdx;
return result;
}
}
}
@@ -18,7 +18,6 @@ import com.intellij.openapi.progress.BackgroundTaskQueue;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
@@ -42,7 +41,7 @@ import java.util.Map;
* @author irengrig
*/
public class DetailsCache {
private final static int ourSize = 400;
private final static int ourSize = 500;
private final SLRUMap<Pair<VirtualFile, AbstractHash>, GitCommit> myCache;
private final SLRUMap<Pair<VirtualFile, AbstractHash>, List<String>> myBranches;
private final Project myProject;
@@ -64,8 +63,8 @@ public class DetailsCache {
myStash = new HashMap<VirtualFile, Map<AbstractHash,String>>();
myRefresh = uiRefresh;
myLock = new Object();
myCache = new SLRUMap<Pair<VirtualFile, AbstractHash>, GitCommit>(ourSize, 50);
myBranches = new SLRUMap<Pair<VirtualFile, AbstractHash>, List<String>>(10, 10);
myCache = new SLRUMap<Pair<VirtualFile, AbstractHash>, GitCommit>(ourSize, 150);
myBranches = new SLRUMap<Pair<VirtualFile, AbstractHash>, List<String>>(20, 20);
}
public GitCommit convert(final VirtualFile root, final AbstractHash hash) {
@@ -61,6 +61,7 @@ public class GitLogSettings implements PersistentStateComponent<GitLogSettings.M
public boolean mySelectedUserIsMe;
// false => filter
public boolean myHighlight = true;
public boolean myShowTree = true;
}
@Override
@@ -72,6 +73,14 @@ public class GitLogSettings implements PersistentStateComponent<GitLogSettings.M
public void loadState(MyState state) {
myState = state;
}
public boolean isShowTree() {
return myState.myShowTree;
}
public void setShowTree(final boolean value) {
myState.myShowTree = value;
}
public void setSelectedUser(final String selected) {
myState.mySelectedUser = selected;
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.CaptionIcon;
import com.intellij.openapi.diff.impl.patch.formove.FilePathComparator;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
@@ -65,9 +66,11 @@ import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.io.File;
import java.util.*;
import java.util.List;
@@ -90,7 +93,7 @@ public class GitLogUI implements Disposable {
private final Map<VirtualFile, SymbolicRefs> myRefs;
private final SymbolicRefs myRecalculatedCommon;
private UIRefresh myUIRefresh;
private JBTable myJBTable;
private MouseOpenJBTable myJBTable;
private GraphGutter myGraphGutter;
private RepositoryChangesBrowser myRepositoryChangesBrowser;
final List<CommitI> myCommitsInRepositoryChangesBrowser;
@@ -125,6 +128,9 @@ public class GitLogUI implements Disposable {
private final TableCellRenderer myAuthorRenderer;
private MyRootsAction myRootsAction;
private JPanel myEqualToHeadr;
private boolean myThereAreFilters;
private final GitLogUI.MyShowTreeAction myMyShowTreeAction;
public GitLogUI(Project project, final Mediator mediator) {
myProject = project;
@@ -154,6 +160,7 @@ public class GitLogUI implements Disposable {
initUiRefresh();
myAuthorRenderer = new HighLightingRenderer(HIGHLIGHT_TEXT_ATTRIBUTES, SimpleTextAttributes.REGULAR_ATTRIBUTES);
myMyShowTreeAction = new MyShowTreeAction();
}
public void initFromSettings() {
@@ -247,6 +254,8 @@ public class GitLogUI implements Disposable {
myDataBeingAdded = false;
myJBTable.revalidate();
myJBTable.repaint();
((JComponent) myEqualToHeadr.getParent()).revalidate();
myEqualToHeadr.getParent().repaint();
}
private void start() {
@@ -423,6 +432,7 @@ public class GitLogUI implements Disposable {
myJBTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
myGraphGutter.getComponent().repaint();
mySelectionRequestsMerger.request();
}
});
@@ -572,7 +582,7 @@ public class GitLogUI implements Disposable {
}
private JPanel createMainTable() {
myJBTable = new JBTable(myTableModel) {
myJBTable = new MouseOpenJBTable(myTableModel) {
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
final TableCellRenderer custom = myTableModel.getColumnInfo(column).getRenderer(myTableModel.getValueAt(row, column));
@@ -596,10 +606,11 @@ public class GitLogUI implements Disposable {
myJBTable.getExpandableItemsHandler().setEnabled(false);
myJBTable.setShowGrid(false);
myJBTable.setModel(myTableModel);
myJBTable.setBorder(null);
myJBTable.addMouseListener(new PopupHandler() {
@Override
public void invokePopup(Component comp, int x, int y) {
createContextMenu().getComponent().show(comp,x,y);
createContextMenu().getComponent().show(comp, x, y);
}
});
@@ -624,22 +635,51 @@ public class GitLogUI implements Disposable {
@Override
public void run() {
updateByScroll();
// todo uncomment for git tree
/*if (myGraphGutter.getComponent().isVisible()) {
myGraphGutter.getComponent().repaint();
}*/
}
});
}, new Runnable() {
@Override
public void run() {
if (myGraphGutter.getComponent().isVisible()) {
myGraphGutter.getComponent().repaint();
}
}
}
);
scrollPane.getViewport().addChangeListener(myMyChangeListener);
final JPanel wrapper = new DataProviderPanel(new BorderLayout());
wrapper.add(actionToolbar.getComponent(), BorderLayout.NORTH);
final JPanel mainBorderWrapper = new JPanel(new BorderLayout());
myGraphGutter.getComponent().setVisible(false);
// todo uncomment for git tree
//mainBorderWrapper.add(myGraphGutter.getComponent(), BorderLayout.WEST);
final JPanel wrapperGutter = new JPanel(new BorderLayout());
//myGraphGutter.getComponent().setVisible(false);
myEqualToHeadr = new JPanel() {
@Override
public Dimension getPreferredSize() {
return getMySize();
}
@Override
public Dimension getMaximumSize() {
return getMySize();
}
@Override
public Dimension getMinimumSize() {
return getMySize();
}
public Dimension getMySize() {
final int height = myJBTable.getTableHeader().getHeight();
final int width = myGraphGutter.getComponent().getPreferredSize().width;
return new Dimension(width, height);
}
};
myEqualToHeadr.setBorder(BorderFactory.createMatteBorder(0,0,1,0,UIUtil.getBorderColor()));
wrapperGutter.add(myEqualToHeadr, BorderLayout.NORTH);
wrapperGutter.add(myGraphGutter.getComponent(), BorderLayout.CENTER);
mainBorderWrapper.add(wrapperGutter, BorderLayout.WEST);
mainBorderWrapper.add(scrollPane, BorderLayout.CENTER);
mainBorderWrapper.setBorder(BorderFactory.createLineBorder(UIUtil.getBorderColor()));
//mainBorderWrapper.setBorder(BorderFactory.createLineBorder(UIUtil.getBorderColor()));
wrapper.add(mainBorderWrapper, BorderLayout.CENTER);
myDetailsPanel = new GitLogDetailsPanel(myProject, myDetailsCache, new Convertor<VirtualFile, SymbolicRefs>() {
@Override
@@ -675,6 +715,7 @@ public class GitLogUI implements Disposable {
group.add(myStructureFilterAction.asTextAction());
group.add(myCherryPickAction);
group.add(ActionManager.getInstance().getAction("ChangesView.CreatePatchFromChanges"));
group.add(myMyShowTreeAction);
group.add(myRefreshAction);
return ActionManager.getInstance().createActionPopupMenu(GIT_LOG_TABLE_PLACE, group);
}
@@ -714,6 +755,7 @@ public class GitLogUI implements Disposable {
myRefreshAction = new MyRefreshAction();
myRootsAction = new MyRootsAction(rootsGetter, myJBTable);
group.add(myRootsAction);
group.add(myMyShowTreeAction);
group.add(myRefreshAction);
// todo debug
//group.add(new TestIndexAction());
@@ -1268,9 +1310,13 @@ public class GitLogUI implements Disposable {
myCommentSearchContext.clear();
myUsersSearchContext.clear();
myGraphGutter.getComponent().setVisible(false);
myThereAreFilters = true;
myEqualToHeadr.getParent().setVisible(false);
if (commentFilterEmpty && (myUserFilterI.myFilter == null) && myStructureFilter.myAllSelected) {
myGraphGutter.getComponent().setVisible(true);
myThereAreFilters = false;
if (myMyShowTreeAction.isSelected(null)) {
myEqualToHeadr.getParent().setVisible(true);
}
myUsersSearchContext.clear();
myMediator.reload(new RootsHolder(myRootsUnderVcs), startingPoints, new GitLogFilters());
} else {
@@ -1577,4 +1623,59 @@ public class GitLogUI implements Disposable {
}
}
}
public static class MouseOpenJBTable extends JBTable {
public MouseOpenJBTable() {
}
public MouseOpenJBTable(TableModel model) {
super(model);
}
@Override
public void processMouseEvent(MouseEvent e) {
super.processMouseEvent(e);
}
@Override
public void processMouseMotionEvent(MouseEvent e) {
super.processMouseMotionEvent(e);
}
@Override
protected void processMouseWheelEvent(MouseWheelEvent e) {
super.processMouseWheelEvent(e);
}
}
public class MyShowTreeAction extends ToggleAction implements DumbAware {
private boolean myIsSelected;
private final GitLogSettings myInstance;
public MyShowTreeAction() {
super("Show graph", "Show graph", IconLoader.getIcon("/icons/branch.png"));
myInstance = GitLogSettings.getInstance(myProject);
myIsSelected = myInstance.isShowTree();
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabled(! myThereAreFilters);
}
@Override
public boolean isSelected(AnActionEvent e) {
return myIsSelected;
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
myIsSelected = state;
myInstance.setShowTree(state);
if (! myThereAreFilters) {
myEqualToHeadr.getParent().setVisible(state);
}
}
}
}
@@ -39,7 +39,7 @@ public class GitTableScrollChangeListener implements ChangeListener {
public GitTableScrollChangeListener(final JBTable table,
final DetailsCache detailsCache,
final BigTableTableModel tableModel,
Runnable checkSelection) {
Runnable checkSelection, final Runnable fastListener) {
myDetailsCache = detailsCache;
myTableModel = tableModel;
myCheckSelection = checkSelection;
@@ -48,6 +48,9 @@ public class GitTableScrollChangeListener implements ChangeListener {
myTimer = UIUtil.createNamedTimer("Git table scroll timer",100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (fastListener != null) {
fastListener.run();
}
final boolean shouldPing = (System.currentTimeMillis() - myRefreshMark) > 300;
//final boolean shouldPing = false;
if (((mySpeedometer.getSpeed() < 0.1) && mySpeedometer.hasData()) || shouldPing) {
@@ -15,8 +15,10 @@
*/
package git4idea.history.wholeTree;
import com.intellij.ui.table.JBTable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -30,16 +32,19 @@ import java.util.List;
* Time: 4:11 PM
*/
public class GraphGutter {
private static final int ourLineWidth = 10;
private static final int ourLineWidth = 8;
private static final int ourInterLineWidth = 1;
private static final int ourInterRepoLineWidth = 5;
public static final int ourIndent = 2;
private int myHeaderHeight;
private int myRowHeight;
private final BigTableTableModel myModel;
private MyComponent myComponent;
private JViewport myTableViewPort;
private JBTable myJBTable;
private GitLogUI.MouseOpenJBTable myJBTable;
private boolean myStarted;
private static final Logger LOG = Logger.getInstance("#git4idea.history.wholeTree.GraphGutter");
public GraphGutter(BigTableTableModel model) {
myModel = model;
@@ -47,7 +52,8 @@ public class GraphGutter {
}
public void setHeaderHeight(int headerHeight) {
myHeaderHeight = headerHeight;
//myHeaderHeight = headerHeight;
myHeaderHeight = 0;
}
public void setRowHeight(int rowHeight) {
@@ -62,7 +68,7 @@ public class GraphGutter {
myTableViewPort = tableViewPort;
}
public void setJBTable(JBTable JBTable) {
public void setJBTable(GitLogUI.MouseOpenJBTable JBTable) {
myJBTable = JBTable;
}
@@ -72,104 +78,256 @@ public class GraphGutter {
// will lay near but not inside scroll pane
class MyComponent extends JPanel {
MyComponent() {
setDoubleBuffered(true);
setBackground(UIUtil.getTableBackground());
}
@Override
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
if (! myStarted) return preferredSize;
int totalWires = myModel.getTotalWires();
return new Dimension(endPoint(totalWires), preferredSize.height);
List<Integer> wiresGroups = getWiresGroups();
return new Dimension(endPoint(totalWires, wiresGroups), preferredSize.height);
}
private int endPoint(final int wireNumber) {
return (wireNumber + 1) * ourLineWidth + wireNumber * ourInterLineWidth;
private int endPoint(final int wireNumber, List<Integer> wiresGroups) {
int add = 0;
for (Integer wiresGroup : wiresGroups) {
if (wiresGroup - 1 <= wireNumber) {
add += ourInterRepoLineWidth - ourInterLineWidth;
}
}
return (wireNumber + 1) * ourLineWidth + wireNumber * ourInterLineWidth + add + ourIndent;
}
private void drawConnectorsFragment(final Graphics g,
final int idxFrom,
final int yOffset,
final Set<Integer> wires,
@Nullable final WireEvent event,
HashSet<Integer> selected, final List<Integer> wiresGroups) {
final Color darker2 = UIUtil.getTableSelectionBackground().darker();
final Color darker = new Color(255,128,0);
int rowYOffset = yOffset;
for (int i = idxFrom; i < event.getCommitIdx(); i++) {
for (Integer wire : wires) {
g.setColor(selected.contains(i) ? UIUtil.getTableSelectionForeground() : (wire/2 % 2 == 1 ? darker : darker2));
int startXPoint = startPoint(wire, wiresGroups) + ourLineWidth/2;
g.drawLine(startXPoint, rowYOffset, startXPoint, rowYOffset + myRowHeight);
}
rowYOffset += myRowHeight;
}
final int eventWire = myModel.getCorrectedWire(myModel.getCommitAt(event.getCommitIdx()));
g.setColor(selected.contains(event.getCommitIdx()) ? UIUtil.getTableSelectionForeground() : (eventWire/2 % 2 == 1 ? darker : darker2));
int eventStartXPoint = startPoint(eventWire, wiresGroups) + ourLineWidth/2;
final Set<Integer> skip = new HashSet<Integer>();
if (event.isStart() && event.isEnd()) {
return;
}
if (event.isStart()) {
skip.add(eventWire);
g.drawLine(eventStartXPoint, rowYOffset + myRowHeight/2, eventStartXPoint, rowYOffset + myRowHeight);
}
if (event.isEnd()) {
skip.add(eventWire);
g.drawLine(eventStartXPoint, rowYOffset, eventStartXPoint, rowYOffset + myRowHeight/2);
}
final int[] commitsStarts = event.getCommitsStarts();
if (commitsStarts != null) {
for (int commitsStart : commitsStarts) {
if (commitsStart == -1) continue;
final int wire = myModel.getCorrectedWire(myModel.getCommitAt(commitsStart));
int startXPoint = startPoint(wire, wiresGroups) + ourLineWidth/2;
g.setColor(selected.contains(event.getCommitIdx()) ? UIUtil.getTableSelectionForeground() : (wire/2 % 2 == 1 ? darker : darker2));
g.drawLine(startXPoint, rowYOffset + myRowHeight, eventStartXPoint, rowYOffset + myRowHeight/2);
}
}
final int[] wireEnds = event.getWireEnds();
if (wireEnds != null) {
for (int end : wireEnds) {
if (end == -1) continue;
final int wire = myModel.getCorrectedWire(myModel.getCommitAt(end));
skip.add(wire);
int startXPoint = startPoint(wire, wiresGroups) + ourLineWidth/2;
g.setColor(selected.contains(event.getCommitIdx()) ? UIUtil.getTableSelectionForeground() : (wire/2 % 2 == 1 ? darker : darker2));
g.drawLine(startXPoint, rowYOffset, eventStartXPoint, rowYOffset + myRowHeight/2);
}
}
for (Integer wire : wires) {
if (skip.contains(wire)) continue;
int startXPoint = startPoint(wire, wiresGroups) + ourLineWidth/2;
g.setColor(selected.contains(event.getCommitIdx()) ? UIUtil.getTableSelectionForeground() : (wire/2 % 2 == 1 ? darker : darker2));
g.drawLine(startXPoint, rowYOffset, startXPoint, rowYOffset + myRowHeight);
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (! myStarted) return;
Graphics graphics = g.create();
try {
int height = getHeight();
super.paintComponent(g);
if (! myStarted) return;
// separators
List<Integer> wiresGroups = myModel.getWiresGroups();
int running = 0;
if (wiresGroups.size() > 1) {
for (int i = 0; i < wiresGroups.size() - 1; i++) {
Integer integer = wiresGroups.get(i);
int x1 = (running + integer) == 0 ? 0 : endPoint(running + integer - 1);
graphics.setColor(UIUtil.getBorderColor());
graphics.drawLine(x1, 0, x1, height);
running += integer;
}
}
// cells
int yOffset = (int) myTableViewPort.getViewPosition().getY();
int integerPart = yOffset / myRowHeight;
int firstCellPart = yOffset - integerPart * myRowHeight;
if (firstCellPart > 0) {
drawFirst(graphics, firstCellPart, integerPart);
}
int width = getWidth();
int upBound = firstCellPart == 0 ? 0 : myRowHeight - firstCellPart; // todo +-
upBound += myHeaderHeight;
int idx = integerPart + (firstCellPart > 0 ? 1 : 0);
BigTableTableModel.WiresGroupIterator groupIterator;
Graphics graphics = g.create();
try {
groupIterator = myModel.getGroupIterator(idx);
} catch (Exception e) {
return;
//
// TODO remove!!!
}
List<Integer> firstUsed = groupIterator.getFirstUsed();
while (upBound < height && idx < myModel.getRowCount()) {
CommitI commitAt = myModel.getCommitAt(idx);
int height = getHeight();
WireEvent eventForRow = groupIterator.getEventForRow(idx);
if (eventForRow != null) {
//todo minus, plus..
// cells
int yOffset = (int) myTableViewPort.getViewPosition().getY();
int integerPart = yOffset / myRowHeight;
int firstCellPart = yOffset - integerPart * myRowHeight;
int width = getWidth();
int upBound = firstCellPart == 0 ? 0 : - firstCellPart;
upBound += myHeaderHeight;
//int idx = integerPart + (firstCellPart > 0 ? 1 : 0);
int idx = integerPart;
int lastIdx = idx + (getHeight()/myRowHeight + 1);
final int[] selectedRows = myJBTable.getSelectedRows();
drawSelection(graphics, width, upBound, idx, lastIdx, selectedRows);
final HashSet<Integer> selected = new HashSet<Integer>();
for (int selectedRow : selectedRows) {
selected.add(selectedRow);
}
// todo temp out
/*for (Integer i : firstUsed) {
int start = startPoint(i);
graphics.setColor(UIUtil.getBorderColor());
graphics.drawRect(start - 1, upBound, start + 1, upBound + myRowHeight);
}*/
if (! commitAt.holdsDecoration()) {
int correctedWire = myModel.getCorrectedWire(commitAt);
int startXPoint = startPoint(correctedWire);
graphics.setColor(Color.black);
((Graphics2D) graphics).drawArc(startXPoint + ourLineWidth / 2 - 4, upBound + myRowHeight / 2 - 4, 8, 8, 0, 360);
graphics.setColor(correctedWire == 0 ? Color.red : Color.yellow);
((Graphics2D) graphics).fillArc(startXPoint + ourLineWidth / 2 - 4, upBound + myRowHeight / 2 - 4, 8, 8, 0, 360);
//graphics.drawString("" + correctedWire, startXPoint, upBound + myRowHeight);
} else {
graphics.setColor(Color.black);
//((Graphics2D) graphics).drawArc(startXPoint + ourLineWidth/2 - 2, upBound + myRowHeight/2 - 2, 4, 4, 0, 360);
//graphics.drawString("H", 0, upBound + myRowHeight);
}
graphics.setColor(UIUtil.getBorderColor());
graphics.drawLine(0, upBound, width, upBound);
++ idx;
upBound += myRowHeight;
// separators
List<Integer> wiresGroups = getWiresGroups();
drawRepoBounds(graphics, height, wiresGroups);
drawConnectors(graphics, lastIdx, upBound, idx, selected, wiresGroups);
drawPoints(graphics, lastIdx, upBound, idx, selected, wiresGroups);
} finally {
graphics.dispose();
}
} finally {
graphics.dispose();
} catch (Exception e) {
LOG.info(e);
}
}
private int startPoint(int correctedWire) {
return correctedWire == 0 ? 0 : endPoint(correctedWire - 1);
private List<Integer> getWiresGroups() {
List<Integer> wiresGroups = myModel.getWiresGroups();
if (wiresGroups == null) return Collections.emptyList();
int running = 0;
for (int i = 0; i < wiresGroups.size(); i++) {
Integer integer = wiresGroups.get(i);
wiresGroups.set(i, running + integer);
running += integer;
}
return wiresGroups;
}
private void drawFirst(Graphics graphics, int firstCellPart, int idx) {
//To change body of created methods use File | Settings | File Templates.
private void drawSelection(Graphics graphics, int width, int upBound, int idx, int lastIdx, int[] selectedRows) {
for (int selectedRow : selectedRows) {
if (selectedRow >= idx && selectedRow <= lastIdx) {
graphics.setColor(UIUtil.getTableSelectionBackground());
graphics.fillRect(0, upBound + (selectedRow - idx) * myRowHeight,width,myRowHeight);
}
}
}
private void drawPoints(Graphics graphics, int lastIdx, int upBound, int idx, HashSet<Integer> selected, List<Integer> wiresGroups) {
final Color darker = UIUtil.getTableSelectionBackground();
final Color fill = new Color(176,230,255);
while (idx <= lastIdx && idx < myModel.getRowCount()) {
CommitI commitAt = myModel.getCommitAt(idx);
final boolean contains = selected.contains(idx);
if (! commitAt.holdsDecoration()) {
int correctedWire = myModel.getCorrectedWire(commitAt);
int startXPoint = startPoint(correctedWire, wiresGroups);
graphics.setColor(contains ? UIUtil.getTableSelectionForeground() : fill);
((Graphics2D) graphics).fillArc(startXPoint + ourLineWidth / 2 - 4, upBound + myRowHeight / 2 - 4, 7, 7, 0, 360);
//graphics.setColor(contains ? UIUtil.getTableSelectionForeground() : UIUtil.getTableSelectionBackground().brighter());
graphics.setColor(contains ? UIUtil.getTableSelectionForeground() : UIUtil.getTableSelectionBackground());
((Graphics2D) graphics).drawArc(startXPoint + ourLineWidth / 2 - 4 + 1, upBound + myRowHeight / 2 - 4, 7, 7, 0, 360);
if (! contains) {
graphics.setColor(UIUtil.getTableSelectionForeground());
((Graphics2D) graphics).drawArc(startXPoint + ourLineWidth / 2 - 4 + 1, upBound + myRowHeight / 2 - 4 + 1, 6, 6, 100, 90);
}
graphics.setColor(contains ? UIUtil.getTableSelectionForeground() : darker);
((Graphics2D) graphics).drawArc(startXPoint + ourLineWidth / 2 - 4, upBound + myRowHeight / 2 - 4, 7, 7, 0, 360);
//graphics.drawString("" + correctedWire, startXPoint, upBound + myRowHeight);
} else {
//((Graphics2D) graphics).drawArc(startXPoint + ourLineWidth/2 - 2, upBound + myRowHeight/2 - 2, 4, 4, 0, 360);
//graphics.drawString("H", 0, upBound + myRowHeight);
}
++ idx;
upBound += myRowHeight;
}
}
private void drawConnectors(Graphics graphics, int lastIdx, int upBound, int idx, HashSet<Integer> selected, List<Integer> wiresGroups) {
final Map<VirtualFile,WireEventsIterator> groupIterators = myModel.getGroupIterators(idx);
for (Map.Entry<VirtualFile, WireEventsIterator> entry : groupIterators.entrySet()) {
final WireEventsIterator eventsIterator = entry.getValue();
int idxFrom = idx;
int yOff = upBound;
Set<Integer> used = new HashSet<Integer>(eventsIterator.getFirstUsed());
final Iterator<WireEvent> iterator = eventsIterator.getWireEventsIterator();
while (iterator.hasNext()) {
final WireEvent wireEvent = iterator.next();
if (wireEvent.getCommitIdx() >= idx) {
drawConnectorsFragment(graphics, idxFrom, yOff, used, wireEvent, selected, wiresGroups);
int delta = wireEvent.getCommitIdx() + 1 - idxFrom;
delta = delta < 0 ? 0 : delta;
yOff += delta * myRowHeight;
idxFrom = wireEvent.getCommitIdx() + 1;
}
// add starts, minus ended
final int[] wireEnds = wireEvent.getWireEnds();
if (wireEnds != null) {
for (int wireEnd : wireEnds) {
used.remove(Integer.valueOf(myModel.getCorrectedWire(myModel.getCommitAt(wireEnd))));
}
}
if (wireEvent.isEnd()) {
used.remove(Integer.valueOf(myModel.getCorrectedWire(myModel.getCommitAt(wireEvent.getCommitIdx()))));
}
final int[] commitsStarts = wireEvent.getCommitsStarts();
if (commitsStarts != null) {
for (int commitsStart : commitsStarts) {
if (commitsStart == -1) continue;
used.add(myModel.getCorrectedWire(myModel.getCommitAt(commitsStart)));
}
}
if (wireEvent.isStart()) {
used.add(myModel.getCorrectedWire(myModel.getCommitAt(wireEvent.getCommitIdx())));
}
if (wireEvent.getCommitIdx() > lastIdx) break;
}
}
}
private void drawRepoBounds(Graphics graphics, int height, List<Integer> wiresGroups) {
graphics.setColor(UIUtil.getBorderColor());
if (wiresGroups.size() > 1) {
for (int i = 0; i < wiresGroups.size() - 1; i++) {
Integer integer = wiresGroups.get(i);
int x1 = integer == 0 ? 0 : endPoint(integer - 1, wiresGroups);
if (x1 > 0) {
x1 -= ourInterRepoLineWidth/2 + 1;
}
graphics.drawLine(x1, 0, x1, height);
}
}
}
private int startPoint(int correctedWire, List<Integer> wiresGroups) {
return correctedWire == 0 ? ourIndent : endPoint(correctedWire - 1, wiresGroups);
}
}
}
@@ -37,6 +37,7 @@ public class SkeletonBuilder {
// !! can intersect with existing, but own lifecycle
private final BidirectionalMap<Integer, AbstractHash> myFutureSeizedWires;
private final Convertor<Integer,List<Integer>> myFutureConvertor;
private int myMaxWireNum;
public SkeletonBuilder(WireEventsListener treeNavigation) {
mySkeleton = treeNavigation;
@@ -53,6 +54,7 @@ public class SkeletonBuilder {
return getFutureWireStarts(o);
}
};
myMaxWireNum = 0;
}
public void consume(final CommitI commitI, final List<AbstractHash> parents, final ReadonlyList<CommitI> commits, final int rowCount) {
@@ -84,7 +86,6 @@ public class SkeletonBuilder {
}
final CommitI waitingI = commits.get(waiting.myIdx);
//waiting.parentFound();
if (waiting.isMerge()) {
// put/update start event - now we know index so can create/update wire event
@@ -96,18 +97,6 @@ public class SkeletonBuilder {
if (seized != null && seized == waiting.myIdx && waitingI.getWireNumber() != wireNumber && something == null) {
// return
willReturnTheirWires.add(waiting);
/*if (wireNumber == -1) { // if this commit still doesn't have wire
// there is no other commits on the wire after parent -> use it
wireNumber = waitingI.getWireNumber();
}
else {
// if there are no other children of that commit. wire dies
if (waiting.allParentsFound()) {
myRing.back(waitingI.getWireNumber());
// end of waiting commits' wire
mySkeleton.parentWireEnds(rowCount, waiting.myIdx);
}
}*/
}
}
@@ -121,7 +110,6 @@ public class SkeletonBuilder {
// event about branch!
if (awaitingList.size() > 1) {
// merge event
//mySkeleton.parentWireEnds(); // fix?
final int[] ends = new int[awaitingList.size()];
for (int i = 0; i < awaitingList.size(); i++) {
final WaitingItem waiting = awaitingList.get(i);
@@ -138,12 +126,10 @@ public class SkeletonBuilder {
}
// register what we choose
if (mySeizedWires.containsValue(rowCount) && mySeizedWires.getKeysByValue(rowCount).iterator().next() != wireNumber) {
System.out.println("caught on adding!");
}
mySeizedWires.put(wireNumber, rowCount);
commitI.setWireNumber(wireNumber);
myMaxWireNum = Math.max(myMaxWireNum, myRing.getMaxNumber());
if (parents.isEmpty()) {
// end event
mySkeleton.wireEnds(rowCount);
@@ -178,64 +164,11 @@ public class SkeletonBuilder {
}
}
}
public void oldBecameNew(final Map<Integer, Integer> map) {
final MultiMap<Integer, WaitingItem> backCopy = new MultiMap<Integer, WaitingItem>();
backCopy.putAllValues(myBackIndex);
myBackIndex.clear();
for (Map.Entry<Integer, Collection<WaitingItem>> entry : backCopy.entrySet()) {
Integer key = map.get(entry.getKey());
Collection<WaitingItem> items = entry.getValue();
if (key == null) {
key = entry.getKey();
}
else {
for (WaitingItem item : items) {
item.myIdx = key;
}
}
myBackIndex.put(key, items);
}
// seized
BidirectionalMap<Integer, Integer> copy = new BidirectionalMap<Integer, Integer>();
copy.putAll(mySeizedWires);
mySeizedWires.clear();
for (Integer oldIdx : copy.values()) {
List<Integer> wires = copy.getKeysByValue(oldIdx);
if (wires == null || wires.size() != 1) {
System.out.println("www");
}
assert (wires != null && wires.size() == 1);
Integer newIdx = map.get(oldIdx);
newIdx = newIdx == null ? oldIdx : newIdx;
mySeizedWires.put(wires.get(0), newIdx);
}
public int getMaxWireNum() {
return myMaxWireNum;
}
/*public void oldBecameNew(int was, int is) {
Collection<WaitingItem> removed = myBackIndex.remove(was);
if (removed != null) {
for (WaitingItem commit : removed) {
commit.myIdx = is;
}
myBackIndex.put(is, removed);
}
List<Integer> keysByValue = mySeizedWires.getKeysByValue(was);
if (keysByValue != null && ! keysByValue.isEmpty()) {
if (keysByValue.size() > 1) {
System.out.println("Ooops!");
}
assert keysByValue.size() == 1; // each commit only on one wire
mySeizedWires.remove(was);
int value = keysByValue.get(0);
mySeizedWires.put(value, is);
}
}*/
// just some order
private static class CommitsComparator implements Comparator<WaitingItem> {
private final static CommitsComparator ourInstance = new CommitsComparator();
@@ -274,39 +207,6 @@ public class SkeletonBuilder {
}
}
private static class WaitingCommit {
private int myIdx; // id of commit that's wait for parents (self)
private int myNumParents; // i.e. a start
private final boolean myIsMerge;
private int myWire;
private WaitingCommit(int idx, int numParents) {
myIdx = idx;
myNumParents = numParents;
myIsMerge = myNumParents > 1;
}
public boolean isMerge() {
return myIsMerge;
}
public void parentFound() {
-- myNumParents;
}
public boolean allParentsFound() {
return myNumParents == 0;
}
public int getWire() {
return myWire;
}
public void setWire(int wire) {
myWire = wire;
}
}
public List<Integer> getFutureWireStarts(final int idx) {
Collection<WaitingItem> waitingItems = myBackIndex.get(idx);
if (waitingItems == null || waitingItems.isEmpty()) return Collections.emptyList();
@@ -12,10 +12,8 @@
*/
package git4idea.history.wholeTree;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.Ring;
import com.intellij.util.Consumer;
import com.intellij.util.containers.BidirectionalMap;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.ReadonlyList;
@@ -33,15 +31,12 @@ public class TreeNavigationImpl implements TreeNavigation, WireEventsListener {
private final int myCommitIndexInterval;
// maximum number of wire events, after which index entry should be written
private final int myNumWiresInGroup;
private int myMaximumWires;
public TreeNavigationImpl(final int commitIndexInterval, final int numWiresInGroup) {
myCommitIndexInterval = commitIndexInterval;
myNumWiresInGroup = numWiresInGroup;
myWireEvents = new TreeMap<Integer, WireEvent>();
myRingIndex = new TreeMap<Integer, RingIndex>();
myMaximumWires = 0;
}
public void recalcIndex(final ReadonlyList<CommitI> commits, final Convertor<Integer, List<Integer>> future) {
@@ -85,19 +80,12 @@ public class TreeNavigationImpl implements TreeNavigation, WireEventsListener {
}
}
// todo write start immediately in event in form of hash
// todo to be able to get it here, when building index
// todo: problem: when doing index, we don't have "future commits" wires!
private void performOnRing(final Ring<Integer> ring, final WireEvent event, final ReadonlyList<CommitI> convertor,
List<Integer> futureWireStarts) {
final int[] wireEnds = event.getWireEnds();
if (wireEnds != null) {
for (int wireEnd : wireEnds) {
int wireNumber = convertor.get(wireEnd).getWireNumber();
if (ring.haveInFree(wireNumber)) {
System.out.println("assertion will rise here, commits size: " + convertor.getSize() + " event idx: " + event.getCommitIdx());
}
//System.out.println("back(1): " + wireNumber + " from: " + event.getCommitIdx());
ring.back(wireNumber);
}
}
@@ -121,7 +109,6 @@ public class TreeNavigationImpl implements TreeNavigation, WireEventsListener {
for (Integer wireStart : futureWireStarts) {
ring.minus(wireStart);
}
myMaximumWires = Math.max(myMaximumWires, ring.getMaxNumber());
}
public Collection<WireEvent> getTail(int rowInclusive) {
@@ -149,15 +136,16 @@ public class TreeNavigationImpl implements TreeNavigation, WireEventsListener {
if (entry.getKey() == row) {
return ring;
}
System.out.println("-----------------> row = " + row);
//System.out.println("-----------------> row = " + row);
final Iterator<WireEvent> iterator = createWireEventsIterator(entry.getKey());
while (iterator.hasNext()) {
final WireEvent event = iterator.next();
if (event.getCommitIdx() >= row) {
return ring;
}
System.out.println("event: " + event.toString());
System.out.println("ring before: " + ring.toString());
// System.out.println("event: " + event.toString());
// System.out.println("ring before: " + ring.toString());
//if (event.getCommitIdx() == entry.getKey()) continue;
performOnRing(ring, event, commits, future.convert(event.getCommitIdx()));
}
return ring;
@@ -306,10 +294,6 @@ public class TreeNavigationImpl implements TreeNavigation, WireEventsListener {
myMaximumWires = Math.max(myMaximumWires, ring.getMaxNumber());
}*/
public int getMaximumWires() {
return myMaximumWires;
}
private void recountFragmentZwichem(ReadonlyList<CommitI> commits,
Map<Integer, Integer> recalculateMap,
int runningCommitNumber,
@@ -53,6 +53,14 @@ public class WireEvent {
}
}
public void setWireEnds(@Nullable int[] wireEnds) {
myWireEnds = wireEnds;
}
public void setCommitsStarts(int[] commitsStarts) {
myCommitsStarts = commitsStarts;
}
@Nullable
public int[] getWireEnds() {
return myWireEnds;
@@ -0,0 +1,34 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.history.wholeTree;
import java.util.Iterator;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/20/11
* Time: 11:49 AM
* To change this template use File | Settings | File Templates.
*/
public interface WireEventsIterator {
Integer getFloor();
Iterator<WireEvent> getWireEventsIterator();
List<Integer> getFirstUsed();
}
@@ -0,0 +1,102 @@
/*
* Copyright 2000-2011 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.tests;
import com.intellij.openapi.vcs.BigArray;
import com.intellij.openapi.vcs.ComparableComparator;
import com.intellij.openapi.vcs.GroupingMerger;
import junit.framework.Assert;
import junit.framework.TestCase;
import java.util.HashMap;
import java.util.Map;
/**
* Created by IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/19/11
* Time: 3:16 PM
*/
public class GroupingMergerTest extends TestCase {
public void testSimple() throws Exception {
final Map<Integer, Integer> recalculation = new HashMap<Integer, Integer>();
// 2nd - index
final Map<Integer, Integer> newInsertions = new HashMap<Integer, Integer>();
final GroupingMerger<Integer, String> merger = new GroupingMerger<Integer, String>() {
@Override
protected String getGroup(Integer integer) {
return "";
}
@Override
protected Integer wrapGroup(String s, Integer item) {
return -1;
}
@Override
protected void oldBecame(int was, int is) {
recalculation.put(was, is);
}
@Override
protected void afterConsumed(Integer integer, int i) {
newInsertions.put(integer, i);
}
};
final BigArray<Integer> main = new BigArray<Integer>(4);
main.add(10);
main.add(20);
main.add(30);
main.add(40);
main.add(50);
main.add(60);
main.add(70);
main.add(80);
main.add(90);
main.add(100);
main.add(110);
final BigArray<Integer> insert = new BigArray<Integer>(4);
insert.add(11);
insert.add(21);
insert.add(31);
insert.add(41);
insert.add(51);
insert.add(61);
insert.add(71);
insert.add(81);
insert.add(91);
insert.add(101);
insert.add(111);
merger.firstPlusSecond(main, insert, new ComparableComparator<Integer>(), -1);
int added = 1;
// 20-110
for (int i = 1; i <= 10; i++) {
final Integer integer = recalculation.get(i);
Assert.assertEquals(i + added, (int)integer);
++ added;
}
int startIdx = 1;
for (int i = 11; i <= 111; i+=10) {
Assert.assertEquals(startIdx, (int)newInsertions.get(i));
startIdx += 2;
}
}
}
@@ -441,14 +441,19 @@ public class GradleModulesImporter {
GradleLog.LOG.warn(String.format("Can't find %s of the library '%s' at path '%s'", pathType, gradleLibrary.getName(), path));
continue;
}
VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile);
if (jarRoot == null) {
GradleLog.LOG.warn(String.format(
"Can't parse contents of the jar file at path '%s' for the library '%s''", path, gradleLibrary.getName()
));
continue;
if (virtualFile.isDirectory()) {
model.addRoot(virtualFile, pathType.getRootType());
}
else {
VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile);
if (jarRoot == null) {
GradleLog.LOG.warn(String.format(
"Can't parse contents of the jar file at path '%s' for the library '%s''", path, gradleLibrary.getName()
));
continue;
}
model.addRoot(jarRoot, pathType.getRootType());
}
model.addRoot(jarRoot, pathType.getRootType());
}
}
}
@@ -35,22 +35,12 @@ public abstract class AbstractGradleDependency extends AbstractGradleEntity impl
@Override
public int hashCode() {
int result = myScope.hashCode();
result = 31 * result + (myExported ? 1 : 0);
return result;
return 31;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AbstractGradleDependency that = (AbstractGradleDependency)o;
if (myExported != that.myExported) return false;
if (myScope != that.myScope) return false;
return true;
return this == o || (o != null && getClass() == o.getClass());
}
@Override
@@ -17,6 +17,7 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.packaging.artifacts.ModifiableArtifactModel;
import com.intellij.projectImport.ProjectImportBuilder;
import org.jetbrains.annotations.NotNull;
@@ -27,6 +28,7 @@ import org.jetbrains.plugins.gradle.importing.model.GradleModule;
import org.jetbrains.plugins.gradle.importing.model.GradleProject;
import org.jetbrains.plugins.gradle.remote.GradleApiFacadeManager;
import org.jetbrains.plugins.gradle.remote.GradleProjectResolver;
import org.jetbrains.plugins.gradle.remote.GradleApiException;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleIcons;
import org.jetbrains.plugins.gradle.util.GradleLog;
@@ -157,14 +159,21 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
}
catch (Exception e) {
Throwable unwrapped = RemoteUtil.unwrap(e);
String reason = unwrapped.getLocalizedMessage();
if (!StringUtil.isEmpty(reason)) {
errorReason.set(reason);
}
if (unwrapped.getClass() == NoClassDefFoundError.class) {
errorReason.set(GradleBundle.message("gradle.import.text.incomplete.tooling.api"));
}
else if (unwrapped.getClass() == GradleApiException.class) {
GradleLog.LOG.warn("Can't resolve gradle project. Reason: gradle api threw an exception:\n"
+ ((GradleApiException)unwrapped).getOriginalReason()
);
}
else {
errorReason.set(unwrapped.getLocalizedMessage());
GradleLog.LOG.warn("Can't resolve gradle project", e);
}
// Ignore here because it will be reported on method exit.
GradleLog.LOG.warn("Can't resolve gradle project", e);
}
}
});
@@ -0,0 +1,85 @@
package org.jetbrains.plugins.gradle.remote;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* We talk to Gradle API from the dedicated process, i.e. all gradle classes are loaded at that process in order to avoid
* memory problems at IJ process. That means that if Gradle API throws an exception, it can't be correctly read at IJ process
* (NoClassDefFoundError and ClassNotFoundException).
* <p/>
* This class allows to extract textual description of the target problem and deliver it for further processing without risking to
* get the problems mentioned above. I.e. it doesn't require anything specific can be safely delivered to IJ process then.
*
* @author Denis Zhdanov
* @since 10/21/11 11:42 AM
*/
public class GradleApiException extends RuntimeException {
private static final long serialVersionUID = 1L;
private final String myOriginalReason;
public GradleApiException() {
this(null, null);
}
public GradleApiException(@Nullable String message) {
this(message, null);
}
public GradleApiException(@Nullable Throwable cause) {
this("", cause);
}
public GradleApiException(@Nullable String message, @Nullable Throwable cause) {
super(extractMessage(message, cause));
if (cause == null) {
myOriginalReason = "";
return;
}
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
try {
cause.printStackTrace(printWriter);
}
finally {
printWriter.close();
}
myOriginalReason = stringWriter.toString();
}
/**
* @return textual description of the wrapped exception (if any); empty string otherwise
*/
@NotNull
public String getOriginalReason() {
return myOriginalReason;
}
@Override
public void printStackTrace(PrintWriter s) {
super.printStackTrace(s);
s.println(myOriginalReason);
}
@Override
public void printStackTrace(PrintStream s) {
super.printStackTrace(s);
s.println(myOriginalReason);
}
@Nullable
private static String extractMessage(@Nullable String message, @Nullable Throwable cause) {
if (message != null) {
return message;
}
return cause == null ? "" : cause.getMessage();
}
}
@@ -43,6 +43,7 @@ import java.nio.charset.Charset;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -131,6 +132,13 @@ public class GradleApiFacadeManager {
params.setMainClass(MAIN_CLASS_NAME);
params.getVMParametersList().addParametersString("-Djava.awt.headless=true -Xmx512m");
// It may take a while for gradle api to resolve external dependencies. Default RMI timeout
// is 15 seconds (http://download.oracle.com/javase/1.4.2/docs/guide/rmi/sunrmiproperties.html#connectionTimeout),
// we don't want to get EOFException because of that.
params.getVMParametersList().addParametersString(
"-Dsun.rmi.transport.connectionTimeout=" + String.valueOf(TimeUnit.HOURS.toMillis(1))
);
//params.getVMParametersList().addParametersString("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5009");
return params;
}
@@ -25,11 +25,12 @@ public interface GradleProjectResolver extends Remote {
* @param downloadLibraries flag that specifies if third-party libraries that are not available locally should be resolved (downloaded)
* @return object-level representation of the target gradle project
* @throws RemoteException in case of unexpected exception during remote communications
* @throws GradleApiException in case of unexpected exception thrown from Gradle API
* @throws IllegalArgumentException if given path doesn't point to directory that contains gradle project or if gradle api
* returns invalid data
* @throws IllegalStateException if it's not possible to resolve target project info
*/
@NotNull
GradleProject resolveProjectInfo(@NotNull String projectPath, boolean downloadLibraries)
throws RemoteException, IllegalArgumentException, IllegalStateException;
throws RemoteException, GradleApiException, IllegalArgumentException, IllegalStateException;
}
@@ -0,0 +1,222 @@
package org.jetbrains.plugins.gradle.remote.impl;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.importing.model.GradleLibrary;
import org.jetbrains.plugins.gradle.importing.model.LibraryPathType;
import java.io.File;
import java.util.*;
/**
* Encapsulates logic of checking if particular collection of gradle libraries contains libraries with the same names and
* tries to diversify them in the case of the positive answer.
* <p/>
* Thread-safe.
*
* @author Denis Zhdanov
* @since 10/19/11 2:04 PM
*/
public class GradleLibraryNamesMixer {
/**
* Holds mappings like <code>('file name'; boolean)</code> where <code>'file name'</code> defines 'too common' file/dir
* name that should not be used during library name generation. Boolean flag indicates if 'common file name' may be used
* if 'non-common' files are the same.
* <p/>
* Example: consider the following file system tree:
* <pre>
* module
* |_src
* |_main
* | |_resources
* |
* |_test
* |_resources
* </pre>
* Let's say we have two libraries where one of them points to <code>'src/main/resources'</code> and another one
* to <code>'src/test/resources'</code>. We want to generate names <code>'module-resources'</code> and
* <code>'module-test-resources'</code> respectively because <code>'test'</code> entry at the current collection is
* stored with <code>'true'</code> flag.
*/
private static final Map<String, Boolean> NON_UNIQUE_PATH_ENTRIES = new HashMap<String, Boolean>();
static {
NON_UNIQUE_PATH_ENTRIES.put("src", false);
NON_UNIQUE_PATH_ENTRIES.put("main", false);
NON_UNIQUE_PATH_ENTRIES.put("test", true);
NON_UNIQUE_PATH_ENTRIES.put("resources", false);
NON_UNIQUE_PATH_ENTRIES.put("java", false);
NON_UNIQUE_PATH_ENTRIES.put("groovy", false);
}
private static final char NAME_SEPARATOR = '-';
/**
* Tries to ensure that given libraries have distinct names, i.e. traverses all of them and tries to generate
* unique name for those with equal names.
*
* @param libraries libraries to process
*/
@SuppressWarnings("MethodMayBeStatic")
public void mixNames(@NotNull Iterable<? extends GradleLibrary> libraries) {
Map<String, Wrapped> names = new HashMap<String, Wrapped>();
List<Wrapped> data = new ArrayList<Wrapped>();
for (GradleLibrary library : libraries) {
Wrapped wrapped = new Wrapped(library);
data.add(wrapped);
}
boolean mixed = false;
while (!mixed) {
mixed = doMixNames(data, names);
}
}
/**
* Does the same as {@link #mixNames(Iterable)} but uses given <code>('library name; wrapped library'}</code> mappings cache.
*
* @param libraries libraries to process
* @param cache cache to use
* @return <code>true</code> if all of the given libraries have distinct names now; <code>false</code> otherwise
*/
private static boolean doMixNames(@NotNull Collection<Wrapped> libraries, @NotNull Map<String, Wrapped> cache) {
cache.clear();
for (Wrapped current : libraries) {
Wrapped previous = cache.remove(current.library.getName());
if (previous == null) {
cache.put(current.library.getName(), current);
}
else {
mixNames(current, previous);
return current.library.getName().equals(previous.library.getName()); // Stop processing if it's not possible to generate
}
}
return true;
}
/**
* Tries to generate distinct names for the given wrapped libraries (assuming that they have equal names at the moment).
*
* @param wrapped1 one of the libraries with equal names
* @param wrapped2 another library which name is equal to the name of the given one
*/
@SuppressWarnings("AssignmentToForLoopParameter")
private static void mixNames(@NotNull Wrapped wrapped1, @NotNull Wrapped wrapped2) {
if (!wrapped1.prepare() || !wrapped2.prepare()) {
return;
}
String wrapped1AltText = null;
String wrapped2AltText = null;
for (File file1 = wrapped1.currentFile, file2 = wrapped2.currentFile;
file1 != null && file2 != null;
file1 = file1.getParentFile(), file2 = file2.getParentFile())
{
while (file1 != null && !StringUtil.isEmpty(file1.getName()) && NON_UNIQUE_PATH_ENTRIES.containsKey(file1.getName())) {
if (NON_UNIQUE_PATH_ENTRIES.get(file1.getName())) {
if (StringUtil.isEmpty(wrapped1AltText)) {
wrapped1AltText = file1.getName();
}
else {
wrapped1AltText += NAME_SEPARATOR + file1.getName();
}
}
file1 = file1.getParentFile();
}
while (file2 != null && !StringUtil.isEmpty(file2.getName()) && NON_UNIQUE_PATH_ENTRIES.containsKey(file2.getName())) {
if (NON_UNIQUE_PATH_ENTRIES.get(file2.getName())) {
if (StringUtil.isEmpty(wrapped2AltText)) {
wrapped2AltText = file2.getName();
}
else {
wrapped2AltText += NAME_SEPARATOR + file2.getName();
}
}
file2 = file2.getParentFile();
}
if (file1 == null) {
wrapped1.nextFile();
}
if (file2 == null) {
wrapped2.nextFile();
}
if (file1 != null && file2 != null && !file1.getName().equals(file2.getName())) {
wrapped1.library.setName(file1.getName() + NAME_SEPARATOR + wrapped1.library.getName());
wrapped2.library.setName(file2.getName() + NAME_SEPARATOR + wrapped2.library.getName());
}
if (wrapped1.library.getName().equals(wrapped2.library.getName())) {
if (wrapped1AltText != null) {
diversifyName(wrapped1AltText, wrapped1, file1);
return;
}
else if (wrapped2AltText != null) {
diversifyName(wrapped2AltText, wrapped2, file1);
return;
}
}
else {
return;
}
if (file1 == null || file2 == null) {
return;
}
}
}
@SuppressWarnings("ConstantConditions")
private static void diversifyName(@NotNull String changeText, @NotNull Wrapped wrapped, @Nullable File file) {
String name = wrapped.library.getName();
int i = file == null ? - 1 : name.indexOf(file.getName());
final String newName;
if (i >= 0) {
newName = name.substring(0, i + file.getName().length()) + NAME_SEPARATOR + changeText + name.substring(i + file.getName().length());
}
else {
newName = changeText + NAME_SEPARATOR + name;
}
wrapped.library.setName(newName);
}
/**
* Wraps target library and hold auxiliary information required for the processing.
*/
private static class Wrapped {
/** Holds list of files that may be used for name generation. */
public final Set<File> files = new HashSet<File>();
/** File that was used for the current name generation. */
public File currentFile;
/** Target library. */
public GradleLibrary library;
Wrapped(@NotNull GradleLibrary library) {
this.library = library;
for (LibraryPathType pathType : LibraryPathType.values()) {
String path = library.getPath(pathType);
if (path != null) {
files.add(new File(path));
}
}
}
public boolean prepare() {
if (currentFile != null) {
return true;
}
return nextFile();
}
public boolean nextFile() {
if (files.isEmpty()) {
return false;
}
Iterator<File> iterator = files.iterator();
currentFile = iterator.next();
iterator.remove();
return true;
}
}
}
@@ -13,16 +13,13 @@ import org.gradle.tooling.model.idea.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.importing.model.*;
import org.jetbrains.plugins.gradle.remote.GradleProjectResolver;
import org.jetbrains.plugins.gradle.remote.RemoteGradleProcessSettings;
import org.jetbrains.plugins.gradle.remote.RemoteGradleService;
import org.jetbrains.plugins.gradle.remote.*;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleLog;
import org.jetbrains.plugins.gradle.util.GradleUtil;
import java.io.File;
import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -37,16 +34,25 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public class GradleProjectResolverImpl extends RemoteObject implements GradleProjectResolver, RemoteGradleService {
private static final Set<String> NON_UNIQUE_PATH_ENTRIES = new HashSet<String>(Arrays.asList(
"src", "main", "java", "test", "resources"
));
private final BlockingQueue<ProjectConnection> myConnections = new LinkedBlockingQueue<ProjectConnection>();
private final AtomicReference<RemoteGradleProcessSettings> mySettings = new AtomicReference<RemoteGradleProcessSettings>();
private final BlockingQueue<ProjectConnection> myConnections = new LinkedBlockingQueue<ProjectConnection>();
private final AtomicReference<RemoteGradleProcessSettings> mySettings = new AtomicReference<RemoteGradleProcessSettings>();
private final GradleLibraryNamesMixer myLibraryNamesMixer = new GradleLibraryNamesMixer();
@NotNull
@Override
public GradleProject resolveProjectInfo(@NotNull String projectPath, boolean downloadLibraries)
throws RemoteException, GradleApiException, IllegalArgumentException, IllegalStateException
{
try {
return doResolveProjectInfo(projectPath, downloadLibraries);
}
catch (Throwable e) {
throw new GradleApiException(e);
}
}
@NotNull
private GradleProject doResolveProjectInfo(@NotNull String projectPath, boolean downloadLibraries)
throws RemoteException, IllegalArgumentException, IllegalStateException
{
ProjectConnection connection = getConnection(projectPath);
@@ -58,7 +64,7 @@ public class GradleProjectResolverImpl extends RemoteObject implements GradlePro
// populating dependent module object.
Map<String, Pair<GradleModule, IdeaModule>> modules = createModules(project, result);
populateModules(modules.values(), result);
diversifyLibraryNamesIfNecessary(result);
myLibraryNamesMixer.mixNames(result.getLibraries());
return result;
}
@@ -315,46 +321,6 @@ public class GradleProjectResolverImpl extends RemoteObject implements GradlePro
return null;
}
/**
* Gradle API doesn't provide library names at the moment, so, we deduce them from the path. However, it's possible to have identical
* names then.
* <p/>
* This method solves that by diversifying duplicate library names.
*
* @param project target project which library names should be diversified if necessary
*/
private static void diversifyLibraryNamesIfNecessary(@NotNull GradleProject project) {
Map<String, GradleLibrary> libraries = new HashMap<String, GradleLibrary>();
for (GradleLibrary library : project.getLibraries()) {
GradleLibrary previous = libraries.remove(library.getName());
if (previous == null) {
libraries.put(library.getName(), library);
continue;
}
previous.setName(generateName(previous));
libraries.put(previous.getName(), previous);
library.setName(generateName(library));
libraries.put(library.getName(), library);
}
}
@NotNull
private static String generateName(@NotNull GradleLibrary library) {
for (LibraryPathType pathType : LibraryPathType.values()) {
String path = library.getPath(pathType);
if (path == null) {
continue;
}
File file = new File(path).getParentFile();
for (; file != null; file = file.getParentFile()) {
if (!NON_UNIQUE_PATH_ENTRIES.contains(file.getName())) {
return file.getName() + "-" + library.getName();
}
}
}
return library.getName();
}
/**
* Allows to retrieve gradle api connection to use for the given project.
*
@@ -0,0 +1,71 @@
package org.jetbrains.plugins.gradle.remote.impl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.importing.model.GradleLibrary;
import org.jetbrains.plugins.gradle.importing.model.LibraryPathType;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
/**
* @author Denis Zhdanov
* @since 10/19/11 5:25 PM
*/
public class GradleLibraryNamesMixerTest {
private GradleLibraryNamesMixer myMixer;
@Before
public void setUp() {
myMixer = new GradleLibraryNamesMixer();
}
@Test
public void sourceVsTest() {
doTest(
t("resources", "my-module-resources", "dir1/dir2/my-module/src/main/resources"),
t("resources", "my-module-test-resources", "dir1/dir2/my-module/src/test/resources"),
t("resources", "my-another-module-resources", "dir1/dir2/my-another-module/src/main/resources"),
t("resources", "my-another-module-test-resources", "dir1/dir2/my-another-module/src/test/resources")
);
}
private void doTest(TestDataEntry... entries) {
Map<GradleLibrary, String> expected = new IdentityHashMap<GradleLibrary, String>();
List<GradleLibrary> libraries = new ArrayList<GradleLibrary>();
for (TestDataEntry entry : entries) {
GradleLibrary library = new GradleLibrary(entry.initialName);
library.addPath(LibraryPathType.BINARY, entry.path);
libraries.add(library);
expected.put(library, entry.expectedName);
}
myMixer.mixNames(libraries);
for (GradleLibrary library : libraries) {
assertEquals(expected.get(library), library.getName());
}
}
private static class TestDataEntry {
public String initialName;
public String expectedName;
public String path;
TestDataEntry(@NotNull String initialName, @NotNull String expectedName, @NotNull String path) {
this.initialName = initialName;
this.expectedName = expectedName;
this.path = path;
}
}
public static TestDataEntry t(@NotNull String initialName, @NotNull String expectedName, @NotNull String path) {
return new TestDataEntry(initialName, expectedName, path);
}
}
@@ -105,8 +105,12 @@ public class GroovyDslExecutor {
return StringUtil.compareVersionNumbers(ideaVersion, ver) >= 0
}
else if (ver instanceof Map) {
def we = ver.ide?.intellij
return we != null && StringUtil.compareVersionNumbers(ideaVersion, we) >= 0
if (ver.dsl) {
return StringUtil.compareVersionNumbers('1.0', ver.dsl) >= 0
}
if (ver.intellij) {
return StringUtil.compareVersionNumbers(ideaVersion, ver.intellij) >= 0
}
}
return false
}
@@ -1,21 +1,19 @@
package org.jetbrains.plugins.groovy.extensions;
import com.intellij.openapi.extensions.AbstractExtensionPointBean;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiMethod;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.Property;
import com.intellij.util.xmlb.annotations.Tag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import java.util.*;
/**
* @author Sergey Evdokimov
*/
public class GroovyMethodDescriptor {
public class GroovyMethodDescriptor extends AbstractExtensionPointBean {
private static final String ATTR_NAMES_DELIMITER = " \t\n\r,;";
@@ -21,7 +21,8 @@ public class GroovyMethodInfo {
private static Map<String, Map<String, List<GroovyMethodInfo>>> LIGHT_METHOD_INFOS;
private final List<String> myParams;
private final ClassLoader myClassLoader;
private final String myReturnType;
private final String myReturnTypeCalculatorClassName;
private PairFunction<GrMethodCall, PsiMethod, PsiType> myReturnTypeCalculatorInstance;
@@ -121,6 +122,7 @@ public class GroovyMethodInfo {
}
public GroovyMethodInfo(GroovyMethodDescriptor method) {
myClassLoader = method.getLoaderForClass();
myParams = method.getParams();
myReturnType = method.returnType;
myReturnTypeCalculatorClassName = method.returnTypeCalculator;
@@ -177,7 +179,7 @@ public class GroovyMethodInfo {
@NotNull
public PairFunction<GrMethodCall, PsiMethod, PsiType> getReturnTypeCalculator() {
if (myReturnTypeCalculatorInstance == null) {
myReturnTypeCalculatorInstance = ClassInstanceCache.getInstance(myReturnTypeCalculatorClassName);
myReturnTypeCalculatorInstance = ClassInstanceCache.getInstance(myReturnTypeCalculatorClassName, myClassLoader);
}
return myReturnTypeCalculatorInstance;
}
@@ -193,7 +195,7 @@ public class GroovyMethodInfo {
public GroovyNamedArgumentProvider getNamedArgProvider() {
if (myNamedArgProviderInstance == null) {
myNamedArgProviderInstance = ClassInstanceCache.getInstance(myNamedArgProviderClassName);
myNamedArgProviderInstance = ClassInstanceCache.getInstance(myNamedArgProviderClassName, myClassLoader);
}
return myNamedArgProviderInstance;
}
@@ -183,8 +183,11 @@ public class DefaultHighlighter {
}
public static final TextAttributes MAP_KEY_ATTRIBUTES = HighlighterColors.TEXT.getDefaultAttributes().clone();
public static final Color MAP_KEY_COLOR = new Color(0, 128, 0);
static {
MAP_KEY_ATTRIBUTES.setForegroundColor(new Color(0, 128, 0));
MAP_KEY_ATTRIBUTES.setForegroundColor(MAP_KEY_COLOR);
}
public static TextAttributesKey UNRESOLVED_ACCESS = TextAttributesKey.createTextAttributesKey(UNRESOLVED_ACCESS_ID, UNRESOLVED_ACCESS_ATTRIBUTES);
public static TextAttributesKey LITERAL_CONVERSION = TextAttributesKey.createTextAttributesKey(LITERAL_CONVERSION_ID, LITERAL_CONVERSION_ATTRIBUTES);
@@ -33,7 +33,6 @@ import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.InheritanceUtil;
@@ -47,8 +46,6 @@ import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.GroovyIcons;
import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
@@ -271,30 +268,17 @@ public class GroovyCompletionUtil {
return setupLookupBuilder(element, substitutor, builder);
}
private static PsiMethod generateMethodInCategory(GroovyResolveResult result) {
final PsiElement element = result.getElement();
assert element instanceof PsiMethod;
final LightMethodBuilder builder = new LightMethodBuilder(element.getManager(), GroovyFileType.GROOVY_LANGUAGE, ((PsiMethod)element).getName());
final PsiParameter[] params = ((PsiMethod)element).getParameterList().getParameters();
for (int i = 1; i < params.length; i++) {
builder.addParameter(params[i]);
}
builder.setBaseIcon(GroovyIcons.METHOD);
return builder;
}
public static LookupElement getLookupElement(Object o) {
if (o instanceof LookupElement) return (LookupElement)o;
if (o instanceof PsiNamedElement) return generateLookupElement((PsiNamedElement)o);
if (o instanceof PsiElement) return setupLookupBuilder((PsiElement)o, PsiSubstitutor.EMPTY, LookupElementBuilder.create(o, ((PsiElement)o).getText()));
return LookupElementBuilder.create(o, o.toString());
return LookupElementBuilder.create(o, o.toString()).setItemTextUnderlined(true);
}
public static LookupElementBuilder generateLookupElement(PsiNamedElement element) {
LookupElementBuilder builder = LookupElementBuilder.create(element);
return setupLookupBuilder(element, PsiSubstitutor.EMPTY, builder);
private static LookupElementBuilder generateLookupElement(PsiNamedElement element) {
return setupLookupBuilder(element, PsiSubstitutor.EMPTY, LookupElementBuilder.create(element));
}
public static LookupElementBuilder setupLookupBuilder(PsiElement element, PsiSubstitutor substitutor, LookupElementBuilder builder) {
private static LookupElementBuilder setupLookupBuilder(PsiElement element, PsiSubstitutor substitutor, LookupElementBuilder builder) {
builder = builder.setIcon(element.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS))
.setInsertHandler(GroovyInsertHandler.INSTANCE);
builder = setTailText(element, builder, substitutor);
@@ -426,9 +410,10 @@ public class GroovyCompletionUtil {
}
//need to shorten references in type argument list
public static void shortenReference(final PsiFile file, final int offset) throws IncorrectOperationException {
private static void shortenReference(final PsiFile file, final int offset) throws IncorrectOperationException {
final PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject());
final Document document = manager.getDocument(file);
assert document != null;
manager.commitDocument(document);
final PsiReference ref = file.findReferenceAt(offset);
if (ref instanceof GrCodeReferenceElement) {
@@ -16,7 +16,6 @@
package org.jetbrains.plugins.groovy.lang.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.StandardPatterns;
@@ -26,6 +25,7 @@ import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.GroovyIcons;
import org.jetbrains.plugins.groovy.extensions.GroovyNamedArgumentProvider;
import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter;
import org.jetbrains.plugins.groovy.lang.completion.handlers.NamedArgumentInsertHandler;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
@@ -89,7 +89,8 @@ class MapArgumentCompletionProvider extends CompletionProvider<CompletionParamet
}
Map<String, GroovyNamedArgumentProvider.ArgumentDescriptor> map = calcNamedArgumentsForCall(mapOrArgumentList);
if (map.isEmpty()) {
boolean sure = !map.isEmpty();
if (!sure) {
map = findOtherNamedArgumentsInFile(mapOrArgumentList);
}
@@ -98,11 +99,16 @@ class MapArgumentCompletionProvider extends CompletionProvider<CompletionParamet
}
for (Map.Entry<String, GroovyNamedArgumentProvider.ArgumentDescriptor> entry : map.entrySet()) {
LookupElement lookup = LookupElementBuilder.create(entry.getValue(), entry.getKey())
.setIcon(GroovyIcons.DYNAMIC)
LookupElementBuilder lookup = LookupElementBuilder.create(entry.getValue(), entry.getKey())
.setInsertHandler(NamedArgumentInsertHandler.INSTANCE)
.setTailText(":");
if (sure) {
lookup = lookup.setIcon(GroovyIcons.DYNAMIC);
} else {
lookup = lookup.setItemTextForeground(DefaultHighlighter.MAP_KEY_COLOR);
}
result.addElement(lookup);
}
@@ -116,7 +122,9 @@ class MapArgumentCompletionProvider extends CompletionProvider<CompletionParamet
if (element instanceof GrArgumentLabel) {
final String name = ((GrArgumentLabel)element).getName();
if (GroovyNamesUtil.isIdentifier(name)) {
map.put(name, new GroovyNamedArgumentProvider.ArgumentDescriptor());
GroovyNamedArgumentProvider.ArgumentDescriptor descriptor = new GroovyNamedArgumentProvider.ArgumentDescriptor();
descriptor.setShowFirst(false);
map.put(name, descriptor);
}
}
super.visitElement(element);
@@ -1,33 +1,24 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.RecursionGuard;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.extensions.GroovyMethodInfo;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
/**
* @author Sergey Evdokimov
*/
public class GrDescriptorReturnTypeCalculator extends GrCallExpressionTypeCalculator {
private static final RecursionGuard ourGuard = RecursionManager.createGuard("GrDescriptorReturnTypeCalculator getClosureReturnType");
@Override
public PsiType calculateReturnType(@NotNull GrMethodCall callExpression, @NotNull PsiMethod method) {
for (GroovyMethodInfo methodInfo : GroovyMethodInfo.getInfos(method)) {
String returnType = methodInfo.getReturnType();
if (returnType != null) {
if (methodInfo.isApplicable(method)) {
return typeFromText(returnType, callExpression);
return JavaPsiFacade.getElementFactory(callExpression.getProject()).createTypeFromText(returnType, callExpression);
}
}
else {
@@ -44,34 +35,4 @@ public class GrDescriptorReturnTypeCalculator extends GrCallExpressionTypeCalcul
return null;
}
@Nullable
public static PsiType typeFromText(String typeName, GrMethodCall callExpression) {
if (typeName.equals("!closure")) {
GrExpression[] allArguments = PsiUtil.getAllArguments(callExpression);
GrClosableBlock closure = null;
for (GrExpression argument : allArguments) {
if (argument instanceof GrClosableBlock) {
closure = (GrClosableBlock)argument;
break;
}
}
if (closure == null) return null;
final GrClosableBlock finalClosure = closure;
return ourGuard.doPreventingRecursion(callExpression, true, new NullableComputable<PsiType>() {
@Override
public PsiType compute() {
PsiType returnType = finalClosure.getReturnType();
if (returnType == PsiType.VOID) return null;
return returnType;
}
});
}
return JavaPsiFacade.getElementFactory(callExpression.getProject()).createTypeFromText(typeName, callExpression);
}
}
@@ -1,7 +1,5 @@
package org.jetbrains.plugins.groovy.util;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.util.containers.ConcurrentHashMap;
import org.jetbrains.annotations.NotNull;
@@ -15,34 +13,16 @@ public class ClassInstanceCache {
private ClassInstanceCache() {
}
private static Object createInstance(@NotNull String className) {
try {
try {
return Class.forName(className).newInstance();
}
catch (ClassNotFoundException e) {
for (IdeaPluginDescriptor descriptor : PluginManager.getPlugins()) {
try {
return descriptor.getPluginClassLoader().loadClass(className).newInstance();
}
catch (ClassNotFoundException ignored) {
}
}
throw new RuntimeException("Class not found: " + className);
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public static <T> T getInstance(@NotNull String className) {
public static <T> T getInstance(@NotNull String className, ClassLoader classLoader) {
Object res = CACHE.get(className);
if (res == null) {
res = createInstance(className);
try {
res = classLoader.loadClass(className).newInstance();
}
catch (Exception e) {
throw new RuntimeException(e);
}
Object oldValue = CACHE.putIfAbsent(className, res);
if (oldValue != null) {
@@ -52,5 +32,4 @@ public class ClassInstanceCache {
return (T)res;
}
}
@@ -0,0 +1,67 @@
/*
* Copyright 2000-2011 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 org.jetbrains.plugins.groovy.util;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.RecursionGuard;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.util.PairFunction;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
/**
* @author Sergey Evdokimov
*/
public class GroovyStdTypeCalculators {
private static final RecursionGuard ourGuard = RecursionManager.createGuard("GrDescriptorReturnTypeCalculator getClosureReturnType");
private GroovyStdTypeCalculators() {
}
public static class ClosureTypeExtractor implements PairFunction<GrMethodCall, PsiMethod, PsiType> {
@Override
public PsiType fun(GrMethodCall methodCall, PsiMethod method) {
GrExpression[] allArguments = PsiUtil.getAllArguments(methodCall);
GrClosableBlock closure = null;
for (GrExpression argument : allArguments) {
if (argument instanceof GrClosableBlock) {
closure = (GrClosableBlock)argument;
break;
}
}
if (closure == null) return null;
final GrClosableBlock finalClosure = closure;
return ourGuard.doPreventingRecursion(methodCall, true, new NullableComputable<PsiType>() {
@Override
public PsiType compute() {
PsiType returnType = finalClosure.getReturnType();
if (returnType == PsiType.VOID) return null;
return returnType;
}
});
}
}
}
@@ -814,7 +814,7 @@ return foo()"""
public void testNamedArgsUsedInFile() throws Exception {
myFixture.configureByFile(getTestName(false) + ".groovy");
doVariantableTest 'foo1', 'foo2', 'foo3', 'foo4', 'foo5', 'false', 'float'
doVariantableTest 'foo2', 'false', 'float', 'foo1', 'foo3', 'foo4', 'foo5'
}
public void testSuggestMembersOfExpectedType() {
@@ -127,13 +127,13 @@ def doo() { println <warning>foo</warning> }
public void testSupportsVersion() {
checkHighlighting '''
if (supportsVersion(ide:[intellij:'9.0'])) {
if (supportsVersion(intellij:'9.0')) {
contribute(currentType("java.lang.String")) { property name:"foo" }
} else {
contribute(currentType("java.lang.String")) { property name:"bar" }
}
if (!supportsVersion(ide:[groovyEclipse:'9.0'])) {
if (!supportsVersion(groovyEclipse:'9.0')) {
contribute(currentType("java.lang.String")) { property name:"goo" }
}
''',
@@ -142,7 +142,15 @@ if (!supportsVersion(ide:[groovyEclipse:'9.0'])) {
public void testAssertVersion() {
checkHighlighting '''
assertVersion ide:[intellij:'9.0']
assertVersion dsl:'1.0'
contribute(currentType("java.lang.String")) { property name:"foo" }
''',
'println "".foo'
}
public void testAssertVersionDsl() {
checkHighlighting '''
assertVersion intellij:'9.0'
contribute(currentType("java.lang.String")) { property name:"foo" }
''',
'println "".foo'
@@ -150,7 +158,15 @@ contribute(currentType("java.lang.String")) { property name:"foo" }
public void testAssertVersionFail() {
checkHighlighting '''
assertVersion ide:[intellij:'239.0']
assertVersion intellij:'239.0'
contribute(currentType("java.lang.String")) { property name:"foo" }
''',
'println "".<warning>foo</warning>'
}
public void testAssertVersionFailDsl() {
checkHighlighting '''
assertVersion dsl:'239.0'
contribute(currentType("java.lang.String")) { property name:"foo" }
''',
'println "".<warning>foo</warning>'
@@ -357,6 +357,11 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
return myData.FORK_MODE;
}
@Override
public boolean collectOutputFromProcessHandler() {
return false;
}
public static class Data implements Cloneable {
public String PACKAGE_NAME;
private String DIR_NAME;
@@ -268,6 +268,7 @@ public abstract class TestObject implements JavaCommandLine {
public void notifyStart(TestProxy root) {
super.notifyStart(root);
unboundOutputRoot.addChild(root);
unboundOutputRoot.setOutputFilePath(myConfiguration.getOutputFilePath());
final JUnitRunningModel model = getModel();
if (model != null) {
handler.getOut().setDispatchListener(model.getNotifier());
+4 -4
View File
@@ -46,15 +46,15 @@
<referencesSearch implementation="com.intellij.psi.impl.search.PropertyReferenceViaLastWordSearcher"/>
<favoriteNodeProvider implementation="com.intellij.ide.favoritesTreeView.ResourcesFavoriteNodeProvider"/>
<localInspection shortName="UnusedProperty" bundle="messages.PropertiesBundle" key="unused.property.inspection.display.name"
groupKey="properties.files.inspection.group.display.name" enabledByDefault="false" level="WARNING"
<localInspection language="Properties" shortName="UnusedProperty" bundle="messages.PropertiesBundle" key="unused.property.inspection.display.name"
groupKey="properties.files.inspection.group.display.name" enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.lang.properties.UnusedPropertyInspection"/>
<globalInspection shortName="DuplicatePropertyInspection" bundle="messages.InspectionsBundle" key="duplicate.property.display.name"
groupKey="group.names.internationalization.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.intellij.codeInspection.duplicatePropertyInspection.DuplicatePropertyInspection"/>
<localInspection shortName="TrailingSpacesInProperty" bundle="messages.PropertiesBundle"
<localInspection language="Properties" shortName="TrailingSpacesInProperty" bundle="messages.PropertiesBundle"
key="trail.spaces.property.inspection.display.name" groupKey="properties.files.inspection.group.display.name"
enabledByDefault="false" level="WARNING"
enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.lang.properties.TrailingSpacesInPropertyInspection"/>
<idIndexer filetype="Properties" implementationClass="com.intellij.psi.impl.cache.impl.idCache.PropertiesIdIndexer"/>
+7 -7
View File
@@ -15,22 +15,22 @@
<psi.referenceContributor language="JAVA" implementation="com.theoryinpractice.testng.TestNGReferenceContributor"/>
<psi.referenceContributor language="XML" implementation="com.theoryinpractice.testng.TestNGSuiteReferenceContributor"/>
<localInspection shortName="JUnitTestNG" displayName="Convert JUnit Tests to TestNG" groupName="TestNG" enabledByDefault="false"
<localInspection language="JAVA" shortName="JUnitTestNG" displayName="Convert JUnit Tests to TestNG" groupName="TestNG" enabledByDefault="false"
level="WARNING" implementationClass="com.theoryinpractice.testng.inspection.JUnitConvertTool"/>
<localInspection shortName="ConvertOldAnnotations" displayName="Convert old @Configuration TestNG annotations" groupName="TestNG"
<localInspection language="JAVA" shortName="ConvertOldAnnotations" displayName="Convert old @Configuration TestNG annotations" groupName="TestNG"
enabledByDefault="false" level="WARNING"
implementationClass="com.theoryinpractice.testng.inspection.ConvertOldAnnotationInspection"/>
<localInspection shortName="ConvertJavadoc" displayName="Convert TestNG Javadoc to 1.5 annotations" groupName="TestNG"
<localInspection language="JAVA" shortName="ConvertJavadoc" displayName="Convert TestNG Javadoc to 1.5 annotations" groupName="TestNG"
enabledByDefault="false" level="WARNING"
implementationClass="com.theoryinpractice.testng.inspection.ConvertJavadocInspection"/>
<localInspection shortName="ConvertAnnotations" displayName="Convert TestNG annotations to javadocs" groupName="TestNG"
<localInspection language="JAVA" shortName="ConvertAnnotations" displayName="Convert TestNG annotations to javadocs" groupName="TestNG"
enabledByDefault="false" level="WARNING"
implementationClass="com.theoryinpractice.testng.inspection.ConvertAnnotationInspection"/>
<localInspection shortName="dependsOnMethodTestNG" displayName="dependsOnMethods problem" groupName="TestNG" enabledByDefault="true"
<localInspection language="JAVA" shortName="dependsOnMethodTestNG" displayName="dependsOnMethods problem" groupName="TestNG" enabledByDefault="true"
level="WARNING" implementationClass="com.theoryinpractice.testng.inspection.DependsOnMethodInspection"/>
<localInspection shortName="groupsTestNG" displayName="Groups problem" groupName="TestNG" enabledByDefault="true" level="WARNING"
<localInspection language="JAVA" shortName="groupsTestNG" displayName="Groups problem" groupName="TestNG" enabledByDefault="true" level="WARNING"
implementationClass="com.theoryinpractice.testng.inspection.DependsOnGroupsInspection"/>
<localInspection shortName="UndeclaredTests" displayName="Undeclared test" groupName="TestNG" enabledByDefault="false" level="WARNING"
<localInspection language="JAVA" shortName="UndeclaredTests" displayName="Undeclared test" groupName="TestNG" enabledByDefault="false" level="WARNING"
implementationClass="com.theoryinpractice.testng.inspection.UndeclaredTestInspection"/>
<intentionAction>
@@ -421,4 +421,9 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
}
return null;
}
@Override
public boolean collectOutputFromProcessHandler() {
return false;
}
}
@@ -170,6 +170,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
@Override
public void startNotified(final ProcessEvent event) {
TestNGRemoteListener listener = new TestNGRemoteListener(console, unboundOutputRoot);
unboundOutputRoot.setOutputFilePath(config.getOutputFilePath());
client.prepareListening(listener, port);
mySearchForTestIndicator = new BackgroundableProcessIndicator(task) {
@Override
@@ -83,15 +83,15 @@
<codeInsight.parameterInfo language="XPath" implementationClass="org.intellij.lang.xpath.XPathParameterInfoHandler" />
<fileTypeFactory implementation="org.intellij.lang.xpath.XPathSupportLoader" />
<localInspection shortName="CheckNodeTest" displayName="Check Node Test" groupName="XPath" enabledByDefault="true" level="WARNING"
<localInspection language="XPath" shortName="CheckNodeTest" displayName="Check Node Test" groupName="XPath" enabledByDefault="true" level="WARNING"
implementationClass="org.intellij.lang.xpath.validation.inspections.CheckNodeTest"/>
<localInspection shortName="ImplicitTypeConversion" displayName="Implicit Type Conversion" groupName="XPath" enabledByDefault="true"
<localInspection language="XPath" shortName="ImplicitTypeConversion" displayName="Implicit Type Conversion" groupName="XPath" enabledByDefault="true"
level="WARNING" implementationClass="org.intellij.lang.xpath.validation.inspections.ImplicitTypeConversion"/>
<localInspection shortName="RedundantTypeConversion" displayName="Redundant Type Conversion" groupName="XPath" enabledByDefault="true"
<localInspection language="XPath" shortName="RedundantTypeConversion" displayName="Redundant Type Conversion" groupName="XPath" enabledByDefault="true"
level="WARNING" implementationClass="org.intellij.lang.xpath.validation.inspections.RedundantTypeConversion"/>
<localInspection shortName="IndexZeroUsage" displayName="Use of index 0 in XPath predicates" groupName="XPath" enabledByDefault="true"
<localInspection language="XPath" shortName="IndexZeroUsage" displayName="Use of index 0 in XPath predicates" groupName="XPath" enabledByDefault="true"
level="WARNING" implementationClass="org.intellij.lang.xpath.validation.inspections.IndexZeroPredicate"/>
<localInspection shortName="HardwiredNamespacePrefix" displayName="Hardwired Namespace Prefix" groupName="XPath" enabledByDefault="true"
<localInspection language="XPath" shortName="HardwiredNamespacePrefix" displayName="Hardwired Namespace Prefix" groupName="XPath" enabledByDefault="true"
level="WARNING" implementationClass="org.intellij.lang.xpath.validation.inspections.HardwiredNamespacePrefix"/>
<quoteHandler fileType="XPath" className="org.intellij.lang.xpath.XPathQuoteHandler" />