Merge remote branch 'origin/master'

This commit is contained in:
irengrig
2012-12-17 18:27:14 +04:00
183 changed files with 2537 additions and 2503 deletions
+1 -3
View File
@@ -504,9 +504,7 @@
<inspection_tool class="ShiftOutOfRangeJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SillyAssignmentJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true">
<scope name="Tests" level="ERROR" enabled="false" />
</inspection_tool>
<inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SingletonInjectsScoped" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
+1 -3
View File
@@ -667,9 +667,7 @@
<inspection_tool class="SillyAssignmentJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifiableConditionalExpression" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true">
<scope name="Tests" level="ERROR" enabled="false" />
</inspection_tool>
<inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SingletonInjectsScoped" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="insideTryAllowed" value="false" />
@@ -38,6 +38,7 @@ import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.rt.compiler.JavacRunner;
@@ -295,9 +296,10 @@ public class JavacCompiler extends ExternalCompiler {
additionalOptions.add("-processorpath");
additionalOptions.add(FileUtil.toSystemDependentName(processorPath));
}
for (String processorName : config.getProcessors()) {
final Set<String> processors = config.getProcessors();
if (!processors.isEmpty()) {
additionalOptions.add("-processor");
additionalOptions.add(processorName);
additionalOptions.add(StringUtil.join(processors, ","));
}
for (Map.Entry<String, String> entry : config.getProcessorOptions().entrySet()) {
additionalOptions.add("-A" + entry.getKey() + "=" +entry.getValue());
@@ -807,7 +807,7 @@ public class BuildManager implements ApplicationComponent{
cmdLine.setCharset(mySystemCharset);
cmdLine.addParameter("-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + mySystemCharset.name());
}
for (String name : new String[]{"user.language", "user.country", "user.region"}) {
for (String name : new String[]{"user.language", "user.country", "user.region", PathManager.PROPERTY_HOME_PATH}) {
final String value = System.getProperty(name);
if (value != null) {
cmdLine.addParameter("-D" + name + "=" + value);
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.Stack;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
@@ -104,14 +105,16 @@ public class JavaArrangementParseInfo {
Stack<Pair<PsiMethod, JavaArrangementMethodDependencyInfo>> toProcess
= new Stack<Pair<PsiMethod, JavaArrangementMethodDependencyInfo>>();
toProcess.push(Pair.create(method, result));
Set<PsiMethod> usedMethods = ContainerUtilRt.newHashSet();
while (!toProcess.isEmpty()) {
Pair<PsiMethod, JavaArrangementMethodDependencyInfo> pair = toProcess.pop();
Set<PsiMethod> dependentMethods = myMethodDependencies.get(pair.first);
if (dependentMethods == null) {
continue;
}
usedMethods.add(pair.first);
for (PsiMethod dependentMethod : dependentMethods) {
if (dependentMethod == method) {
if (usedMethods.contains(dependentMethod)) {
// Prevent cyclic dependencies.
return null;
}
@@ -21,7 +21,6 @@ import com.intellij.formatting.alignment.AlignmentInColumnsHelper;
import com.intellij.formatting.alignment.AlignmentStrategy;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -156,7 +155,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
Wrap wrap,
@NotNull AlignmentStrategy alignmentStrategy,
int startOffset) {
Indent actualIndent = indent == null ? getDefaultSubtreeIndent(child, settings.getRootSettings().getIndentOptions(StdFileTypes.JAVA)) : indent;
Indent actualIndent = indent == null ? getDefaultSubtreeIndent(child, getJavaIndentOptions(settings)) : indent;
final IElementType elementType = child.getElementType();
Alignment alignment = alignmentStrategy.getAlignment(elementType);
@@ -207,10 +206,17 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
@NotNull
public static Block createJavaBlock(@NotNull ASTNode child, @NotNull CommonCodeStyleSettings settings) {
return createJavaBlock(child, settings, getDefaultSubtreeIndent(child, settings.getRootSettings().getIndentOptions(StdFileTypes.JAVA)),
return createJavaBlock(child, settings, getDefaultSubtreeIndent(child, getJavaIndentOptions(settings)),
null, AlignmentStrategy.getNullStrategy());
}
@NotNull
private static CommonCodeStyleSettings.IndentOptions getJavaIndentOptions(CommonCodeStyleSettings settings) {
CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptions();
assert indentOptions != null : "Java indent options are not initialized";
return indentOptions;
}
private static boolean isLikeExtendsList(final IElementType elementType) {
return elementType == JavaElementType.EXTENDS_LIST
|| elementType == JavaElementType.IMPLEMENTS_LIST
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.introduceField;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -37,7 +38,8 @@ import java.awt.event.ItemListener;
public abstract class IntroduceFieldCentralPanel {
protected static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceField.IntroduceFieldDialog");
public static boolean ourLastCbFinalState = false;
private static final String INTRODUCE_FIELD_FINAL_CHECKBOX = "introduce.final.checkbox";
public static boolean ourLastCbFinalState = PropertiesComponent.getInstance().getBoolean(INTRODUCE_FIELD_FINAL_CHECKBOX, true);
protected final PsiClass myParentClass;
protected final PsiExpression myInitializerExpression;
@@ -273,6 +275,7 @@ public abstract class IntroduceFieldCentralPanel {
public void saveFinalState() {
if (myCbFinal != null && myCbFinal.isEnabled()) {
ourLastCbFinalState = myCbFinal.isSelected();
PropertiesComponent.getInstance().setValue(INTRODUCE_FIELD_FINAL_CHECKBOX, String.valueOf(ourLastCbFinalState));
}
}
@@ -92,7 +92,7 @@ public class IntroduceFieldPopupPanel extends IntroduceFieldCentralPanel {
@Override
public boolean isDeclareFinal() {
return allowFinal();
return ourLastCbFinalState && allowFinal();
}
private void selectInCurrentMethod() {
@@ -139,7 +139,7 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro
PsiExpression expression = refVariableElement instanceof PsiKeyword && refVariableElementParent instanceof PsiNewExpression
? (PsiNewExpression)refVariableElementParent
: PsiTreeUtil.getParentOfType(refVariableElement, PsiReferenceExpression.class);
if (expression instanceof PsiReferenceExpression) {
if (expression instanceof PsiReferenceExpression && !(expression.getParent() instanceof PsiMethodCallExpression)) {
final String referenceName = ((PsiReferenceExpression)expression).getReferenceName();
if (((PsiReferenceExpression)expression).resolve() == psiVariable ||
Comparing.strEqual(psiVariable.getName(), referenceName) ||
@@ -132,8 +132,11 @@ public class MethodCandidateInfo extends CandidateInfo{
public boolean isTypeArgumentsApplicable() {
PsiTypeParameter[] typeParams = getElement().getTypeParameters();
if (myTypeArguments != null && typeParams.length != myTypeArguments.length) return false;
final PsiMethod psiMethod = getElement();
PsiTypeParameter[] typeParams = psiMethod.getTypeParameters();
if (myTypeArguments != null && typeParams.length != myTypeArguments.length && !PsiUtil.isLanguageLevel7OrHigher(psiMethod)){
return false;
}
PsiSubstitutor substitutor = getSubstitutor();
return GenericsUtil.isTypeArgumentsApplicable(typeParams, substitutor, getParent());
}
@@ -159,7 +159,13 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
if (newBound instanceof PsiCapturedWildcardType) {
final PsiWildcardType wildcard = ((PsiCapturedWildcardType)newBound).getWildcard();
if (wildcardType.isExtends() != wildcard.isExtends()) {
return wildcard.isBounded() ? PsiWildcardType.createUnbounded(wildcardType.getManager()) : newBound;
if (wildcard.isBounded()) {
return wildcardType.isExtends() ? PsiWildcardType.createExtends(wildcardType.getManager(), newBound)
: PsiWildcardType.createSuper(wildcardType.getManager(), newBound);
}
else {
return newBound;
}
}
if (!wildcard.isBounded()) return PsiWildcardType.createUnbounded(wildcardType.getManager());
}
@@ -215,15 +215,15 @@ public class PsiSuperMethodImplUtil {
LOG.assertTrue(copy.getMethod().isValid());
map.put(signature, copy);
}
else if (isSuperMethod(aClass, existing, hierarchicalMethodSignature)) {
mergeSupers(existing, hierarchicalMethodSignature);
}
else if (isReturnTypeIsMoreSpecificThan(hierarchicalMethodSignature, existing) && isSuperMethod(aClass, hierarchicalMethodSignature, existing)) {
HierarchicalMethodSignatureImpl newSuper = copy(hierarchicalMethodSignature);
mergeSupers(newSuper, existing);
LOG.assertTrue(newSuper.getMethod().isValid());
map.put(signature, newSuper);
}
else if (isSuperMethod(aClass, existing, hierarchicalMethodSignature)) {
mergeSupers(existing, hierarchicalMethodSignature);
}
// just drop an invalid method declaration there - to highlight accordingly
else if (!result.containsKey(signature)) {
LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid());
@@ -0,0 +1,11 @@
class TcpConnection extends ClientConnection {
ConnectionEventDelegate<? extends ClientConnection> eventDelegate;
{
eventDelegate.<ClientConnection> onDisconnect<error descr="'onDisconnect(capture<? extends ClientConnection>)' in 'ConnectionEventDelegate' cannot be applied to '(TcpConnection)'">(this)</error>;
}
}
class ClientConnection {}
interface ConnectionEventDelegate<T extends ClientConnection> {
void onDisconnect(T t);
}
@@ -0,0 +1,15 @@
import java.util.List;
interface ExampleInterface {
public List exampleMethod();
}
class ExampleSuperClass {
public List<String> exampleMethod() {
return null;
}
}
public class ExampleSubClass extends ExampleSuperClass implements ExampleInterface {
}
@@ -0,0 +1,15 @@
class NodeProperty<A, B> {}
class NodeType {}
class NumberExpression extends NodeType {}
class Node<NodeTypeT extends NodeType> {
public <ValueT> ValueT get(NodeProperty<? super NodeTypeT, ValueT> prop) {
return null;
}
}
class Main {
public static void main(NodeProperty<NumberExpression, Integer> nval, Node<? extends NodeType> expr) {
int val = expr.get<error descr="'get(NodeProperty<? super capture<? extends NodeType>,java.lang.Integer>)' in 'Node' cannot be applied to '(NodeProperty<NumberExpression,java.lang.Integer>)'">(nval)</error>;
}
}
@@ -0,0 +1,10 @@
class A {
int f() {
return 0;
}
void m() {
f<caret>();
f();
}
}
@@ -0,0 +1,9 @@
class A {
int f() {
return 0;
}
void m(int f) {
f();
}
}
@@ -205,6 +205,8 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testInstanceClassInStaticContextAccess() throws Exception { doTest17Incompatibility(false); }
public void testFlattenIntersectionType() throws Exception { doTest17Incompatibility(false); }
public void testIDEA97276() throws Exception { doTest17Incompatibility(false); }
public void testWildcardsBoundsIntersection() throws Exception { doTest17Incompatibility(false); }
public void testOverrideWithMoreSpecificReturn() throws Exception { doTest17Incompatibility(false); }
public void testJavaUtilCollections_NoVerify() throws Exception {
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
@@ -160,4 +160,5 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
public void testUncheckedWarningIDEA26738() throws Exception { doTest(true, false); }
public void testDefaultMethodVisibility() throws Exception { doTest(true, false); }
public void testEnclosingInstance() throws Exception { doTest(false, false); }
public void testWrongArgsAndUnknownTypeParams() throws Exception { doTest(false, false); }
}
@@ -128,6 +128,6 @@ public class LossyEncodingTest extends LightDaemonAnalyzerTestCase {
doHighlighting();
List<HighlightInfo> infos = DaemonCodeAnalyzerImpl.getFileLevelHighlights(getProject(), getFile());
HighlightInfo info = assertOneElement(infos);
assertEquals("File was loaded in a wrong encoding: 'UTF-8'", info.description);
assertEquals("File was loaded in the wrong encoding: 'UTF-8'", info.description);
}
}
@@ -255,7 +255,8 @@ public class InspectionProfileTest extends LightIdeaTestCase {
InspectionProfileEntry[] tools = profile.getInspectionTools(null);
assertTrue(tools.length > 0);
InspectionProfileEntry tool = tools[0];
String id = tool.getShortName();
String id = tool.getShortName();
System.out.println(id);
if (profile.isToolEnabled(HighlightDisplayKey.findById(id))) {
profile.disableTool(id);
}
@@ -152,6 +152,6 @@ public class TypeInferenceTest extends Resolve15TestCase {
}
public void testBoundComposition() throws Exception {
checkResolvesTo("java.lang.Class<?>");
checkResolvesTo("java.lang.Class<? super ? extends java.lang.Object>");
}
}
@@ -69,6 +69,14 @@ public class InplaceIntroduceParameterTest extends AbstractJavaInplaceIntroduceT
});
}
public void testParamNameEqMethodName() throws Exception {
doTest(new Pass<AbstractInplaceIntroducer>() {
@Override
public void pass(AbstractInplaceIntroducer inplaceIntroducePopup) {
}
});
}
@Override
protected String getBasePath() {
return BASE_PATH;
@@ -58,6 +58,7 @@
</item>
<item name='java.lang.String byte[] getBytes(java.lang.String) 0'>
<annotation name='org.jetbrains.annotations.NonNls'/>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='java.lang.RuntimeException RuntimeException(java.lang.String) 0'>
<annotation name='org.jetbrains.annotations.NonNls'/>
@@ -98,4 +99,7 @@
<item name='java.lang.Class java.lang.reflect.Field getField(java.lang.String) 0'>
<annotation name='org.jetbrains.annotations.NonNls'/>
</item>
<item name='java.lang.String byte[] getBytes(java.nio.charset.Charset) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1 @@
org.jetbrains.jps.incremental.java.AnnotationsExcludedJavaSourceRootProvider
@@ -21,7 +21,6 @@ import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsDummyElement;
import org.jetbrains.jps.model.JpsProject;
import org.jetbrains.jps.model.JpsSimpleElement;
import org.jetbrains.jps.model.java.*;
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
@@ -41,30 +40,25 @@ import java.util.*;
* Date: 9/30/11
*/
public class ProjectPaths {
@NotNull
private final JpsProject myProject;
//private final Map<JpsJavaClasspathKind, Map<ModuleChunk, List<String>>> myCachedClasspath = new HashMap<JpsJavaClasspathKind, Map<ModuleChunk, List<String>>>();
public ProjectPaths(@NotNull JpsProject project) {
myProject = project;
private ProjectPaths() {
}
public Collection<File> getCompilationClasspathFiles(ModuleChunk chunk,
public static Collection<File> getCompilationClasspathFiles(ModuleChunk chunk,
boolean includeTests,
final boolean excludeMainModuleOutput,
final boolean exportedOnly) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(includeTests), excludeMainModuleOutput, ClasspathPart.WHOLE, exportedOnly);
}
public Collection<File> getPlatformCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
public static Collection<File> getPlatformCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.BEFORE_JDK, true);
}
public Collection<File> getCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
public static Collection<File> getCompilationClasspath(ModuleChunk chunk, boolean excludeMainModuleOutput) {
return getClasspathFiles(chunk, JpsJavaClasspathKind.compile(chunk.containsTests()), excludeMainModuleOutput, ClasspathPart.AFTER_JDK, true);
}
private Collection<File> getClasspathFiles(ModuleChunk chunk,
private static Collection<File> getClasspathFiles(ModuleChunk chunk,
JpsJavaClasspathKind kind,
final boolean excludeMainModuleOutput,
ClasspathPart classpathPart, final boolean exportedOnly) {
@@ -159,12 +153,12 @@ public class ProjectPaths {
}
@Nullable
public File getModuleOutputDir(JpsModule module, boolean forTests) {
public static File getModuleOutputDir(JpsModule module, boolean forTests) {
return JpsJavaExtensionService.getInstance().getOutputDirectory(module, forTests);
}
@Nullable
public File getAnnotationProcessorGeneratedSourcesOutputDir(JpsModule module, final boolean forTests, ProcessorConfigProfile profile) {
public static File getAnnotationProcessorGeneratedSourcesOutputDir(JpsModule module, final boolean forTests, ProcessorConfigProfile profile) {
final String sourceDirName = profile.getGeneratedSourcesDirectoryName(forTests);
if (profile.isOutputRelativeToContentRoot()) {
List<String> roots = module.getContentRootsList().getUrls();
@@ -20,6 +20,7 @@ import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
/**
*
* @author nik
*/
public abstract class ExcludedJavaSourceRootProvider {
@@ -16,15 +16,11 @@
package org.jetbrains.jps.incremental;
import com.intellij.openapi.util.UserDataHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.builders.logging.BuildLoggingManager;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
import org.jetbrains.jps.model.module.JpsModule;
/**
* @author Eugene Zhuravlev
@@ -33,8 +29,6 @@ import org.jetbrains.jps.model.module.JpsModule;
public interface CompileContext extends UserDataHolder, MessageHandler {
ProjectDescriptor getProjectDescriptor();
ProjectPaths getProjectPaths();
CompileScope getScope();
boolean isMake();
@@ -48,10 +42,6 @@ public interface CompileContext extends UserDataHolder, MessageHandler {
void removeBuildListener(BuildListener listener);
@NotNull
ProcessorConfigProfile getAnnotationProcessingProfile(JpsModule module);
boolean shouldDifferentiate(ModuleChunk chunk);
CanceledStatus getCancelStatus();
@@ -18,10 +18,8 @@ package org.jetbrains.jps.incremental;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.EventDispatcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.builders.logging.BuildLoggingManager;
@@ -30,10 +28,6 @@ import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.FileDeletedEvent;
import org.jetbrains.jps.incremental.messages.FileGeneratedEvent;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
import org.jetbrains.jps.model.module.JpsModule;
import java.util.*;
@@ -49,14 +43,12 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
private final MessageHandler myDelegateMessageHandler;
private final Set<ModuleBuildTarget> myNonIncrementalModules = new HashSet<ModuleBuildTarget>();
private final ProjectPaths myProjectPaths;
private volatile long myCompilationStartStamp;
private final ProjectDescriptor myProjectDescriptor;
private final Map<String, String> myBuilderParams;
private final CanceledStatus myCancelStatus;
private volatile float myDone = -1.0f;
private EventDispatcher<BuildListener> myListeners = EventDispatcher.create(BuildListener.class);
private Map<JpsModule, ProcessorConfigProfile> myAnnotationProcessingProfileMap;
public CompileContextImpl(CompileScope scope,
ProjectDescriptor pd, boolean isMake,
@@ -72,7 +64,6 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
myIsProjectRebuild = isProjectRebuild;
myIsMake = !isProjectRebuild && isMake;
myDelegateMessageHandler = delegateMessageHandler;
myProjectPaths = new ProjectPaths(pd.getProject());
}
@Override
@@ -85,11 +76,6 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
myCompilationStartStamp = System.currentTimeMillis();
}
@Override
public ProjectPaths getProjectPaths() {
return myProjectPaths;
}
@Override
public boolean isMake() {
return myIsMake;
@@ -121,34 +107,6 @@ public class CompileContextImpl extends UserDataHolderBase implements CompileCon
myListeners.removeListener(listener);
}
@Override
@NotNull
public ProcessorConfigProfile getAnnotationProcessingProfile(JpsModule module) {
final JpsJavaCompilerConfiguration compilerConfig = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
getProjectDescriptor().getProject());
Map<JpsModule, ProcessorConfigProfile> map = myAnnotationProcessingProfileMap;
if (map == null) {
map = new HashMap<JpsModule, ProcessorConfigProfile>();
final Map<String, JpsModule> namesMap = new HashMap<String, JpsModule>();
for (JpsModule m : getProjectDescriptor().getProject().getModules()) {
namesMap.put(m.getName(), m);
}
if (!namesMap.isEmpty()) {
for (ProcessorConfigProfile profile : compilerConfig.getAnnotationProcessingConfigurations()) {
for (String name : profile.getModuleNames()) {
final JpsModule mod = namesMap.get(name);
if (mod != null) {
map.put(mod, profile);
}
}
}
}
myAnnotationProcessingProfileMap = map;
}
final ProcessorConfigProfile profile = map.get(module);
return profile != null? profile : compilerConfig.getDefaultAnnotationProcessingConfiguration();
}
@Override
public void markNonIncremental(ModuleBuildTarget target) {
if (!target.isTests()) {
@@ -21,6 +21,7 @@ import com.intellij.util.SmartList;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.builders.*;
import org.jetbrains.jps.builders.java.ExcludedJavaSourceRootProvider;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
@@ -69,9 +70,11 @@ public final class ModuleBuildTarget extends JVMModuleBuildTarget<JavaSourceRoot
if (outputDir != null) {
result.add(outputDir);
}
final ProcessorConfigProfile profile = context.getAnnotationProcessingProfile(getModule());
final JpsModule module = getModule();
final JpsJavaCompilerConfiguration configuration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(module.getProject());
final ProcessorConfigProfile profile = configuration.getAnnotationProcessingProfile(module);
if (profile.isEnabled()) {
final File annotationOut = context.getProjectPaths().getAnnotationProcessorGeneratedSourcesOutputDir(getModule(), isTests(), profile);
final File annotationOut = ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir(module, isTests(), profile);
if (annotationOut != null) {
result.add(annotationOut);
}
@@ -20,7 +20,6 @@ import com.intellij.util.SmartList;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetRegistry;
@@ -37,7 +36,6 @@ import org.jetbrains.jps.model.java.JavaSourceRootProperties;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot;
import org.jetbrains.jps.service.JpsServiceManager;
@@ -113,34 +111,9 @@ public final class ResourcesTarget extends JVMModuleBuildTarget<ResourceRootDesc
addedRoots.add(rootFile);
}
final ProcessorConfigProfile profile = findAnnotationProcessingProfile(model);
if (profile != null) {
final File annotationOut = new ProjectPaths(model.getProject()).getAnnotationProcessorGeneratedSourcesOutputDir(getModule(), isTests(), profile);
if (annotationOut != null && !addedRoots.contains(annotationOut) && !FileUtil.filesEqual(annotationOut, getOutputDir())) {
roots.add(new ResourceRootDescriptor(annotationOut, this, true, "", computeRootExcludes(annotationOut, index)));
}
}
return roots;
}
@Nullable
private ProcessorConfigProfile findAnnotationProcessingProfile(JpsModel model) {
final Collection<ProcessorConfigProfile> allProfiles =
JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(model.getProject()).getAnnotationProcessingConfigurations();
ProcessorConfigProfile profile = null;
final String moduleName = getModule().getName();
for (ProcessorConfigProfile p : allProfiles) {
if (p.getModuleNames().contains(moduleName)) {
if (p.isEnabled()) {
profile = p;
}
break;
}
}
return profile;
}
@NotNull
@Override
public String getPresentableName() {
@@ -79,11 +79,9 @@ public abstract class ClassProcessingBuilder extends ModuleLevelBuilder {
try {
InstrumentationClassFinder finder = CLASS_FINDER.get(context); // try using shared finder
if (finder == null) {
final ProjectPaths paths = context.getProjectPaths();
final Collection<File> platformCp = paths.getPlatformCompilationClasspath(chunk, false);
final Collection<File> platformCp = ProjectPaths.getPlatformCompilationClasspath(chunk, false);
final Collection<File> classpath = new ArrayList<File>();
classpath.addAll(paths.getCompilationClasspath(chunk, false));
classpath.addAll(ProjectPaths.getCompilationClasspath(chunk, false));
classpath.addAll(ProjectPaths.getSourceRootsWithDependents(chunk).keySet());
finder = createInstrumentationClassFinder(platformCp, classpath, outputConsumer);
@@ -30,6 +30,7 @@ import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
@@ -118,7 +119,7 @@ public class RmiStubsGenerator extends ClassProcessingBuilder {
OutputConsumer outputConsumer) {
ExitCode exitCode = ExitCode.NOTHING_DONE;
final Collection<File> classpath = context.getProjectPaths().getCompilationClasspath(chunk, false);
final Collection<File> classpath = ProjectPaths.getCompilationClasspath(chunk, false);
final StringBuilder buf = new StringBuilder();
for (File file : classpath) {
if (buf.length() > 0) {
@@ -0,0 +1,49 @@
/*
* Copyright 2000-2012 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.jps.incremental.java;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ProjectPaths;
import org.jetbrains.jps.builders.java.ExcludedJavaSourceRootProvider;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
import java.io.File;
/**
* @author Eugene Zhuravlev
* Date: 12/14/12
*/
public class AnnotationsExcludedJavaSourceRootProvider extends ExcludedJavaSourceRootProvider{
@Override
public boolean isExcludedFromCompilation(@NotNull JpsModule module, @NotNull JpsModuleSourceRoot root) {
final JpsJavaCompilerConfiguration compilerConfig = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(module.getProject());
final ProcessorConfigProfile profile = compilerConfig.getAnnotationProcessingProfile(module);
if (!profile.isEnabled()) {
return false;
}
final File outputDir =
ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir(module, JavaSourceRootType.TEST_SOURCE == root.getRootType(), profile);
return outputDir != null && FileUtil.filesEqual(outputDir, root.getFile());
}
}
@@ -62,6 +62,7 @@ import java.net.ServerSocket;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Eugene Zhuravlev
@@ -74,6 +75,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null;
private static final Key<Integer> JAVA_COMPILER_VERSION_KEY = Key.create("_java_compiler_version_");
private static final Key<Boolean> IS_ENABLED = Key.create("_java_compiler_enabled_");
private static final Key<AtomicReference<String>> COMPILER_VERSION_INFO = Key.create("_java_compiler_version_info_");
private static final Set<String> FILTERED_OPTIONS = new HashSet<String>(Arrays.<String>asList(
"-target"
));
@@ -130,10 +133,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
else if (isEclipse) {
messageText = "Using eclipse compiler to compile java sources";
}
if (messageText != null) {
LOG.info(messageText);
context.processMessage(new CompilerMessage("", BuildMessage.Kind.INFO, messageText));
}
COMPILER_VERSION_INFO.set(context, new AtomicReference<String>(messageText));
}
public ExitCode build(final CompileContext context,
@@ -207,12 +207,11 @@ public class JavaBuilder extends ModuleLevelBuilder {
return exitCode;
}
final ProjectPaths paths = context.getProjectPaths();
final ProjectDescriptor pd = context.getProjectDescriptor();
JavaBuilderUtil.ensureModuleHasJdk(chunk.representativeTarget().getModule(), context, BUILDER_NAME);
final Collection<File> classpath = paths.getCompilationClasspath(chunk, false/*context.isProjectRebuild()*/);
final Collection<File> platformCp = paths.getPlatformCompilationClasspath(chunk, false/*context.isProjectRebuild()*/);
final Collection<File> classpath = ProjectPaths.getCompilationClasspath(chunk, false/*context.isProjectRebuild()*/);
final Collection<File> platformCp = ProjectPaths.getPlatformCompilationClasspath(chunk, false/*context.isProjectRebuild()*/);
// begin compilation round
final DiagnosticSink diagnosticSink = new DiagnosticSink(context);
@@ -221,6 +220,12 @@ public class JavaBuilder extends ModuleLevelBuilder {
final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getName());
try {
if (hasSourcesToCompile) {
final AtomicReference<String> ref = COMPILER_VERSION_INFO.get(context);
final String versionInfo = ref.getAndSet(null); // display compiler version info only once per compile session
if (versionInfo != null) {
LOG.info(versionInfo);
context.processMessage(new CompilerMessage("", BuildMessage.Kind.INFO, versionInfo));
}
exitCode = ExitCode.OK;
final Set<File> srcPath = new HashSet<File>();
@@ -291,14 +296,18 @@ public class JavaBuilder extends ModuleLevelBuilder {
final TasksCounter counter = new TasksCounter();
COUNTER_KEY.set(context, counter);
final JpsJavaExtensionService javaExt = JpsJavaExtensionService.getInstance();
final JpsJavaCompilerConfiguration compilerConfig = javaExt.getCompilerConfiguration(context.getProjectDescriptor().getProject());
assert compilerConfig != null;
final Set<JpsModule> modules = chunk.getModules();
ProcessorConfigProfile profile = null;
if (modules.size() == 1) {
profile = context.getAnnotationProcessingProfile(modules.iterator().next());
final JpsModule module = modules.iterator().next();
profile = compilerConfig.getAnnotationProcessingProfile(module);
}
else {
// perform cycle-related validations
final JpsJavaExtensionService javaExt = JpsJavaExtensionService.getInstance();
Pair<String, LanguageLevel> pair = null;
for (JpsModule module : modules) {
final LanguageLevel moduleLevel = javaExt.getLanguageLevel(module);
@@ -316,7 +325,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
// check that all chunk modules are excluded from annotation processing
for (JpsModule module : modules) {
final ProcessorConfigProfile prof = context.getAnnotationProcessingProfile(module);
final ProcessorConfigProfile prof = compilerConfig.getAnnotationProcessingProfile(module);
if (prof.isEnabled()) {
final String message = "Annotation processing is not supported for module cycles. Please ensure that all modules from cycle [" + chunk.getName() + "] are excluded from annotation processing";
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message));
@@ -328,6 +337,9 @@ public class JavaBuilder extends ModuleLevelBuilder {
final Map<File, Set<File>> outs = buildOutputDirectoriesMap(context, chunk);
final List<String> options = getCompilationOptions(context, chunk, profile);
final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink);
if (LOG.isDebugEnabled()) {
LOG.debug("Compiling chunk [" + chunk.getName() + "] with options: \"" + StringUtil.join(options, " ") + "\"");
}
try {
final boolean rc;
if (USE_EMBEDDED_JAVAC) {
@@ -581,16 +593,17 @@ public class JavaBuilder extends ModuleLevelBuilder {
options.add(processorsPath == null? "" : FileUtil.toSystemDependentName(processorsPath.trim()));
}
for (String procFQName : profile.getProcessors()) {
final Set<String> processors = profile.getProcessors();
if (!processors.isEmpty()) {
options.add("-processor");
options.add(procFQName);
options.add(StringUtil.join(processors, ","));
}
for (Map.Entry<String, String> optionEntry : profile.getProcessorOptions().entrySet()) {
options.add("-A" + optionEntry.getKey() + "=" + optionEntry.getValue());
}
final File srcOutput = context.getProjectPaths().getAnnotationProcessorGeneratedSourcesOutputDir(
final File srcOutput = ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir(
chunk.getModules().iterator().next(), chunk.containsTests(), profile
);
if (srcOutput != null) {
@@ -59,18 +59,14 @@ public class ModuleClasspathTest extends JpsRebuildTestCase {
public void testCompilationClasspath() {
ModuleChunk chunk = createChunk('main')
assertClasspath(["util/lib/exported.jar", "out/production/util", "/jdk.jar"],
getPathsList(getProjectPaths().getPlatformCompilationClasspath(chunk, true)))
getPathsList(ProjectPaths.getPlatformCompilationClasspath(chunk, true)))
assertClasspath(["main/lib/service.jar"],
getPathsList(getProjectPaths().getCompilationClasspath(chunk, true)))
}
private ProjectPaths getProjectPaths() {
return new ProjectPaths(myProject)
getPathsList(ProjectPaths.getCompilationClasspath(chunk, true)))
}
private def assertClasspath(String moduleName, boolean includeTests, List<String> expected) {
ModuleChunk chunk = createChunk(moduleName)
final List<String> classpath = getPathsList(new ProjectPaths(myProject).getCompilationClasspathFiles(chunk, includeTests, true, true))
final List<String> classpath = getPathsList(new ProjectPaths().getCompilationClasspathFiles(chunk, includeTests, true, true))
assertClasspath(expected, toSystemIndependentPaths(classpath))
}
@@ -18,6 +18,7 @@ package org.jetbrains.jps.model.java.compiler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.module.JpsModule;
import java.util.Collection;
import java.util.List;
@@ -36,10 +37,21 @@ public interface JpsJavaCompilerConfiguration extends JpsElement {
JpsCompilerExcludes getCompilerExcludes();
@NotNull
ProcessorConfigProfile getDefaultAnnotationProcessingConfiguration();
ProcessorConfigProfile getDefaultAnnotationProcessingProfile();
ProcessorConfigProfile addAnnotationProcessingProfile();
/**
* @return a list of currently configured profiles excluding default one
*/
@NotNull
Collection<ProcessorConfigProfile> getAnnotationProcessingConfigurations();
Collection<ProcessorConfigProfile> getAnnotationProcessingProfiles();
/**
* @param module
* @return annotation profile with which the given module is associated
*/
@NotNull
ProcessorConfigProfile getAnnotationProcessingProfile(JpsModule module);
void addResourcePattern(String pattern);
List<String> getResourcePatterns();
@@ -24,6 +24,7 @@ import org.jetbrains.jps.model.java.compiler.JpsCompilerExcludes;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions;
import org.jetbrains.jps.model.java.compiler.ProcessorConfigProfile;
import org.jetbrains.jps.model.module.JpsModule;
import java.util.*;
@@ -42,6 +43,7 @@ public class JpsJavaCompilerConfigurationImpl extends JpsCompositeElementBase<Jp
private Map<String, String> myModulesByteCodeTargetLevels = new HashMap<String, String>();
private Map<String, JpsJavaCompilerOptions> myCompilerOptions = new HashMap<String, JpsJavaCompilerOptions>();
private String myJavaCompilerId = "Javac";
private Map<JpsModule, ProcessorConfigProfile> myAnnotationProcessingProfileMap;
public JpsJavaCompilerConfigurationImpl() {
}
@@ -84,13 +86,13 @@ public class JpsJavaCompilerConfigurationImpl extends JpsCompositeElementBase<Jp
@NotNull
@Override
public ProcessorConfigProfile getDefaultAnnotationProcessingConfiguration() {
public ProcessorConfigProfile getDefaultAnnotationProcessingProfile() {
return myDefaultAnnotationProcessingProfile;
}
@NotNull
@Override
public Collection<ProcessorConfigProfile> getAnnotationProcessingConfigurations() {
public Collection<ProcessorConfigProfile> getAnnotationProcessingProfiles() {
return myAnnotationProcessingProfiles;
}
@@ -163,4 +165,30 @@ public class JpsJavaCompilerConfigurationImpl extends JpsCompositeElementBase<Jp
myAnnotationProcessingProfiles.add(profile);
return profile;
}
@Override
@NotNull
public ProcessorConfigProfile getAnnotationProcessingProfile(JpsModule module) {
Map<JpsModule, ProcessorConfigProfile> map = myAnnotationProcessingProfileMap;
if (map == null) {
map = new HashMap<JpsModule, ProcessorConfigProfile>();
final Map<String, JpsModule> namesMap = new HashMap<String, JpsModule>();
for (JpsModule m : module.getProject().getModules()) {
namesMap.put(m.getName(), m);
}
if (!namesMap.isEmpty()) {
for (ProcessorConfigProfile profile : getAnnotationProcessingProfiles()) {
for (String name : profile.getModuleNames()) {
final JpsModule mod = namesMap.get(name);
if (mod != null) {
map.put(mod, profile);
}
}
}
}
myAnnotationProcessingProfileMap = map;
}
final ProcessorConfigProfile profile = map.get(module);
return profile != null? profile : getDefaultAnnotationProcessingProfile();
}
}
@@ -68,7 +68,7 @@ public class AnnotationProcessorProfileSerializer {
profile.clearProcessors();
for (Object procElement : element.getChildren("processor")) {
final String name = ((Element)procElement).getAttributeValue(NAME);
if (StringUtil.isEmptyOrSpaces(name)) {
if (!StringUtil.isEmptyOrSpaces(name)) {
profile.addProcessor(name);
}
}
@@ -80,7 +80,7 @@ public class JpsJavaCompilerConfigurationSerializer extends JpsProjectExtensionS
for (Element profileTag : profiles) {
boolean isDefault = Boolean.parseBoolean(profileTag.getAttributeValue("default"));
if (isDefault) {
AnnotationProcessorProfileSerializer.readExternal(configuration.getDefaultAnnotationProcessingConfiguration(), profileTag);
AnnotationProcessorProfileSerializer.readExternal(configuration.getDefaultAnnotationProcessingProfile(), profileTag);
}
else {
AnnotationProcessorProfileSerializer.readExternal(configuration.addAnnotationProcessingProfile(), profileTag);
@@ -38,7 +38,7 @@ public class JpsCompilerConfigurationTest extends JpsSerializationTestCase {
assertNotNull(configuration);
assertFalse(configuration.isClearOutputDirectoryOnRebuild());
assertFalse(configuration.isAddNotNullAssertions());
ProcessorConfigProfile defaultProfile = configuration.getDefaultAnnotationProcessingConfiguration();
ProcessorConfigProfile defaultProfile = configuration.getDefaultAnnotationProcessingProfile();
assertTrue(defaultProfile.isEnabled());
assertFalse(defaultProfile.isObtainProcessorsFromClasspath());
assertEquals(FileUtil.toSystemDependentName(JpsPathUtil.urlToPath(getUrl("src"))), defaultProfile.getProcessorPath());
@@ -78,6 +78,9 @@ public class CharsetToolkit {
public static final Charset UTF8_CHARSET = Charset.forName(UTF8);
public static final Charset UTF_16LE_CHARSET = Charset.forName("UTF-16LE");
public static final Charset UTF_16BE_CHARSET = Charset.forName("UTF-16BE");
public static final Charset UTF_32BE_CHARSET = Charset.forName("UTF-32BE");
public static final Charset UTF_32LE_CHARSET = Charset.forName("UTF-32LE");
public static final Charset UTF_16_CHARSET = Charset.forName("UTF-16");
private final byte[] buffer;
private final Charset defaultCharset;
@@ -86,12 +89,16 @@ public class CharsetToolkit {
public static final byte[] UTF8_BOM = {0xffffffef, 0xffffffbb, 0xffffffbf, };
public static final byte[] UTF16LE_BOM = {-1, -2, };
public static final byte[] UTF16BE_BOM = {-2, -1, };
public static final byte[] UTF32BE_BOM = {0, 0, -2, -1, };
public static final byte[] UTF32LE_BOM = {-1, -2, 0, 0 };
@NonNls public static final String FILE_ENCODING_PROPERTY = "file.encoding";
@NonNls private static final Map<Charset, byte[]> CHARSET_TO_BOM = new THashMap<Charset, byte[]>(2);
static {
CHARSET_TO_BOM.put(UTF_16LE_CHARSET, UTF16LE_BOM);
CHARSET_TO_BOM.put(UTF_16BE_CHARSET, UTF16BE_BOM);
CHARSET_TO_BOM.put(UTF_32BE_CHARSET, UTF32BE_BOM);
CHARSET_TO_BOM.put(UTF_32LE_CHARSET, UTF32LE_BOM);
}
/**
@@ -320,6 +327,8 @@ public class CharsetToolkit {
@Nullable
public static Charset guessFromBOM(@NotNull byte[] buffer) {
if (hasUTF8Bom(buffer)) return UTF8_CHARSET;
if (hasUTF32BEBom(buffer)) return UTF_32BE_CHARSET;
if (hasUTF32LEBom(buffer)) return UTF_32LE_CHARSET;
if (hasUTF16LEBom(buffer)) return UTF_16LE_CHARSET;
if (hasUTF16BEBom(buffer)) return UTF_16BE_CHARSET;
@@ -456,6 +465,12 @@ public class CharsetToolkit {
public static boolean hasUTF16BEBom(@NotNull byte[] bom) {
return ArrayUtil.startsWith(bom, UTF16BE_BOM);
}
public static boolean hasUTF32BEBom(@NotNull byte[] bom) {
return ArrayUtil.startsWith(bom, UTF32BE_BOM);
}
public static boolean hasUTF32LEBom(@NotNull byte[] bom) {
return ArrayUtil.startsWith(bom, UTF32LE_BOM);
}
/**
* Retrieves all the available <code>Charset</code>s on the platform,
@@ -483,6 +498,12 @@ public class CharsetToolkit {
if (charset != null && charset.name().contains(UTF8) && hasUTF8Bom(content)) {
return UTF8_BOM.length;
}
if (hasUTF32BEBom(content)) {
return UTF32BE_BOM.length;
}
if (hasUTF32BEBom(content)) {
return UTF32BE_BOM.length;
}
if (hasUTF16LEBom(content)) {
return UTF16LE_BOM.length;
}
@@ -519,37 +540,94 @@ public class CharsetToolkit {
return charset;
}
private static final byte FF = (byte)0xff;
private static final byte FE = (byte)0xfe;
private static final byte EF = (byte)0xef;
private static final byte BB = (byte)0xbb;
private static final byte BF = (byte)0xbf;
@NotNull
public static InputStream inputStreamSkippingBOM(@NotNull InputStream stream) throws IOException {
assert stream.markSupported() :stream;
stream.mark(3);
stream.mark(4);
boolean mustReset = true;
try {
int ret = stream.read();
if (ret == -1) {
return stream;
return stream; // no bom
}
byte b0 = (byte)ret;
if (b0 != UTF8_BOM[0] && b0 != UTF16LE_BOM[0] && b0 != UTF16BE_BOM[0]) return stream;
if (b0 != EF && b0 != FF && b0 != FE && b0 != 0) return stream; // no bom
ret = stream.read();
if (ret == -1) {
return stream;
return stream; // no bom
}
byte b1 = (byte)ret;
if (b0 == UTF16LE_BOM[0] && b1 == UTF16LE_BOM[1]) { mustReset = false; return stream; }
if (b0 == UTF16BE_BOM[0] && b1 == UTF16BE_BOM[1]) { mustReset = false; return stream; }
if (b0 != UTF8_BOM[0] || b1 != UTF8_BOM[1]) {
if (b0 == FF && b1 == FE) {
stream.mark(2);
ret = stream.read();
if (ret == -1) {
return stream; // utf-16 LE
}
byte b2 = (byte)ret;
if (b2 != 0) {
return stream; // utf-16 LE
}
ret = stream.read();
if (ret == -1) {
return stream;
}
byte b3 = (byte)ret;
if (b3 != 0) {
return stream; // utf-16 LE
}
// utf-32 LE
mustReset = false;
return stream;
}
if (b0 == FE && b1 == FF) {
mustReset = false;
return stream; // utf-16 BE
}
if (b0 == EF && b1 == BB) {
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b2 = (byte)ret;
if (b2 == BF) {
mustReset = false;
return stream; // utf-8 bom
}
// no bom
return stream;
}
ret = stream.read();
if (ret == -1) {
return stream;
}
byte b2 = (byte)ret;
if (b2 == UTF8_BOM[2]) { mustReset = false; return stream; }
if (b0 == 0 && b1 == 0) {
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b2 = (byte)ret;
if (b2 != FE) {
return stream; // no bom
}
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b3 = (byte)ret;
if (b3 != FF) {
return stream; // no bom
}
mustReset = false;
return stream; // UTF-32 BE
}
// no bom
return stream;
}
finally {
@@ -495,8 +495,8 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
if (Comparing.equal(charset, old)) return;
byte[] bom = charset == null ? null : CharsetToolkit.getBom(charset);
byte[] existingBOM = getBOM();
if (bom == null && charset != null && CharsetToolkit.canHaveBom(charset, existingBOM)) {
bom = existingBOM;
if (bom == null && charset != null) {
bom = CharsetToolkit.canHaveBom(charset, existingBOM) ? existingBOM : null;
}
setBOM(bom);
@@ -34,7 +34,8 @@ import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
@@ -142,28 +143,33 @@ public final class LoadTextUtil {
}
@Nullable("null means no luck, otherwise it's tuple(guessed encoding, hint about content if was unable to guess, BOM)")
public static Trinity<Charset, CharsetToolkit.GuessedEncoding, byte[]> guessFromContent(VirtualFile virtualFile, byte[] content, int length) {
public static Trinity<Charset, CharsetToolkit.GuessedEncoding, byte[]> guessFromContent(@NotNull VirtualFile virtualFile, @NotNull byte[] content, int length) {
EncodingRegistry settings = EncodingRegistry.getInstance();
boolean shouldGuess = settings != null && settings.isUseUTFGuessing(virtualFile);
CharsetToolkit toolkit = shouldGuess ? new CharsetToolkit(content, EncodingRegistry.getInstance().getDefaultCharset()) : null;
setCharsetWasDetectedFromBytes(virtualFile, false);
if (shouldGuess) {
toolkit.setEnforce8Bit(true);
Charset charset = toolkit.guessFromBOM();
if (charset != null) {
setCharsetWasDetectedFromBytes(virtualFile, true);
byte[] bom = CharsetToolkit.getBom(charset);
if (bom == null) bom = CharsetToolkit.UTF8_BOM;
return Trinity.create(charset, null, bom);
String detectedFromBytes = null;
try {
if (shouldGuess) {
toolkit.setEnforce8Bit(true);
Charset charset = toolkit.guessFromBOM();
if (charset != null) {
detectedFromBytes = "auto-detected from BOM";
byte[] bom = CharsetToolkit.getBom(charset);
if (bom == null) bom = CharsetToolkit.UTF8_BOM;
return Trinity.create(charset, null, bom);
}
CharsetToolkit.GuessedEncoding guessed = toolkit.guessFromContent(length);
if (guessed == CharsetToolkit.GuessedEncoding.VALID_UTF8) {
detectedFromBytes = "auto-detected from bytes";
return Trinity.create(CharsetToolkit.UTF8_CHARSET, guessed, null); //UTF detected, ignore all directives
}
return Trinity.create(null, guessed,null);
}
CharsetToolkit.GuessedEncoding guessed = toolkit.guessFromContent(length);
if (guessed == CharsetToolkit.GuessedEncoding.VALID_UTF8) {
setCharsetWasDetectedFromBytes(virtualFile, true);
return Trinity.create(CharsetToolkit.UTF8_CHARSET,null,null); //UTF detected, ignore all directives
}
return Trinity.create(null, guessed,null);
return null;
}
finally {
setCharsetWasDetectedFromBytes(virtualFile, detectedFromBytes);
}
return null;
}
@NotNull
@@ -172,11 +178,9 @@ public final class LoadTextUtil {
return Pair.create(charset, CharsetToolkit.UTF8_BOM);
}
try {
if (CharsetToolkit.hasUTF16LEBom(content)) {
return Pair.create(CharsetToolkit.UTF_16LE_CHARSET, CharsetToolkit.UTF16LE_BOM);
}
if (CharsetToolkit.hasUTF16BEBom(content)) {
return Pair.create(CharsetToolkit.UTF_16BE_CHARSET, CharsetToolkit.UTF16BE_BOM);
Charset fromBOM = CharsetToolkit.guessFromBOM(content);
if (fromBOM != null) {
return Pair.create(fromBOM, CharsetToolkit.getBom(fromBOM));
}
}
catch (UnsupportedCharsetException ignore) {
@@ -200,68 +204,87 @@ public final class LoadTextUtil {
* @throws java.io.IOException if an I/O error occurs
* @see VirtualFile#getModificationStamp()
*/
@SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"})
public static void write(@Nullable Project project,
@NotNull VirtualFile virtualFile,
@NotNull Object requestor,
@NotNull String text,
long newModificationStamp) throws IOException {
Charset existing = virtualFile.getCharset();
Charset specified = extractCharsetFromFileContent(project, virtualFile, text);
Charset charset = chooseMostlyHarmlessCharset(existing, specified, text);
Pair<Charset, byte[]> chosen = charsetForWriting(project, virtualFile, text, existing);
Charset charset = chosen.first;
byte[] buffer = chosen.second;
if (charset != null) {
if (!charset.equals(existing)) {
virtualFile.setCharset(charset);
}
setDetectedFromBytesFlagBack(virtualFile, charset, text);
}
setDetectedFromBytesFlagBack(virtualFile, buffer);
// in c ase of "UTF-16", OutputStreamWriter sometimes adds BOM on it's own.
OutputStream outputStream = virtualFile.getOutputStream(requestor, newModificationStamp, -1);
try {
outputStream.write(buffer);
}
finally {
outputStream.close();
}
}
@NotNull
private static Pair<Charset, byte[]> charsetForWriting(@Nullable Project project,
@NotNull VirtualFile virtualFile,
@NotNull String text,
@Nullable Charset existing) {
Charset specified = extractCharsetFromFileContent(project, virtualFile, text);
Pair<Charset, byte[]> chosen = chooseMostlyHarmlessCharset(existing, specified, text);
Charset charset = chosen.first;
// in case of "UTF-16", OutputStreamWriter sometimes adds BOM on it's own.
// see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6800103
byte[] bom = virtualFile.getBOM();
Charset fromBom = bom == null ? null : CharsetToolkit.guessFromBOM(bom);
if (fromBom != null) charset = fromBom;
OutputStream outputStream = virtualFile.getOutputStream(requestor, newModificationStamp, -1);
OutputStreamWriter writer = charset == null ? new OutputStreamWriter(outputStream) : new OutputStreamWriter(outputStream, charset);
// no need to buffer ByteArrayOutputStream
Writer w = outputStream instanceof ByteArrayOutputStream ? writer : new BufferedWriter(writer);
try {
w.write(text);
}
finally {
w.close();
if (fromBom != null && !fromBom.equals(charset)) {
chosen = Pair.create(fromBom, toBytes(text, fromBom));
}
return chosen;
}
private static void setDetectedFromBytesFlagBack(@NotNull VirtualFile virtualFile, @NotNull Charset charset, @NotNull String text) {
public static void setDetectedFromBytesFlagBack(@NotNull VirtualFile virtualFile, @NotNull byte[] content) {
if (virtualFile.getBOM() != null) {
// prevent file to be reloaded in other encoding after save with BOM
setCharsetWasDetectedFromBytes(virtualFile, true);
return;
setCharsetWasDetectedFromBytes(virtualFile, "auto-detected from BOM");
}
byte[] content = text.getBytes(charset);
CharsetToolkit.GuessedEncoding guessedEncoding = new CharsetToolkit(content).guessFromContent(content.length);
if (guessedEncoding == CharsetToolkit.GuessedEncoding.VALID_UTF8) {
setCharsetWasDetectedFromBytes(virtualFile, true);
else {
guessFromContent(virtualFile, content, content.length);
}
}
private static Charset chooseMostlyHarmlessCharset(Charset existing, Charset specified, String text) {
if (existing == null) return specified;
if (specified == null) return existing;
if (specified.equals(existing)) return specified;
if (isSupported(specified, text)) return specified; //if explicitly specified encoding is safe, return it
if (isSupported(existing, text)) return existing; //otherwise stick to the old encoding if it's ok
return specified; //if both are bad there is no difference
@NotNull
public static Pair<Charset, byte[]> chooseMostlyHarmlessCharset(Charset existing, Charset specified, @NotNull String text) {
if (existing == null) return Pair.create(specified, toBytes(text, specified));
if (specified == null || specified.equals(existing)) return Pair.create(specified, toBytes(text, existing));
byte[] out = isSupported(specified, text);
if (out != null) return Pair.create(specified, out); //if explicitly specified encoding is safe, return it
out = isSupported(existing, text);
if (out != null) return Pair.create(existing, out); //otherwise stick to the old encoding if it's ok
return Pair.create(specified, toBytes(text, specified)); //if both are bad there is no difference
}
private static boolean isSupported(@NotNull Charset charset, @NotNull String str) {
if (!charset.canEncode()) return false;
ByteBuffer out = charset.encode(str);
CharBuffer buffer = charset.decode(out);
return str.equals(buffer.toString());
@NotNull
private static byte[] toBytes(@NotNull String text, @Nullable Charset charset) {
return charset == null ? text.getBytes() : text.getBytes(charset);
}
@Nullable("null means not supported, otherwise it is converted byte stream")
private static byte[] isSupported(@NotNull Charset charset, @NotNull String str) {
if (!charset.canEncode()) return null;
byte[] bytes = str.getBytes(charset);
if (!str.equals(new String(bytes, charset))) {
return null;
}
return bytes;
}
public static Charset extractCharsetFromFileContent(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull String text) {
@@ -381,18 +404,20 @@ public final class LoadTextUtil {
charset = CharsetToolkit.getDefaultSystemCharset();
}
if (charset == null) {
//noinspection HardCodedStringLiteral
charset = Charset.forName("ISO-8859-1");
}
CharBuffer charBuffer = charset.decode(byteBuffer);
return convertLineSeparators(charBuffer);
}
private static final Key<Boolean> CHARSET_WAS_DETECTED_FROM_BYTES = new Key<Boolean>("CHARSET_WAS_DETECTED_FROM_BYTES");
public static boolean wasCharsetDetectedFromBytes(@NotNull VirtualFile virtualFile) {
return virtualFile.getUserData(CHARSET_WAS_DETECTED_FROM_BYTES) != null;
private static final Key<String> CHARSET_WAS_DETECTED_FROM_BYTES = Key.create("CHARSET_WAS_DETECTED_FROM_BYTES");
@Nullable("null if was not detected, otherwise the reason it was")
public static String wasCharsetDetectedFromBytes(@NotNull VirtualFile virtualFile) {
return virtualFile.getUserData(CHARSET_WAS_DETECTED_FROM_BYTES);
}
public static void setCharsetWasDetectedFromBytes(@NotNull VirtualFile virtualFile, boolean flag) {
virtualFile.putUserData(CHARSET_WAS_DETECTED_FROM_BYTES, flag ? Boolean.TRUE : null);
public static void setCharsetWasDetectedFromBytes(@NotNull VirtualFile virtualFile,
@Nullable("null if was not detected, otherwise the reason it was") String reason) {
virtualFile.putUserData(CHARSET_WAS_DETECTED_FROM_BYTES, reason);
}
}
@@ -19,6 +19,7 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.roots.*
import org.jetbrains.annotations.NotNull
/**
*
@@ -32,11 +33,13 @@ class MockProjectRootManager extends ProjectRootManager {
}
@NotNull
@Override
VirtualFile[] getContentRoots() {
myContentRoots
}
@NotNull
@Override
ProjectFileIndex getFileIndex() {
throw new UnsupportedOperationException()
@@ -46,13 +49,15 @@ class MockProjectRootManager extends ProjectRootManager {
@NotNull
@Override
OrderEnumerator orderEntries() {
throw new UnsupportedOperationException()
}
@NotNull
@Override
OrderEnumerator orderEntries(Collection<? extends Module> modules) {
OrderEnumerator orderEntries(@NotNull Collection<? extends Module> modules) {
throw new UnsupportedOperationException()
}
@@ -61,6 +66,7 @@ class MockProjectRootManager extends ProjectRootManager {
throw new UnsupportedOperationException()
}
@NotNull
@Override
List<String> getContentRootUrls() {
throw new UnsupportedOperationException()
@@ -44,11 +44,11 @@ import com.intellij.util.containers.MultiMap;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.text.StringSearcher;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -239,19 +239,13 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
try {
if (myManager.getProject().isDisposed()) throw new ProcessCanceledException();
List<PsiFile> psiRoots = file.getViewProvider().getAllFiles();
Set<PsiElement> processed = new HashSet<PsiElement>(psiRoots.size() * 2, (float)0.5);
Set<PsiElement> processed = new THashSet<PsiElement>(psiRoots.size() * 2, (float)0.5);
for (PsiElement psiRoot : psiRoots) {
if (progress != null) progress.checkCanceled();
assert psiRoot != null : "One of the roots of file " + file + " is null. All roots: " + psiRoots +
"; ViewProvider: " + file.getViewProvider() + "; Virtual file: " + file.getViewProvider().getVirtualFile();
if (!processed.add(psiRoot)) continue;
if (!psiRoot.isValid()) continue;
assert psiRoot != null : "One of the roots of file " +
file +
" is null. All roots: " +
Arrays.asList(psiRoots) +
"; Viewprovider: " +
file.getViewProvider() +
"; Virtual file: " +
file.getViewProvider().getVirtualFile();
if (!psiRootProcessor.process(psiRoot)) {
canceled.set(true);
return;
@@ -56,7 +56,7 @@ public class CompositeFilter implements Filter, FilterMixin {
Result result = filter.applyFilter(line, entireLength);
finalResult = merge(finalResult, result);
t0 = System.currentTimeMillis() - t0;
if (t0 > 100) {
if (t0 > 1000) {
LOG.warn(filter.getClass().getSimpleName() + ".applyFilter() took " + t0 + " ms on '''" + line + "'''");
}
if (finalResult != null && finalResult.getNextAction() == NextAction.EXIT) {
@@ -94,7 +94,7 @@ public class WizardContext {
if (myProjectFileDirectory != null) {
return myProjectFileDirectory;
}
final String lastProjectLocation = GeneralSettings.getInstance().getLastProjectLocation();
final String lastProjectLocation = GeneralSettings.getInstance().getLastProjectCreationLocation();
if (lastProjectLocation != null) {
return lastProjectLocation.replace('/', File.separatorChar);
}
@@ -22,23 +22,25 @@
*/
package com.intellij.codeInspection;
import com.intellij.ide.DataManager;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lang.properties.charset.Native2AsciiCharset;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.ChooseFileEncodingAction;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.ReloadFileInOtherEncodingAction;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.openapi.wm.impl.status.EncodingActionsPair;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.Nls;
@@ -57,24 +59,28 @@ public class LossyEncodingInspection extends LocalInspectionTool {
private static final LocalQuickFix CHANGE_ENCODING_FIX = new ChangeEncodingFix();
private static final LocalQuickFix RELOAD_ENCODING_FIX = new ReloadInAnotherEncodingFix();
@Override
@Nls
@NotNull
public String getGroupDisplayName() {
return InspectionsBundle.message("group.names.internationalization.issues");
}
@Override
@Nls
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("lossy.encoding");
}
@Override
@NonNls
@NotNull
public String getShortName() {
return "LossyEncoding";
}
@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
if (InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) return null;
@@ -93,44 +99,61 @@ public class LossyEncodingInspection extends LocalInspectionTool {
List<ProblemDescriptor> descriptors = new SmartList<ProblemDescriptor>();
checkIfCharactersWillBeLostAfterSave(file, manager, isOnTheFly, text, charset, descriptors);
checkFileLoadedInWrongEncoding(file, manager, isOnTheFly, virtualFile, charset, descriptors);
checkFileLoadedInWrongEncoding(file, manager, isOnTheFly, text, virtualFile, charset, descriptors);
return descriptors.toArray(new ProblemDescriptor[descriptors.size()]);
}
private static void checkFileLoadedInWrongEncoding(PsiFile file,
InspectionManager manager,
private static void checkFileLoadedInWrongEncoding(@NotNull PsiFile file,
@NotNull InspectionManager manager,
boolean isOnTheFly,
VirtualFile virtualFile,
Charset charset, List<ProblemDescriptor> descriptors) {
@NotNull String text,
@NotNull VirtualFile virtualFile,
@NotNull Charset charset,
@NotNull List<ProblemDescriptor> descriptors) {
if (FileDocumentManager.getInstance().isFileModified(virtualFile) // when file is modified, it's too late to reload it
|| ChooseFileEncodingAction.isEnabledAndWhyNot(virtualFile) != null // can't reload in another encoding, no point trying
|| ChooseFileEncodingAction.checkCanReload(virtualFile).second != null // can't reload in another encoding, no point trying
) {
return;
}
// check if file was loaded in correct encoding
boolean ok = isGoodCharset(file.getProject(), virtualFile, text, charset);
if (!ok) {
descriptors.add(manager.createProblemDescriptor(file, "File was loaded in the wrong encoding: '"+charset+"'",
RELOAD_ENCODING_FIX, ProblemHighlightType.GENERIC_ERROR, isOnTheFly));
}
}
// check if file was loaded in correct encoding
// returns true if text converted with charset is equals to the bytes currently on disk
public static boolean isGoodCharset(@NotNull Project project,
@NotNull VirtualFile virtualFile,
@NotNull String text,
@NotNull Charset charset) {
byte[] bytes;
try {
bytes = virtualFile.contentsToByteArray();
}
catch (IOException e) {
return;
return true;
}
String separator = FileDocumentManager.getInstance().getLineSeparator(virtualFile, file.getProject());
String toSave = StringUtil.convertLineSeparators(file.getText(), separator);
String separator = FileDocumentManager.getInstance().getLineSeparator(virtualFile, project);
String toSave = StringUtil.convertLineSeparators(text, separator);
byte[] bom = virtualFile.getBOM();
byte[] bytesToSave = ArrayUtil.mergeArrays(bom == null ? ArrayUtil.EMPTY_BYTE_ARRAY : bom, toSave.getBytes(charset));
if (!Arrays.equals(bytesToSave, bytes)) {
descriptors.add(manager.createProblemDescriptor(file, "File was loaded in a wrong encoding: '"+charset+"'",
RELOAD_ENCODING_FIX, ProblemHighlightType.GENERIC_ERROR, isOnTheFly));
bom = bom == null ? ArrayUtil.EMPTY_BYTE_ARRAY : bom;
byte[] bytesToSave = toSave.getBytes(charset);
if (!ArrayUtil.startsWith(bytesToSave, bom)) {
bytesToSave = ArrayUtil.mergeArrays(bom, bytesToSave); // for 2-byte encodings String.getBytes(Charset) adds BOM automatically
}
return Arrays.equals(bytesToSave, bytes);
}
private static void checkIfCharactersWillBeLostAfterSave(PsiFile file,
InspectionManager manager,
private static void checkIfCharactersWillBeLostAfterSave(@NotNull PsiFile file,
@NotNull InspectionManager manager,
boolean isOnTheFly,
String text,
Charset charset, List<ProblemDescriptor> descriptors) {
@NotNull String text,
@NotNull Charset charset,
@NotNull List<ProblemDescriptor> descriptors) {
int errorCount = 0;
int start = -1;
for (int i = 0; i <= text.length(); i++) {
@@ -153,7 +176,7 @@ public class LossyEncodingInspection extends LocalInspectionTool {
}
}
private static boolean isRepresentable(final char c, final Charset charset) {
private static boolean isRepresentable(final char c, @NotNull Charset charset) {
String str = Character.toString(c);
ByteBuffer out = charset.encode(str);
CharBuffer buffer = charset.decode(out);
@@ -191,17 +214,12 @@ public class LossyEncodingInspection extends LocalInspectionTool {
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiFile psiFile = descriptor.getPsiElement().getContainingFile();
VirtualFile virtualFile = psiFile.getVirtualFile();
ChooseFileEncodingAction action = new ChooseFileEncodingAction(virtualFile) {
@Override
protected void chosen(VirtualFile virtualFile, @NotNull Charset charset) {
if (virtualFile != null) {
EncodingManager.getInstance().setEncoding(virtualFile, charset);
}
}
};
DefaultActionGroup group = action.createGroup(null);
DataContext dataContext = DataManager.getInstance().getDataContext();
JBPopupFactory.getInstance().createActionGroupPopup(null, group, dataContext, false, false, false, null, 30, null).showInBestPositionFor(dataContext);
Editor editor = PsiUtilBase.findEditor(psiFile);
DataContext dataContext =
EncodingActionsPair.createDataContext(editor, editor == null ? null : editor.getComponent(), virtualFile, project);
ReloadFileInOtherEncodingAction reloadAction = new ReloadFileInOtherEncodingAction();
reloadAction.actionPerformed(new AnActionEvent(null, dataContext, "", reloadAction.getTemplatePresentation(), ActionManager.getInstance(), 0));
}
}
}
@@ -107,6 +107,7 @@ class BeforeRunStepsPanel extends JPanel {
BeforeRunTaskProvider<BeforeRunTask> provider = selection.getSecond();
if (provider.configureTask(myRunConfiguration, task)) {
myModel.setElementAt(task, index);
updateText();
}
}
});
@@ -173,7 +174,7 @@ class BeforeRunStepsPanel extends JPanel {
StringBuilder sb = new StringBuilder();
if (myShowSettingsBeforeRunCheckBox.isSelected()) {
sb.append(ExecutionBundle.message("configuration.edit.before.run")).append(", ");
sb.append(ExecutionBundle.message("configuration.edit.before.run"));
}
List<BeforeRunTask> tasks = myModel.getItems();
@@ -199,12 +200,13 @@ class BeforeRunStepsPanel extends JPanel {
if (name.startsWith("Run ")) {
name = name.substring(4);
}
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(name);
if (entry.getValue() > 1) {
sb.append(" (").append(entry.getValue().intValue()).append(")");
}
if (iterator.hasNext())
sb.append(", ");
}
}
if (sb.length() > 0) {
@@ -206,7 +206,7 @@ public class FavoritesManager implements ProjectComponent, JDOMExternalizable {
}
private void appendChildNodes(AbstractTreeNode node, TreeItem<Pair<AbstractUrl, String>> treeItem) {
final Collection<AbstractTreeNode> children = node.getChildren();
final Collection<? extends AbstractTreeNode> children = node.getChildren();
for (AbstractTreeNode child : children) {
final TreeItem<Pair<AbstractUrl, String>> childTreeItem = new TreeItem<Pair<AbstractUrl, String>>(createPairForNode(child));
treeItem.addChild(childTreeItem);
@@ -26,21 +26,51 @@ import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerListener;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.roots.impl.DirectoryIndex;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.indexing.FileBasedIndex;
import java.util.*;
/**
* Maintains a list of files marked as plain text in a local environment (configuration). Every time a project is loaded/open, it reads
* files marked as plain text from a project into local environment (configuration). User actions (mark/unmark as plain text) are
* synchronized between local and project configurations.
*
* @author Rustam Vishnyakov
*/
@State(name = "EnforcedPlainTextFileTypeManager", storages = {@Storage( file = StoragePathMacros.APP_CONFIG + "/plainTextFiles.xml")})
public class EnforcedPlainTextFileTypeManager extends PersistentFileSetManager {
public class EnforcedPlainTextFileTypeManager extends PersistentFileSetManager implements ProjectManagerListener {
private Set<Project> myProcessedProjects = new HashSet<Project>();
private boolean myNeedsSync = true;
public EnforcedPlainTextFileTypeManager() {
ProjectManager.getInstance().addProjectManagerListener(this);
}
public boolean isMarkedAsPlainText(VirtualFile file) {
if (myNeedsSync) {
myNeedsSync = !syncWithOpenProject();
}
return containsFile(file);
}
public boolean syncWithOpenProject() {
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
if (openProjects.length > 0) {
Project firstOpenProject = openProjects[0];
if (!myProcessedProjects.contains(firstOpenProject)) {
return syncWithProject(firstOpenProject);
}
return true;
}
return false;
}
public static boolean isApplicableFor(VirtualFile file) {
if (file.isDirectory()) return false;
FileType originalType = FileTypeManager.getInstance().getFileTypeByFileName(file.getName());
@@ -53,29 +83,44 @@ public class EnforcedPlainTextFileTypeManager extends PersistentFileSetManager {
}
public void markAsPlainText(VirtualFile... files) {
List<VirtualFile> filesToSync = new ArrayList<VirtualFile>();
for (VirtualFile file : files) {
if (addFile(file)) {
filesToSync.add(file);
FileBasedIndex.getInstance().requestReindex(file);
}
}
fireRootsChanged();
fireRootsChanged(filesToSync, true);
}
public void unmarkPlainText(VirtualFile... files) {
List<VirtualFile> filesToSync = new ArrayList<VirtualFile>();
for (VirtualFile file : files) {
if (removeFile(file)) {
filesToSync.add(file);
FileBasedIndex.getInstance().requestReindex(file);
}
}
fireRootsChanged();
fireRootsChanged(filesToSync, false);
}
private static void fireRootsChanged() {
private static void fireRootsChanged(final Collection<VirtualFile> files, final boolean isAdded) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.getInstance(), false, true);
ProjectPlainTextFileTypeManager projectPlainTextFileTypeManager = ProjectPlainTextFileTypeManager.getInstance(project);
for (VirtualFile file : files) {
if (projectPlainTextFileTypeManager.hasProjectContaining(file)) {
if (isAdded) {
projectPlainTextFileTypeManager.addFile(file);
}
else {
projectPlainTextFileTypeManager.removeFile(file);
}
}
}
}
}
});
@@ -89,4 +134,41 @@ public class EnforcedPlainTextFileTypeManager extends PersistentFileSetManager {
}
return ourInstance;
}
@Override
public void projectOpened(Project project) {
syncWithProject(project);
}
@Override
public boolean canCloseProject(Project project) {
return true;
}
@Override
public void projectClosed(Project project) {
if (myProcessedProjects.contains(project)) {
myProcessedProjects.remove(project);
}
}
@Override
public void projectClosing(Project project) {
}
private boolean syncWithProject(Project project) {
if (!DirectoryIndex.getInstance(project).isInitialized()) return false;
myProcessedProjects.add(project);
ProjectPlainTextFileTypeManager projectPlainTextFileTypeManager = ProjectPlainTextFileTypeManager.getInstance(project);
if (projectPlainTextFileTypeManager == null) return true;
for (VirtualFile file : projectPlainTextFileTypeManager.getFiles()) {
addFile(file);
}
for (VirtualFile file : getFiles()) {
if (projectPlainTextFileTypeManager.hasProjectContaining(file)) {
projectPlainTextFileTypeManager.addFile(file);
}
}
return true;
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2000-2012 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.file.exclude;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
/**
* @author Rustam Vishnyakov
*/
@State(name = "ProjectPlainTextFileTypeManager", storages = {@Storage( file = StoragePathMacros.PROJECT_FILE)})
public class ProjectPlainTextFileTypeManager extends PersistentFileSetManager {
private ProjectFileIndex myIndex;
public ProjectPlainTextFileTypeManager(Project project) {
myIndex = ProjectRootManager.getInstance(project).getFileIndex();
}
public boolean hasProjectContaining(VirtualFile file) {
return myIndex.isInContent(file);
}
public static ProjectPlainTextFileTypeManager getInstance(Project project) {
return ServiceManager.getService(project, ProjectPlainTextFileTypeManager.class);
}
}
@@ -29,6 +29,7 @@ public class ConfigureFileDefaultEncodingAction extends AnAction {
final Project project = e.getData(PlatformDataKeys.PROJECT);
final VirtualFile virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE);
assert project != null;
final FileEncodingConfigurable configurable = new FileEncodingConfigurable(project);
ShowSettingsUtil.getInstance().editConfigurable(project, configurable, new Runnable(){
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -24,10 +24,10 @@ package com.intellij.openapi.vfs.encoding;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.util.ui.tree.AbstractFileTreeTable;
import org.jetbrains.annotations.NotNull;
@@ -39,9 +39,9 @@ import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.nio.charset.Charset;
public class FileTreeTable extends AbstractFileTreeTable<Charset> {
public FileTreeTable(final Project project) {
super(project, Charset.class, "Default Encoding");
class EncodingFileTreeTable extends AbstractFileTreeTable<Charset> {
public EncodingFileTreeTable(@NotNull Project project) {
super(project, Charset.class, "Default Encoding", VirtualFileFilter.ALL, false);
reset(EncodingProjectManager.getInstance(project).getAllMappings());
getValueColumn().setCellRenderer(new DefaultTableCellRenderer(){
@@ -52,24 +52,19 @@ public class FileTreeTable extends AbstractFileTreeTable<Charset> {
final Charset t = (Charset)value;
final Object userObject = table.getModel().getValueAt(row, 0);
final VirtualFile file = userObject instanceof VirtualFile ? (VirtualFile)userObject : null;
final Pair<String,Boolean> pair = ChooseFileEncodingAction.update(file);
final boolean enabled = file == null || pair.getSecond();
if (t != null) {
setText(t.displayName());
}
else if (file != null) {
String failReason;
Charset charset = ChooseFileEncodingAction.cachedCharsetFromContent(file);
if (charset != null) {
setText(charset.displayName()+ " (Hardcoded in the text)");
}
else if (LoadTextUtil.wasCharsetDetectedFromBytes(file)) {
setText(file.getCharset().displayName() + " (Auto-detected)");
}
else if ((failReason = ChooseFileEncodingAction.isEnabledAndWhyNot(file)) != null) {
setText("N/A ("+failReason+")");
}
Pair<Charset, String> check = file == null || file.isDirectory() ? null : ChooseFileEncodingAction.checkCanReload(file);
String failReason = check == null ? null : check.second;
boolean enabled = failReason == null;
// show existing encoding only if it was specified explicitly or it is unchangeable (with reason)
boolean toShow = t != null || failReason != null;
if (toShow) {
Charset existing = check == null ? null : check.first;
String encodingText = t != null ? t.displayName() : existing == null ? "N/A" : existing.displayName();
setText(encodingText + (failReason == null ? "" : " (" + failReason + ")"));
}
setEnabled(enabled);
return this;
}
@@ -96,7 +91,17 @@ public class FileTreeTable extends AbstractFileTreeTable<Charset> {
final Object o = table.getModel().getValueAt(row, 0);
myVirtualFile = o instanceof Project ? null : (VirtualFile)o;
final ChooseFileEncodingAction changeAction = new ChooseFileEncodingAction(myVirtualFile){
ChooseFileEncodingAction changeAction = new ChooseFileEncodingAction(myVirtualFile) {
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
return createGroup("<Clear>", null, "Encoding ''{1}''", null);
}
@Override
public void update(AnActionEvent e) {
}
@Override
protected void chosen(VirtualFile virtualFile, @NotNull Charset charset) {
getValueColumn().getCellEditor().stopCellEditing();
@@ -107,15 +112,15 @@ public class FileTreeTable extends AbstractFileTreeTable<Charset> {
}
};
Presentation templatePresentation = changeAction.getTemplatePresentation();
final JComponent comboComponent = changeAction.createCustomComponent(templatePresentation);
JComponent comboComponent = changeAction.createCustomComponent(templatePresentation);
DataContext dataContext = SimpleDataContext.getSimpleContext(PlatformDataKeys.VIRTUAL_FILE.getName(), myVirtualFile,
SimpleDataContext.getProjectContext(getProject()));
AnActionEvent event = new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, templatePresentation, ActionManager.getInstance(), 0);
changeAction.update(event);
changeAction.getTemplatePresentation().setDescription(null);
templatePresentation.setDescription(null);
if (myVirtualFile == null) {
changeAction.getTemplatePresentation().setEnabled(true); // enable changing encoding for tree root (entire project)
templatePresentation.setEnabled(true); // enable changing encoding for tree root (entire project)
}
editorComponent = comboComponent;
comboComponent.addComponentListener(new ComponentAdapter() {
@@ -141,6 +146,7 @@ public class FileTreeTable extends AbstractFileTreeTable<Charset> {
@Override
protected boolean isValueEditableForFile(final VirtualFile virtualFile) {
return ChooseFileEncodingAction.update(virtualFile).getSecond();
return virtualFile == null || virtualFile.isDirectory() ||
ChooseFileEncodingAction.checkCanReload(virtualFile).second == null;
}
}
@@ -3,7 +3,7 @@
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="86" width="454" height="334"/>
<xy x="20" y="86" width="466" height="334"/>
</constraints>
<properties/>
<clientProperties>
@@ -21,7 +21,7 @@
</border>
<children/>
</scrollpane>
<grid id="7187a" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="7187a" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -34,7 +34,7 @@
<children>
<grid id="9ed8f" binding="myPropertiesFilesEncodingCombo" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -56,9 +56,14 @@
<text resource-bundle="messages/IdeBundle" key="checkbox.transparent.native.to.ascii.conversion"/>
</properties>
</component>
<hspacer id="6003d">
<constraints>
<grid row="0" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
</children>
</grid>
<grid id="f15cb" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="f15cb" layout-manager="GridLayoutManager" row-count="2" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -84,23 +89,58 @@
</grid>
<component id="29b05" class="javax.swing.JCheckBox" binding="myAutodetectUTFEncodedFilesCheckBox" default-binding="true">
<constraints>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<horizontalAlignment value="4"/>
<horizontalAlignment value="2"/>
<horizontalTextPosition value="11"/>
<text resource-bundle="messages/IdeBundle" key="checkbox.autodetect.utf"/>
</properties>
</component>
<component id="6435b" class="javax.swing.JLabel">
<constraints>
<grid row="1" 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="Project Encoding:"/>
</properties>
</component>
<grid id="fac05" binding="myProjectEncodingListCombo" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
<hspacer id="f9e85">
<constraints>
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
</children>
</grid>
<grid id="63e2d" layout-manager="GridLayoutManager" row-count="1" 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>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
</clientProperties>
<border type="etched" title="Override Encoding for Files/Directories"/>
<children>
<component id="e9af6" class="javax.swing.JLabel" binding="myTitleLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="encodings.dialog.caption"/>
</properties>
</component>
</children>
</grid>
<component id="e9af6" class="javax.swing.JLabel" binding="myTitleLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="encodings.dialog.caption"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -46,7 +46,7 @@ import java.util.Map;
public class FileEncodingConfigurable implements SearchableConfigurable, OptionalConfigurable, Configurable.NoScroll {
private static final String SYSTEM_DEFAULT = IdeBundle.message("encoding.name.system.default");
private final Project myProject;
private FileTreeTable myTreeView;
private EncodingFileTreeTable myTreeView;
private JScrollPane myTreePanel;
private JPanel myPanel;
private JCheckBox myAutodetectUTFEncodedFilesCheckBox;
@@ -54,12 +54,15 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
private JPanel myPropertiesFilesEncodingCombo;
private final Ref<Charset> mySelectedCharsetForPropertiesFiles = new Ref<Charset>();
private final Ref<Charset> mySelectedIdeCharset = new Ref<Charset>();
private final Ref<Charset> mySelectedProjectCharset = new Ref<Charset>();
private JLabel myTitleLabel;
private JPanel myIdeEncodingsListCombo;
private JPanel myProjectEncodingListCombo;
private ChooseFileEncodingAction myPropertiesEncodingAction;
private ChooseFileEncodingAction myIdeEncodingAction;
private ChooseFileEncodingAction myProjectEncodingAction;
public FileEncodingConfigurable(Project project) {
public FileEncodingConfigurable(@NotNull Project project) {
myProject = project;
myTitleLabel.setText(myTitleLabel.getText().replace("$productName", ApplicationNamesInfo.getInstance().getFullProductName()));
}
@@ -100,19 +103,19 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
@Override
protected void chosen(final VirtualFile virtualFile, @NotNull final Charset charset) {
selected.set(charset == NO_ENCODING ? null : charset);
update((AnActionEvent)null);
update(null);
}
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
return createGroup("<System Default>");
return createGroup("<System Default>", null, "Choose encoding ''{1}''", selected.get());
}
};
parentPanel.removeAll();
Presentation templatePresentation = myAction.getTemplatePresentation();
parentPanel.add(myAction.createCustomComponent(templatePresentation), BorderLayout.CENTER);
myAction.update((AnActionEvent)null);
myAction.update(null);
return myAction;
}
@@ -120,7 +123,8 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
public JComponent createComponent() {
myPropertiesEncodingAction = installChooseEncodingCombo(myPropertiesFilesEncodingCombo, mySelectedCharsetForPropertiesFiles);
myIdeEncodingAction = installChooseEncodingCombo(myIdeEncodingsListCombo, mySelectedIdeCharset);
myTreeView = new FileTreeTable(myProject);
myProjectEncodingAction = installChooseEncodingCombo(myProjectEncodingListCombo, mySelectedProjectCharset);
myTreeView = new EncodingFileTreeTable(myProject);
myTreePanel.setViewportView(myTreeView);
myTreeView.getEmptyText().setText(IdeBundle.message("file.encodings.not.configured"));
return myPanel;
@@ -128,7 +132,8 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
@Override
public boolean isModified() {
if (isEncodingModified()) return true;
if (isIdeEncodingModified()) return true;
if (isProjectEncodingModified()) return true;
EncodingProjectManager encodingManager = EncodingProjectManager.getInstance(myProject);
Map<VirtualFile, Charset> editing = myTreeView.getValues();
@@ -141,7 +146,7 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
return !same;
}
public boolean isEncodingModified() {
private boolean isIdeEncodingModified() {
Charset charset = mySelectedIdeCharset.get();
if (null == charset) {
return !StringUtil.isEmpty(EncodingManager.getInstance().getDefaultCharsetName());
@@ -149,6 +154,10 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
return !Comparing.equal(charset, EncodingManager.getInstance().getDefaultCharset());
}
private boolean isProjectEncodingModified() {
Charset charset = mySelectedProjectCharset.get();
return !Comparing.equal(charset, EncodingProjectManager.getInstance(myProject).getEncoding(null, false));
}
@Override
public void apply() throws ConfigurationException {
@@ -159,8 +168,10 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
encodingManager.setNative2AsciiForPropertiesFiles(null, myTransparentNativeToAsciiCheckBox.isSelected());
encodingManager.setUseUTFGuessing(null, myAutodetectUTFEncodedFilesCheckBox.isSelected());
Charset charset = mySelectedIdeCharset.get();
EncodingManager.getInstance().setDefaultCharsetName(charset == null ? "" : charset.name());
Charset ideCharset = mySelectedIdeCharset.get();
EncodingManager.getInstance().setDefaultCharsetName(ideCharset == null ? "" : ideCharset.name());
Charset projectCharset = mySelectedIdeCharset.get();
EncodingProjectManager.getInstance(myProject).setEncoding(null, projectCharset);
}
@Override
@@ -172,8 +183,10 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
mySelectedCharsetForPropertiesFiles.set(encodingManager.getDefaultCharsetForPropertiesFiles(null));
mySelectedIdeCharset.set(EncodingManager.getInstance().getDefaultCharset());
myPropertiesEncodingAction.update((AnActionEvent)null);
myIdeEncodingAction.update((AnActionEvent)null);
mySelectedProjectCharset.set(EncodingProjectManager.getInstance(myProject).getEncoding(null, false));
myPropertiesEncodingAction.update(null);
myIdeEncodingAction.update(null);
myProjectEncodingAction.update(null);
}
@Override
@@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
* @author peter
*/
public class TemplateDataLanguageConfigurable extends LanguagePerFileConfigurable<Language> {
public TemplateDataLanguageConfigurable(Project project) {
public TemplateDataLanguageConfigurable(@NotNull Project project) {
super(project, Language.class, TemplateDataLanguageMappings.getInstance(project),
LangBundle.message("dialog.template.data.language.caption", ApplicationNamesInfo.getInstance().getFullProductName()),
LangBundle.message("template.data.language.configurable.tree.table.title"),
@@ -52,11 +52,11 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
private final MyModel<T> myModel;
private final Project myProject;
public AbstractFileTreeTable(final Project project, final Class<T> valueClass, final String valueTitle) {
this(project, valueClass, valueTitle, VirtualFileFilter.ALL);
}
public AbstractFileTreeTable(final Project project, final Class<T> valueClass, final String valueTitle, @NotNull VirtualFileFilter filter) {
public AbstractFileTreeTable(@NotNull Project project,
@NotNull Class<T> valueClass,
@NotNull String valueTitle,
@NotNull VirtualFileFilter filter,
boolean showProjectNode) {
super(new MyModel<T>(project, valueClass, valueTitle, filter));
myProject = project;
@@ -83,7 +83,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
getTree().setShowsRootHandles(true);
getTree().setLineStyleAngled();
getTree().setRootVisible(true);
getTree().setRootVisible(showProjectNode);
getTree().setCellRenderer(new DefaultTreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean sel, final boolean expanded,
@@ -122,7 +122,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
return false;
}
private String getProjectNodeText() {
private static String getProjectNodeText() {
return "Project";
}
@@ -176,6 +176,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
}
}
@NotNull
public Map<VirtualFile, T> getValues() {
return myModel.getValues();
}
@@ -190,12 +191,13 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
return tableRenderer;
}
public void reset(final Map<VirtualFile, T> mappings) {
public void reset(@NotNull Map<VirtualFile, T> mappings) {
myModel.reset(mappings);
final TreeNode root = (TreeNode)myModel.getRoot();
myModel.nodeChanged(root);
getTree().setModel(null);
getTree().setModel(myModel);
TreeUtil.expandRootChildIfOnlyOne(getTree());
}
public void select(@Nullable final VirtualFile toSelect) {
@@ -230,7 +232,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
private final String myValueTitle;
private AbstractFileTreeTable<T> myTreeTable;
private MyModel(final Project project, final Class<T> valueClass, final String valueTitle, VirtualFileFilter filter) {
private MyModel(@NotNull Project project, @NotNull Class<T> valueClass, @NotNull String valueTitle, @NotNull VirtualFileFilter filter) {
super(new ProjectRootNode(project, filter));
myValueClass = valueClass;
myValueTitle = valueTitle;
@@ -324,7 +326,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
fireTreeNodesChanged(this, new Object[]{getRoot()}, null, null);
}
public void reset(final Map<VirtualFile, T> mappings) {
public void reset(@NotNull Map<VirtualFile, T> mappings) {
myCurrentMapping.clear();
myCurrentMapping.putAll(mappings);
((ProjectRootNode)getRoot()).clearCachedChildren();
@@ -348,7 +350,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
}
@Override
protected void appendChildrenTo(final Collection<ConvenientNode> children) {
protected void appendChildrenTo(@NotNull final Collection<ConvenientNode> children) {
Project project = getObject();
VirtualFile[] roots = ProjectRootManager.getInstance(project).getContentRoots();
@@ -375,7 +377,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
return myObject;
}
protected abstract void appendChildrenTo(final Collection<ConvenientNode> children);
protected abstract void appendChildrenTo(@NotNull Collection<ConvenientNode> children);
@Override
public int getChildCount() {
@@ -450,7 +452,7 @@ public abstract class AbstractFileTreeTable<T> extends TreeTable {
}
@Override
protected void appendChildrenTo(final Collection<ConvenientNode> children) {
protected void appendChildrenTo(@NotNull final Collection<ConvenientNode> children) {
VirtualFile[] childrenf = getObject().getChildren();
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
for (VirtualFile child : childrenf) {
@@ -26,6 +26,7 @@ import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SimpleTextAttributes;
@@ -56,7 +57,7 @@ public abstract class LanguagePerFileConfigurable<T> implements SearchableConfig
private JPanel myPanel;
private JLabel myLabel;
protected LanguagePerFileConfigurable(final Project project, Class<T> valueClass, PerFileMappings<T> mappings, String caption, String treeTableTitle, String overrideQuestion, String overrideTitle) {
protected LanguagePerFileConfigurable(@NotNull Project project, Class<T> valueClass, PerFileMappings<T> mappings, String caption, String treeTableTitle, String overrideQuestion, String overrideTitle) {
myProject = project;
myValueClass = valueClass;
myMappings = mappings;
@@ -131,9 +132,8 @@ public abstract class LanguagePerFileConfigurable<T> implements SearchableConfig
}
private class MyTreeTable extends AbstractFileTreeTable<T> {
public MyTreeTable() {
super(myProject, myValueClass, myTreeTableTitle);
super(myProject, myValueClass, myTreeTableTitle, VirtualFileFilter.ALL, true);
getValueColumn().setCellEditor(new DefaultCellEditor(new JComboBox()) {
private VirtualFile myVirtualFile;
@@ -129,11 +129,11 @@ public class GeneralSettings implements NamedJDOMExternalizable, ExportableAppli
/**
* @return a path pointing to a directory where the last project was created or null if not available
*/
public String getLastProjectLocation() {
public String getLastProjectCreationLocation() {
return myLastProjectLocation;
}
public void setLastProjectLocation(String lastProjectLocation) {
public void setLastProjectCreationLocation(String lastProjectLocation) {
myLastProjectLocation = lastProjectLocation;
}
@@ -65,9 +65,10 @@ public class AnActionEvent implements PlaceProvider<String> {
myModifiers = modifiers;
}
public static AnActionEvent createFromInputEvent(AnAction action, InputEvent event, String place) {
DataContext context = event != null ? DataManager.getInstance().getDataContext(event.getComponent()) : DataManager.getInstance().getDataContext();
int modifiers = event != null ? event.getModifiers() : 0;
@NotNull
public static AnActionEvent createFromInputEvent(@NotNull AnAction action, InputEvent event, @NotNull String place) {
DataContext context = event == null ? DataManager.getInstance().getDataContext() : DataManager.getInstance().getDataContext(event.getComponent());
int modifiers = event == null ? 0 : event.getModifiers();
return new AnActionEvent(
event,
context,
@@ -56,7 +56,7 @@ public class DefaultActionGroup extends ActionGroup {
* @param actions the actions to add to the group
* @since 9.0
*/
public DefaultActionGroup(AnAction... actions) {
public DefaultActionGroup(@NotNull AnAction... actions) {
this(null, false);
for (AnAction action : actions) {
add(action);
@@ -27,7 +27,6 @@ import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -48,9 +47,11 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
protected ComboBoxAction() {
}
@Override
public void actionPerformed(AnActionEvent e) {
}
@Override
public JComponent createCustomComponent(Presentation presentation) {
JPanel panel = new JPanel(new GridBagLayout());
ComboBoxButton button = createComboBoxButton(presentation);
@@ -114,9 +115,11 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
}
addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!myForcePressed) {
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(new Runnable() {
@Override
public void run() {
showPopup();
}
@@ -197,9 +200,11 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
repaint();
Runnable onDispose = new Runnable() {
@Override
public void run() {
// give button chance to handle action listener
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
myForcePressed = false;
myPopup = null;
@@ -210,7 +215,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
};
myPopup = createPopup(onDispose);
myPopup.show(new RelativePoint(this, new Point(0, this.getHeight() - 1)));
myPopup.show(new RelativePoint(this, new Point(0, getHeight() - 1)));
}
@Nullable
@@ -263,7 +268,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
private void updateTooltipText(String description) {
String tooltip = AnAction.createTooltipText(description, ComboBoxAction.this);
setToolTipText(tooltip.length() > 0 ? tooltip : null);
setToolTipText(!tooltip.isEmpty() ? tooltip : null);
}
@Override
@@ -275,16 +280,19 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
}
protected class MyButtonModel extends DefaultButtonModel {
@Override
public boolean isPressed() {
return myForcePressed || super.isPressed();
}
@Override
public boolean isArmed() {
return myForcePressed || super.isArmed();
}
}
private class MyButtonSynchronizer implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
if (Presentation.PROP_TEXT.equals(propertyName)) {
@@ -390,7 +398,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
}
}
else {
super.paintComponent(g);
paintComponent(g);
}
final Insets insets = super.getInsets();
final Icon icon = isEnabled() ? AllIcons.General.ComboArrow : DISABLED_ARROW_ICON;
@@ -32,7 +32,10 @@ public abstract class ReadonlyStatusHandler {
public static boolean ensureDocumentWritable(@NotNull Project project, @NotNull Document document) {
final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
boolean okWritable;
if (psiFile != null) {
if (psiFile == null) {
okWritable = document.isWritable();
}
else {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile != null) {
okWritable = ensureFilesWritable(project, virtualFile);
@@ -41,9 +44,6 @@ public abstract class ReadonlyStatusHandler {
okWritable = psiFile.isWritable();
}
}
else {
okWritable = document.isWritable();
}
return okWritable;
}
@@ -60,7 +60,7 @@ public abstract class ReadonlyStatusHandler {
public abstract OperationStatus ensureFilesWritable(@NotNull VirtualFile... files);
public OperationStatus ensureFilesWritable(@NotNull Collection<VirtualFile> files) {
return ensureFilesWritable(VfsUtil.toVirtualFileArray(files));
return ensureFilesWritable(VfsUtilCore.toVirtualFileArray(files));
}
public static ReadonlyStatusHandler getInstance(Project project) {
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.nio.charset.Charset;
import java.util.Map;
@@ -32,8 +33,9 @@ public abstract class EncodingProjectManager extends EncodingManager implements
return project.getComponent(EncodingProjectManager.class);
}
@NotNull
public abstract Map<VirtualFile, Charset> getAllMappings();
public abstract void setMapping(Map<VirtualFile, Charset> result);
public abstract void setMapping(@NotNull Map<VirtualFile, Charset> result);
}
@@ -37,7 +37,7 @@ public class ErrorLabel extends JLabel {
}
public ErrorLabel(String text, Icon icon) {
super(text, icon, JLabel.LEFT);
super(text, icon, SwingConstants.LEFT);
setOpaque(false);
}
@@ -52,6 +52,7 @@ public class ErrorLabel extends JLabel {
}
}
@Override
public void setToolTipText(String text) {
if (myUnderline) {
myTooltip = text;
@@ -69,24 +70,26 @@ public class ErrorLabel extends JLabel {
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (getText() != null & myUnderline) {
String text = getText();
if (text != null && myUnderline) {
g.setColor(myForeground);
int x = 0;
if (getIcon() != null) {
x = getIcon().getIconWidth() + getIconTextGap();
Icon icon = getIcon();
if (icon != null) {
x = icon.getIconWidth() + getIconTextGap();
}
if (getHorizontalAlignment() == CENTER) {
int w = g.getFontMetrics().stringWidth(getText());
int w = g.getFontMetrics().stringWidth(text);
x += (getWidth() - x - w) >> 1;
}
drawWave(this, g, x, getText());
drawWave(this, g, x, text);
}
}
@@ -117,6 +120,6 @@ public class ErrorLabel extends JLabel {
private static int getTextBaseLine(Component c) {
FontMetrics fm = c.getFontMetrics(c.getFont());
return (c.getHeight() >> 1) + ((fm.getHeight() >> 1) - fm.getDescent());
return (c.getHeight() >> 1) + (fm.getHeight() >> 1) - fm.getDescent();
}
}
@@ -113,57 +113,66 @@ public abstract class GroupedElementsRenderer {
return getBorder();
}
private Border getSelectedBorder() {
private static Border getSelectedBorder() {
return UIUtil.isToUseDottedCellBorder() ? new DottedBorder(UIUtil.getListCellPadding(), SELECTED_FRAME_FOREGROUND) : new EmptyBorder(UIUtil.getListCellPadding());
}
private Border getBorder() {
private static Border getBorder() {
return new EmptyBorder(UIUtil.getListCellPadding());
}
public static abstract class List extends GroupedElementsRenderer {
public abstract static class List extends GroupedElementsRenderer {
@Override
protected final void layout() {
myRendererComponent.add(mySeparatorComponent, BorderLayout.NORTH);
myRendererComponent.add(myComponent, BorderLayout.CENTER);
}
@Override
protected final Color getSelectionBackground() {
return UIUtil.getListSelectionBackground();
}
@Override
protected final Color getSelectionForeground() {
return UIUtil.getListSelectionForeground();
}
@Override
protected final Color getBackground() {
return UIUtil.getListBackground();
}
@Override
protected final Color getForeground() {
return UIUtil.getListForeground();
}
}
public static abstract class Tree extends GroupedElementsRenderer implements TreeCellRenderer {
public abstract static class Tree extends GroupedElementsRenderer implements TreeCellRenderer {
@Override
protected void layout() {
myRendererComponent.add(mySeparatorComponent, BorderLayout.NORTH);
myRendererComponent.add(myComponent, BorderLayout.WEST);
}
@Override
protected final Color getSelectionBackground() {
return UIUtil.getTreeSelectionBackground();
}
@Override
protected final Color getSelectionForeground() {
return UIUtil.getTreeSelectionForeground();
}
@Override
protected final Color getBackground() {
return UIUtil.getTreeTextBackground();
}
@Override
protected final Color getForeground() {
return UIUtil.getTreeTextForeground();
}
@@ -20,6 +20,7 @@ import com.intellij.ide.GeneralSettings;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.highlighter.ProjectFileType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.StorageScheme;
import com.intellij.openapi.components.impl.stores.IProjectStore;
@@ -37,6 +38,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.*;
import com.intellij.projectImport.ProjectOpenProcessor;
import com.intellij.ui.AppIcon;
import com.intellij.util.SystemProperties;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -73,7 +75,7 @@ public class ProjectUtil {
LOG.info(e);
return;
}
GeneralSettings.getInstance().setLastProjectLocation(path.replace(File.separatorChar, '/'));
GeneralSettings.getInstance().setLastProjectCreationLocation(path.replace(File.separatorChar, '/'));
}
/**
@@ -275,4 +277,15 @@ public class ProjectUtil {
public static boolean isProjectOrWorkspaceFile(final VirtualFile file) {
return com.intellij.openapi.project.ProjectUtil.isProjectOrWorkspaceFile(file);
}
public static String getBaseDir() {
final String lastProjectLocation = GeneralSettings.getInstance().getLastProjectCreationLocation();
if (lastProjectLocation != null) {
return lastProjectLocation.replace('/', File.separatorChar);
}
final String userHome = SystemProperties.getUserHome();
//noinspection HardCodedStringLiteral
return userHome.replace('/', File.separatorChar) + File.separator + ApplicationNamesInfo.getInstance().getLowercaseProductName() +
"Projects";
}
}
@@ -120,6 +120,9 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
try {
method.invoke(myBus.syncPublisher(AppTopics.FILE_DOCUMENT_SYNC), args);
}
catch (ClassCastException e) {
LOG.error("Arguments: "+ Arrays.toString(args), e);
}
catch (Exception e) {
LOG.error(e);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -45,7 +45,6 @@ import com.intellij.ui.*;
import com.intellij.ui.mac.foundation.Foundation;
import com.intellij.ui.mac.foundation.ID;
import com.intellij.ui.mac.foundation.MacUtil;
import com.intellij.ui.popup.StackingPopupDispatcherImpl;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -67,11 +66,8 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
private DialogWrapper myWrapper;
private AbstractDialog myDialog;
private boolean myCanBeParent = true;
/*
* Default dialog's actions.
*/
private WindowManagerEx myWindowManager;
private final java.util.List<Runnable> myDisposeActions = new ArrayList<Runnable>();
private final List<Runnable> myDisposeActions = new ArrayList<Runnable>();
private Project myProject;
private final ActionCallback myWindowFocusedCallback = new ActionCallback("DialogFocusedCallback");
@@ -89,7 +85,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
*/
protected DialogWrapperPeerImpl(DialogWrapper wrapper, @Nullable Project project, boolean canBeParent) {
myWrapper = wrapper;
myTypeAheadCallback = myWrapper.isTypeAheadEnabled() ? new ActionCallback() : (ActionCallback)null;
myTypeAheadCallback = myWrapper.isTypeAheadEnabled() ? new ActionCallback() : null;
myWindowManager = null;
Application application = ApplicationManager.getApplication();
if (application != null && application.hasComponent(WindowManager.class)) {
@@ -100,6 +96,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
if (myWindowManager != null) {
if (project == null) {
//noinspection deprecation
project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
}
@@ -150,7 +147,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
/**
* @param parent parent component whicg is used to canculate heavy weight window ancestor.
* @param parent parent component which is used to calculate heavy weight window ancestor.
* <code>parent</code> cannot be <code>null</code> and must be showing.
*/
protected DialogWrapperPeerImpl(DialogWrapper wrapper, @NotNull Component parent, boolean canBeParent) {
@@ -211,18 +208,11 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
return;
}
if (owner instanceof Frame) {
myDialog = new MyDialog((Frame)owner, myWrapper, myProject, myWindowFocusedCallback, myTypeAheadDone, myTypeAheadCallback);
}
else {
myDialog = new MyDialog((Dialog)owner, myWrapper, myProject, myWindowFocusedCallback, myTypeAheadDone, myTypeAheadCallback);
}
myDialog = new MyDialog(owner, myWrapper, myProject, myWindowFocusedCallback, myTypeAheadDone, myTypeAheadCallback);
myDialog.setModal(true);
myCanBeParent = canBeParent;
}
public void toFront() {
myDialog.toFront();
}
@@ -231,6 +221,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
myDialog.toBack();
}
@SuppressWarnings("SSBasedInspection")
protected void dispose() {
LOG.assertTrue(EventQueue.isDispatchThread(), "Access is allowed from event dispatch thread only");
for (Runnable runnable : myDisposeActions) {
@@ -243,14 +234,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
public void run() {
myDialog.dispose();
myProject = null;
/*
if (myWindowManager == null) {
myDialog.dispose();
}
else {
myWindowManager.hideDialog(myDialog, myProject);
}
*/
SwingUtilities.invokeLater(new Runnable() {
public void run() {
@@ -403,14 +386,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
final boolean appStarted = commandProcessor != null;
if (myDialog.isModal() && !isProgressDialog()) {
/*
if (ApplicationManager.getApplication() != null) {
if (ApplicationManager.getApplication().getCurrentWriteAction(null) != null) {
LOG.warn(
"Showing of a modal dialog inside write-action may be dangerous and resulting in unpredictable behavior! Current modalityState=" + ModalityState.current(), new Exception());
}
}
*/
if (appStarted) {
commandProcessor.enterModal();
LaterInvocator.enterModal(myDialog);
@@ -438,16 +413,14 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
return result;
}
//[kirillk] for now it only deals with the TaskWindow under Mac OS X: modal dialogs are shown behind JBPopup
//hopefully this whole code will go away
private void hidePopupsIfNeeded() {
if (!SystemInfo.isMac) return;
StackingPopupDispatcherImpl.getInstance().hidePersistentPopups();
StackingPopupDispatcher.getInstance().hidePersistentPopups();
myDisposeActions.add(new Runnable() {
public void run() {
StackingPopupDispatcherImpl.getInstance().restorePersistentPopups();
StackingPopupDispatcher.getInstance().restorePersistentPopups();
}
});
}
@@ -488,6 +461,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
private static class MyDialog extends JDialog implements DialogWrapperDialog, DataProvider, FocusTrackback.Provider, Queryable, AbstractDialog {
private final WeakReference<DialogWrapper> myDialogWrapper;
/**
* Initial size of the dialog. When the dialog is being closed and
* current size of the dialog is not equals to the initial size then the
@@ -507,16 +481,12 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
private ActionCallback myTypeAheadCallback;
private MyComponentListener myComponentListener;
public MyDialog(Dialog owner, DialogWrapper dialogWrapper, Project project, ActionCallback focused, ActionCallback typeAheadDone, ActionCallback typeAheadCallback) {
super(owner);
myDialogWrapper = new WeakReference<DialogWrapper>(dialogWrapper);
myProject = project != null ? new WeakReference<Project>(project) : null;
initDialog(focused, typeAheadDone, typeAheadCallback);
}
public MyDialog(Frame owner, DialogWrapper dialogWrapper, Project project, ActionCallback focused, ActionCallback typeAheadDone, ActionCallback typeAheadCallback) {
public MyDialog(Window owner,
DialogWrapper dialogWrapper,
Project project,
ActionCallback focused,
ActionCallback typeAheadDone,
ActionCallback typeAheadCallback) {
super(owner);
myDialogWrapper = new WeakReference<DialogWrapper>(dialogWrapper);
myProject = project != null ? new WeakReference<Project>(project) : null;
@@ -605,6 +575,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
return new DialogRootPane();
}
@SuppressWarnings("deprecation")
public void show() {
myFocusTrackback = new FocusTrackback(getDialogWrapper(), getParent(), true);
@@ -628,7 +599,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
location = DimensionService.getInstance().getLocation(myDimensionServiceKey, projectGuess);
Dimension size = DimensionService.getInstance().getSize(myDimensionServiceKey, projectGuess);
if (size != null) {
myInitialSize = (Dimension)size.clone();
myInitialSize = new Dimension(size);
_setSizeForLocation(myInitialSize.width, myInitialSize.height, location);
}
}
@@ -653,7 +624,8 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
setBounds(bounds);
addWindowListener(new WindowAdapter() {
public void windowActivated(final WindowEvent e) {
@Override
public void windowActivated(WindowEvent e) {
final DialogWrapper wrapper = getDialogWrapper();
if (wrapper != null && myFocusTrackback != null) {
myFocusTrackback.cleanParentWindow();
@@ -665,10 +637,12 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
public void windowDeactivated(final WindowEvent e) {
@Override
public void windowDeactivated(WindowEvent e) {
if (!isModal()) {
final Ref<IdeFocusManager> focusManager = new Ref<IdeFocusManager>(null);
if (myProject != null && myProject.get() != null && !myProject.get().isDisposed()) {
Project project = getProject();
if (project != null && !project.isDisposed()) {
focusManager.set(getFocusManager());
focusManager.get().doWhenFocusSettlesDown(new Runnable() {
public void run() {
@@ -681,6 +655,20 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
}
@Override
public void windowOpened(WindowEvent e) {
if (!SystemInfo.isMacOSLion) return;
Window window = e.getWindow();
if (window instanceof Dialog) {
ID _native = MacUtil.findWindowForTitle(((Dialog)window).getTitle());
if (_native != null && _native.intValue() > 0) {
// see MacMainFrameDecorator
// NSCollectionBehaviorFullScreenAuxiliary = 1 << 8
Foundation.invoke(_native, "setCollectionBehavior:", 1 << 8);
}
}
}
});
if (Registry.is("actionSystem.fixLostTyping")) {
@@ -697,40 +685,28 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
if (SystemInfo.isMacOSLion) {
final WindowAdapter macFullScreenPatchListener = new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
Window window = e.getWindow();
if (window instanceof Dialog) {
ID _native = MacUtil.findWindowForTitle(((Dialog)window).getTitle());
if (_native != null && _native.intValue() > 0) {
// see MacMainFrameDecorator
// NSCollectionBehaviorFullScreenAuxiliary = 1 << 8
Foundation.invoke(_native, "setCollectionBehavior:", 1 << 8);
}
}
}
};
addWindowListener(macFullScreenPatchListener);
}
if (SystemInfo.isMac && myProject != null && Registry.is("ide.mac.fix.dialog.showing") && !dialogWrapper.isModalProgress()) {
final IdeFrame frame = WindowManager.getInstance().getIdeFrame(myProject.get());
AppIcon.getInstance().requestFocus(frame);
}
setBackground(UIUtil.getPanelBackground());
superShow();
}
private void superShow() {
setBackground(UIUtil.getPanelBackground());
super.show();
}
@Nullable
private Project getProject() {
return myProject != null ? myProject.get() : null;
}
@Override
public IdeFocusManager getFocusManager() {
if (myProject != null && myProject.get() != null && !myProject.get().isDisposed()) {
return IdeFocusManager.getInstance(myProject.get());
} else {
Project project = getProject();
if (project != null && !project.isDisposed()) {
return IdeFocusManager.getInstance(project);
}
else {
return IdeFocusManager.findInstance();
}
}
@@ -758,7 +734,8 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
@Deprecated
@Override
@SuppressWarnings("deprecation")
public void hide() {
super.hide();
if (myFocusTrackback != null && !(myFocusTrackback.isSheduledForRestore() || myFocusTrackback.isWillBeSheduledForRestore())) {
@@ -774,6 +751,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
@Override
public void dispose() {
if (isShowing()) {
hide();
@@ -858,6 +836,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
super.paint(g);
}
@SuppressWarnings("SSBasedInspection")
private class MyWindowListener extends WindowAdapter {
public void windowClosing(WindowEvent e) {
DialogWrapper dialogWrapper = getDialogWrapper();
@@ -866,6 +845,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
@Override
public void windowClosed(WindowEvent e) {
saveSize();
}
@@ -888,7 +868,6 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
@Override
public void windowOpened(WindowEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@@ -904,6 +883,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
});
}
@Override
public void windowActivated(final WindowEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
@@ -979,8 +959,8 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
Robot robot = new Robot();
robot.mouseMove(p.x + r.width / 2, p.y + r.height / 2);
}
catch (AWTException exc) {
exc.printStackTrace();
catch (AWTException e) {
LOG.warn(e);
}
}
}
@@ -1016,7 +996,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
public Object getData(@NonNls String dataId) {
final DialogWrapper wrapper = myDialogWrapper.get();
return PlatformDataKeys.UI_DISPOSABLE.is(dataId) ? wrapper.getDisposable() : null;
return wrapper != null && PlatformDataKeys.UI_DISPOSABLE.is(dataId) ? wrapper.getDisposable() : null;
}
}
@@ -1057,7 +1037,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
myEvents.addAll(context.getQueue());
context.getQueue().clear();
if (isToDipatchToDialogNow(e)) {
if (isToDispatchToDialogNow(e)) {
return false;
} else {
myEvents.add(e);
@@ -1065,7 +1045,7 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
}
}
private boolean isToDipatchToDialogNow(KeyEvent e) {
private boolean isToDispatchToDialogNow(KeyEvent e) {
return e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_ESCAPE || e.getKeyCode() == KeyEvent.VK_TAB;
}
@@ -52,15 +52,19 @@ public class CheckForUpdateAction extends AnAction implements DumbAware {
indicator.setIndeterminate(true);
final CheckForUpdateResult result = UpdateChecker.checkForUpdates(instance, true);
if (result.getState() == UpdateStrategy.State.CONNECTION_ERROR) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
UpdateChecker.showConnectionErrorDialog();
}
});
return;
}
final List<PluginDownloader> updatedPlugins = UpdateChecker.updatePlugins(true, hostsConfigurable, indicator);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (result.getState() == UpdateStrategy.State.CONNECTION_ERROR) {
UpdateChecker.showConnectionErrorDialog();
return;
}
instance.saveLastCheckedInfo();
UpdateChecker.showUpdateResult(result, updatedPlugins, true, enableLink, true);
}
@@ -26,10 +26,7 @@ import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.MultiValuesMap;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.WritingAccessProvider;
import com.intellij.openapi.vfs.*;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
@@ -59,14 +56,17 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
myAccessProviders = WritingAccessProvider.getProvidersForProject(myProject);
}
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
@Override
public OperationStatus ensureFilesWritable(@NotNull VirtualFile... files) {
if (files.length == 0) {
return new OperationStatusImpl(VirtualFile.EMPTY_ARRAY);
@@ -80,7 +80,7 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
realFiles.add(file);
}
}
files = VfsUtil.toVirtualFileArray(realFiles);
files = VfsUtilCore.toVirtualFileArray(realFiles);
for (final WritingAccessProvider accessProvider : myAccessProviders) {
Collection<VirtualFile> denied = ContainerUtil.filter(files, new Condition<VirtualFile>() {
@@ -94,7 +94,7 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
denied = accessProvider.requestWriting(files);
}
if (!denied.isEmpty()) {
return new OperationStatusImpl(VfsUtil.toVirtualFileArray(denied));
return new OperationStatusImpl(VfsUtilCore.toVirtualFileArray(denied));
}
}
@@ -131,7 +131,7 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
}
}
return new OperationStatusImpl(VfsUtil.toVirtualFileArray(readOnlyFiles));
return new OperationStatusImpl(VfsUtilCore.toVirtualFileArray(readOnlyFiles));
}
private FileInfo[] createFileInfos(VirtualFile[] files) {
@@ -170,15 +170,18 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
myReadonlyFiles = readonlyFiles;
}
@Override
@NotNull
public VirtualFile[] getReadonlyFiles() {
return myReadonlyFiles;
}
@Override
public boolean hasReadonlyFiles() {
return myReadonlyFiles.length > 0;
}
@Override
@NotNull
public String getReadonlyFilesMessage() {
if (hasReadonlyFiles()) {
@@ -1,79 +0,0 @@
/*
* Copyright 2000-2009 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.vfs.encoding;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author cdr
*/
public class ChangeFileEncodingGroup extends ActionGroup {
@Override
@NotNull
public AnAction[] getChildren(@Nullable final AnActionEvent e) {
if (e == null) return EMPTY_ARRAY;
VirtualFile virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE);
if(virtualFile == null || !virtualFile.isInLocalFileSystem()){
return EMPTY_ARRAY;
}
List<Charset> charsets = new ArrayList<Charset>(EncodingManager.getInstance().getFavorites());
Collections.sort(charsets);
Charset current = virtualFile.getCharset();
charsets.remove(current);
List<AnAction> children = new ArrayList<AnAction>(charsets.size());
for (Charset charset : charsets) {
ChangeFileEncodingTo action = new ChangeFileEncodingTo(virtualFile, charset);
children.add(action);
}
children.add(new More(virtualFile));
children.add(new Separator());
return children.toArray(new AnAction[children.size()]);
}
private static class More extends AnAction implements DumbAware {
private final VirtualFile myVirtualFile;
private More(VirtualFile virtualFile) {
myVirtualFile = virtualFile;
getTemplatePresentation().setText("more...");
}
@Override
public void actionPerformed(final AnActionEvent e) {
Charset[] charsets = CharsetToolkit.getAvailableCharsets();
ChooseEncodingDialog dialog = new ChooseEncodingDialog(charsets, myVirtualFile.getCharset(), myVirtualFile);
dialog.show();
Charset charset = dialog.getChosen();
if (dialog.isOK() && charset != null) {
EncodingManager.getInstance().setEncoding(myVirtualFile, charset);
}
}
}
}
@@ -17,36 +17,25 @@ package com.intellij.openapi.vfs.encoding;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.charset.Charset;
import java.text.MessageFormat;
/**
* @author cdr
*/
class ChangeFileEncodingTo extends AnAction implements DumbAware {
abstract class ChangeFileEncodingTo extends AnAction implements DumbAware {
private final VirtualFile myFile;
private final Charset myCharset;
ChangeFileEncodingTo(@Nullable VirtualFile file, @NotNull Charset charset) {
super(charset.displayName());
ChangeFileEncodingTo(@Nullable VirtualFile file, @NotNull Charset charset, @NotNull String pattern) {
super(charset.displayName(), MessageFormat.format(pattern, file == null ? null : file.getName(), charset.displayName()), null);
myFile = file;
myCharset = charset;
String description;
if (file == null) {
description = "Change default encoding to '"+charset.displayName()+"'.";
}
else {
Pair<String, Boolean> result = ChooseFileEncodingAction.update(file);
boolean enabled = result.second;
description = enabled ? result.first + " '" + charset.displayName() + "'" : result.first;
}
getTemplatePresentation().setDescription(description);
}
@Override
@@ -54,7 +43,5 @@ class ChangeFileEncodingTo extends AnAction implements DumbAware {
chosen(myFile, myCharset);
}
protected void chosen(@Nullable VirtualFile file, @NotNull Charset charset) {
EncodingManager.getInstance().setEncoding(file, charset);
}
protected abstract void chosen(@Nullable VirtualFile file, @NotNull Charset charset);
}
@@ -22,6 +22,7 @@
*/
package com.intellij.openapi.vfs.encoding;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
@@ -32,13 +33,13 @@ import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
@@ -56,68 +57,44 @@ public abstract class ChooseFileEncodingAction extends ComboBoxAction {
}
@Override
public void update(final AnActionEvent e) {
Pair<String, Boolean> result = update(myVirtualFile);
public abstract void update(final AnActionEvent e);
boolean enabled = result.second;
if (myVirtualFile != null) {
Charset charset = cachedCharsetFromContent(myVirtualFile);
String prefix = charset == null ? "" : "Encoding (auto-detected):";
if (charset == null) charset = myVirtualFile.getCharset();
e.getPresentation().setText(prefix + " " + charset.toString());
}
e.getPresentation().setEnabled(enabled);
e.getPresentation().setDescription(result.first);
}
// returns null if "change encoding" action is enabled for the file;
// reason why not, if it is disabled
public static String isEnabledAndWhyNot(@Nullable VirtualFile virtualFile) {
if (virtualFile == null) {
return "file not specified";
}
Charset charset = cachedCharsetFromContent(virtualFile);
if (charset != null) {
return "charset specified inside the file";
}
if (virtualFile.isDirectory()) {
return null;
}
@NotNull
private static Pair<Charset, String> checkFileType(@NotNull VirtualFile virtualFile) {
FileType fileType = virtualFile.getFileType();
if (fileType.isBinary()) return "binary file";
if (fileType == StdFileTypes.GUI_DESIGNER_FORM) return "IDEA GUI Designer form";
if (fileType == StdFileTypes.IDEA_MODULE) return "IDEA module file";
if (fileType == StdFileTypes.IDEA_PROJECT) return "IDEA project file";
if (fileType == StdFileTypes.IDEA_WORKSPACE) return "IDEA workspace file";
if (fileType.isBinary()) return Pair.create(null, "binary file");
if (fileType == StdFileTypes.GUI_DESIGNER_FORM) return Pair.create(CharsetToolkit.UTF8_CHARSET, "IDEA GUI Designer form");
if (fileType == StdFileTypes.IDEA_MODULE) return Pair.create(CharsetToolkit.UTF8_CHARSET, "IDEA module file");
if (fileType == StdFileTypes.IDEA_PROJECT) return Pair.create(CharsetToolkit.UTF8_CHARSET, "IDEA project file");
if (fileType == StdFileTypes.IDEA_WORKSPACE) return Pair.create(CharsetToolkit.UTF8_CHARSET, "IDEA workspace file");
if (fileType == StdFileTypes.PROPERTIES) return ".properties file";
if (fileType == StdFileTypes.PROPERTIES) return Pair.create(virtualFile.getCharset(), ".properties file");
if (fileType == StdFileTypes.XML
|| fileType == StdFileTypes.JSPX && fileType != FileTypes.PLAIN_TEXT // in community tests JSPX==PLAIN_TEXT
) {
return "XML file";
return Pair.create(virtualFile.getCharset(), "XML file");
}
return null;
return Pair.create(null, null);
}
@Nullable("returns null if charset set cannot be determined from content")
public static Charset cachedCharsetFromContent(final VirtualFile virtualFile) {
if (virtualFile == null) return null;
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) return null;
private void fillCharsetActions(@NotNull DefaultActionGroup group,
@Nullable VirtualFile virtualFile,
@NotNull List<Charset> charsets,
@Nullable final Condition<Charset> charsetFilter,
@NotNull String pattern) {
for (final Charset slave : charsets) {
ChangeFileEncodingTo action = new ChangeFileEncodingTo(virtualFile, slave, pattern) {
{
if (charsetFilter != null && !charsetFilter.value(slave)) {
getTemplatePresentation().setIcon(AllIcons.General.Warning);
}
}
return EncodingManager.getInstance().getCachedCharsetFromContent(document);
}
@Override
public void update(AnActionEvent e) {
}
@Override
@NotNull
protected DefaultActionGroup createPopupActionGroup(final JComponent button) {
return createGroup("<Clear>");
}
private void fillCharsetActions(DefaultActionGroup group, final VirtualFile virtualFile, List<Charset> charsets) {
for (Charset slave : charsets) {
ChangeFileEncodingTo action = new ChangeFileEncodingTo(virtualFile, slave){
@Override
protected void chosen(final VirtualFile file, @NotNull final Charset charset) {
ChooseFileEncodingAction.this.chosen(file, charset);
@@ -127,60 +104,71 @@ public abstract class ChooseFileEncodingAction extends ComboBoxAction {
}
}
// returns (action text, enabled flag)
@NotNull
public static Pair<String,Boolean> update(@Nullable VirtualFile virtualFile) {
String pattern;
String failReason = isEnabledAndWhyNot(virtualFile);
boolean enabled = failReason == null;
Charset charsetFromContent = cachedCharsetFromContent(virtualFile);
if (virtualFile != null && FileDocumentManager.getInstance().isFileModified(virtualFile)) {
//no sense to reload file with UTF-detected chars using other encoding
if (charsetFromContent != null) {
pattern = "Encoding (content-specified): {0}";
enabled = false;
}
else if (enabled) {
pattern = "Save ''{0}'' file in another encoding";
}
else {
pattern = "Encoding ''{0}'' ("+failReason+")";
}
@Nullable("null means enabled, notnull means disabled and contains error message")
public static String checkCanConvert(@NotNull VirtualFile virtualFile) {
if (virtualFile.isDirectory()) {
return "file is a directory";
}
String reason = LoadTextUtil.wasCharsetDetectedFromBytes(virtualFile);
if (reason == null) {
return null;
}
String failReason = null;
Charset charsetFromContent = ((EncodingManagerImpl)EncodingManager.getInstance()).computeCharsetFromContent(virtualFile);
if (charsetFromContent != null) {
failReason = "hard coded in text, encoding: {0}";
}
else {
// try to reload
// no sense in reloading file with UTF-detected chars using other encoding
if (virtualFile != null && LoadTextUtil.wasCharsetDetectedFromBytes(virtualFile)) {
pattern = "Encoding (auto-detected): {0}";
enabled = false;
}
else if (enabled && virtualFile != null && virtualFile.isDirectory()) {
pattern = "Reload ''{0}'' files under the directory in";
}
else if (enabled) {
pattern = "Reload ''{0}'' file in another encoding";
}
else if (charsetFromContent != null) {
pattern = "Encoding (content-specified): {0}";
}
else {
pattern = "Encoding ''{0}'' ("+failReason+")";
Pair<Charset, String> check = checkFileType(virtualFile);
if (check.second != null) {
failReason = check.second;
}
}
Charset charset = charsetFromContent != null ? charsetFromContent : virtualFile != null ? virtualFile.getCharset() : NO_ENCODING;
String text = charset == NO_ENCODING ? "Change file encoding" : MessageFormat.format(pattern, charset.displayName());
if (failReason != null) {
return MessageFormat.format(failReason, charsetFromContent == null ? "" : charsetFromContent.displayName());
}
return null;
}
return Pair.create(text, enabled);
@NotNull
// returns existing charset (null means N/A), failReason: null means enabled, notnull means disabled and contains error message
public static Pair<Charset, String> checkCanReload(@NotNull VirtualFile virtualFile) {
if (virtualFile.isDirectory()) {
return Pair.create(null, "file is a directory");
}
FileDocumentManager documentManager = FileDocumentManager.getInstance();
Document document = documentManager.getDocument(virtualFile);
if (document == null) return Pair.create(null, "binary file");
Charset charsetFromContent = ((EncodingManagerImpl)EncodingManager.getInstance()).computeCharsetFromContent(virtualFile);
Charset existing = charsetFromContent;
String failReason = LoadTextUtil.wasCharsetDetectedFromBytes(virtualFile);
if (failReason != null) {
// no point changing encoding if it was auto-detected
existing = virtualFile.getCharset();
}
else if (charsetFromContent != null) {
failReason = "hard coded in text";
}
else {
Pair<Charset, String> fileTypeCheck = checkFileType(virtualFile);
if (fileTypeCheck.second != null) {
failReason = fileTypeCheck.second;
existing = fileTypeCheck.first;
}
}
if (failReason != null) {
return Pair.create(existing, failReason);
}
return Pair.create(virtualFile.getCharset(), null);
}
private class ClearThisFileEncodingAction extends AnAction {
private final VirtualFile myFile;
private ClearThisFileEncodingAction(@Nullable VirtualFile file, @NotNull String clearItemText) {
super(clearItemText, "Clear " +
(file == null ? "default" : "file '"+file.getName()+"'") +
" encoding.", null);
super(clearItemText, "Clear " + (file == null ? "default" : "file '"+file.getName()+"'") + " encoding.", null);
myFile = file;
}
@@ -209,25 +197,29 @@ public abstract class ChooseFileEncodingAction extends ComboBoxAction {
protected abstract void chosen(@Nullable VirtualFile virtualFile, @NotNull Charset charset);
@NotNull
public DefaultActionGroup createGroup(@Nullable String clearItemText) {
public DefaultActionGroup createGroup(@Nullable("null means do not show 'clear' text") String clearItemText,
@Nullable Condition<Charset> charsetFilter,
@NotNull String pattern,
Charset alreadySelected) {
DefaultActionGroup group = new DefaultActionGroup();
List<Charset> favorites = new ArrayList<Charset>(EncodingManager.getInstance().getFavorites());
Collections.sort(favorites);
Charset current = myVirtualFile == null ? null : myVirtualFile.getCharset();
favorites.remove(current);
favorites.remove(alreadySelected);
if (clearItemText != null) {
group.add(new ClearThisFileEncodingAction(myVirtualFile, clearItemText));
}
if (favorites.isEmpty() && clearItemText == null) {
fillCharsetActions(group, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()));
fillCharsetActions(group, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()), charsetFilter, pattern);
}
else {
fillCharsetActions(group, myVirtualFile, favorites);
fillCharsetActions(group, myVirtualFile, favorites, charsetFilter, pattern);
DefaultActionGroup more = new DefaultActionGroup("more", true);
group.add(more);
fillCharsetActions(more, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()));
fillCharsetActions(more, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()), charsetFilter, pattern);
}
return group;
}
@@ -0,0 +1,124 @@
/*
* Copyright 2000-2012 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.vfs.encoding;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectLocator;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileListener;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.charset.Charset;
import java.text.MessageFormat;
/**
* @author cdr
*/
public class ConvertFileEncodingAction extends ReloadFileInOtherEncodingAction {
public ConvertFileEncodingAction() {
text = "Convert to...";
}
@Nullable
@Override
// document, description
public Pair<Document, String> checkEnabled(@NotNull VirtualFile virtualFile) {
String failReason = ChooseFileEncodingAction.checkCanConvert(virtualFile);
if (failReason != null) return null;
FileDocumentManager documentManager = FileDocumentManager.getInstance();
Document document = documentManager.getDocument(virtualFile);
if (document == null) return null;
Charset charsetFromContent = EncodingManager.getInstance().getCachedCharsetFromContent(document);
Charset charset = charsetFromContent != null ? charsetFromContent : virtualFile.getCharset();
String text = MessageFormat.format("Convert ''{0}''-encoded file ''{1}'' to another encoding", charset.displayName(), virtualFile.getName());
return Pair.create(document, text);
}
@Override
public boolean value(Charset charset) {
return canBeConvertedTo(myFile, charset);
}
public static boolean canBeConvertedTo(@NotNull VirtualFile virtualFile, @NotNull Charset charset) {
FileDocumentManager documentManager = FileDocumentManager.getInstance();
Document document = documentManager.getDocument(virtualFile);
if (document == null) return false;
String text = document.getText();
Pair<Charset, byte[]> chosen = LoadTextUtil.chooseMostlyHarmlessCharset(virtualFile.getCharset(), charset, text);
byte[] buffer = chosen.second;
CharSequence textLoadedBack = LoadTextUtil.getTextByBinaryPresentation(buffer, charset);
return text.equals(textLoadedBack.toString());
}
@Override
protected void chosen(@NotNull Document document, Editor editor, @NotNull VirtualFile virtualFile, @NotNull final Charset charset) {
if (!canBeConvertedTo(virtualFile, charset)) {
int res = Messages.showDialog("Encoding '" + charset.displayName() + "' does not support some characters from the text.",
"Incompatible Encoding: "+charset.displayName(), new String[]{"Convert anyway", "Cancel"}, 1, AllIcons.General.WarningDialog);
if (res != 0) return;
}
convert(document, editor, virtualFile, charset);
}
public static void convert(@NotNull Document document, Editor editor, @NotNull VirtualFile virtualFile, @NotNull Charset charset) {
FileDocumentManager documentManager = FileDocumentManager.getInstance();
if (documentManager.isFileModified(virtualFile)) {
EncodingManager.getInstance().setEncoding(virtualFile, charset);
LoadTextUtil.setCharsetWasDetectedFromBytes(virtualFile, null);
documentManager.saveDocument(document);
}
else {
Project project = ProjectLocator.getInstance().guessProjectForFile(virtualFile);
boolean writable = project == null ? virtualFile.isWritable() : ReadonlyStatusHandler.ensureFilesWritable(project, virtualFile);
if (!writable) {
CommonRefactoringUtil
.showErrorHint(project, editor, "Cannot save the file " + virtualFile.getPresentableUrl(), "Unable to Save", null);
return;
}
virtualFile.setCharset(charset);
try {
LoadTextUtil.write(project, virtualFile, virtualFile, document.getText(), document.getModificationStamp());
}
catch (IOException io) {
Messages.showErrorDialog(project, io.getMessage(), "Error Writing File");
}
EncodingManager.getInstance().setEncoding(virtualFile, charset);
((VirtualFileListener)documentManager).contentsChanged(new VirtualFileEvent(null, virtualFile, virtualFile.getName(), virtualFile.getParent()));
}
}
}
@@ -41,6 +41,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectLocator;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -126,13 +127,36 @@ public class EncodingManagerImpl extends EncodingManager implements PersistentSt
Charset charset = LoadTextUtil.charsetFromContentOrNull(project, virtualFile, document.getText());
Charset oldCached = getCachedCharsetFromContent(document);
if (!Comparing.equal(charset, oldCached)) {
document.putUserData(CACHED_CHARSET_FROM_CONTENT, charset);
firePropertyChange(PROP_CACHED_ENCODING_CHANGED, oldCached, charset);
setCachedCharsetFromContent(charset, oldCached, document);
}
}
});
}
private void setCachedCharsetFromContent(Charset charset, Charset oldCached, Document document) {
document.putUserData(CACHED_CHARSET_FROM_CONTENT, charset);
firePropertyChange(PROP_CACHED_ENCODING_CHANGED, oldCached, charset);
}
@Nullable("returns null if charset set cannot be determined from content")
public Charset computeCharsetFromContent(@NotNull final VirtualFile virtualFile) {
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) return null;
final Charset cached = EncodingManager.getInstance().getCachedCharsetFromContent(document);
if (cached != null) return cached;
final Project project = ProjectLocator.getInstance().guessProjectForFile(virtualFile);
return ApplicationManager.getApplication().runReadAction(new Computable<Charset>() {
@Override
public Charset compute() {
Charset charsetFromContent = LoadTextUtil.charsetFromContentOrNull(project, virtualFile, document.getText());
if (charsetFromContent != null) {
setCachedCharsetFromContent(charsetFromContent, cached, document);
}
return charsetFromContent;
}
});
}
@Override
public void dispose() {
updateEncodingFromContent.cancelAllRequests();
@@ -36,8 +36,12 @@ import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
@@ -75,7 +79,10 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
}
};
public EncodingProjectManagerImpl(Project project, GeneralSettings generalSettings, EditorSettingsExternalizable editorSettings, PsiDocumentManager documentManager) {
public EncodingProjectManagerImpl(Project project,
GeneralSettings generalSettings,
EditorSettingsExternalizable editorSettings,
PsiDocumentManager documentManager) {
myProject = project;
myGeneralSettings = generalSettings;
myEditorSettings = editorSettings;
@@ -123,6 +130,7 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
@Override
public void loadState(Element element) {
List<Element> files = element.getChildren("file");
final Map<VirtualFile, Charset> mapping = new HashMap<VirtualFile, Charset>();
for (Element fileElement : files) {
String url = fileElement.getAttributeValue("url");
String charsetName = fileElement.getAttributeValue("charset");
@@ -130,9 +138,23 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
if (charset == null) continue;
VirtualFile file = url.equals("PROJECT") ? null : VirtualFileManager.getInstance().findFileByUrl(url);
if (file != null || url.equals("PROJECT")) {
myMapping.put(file, charset);
mapping.put(file, charset);
}
}
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
if (myProject.isDisposed()) {
// give last chance to save
myMapping.clear();
myMapping.putAll(mapping);
}
else {
setMapping(mapping);
}
}
});
myUseUTFGuessing = Boolean.parseBoolean(element.getAttributeValue("useUTFGuessing"));
myNative2AsciiForPropertiesFiles = Boolean.parseBoolean(element.getAttributeValue("native2AsciiForPropertiesFiles"));
myDefaultCharsetForPropertiesFiles = CharsetToolkit.forName(element.getAttributeValue("defaultCharsetForPropertiesFiles"));
@@ -206,12 +228,11 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
setAndSaveOrReload(virtualFileOrDir, charset);
}
private static void setAndSaveOrReload(final VirtualFile virtualFileOrDir, final Charset charset) {
if (virtualFileOrDir == null || virtualFileOrDir.isDirectory()) {
private static void setAndSaveOrReload(VirtualFile virtualFileOrDir, Charset charset) {
if (virtualFileOrDir == null) {
return;
}
virtualFileOrDir.setCharset(charset);
LoadTextUtil.setCharsetWasDetectedFromBytes(virtualFileOrDir, false);
saveOrReload(virtualFileOrDir);
}
@@ -235,29 +256,44 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
result.addAll(myMapping.values());
result.add(CharsetToolkit.UTF8_CHARSET);
result.add(CharsetToolkit.getDefaultSystemCharset());
result.add(CharsetToolkit.UTF_16_CHARSET);
result.add(CharsetToolkit.forName("ISO-8859-1"));
result.add(CharsetToolkit.forName("US-ASCII"));
result.add(EncodingManager.getInstance().getDefaultCharset());
result.add(EncodingManager.getInstance().getDefaultCharsetForPropertiesFiles(null));
return result;
}
@NotNull
@Override
public Map<VirtualFile, Charset> getAllMappings() {
return myMapping;
}
@Override
public void setMapping(final Map<VirtualFile, Charset> result) {
Map<VirtualFile, Charset> map = new HashMap<VirtualFile, Charset>(result);
//todo return it back as soon as FileIndex get to the platform
//ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
//for (VirtualFile file : result.keySet()) {
// if (file != null && !fileIndex.isInContent(file)) {
// map.remove(file);
// }
//}
public void setMapping(@NotNull final Map<VirtualFile, Charset> result) {
Map<VirtualFile, Charset> map = new HashMap<VirtualFile, Charset>(result.size());
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
for (Map.Entry<VirtualFile, Charset> entry : result.entrySet()) {
VirtualFile virtualFile = entry.getKey();
Charset charset = entry.getValue();
if (virtualFile != null && !fileIndex.isInContent(virtualFile)) {
continue;
}
Pair<Charset, String> check = virtualFile == null || virtualFile.isDirectory() ? null : ChooseFileEncodingAction.checkCanReload(virtualFile);
String failReason = check == null ? null : check.second;
boolean enabled = failReason == null;
if (!enabled) {
continue; // file became autodetected, exclude from explicitly specified
}
map.put(virtualFile, charset);
}
myMapping.clear();
myMapping.putAll(map);
for (VirtualFile virtualFile : map.keySet()) {
Charset charset = map.get(virtualFile);
for (Map.Entry<VirtualFile, Charset> entry : map.entrySet()) {
Charset charset = entry.getValue();
assert charset != null;
VirtualFile virtualFile = entry.getKey();
setAndSaveOrReload(virtualFile, charset);
}
if (!myProject.isDefault()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -18,20 +18,24 @@ package com.intellij.openapi.vfs.encoding;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.impl.status.EncodingActionsPair;
import com.intellij.pom.Navigatable;
/**
* @author cdr
*/
public class ChangeEncodingUpdateGroup extends DefaultActionGroup implements DumbAware {
public class FileChangeEncodingGroup extends DefaultActionGroup implements DumbAware {
private boolean myUpdating;
private final EncodingActionsPair encodingActionsPair = new EncodingActionsPair();
@Override
public void update(final AnActionEvent e) {
public void update(AnActionEvent e) {
if (myUpdating) {
return;
}
@@ -51,12 +55,19 @@ public class ChangeEncodingUpdateGroup extends DefaultActionGroup implements Dum
virtualFile = null;
}
Pair<String, Boolean> result = ChooseFileEncodingAction.update(virtualFile);
Editor editor = e.getData(PlatformDataKeys.EDITOR);
boolean enabled =
encodingActionsPair.areActionsEnabled(null, editor, editor == null ? null : editor.getComponent(), virtualFile, getEventProject(e));
removeAll();
if (enabled) {
addAll(encodingActionsPair.createActionGroup());
}
myUpdating = true;
try {
e.getPresentation().setText(result.getFirst());
e.getPresentation().setText("File encoding");
// updating the enabled state of the action can trigger the menuSelected handler, which updates the action group again
e.getPresentation().setEnabled(result.getSecond());
e.getPresentation().setEnabled(enabled);
}
finally {
myUpdating = false;
@@ -0,0 +1,151 @@
/*
* Copyright 2000-2012 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.vfs.encoding;
import com.intellij.AppTopics;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileListener;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.nio.charset.Charset;
import java.text.MessageFormat;
/**
* @author cdr
*/
public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAware, Condition<Charset> {
protected VirtualFile myFile;
protected String text;
public ReloadFileInOtherEncodingAction() {
text = "Reload in...";
}
@Nullable("null means disabled, otherwise it's the document and the action description")
protected Pair<Document, String> checkEnabled(@NotNull VirtualFile virtualFile) {
String failReason = ChooseFileEncodingAction.checkCanReload(virtualFile).second;
if (failReason != null) return null;
FileDocumentManager documentManager = FileDocumentManager.getInstance();
Document document = documentManager.getDocument(virtualFile);
if (document == null) return null;
Charset charsetFromContent = EncodingManager.getInstance().getCachedCharsetFromContent(document);
Charset charset = charsetFromContent != null ? charsetFromContent : virtualFile.getCharset();
String text = MessageFormat.format("Reload ''{0}''-encoded file ''{1}'' in another encoding", charset.displayName(), virtualFile.getName());
return Pair.create(document, text);
}
@Override
public void update(AnActionEvent e) {
myFile = e.getData(PlatformDataKeys.VIRTUAL_FILE);
Pair<Document, String> pair = myFile == null ? null : checkEnabled(myFile);
e.getPresentation().setEnabled(pair != null);
if (pair != null) {
e.getPresentation().setDescription(pair.second);
e.getPresentation().setText(text);
}
}
@Override
public final void actionPerformed(final AnActionEvent e) {
Pair<Document, String> pair = checkEnabled(myFile);
if (pair == null) return;
final Document document = pair.first;
final Editor editor = e.getData(PlatformDataKeys.EDITOR);
DefaultActionGroup group =
new ChooseFileEncodingAction(myFile) {
@Override
public void update(final AnActionEvent e) {
}
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
return createGroup(null, ReloadFileInOtherEncodingAction.this, "Reload file ''{0}'' in''{1}''", myFile.getCharset()); // no 'clear'
}
@Override
protected void chosen(@Nullable VirtualFile virtualFile, @NotNull Charset charset) {
if (virtualFile != null) {
ReloadFileInOtherEncodingAction.this.chosen(document, editor, virtualFile, charset);
}
}
}
.createPopupActionGroup(null);
final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(
text, group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false);
popup.showInBestPositionFor(e.getDataContext());
}
protected void chosen(@NotNull Document document, Editor editor, @NotNull VirtualFile virtualFile, @NotNull final Charset charset) {
FileDocumentManager documentManager = FileDocumentManager.getInstance();
//Project project = ProjectLocator.getInstance().guessProjectForFile(myFile);
//if (documentManager.isFileModified(myFile)) {
// int result = Messages.showDialog(project, "File is modified. Reload file anyway?", "File is Modified", new String[]{"Reload", "Cancel"}, 0, AllIcons.General.WarningDialog);
// if (result != 0) return;
//}
Disposable disposable = Disposer.newDisposable();
MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(disposable);
connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() {
@Override
public void beforeFileContentReload(VirtualFile file, @NotNull Document document) {
EncodingManager.getInstance().setEncoding(myFile, charset);
myFile.setCharset(charset);
LoadTextUtil.setCharsetWasDetectedFromBytes(myFile, null);
}
});
// if file was modified, the user will be asked here
try {
((VirtualFileListener)documentManager).contentsChanged(new VirtualFileEvent(null, myFile, myFile.getName(), myFile.getParent()));
}
finally {
Disposer.dispose(disposable);
}
}
// charset filter
@Override
public boolean value(Charset charset) {
return true;
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2012 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.wm.impl.status;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.ConvertFileEncodingAction;
import com.intellij.openapi.vfs.encoding.ReloadFileInOtherEncodingAction;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.awt.event.InputEvent;
public class EncodingActionsPair {
private final ConvertFileEncodingAction convert = new ConvertFileEncodingAction();
private final ReloadFileInOtherEncodingAction reload = new ReloadFileInOtherEncodingAction();
public boolean areActionsEnabled(InputEvent e,Editor editor, Component component, VirtualFile selectedFile, Project project) {
DataContext dataContext = createDataContext(editor, component, selectedFile, project);
convert.update(new AnActionEvent(e, dataContext, "", convert.getTemplatePresentation(), ActionManager.getInstance(), 0));
reload.update(new AnActionEvent(e, dataContext, "", reload.getTemplatePresentation(), ActionManager.getInstance(), 0));
return convert.getTemplatePresentation().isEnabled() || reload.getTemplatePresentation().isEnabled();
}
@NotNull
public static DataContext createDataContext(Editor editor, Component component, VirtualFile selectedFile, Project project) {
DataContext parent = DataManager.getInstance().getDataContext(component);
return SimpleDataContext.getSimpleContext(PlatformDataKeys.VIRTUAL_FILE.getName(), selectedFile,
SimpleDataContext.getSimpleContext(PlatformDataKeys.PROJECT.getName(), project,
SimpleDataContext.getSimpleContext(PlatformDataKeys.CONTEXT_COMPONENT.getName(), editor == null ? null : editor.getComponent(),
parent)));
}
public DefaultActionGroup createActionGroup() {
DefaultActionGroup group = new DefaultActionGroup();
group.add(convert);
group.add(reload);
return group;
}
}
@@ -17,7 +17,9 @@ package com.intellij.openapi.wm.impl.status;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
@@ -25,6 +27,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.project.Project;
@@ -47,7 +50,9 @@ import com.intellij.ui.ClickListener;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Alarm;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -66,7 +71,7 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
public EncodingPanel(@NotNull final Project project) {
super(project);
myComponent = new TextPanel(getMaxValue()){
myComponent = new TextPanel(getMaxValue()) {
@Override
protected void paintComponent(@NotNull final Graphics g) {
super.paintComponent(g);
@@ -78,6 +83,7 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
}
}
};
new ClickListener() {
@Override
public boolean onClick(MouseEvent e, int clickCount) {
@@ -89,6 +95,15 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
myComponent.setBorder(WidgetBorder.INSTANCE);
}
@Nullable("returns null if charset set cannot be determined from content")
private static Charset cachedCharsetFromContent(final VirtualFile virtualFile) {
if (virtualFile == null) return null;
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) return null;
return EncodingManager.getInstance().getCachedCharsetFromContent(document);
}
@Override
public void selectionChanged(FileEditorManagerEvent event) {
if (ApplicationManager.getApplication().isUnitTestMode()) return;
@@ -105,15 +120,18 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
return new EncodingPanel(getProject());
}
@Override
@NotNull
public String ID() {
return "Encoding";
}
@Override
public WidgetPresentation getPresentation(@NotNull PlatformType type) {
return null;
}
@NonNls
@NotNull
private static String getMaxValue() {
return "windows-1251";
@@ -157,59 +175,49 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
}, this);
}
private final EncodingActionsPair encodingActionsPair = new EncodingActionsPair();
private void showPopup(MouseEvent e) {
ListPopup popup = getPopupStep();
if (popup == null) return;
final Dimension dimension = popup.getContent().getPreferredSize();
final Point at = new Point(0, -dimension.height);
if (!actionEnabled) {
return;
}
DataContext dataContext = getContext();
DefaultActionGroup group = encodingActionsPair.createActionGroup();
ListPopup popup =
JBPopupFactory.getInstance().createActionGroupPopup("File Encoding", group, dataContext, true, false, false, null, 2, null);
Dimension dimension = popup.getContent().getPreferredSize();
Point at = new Point(0, -dimension.height);
popup.show(new RelativePoint(e.getComponent(), at));
Disposer.register(this, popup); // do not forget to destroy popup on unexpected project close
Disposer.register(this, popup); // destroy popup on unexpected project close
}
private ListPopup getPopupStep() {
Pair<String,Boolean> result = ChooseFileEncodingAction.update(getSelectedFile());
boolean enabled = result.second;
final DataContext parent = DataManager.getInstance().getDataContext((Component)myStatusBar);
final DataContext dataContext =
SimpleDataContext.getSimpleContext(PlatformDataKeys.VIRTUAL_FILE.getName(), getSelectedFile(),
SimpleDataContext.getSimpleContext(PlatformDataKeys.PROJECT.getName(), getProject(), parent));
if (!enabled) {
return null;
}
DefaultActionGroup group = new ChooseFileEncodingAction(getSelectedFile()) {
@Override
protected void chosen(VirtualFile virtualFile, @NotNull Charset charset) {
if (virtualFile != null) {
EncodingManager.getInstance().setEncoding(virtualFile, charset);
update(new AnActionEvent(null, dataContext, ActionPlaces.EDITOR_TOOLBAR, getTemplatePresentation(), ActionManager.getInstance(), 0));
EncodingPanel.this.update();
}
}
}.createGroup(null);
return JBPopupFactory.getInstance().createActionGroupPopup(null, group, dataContext, false, false, false, null, 30, null);
@NotNull
private DataContext getContext() {
Editor editor = getEditor();
DataContext parent = DataManager.getInstance().getDataContext((Component)myStatusBar);
return SimpleDataContext.getSimpleContext(PlatformDataKeys.VIRTUAL_FILE.getName(), getSelectedFile(),
SimpleDataContext.getSimpleContext(PlatformDataKeys.PROJECT.getName(), getProject(),
SimpleDataContext.getSimpleContext(PlatformDataKeys.CONTEXT_COMPONENT.getName(), editor == null ? null : editor.getComponent(), parent)
));
}
private void update() {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
final VirtualFile file = getSelectedFile();
Pair<String, Boolean> result = ChooseFileEncodingAction.update(file);
String text;
String toolTip;
if (file != null) {
Charset charset = ChooseFileEncodingAction.cachedCharsetFromContent(file);
if (charset == null) charset = file.getCharset();
VirtualFile file = getSelectedFile();
Charset charset = cachedCharsetFromContent(file);
if (charset == null && file != null) charset = file.getCharset();
text = charset.displayName();
actionEnabled = result.second;
toolTip = result.first;
}
else {
text = "";
actionEnabled = false;
toolTip = "";
}
String text = charset == null ? "" : charset.displayName();
actionEnabled = encodingActionsPair.areActionsEnabled(null,getEditor(), (Component)myStatusBar, file, getProject());
Pair<Charset,String> check = file == null ? null : ChooseFileEncodingAction.checkCanReload(file);
String failReason = check == null ? null : check.second;
String toolTip = "File Encoding" +
(check == null || check.first == null ? "" : ": "+check.first.displayName()) +
(actionEnabled || failReason == null ? "" : " (change disabled: " + failReason + ")");
myComponent.setToolTipText(toolTip);
myComponent.setText(text);
@@ -90,7 +90,7 @@ public class NewDirectoryProjectAction extends AnAction implements DumbAware {
return null;
}
}
GeneralSettings.getInstance().setLastProjectLocation(location.getParent());
GeneralSettings.getInstance().setLastProjectCreationLocation(location.getParent());
final Object finalSettings = settings;
return PlatformProjectOpenProcessor.doOpenProject(baseDir, null, false, -1, new ProjectOpenedCallback() {
@Override
@@ -18,15 +18,13 @@ package com.intellij.platform;
import com.intellij.facet.ui.FacetEditorValidator;
import com.intellij.facet.ui.FacetValidatorsManager;
import com.intellij.facet.ui.ValidationResult;
import com.intellij.ide.GeneralSettings;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -36,7 +34,6 @@ import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;
/**
@@ -66,7 +63,7 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
myLocationLabel.setLabelFor(myLocationField.getChildComponent());
new LocationNameFieldsBinding(project, myLocationField, myProjectNameTextField, getBaseDir(), "Select Location for Project Directory");
new LocationNameFieldsBinding(project, myLocationField, myProjectNameTextField, ProjectUtil.getBaseDir(), "Select Location for Project Directory");
final DirectoryProjectGenerator[] generators = getGenerators();
if (generators.length == 0) {
@@ -217,17 +214,6 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
});
}
public static String getBaseDir() {
final String lastProjectLocation = GeneralSettings.getInstance().getLastProjectLocation();
if (lastProjectLocation != null) {
return lastProjectLocation.replace('/', File.separatorChar);
}
final String userHome = SystemProperties.getUserHome();
//noinspection HardCodedStringLiteral
return userHome.replace('/', File.separatorChar) + File.separator + ApplicationNamesInfo.getInstance().getLowercaseProductName() +
"Projects";
}
protected JComponent createCenterPanel() {
return myRootPane;
}
@@ -199,9 +199,16 @@ public class PopupFactoryImpl extends JBPopupFactory {
private final Runnable myDisposeCallback;
private final Component myComponent;
public ActionGroupPopup(final String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext,
boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions, boolean honorActionMnemonics,
final Runnable disposeCallback, final int maxRowCount, final Condition<AnAction> preselectActionCondition,
public ActionGroupPopup(final String title,
@NotNull ActionGroup actionGroup,
@NotNull DataContext dataContext,
boolean showNumbers,
boolean useAlphaAsNumbers,
boolean showDisabledActions,
boolean honorActionMnemonics,
final Runnable disposeCallback,
final int maxRowCount,
final Condition<AnAction> preselectActionCondition,
@Nullable final String actionPlace) {
super(createStep(title, actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics,
preselectActionCondition, actionPlace),
@@ -226,10 +233,15 @@ public class PopupFactoryImpl extends JBPopupFactory {
});
}
private static ListPopupStep createStep(String title, @NotNull ActionGroup actionGroup, @NotNull DataContext dataContext,
boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions,
private static ListPopupStep createStep(String title,
@NotNull ActionGroup actionGroup,
@NotNull DataContext dataContext,
boolean showNumbers,
boolean useAlphaAsNumbers,
boolean showDisabledActions,
boolean honorActionMnemonics,
Condition<AnAction> preselectActionCondition, @Nullable String actionPlace) {
Condition<AnAction> preselectActionCondition,
@Nullable String actionPlace) {
final Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext);
final ActionStepBuilder builder =
@@ -347,8 +359,9 @@ public class PopupFactoryImpl extends JBPopupFactory {
}, autoSelectionEnabled, showDisabledActions);
}
@NotNull
private static List<ActionItem> makeActionItemsFromActionGroup(@NotNull ActionGroup actionGroup,
DataContext dataContext,
@NotNull DataContext dataContext,
boolean showNumbers,
boolean useAlphaAsNumbers,
boolean showDisabledActions,
@@ -359,6 +372,7 @@ public class PopupFactoryImpl extends JBPopupFactory {
return builder.getItems();
}
@NotNull
private static ListPopupStep createActionsStep(@NotNull ActionGroup actionGroup, @NotNull DataContext dataContext,
boolean showNumbers, boolean useAlphaAsNumbers, boolean showDisabledActions,
String title, Component component, boolean honorActionMnemonics,
@@ -815,6 +829,7 @@ public class PopupFactoryImpl extends JBPopupFactory {
myActionPlace = actionPlace;
}
@NotNull
public List<ActionItem> getItems() {
return myListModel;
}
@@ -831,8 +846,7 @@ public class PopupFactoryImpl extends JBPopupFactory {
}
private void calcMaxIconSize(final ActionGroup actionGroup) {
AnAction[] actions = actionGroup.getChildren(new AnActionEvent(null, myDataContext, myActionPlace,
getPresentation(actionGroup), ActionManager.getInstance(), 0));
AnAction[] actions = actionGroup.getChildren(createActionEvent(actionGroup));
for (AnAction action : actions) {
if (action == null) continue;
if (action instanceof ActionGroup) {
@@ -857,9 +871,13 @@ public class PopupFactoryImpl extends JBPopupFactory {
}
}
@NotNull
private AnActionEvent createActionEvent(@NotNull AnAction actionGroup) {
return new AnActionEvent(null, myDataContext, myActionPlace, getPresentation(actionGroup), ActionManager.getInstance(), 0);
}
private void appendActionsFromGroup(@NotNull ActionGroup actionGroup) {
AnAction[] actions = actionGroup.getChildren(new AnActionEvent(null, myDataContext, myActionPlace,
getPresentation(actionGroup), ActionManager.getInstance(), 0));
AnAction[] actions = actionGroup.getChildren(createActionEvent(actionGroup));
for (AnAction action : actions) {
if (action == null) {
LOG.error("null action in group " + actionGroup);
@@ -888,7 +906,7 @@ public class PopupFactoryImpl extends JBPopupFactory {
private void appendAction(@NotNull AnAction action) {
Presentation presentation = getPresentation(action);
AnActionEvent event = new AnActionEvent(null, myDataContext, myActionPlace, presentation, ActionManager.getInstance(), 0);
AnActionEvent event = createActionEvent(action);
ActionUtil.performDumbAwareUpdate(action, event, true);
if ((myShowDisabled || presentation.isEnabled()) && presentation.isVisible()) {
@@ -25,8 +25,6 @@ import javax.swing.*;
import java.awt.*;
public class GroupedItemsListRenderer extends GroupedElementsRenderer.List implements ListCellRenderer {
protected ListItemDescriptor myDescriptor;
protected JLabel myNextStepLabel;
@@ -40,20 +38,22 @@ public class GroupedItemsListRenderer extends GroupedElementsRenderer.List imple
myDescriptor = descriptor;
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
String caption = myDescriptor.getCaptionAboveOf(value);
boolean hasSeparator = myDescriptor.hasSeparatorAboveOf(value);
if (index == 0 && StringUtil.isEmptyOrSpaces(caption)) hasSeparator = false;
Icon icon = myDescriptor.getIconFor(value);
final JComponent result = configureComponent(myDescriptor.getTextFor(value), myDescriptor.getTooltipFor(value),
myDescriptor.getIconFor(value), myDescriptor.getIconFor(value), isSelected, hasSeparator,
icon, icon, isSelected, hasSeparator,
caption, -1);
customizeComponent(list, value, isSelected);
return result;
}
@Override
protected JComponent createItemComponent() {
myTextLabel = new ErrorLabel();
myTextLabel.setOpaque(true);
@@ -28,22 +28,27 @@ public class PopupListElementRenderer extends GroupedItemsListRenderer {
public PopupListElementRenderer(final ListPopupImpl aPopup) {
super(new ListItemDescriptor() {
@Override
public String getTextFor(Object value) {
return aPopup.getListStep().getTextFor(value);
}
@Override
public String getTooltipFor(Object value) {
return null;
}
@Override
public Icon getIconFor(Object value) {
return aPopup.getListStep().getIconFor(value);
}
@Override
public boolean hasSeparatorAboveOf(Object value) {
return aPopup.getListModel().isSeparatorAboveOf(value);
}
@Override
public String getCaptionAboveOf(Object value) {
return aPopup.getListModel().getCaptionAboveOf(value);
}
@@ -51,6 +56,7 @@ public class PopupListElementRenderer extends GroupedItemsListRenderer {
myPopup = aPopup;
}
@Override
protected void customizeComponent(JList list, Object value, boolean isSelected) {
ListPopupStep<Object> step = myPopup.getListStep();
boolean isSelectable = step.isSelectable(value);
@@ -232,6 +232,7 @@ public class WebServer {
}
if (tryAnyPort) {
LOG.info("We cannot bind to our default range, so, try to bind to any free port");
try {
Channel channel = bootstrap.bind(new InetSocketAddress(0));
openChannels.add(channel);
@@ -1043,7 +1043,7 @@ finished.with.exit.code.text.message=Process finished with exit code {0}
# Encodings
file.encodings.configurable=File Encodings
file.encodings.not.configured=Encodings are not configured
encodings.dialog.caption=<html>To change encoding $productName uses for a file, directory, or an entire project, click an item and then select encoding from the Default Encoding list.<br>Notes\:<br>Built-in file encoding (e.g. JSP, HTML or XML) overrides encoding you specify here. If not specified, files and directories inherit encoding settings from parent.</html>
encodings.dialog.caption=<html>To change encoding $productName uses for a file or directory, click an item and then select encoding from the Default Encoding list.<br><br>Built-in file encoding (e.g. JSP, HTML or XML) overrides encoding you specify here.<br>If not specified, files and directories inherit encoding settings from the parent.</html>
encoding.name.system.default=<System Default>
quick.lists.presentable.name=Quick lists
@@ -161,8 +161,7 @@
<action id="Synchronize" class="com.intellij.ide.actions.SynchronizeAction" icon="AllIcons.Actions.Refresh"/>
<action id="InvalidateCaches" class="com.intellij.ide.actions.InvalidateCachesAction"/>
<group id="ChangeFileEncodingGroup" popup="true" class="com.intellij.openapi.vfs.encoding.ChangeEncodingUpdateGroup">
<action id="ChangeFileEncodingGroupAction" class="com.intellij.openapi.vfs.encoding.ChangeFileEncodingGroup" text=""/>
<group id="ChangeFileEncodingGroup" popup="true" class="com.intellij.openapi.vfs.encoding.FileChangeEncodingGroup">
</group>
<action id="ToggleReadOnlyAttribute" class="com.intellij.ide.actions.ToggleReadOnlyAttributeAction"/>
<separator/>
@@ -54,7 +54,7 @@ public class Splitter extends JPanel {
private final float myMaxProp;
protected float myProportion;
protected float myProportion;// first size divided by total size
private final Divider myDivider;
private JComponent mySecondComponent;
@@ -177,7 +177,7 @@ public class Splitter extends JPanel {
if (myFirstComponent != null && myFirstComponent.isVisible() && mySecondComponent != null && mySecondComponent.isVisible()) {
final Dimension firstMinSize = myFirstComponent.getMinimumSize();
final Dimension secondMinSize = mySecondComponent.getMinimumSize();
return getOrientation()
return isVertical()
? new Dimension(Math.max(firstMinSize.width, secondMinSize.width), firstMinSize.height + dividerWidth + secondMinSize.height)
: new Dimension(firstMinSize.width + dividerWidth + secondMinSize.width, Math.max(firstMinSize.height, secondMinSize.height));
}
@@ -199,7 +199,7 @@ public class Splitter extends JPanel {
if (myFirstComponent != null && myFirstComponent.isVisible() && mySecondComponent != null && mySecondComponent.isVisible()) {
final Dimension firstPrefSize = myFirstComponent.getPreferredSize();
final Dimension secondPrefSize = mySecondComponent.getPreferredSize();
return getOrientation()
return isVertical()
? new Dimension(Math.max(firstPrefSize.width, secondPrefSize.width),
firstPrefSize.height + dividerWidth + secondPrefSize.height)
: new Dimension(firstPrefSize.width + dividerWidth + secondPrefSize.width,
@@ -225,11 +225,11 @@ public class Splitter extends JPanel {
mySkipNextLayouting = false;
return;
}
final double width = getWidth();
final double height = getHeight();
int width = getWidth();
int height = getHeight();
final double componentSize = getOrientation() ? height : width;
if (componentSize <= 0) return;
int total = isVertical() ? height : width;
if (total <= 0) return;
if (!isNull(myFirstComponent) && myFirstComponent.isVisible() && !isNull(mySecondComponent) && mySecondComponent.isVisible()) {
// both first and second components are visible
@@ -237,64 +237,52 @@ public class Splitter extends JPanel {
Rectangle dividerRect = new Rectangle();
Rectangle secondRect = new Rectangle();
double dividerWidth = getDividerWidth();
double firstComponentSize;
double secondComponentSize;
int d = getDividerWidth();
double size1;
if (componentSize <= dividerWidth) {
firstComponentSize = 0;
secondComponentSize = 0;
dividerWidth = componentSize;
if (total <= d) {
size1 = 0;
d = total;
}
else {
firstComponentSize = myProportion * (float)(componentSize - dividerWidth);
secondComponentSize = getOrientation() ? height - firstComponentSize - dividerWidth : width - firstComponentSize - dividerWidth;
size1 = myProportion * total;
double size2 = total - size1 - d;
if (isHonorMinimumSize()) {
final double firstMinSize =
getOrientation() ? myFirstComponent.getMinimumSize().getHeight() : myFirstComponent.getMinimumSize().getWidth();
final double secondMinSize =
getOrientation() ? mySecondComponent.getMinimumSize().getHeight() : mySecondComponent.getMinimumSize().getWidth();
double mSize1 = isVertical() ? myFirstComponent.getMinimumSize().getHeight() : myFirstComponent.getMinimumSize().getWidth();
double mSize2 = isVertical() ? mySecondComponent.getMinimumSize().getHeight() : mySecondComponent.getMinimumSize().getWidth();
if (firstComponentSize + secondComponentSize < firstMinSize + secondMinSize) {
double proportion = firstMinSize / (firstMinSize + secondMinSize);
firstComponentSize = (int)(proportion * (float)(componentSize - dividerWidth));
secondComponentSize = getOrientation() ? height - firstComponentSize - dividerWidth : width - firstComponentSize - dividerWidth;
if (size1 + size2 < mSize1 + mSize2) {
double proportion = mSize1 / (mSize1 + mSize2);
size1 = proportion * total;
}
else {
if (firstComponentSize < firstMinSize) {
secondComponentSize -= firstMinSize - firstComponentSize;
firstComponentSize = firstMinSize;
if (size1 < mSize1) {
size1 = mSize1;
}
else if (secondComponentSize < secondMinSize) {
firstComponentSize -= secondMinSize - secondComponentSize;
secondComponentSize = secondMinSize;
else if (size2 < mSize2) {
size2 = mSize2;
size1 = total - size2 - d;
}
}
}
}
myProportion = (float)(firstComponentSize / (firstComponentSize + secondComponentSize));
myProportion = (float)(size1 / total);
firstComponentSize = Math.floor(firstComponentSize);
secondComponentSize = Math.floor(secondComponentSize);
int iSize1 = (int)Math.round(Math.floor(size1));
int iSize2 = (int)Math.round(total - size1 - d);
if (getOrientation()) {
// fix flooring
secondComponentSize += (int)(height - firstComponentSize - secondComponentSize - dividerWidth);
firstRect.setBounds(0, 0, (int)width, (int)firstComponentSize);
dividerRect.setBounds(0, (int)firstComponentSize, (int)width, (int)dividerWidth);
secondRect.setBounds(0, (int)(firstComponentSize + dividerWidth), (int)width, (int)secondComponentSize);
if (isVertical()) {
firstRect.setBounds(0, 0, width, iSize1);
dividerRect.setBounds(0, iSize1, width, d);
secondRect.setBounds(0, iSize1 + d, width, iSize2);
}
else {
// fix flooring
secondComponentSize += (int)(width - firstComponentSize - secondComponentSize - dividerWidth);
firstRect.setBounds(0, 0, (int)firstComponentSize, (int)height);
dividerRect.setBounds((int)firstComponentSize, 0, (int)dividerWidth, (int)height);
secondRect.setBounds((int)(firstComponentSize + dividerWidth), 0, (int)secondComponentSize, (int)height);
firstRect.setBounds(0, 0, iSize1, height);
dividerRect.setBounds(iSize1, 0, d, height);
secondRect.setBounds((iSize1 + d), 0, iSize2, height);
}
myDivider.setVisible(true);
myFirstComponent.setBounds(firstRect);
@@ -306,13 +294,13 @@ public class Splitter extends JPanel {
else if (!isNull(myFirstComponent) && myFirstComponent.isVisible()) { // only first component is visible
hideNull(mySecondComponent);
myDivider.setVisible(false);
myFirstComponent.setBounds(0, 0, (int)width, (int)height);
myFirstComponent.setBounds(0, 0, width, height);
myFirstComponent.revalidate();
}
else if (!isNull(mySecondComponent) && mySecondComponent.isVisible()) { // only second component is visible
hideNull(myFirstComponent);
myDivider.setVisible(false);
mySecondComponent.setBounds(0, 0, (int)width, (int)height);
mySecondComponent.setBounds(0, 0, width, height);
mySecondComponent.revalidate();
}
else { // both components are null or invisible
@@ -401,6 +389,13 @@ public class Splitter extends JPanel {
return myVerticalSplit;
}
/**
* @return true if |-|
*/
public boolean isVertical() {
return myVerticalSplit;
}
/**
* @param verticalSplit <code>true</code> means that splitter will have vertical split
*/
@@ -486,7 +481,7 @@ public class Splitter extends JPanel {
private void setOrientation(boolean isVerticalSplit) {
removeAll();
setCursor(getOrientation() ?
setCursor(isVertical() ?
Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) :
Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
@@ -570,7 +565,7 @@ public class Splitter extends JPanel {
if (MouseEvent.MOUSE_DRAGGED == e.getID()) {
myPoint = SwingUtilities.convertPoint(this, e.getPoint(), Splitter.this);
float proportion;
if (getOrientation()) {
if (isVertical()) {
if (getHeight() > 0) {
proportion = Math.min(1.0f, Math.max(.0f, Math
.min(Math.max(getMinProportion(myFirstComponent), (float)myPoint.y / (float)Splitter.this.getHeight()),
@@ -593,7 +588,7 @@ public class Splitter extends JPanel {
if (isHonorMinimumSize()) {
if (component != null && myFirstComponent != null && myFirstComponent.isVisible() && mySecondComponent != null &&
mySecondComponent.isVisible()) {
if (getOrientation()) {
if (isVertical()) {
return (float)component.getMinimumSize().height / (float)(Splitter.this.getHeight() - getDividerWidth());
}
else {
@@ -623,7 +618,7 @@ public class Splitter extends JPanel {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
else {
setCursor(getOrientation() ?
setCursor(isVertical() ?
Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR) :
Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
}
@@ -43,7 +43,7 @@ import static com.intellij.util.BitUtil.notSet;
* @version 11.1
*/
public class FileSystemUtil {
public static final String FORCE_USE_NIO2_KEY = "idea.io.use.nio2";
private static final String FORCE_USE_NIO2_KEY = "idea.io.use.nio2";
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileSystemUtil");
@@ -22,7 +22,7 @@ import java.awt.*;
/**
* @author Konstantin Bulenkov
*/
@SuppressWarnings("InspectionUsingJBColors")
@SuppressWarnings("UseJBColor")
public class JBColor extends Color {
public JBColor(int rgb, int darkRGB) {
super(isDark() ? darkRGB : rgb);
@@ -437,21 +437,21 @@ public class ArrayUtil extends ArrayUtilRt {
return indexOf(src, obj);
}
public static boolean startsWith(byte[] array, byte[] subArray) {
if (array == subArray) {
public static boolean startsWith(byte[] array, byte[] prefix) {
if (array == prefix) {
return true;
}
if (array == null || subArray == null) {
if (array == null || prefix == null) {
return false;
}
int length = subArray.length;
int length = prefix.length;
if (array.length < length) {
return false;
}
for (int i = 0; i < length; i++) {
if (array[i] != subArray[i]) {
if (array[i] != prefix[i]) {
return false;
}
}
@@ -96,7 +96,7 @@ public class PagedFileStorage implements Forceable {
}
private final byte[] myTypedIOBuffer;
private boolean isDirty = false;
private volatile boolean isDirty = false;
private final File myFile;
protected long mySize = -1;
protected final int myPageSize;
@@ -125,7 +125,6 @@ public class PagedFileStorage implements Forceable {
public void putInt(int addr, int value) {
if (myValuesAreBufferAligned) {
isDirty = true;
int page = addr / myPageSize;
int page_offset = addr % myPageSize;
getBuffer(page).putInt(page_offset, value);
@@ -148,7 +147,6 @@ public class PagedFileStorage implements Forceable {
public final void putShort(int addr, short value) {
if (myValuesAreBufferAligned) {
isDirty = true;
int page = addr / myPageSize;
int page_offset = addr % myPageSize;
getBuffer(page).putShort(page_offset, value);
@@ -179,7 +177,6 @@ public class PagedFileStorage implements Forceable {
public void putLong(int addr, long value) {
if (myValuesAreBufferAligned) {
isDirty = true;
int page = addr / myPageSize;
int page_offset = addr % myPageSize;
getBuffer(page).putLong(page_offset, value);
@@ -217,7 +214,6 @@ public class PagedFileStorage implements Forceable {
}
public void put(int index, byte value) {
isDirty = true;
int page = index / myPageSize;
int offset = index % myPageSize;
@@ -254,7 +250,6 @@ public class PagedFileStorage implements Forceable {
}
public void put(int index, byte[] src, int offset, int length) {
isDirty = true;
int i = index;
int o = offset;
int l = length;
@@ -364,19 +359,19 @@ public class PagedFileStorage implements Forceable {
if (myLastPage == page) {
ByteBuffer buf = myLastBuffer.getCachedBuffer();
if (buf != null && myLastChangeCount == myStorageLockContext.myStorageLock.myMappingChangeCount) {
if (modify) myLastBuffer.markDirty();
if (modify) markDirty(myLastBuffer);
return buf;
}
} else if (myLastPage2 == page) {
ByteBuffer buf = myLastBuffer2.getCachedBuffer();
if (buf != null && myLastChangeCount2 == myStorageLockContext.myStorageLock.myMappingChangeCount) {
if (modify) myLastBuffer2.markDirty();
if (modify) markDirty(myLastBuffer2);
return buf;
}
} else if (myLastPage3 == page) {
ByteBuffer buf = myLastBuffer3.getCachedBuffer();
if (buf != null && myLastChangeCount3 == myStorageLockContext.myStorageLock.myMappingChangeCount) {
if (modify) myLastBuffer3.markDirty();
if (modify) markDirty(myLastBuffer3);
return buf;
}
}
@@ -388,7 +383,7 @@ public class PagedFileStorage implements Forceable {
myStorageIndex = myStorageLockContext.myStorageLock.registerPagedFileStorage(this);
}
ByteBufferWrapper byteBufferWrapper = myStorageLockContext.myStorageLock.get(myStorageIndex | page);
if (modify) byteBufferWrapper.markDirty();
if (modify) markDirty(byteBufferWrapper);
ByteBuffer buf = byteBufferWrapper.getBuffer();
if (myLastPage != page) {
@@ -415,6 +410,11 @@ public class PagedFileStorage implements Forceable {
}
}
private void markDirty(ByteBufferWrapper buffer) {
if (!isDirty) isDirty = true;
buffer.markDirty();
}
public void force() {
long started = IOStatistics.DEBUG ? System.currentTimeMillis():0;
if (isDirty) {
@@ -20,10 +20,7 @@ import junit.framework.TestCase;
import javax.swing.*;
import java.awt.*;
import com.intellij.util.concurrency.Semaphore;
public class SplitterTest extends TestCase{
private static final int RATHER_LATER_INVOKES = 10;
public void testResizeVert() {
resizeTest(new Splitter(true));
@@ -43,44 +40,51 @@ public class SplitterTest extends TestCase{
splitter.setHonorComponentsMinimumSize(true);
// disabled since honoring min size is rather confusing, reasonable min size is hardcoded instead
//splitter.setSize(new Dimension(500, 500));
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setSize(new Dimension(300, 300));
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setProportion(.1f);
//splitter.doLayout();
//checkBounds(splitter);
//
////assertTrue(Math.abs(splitter.getProportion() - jPanel1.getMinimumSize().height / (splitter.getSize().height - splitter.getDividerWidth())) < .00001);
//
//splitter.setProportion(.9f);
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setSize(new Dimension(100, 100));
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setProportion(.1f);
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setSize(new Dimension(10, 10));
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setSize(new Dimension(100, 100));
//splitter.doLayout();
//checkBounds(splitter);
//
//splitter.setSize(new Dimension(150, 150));
//splitter.doLayout();
//checkBounds(splitter);
splitter.setSize(new Dimension(500, 500));
splitter.doLayout();
checkBounds(splitter);
splitter.setSize(new Dimension(300, 300));
splitter.doLayout();
checkBounds(splitter);
splitter.setProportion(.1f);
splitter.doLayout();
checkBounds(splitter);
splitter.setProportion(.9f);
splitter.doLayout();
checkBounds(splitter);
splitter.setSize(new Dimension(100, 100));
splitter.doLayout();
checkBounds(splitter);
splitter.setProportion(.1f);
splitter.doLayout();
checkBounds(splitter);
splitter.setSize(new Dimension(10, 10));
splitter.doLayout();
checkBounds(splitter);
splitter.setSize(new Dimension(100, 100));
splitter.doLayout();
checkBounds(splitter);
splitter.setSize(new Dimension(150, 150));
splitter.doLayout();
checkBounds(splitter);
splitter.setSize(splitter.isVertical() ? new Dimension(150, 1000) : new Dimension(1000, 150));
for (float f = .01F; f < 1F; f+=.01F) {
splitter.setProportion(f);
splitter.doLayout();
float proportion = splitter.getProportion();
assertTrue (proportion>=.1 && proportion<=9);
if (f>=.1 && f<=.89)
assertEquals(f, proportion, 1e-4);
}
}
@@ -107,24 +111,4 @@ public class SplitterTest extends TestCase{
assertTrue(firstSize.height < firstMinimum.height == secondSize.height < secondMinimum.height);
}
}
private void invokeRatherLater(final Runnable runnable) {
invokeRatherLater(runnable, RATHER_LATER_INVOKES);
}
private void invokeRatherLater(final Runnable runnable, final int n) {
if(n == 0) {
runnable.run();
}
else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
invokeRatherLater(runnable, n - 1);
}
});
}
}
}
@@ -19,22 +19,36 @@ import com.intellij.openapi.util.SystemInfo;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.lang.reflect.Field;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
public class FileAttributesNio2ReadingTest extends FileAttributesReadingTest {
private static final String FORCE_USE_NIO_2_KEY;
static {
try {
Field field = FileSystemUtil.class.getDeclaredField("FORCE_USE_NIO2_KEY");
field.setAccessible(true);
FORCE_USE_NIO_2_KEY = (String)field.get(null);
}
catch (Exception e) {
throw new AssertionError("Please keep constants in sync: " + e.getMessage());
}
}
@BeforeClass
public static void setUpClass() throws Exception {
assumeTrue(SystemInfo.isJavaVersionAtLeast("1.7"));
System.setProperty(FileSystemUtil.FORCE_USE_NIO2_KEY, "true");
System.setProperty(FORCE_USE_NIO_2_KEY, "true");
FileSystemUtil.resetMediator();
assertEquals("NIO2", FileSystemUtil.getMediatorName());
}
@AfterClass
public static void tearDownClass() throws Exception {
System.setProperty(FileSystemUtil.FORCE_USE_NIO2_KEY, "");
System.setProperty(FORCE_USE_NIO_2_KEY, "");
FileSystemUtil.resetMediator();
}
}
@@ -188,8 +188,12 @@ public class PointlessBooleanExpressionInspection extends BaseInspection {
private void buildSimplifiedExpression(List<PsiExpression> expressions, String token, boolean negate, StringBuilder out) {
if (expressions.size() == 1) {
final PsiExpression expression = expressions.get(0);
final String expressionText = expression.getText();
if (isBoxedTypeComparison(token, expression)) {
out.append(expressionText).append(" != null && ");
}
if (!negate) {
out.append(expression.getText());
out.append(expressionText);
return;
}
if (ComparisonUtils.isComparison(expression)) {
@@ -202,10 +206,10 @@ public class PointlessBooleanExpressionInspection extends BaseInspection {
}
else {
if (ParenthesesUtils.getPrecedence(expression) > ParenthesesUtils.PREFIX_PRECEDENCE) {
out.append("!(").append(expression.getText()).append(')');
out.append("!(").append(expressionText).append(')');
}
else {
out.append('!').append(expression.getText());
out.append('!').append(expressionText);
}
}
}
@@ -229,6 +233,10 @@ public class PointlessBooleanExpressionInspection extends BaseInspection {
}
}
private static boolean isBoxedTypeComparison(String token, PsiExpression expression) {
return ("==".equals(token) || "!=".equals(token)) && expression instanceof PsiReferenceExpression && expression.getType() instanceof PsiClassType;
}
private void buildSimplifiedPrefixExpression(PsiPrefixExpression expression, StringBuilder out) {
final PsiJavaToken sign = expression.getOperationSign();
final IElementType tokenType = sign.getTokenType();
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,12 +18,15 @@ package com.siyeh.ig.jdk;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -31,14 +34,12 @@ public class ForeachStatementInspection extends BaseInspection {
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"extended.for.statement.display.name");
return InspectionGadgetsBundle.message("extended.for.statement.display.name");
}
@NotNull
public String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"extended.for.statement.problem.descriptor");
return InspectionGadgetsBundle.message("extended.for.statement.problem.descriptor");
}
protected InspectionGadgetsFix buildFix(Object... infos) {
@@ -49,85 +50,62 @@ public class ForeachStatementInspection extends BaseInspection {
@NotNull
public String getName() {
return InspectionGadgetsBundle.message(
"extended.for.statement.replace.quickfix");
return InspectionGadgetsBundle.message("extended.for.statement.replace.quickfix");
}
public void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
final PsiElement element = descriptor.getPsiElement();
final PsiForeachStatement statement =
(PsiForeachStatement)element.getParent();
final JavaCodeStyleManager codeStyleManager =
JavaCodeStyleManager.getInstance(project);
final PsiForeachStatement statement = (PsiForeachStatement)element.getParent();
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
assert statement != null;
final PsiExpression iteratedValue = statement.getIteratedValue();
if (iteratedValue == null) {
return;
}
@NonNls final StringBuffer newStatement = new StringBuffer();
final PsiParameter iterationParameter =
statement.getIterationParameter();
@NonNls final StringBuilder newStatement = new StringBuilder();
final PsiParameter iterationParameter = statement.getIterationParameter();
final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(project);
if (iteratedValue.getType() instanceof PsiArrayType) {
final PsiType type = iterationParameter.getType();
final String index =
codeStyleManager.suggestUniqueVariableName("i",
statement, true);
newStatement.append("for(int ");
newStatement.append(index);
newStatement.append(" = 0;");
newStatement.append(index);
newStatement.append('<');
newStatement.append(iteratedValue.getText());
newStatement.append(".length;");
newStatement.append(index);
newStatement.append("++)");
newStatement.append("{ ");
newStatement.append(type.getCanonicalText());
newStatement.append(' ');
newStatement.append(iterationParameter.getName());
newStatement.append(" = ");
newStatement.append(iteratedValue.getText());
newStatement.append('[');
newStatement.append(index);
newStatement.append("];");
final String index = codeStyleManager.suggestUniqueVariableName("i", statement, true);
newStatement.append("for(int ").append(index).append(" = 0;");
newStatement.append(index).append('<').append(iteratedValue.getText()).append(".length;");
newStatement.append(index).append("++)").append("{ ");
if (codeStyleSettings.GENERATE_FINAL_LOCALS) {
newStatement.append("final ");
}
newStatement.append(type.getCanonicalText()).append(' ').append(iterationParameter.getName());
newStatement.append(" = ").append(iteratedValue.getText()).append('[').append(index).append("];");
}
else {
final PsiType iteratedType = iteratedValue.getType();
final PsiType type;
if (iteratedType instanceof PsiClassType) {
final PsiClassType classType = (PsiClassType)iteratedType;
final PsiType[] types = classType.getParameters();
type = types[0];
@NonNls final StringBuilder methodCall = new StringBuilder();
if (ParenthesesUtils.getPrecedence(iteratedValue) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) {
methodCall.append('(').append(iteratedValue.getText()).append(')');
}
else {
type = iterationParameter.getType();
methodCall.append(iteratedValue.getText());
}
final String iterator =
codeStyleManager.suggestUniqueVariableName("it",
statement, true);
final String typeText = type.getCanonicalText();
newStatement.append("for(java.util.Iterator<");
newStatement.append(typeText);
newStatement.append("> ");
newStatement.append(iterator);
newStatement.append(" = ");
newStatement.append(iteratedValue.getText());
newStatement.append(".iterator();");
newStatement.append(iterator);
newStatement.append(".hasNext();)");
newStatement.append('{');
newStatement.append(typeText);
newStatement.append(' ');
newStatement.append(iterationParameter.getName());
newStatement.append(" = ");
newStatement.append(iterator);
newStatement.append(".next();");
methodCall.append(".iterator()");
final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
final PsiExpression iteratorCall = factory.createExpressionFromText(methodCall.toString(), iteratedValue);
final PsiType variableType = GenericsUtil.getVariableTypeByExpressionType(iteratorCall.getType());
if (variableType == null) {
return;
}
final PsiType parameterType = iterationParameter.getType();
final String typeText = parameterType.getCanonicalText();
newStatement.append("for(").append(variableType.getCanonicalText()).append(' ');
final String iterator = codeStyleManager.suggestUniqueVariableName("iterator", statement, true);
newStatement.append(iterator).append("=").append(iteratorCall.getText()).append(';');
newStatement.append(iterator).append(".hasNext();){");
if (codeStyleSettings.GENERATE_FINAL_LOCALS) {
newStatement.append("final ");
}
newStatement.append(typeText).append(' ').append(iterationParameter.getName()).append(" = ").append(iterator).append(".next();");
}
final PsiStatement body = statement.getBody();
if (body instanceof PsiBlockStatement) {
final PsiBlockStatement blockStatement =
(PsiBlockStatement)body;
final PsiBlockStatement blockStatement = (PsiBlockStatement)body;
final PsiCodeBlock block = blockStatement.getCodeBlock();
final PsiElement[] children = block.getChildren();
for (int i = 1; i < children.length - 1; i++) {
@@ -146,7 +124,7 @@ public class ForeachStatementInspection extends BaseInspection {
newStatement.append(bodyText);
}
newStatement.append('}');
replaceStatement(statement, newStatement.toString());
replaceStatementAndShortenClassNames(statement, newStatement.toString());
}
}
@@ -154,12 +132,10 @@ public class ForeachStatementInspection extends BaseInspection {
return new ForeachStatementVisitor();
}
private static class ForeachStatementVisitor
extends BaseInspectionVisitor {
private static class ForeachStatementVisitor extends BaseInspectionVisitor {
@Override
public void visitForeachStatement(
@NotNull PsiForeachStatement statement) {
public void visitForeachStatement(@NotNull PsiForeachStatement statement) {
super.visitForeachStatement(statement);
registerStatementError(statement);
}

Some files were not shown because too many files have changed in this diff Show More