mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote branch 'origin/master'
This commit is contained in:
@@ -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="&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);
|
||||
}
|
||||
|
||||
+17
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -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,
|
||||
|
||||
+2
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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
-1
@@ -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)
|
||||
|
||||
+15
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-7
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-12
@@ -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
|
||||
|
||||
+12
-3
@@ -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;
|
||||
}
|
||||
|
||||
+222
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-52
@@ -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.
|
||||
*
|
||||
|
||||
+71
@@ -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
|
||||
}
|
||||
|
||||
+2
-4
@@ -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);
|
||||
|
||||
+6
-21
@@ -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) {
|
||||
|
||||
+13
-5
@@ -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
-40
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -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());
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user