Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Kirill Kalishev
2010-05-20 19:19:29 +04:00
91 changed files with 1506 additions and 647 deletions
@@ -143,7 +143,6 @@ public class DfaUtil {
return codeBlock;
}
@Nullable("null means DFA analysis has failed (too complex to analyze)")
public static Collection<? extends PsiElement> getPossibleInitializationElements(final PsiElement qualifierExpression) {
if (qualifierExpression instanceof PsiMethodCallExpression) {
return Collections.singletonList(qualifierExpression);
@@ -152,8 +151,7 @@ public class DfaUtil {
final PsiElement targetElement = ((PsiReferenceExpression)qualifierExpression).resolve();
if (targetElement instanceof PsiVariable) {
final Collection<? extends PsiElement> variableValues = getCachedVariableValues((PsiVariable)targetElement, qualifierExpression);
if (variableValues == null) return null;
if (variableValues.isEmpty() && targetElement instanceof PsiField) {
if ((variableValues == null || variableValues.isEmpty())) {
return getVariableAssignmentsInFile((PsiVariable)targetElement, false);
}
return variableValues;
@@ -18,6 +18,7 @@ package com.intellij.ide;
import com.intellij.application.options.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.lang.Language;
import com.intellij.lang.StdLanguages;
import com.intellij.psi.codeStyle.CodeStyleCustomizationsConsumer;
import org.jetbrains.annotations.NotNull;
/**
@@ -44,6 +45,17 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
return GENERAL_CODE_SAMPLE;
}
@Override
public void customizeSpacingOptions(CodeStyleCustomizationsConsumer consumer) {
consumer.showAllStandardOptions();
}
@Override
public void customizeBlankLinesOptions(CodeStyleCustomizationsConsumer consumer) {
consumer.showAllStandardOptions();
}
private static final String GENERAL_CODE_SAMPLE = "public class Foo {\n" +
" public int[] X = new int[]{1, 3, 5 7, 9, 11};\n" +
"\n" +
@@ -24,6 +24,7 @@ import com.intellij.psi.impl.source.tree.Factory;
import com.intellij.psi.impl.source.tree.LeafElement;
import com.intellij.psi.impl.source.tree.SharedImplUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTagValue;
import com.intellij.psi.javadoc.PsiDocToken;
import com.intellij.psi.scope.PsiScopeProcessor;
@@ -50,7 +51,9 @@ public class PsiDocParamRef extends CompositePsiElement implements PsiDocTagValu
public PsiReference getReference() {
PsiReference cachedReference = myCachedReference;
if (cachedReference != null) return cachedReference;
final PsiDocCommentOwner owner = PsiTreeUtil.getParentOfType(this, PsiDocCommentOwner.class);
final PsiDocComment comment = PsiTreeUtil.getParentOfType(this, PsiDocComment.class);
if (comment == null) return null;
final PsiDocCommentOwner owner = comment.getOwner();
if (!(owner instanceof PsiMethod) &&
!(owner instanceof PsiClass)) return null;
final ASTNode valueToken = findChildByType(JavaDocTokenType.DOC_TAG_VALUE_TOKEN);
@@ -108,16 +108,16 @@ public interface ASTNode extends UserDataHolder {
ASTNode getLastChildNode();
/**
* Returns the previous sibling of this node in the tree.
* Returns the next sibling of this node in the tree.
*
* @return the previous sibling node.
* @return the next sibling node.
*/
ASTNode getTreeNext();
/**
* Returns the next sibling of this node in the tree.
* Returns the previous sibling of this node in the tree.
*
* @return the next sibling node.
* @return the previous sibling node.
*/
ASTNode getTreePrev();
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2010 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.psi.codeStyle;
import com.intellij.openapi.application.ApplicationBundle;
/**
* @author yole
*/
public interface CodeStyleCustomizationsConsumer {
void showAllStandardOptions();
void showStandardOptions(String... optionNames);
void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass, String fieldName, String optionName, String groupName);
String AROUND_OPERATORS = ApplicationBundle.message("group.spaces.around.operators");
String BEFORE_PARENTHESES = ApplicationBundle.message("group.spaces.before.parentheses");
String BEFORE_LEFT_BRACE = ApplicationBundle.message("group.spaces.before.left.brace");
String WITHIN_PARENTHESES = ApplicationBundle.message("group.spaces.within.parentheses");
String TERNARY_OPERATOR = ApplicationBundle.message("group.spaces.in.ternary.operator");
String TYPE_ARGUMENTS = ApplicationBundle.message("group.spaces.in.type.arguments");
String OTHER = ApplicationBundle.message("group.spaces.other");
}
@@ -44,4 +44,8 @@ public abstract class CodeStyleSettingsProvider {
public String getConfigurableDisplayName() {
return null;
}
public boolean hasSettingsPage() {
return true;
}
}
@@ -208,11 +208,13 @@ public class CodeStyleSchemesConfigurable extends SearchableConfigurable.Parent.
myPanels = new ArrayList<CodeStyleConfigurableWrapper>();
for (final CodeStyleSettingsProvider provider : Extensions.getExtensions(CodeStyleSettingsProvider.EXTENSION_POINT_NAME)) {
myPanels.add(new CodeStyleConfigurableWrapper(provider, new CodeStyleSettingsPanelFactory() {
public NewCodeStyleSettingsPanel createPanel(final CodeStyleScheme scheme) {
return new NewCodeStyleSettingsPanel(provider.createSettingsPage(scheme.getCodeStyleSettings(), ensureModel().getCloneSettings(scheme)));
}
}));
if (provider.hasSettingsPage()) {
myPanels.add(new CodeStyleConfigurableWrapper(provider, new CodeStyleSettingsPanelFactory() {
public NewCodeStyleSettingsPanel createPanel(final CodeStyleScheme scheme) {
return new NewCodeStyleSettingsPanel(provider.createSettingsPage(scheme.getCodeStyleSettings(), ensureModel().getCloneSettings(scheme)));
}
}));
}
}
return myPanels.toArray(new Configurable[myPanels.size()]);
@@ -16,34 +16,36 @@
package com.intellij.application.options.codeStyle;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleCustomizationsConsumer;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import com.intellij.ui.OptionGroup;
import javax.swing.*;
import java.awt.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.List;
public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPanel {
private JTextField myKeepBlankLinesInDeclarations;
private JTextField myKeepBlankLinesInCode;
private JTextField myBlankLinesBeforePackage;
private JTextField myBlankLinesAfterPackage;
private JTextField myBlankLinesBeforeImports;
private JTextField myBlankLinesAfterImports;
private JTextField myBlankLinesAroundClass;
private JTextField myBlankLinesAroundField;
private JTextField myBlankLinesAroundMethod;
private JTextField myBlankLinesBeforeMethodBody;
private JTextField myBlankLinesAroundFieldI;
private JTextField myBlankLinesAroundMethodI;
private JTextField myBlankLinesAfterClassHeader;
private JTextField myKeepBlankLinesBeforeRBrace;
public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPanel implements CodeStyleCustomizationsConsumer {
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.codeStyle.CodeStyleBlankLinesPanel");
private List<IntOption> myOptions = new ArrayList<IntOption>();
private Set<String> myAllowedOptions = new HashSet<String>();
private boolean myAllOptionsAllowed = false;
private final JPanel myPanel = new JPanel(new GridBagLayout());
public CodeStyleBlankLinesPanel(CodeStyleSettings settings) {
super(settings);
for(LanguageCodeStyleSettingsProvider provider: Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) {
provider.customizeBlankLinesOptions(this);
}
myPanel
.add(createKeepBlankLinesPanel(),
new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 4), 0, 0));
@@ -69,38 +71,17 @@ public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPane
private JPanel createBlankLinesPanel() {
OptionGroup optionGroup = new OptionGroup(ApplicationBundle.message("title.blank.lines"));
myBlankLinesBeforePackage = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.before.package.statement")), myBlankLinesBeforePackage);
myBlankLinesAfterPackage = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.after.package.statement")), myBlankLinesAfterPackage);
myBlankLinesBeforeImports = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.before.imports")), myBlankLinesBeforeImports);
myBlankLinesAfterImports = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.after.imports")), myBlankLinesAfterImports);
myBlankLinesAroundClass = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.around.class")), myBlankLinesAroundClass);
myBlankLinesAroundField = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.around.field")), myBlankLinesAroundField);
myBlankLinesAroundMethod = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.around.method")), myBlankLinesAroundMethod);
myBlankLinesBeforeMethodBody = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.before.method.body")), myBlankLinesBeforeMethodBody);
myBlankLinesAroundFieldI = createTextField();
optionGroup.add(new JLabel("Around field in interface:"), myBlankLinesAroundFieldI);
myBlankLinesAroundMethodI = createTextField();
optionGroup.add(new JLabel("Around method in interface:"), myBlankLinesAroundMethodI);
myBlankLinesAfterClassHeader = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.blanklines.after.class.header")), myBlankLinesAfterClassHeader);
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.before.package.statement"), "BLANK_LINES_BEFORE_PACKAGE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.package.statement"), "BLANK_LINES_AFTER_PACKAGE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.before.imports"), "BLANK_LINES_BEFORE_IMPORTS");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.imports"), "BLANK_LINES_AFTER_IMPORTS");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.around.class"), "BLANK_LINES_AROUND_CLASS");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.around.field"), "BLANK_LINES_AROUND_FIELD");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.around.method"), "BLANK_LINES_AROUND_METHOD");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.before.method.body"), "BLANK_LINES_BEFORE_METHOD_BODY");
createOption(optionGroup, "Around field in interface:", "BLANK_LINES_AROUND_FIELD_IN_INTERFACE");
createOption(optionGroup, "Around method in interface:", "BLANK_LINES_AROUND_METHOD_IN_INTERFACE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.class.header"), "BLANK_LINES_AFTER_CLASS_HEADER");
return optionGroup.createPanel();
}
@@ -108,97 +89,41 @@ public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPane
private JPanel createKeepBlankLinesPanel() {
OptionGroup optionGroup = new OptionGroup(ApplicationBundle.message("title.keep.blank.lines"));
myKeepBlankLinesInDeclarations = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.keep.blanklines.in.declarations")), myKeepBlankLinesInDeclarations);
myKeepBlankLinesInCode = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.keep.blanklines.in.code")), myKeepBlankLinesInCode);
myKeepBlankLinesBeforeRBrace = createTextField();
optionGroup.add(new JLabel(ApplicationBundle.message("editbox.keep.blanklines.before.rbrace")), myKeepBlankLinesBeforeRBrace);
createOption(optionGroup, ApplicationBundle.message("editbox.keep.blanklines.in.declarations"), "KEEP_BLANK_LINES_IN_DECLARATIONS");
createOption(optionGroup, ApplicationBundle.message("editbox.keep.blanklines.in.code"), "KEEP_BLANK_LINES_IN_CODE");
createOption(optionGroup, ApplicationBundle.message("editbox.keep.blanklines.before.rbrace"), "KEEP_BLANK_LINES_BEFORE_RBRACE");
return optionGroup.createPanel();
}
protected void resetImpl(final CodeStyleSettings settings) {
myKeepBlankLinesInDeclarations.setText(String.valueOf(settings.KEEP_BLANK_LINES_IN_DECLARATIONS));
myKeepBlankLinesInCode.setText(String.valueOf(settings.KEEP_BLANK_LINES_IN_CODE));
myKeepBlankLinesBeforeRBrace.setText(String.valueOf(settings.KEEP_BLANK_LINES_BEFORE_RBRACE));
myBlankLinesBeforePackage.setText(String.valueOf(settings.BLANK_LINES_BEFORE_PACKAGE));
myBlankLinesAfterPackage.setText(String.valueOf(settings.BLANK_LINES_AFTER_PACKAGE));
myBlankLinesBeforeImports.setText(String.valueOf(settings.BLANK_LINES_BEFORE_IMPORTS));
myBlankLinesAfterImports.setText(String.valueOf(settings.BLANK_LINES_AFTER_IMPORTS));
myBlankLinesAroundClass.setText(String.valueOf(settings.BLANK_LINES_AROUND_CLASS));
myBlankLinesAroundField.setText(String.valueOf(settings.BLANK_LINES_AROUND_FIELD));
myBlankLinesAroundMethod.setText(String.valueOf(settings.BLANK_LINES_AROUND_METHOD));
myBlankLinesBeforeMethodBody.setText(String.valueOf(settings.BLANK_LINES_BEFORE_METHOD_BODY));
myBlankLinesAroundFieldI.setText(String.valueOf(settings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE));
myBlankLinesAroundMethodI.setText(String.valueOf(settings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE));
myBlankLinesAfterClassHeader.setText(String.valueOf(settings.BLANK_LINES_AFTER_CLASS_HEADER));
private void createOption(OptionGroup optionGroup, String label, String fieldName) {
if (myAllOptionsAllowed || myAllowedOptions.contains(fieldName)) {
IntOption option = new IntOption(CodeStyleSettings.class, fieldName);
optionGroup.add(new JLabel(label), option.myTextField);
myOptions.add(option);
}
}
protected void resetImpl(final CodeStyleSettings settings) {
for (IntOption option : myOptions) {
option.setValue(option.getFieldValue(settings));
}
}
public void apply(CodeStyleSettings settings) {
settings.KEEP_BLANK_LINES_IN_DECLARATIONS = getValue(myKeepBlankLinesInDeclarations);
settings.KEEP_BLANK_LINES_IN_CODE = getValue(myKeepBlankLinesInCode);
settings.KEEP_BLANK_LINES_BEFORE_RBRACE = getValue(myKeepBlankLinesBeforeRBrace);
settings.BLANK_LINES_BEFORE_PACKAGE = getValue(myBlankLinesBeforePackage);
settings.BLANK_LINES_AFTER_PACKAGE = getValue(myBlankLinesAfterPackage);
settings.BLANK_LINES_BEFORE_IMPORTS = getValue(myBlankLinesBeforeImports);
settings.BLANK_LINES_AFTER_IMPORTS = getValue(myBlankLinesAfterImports);
settings.BLANK_LINES_AROUND_CLASS = getValue(myBlankLinesAroundClass);
settings.BLANK_LINES_AROUND_FIELD = getValue(myBlankLinesAroundField);
settings.BLANK_LINES_AROUND_METHOD = getValue(myBlankLinesAroundMethod);
settings.BLANK_LINES_BEFORE_METHOD_BODY = getValue(myBlankLinesBeforeMethodBody);
settings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE = getValue(myBlankLinesAroundFieldI);
settings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE = getValue(myBlankLinesAroundMethodI);
settings.BLANK_LINES_AFTER_CLASS_HEADER = getValue(myBlankLinesAfterClassHeader);
for (IntOption option : myOptions) {
option.setFieldValue(settings, option.getValue());
}
}
public boolean isModified(CodeStyleSettings settings) {
boolean isModified;
isModified = settings.KEEP_BLANK_LINES_IN_DECLARATIONS != getValue(myKeepBlankLinesInDeclarations);
isModified |= settings.KEEP_BLANK_LINES_IN_CODE != getValue(myKeepBlankLinesInCode);
isModified |= settings.KEEP_BLANK_LINES_BEFORE_RBRACE != getValue(myKeepBlankLinesBeforeRBrace);
isModified |= settings.BLANK_LINES_BEFORE_PACKAGE != getValue(myBlankLinesBeforePackage);
isModified |= settings.BLANK_LINES_AFTER_PACKAGE != getValue(myBlankLinesAfterPackage);
isModified |= settings.BLANK_LINES_BEFORE_IMPORTS != getValue(myBlankLinesBeforeImports);
isModified |= settings.BLANK_LINES_AFTER_IMPORTS != getValue(myBlankLinesAfterImports);
isModified |= settings.BLANK_LINES_AROUND_CLASS != getValue(myBlankLinesAroundClass);
isModified |= settings.BLANK_LINES_AROUND_FIELD != getValue(myBlankLinesAroundField);
isModified |= settings.BLANK_LINES_AROUND_METHOD != getValue(myBlankLinesAroundMethod);
isModified |= settings.BLANK_LINES_BEFORE_METHOD_BODY != getValue(myBlankLinesBeforeMethodBody);
isModified |= settings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE != getValue(myBlankLinesAroundFieldI);
isModified |= settings.BLANK_LINES_AROUND_METHOD_IN_INTERFACE != getValue(myBlankLinesAroundMethodI);
isModified |= settings.BLANK_LINES_AFTER_CLASS_HEADER != getValue(myBlankLinesAfterClassHeader);
return isModified;
}
private static int getValue(JTextField textField) {
int ret = 0;
try {
ret = Integer.parseInt(textField.getText());
if (ret < 0) {
ret = 0;
}
if (ret > 10) {
ret = 10;
for (IntOption option : myOptions) {
if (option.getFieldValue(settings) != option.getValue()) {
return true;
}
}
catch (NumberFormatException e) {
//bad number entered
}
return ret;
}
return false;
private static JTextField createTextField() {
JTextField field = new JTextField(6);
field.setMinimumSize(new Dimension(30, field.getMinimumSize().height));
return field;
}
protected int getRightMargin() {
@@ -212,4 +137,75 @@ public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPane
protected void prepareForReformat(final PsiFile psiFile) {
//psiFile.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, LanguageLevel.HIGHEST);
}
public void showAllStandardOptions() {
myAllOptionsAllowed = true;
}
public void showStandardOptions(String... optionNames) {
Collections.addAll(myAllowedOptions, optionNames);
}
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
String fieldName,
String optionName,
String groupName) {
throw new UnsupportedOperationException();
}
private static class IntOption {
private final JTextField myTextField;
private final Field myTarget;
private IntOption(Class targetClass, String fieldName) {
try {
myTarget = targetClass.getField(fieldName);
}
catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
myTextField = new JTextField(6);
myTextField.setMinimumSize(new Dimension(30, myTextField.getMinimumSize().height));
}
private int getFieldValue(CodeStyleSettings settings) {
try {
return myTarget.getInt(settings);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public void setFieldValue(CodeStyleSettings settings, int value) {
try {
myTarget.setInt(settings, value);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
}
private int getValue() {
int ret = 0;
try {
ret = Integer.parseInt(myTextField.getText());
if (ret < 0) {
ret = 0;
}
if (ret > 10) {
ret = 10;
}
}
catch (NumberFormatException e) {
//bad number entered
}
return ret;
}
public void setValue(int fieldValue) {
myTextField.setText(String.valueOf(fieldValue));
}
}
}
@@ -16,13 +16,24 @@
package com.intellij.application.options.codeStyle;
import com.intellij.openapi.application.ApplicationBundle;
//import com.intellij.openapi.editor.Editor;
//import com.intellij.openapi.editor.EditorSettings;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleCustomizationsConsumer;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NonNls;
import javax.swing.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel implements CodeStyleCustomizationsConsumer {
private boolean myShowAllStandardOptions = false;
private Set<String> myAllowedOptions;
private MultiMap<String, Trinity<Class<? extends CustomCodeStyleSettings>, String, String>> myCustomOptions;
public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
public CodeStyleSpacesPanel(CodeStyleSettings settings) {
super(settings);
}
@@ -32,15 +43,13 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
return LanguageCodeStyleSettingsProvider.SettingsType.SPACING_SETTINGS;
}
private static final String AROUND_OPERATORS = ApplicationBundle.message("group.spaces.around.operators");
private static final String BEFORE_PARENTHESES = ApplicationBundle.message("group.spaces.before.parentheses");
private static final String BEFORE_LEFT_BRACE = ApplicationBundle.message("group.spaces.before.left.brace");
private static final String WITHIN_PARENTHESES = ApplicationBundle.message("group.spaces.within.parentheses");
private static final String TERNARY_OPERATOR = ApplicationBundle.message("group.spaces.in.ternary.operator");
private static final String TYPE_ARGUMENTS = ApplicationBundle.message("group.spaces.in.type.arguments");
private static final String OTHER = ApplicationBundle.message("group.spaces.other");
protected void initTables() {
myAllowedOptions = new HashSet<String>();
myCustomOptions = new MultiMap<String, Trinity<Class<? extends CustomCodeStyleSettings>, String, String>>();
for(LanguageCodeStyleSettingsProvider provider: Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) {
provider.customizeSpacingOptions(this);
}
initBooleanField("SPACE_BEFORE_METHOD_CALL_PARENTHESES", ApplicationBundle.message("checkbox.spaces.method.call.parentheses"), BEFORE_PARENTHESES);
initBooleanField("SPACE_BEFORE_METHOD_PARENTHESES", ApplicationBundle.message("checkbox.spaces.method.declaration.parentheses"), BEFORE_PARENTHESES);
initBooleanField("SPACE_BEFORE_IF_PARENTHESES", ApplicationBundle.message("checkbox.spaces.if.parentheses"), BEFORE_PARENTHESES);
@@ -50,6 +59,7 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
initBooleanField("SPACE_BEFORE_SWITCH_PARENTHESES", ApplicationBundle.message("checkbox.spaces.switch.parentheses"), BEFORE_PARENTHESES);
initBooleanField("SPACE_BEFORE_SYNCHRONIZED_PARENTHESES", ApplicationBundle.message("checkbox.spaces.synchronized.parentheses"), BEFORE_PARENTHESES);
initBooleanField("SPACE_BEFORE_ANOTATION_PARAMETER_LIST", ApplicationBundle.message("checkbox.spaces.annotation.parameters"), BEFORE_PARENTHESES);
initCustomOptions(BEFORE_PARENTHESES);
initBooleanField("SPACE_AROUND_ASSIGNMENT_OPERATORS", ApplicationBundle.message("checkbox.spaces.assignment.operators"), AROUND_OPERATORS);
initBooleanField("SPACE_AROUND_LOGICAL_OPERATORS", ApplicationBundle.message("checkbox.spaces.logical.operators"), AROUND_OPERATORS);
@@ -59,6 +69,7 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
initBooleanField("SPACE_AROUND_ADDITIVE_OPERATORS", ApplicationBundle.message("checkbox.spaces.additive.operators"), AROUND_OPERATORS);
initBooleanField("SPACE_AROUND_MULTIPLICATIVE_OPERATORS", ApplicationBundle.message("checkbox.spaces.multiplicative.operators"), AROUND_OPERATORS);
initBooleanField("SPACE_AROUND_SHIFT_OPERATORS", ApplicationBundle.message("checkbox.spaces.shift.operators"), AROUND_OPERATORS);
initCustomOptions(AROUND_OPERATORS);
initBooleanField("SPACE_BEFORE_CLASS_LBRACE", ApplicationBundle.message("checkbox.spaces.class.left.brace"), BEFORE_LEFT_BRACE);
initBooleanField("SPACE_BEFORE_METHOD_LBRACE", ApplicationBundle.message("checkbox.spaces.method.left.brace"), BEFORE_LEFT_BRACE);
@@ -73,6 +84,7 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
initBooleanField("SPACE_BEFORE_FINALLY_LBRACE", ApplicationBundle.message("checkbox.spaces.finally.left.brace"), BEFORE_LEFT_BRACE);
initBooleanField("SPACE_BEFORE_SYNCHRONIZED_LBRACE", ApplicationBundle.message("checkbox.spaces.synchronized.left.brace"), BEFORE_LEFT_BRACE);
initBooleanField("SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE", ApplicationBundle.message("checkbox.spaces.array.initializer.left.brace"), BEFORE_LEFT_BRACE);
initCustomOptions(BEFORE_LEFT_BRACE);
initBooleanField("SPACE_WITHIN_PARENTHESES", ApplicationBundle.message("checkbox.spaces.parentheses"), WITHIN_PARENTHESES);
initBooleanField("SPACE_WITHIN_METHOD_CALL_PARENTHESES", ApplicationBundle.message("checkbox.spaces.checkbox.spaces.method.call.parentheses"), WITHIN_PARENTHESES);
@@ -85,15 +97,18 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
initBooleanField("SPACE_WITHIN_SYNCHRONIZED_PARENTHESES", ApplicationBundle.message("checkbox.spaces.synchronized.parentheses"), WITHIN_PARENTHESES);
initBooleanField("SPACE_WITHIN_CAST_PARENTHESES", ApplicationBundle.message("checkbox.spaces.type.cast.parentheses"), WITHIN_PARENTHESES);
initBooleanField("SPACE_WITHIN_ANNOTATION_PARENTHESES", ApplicationBundle.message("checkbox.spaces.annotation.parentheses"), WITHIN_PARENTHESES);
initCustomOptions(WITHIN_PARENTHESES);
initBooleanField("SPACE_BEFORE_QUEST", ApplicationBundle.message("checkbox.spaces.before.question"), TERNARY_OPERATOR);
initBooleanField("SPACE_AFTER_QUEST", ApplicationBundle.message("checkbox.spaces.after.question"), TERNARY_OPERATOR);
initBooleanField("SPACE_BEFORE_COLON", ApplicationBundle.message("checkbox.spaces.before.colon"), TERNARY_OPERATOR);
initBooleanField("SPACE_AFTER_COLON", ApplicationBundle.message("checkbox.spaces.after.colon"), TERNARY_OPERATOR);
initCustomOptions(TERNARY_OPERATOR);
initBooleanField("SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS", ApplicationBundle.message("checkbox.spaces.after.comma"), TYPE_ARGUMENTS);
initCustomOptions(TYPE_ARGUMENTS);
initBooleanField("SPACE_AFTER_LABEL", ApplicationBundle.message("checkbox.spaces.after.colon.in.label.declaration"), OTHER);
//TODO looks like this option is never implemented: initBooleanField("SPACE_AFTER_LABEL", ApplicationBundle.message("checkbox.spaces.after.colon.in.label.declaration"), OTHER);
initBooleanField("SPACE_WITHIN_BRACKETS", ApplicationBundle.message("checkbox.spaces.within.brackets"), OTHER);
initBooleanField("SPACE_WITHIN_ARRAY_INITIALIZER_BRACES", ApplicationBundle.message("checkbox.spaces.within.array.initializer.braces"), OTHER);
initBooleanField("SPACE_AFTER_COMMA", ApplicationBundle.message("checkbox.spaces.after.comma"), OTHER);
@@ -102,6 +117,13 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
initBooleanField("SPACE_BEFORE_SEMICOLON", ApplicationBundle.message("checkbox.spaces.before.semicolon"), OTHER);
initBooleanField("SPACE_AFTER_TYPE_CAST", ApplicationBundle.message("checkbox.spaces.after.type.cast"), OTHER);
initBooleanField("SPACE_AFTER_UNARY_OPERATOR", ApplicationBundle.message("checkbox.spaces.after.unary.operator"), OTHER);
initCustomOptions(OTHER);
}
private void initCustomOptions(String groupName) {
for(Trinity<Class<? extends CustomCodeStyleSettings>, String, String> option: myCustomOptions.get(groupName)) {
initCustomBooleanField(option.first, option.second, option.third, groupName);
}
}
/*
@@ -117,7 +139,30 @@ public class CodeStyleSpacesPanel extends OptionTreeWithPreviewPanel {
}
*/
@Override
protected void initBooleanField(@NonNls String fieldName, String cbName, String groupName) {
if (myShowAllStandardOptions || myAllowedOptions.contains(fieldName)) {
super.initBooleanField(fieldName, cbName, groupName);
}
}
public JComponent getPanel() {
return getInternalPanel();
}
public void showAllStandardOptions() {
myShowAllStandardOptions = true;
}
public void showStandardOptions(String... optionNames) {
Collections.addAll(myAllowedOptions, optionNames);
}
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
String fieldName,
String optionName,
String groupName) {
myCustomOptions.putValue(groupName,
Trinity.<Class<? extends CustomCodeStyleSettings>, String, String>create(settingsClass, fieldName, optionName));
}
}
@@ -18,6 +18,7 @@ package com.intellij.application.options.codeStyle;
import com.intellij.lang.Language;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.codeStyle.CodeStyleCustomizationsConsumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,6 +42,12 @@ public abstract class LanguageCodeStyleSettingsProvider {
public abstract String getCodeSample(@NotNull SettingsType settingsType);
public void customizeSpacingOptions(CodeStyleCustomizationsConsumer consumer) {
}
public void customizeBlankLinesOptions(CodeStyleCustomizationsConsumer consumer) {
}
public static Language[] getLanguagesWithCodeStyleSettings() {
ArrayList<Language> langs = new ArrayList<Language>();
for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(EP_NAME)) {
@@ -18,11 +18,12 @@ package com.intellij.application.options.codeStyle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.*;
@@ -40,7 +41,6 @@ import java.util.ArrayList;
public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleAbstractPanel {
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.CodeStyleSpacesPanel");
private final JTree myOptionsTree;
private final HashMap<BooleanOptionKey, Field> myKeyToFieldMap = new HashMap<BooleanOptionKey, Field>();
private final ArrayList<BooleanOptionKey> myKeys = new ArrayList<BooleanOptionKey>();
private final JPanel myPanel = new JPanel(new GridBagLayout());
@@ -144,7 +144,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
resetNode(root, settings);
}
private void resetNode(TreeNode node, final CodeStyleSettings settings) {
private static void resetNode(TreeNode node, final CodeStyleSettings settings) {
if (node instanceof MyToggleTreeNode) {
resetMyTreeNode((MyToggleTreeNode)node, settings);
return;
@@ -155,11 +155,10 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
}
}
private void resetMyTreeNode(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
private static void resetMyTreeNode(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
try {
BooleanOptionKey key = (BooleanOptionKey)childNode.getKey();
Field field = myKeyToFieldMap.get(key);
childNode.setSelected(field.getBoolean(settings));
childNode.setSelected(key.getValue(settings));
}
catch (IllegalArgumentException e) {
LOG.error(e);
@@ -175,7 +174,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
applyNode(root, settings);
}
private void applyNode(TreeNode node, final CodeStyleSettings settings) {
private static void applyNode(TreeNode node, final CodeStyleSettings settings) {
if (node instanceof MyToggleTreeNode) {
applyToggleNode((MyToggleTreeNode)node, settings);
return;
@@ -186,18 +185,9 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
}
}
private void applyToggleNode(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
try {
BooleanOptionKey key = (BooleanOptionKey)childNode.getKey();
Field field = myKeyToFieldMap.get(key);
field.set(settings, childNode.isSelected() ? Boolean.TRUE : Boolean.FALSE);
}
catch (IllegalArgumentException e) {
LOG.error(e);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
private static void applyToggleNode(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
BooleanOptionKey key = (BooleanOptionKey)childNode.getKey();
key.setValue(settings, childNode.isSelected() ? Boolean.TRUE : Boolean.FALSE);
}
public boolean isModified(CodeStyleSettings settings) {
@@ -210,7 +200,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
}
private boolean isModified(TreeNode node, final CodeStyleSettings settings) {
private static boolean isModified(TreeNode node, final CodeStyleSettings settings) {
if (node instanceof MyToggleTreeNode) {
if (isToggleNodeModified((MyToggleTreeNode)node, settings)) {
return true;
@@ -225,11 +215,10 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
return false;
}
private boolean isToggleNodeModified(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
private static boolean isToggleNodeModified(MyToggleTreeNode childNode, final CodeStyleSettings settings) {
try {
BooleanOptionKey key = (BooleanOptionKey)childNode.getKey();
Field field = myKeyToFieldMap.get(key);
return childNode.isSelected() != field.getBoolean(settings);
return childNode.isSelected() != key.getValue(settings);
}
catch (IllegalArgumentException e) {
LOG.error(e);
@@ -244,13 +233,27 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
try {
Class styleSettingsClass = CodeStyleSettings.class;
Field field = styleSettingsClass.getField(fieldName);
BooleanOptionKey key = new BooleanOptionKey(groupName, cbName);
myKeyToFieldMap.put(key, field);
BooleanOptionKey key = new BooleanOptionKey(groupName, cbName, field);
myKeys.add(key);
}
catch (NoSuchFieldException e) {
LOG.error(e);
}
catch (SecurityException e) {
LOG.error(e);
}
}
protected <T extends CustomCodeStyleSettings> void initCustomBooleanField(@NotNull Class<T> customClass, String fieldName, String cbName, String groupName) {
try {
Field field = customClass.getField(fieldName);
myKeys.add(new CustomBooleanOptionKey(groupName, cbName, customClass, field));
}
catch (NoSuchFieldException e) {
LOG.error(e);
}
catch (SecurityException e) {
LOG.error(e);
}
}
@@ -359,10 +362,12 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
private static class BooleanOptionKey {
final String groupName;
final String cbName;
final Field field;
public BooleanOptionKey(String groupName, String cbName) {
public BooleanOptionKey(String groupName, String cbName, Field field) {
this.groupName = groupName;
this.cbName = cbName;
this.field = field;
}
public boolean equals(Object obj) {
@@ -374,6 +379,45 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA
public int hashCode() {
return cbName.hashCode();
}
public void setValue(CodeStyleSettings settings, Boolean aBoolean) {
try {
field.set(settings, aBoolean);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
}
public boolean getValue(CodeStyleSettings settings) throws IllegalAccessException {
return field.getBoolean(settings);
}
}
private static class CustomBooleanOptionKey<T extends CustomCodeStyleSettings> extends BooleanOptionKey {
private final Class<T> mySettingsClass;
public CustomBooleanOptionKey(String groupName, String cbName, Class<T> settingsClass, Field field) {
super(groupName, cbName, field);
mySettingsClass = settingsClass;
}
@Override
public void setValue(CodeStyleSettings settings, Boolean aBoolean) {
final CustomCodeStyleSettings customSettings = settings.getCustomSettings(mySettingsClass);
try {
field.set(customSettings, aBoolean);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
}
@Override
public boolean getValue(CodeStyleSettings settings) throws IllegalAccessException {
final CustomCodeStyleSettings customSettings = settings.getCustomSettings(mySettingsClass);
return field.getBoolean(customSettings);
}
}
private static class MyToggleTreeNode extends DefaultMutableTreeNode {
@@ -222,11 +222,6 @@ public class CustomTemplateCallback {
myBuilder.insertText(offset, text);
}
public void insertNewLine() {
myBuilder.insertText(myOffset, "\n");
myOffset++;
}
public boolean newLineBefore() {
int i = myOffset - 1;
CharSequence text = myBuilder.getText();
@@ -47,6 +47,10 @@ public class CollectionFactory {
return new ArrayList<T>();
}
public static <T> HashSet<T> hashSet() {
return new HashSet<T>();
}
public static <T, V> LinkedHashMap<T, V> linkedMap() {
return new LinkedHashMap<T,V>();
}
@@ -0,0 +1,26 @@
/*
* Copyright 2000-2010 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.openapi.vcs;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD})
public @interface CalledInAny {
}
@@ -0,0 +1,110 @@
/*
* Copyright 2000-2010 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.openapi.vcs;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.util.Consumer;
import com.intellij.util.concurrency.Semaphore;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Future;
// competes to calculate The Result
public class ConcurrentTasks<T> {
private volatile boolean myResultKnown;
private final Semaphore mySemaphore;
private volatile T myResult;
private volatile int myCntAlive;
private final ProgressIndicator myParentIndicator;
private final Consumer<Consumer<T>>[] myTasks;
public void compute() {
final EmptyProgressIndicator pi = new EmptyProgressIndicator() {
@Override
public void checkCanceled() {
if (myResultKnown || (myParentIndicator != null) && myParentIndicator.isCanceled()) {
super.cancel();
}
super.checkCanceled();
}
};
myCntAlive = myTasks.length;
mySemaphore.down();
final List<Future<?>> futures = new LinkedList<Future<?>>();
for (final Consumer<Consumer<T>> task : myTasks) {
if (myResultKnown) break;
final Runnable computableProxy = new Runnable() {
public void run() {
try {
task.consume(new Consumer<T>() {
public void consume(T t) {
myResult = t;
myResultKnown = true;
-- myCntAlive;
mySemaphore.up();
}
});
}
catch (ProcessCanceledException e) {
-- myCntAlive;
if (myCntAlive == 0) {
mySemaphore.up();
}
throw e;
}
}
};
final Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
ProgressManager.getInstance().runProcess(computableProxy, pi);
}
});
futures.add(future);
}
while (true) {
mySemaphore.waitFor(1000);
if (myResultKnown) break;
pi.checkCanceled();
}
// in it possible to even interrupt() threads involved, but at the moment it's better for tasks themselves to check cancel status
for (Future<?> future : futures) {
if ((! future.isCancelled() && (! future.isDone()))) {
future.cancel(true);
}
}
}
public boolean isResultKnown() {
return myResultKnown;
}
public T getResult() {
return myResult;
}
public ConcurrentTasks(final ProgressIndicator parentIndicator, final Consumer<Consumer<T>>... tasks) {
myParentIndicator = parentIndicator;
myTasks = tasks;
mySemaphore = new Semaphore();
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2010 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.openapi.vcs.changes.committed;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import org.jetbrains.annotations.NotNull;
public class RunBackgroundable {
private RunBackgroundable() {
}
public static void run(@NotNull final Task task) {
final ProgressManager pm = ProgressManager.getInstance();
if (ApplicationManager.getApplication().isDispatchThread()) {
pm.run(task);
} else {
task.run(pm.getProgressIndicator());
}
}
}
@@ -5,5 +5,5 @@ This inspection reports on any access to a <b><font color="#000080">static</font
of any non-threadsafe type specified below, which is accessed from an instance field or a
non-synchronized block. It is possible that the static field is accessed from
multiple threads, which can lead to unspecified side effects.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -4,5 +4,5 @@
This inspection reports any calls to JUnit's <b><font color="#000080">assertEquals()</font></b>
method where the expected result and actual result arguments are of incompatible
types. While such a call might theoretically be useful, most likely it represents a bug.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -2,5 +2,5 @@
<body><table> <tr> <td valign="top" height="150">
<font face="verdana" size="-1">
This global inspection reports any boolean fields which are always negated when read.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -5,5 +5,5 @@ This inspection reports any <b><font color="#000080">catch</font></b> block wher
the caught exception is immediately rethrown, without performing any action on it.
Such <b><font color="#000080">catch</font></b> blocks are unnecessary or lack error
handling.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -8,5 +8,5 @@ classes are reported by this inspection.
<p>
Use the field below to specify the maximum number of dependencies a class may have
before triggering this inspection
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -9,5 +9,5 @@ Only top-level classes are reported by this inspection.
Use the field below to specify the maximum number of dependents a class may have before
triggering this inspection
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -9,5 +9,5 @@ Only top-level classes are reported by this inspection.
Use the field below to specify the maximum number of direct or indirect dependencies
a class may have before triggering this inspection
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -9,5 +9,5 @@ are reported by this inspection.
Use the field below to specify the maximum number of direct or indirect dependents
a class may have before triggering this inspection
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -10,5 +10,5 @@ methods of <b><font color="#000080">java.net.URL</font></b>.
<b><font color="#000080">java.net.URL</font></b>'s equals and hashCode method use a DNS
lookup, which depending on the availability of the network and the speed of the DNS server
can cause significant delays.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -4,5 +4,5 @@
This inspection reports any parameters of <b><font color="#000080">java.util.Comparator.compare()</font></b>
which are not used. Most likely this is the result of a typing mistake and one parameter is compared
with itself or the method is not implemented correctly.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -3,5 +3,5 @@
<font face="verdana" size="-1">
This global inspection reports any classes which are mutually or cyclically dependent on
other classes. Such cyclic dependencies make for fragile code and high maintenance costs.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -3,5 +3,5 @@
<font face="verdana" size="-1">
This global inspection reports any packages which are mutually or cyclically dependent
on other packages. Such cyclic dependencies make for fragile code and high maintenance costs.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -5,5 +5,5 @@ This inspection reports instances of <b><font color="#000080">Enumeration</font>
used, which can be replaced equivalent <b><font color="#000080">Iterator</font></b>
constructs. <b><font color="#000080">Iterator</font></b>s are part of the Java
Collection Framework, which has been available since Java 1.2.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -8,5 +8,5 @@ problems because those methods uses a DNS lookup
to determine the equality of two <b><font color="#000080">java.net.URL</font></b> objects.
Depending on the availability of the network and the speed of the DNS server, this can cause
significant delays.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -2,5 +2,5 @@
<body><table> <tr> <td valign="top" height="150">
<font face="verdana" size="-1">
This global inspection reports any instance fields which can be moved to a subclass.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -5,5 +5,5 @@ This inspection reports any arrays used in <b><font color="#000080">String</font
concatenations or as parameters to <b><font color="#000080">java.io.PrintStream</font></b>
methods (such as <b><font color="#000080">System.out.println()</font></b>). Usually in such
a case, the contents of the array were meant to be used and the not array object itself.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -3,5 +3,5 @@
<font face="verdana" size="-1">This inspection reports any Law of Demeter violations.
See here <a href="http://en.wikipedia.org/wiki/Law_of_Demeter">http://en.wikipedia.org/wiki/Law_of_Demeter</a>
for an explanation what the Law of Demeter is.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -4,5 +4,5 @@
This inspection reports any <b><font color="#000080">List.indexOf()</font></b>
expressions which can be replaced with the method
<b><font color="#000080">List.contains()</font></b>.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -11,5 +11,5 @@ in a <b><font color="#000080">while</font></b> or <b><font color="#000080">for</
loops and the last or only statement in a <b><font color="#000080">do-while</font></b> loop.
Such a loop would be clearer if the if statement was removed and its condition
was made an explicit loop condition.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -5,5 +5,5 @@ is added individually using a for loop. Such constructs may be replaced by a cal
<b><font color="#000080">Collection.addAll(Arrays.asList())</font></b>.
<br>
This inspection provides a quick fix.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -8,5 +8,5 @@ equal to <b><font color="#000080">this</font></b> for instance methods
or ClassName.<b><font color="#000080">class</font></b> for static methods. In
such cases the synchronized statements may be replaced by their contents and the
containing method marked <b><font color="#000080">synchronized</font></b>.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -2,5 +2,5 @@
<body><table> <tr> <td valign="top" height="150">
<font face="verdana" size="-1">
This global inspection reports methods which only ever return a constant.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -6,5 +6,5 @@ indicate an overly fragmented design.
<p>
Use the field below to specify the minimum number of classes a module may have before triggering this inspection.
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -6,5 +6,5 @@ indicate a lack of design clarity.
<p>
Use the field below to specify the maximum number of classes a module may have before triggering this inspection.
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -6,5 +6,5 @@ and <b><font color="#000080">new StringBuilder()</font></b> calls with an argume
with type <b><font color="#000080">char</font></b>. Such an argument is silently
casted to an interger used to specify the length of the buffer. Usually this is
not what was intended.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -5,5 +5,5 @@ This inspection reports any use of <b><font color="#000080">==</font></b> to tes
rather than the <b><font color="#000080">".equals()"</font></b> method. With auto-boxing it is easy
to make the mistake of comparing two Integer (or other subclass of java.lang.Number) objects instead
of two ints.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -2,5 +2,5 @@
<body><table> <tr> <td valign="top" height="150">
<font face="verdana" size="-1">
This global inspection reports any packages which are present in multiple modules.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -6,5 +6,5 @@ indicate an overly fragmented design.
<p>
Use the field below to specify the minimum number of classes a package may have before triggering this inspection.
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -6,5 +6,5 @@ indicate a lack of design clarity.
<p>
Use the field below to specify the maximum number of classes a package may have before triggering this inspection.
</p>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -5,5 +5,5 @@ This inspection reports any instances of constructors with too many parameters.
with too many parameters can be a good sign that refactoring is necessary.
<p>
Use the field provided below to specify the maximum acceptable number of parameters a constructor might have.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -3,5 +3,5 @@
<font face="verdana" size="-1">
This global inspection reports any static fields wich are only used in a differenc class than the one they
are defined in. Such fields can be moved.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -4,5 +4,5 @@
This inspection reports any suspicious indentation of statements after a control statement
without braces. Such indentation can make it look like the statement is part of the control
statement, when in fact it will be executed after the control stratement.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -8,5 +8,5 @@ Because of this, it is possible that some other part of the system
which uses an object initialized with the same literal, is actually holding a
reference to the exact same object. This can create unexpected dead-lock situations,
if the string was thought to be private.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -4,5 +4,5 @@
This inspection reports any instances of <b><font color="#000080">Throwable</font></b>
instantiation, where the created <b><font color="#000080">Throwable</font></b>
is never actually thrown. Most often this is the result of a simple mistake.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>
@@ -7,5 +7,5 @@ with a zero-length array argument. When passing in an array of too small size, t
<b><font color="#000080">toArray()</font></b> method has to construct a new array of
the right size using reflection. This has significantly worse performance than passing
in an array of at least the size of the collection itself.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -9,5 +9,5 @@ to be initialized separately in a <b><font color="#000080">readObject</font></b>
during deserialization. Any <b><font color="#000080">transient</font></b> fields which
are not initialized during normal object construction are considered to use the default
initialization and are not reported by this inspection.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -22,5 +22,5 @@ and <b><font color="#000080">containsValue()</font></b>.
Use the third checkbox below to specify if this inspection should warn when a type can be
weakened to <b><font color="#000080">java.lang.Object</font></b>. Weakening to
<b><font color="#000080">java.lang.Object</font></b> is often not very useful.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">Powered by InspectionGadgets</font> </td> </tr> </table> </body>
</html>
@@ -12,5 +12,5 @@ This inspection reports any unnecessary unary minuses. For example:</font>
<b><font color="#000080">i</font> = <font color="#000080">i</font> - 8;</b>
</pre>
</td></tr>
<tr><td height="20"><font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font></td></tr></table> </body>
<tr><td height="20"><font face="verdana" size="-2">Powered by InspectionGadgets</font></td></tr></table> </body>
</html>
@@ -7,5 +7,5 @@ These constructors can have somewhat unpredictable results because many numbers
cannot be represented exactly in a <b><font color="#000080">double</font></b>.
It is recommend to use the constructors which accept a String instead.
</font></td></tr>
<tr><td height="20"><font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font></td></tr></table> </body>
<tr><td height="20"><font face="verdana" size="-2">Powered by InspectionGadgets</font></td></tr></table> </body>
</html>
@@ -5,5 +5,5 @@ This inspection reports on field accesses which are not qualified with
<b><font color="#000080">this</font></b> or some other qualifier. Some coding styles
mandate that all field accesses are qualified to prevent confusion with local
variable or parameter accesses.</font></td></tr>
<tr><td height="20"><font face="verdana" size="-2">New in 7, Powered by InspectionGadgets</font></td></tr></table> </body>
<tr><td height="20"><font face="verdana" size="-2">Powered by InspectionGadgets</font></td></tr></table> </body>
</html>
@@ -53,9 +53,10 @@ public class GroovyConditionalWithIdenticalBranchesInspection extends BaseInspec
return "Collapse conditional expression";
}
public void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final GrConditionalExpression expression = (GrConditionalExpression) descriptor.getPsiElement();
public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
final PsiElement element = descriptor.getPsiElement();
if (!(element instanceof GrConditionalExpression)) return;
final GrConditionalExpression expression = (GrConditionalExpression)element;
final GrExpression thenBranch = expression.getThenBranch();
replaceExpression(expression, thenBranch.getText());
}
@@ -37,9 +37,10 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
*/
public class BuiltInTypeFilter implements ElementFilter {
public boolean isAcceptable(Object element, PsiElement context) {
PsiElement previous = PsiImplUtil.realPrevious(context.getParent().getPrevSibling());
if (previous != null &&
GroovyTokenTypes.mAT.equals(previous.getNode().getElementType())) {
final PsiElement parent = context.getParent();
if (parent == null) return false;
PsiElement previous = PsiImplUtil.realPrevious(parent.getPrevSibling());
if (previous != null && GroovyTokenTypes.mAT.equals(previous.getNode().getElementType())) {
return false;
}
if (GroovyCompletionUtil.asSimpleVariable(context) ||
@@ -47,29 +48,29 @@ public class BuiltInTypeFilter implements ElementFilter {
GroovyCompletionUtil.asVariableInBlock(context)) {
return true;
}
if ((context.getParent() instanceof GrParameter &&
((GrParameter) context.getParent()).getTypeElementGroovy() == null) ||
context.getParent() instanceof GrReferenceElement &&
!(context.getParent().getParent() instanceof GrImportStatement) &&
!(context.getParent().getParent() instanceof GrPackageDefinition) &&
!(context.getParent().getParent() instanceof GrArgumentList)) {
if ((parent instanceof GrParameter &&
((GrParameter)parent).getTypeElementGroovy() == null) ||
parent instanceof GrReferenceElement &&
!(parent.getParent() instanceof GrImportStatement) &&
!(parent.getParent() instanceof GrPackageDefinition) &&
!(parent.getParent() instanceof GrArgumentList)) {
PsiElement prevSibling = context.getPrevSibling();
if (context.getParent() instanceof GrReferenceElement && prevSibling != null && prevSibling.getNode() != null) {
if (parent instanceof GrReferenceElement && prevSibling != null && prevSibling.getNode() != null) {
ASTNode node = prevSibling.getNode();
return !GroovyTokenTypes.DOTS.contains(node.getElementType());
} else {
return true;
}
}
if (PsiImplUtil.realPrevious(context.getParent().getPrevSibling()) instanceof GrModifierList) {
if (PsiImplUtil.realPrevious(parent.getPrevSibling()) instanceof GrModifierList) {
return true;
}
if (PsiImplUtil.realPrevious(context.getPrevSibling()) instanceof GrModifierList) {
return true;
}
return context.getParent() instanceof GrExpression &&
context.getParent().getParent() instanceof GroovyFile &&
GroovyCompletionUtil.isNewStatement(context, false);
return parent instanceof GrExpression &&
parent.getParent() instanceof GroovyFile &&
GroovyCompletionUtil.isNewStatement(context, false);
}
public boolean isClassAcceptable(Class hintClass) {
@@ -346,9 +346,14 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory {
public GrMethod createMethodFromText(@NotNull String methodText) {
GroovyFileBase file = createDummyFile(methodText);
GrTopLevelDefintion defintion = file.getTopLevelDefinitions()[0];
assert defintion != null && defintion instanceof GrMethod;
return ((GrMethod) defintion);
try {
GrTopLevelDefintion defintion = file.getTopLevelDefinitions()[0];
assert defintion != null && defintion instanceof GrMethod;
return ((GrMethod)defintion);
}
catch (Error error) {
throw new IncorrectOperationException("Can't create method from text: '" + file.getText() + "'");
}
}
@Override
@@ -29,7 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
public class GroovyWithTypeCastSurrounder extends GroovyExpressionSurrounder {
protected TextRange surroundExpression(GrExpression expression) {
GrParenthesizedExpression parenthesized = (GrParenthesizedExpression) GroovyPsiElementFactory.getInstance(expression.getProject()).createTopElementFromText("((Type)a)");
parenthesized = (GrParenthesizedExpression) expression.replaceWithExpression(parenthesized, true);
parenthesized = (GrParenthesizedExpression) expression.replaceWithExpression(parenthesized, false);
GrTypeCastExpression typeCast = (GrTypeCastExpression) parenthesized.getOperand();
replaceToOldExpression(typeCast.getOperand(), expression);
GrTypeElement typeElement = typeCast.getCastTypeElement();
@@ -22,8 +22,8 @@ hg4idea.revert=Revert
hg4idea.commit=Commit
hg4idea.configuration.title=Mercurial Configuration
hg4idea.configuration.description=Path to hg executable
hg4idea.configuration.executable.error=\"{0}\" doesn't appear to be a valid hg executable
hg4idea.configuration.description=Full path to hg executable
hg4idea.configuration.executable.error=\"{0}\" doesn\'t appear to be a valid hg executable
hg4idea.command.executable.error=Error executing \"{0}\". Make sure you have setup the right executable in Mercurial configuration
@@ -54,4 +54,3 @@ hg4idea.status.currentBranch.text=<html><b>{0}</b></html>
hg4idea.status.currentBranch.description=<html>Current mercurial branch</html>
hg4idea.warning.no-default-update-path=Skipped \"{0}\". No default update path.
hg4idea.merge.please-commit=Merged heads, please commit repository \"{0}\"
hg4idea.error.invalidExecutable=\"{0}\" is not a valid mercurial executable
@@ -34,7 +34,7 @@
<text value="&amp;Specify executable path"/>
</properties>
</component>
<component id="42f2c" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="pathSelector">
<component id="42f2c" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="pathSelector" custom-create="true">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="0" fill="1" indent="0" use-parent-layout="false">
<minimum-size width="100" height="-1"/>
@@ -45,14 +45,6 @@ public class HgConfigurationIdePanel {
this.globalSettings = globalSettings;
loadSettings();
String title = HgVcsMessages.message("hg4idea.configuration.title");
String description = HgVcsMessages.message("hg4idea.configuration.description");
pathSelector.addBrowseFolderListener(
title, description, null,
new FileChooserDescriptor(true, false, false, false, false, false)
);
final ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
pathSelector.setEnabled(selectRadioButton.isSelected());
@@ -109,54 +101,7 @@ public class HgConfigurationIdePanel {
}
}
{
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
$$$setupUI$$$();
}
/**
* Method generated by IntelliJ IDEA GUI Designer
* >>> IMPORTANT!! <<<
* DO NOT edit this method OR call it in your code!
*
* @noinspection ALL
*/
private void $$$setupUI$$$() {
basePanel = new JPanel();
basePanel.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1));
final JPanel panel1 = new JPanel();
panel1.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1));
basePanel.add(panel1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Path to hg executable"));
autoRadioButton = new JRadioButton();
autoRadioButton.setSelected(true);
autoRadioButton.setText("Autodetect hg in PATH");
autoRadioButton.setMnemonic('A');
autoRadioButton.setDisplayedMnemonicIndex(0);
panel1.add(autoRadioButton, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
selectRadioButton = new JRadioButton();
selectRadioButton.setEnabled(true);
selectRadioButton.setText("Specify executable path");
selectRadioButton.setMnemonic('S');
selectRadioButton.setDisplayedMnemonicIndex(0);
panel1.add(selectRadioButton, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
pathSelector = new TextFieldWithBrowseButton();
pathSelector.setEnabled(false);
panel1.add(pathSelector, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, new Dimension(100, -1), null, null, 0, false));
final Spacer spacer1 = new Spacer();
basePanel.add(spacer1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
ButtonGroup buttonGroup;
buttonGroup = new ButtonGroup();
buttonGroup.add(autoRadioButton);
buttonGroup.add(selectRadioButton);
}
/**
* @noinspection ALL
*/
public JComponent $$$getRootComponent$$$() {
return basePanel;
private void createUIComponents() {
pathSelector = new HgSetExecutablePathPanel();
}
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.zmlx.hg4idea.ui.HgSetExecutableDialog">
<grid id="27dc6" binding="centerPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myCenterPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="564" height="400"/>
@@ -8,7 +8,7 @@
<properties/>
<border type="none"/>
<children>
<component id="40fef" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="hgExecutablePath">
<component id="c91cc" class="org.zmlx.hg4idea.ui.HgSetExecutablePathPanel" binding="myHgExecutablePath" custom-create="true">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="7" anchor="9" fill="0" indent="0" use-parent-layout="false">
<preferred-size width="400" height="-1"/>
@@ -16,27 +16,17 @@
</constraints>
<properties/>
</component>
<component id="a1421" class="javax.swing.JLabel" binding="infoLabel">
<component id="a1421" class="javax.swing.JLabel" binding="myInfoLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Full path to hg executable or 'hg' if PATH has it:"/>
</properties>
</component>
<component id="c771f" class="javax.swing.JLabel" binding="errorLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<font style="2"/>
<foreground awt-color="red"/>
<text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.error.invalidExecutable"/>
<text resource-bundle="org/zmlx/hg4idea/HgVcsMessages" key="hg4idea.configuration.description"/>
</properties>
</component>
<vspacer id="4c273">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
</children>
@@ -14,26 +14,16 @@ package org.zmlx.hg4idea.ui;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import org.zmlx.hg4idea.HgVcsMessages;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.util.ResourceBundle;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class HgSetExecutableDialog extends DialogWrapper {
private JPanel centerPanel;
private TextFieldWithBrowseButton hgExecutablePath;
private JLabel infoLabel;
private JLabel errorLabel;
private JPanel myCenterPanel;
private HgSetExecutablePathPanel myHgExecutablePath;
private JLabel myInfoLabel;
public HgSetExecutableDialog(Project project) {
super(project, false);
@@ -42,81 +32,24 @@ public class HgSetExecutableDialog extends DialogWrapper {
@Override
protected JComponent createCenterPanel() {
return centerPanel;
return myCenterPanel;
}
public void setBadHgPath(String hgPath) {
hgExecutablePath.setText(hgPath);
errorLabel.setText(HgVcsMessages.message("hg4idea.error.invalidExecutable", hgPath));
myHgExecutablePath.setText(hgPath);
setErrorText(HgVcsMessages.message("hg4idea.configuration.executable.error", hgPath));
}
public String getNewHgPath() {
return hgExecutablePath.getText();
return myHgExecutablePath.getText();
}
{
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
$$$setupUI$$$();
}
/**
* Method generated by IntelliJ IDEA GUI Designer
* >>> IMPORTANT!! <<<
* DO NOT edit this method OR call it in your code!
*
* @noinspection ALL
*/
private void $$$setupUI$$$() {
centerPanel = new JPanel();
centerPanel.setLayout(new GridLayoutManager(4, 1, new Insets(0, 0, 0, 0), -1, -1));
hgExecutablePath = new TextFieldWithBrowseButton();
centerPanel.add(hgExecutablePath, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(400, -1), null, 0, false));
infoLabel = new JLabel();
infoLabel.setText("Full path to hg executable or 'hg' if PATH has it:");
centerPanel.add(infoLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
errorLabel = new JLabel();
errorLabel.setFont(new Font(errorLabel.getFont().getName(), Font.ITALIC, errorLabel.getFont().getSize()));
errorLabel.setForeground(Color.red);
this.$$$loadLabelText$$$(errorLabel, ResourceBundle.getBundle("org/zmlx/hg4idea/HgVcsMessages").getString("hg4idea.error.invalidExecutable"));
centerPanel.add(errorLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
final Spacer spacer1 = new Spacer();
centerPanel.add(spacer1, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
}
/**
* @noinspection ALL
*/
private void $$$loadLabelText$$$(JLabel component, String text) {
StringBuffer result = new StringBuffer();
boolean haveMnemonic = false;
char mnemonic = '\0';
int mnemonicIndex = -1;
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == '&') {
i++;
if (i == text.length()) break;
if (!haveMnemonic && text.charAt(i) != '&') {
haveMnemonic = true;
mnemonic = text.charAt(i);
mnemonicIndex = result.length();
}
private void createUIComponents() {
myHgExecutablePath = new HgSetExecutablePathPanel();
myHgExecutablePath.addOKListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
setErrorText("");
}
result.append(text.charAt(i));
}
component.setText(result.toString());
if (haveMnemonic) {
component.setDisplayedMnemonic(mnemonic);
component.setDisplayedMnemonicIndex(mnemonicIndex);
}
}
/**
* @noinspection ALL
*/
public JComponent $$$getRootComponent$$$() {
return centerPanel;
});
}
}
@@ -0,0 +1,45 @@
package org.zmlx.hg4idea.ui;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.vfs.VirtualFile;
import org.zmlx.hg4idea.HgVcsMessages;
import org.zmlx.hg4idea.command.HgVersionCommand;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Set;
/**
* HgSetExecutablePathPanel is a {@link com.intellij.openapi.ui.TextFieldWithBrowseButton}, which opens a file chooser for hg executable
* and checks validity of the selected file to be an hg executable.
*/
class HgSetExecutablePathPanel extends TextFieldWithBrowseButton {
private final Set<ActionListener> myOkListeners = new HashSet<ActionListener>();
HgSetExecutablePathPanel() {
FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, false, false) {
public void validateSelectedFiles(VirtualFile[] files) throws Exception {
HgVersionCommand command = new HgVersionCommand();
String path = files[0].getPath();
if (!command.isValid(path)) {
throw new ConfigurationException(HgVcsMessages.message("hg4idea.configuration.executable.error", path));
}
for (ActionListener okListener : myOkListeners) {
okListener.actionPerformed(null);
}
}
};
addBrowseFolderListener(HgVcsMessages.message("hg4idea.configuration.title"), HgVcsMessages.message("hg4idea.configuration.description"), null, descriptor);
}
/**
* Adds a listener which will be called when file chooser dialog is closed successfully.
*/
void addOKListener(ActionListener listener) {
myOkListeners.add(listener);
}
}
@@ -68,6 +68,7 @@ import org.jetbrains.idea.svn.actions.ShowPropertiesDiffWithLocalAction;
import org.jetbrains.idea.svn.actions.SvnMergeProvider;
import org.jetbrains.idea.svn.annotate.SvnAnnotationProvider;
import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment;
import org.jetbrains.idea.svn.dialogs.SvnBranchPointsCalculator;
import org.jetbrains.idea.svn.dialogs.SvnFormatWorker;
import org.jetbrains.idea.svn.dialogs.WCInfo;
import org.jetbrains.idea.svn.history.*;
@@ -144,6 +145,8 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
public static final Topic<Runnable> ROOTS_RELOADED = new Topic<Runnable>("ROOTS_RELOADED", Runnable.class);
private VcsListener myVcsListener;
private SvnBranchPointsCalculator mySvnBranchPointsCalculator;
private final RootsToWorkingCopies myRootsToWorkingCopies;
private final SvnAuthenticationNotifier myAuthNotifier;
private static RareLogger.LogFilter[] ourLogFilters;
@@ -365,6 +368,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
FrameStateManager.getInstance().addListener(myFrameStateListener);
myAuthNotifier.init();
mySvnBranchPointsCalculator = new SvnBranchPointsCalculator(myProject);
// do one time after project loaded
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
@@ -466,6 +470,8 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
myAuthNotifier.stop();
myAuthNotifier.clear();
mySvnBranchPointsCalculator = null;
}
public VcsShowConfirmationOption getAddConfirmation() {
@@ -1038,4 +1044,8 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
public CommittedChangeList getRevisionChanges(VcsFileRevision revision, VirtualFile file) throws VcsException {
return ShowAllSubmittedFilesAction.loadRevisions(getProject(), (SvnFileRevision)revision, file, false);
}
public SvnBranchPointsCalculator getSvnBranchPointsCalculator() {
return mySvnBranchPointsCalculator;
}
}
@@ -55,7 +55,7 @@ public class BranchMerger implements IMerger {
}
public String getComment() {
return "Merge from " + myBranchName;
return "Merge all from " + myBranchName;
}
public boolean hasNext() {
@@ -17,56 +17,29 @@ package org.jetbrains.idea.svn.dialogs;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.CommittedChangesProvider;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.changes.ui.ChangesViewBalloonProblemNotifier;
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.DottedBorder;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.util.AsynchConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.containers.Convertor;
import com.intellij.util.io.EqualityPolicy;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.NestedCopyType;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.WorkingCopyFormat;
import org.jetbrains.idea.svn.actions.ChangeListsMergerFactory;
import org.jetbrains.idea.svn.actions.SelectBranchPopup;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider;
import org.jetbrains.idea.svn.history.FirstInBranch;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.jetbrains.idea.svn.history.SvnRepositoryLocation;
import org.jetbrains.idea.svn.integrate.IMerger;
import org.jetbrains.idea.svn.integrate.MergerFactory;
import org.jetbrains.idea.svn.integrate.SvnIntegrateChangesTask;
import org.jetbrains.idea.svn.integrate.WorkingCopyInfo;
import org.jetbrains.idea.svn.mergeinfo.BranchInfo;
import org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache;
import org.jetbrains.idea.svn.update.UpdateEventHandler;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.SVNRevision;
import javax.swing.*;
@@ -77,8 +50,6 @@ import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class CopiesPanel {
@@ -291,149 +262,11 @@ public class CopiesPanel {
private void mergeFrom(final WCInfo wcInfo, final VirtualFile root, final LinkLabel mergeLabel) {
SelectBranchPopup.showForBranchRoot(myProject, root, new SelectBranchPopup.BranchSelectedCallback() {
public void branchSelected(Project project, SvnBranchConfigurationNew configuration, String url, long revision) {
if (url.equals(wcInfo.getRootUrl())) {
showErrorBalloon("Cannot merge from self");
return;
}
ProgressManager.getInstance().run(new MergeCalculator(wcInfo, root, url, configuration.getBaseName(url)));
new QuickMerge(project, url, wcInfo, configuration.getBaseName(url), configuration).execute();
}
}, "Select branch", mergeLabel);
}
private void showErrorBalloon(final String s) {
ChangesViewBalloonProblemNotifier.showMe(myProject, s, MessageType.ERROR);
}
private class MergeCalculator extends Task.Backgroundable {
private final WCInfo myWcInfo;
private final VirtualFile myRoot;
private final String mySourceUrl;
private final String myBranchName;
private boolean myIsReintegrate;
private final List<CommittedChangeList> myNotMerged;
private String myMergeTitle;
private BranchInfo myBranchInfo;
private MergeCalculator(WCInfo wcInfo, VirtualFile root, String sourceUrl, String branchName) {
super(CopiesPanel.this.myProject, "Calculating not merged revisions", true, BackgroundFromStartOption.getInstance());
myWcInfo = wcInfo;
myRoot = root;
mySourceUrl = sourceUrl;
myBranchName = branchName;
myNotMerged = new LinkedList<CommittedChangeList>();
myMergeTitle = "Merge from " + branchName;
}
public void run(@NotNull ProgressIndicator indicator) {
// branch is info holder
new FirstInBranch(myVcs, myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl(), mySourceUrl,
new Consumer<FirstInBranch.CopyData>() {
public void consume(FirstInBranch.CopyData copyData) {
if (copyData == null) {
showErrorBalloon("Merge start wasn't found");
return;
}
myIsReintegrate = ! copyData.isTrunkSupposedCorrect();
if (! myWcInfo.getFormat().supportsMergeInfo()) return;
final long localLatest = Math.max(copyData.getCopyTargetRevision(), copyData.getCopySourceRevision());
myBranchInfo = new BranchInfo(myVcs, myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl(), mySourceUrl, mySourceUrl, myVcs.createWCClient());
final CommittedChangesProvider<SvnChangeList,ChangeBrowserSettings> committedChangesProvider =
myVcs.getCommittedChangesProvider();
final ChangeBrowserSettings settings = new ChangeBrowserSettings();
settings.CHANGE_AFTER = Long.toString(localLatest);
try {
committedChangesProvider.loadCommittedChanges(settings, new SvnRepositoryLocation(mySourceUrl),
committedChangesProvider.getUnlimitedCountValue(), new AsynchConsumer<CommittedChangeList>() {
public void finished() {
}
public void consume(CommittedChangeList committedChangeList) {
final SvnChangeList svnList = (SvnChangeList)committedChangeList;
if (localLatest >= svnList.getNumber()) return;
final SvnMergeInfoCache.MergeCheckResult checkResult =
myBranchInfo.checkList(svnList, myWcInfo.getPath());
if (SvnMergeInfoCache.MergeCheckResult.NOT_MERGED.equals(checkResult)) {
myNotMerged.add(svnList);
}
}
});
}
catch (VcsException e) {
AbstractVcsHelper.getInstance(myProject).showErrors(Collections.singletonList(e), "Checking revisions for merge fault");
}
}
}).run();
}
@Override
public void onCancel() {
onSuccess();
}
@Nullable
private MergerFactory askParameters() {
final int result = Messages.showDialog(myProject, myNotMerged.size() + " not merged revision(s) found.", myMergeTitle,
new String[]{"Merge &all", "&Select revisions to merge", "Cancel"}, 0, Messages.getQuestionIcon());
if (result == 2) return null;
final MergerFactory factory;
if (result == 0) {
factory = createMergeAllFactory();
} else {
final ToBeMergedDialog dialog = new ToBeMergedDialog(myProject, myNotMerged, myMergeTitle, myBranchInfo);
dialog.show();
if (dialog.getExitCode() == DialogWrapper.CANCEL_EXIT_CODE) {
return null;
}
final List<CommittedChangeList> lists = dialog.getSelected();
if (lists.isEmpty()) return null;
factory = new ChangeListsMergerFactory(lists);
}
return factory;
}
private MergerFactory createMergeAllFactory() {
return new MergerFactory() {
public IMerger createMerger(SvnVcs vcs, File target, UpdateEventHandler handler, SVNURL currentBranchUrl) {
return new BranchMerger(vcs, currentBranchUrl, myWcInfo.getUrl(), myWcInfo.getPath(), handler, myIsReintegrate, myBranchName);
}
};
}
@Override
public void onSuccess() {
if (! myWcInfo.getFormat().supportsMergeInfo()) {
doMerge(createMergeAllFactory());
return;
}
if (myNotMerged.isEmpty()) {
ChangesViewBalloonProblemNotifier.showMe(myProject, "Everything is up-to-date", MessageType.WARNING);
return;
}
final MergerFactory factory = askParameters();
if (factory == null) return;
doMerge(factory);
}
private void doMerge(MergerFactory factory) {
final SVNURL sourceUrlUrl;
try {
sourceUrlUrl = SVNURL.parseURIEncoded(mySourceUrl);
} catch (SVNException e) {
showErrorBalloon("Cannot merge: " + e.getMessage());
return;
}
final SvnIntegrateChangesTask task = new SvnIntegrateChangesTask(SvnVcs.getInstance(myProject),
new WorkingCopyInfo(myWcInfo.getPath(), true), factory, sourceUrlUrl, myMergeTitle, false);
ProgressManager.getInstance().run(task);
}
}
private void setFocusableForLinks(final LinkLabel label) {
final Border border = new DottedBorder(new Insets(1,2,1,1), Color.black);
label.setFocusable(true);
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2010 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.idea.svn.dialogs;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.CalledInAwt;
import com.intellij.util.Consumer;
import com.intellij.util.ValueHolder;
import com.intellij.util.containers.Convertor;
// cache. persistent. by request
public class FactsCalculator<In, Out> {
private final Project myProject;
private final String myTaskTitle;
private final ValueHolder<Out, In> myCache;
private final Convertor<In, Out> myLive;
public FactsCalculator(Project project, String taskTitle, ValueHolder<Out, In> cache, Convertor<In, Out> live) {
myProject = project;
myTaskTitle = taskTitle;
myCache = cache;
myLive = live;
}
@CalledInAwt
public void get(final In in, final Consumer<Out> resultConsumer) {
new RunOrContinuation<Out>(myProject, myTaskTitle) {
@Override
protected Out calculate() {
return myCache.getValue(in);
}
@Override
protected Out calculateLong() {
final Out result = myLive.convert(in);
if (result != null) {
myCache.setValue(result, in);
}
return result;
}
@Override
protected void processResult(Out out) {
resultConsumer.consume(out);
}
}.execute();
}
}
@@ -0,0 +1,258 @@
/*
* Copyright 2000-2010 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.idea.svn.dialogs;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.changes.committed.RunBackgroundable;
import com.intellij.openapi.vcs.changes.ui.ChangesViewBalloonProblemNotifier;
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.util.AsynchConsumer;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.actions.ChangeListsMergerFactory;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.history.CopyData;
import org.jetbrains.idea.svn.history.FirstInBranch;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.jetbrains.idea.svn.history.SvnRepositoryLocation;
import org.jetbrains.idea.svn.integrate.IMerger;
import org.jetbrains.idea.svn.integrate.MergerFactory;
import org.jetbrains.idea.svn.integrate.SvnIntegrateChangesTask;
import org.jetbrains.idea.svn.integrate.WorkingCopyInfo;
import org.jetbrains.idea.svn.mergeinfo.BranchInfo;
import org.jetbrains.idea.svn.mergeinfo.SvnMergeInfoCache;
import org.jetbrains.idea.svn.update.UpdateEventHandler;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import java.io.File;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class QuickMerge {
private final Project myProject;
private final String myBranchName;
private final SvnBranchConfigurationNew myConfiguration;
private final WCInfo myWcInfo;
private String mySourceUrl;
private SvnVcs myVcs;
private final String myTitle;
public QuickMerge(Project project, String sourceUrl, WCInfo wcInfo, final String branchName, final SvnBranchConfigurationNew configuration) {
myProject = project;
myBranchName = branchName;
myConfiguration = configuration;
myVcs = SvnVcs.getInstance(project);
mySourceUrl = sourceUrl;
myWcInfo = wcInfo;
myTitle = "Merge from " + myBranchName;
}
private void correctSourceUrl() throws SVNException {
final SVNURL branch = myConfiguration.getWorkingBranch(myWcInfo.getUrl());
if (branch != null && (! myWcInfo.getUrl().equals(branch))) {
final String branchString = branch.toString();
if (SVNPathUtil.isAncestor(branchString, myWcInfo.getRootUrl())) {
final String subPath = SVNPathUtil.getRelativePath(branchString, myWcInfo.getRootUrl());
mySourceUrl = SVNPathUtil.append(mySourceUrl, subPath);
}
}
}
private boolean prompt(final String question) {
return Messages.showOkCancelDialog(myProject, question, myTitle, Messages.getQuestionIcon()) == 0;
}
@CalledInAwt
public void execute() {
if (SVNPathUtil.isAncestor(mySourceUrl, myWcInfo.getRootUrl()) || SVNPathUtil.isAncestor(myWcInfo.getRootUrl(), mySourceUrl)) {
showErrorBalloon("Cannot merge from self");
return;
}
try {
correctSourceUrl();
}
catch (SVNException e) {
showErrorBalloon(e.getMessage());
return;
}
if (! myWcInfo.getFormat().supportsMergeInfo()) {
mergeAll();
return;
}
final int result = Messages.showDialog(myProject, "Merge all?", myTitle,
new String[]{"Merge &all", "&Select revisions to merge", "Cancel"}, 0, Messages.getQuestionIcon());
if (result == 2) return;
if (result == 0) {
mergeAll();
return;
}
ProgressManager.getInstance().run(new MergeCalculator(myProject, myWcInfo, mySourceUrl, myBranchName));
}
@CalledInAny
private void showErrorBalloon(final String s) {
ChangesViewBalloonProblemNotifier.showMe(myProject, s, MessageType.ERROR);
}
// continuation... continuation.. hidden continuation..
private void mergeAll() {
// suppose we're in branch
myVcs.getSvnBranchPointsCalculator().getFirstCopyPoint(myWcInfo.getRepositoryRoot(), mySourceUrl, myWcInfo.getRootUrl(),
new Consumer<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>>() {
public void consume(SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> result) {
if (result == null) {
showErrorBalloon("Merge start wasn't found");
return;
}
final boolean reintegrate = result.isInvertedSense();
final MergerFactory mergerFactory = new MergerFactory() {
public IMerger createMerger(SvnVcs vcs, File target, UpdateEventHandler handler, SVNURL currentBranchUrl) {
return new BranchMerger(vcs, currentBranchUrl, myWcInfo.getUrl(), myWcInfo.getPath(), handler, reintegrate, myBranchName);
}
};
final String title = "Merging all from " + myBranchName + (reintegrate ? " (reintegrate)" : "");
doMerge(mergerFactory, title);
}
});
}
@CalledInAny
private void doMerge(final MergerFactory factory, final String mergeTitle) {
final SVNURL sourceUrlUrl;
try {
sourceUrlUrl = SVNURL.parseURIEncoded(mySourceUrl);
} catch (SVNException e) {
showErrorBalloon("Cannot merge: " + e.getMessage());
return;
}
final SvnIntegrateChangesTask task = new SvnIntegrateChangesTask(SvnVcs.getInstance(myProject),
new WorkingCopyInfo(myWcInfo.getPath(), true), factory, sourceUrlUrl, mergeTitle, false);
RunBackgroundable.run(task);
}
private class MergeCalculator extends Task.Backgroundable {
private final WCInfo myWcInfo;
private final String mySourceUrl;
private final String myBranchName;
private boolean myIsReintegrate;
private final List<CommittedChangeList> myNotMerged;
private String myMergeTitle;
private BranchInfo myBranchInfo;
private MergeCalculator(Project project, WCInfo wcInfo, String sourceUrl, String branchName) {
super(project, "Calculating not merged revisions", true, BackgroundFromStartOption.getInstance());
myWcInfo = wcInfo;
mySourceUrl = sourceUrl;
myBranchName = branchName;
myNotMerged = new LinkedList<CommittedChangeList>();
myMergeTitle = "Merge from " + branchName;
}
public void run(@NotNull ProgressIndicator indicator) {
// branch is info holder
new FirstInBranch(myVcs, myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl(), mySourceUrl,
new Consumer<CopyData>() {
public void consume(CopyData copyData) {
if (copyData == null) {
showErrorBalloon("Merge start wasn't found");
return;
}
myIsReintegrate = ! copyData.isTrunkSupposedCorrect();
if (! myWcInfo.getFormat().supportsMergeInfo()) return;
final long localLatest = Math.max(copyData.getCopyTargetRevision(), copyData.getCopySourceRevision());
myBranchInfo = new BranchInfo(myVcs, myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl(), mySourceUrl, mySourceUrl, myVcs.createWCClient());
final CommittedChangesProvider<SvnChangeList,ChangeBrowserSettings> committedChangesProvider =
myVcs.getCommittedChangesProvider();
final ChangeBrowserSettings settings = new ChangeBrowserSettings();
settings.CHANGE_AFTER = Long.toString(localLatest);
try {
committedChangesProvider.loadCommittedChanges(settings, new SvnRepositoryLocation(mySourceUrl),
committedChangesProvider.getUnlimitedCountValue(), new AsynchConsumer<CommittedChangeList>() {
public void finished() {
}
public void consume(CommittedChangeList committedChangeList) {
final SvnChangeList svnList = (SvnChangeList)committedChangeList;
if (localLatest >= svnList.getNumber()) return;
final SvnMergeInfoCache.MergeCheckResult checkResult =
myBranchInfo.checkList(svnList, myWcInfo.getPath());
if (SvnMergeInfoCache.MergeCheckResult.NOT_MERGED.equals(checkResult)) {
myNotMerged.add(svnList);
}
}
});
}
catch (VcsException e) {
AbstractVcsHelper.getInstance(myProject).showErrors(Collections.singletonList(e), "Checking revisions for merge fault");
}
}
}).run();
}
@Override
public void onCancel() {
onSuccess();
}
@Nullable
private MergerFactory askParameters() {
final MergerFactory factory;
final ToBeMergedDialog dialog = new ToBeMergedDialog(myProject, myNotMerged, myMergeTitle, myBranchInfo);
dialog.show();
if (dialog.getExitCode() == DialogWrapper.CANCEL_EXIT_CODE) {
return null;
}
final List<CommittedChangeList> lists = dialog.getSelected();
if (lists.isEmpty()) return null;
factory = new ChangeListsMergerFactory(lists);
return factory;
}
@Override
public void onSuccess() {
if (myNotMerged.isEmpty()) {
ChangesViewBalloonProblemNotifier.showMe(myProject, "Everything is up-to-date", MessageType.WARNING);
return;
}
final MergerFactory factory = askParameters();
if (factory == null) return;
doMerge(factory, myMergeTitle);
}
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2000-2010 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.idea.svn.dialogs;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.CalledInAwt;
import com.intellij.openapi.vcs.CalledInBackground;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class RunOrContinuation<T> {
protected final Project myProject;
private final String myTaskTitle;
private boolean myWasCanceled;
protected RunOrContinuation(final Project project, final String taskTitle) {
myProject = project;
myTaskTitle = taskTitle;
}
@Nullable
@CalledInAwt
protected abstract T calculate();
@Nullable
@CalledInBackground
protected abstract T calculateLong();
@CalledInAwt
protected abstract void processResult(final T t);
protected void cancel() {
myWasCanceled = true;
}
@CalledInAwt
public void execute() {
final Ref<T> refT = new Ref<T>();
refT.set(calculate());
if ((! myWasCanceled) && (! refT.isNull())) {
processResult(refT.get());
return;
}
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, myTaskTitle, true, BackgroundFromStartOption.getInstance()) {
public void run(@NotNull ProgressIndicator indicator) {
refT.set(calculateLong());
}
@Override
public void onSuccess() {
if ((! myWasCanceled) && (! refT.isNull())) processResult(refT.get());
}
});
}
}
@@ -0,0 +1,337 @@
/*
* Copyright 2000-2010 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.idea.svn.dialogs;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import com.intellij.util.ValueHolder;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.PersistentHashMap;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.history.CopyData;
import org.jetbrains.idea.svn.history.FirstInBranch;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.*;
public class SvnBranchPointsCalculator {
private final FactsCalculator<KeyData, WrapperInvertor<BranchCopyData>> myCalculator;
private PersistentHolder myPersistentHolder;
public SvnBranchPointsCalculator(final Project project) {
final File vcs = new File(PathManager.getSystemPath(), "vcs");
File file = new File(vcs, "svn_copy_sources");
file.mkdirs();
file = new File(file, project.getLocationHash());
// todo when will it die?
ValueHolder<WrapperInvertor<BranchCopyData>, KeyData> cache = null;
try {
myPersistentHolder = new PersistentHolder(file);
cache = new ValueHolder<WrapperInvertor<BranchCopyData>, KeyData>() {
public WrapperInvertor<BranchCopyData> getValue(KeyData dataHolder) {
try {
return myPersistentHolder.getBestHit(dataHolder.getRepoUrl(), dataHolder.getSourceUrl(), dataHolder.getTargetUrl());
} catch (IOException e) {
}
return null;
}
// todo carefully check
public void setValue(WrapperInvertor<BranchCopyData> value, KeyData dataHolder) {
try {
myPersistentHolder.put(dataHolder.getRepoUrl(),
value.isInvertedSense() ? dataHolder.getSourceUrl() : dataHolder.getTargetUrl(), value.getWrapped());
}
catch (IOException e) {
}
}
};
}
catch (IOException e) {
cache = new ValueHolder<WrapperInvertor<BranchCopyData>, KeyData>() {
public WrapperInvertor<BranchCopyData> getValue(KeyData dataHolder) {
return null;
}
public void setValue(WrapperInvertor<BranchCopyData> value, KeyData dataHolder) {
}
};
}
myCalculator = new FactsCalculator<KeyData, WrapperInvertor<BranchCopyData>>(project, "Looking for branch origin", cache, new Loader(project));
}
private static class BranchDataExternalizer implements DataExternalizer<TreeMap<String,BranchCopyData>> {
public void save(DataOutput out, TreeMap<String,BranchCopyData> value) throws IOException {
out.writeInt(value.size());
for (Map.Entry<String, BranchCopyData> entry : value.entrySet()) {
out.writeUTF(entry.getKey());
final BranchCopyData entryValue = entry.getValue();
out.writeUTF(entryValue.getSource());
out.writeUTF(entryValue.getTarget());
out.writeLong(entryValue.getSourceRevision());
out.writeLong(entryValue.getTargetRevision());
}
}
public TreeMap<String,BranchCopyData> read(DataInput in) throws IOException {
final TreeMap<String,BranchCopyData> result = new TreeMap<String, BranchCopyData>();
final int num = in.readInt();
for (int i = 0; i < num; i++) {
final String key = in.readUTF();
final String source = in.readUTF();
final String target = in.readUTF();
final long sourceRevision = in.readLong();
final long targetRevision = in.readLong();
result.put(key, new BranchCopyData(source, sourceRevision, target, targetRevision));
}
return result;
}
}
public static class WrapperInvertor<T extends Invertor<T>> {
private final T myWrapped;
private final boolean myInvertedSense;
public WrapperInvertor(boolean invertedSense, T wrapped) {
myInvertedSense = invertedSense;
myWrapped = wrapped;
}
public boolean isInvertedSense() {
return myInvertedSense;
}
public T getWrapped() {
return myWrapped;
}
public T getTrue() {
return myInvertedSense ? myWrapped.invertSelf() : myWrapped;
}
public T inverted() {
return myWrapped.invertSelf();
}
}
private static class PersistentHolder {
private final PersistentHashMap<String, TreeMap<String, BranchCopyData>> myPersistentMap;
private final MultiMap<String, String> myForSearchMap;
private final Object myLock;
PersistentHolder(final File file) throws IOException {
myLock = new Object();
myPersistentMap = new PersistentHashMap<String, TreeMap<String, BranchCopyData>>(
file, new EnumeratorStringDescriptor(), new BranchDataExternalizer());
final Ref<IOException> excRef = new Ref<IOException>();
// list for values by default
myForSearchMap = new MultiMap<String, String>();
myPersistentMap.iterateData(new Processor<String>() {
public boolean process(final String s) {
try {
final TreeMap<String, BranchCopyData> map = myPersistentMap.get(s);
myForSearchMap.put(s, new ArrayList<String>(map.keySet()));
}
catch (IOException e) {
excRef.set(e);
return false;
}
return true;
}
});
if (! excRef.isNull()) {
throw excRef.get();
}
for (String key : myForSearchMap.keySet()) {
Collections.sort((List<String>) myForSearchMap.get(key));
}
}
public void put(final String uid, final String target, final BranchCopyData data) throws IOException {
// todo - rewrite of rather big piece; consider rewriting
synchronized (myLock) {
TreeMap<String, BranchCopyData> map = myPersistentMap.get(uid);
if (map == null) {
map = new TreeMap<String, BranchCopyData>();
}
map.put(target, data);
myPersistentMap.put(uid, map);
if (myForSearchMap.containsKey(uid)) {
final List<String> list = (List<String>)myForSearchMap.get(uid);
final int idx = Collections.binarySearch(list, target);
if (idx < 0) {
final int insertionIdx = - idx - 1;
list.add(insertionIdx, target);
}
} else {
myForSearchMap.putValue(uid, target);
}
}
myPersistentMap.force();
}
@Nullable
public WrapperInvertor<BranchCopyData> getBestHit(final String repoUrl, final String source, final String target) throws IOException {
final List<String> keys;
synchronized (myLock) {
keys = (List<String>) myForSearchMap.get(repoUrl);
}
// keys are never removed, so we can use 2 synchronized blocks
final String sourceMatching = getMatchingUrl(keys, source);
final String targetMatching = getMatchingUrl(keys, target);
if (sourceMatching == null && targetMatching == null) return null;
synchronized (myLock) {
final TreeMap<String, BranchCopyData> map = myPersistentMap.get(repoUrl);
final boolean sourceIsOut = sourceMatching == null;
if (sourceIsOut || targetMatching == null) {
// if found by "target" url - we correctly thought that target of copy is target
return sourceIsOut ? new WrapperInvertor<BranchCopyData>(false, map.get(targetMatching)) :
new WrapperInvertor<BranchCopyData>(false, map.get(sourceMatching));
}
final BranchCopyData sourceData = map.get(sourceMatching);
final BranchCopyData targetData = map.get(targetMatching);
final boolean inverted = sourceData.getTargetRevision() > targetData.getTargetRevision();
return new WrapperInvertor<BranchCopyData>(inverted, inverted ? sourceData : targetData);
}
}
@Nullable
private String getMatchingUrl(List<String> keys, String source) {
final int idx = Collections.binarySearch(keys, source);
if (idx >= 0) return keys.get(idx);
final int beforeInsertionIdx = - idx - 2;
if (beforeInsertionIdx < 0) return null;
final String candidate = keys.get(beforeInsertionIdx);
if (source.startsWith(candidate)) return candidate;
return null;
}
}
private static class Loader implements Convertor<KeyData, WrapperInvertor<BranchCopyData>> {
private SvnVcs myVcs;
private Loader(final Project project) {
myVcs = SvnVcs.getInstance(project);
}
public WrapperInvertor<BranchCopyData> convert(final KeyData keyData) {
final Ref<WrapperInvertor<BranchCopyData>> result = new Ref<WrapperInvertor<BranchCopyData>>();
new FirstInBranch(myVcs, keyData.getRepoUrl(), keyData.getTargetUrl(), keyData.getSourceUrl(), new Consumer<CopyData>() {
public void consume(CopyData copyData) {
if (copyData != null) {
final boolean correct = copyData.isTrunkSupposedCorrect();
final BranchCopyData branchCopyData;
if (correct) {
branchCopyData = new BranchCopyData(keyData.getSourceUrl(), copyData.getCopySourceRevision(), keyData.getTargetUrl(),
copyData.getCopyTargetRevision());
} else {
branchCopyData = new BranchCopyData(keyData.getTargetUrl(), copyData.getCopySourceRevision(), keyData.getSourceUrl(),
copyData.getCopyTargetRevision());
}
result.set(new WrapperInvertor<BranchCopyData>(! correct, branchCopyData));
}
}
}).run();
return result.get();
}
}
private static class KeyData {
private final String myRepoUrl;
private final String mySourceUrl;
private final String myTargetUrl;
public KeyData(final String repoUID, final String sourceUrl, final String targetUrl) {
myRepoUrl = repoUID;
mySourceUrl = sourceUrl;
myTargetUrl = targetUrl;
}
public String getRepoUrl() {
return myRepoUrl;
}
public String getSourceUrl() {
return mySourceUrl;
}
public String getTargetUrl() {
return myTargetUrl;
}
}
public static class BranchCopyData implements Invertor<BranchCopyData> {
private final String mySource;
private final String myTarget;
private final long mySourceRevision;
private final long myTargetRevision;
public BranchCopyData(String source, long sourceRevision, String target, long targetRevision) {
mySource = source;
mySourceRevision = sourceRevision;
myTarget = target;
myTargetRevision = targetRevision;
}
public String getSource() {
return mySource;
}
public long getSourceRevision() {
return mySourceRevision;
}
public String getTarget() {
return myTarget;
}
public long getTargetRevision() {
return myTargetRevision;
}
public BranchCopyData invertSelf() {
return new BranchCopyData(myTarget, myTargetRevision, mySource, mySourceRevision);
}
}
private interface Invertor<T> {
T invertSelf();
}
public void getFirstCopyPoint(final String repoUID, final String sourceUrl, final String targetUrl, Consumer<WrapperInvertor<BranchCopyData>> consumer) {
myCalculator.get(new KeyData(repoUID, sourceUrl, targetUrl), consumer);
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2000-2010 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.idea.svn.history;
public class CopyData {
private final long myCopySourceRevision;
private final long myCopyTargetRevision;
private final boolean myTrunkSupposedCorrect;
public CopyData(long copySourceRevision, long copyTargetRevision, boolean trunkSupposedCorrect) {
myCopySourceRevision = copySourceRevision;
myCopyTargetRevision = copyTargetRevision;
myTrunkSupposedCorrect = trunkSupposedCorrect;
}
public long getCopySourceRevision() {
return myCopySourceRevision;
}
public long getCopyTargetRevision() {
return myCopyTargetRevision;
}
public boolean isTrunkSupposedCorrect() {
return myTrunkSupposedCorrect;
}
}
@@ -15,6 +15,9 @@
*/
package org.jetbrains.idea.svn.history;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.ConcurrentTasks;
import com.intellij.util.Consumer;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.*;
@@ -26,27 +29,16 @@ import java.util.Map;
public class FirstInBranch implements Runnable {
private final SvnVcs myVcs;
private final String myRepositoryRoot;
private final String myFullBranchUrl;
private final String myFullTrunkUrl;
private final String myBranchUrl;
private final String myTrunkUrl;
private final Consumer<CopyData> myConsumer;
private CopyData myResult;
private final boolean myPrimary;
public FirstInBranch(final SvnVcs vcs, final String repositoryRoot, final String branchUrl, final String trunkUrl, final Consumer<CopyData> consumer) {
this(vcs, repositoryRoot, branchUrl, trunkUrl, consumer, true);
}
public FirstInBranch(final SvnVcs vcs, final String repositoryRoot, final String branchUrl, final String trunkUrl, final Consumer<CopyData> consumer, final boolean primary) {
myPrimary = primary;
myVcs = vcs;
myRepositoryRoot = repositoryRoot;
myConsumer = consumer;
myResult = null;
myFullBranchUrl = branchUrl;
myFullTrunkUrl = trunkUrl;
myBranchUrl = relativePath(repositoryRoot, branchUrl);
@@ -59,65 +51,84 @@ public class FirstInBranch implements Runnable {
}
public void run() {
final SVNLogClient logClient = myVcs.createLogClient();
final SVNURL branchURL;
final SVNURL trunkURL;
try {
logClient.doLog(SVNURL.parseURIEncoded(myFullBranchUrl), null, SVNRevision.UNDEFINED, SVNRevision.HEAD, SVNRevision.create(0), true, true, 0,
new ISVNLogEntryHandler() {
public void handleLogEntry(final SVNLogEntry logEntry) throws SVNException {
final Map map = logEntry.getChangedPaths();
for (Object o : map.values()) {
final SVNLogEntryPath path = (SVNLogEntryPath) o;
final String localPath = path.getPath();
final String copyPath = path.getCopyPath();
if ('A' == path.getType() &&
(myBranchUrl.equals(localPath) || SVNPathUtil.isAncestor(localPath, myBranchUrl)) &&
(myTrunkUrl.equals(copyPath)) || SVNPathUtil.isAncestor(copyPath, myTrunkUrl)) {
myResult = new CopyData(path.getCopyRevision(), logEntry.getRevision(), myPrimary);
throw new MockException();
}
}
}
});
}
catch (MockException e) {
myConsumer.consume(myResult);
return;
branchURL = SVNURL.parseURIEncoded(myFullBranchUrl);
trunkURL = SVNURL.parseURIEncoded(myFullTrunkUrl);
}
catch (SVNException e) {
myConsumer.consume(myResult);
myConsumer.consume(null);
return;
}
if (myPrimary) {
new FirstInBranch(myVcs, myRepositoryRoot, myFullTrunkUrl, myFullBranchUrl, myConsumer, false).run();
final ConcurrentTasks<CopyData> tasks =
new ConcurrentTasks<CopyData>(ProgressManager.getInstance().getProgressIndicator(), createTask(branchURL), createTask(trunkURL));
tasks.compute();
if (tasks.isResultKnown()) {
myConsumer.consume(tasks.getResult());
} else {
myConsumer.consume(myResult);
myConsumer.consume(null);
}
}
private static class MockException extends RuntimeException {}
private Consumer<Consumer<CopyData>> createTask(final SVNURL branchURL) {
return new Consumer<Consumer<CopyData>>() {
public void consume(final Consumer<CopyData> copyDataConsumer) {
final SVNLogClient logClient = myVcs.createLogClient();
final long start1 = getStart(logClient, branchURL);
if (start1 > 0) {
final SVNRevision start1Rev = SVNRevision.create(start1);
try {
logClient.doLog(branchURL, null, SVNRevision.UNDEFINED, start1Rev, start1Rev, true, true, 1, new ISVNLogEntryHandler() {
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
checkForCopy(logEntry, copyDataConsumer);
}
});
} catch (SVNException e) {
//
}
}
}
};
}
public static class CopyData {
private final long myCopySourceRevision;
private final long myCopyTargetRevision;
private final boolean myTrunkSupposedCorrect;
private static long getStart(final SVNLogClient logClient, final SVNURL url) {
final Ref<Long> myRevisionCandidate = new Ref<Long>(0L);
try {
logClient.doLog(url, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, SVNRevision.create(0),
true, false, 0, new ISVNLogEntryHandler() {
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
ProgressManager.checkCanceled();
public CopyData(long copySourceRevision, long copyTargetRevision, boolean trunkSupposedCorrect) {
myCopySourceRevision = copySourceRevision;
myCopyTargetRevision = copyTargetRevision;
myTrunkSupposedCorrect = trunkSupposedCorrect;
myRevisionCandidate.set(logEntry.getRevision());
}
});
}
public long getCopySourceRevision() {
return myCopySourceRevision;
catch (SVNException e) {
//
}
return myRevisionCandidate.get();
}
public long getCopyTargetRevision() {
return myCopyTargetRevision;
}
private void checkForCopy(final SVNLogEntry logEntry, final Consumer<CopyData> result) {
final Map map = logEntry.getChangedPaths();
for (Object o : map.values()) {
final SVNLogEntryPath path = (SVNLogEntryPath) o;
final String localPath = path.getPath();
final String copyPath = path.getCopyPath();
public boolean isTrunkSupposedCorrect() {
return myTrunkSupposedCorrect;
if ('A' == path.getType()) {
if ((myBranchUrl.equals(localPath) || SVNPathUtil.isAncestor(localPath, myBranchUrl)) &&
(myTrunkUrl.equals(copyPath)) || SVNPathUtil.isAncestor(copyPath, myTrunkUrl)) {
result.consume(new CopyData(path.getCopyRevision(), logEntry.getRevision(), true));
} else {
if ((myBranchUrl.equals(copyPath) || SVNPathUtil.isAncestor(copyPath, myBranchUrl)) &&
(myTrunkUrl.equals(localPath)) || SVNPathUtil.isAncestor(localPath, myTrunkUrl)) {
result.consume(new CopyData(path.getCopyRevision(), logEntry.getRevision(), false));
}
}
}
}
}
}
@@ -56,16 +56,20 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
private final List<VcsException> myExceptions;
private final UpdateEventHandler myHandler;
private final IMerger myMerger;
private final ResolveWorker myResolveWorker;
private UpdateEventHandler myHandler;
private IMerger myMerger;
private ResolveWorker myResolveWorker;
private FilePathImpl myMergeTarget;
private final String myTitle;
private final MergerFactory myMergerFactory;
private final SVNURL myCurrentBranchUrl;
private boolean myDryRun;
public SvnIntegrateChangesTask(final SvnVcs vcs, final WorkingCopyInfo info, final MergerFactory mergerFactory,
final SVNURL currentBranchUrl, final String title, final boolean dryRun) {
super(vcs.getProject(), title, true, VcsConfiguration.getInstance(vcs.getProject()).getUpdateOption());
myMergerFactory = mergerFactory;
myCurrentBranchUrl = currentBranchUrl;
myDryRun = dryRun;
myTitle = title;
@@ -76,10 +80,6 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
myAccomulatedFiles = new UpdatedFilesReverseSide(UpdatedFiles.create());
myExceptions = new ArrayList<VcsException>();
myHandler = new IntegrateEventHandler(myVcs, ProgressManager.getInstance().getProgressIndicator());
myMerger = mergerFactory.createMerger(myVcs, new File(info.getLocalPath()), myHandler, currentBranchUrl);
myResolveWorker = new ResolveWorker(myInfo.isUnderProjectRoot(), myProject);
}
private void indicatorOnStart() {
@@ -93,6 +93,10 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable {
}
public void run(@NotNull final ProgressIndicator indicator) {
myHandler = new IntegrateEventHandler(myVcs, ProgressManager.getInstance().getProgressIndicator());
myMerger = myMergerFactory.createMerger(myVcs, new File(myInfo.getLocalPath()), myHandler, myCurrentBranchUrl);
myResolveWorker = new ResolveWorker(myInfo.isUnderProjectRoot(), myProject);
BlockReloadingUtil.block();
myProjectLevelVcsManager.startBackgroundVcsOperation();
@@ -157,6 +157,7 @@ public class BranchInfo {
final String absoluteInTrunkPath = SVNPathUtil.append(myRepositoryRoot, path);
if (! absoluteInTrunkPath.startsWith(myTrunkPathCorrespondingToLocalBranchPath)) {
result.putValue(SvnMergeInfoCache.MergeCheckResult.NOT_EXISTS, path);
continue;
}
final String relativeToTrunkPath = absoluteInTrunkPath.substring(myTrunkPathCorrespondingToLocalBranchPath.length());
final String localPathInBranch = new File(branchPath, relativeToTrunkPath).getAbsolutePath();
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.dialogs.WCInfoWithBranches;
import org.jetbrains.idea.svn.dialogs.WCPaths;
import org.jetbrains.idea.svn.history.CopyData;
import org.jetbrains.idea.svn.history.FirstInBranch;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
@@ -167,8 +168,8 @@ public class SvnMergeInfoCache {
myRevision = -1;
ApplicationManager.getApplication().executeOnPooledThread(new FirstInBranch(vcs, repositoryRoot, branchUrl, trunkUrl,
new Consumer<FirstInBranch.CopyData>() {
public void consume(FirstInBranch.CopyData copyData) {
new Consumer<CopyData>() {
public void consume(CopyData copyData) {
if (copyData == null) return;
myRevision = copyData.getCopySourceRevision();
if (myRevision != -1) {
@@ -42,6 +42,6 @@
Property <font color="#000080"><b>abc</b></font> will be reported as unnecessarily inherited in the file <b>messages_fr.properties</b>.
<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -8,6 +8,6 @@
or configuring the <b>Settings|General|File Encoding|Default encoding</b> setting,
or by setting up the file/directory encoding in the <b>Settings|File/Directory Options|File Encodings</b>.
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -4,6 +4,6 @@
This inspection lets you control MIME type name validity.
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -9,6 +9,6 @@
<li>another <b><font color="#000080">@TestOnly</font></b>-annotated method
</ul>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,6 +3,6 @@
<font face="verdana" size="-1">This inspection reports libraries attached to the specified inspection scope that
are not used directly from code.<br><br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,6 +3,6 @@
<font face="verdana" size="-1">Checks consistency of <b>DTD</b> specific references, e.g. references to XML entity or to DTD element declaration.
The validation works in DTD or XML file types.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,7 +3,7 @@
<font face="verdana" size="-1">Reports empty tags (like <b>script</b>) that do not work in some browsers.
The validation works in html or jsp file types.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,6 +3,6 @@
<font face="verdana" size="-1">Reports <b>empty</b> tag body.
The validation works in XML / JSP / JSPX / HTML/ XHTML file types.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,6 +3,6 @@
<font face="verdana" size="-1">Thoroughly checks XML files for DTD / schema compliance using Xerces validator.
The validation works in XML or XHTML file types.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -2,6 +2,6 @@
<body>
<font face="verdana" size="-1">This inspection spots extra closing tag for the empty elements like IMG or BR.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,6 +3,6 @@
<font face="verdana" size="-1">This inspection highlight unknown HTML tag attributes as invalid and provides an ability to mark
such attributes as Custom to not highlight them as invalid.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -3,6 +3,6 @@
<font face="verdana" size="-1">This inspection highlights unknown HTML tags and provides an ability to mark such tags as Custom to
not highlight them as unknown in future.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>
@@ -2,6 +2,6 @@
<body>
<font face="verdana" size="-1">This inspection checks if root tag name is the same as in &lt;doctype&gt;.<br>
</font>
<p><font face="verdana" size="-2">New in 7</font></p>
</body>
</html>