diff --git a/bin/scripts/unix/idea.sh b/bin/scripts/unix/idea.sh index 19932d440338..28b37bd39950 100755 --- a/bin/scripts/unix/idea.sh +++ b/bin/scripts/unix/idea.sh @@ -151,7 +151,7 @@ if [ "$IS_EAP" = "true" ]; then OS_NAME=`echo $OS_TYPE | "$TR" '[:upper:]' '[:lower:]'` AGENT_LIB="yjpagent-$OS_NAME$BITS" if [ -r "$IDE_BIN_HOME/lib$AGENT_LIB.so" ]; then - AGENT="-agentlib:$AGENT_LIB=disablej2ee,disablealloc,delay=10000,sessionname=@@system_selector@@" + AGENT="-agentlib:$AGENT_LIB=disablealloc,delay=10000,sessionname=@@system_selector@@" fi fi diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index 4edda91e2dd6..fc3cf13b92db 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -142,11 +142,11 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements Element state = new Element("state"); XmlSerializer.serializeInto(myState, state, new SkipDefaultValuesSerializationFilters() { @Override - protected boolean accepts(@NotNull Accessor accessor, @NotNull Object bean, @Nullable Object beanValue) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { if (myState.compilerWasSpecified && "DEFAULT_COMPILER".equals(accessor.getName())) { return true; } - return super.accepts(accessor, bean, beanValue); + return super.accepts(accessor, bean); } }); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 9ceffac57eb4..ceeef8a6c781 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -93,6 +93,7 @@ import io.netty.handler.codec.protobuf.ProtobufDecoder; import io.netty.handler.codec.protobuf.ProtobufEncoder; import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; +import io.netty.util.internal.ThreadLocalRandom; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.ide.PooledThreadExecutor; @@ -999,6 +1000,9 @@ public class BuildManager implements ApplicationComponent{ cmdLine.addParameter("-Didea.case.sensitive.fs=" + isFSCaseSensitive); } + // this will make netty initialization faster on some systems + cmdLine.addParameter("-Dio.netty.initialSeedUniquifier=" + ThreadLocalRandom.getInitialSeedUniquifier()); + boolean isProfilingMode = false; final String additionalOptions = config.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS; if (!StringUtil.isEmpty(additionalOptions)) { @@ -1013,7 +1017,7 @@ public class BuildManager implements ApplicationComponent{ } if (isProfilingMode) { - cmdLine.addParameter("-agentlib:yjpagent=disablej2ee,disablealloc,delay=10000,sessionname=ExternalBuild"); + cmdLine.addParameter("-agentlib:yjpagent=disablealloc,delay=10000,sessionname=ExternalBuild"); } // debugging diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java b/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java index 4868321f9ca2..9d34478d9e53 100644 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java +++ b/java/compiler/impl/src/com/intellij/openapi/compiler/util/InspectionValidatorWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -29,13 +29,11 @@ import com.intellij.lang.annotation.AnnotationSession; import com.intellij.lang.annotation.ExternalAnnotator; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.application.ReadActionProcessor; -import com.intellij.openapi.application.Result; import com.intellij.openapi.compiler.*; import com.intellij.openapi.compiler.options.ExcludesConfiguration; import com.intellij.openapi.editor.Document; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; @@ -143,41 +141,41 @@ public class InspectionValidatorWrapper implements Validator { return ProcessingItem.EMPTY_ARRAY; } final ExcludesConfiguration excludesConfiguration = ValidationConfiguration.getExcludedEntriesConfiguration(project); - final List items = new ReadAction>() { - @Override - protected void run(final Result> result) { - final CompileScope compileScope = context.getCompileScope(); - if (!myValidator.isAvailableOnScope(compileScope)) return; + final List items = + DumbService.getInstance(project).runReadActionInSmartMode(new Computable>() { + @Override + public List compute() { + final CompileScope compileScope = context.getCompileScope(); + if (!myValidator.isAvailableOnScope(compileScope)) return null; - final ArrayList items = new ArrayList(); + final ArrayList items = new ArrayList(); - final Processor processor = new ReadActionProcessor() { - @Override - public boolean processInReadAction(VirtualFile file) { - if (!file.isValid()) { - return true; - } - - if (myCompilerManager.isExcludedFromCompilation(file) || - excludesConfiguration.isExcluded(file)) { - return true; - } - - final Module module = context.getModuleByFile(file); - if (module != null) { - final PsiFile psiFile = myPsiManager.findFile(file); - if (psiFile != null) { - items.add(new MyValidatorProcessingItem(psiFile)); + final Processor processor = new Processor() { + @Override + public boolean process(VirtualFile file) { + if (!file.isValid()) { + return true; } - } - return true; - } - }; - ContainerUtil.process(myValidator.getFilesToProcess(myPsiManager.getProject(), context), processor); - result.setResult(items); - } - }.execute().getResultObject(); + if (myCompilerManager.isExcludedFromCompilation(file) || + excludesConfiguration.isExcluded(file)) { + return true; + } + + final Module module = context.getModuleByFile(file); + if (module != null) { + final PsiFile psiFile = myPsiManager.findFile(file); + if (psiFile != null) { + items.add(new MyValidatorProcessingItem(psiFile)); + } + } + return true; + } + }; + ContainerUtil.process(myValidator.getFilesToProcess(myPsiManager.getProject(), context), processor); + return items; + } + }); if (items == null) return ProcessingItem.EMPTY_ARRAY; return items.toArray(new ProcessingItem[items.size()]); diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java index a93bf8101a31..c25db1da19b5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/AddToWatchActionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -78,7 +78,7 @@ public class AddToWatchActionHandler extends DebuggerActionHandler { if(session == null) { return; } - final MainWatchPanel watchPanel = DebuggerPanelsManager.getInstance(debuggerContext.getProject()).getWatchPanel(); + final MainWatchPanel watchPanel = null;// DebuggerPanelsManager.getInstance(debuggerContext.getProject()).getWatchPanel(); if(watchPanel == null) { return; diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/EvaluateActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/EvaluateActionHandler.java deleted file mode 100644 index 22694cb0b683..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/actions/EvaluateActionHandler.java +++ /dev/null @@ -1,143 +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. - */ - -/* - * Class EvaluateAction - * @author Jeka - */ -package com.intellij.debugger.actions; - -import com.intellij.debugger.DebuggerInvocationUtil; -import com.intellij.debugger.engine.evaluation.CodeFragmentKind; -import com.intellij.debugger.engine.evaluation.EvaluateException; -import com.intellij.debugger.engine.evaluation.TextWithImports; -import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; -import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerSession; -import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.debugger.ui.ExpressionEvaluationDialog; -import com.intellij.debugger.ui.StatementEvaluationDialog; -import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeExpression; -import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl; -import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; -import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.DataKeys; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; -import com.intellij.xdebugger.impl.actions.DebuggerActionHandler; -import org.jetbrains.annotations.NotNull; - -public class EvaluateActionHandler extends DebuggerActionHandler { - public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) { - DebuggerContextImpl context = DebuggerAction.getDebuggerContext(event.getDataContext()); - - if(context != null) { - DebuggerSession debuggerSession = context.getDebuggerSession(); - return debuggerSession != null && debuggerSession.isPaused(); - } - - return false; - } - - public void perform(@NotNull final Project project, final AnActionEvent event) { - final DataContext dataContext = event.getDataContext(); - final DebuggerContextImpl context = DebuggerAction.getDebuggerContext(dataContext); - - if(context == null) { - return; - } - - final Editor editor = event.getData(DataKeys.EDITOR); - - TextWithImports editorText = DebuggerUtilsEx.getEditorText(editor); - if (editorText == null) { - final DebuggerTreeNodeImpl selectedNode = DebuggerAction.getSelectedNode(dataContext); - final String actionName = event.getPresentation().getText(); - - if (selectedNode != null && selectedNode.getDescriptor() instanceof ValueDescriptorImpl) { - context.getDebugProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(context) { - public void threadAction() { - try { - final TextWithImports evaluationText = DebuggerTreeNodeExpression.createEvaluationText(selectedNode, context); - DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() { - public void run() { - showEvaluationDialog(project, evaluationText); - } - }); - } - catch (final EvaluateException e1) { - DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() { - public void run() { - Messages.showErrorDialog(project, e1.getMessage(), actionName); - } - }); - } - } - - protected void commandCancelled() { - DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() { - public void run() { - if(selectedNode.getDescriptor() instanceof WatchItemDescriptor) { - try { - TextWithImports editorText = DebuggerTreeNodeExpression.createEvaluationText(selectedNode, context); - showEvaluationDialog(project, editorText); - } - catch (EvaluateException e1) { - Messages.showErrorDialog(project, e1.getMessage(), actionName); - } - } - } - }); - } - }); - return; - } - } - - showEvaluationDialog(project, editorText); - } - - public static void showEvaluationDialog(Project project, TextWithImports defaultExpression, String dialogType) { - if(defaultExpression == null) { - defaultExpression = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, ""); - } - - CodeFragmentKind kind = DebuggerSettings.EVALUATE_FRAGMENT.equals(dialogType) ? CodeFragmentKind.CODE_BLOCK : CodeFragmentKind.EXPRESSION; - - DebuggerSettings.getInstance().EVALUATION_DIALOG_TYPE = dialogType; - TextWithImportsImpl text = new TextWithImportsImpl(kind, defaultExpression.getText(), defaultExpression.getImports(), defaultExpression.getFileType()); - - final DialogWrapper dialog; - if(DebuggerSettings.EVALUATE_FRAGMENT.equals(dialogType)) { - dialog = new StatementEvaluationDialog(project, text); - } - else { - dialog = new ExpressionEvaluationDialog(project, text); - } - - dialog.show(); - } - - public static void showEvaluationDialog(Project project, TextWithImports text) { - showEvaluationDialog(project, text, DebuggerSettings.getInstance().EVALUATION_DIALOG_TYPE); - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ShowFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ShowFrameAction.java deleted file mode 100644 index 6b1bf1f9b1b1..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ShowFrameAction.java +++ /dev/null @@ -1,42 +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.debugger.actions; - -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerStateManager; -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerSession; -import com.intellij.debugger.ui.DebuggerPanelsManager; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataConstants; -import com.intellij.openapi.project.Project; - -/** - * User: lex - * Date: Sep 26, 2003 - * Time: 7:45:21 PM - */ -public class ShowFrameAction extends GotoFrameSourceAction { - public void actionPerformed(AnActionEvent e) { - super.actionPerformed(e); - DebuggerStateManager stateManager = getContextManager(e.getDataContext()); - DebuggerContextImpl context = stateManager.getContext(); - - if(context != null) { - DebuggerPanelsManager.getInstance(context.getProject()).showFramePanel(); - } - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java index 96e6d015f026..9386cca37ec8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ThreadDumpAction.java @@ -27,8 +27,8 @@ import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; -import com.intellij.debugger.ui.DebuggerSessionTab; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -70,7 +70,7 @@ public class ThreadDumpAction extends AnAction implements AnAction.TransparentUp public void run() { XDebugSession xSession = session.getXDebugSession(); if (xSession != null) { - DebuggerSessionTab.addThreadDump(project, threads, xSession.getUI(), session); + DebuggerUtilsEx.addThreadDump(project, threads, xSession.getUI(), session); } } }, ModalityState.NON_MODAL); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index ce2215f1665b..92fbca934720 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -27,7 +27,6 @@ import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.debugger.ui.DebuggerPanelsManager; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.breakpoints.LineBreakpoint; import com.intellij.execution.configurations.RemoteConnection; @@ -452,7 +451,6 @@ public class DebugProcessEvents extends DebugProcessImpl { DebuggerInvocationUtil.invokeAndWait(getProject(), new Runnable() { @Override public void run() { - DebuggerPanelsManager.getInstance(getProject()).toFront(mySession); final String displayName = requestor instanceof Breakpoint? ((Breakpoint)requestor).getDisplayName() : requestor.getClass().getSimpleName(); final String message = DebuggerBundle.message("error.evaluating.breakpoint.condition.or.action", displayName, ex.getMessage()); considerRequestHit[0] = Messages.showYesNoDialog(getProject(), message, ex.getTitle(), Messages.getQuestionIcon()) == Messages.YES; diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index 29a2c3414695..09c869db99c5 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -1098,7 +1098,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb throw (RuntimeException)exception[0]; } else { - LOG.assertTrue(false); + LOG.error("Unexpected exception " + exception[0]); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java index c7e682f200a5..5bd576c109f6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java @@ -33,7 +33,14 @@ import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.ui.CompletionEditor; import com.intellij.debugger.ui.breakpoints.Breakpoint; import com.intellij.debugger.ui.tree.DebuggerTreeNode; +import com.intellij.execution.filters.ExceptionFilters; +import com.intellij.execution.filters.TextConsoleBuilder; +import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.RunnerLayoutUi; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -47,6 +54,9 @@ import com.intellij.pom.Navigatable; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.ui.classFilter.ClassFilter; +import com.intellij.ui.content.Content; +import com.intellij.unscramble.ThreadDumpPanel; +import com.intellij.unscramble.ThreadState; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.xdebugger.XSourcePosition; @@ -399,6 +409,43 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils { return null; } + private static int myThreadDumpsCount = 0; + private static int myCurrentThreadDumpId = 1; + + private static final String THREAD_DUMP_CONTENT_PREFIX = "Dump"; + + public static void addThreadDump(Project project, List threads, final RunnerLayoutUi ui, DebuggerSession session) { + final TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project); + consoleBuilder.filters(ExceptionFilters.getFilters(session.getSearchScope())); + final ConsoleView consoleView = consoleBuilder.getConsole(); + final DefaultActionGroup toolbarActions = new DefaultActionGroup(); + consoleView.allowHeavyFilters(); + final ThreadDumpPanel panel = new ThreadDumpPanel(project, consoleView, toolbarActions, threads); + + final String id = THREAD_DUMP_CONTENT_PREFIX + " #" + myCurrentThreadDumpId; + final Content content = ui.createContent(id, panel, id, null, null); + content.setCloseable(true); + content.setDescription("Thread Dump"); + ui.addContent(content); + ui.selectAndFocus(content, true, true); + myThreadDumpsCount++; + myCurrentThreadDumpId++; + Disposer.register(content, new Disposable() { + @Override + public void dispose() { + myThreadDumpsCount--; + if (myThreadDumpsCount == 0) { + myCurrentThreadDumpId = 1; + } + } + }); + Disposer.register(content, consoleView); + ui.selectAndFocus(content, true, false); + if (threads.size() > 0) { + panel.selectStackFrame(0); + } + } + public abstract DebuggerTreeNode getSelectedNode (DataContext context); public abstract EvaluatorBuilder getEvaluatorBuilder(); diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java index d084c0308b72..a443b6c03dbd 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -84,6 +84,22 @@ public class StackFrameProxyImpl extends JdiProxy implements StackFrameProxy { throw new EvaluateException(error.getMessage(), error); } + @Override + public boolean isValid() { + DebuggerManagerThreadImpl.assertIsManagerThread(); + if (!super.isValid()) { + return false; + } + try { + if (myStackFrame != null) { + myStackFrame.location(); //extra check if jdi frame is valid + } + return true; + } catch (InvalidStackFrameException e) { + return false; + } + } + @Override protected void clearCaches() { DebuggerManagerThreadImpl.assertIsManagerThread(); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java index eaf49dc37b29..71811a2bde26 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerPanelsManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,8 @@ import com.intellij.debugger.engine.JavaDebugProcess; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.impl.DebuggerStateManager; -import com.intellij.debugger.ui.impl.MainWatchPanel; import com.intellij.debugger.ui.tree.render.BatchEvaluator; import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionManager; import com.intellij.execution.Executor; import com.intellij.execution.configurations.RemoteConnection; import com.intellij.execution.configurations.RunProfileState; @@ -39,9 +37,8 @@ import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunContentManager; import com.intellij.execution.ui.RunContentWithExecutorListener; import com.intellij.openapi.components.ProjectComponent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugProcessStarter; import com.intellij.xdebugger.XDebugSession; @@ -50,43 +47,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class DebuggerPanelsManager implements ProjectComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.DebuggerPanelsManager"); - private final Project myProject; - private final ExecutionManager myExecutionManager; - //private final PositionHighlighter myEditorManager; - //private final HashMap mySessionTabs = new HashMap(); - - public DebuggerPanelsManager(Project project, final EditorColorsManager colorsManager, ExecutionManager executionManager) { + public DebuggerPanelsManager(Project project) { myProject = project; - myExecutionManager = executionManager; - - //myEditorManager = new PositionHighlighter(myProject, getContextManager()); - // - //final EditorColorsListener myColorsListener = new EditorColorsListener() { - // public void globalSchemeChange(EditorColorsScheme scheme) { - // myEditorManager.updateContextPointDescription(); - // } - //}; - //colorsManager.addEditorColorsListener(myColorsListener); - //Disposer.register(project, new Disposable() { - // public void dispose() { - // colorsManager.removeEditorColorsListener(myColorsListener); - // } - //}); - // - //getContextManager().addListener(new DebuggerContextListener() { - // public void changeEvent(final DebuggerContextImpl newContext, int event) { - // if (event == DebuggerSession.EVENT_PAUSE) { - // DebuggerInvocationUtil.invokeLater(myProject, new Runnable() { - // public void run() { - // toFront(newContext.getDebuggerSession()); - // } - // }); - // } - // } - //}); } private DebuggerStateManager getContextManager() { @@ -195,48 +159,12 @@ public class DebuggerPanelsManager implements ProjectComponent { return project.getComponent(DebuggerPanelsManager.class); } - @Nullable - public MainWatchPanel getWatchPanel() { - DebuggerSessionTab sessionTab = getSessionTab(); - return sessionTab != null ? sessionTab.getWatchPanel() : null; - } - - @Nullable - public DebuggerSessionTab getSessionTab() { - DebuggerContextImpl context = DebuggerManagerEx.getInstanceEx(myProject).getContext(); - return getSessionTab(context.getDebuggerSession()); - } - - public void showFramePanel() { - DebuggerSessionTab sessionTab = getSessionTab(); - if (sessionTab != null) { - sessionTab.showFramePanel(); - } - } - - public void toFront(DebuggerSession session) { - DebuggerSessionTab sessionTab = getSessionTab(session); - if (sessionTab != null) { - sessionTab.toFront(true, null); - } - } - private static DebuggerSession getSession(Project project, RunContentDescriptor descriptor) { - for (XDebugSession session : XDebuggerManager.getInstance(project).getDebugSessions()) { - if (session.getRunContentDescriptor().equals(descriptor)) { - XDebugProcess process = session.getDebugProcess(); - if (process instanceof JavaDebugProcess) { - return ((JavaDebugProcess)process).getDebuggerSession(); - } + for (JavaDebugProcess process : XDebuggerManager.getInstance(project).getDebugProcesses(JavaDebugProcess.class)) { + if (Comparing.equal(process.getProcessHandler(), descriptor.getProcessHandler())) { + return process.getDebuggerSession(); } } return null; } - - @Nullable - private DebuggerSessionTab getSessionTab(DebuggerSession session) { - //return session != null ? getSessionTab(session.getProcess().getExecutionResult().getProcessHandler()) : null; - return null; - } - } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java index 51a96197ba48..7842769a7479 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java @@ -36,12 +36,8 @@ import com.intellij.execution.ExecutionManager; import com.intellij.execution.ExecutionResult; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.executors.DefaultDebugExecutor; -import com.intellij.execution.filters.ExceptionFilters; -import com.intellij.execution.filters.TextConsoleBuilder; -import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ExecutionConsoleEx; -import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.icons.AllIcons; import com.intellij.idea.ActionsBundle; @@ -56,8 +52,6 @@ import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManagerAdapter; import com.intellij.ui.content.ContentManagerEvent; import com.intellij.ui.content.tabs.PinToolwindowTabAction; -import com.intellij.unscramble.ThreadDumpPanel; -import com.intellij.unscramble.ThreadState; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.impl.actions.XDebuggerActions; import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager; @@ -68,7 +62,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.TreePath; -import java.util.List; public class DebuggerSessionTab extends DebuggerSessionTabBase implements Disposable { private static final Logger LOG = Logger.getInstance(DebuggerSessionTab.class); @@ -84,7 +77,6 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos private final DebugUIEnvironment myDebugUIEnvironment; private final ThreadsPanel myThreadsPanel; - private static final String THREAD_DUMP_CONTENT_PREFIX = "Dump"; public DebuggerSessionTab(final Project project, final String sessionName, @NotNull final DebugUIEnvironment environment, @NotNull DebuggerSession debuggerSession) { @@ -447,51 +439,6 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos myUi.selectAndFocus(myUi.findContent(DebuggerContentInfo.FRAME_CONTENT), true, false); } - private static int myThreadDumpsCount = 0; - private static int myCurrentThreadDumpId = 1; - - public static void addThreadDump(Project project, List threads, final RunnerLayoutUi ui, DebuggerSession session) { - final TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project); - consoleBuilder.filters(ExceptionFilters.getFilters(session.getSearchScope())); - final ConsoleView consoleView = consoleBuilder.getConsole(); - final DefaultActionGroup toolbarActions = new DefaultActionGroup(); - consoleView.allowHeavyFilters(); - final ThreadDumpPanel panel = new ThreadDumpPanel(project, consoleView, toolbarActions, threads); - - final String id = createThreadDumpContentId(); - final Content content = ui.createContent(id, panel, id, null, null); - content.setCloseable(true); - content.setDescription("Thread Dump"); - ui.addContent(content); - ui.selectAndFocus(content, true, true); - myThreadDumpsCount += 1; - myCurrentThreadDumpId += 1; - //Disposer.register(this, new Disposable() { - // @Override - // public void dispose() { - // ui.removeContent(content, true); - // } - //}); - Disposer.register(content, new Disposable() { - @Override - public void dispose() { - myThreadDumpsCount -= 1; - if (myThreadDumpsCount == 0) { - myCurrentThreadDumpId = 1; - } - } - }); - Disposer.register(content, consoleView); - ui.selectAndFocus(content, true, false); - if (threads.size() > 0) { - panel.selectStackFrame(0); - } - } - - private static String createThreadDumpContentId() { - return THREAD_DUMP_CONTENT_PREFIX + " #" + myCurrentThreadDumpId; - } - private class MyDebuggerStateManager extends DebuggerStateManager { @Override public void fireStateChanged(DebuggerContextImpl newContext, int event) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java deleted file mode 100644 index a4e1b1675c13..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java +++ /dev/null @@ -1,190 +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.debugger.ui; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.DebuggerInvocationUtil; -import com.intellij.debugger.HelpID; -import com.intellij.debugger.actions.EvaluateActionHandler; -import com.intellij.debugger.engine.evaluation.CodeFragmentFactory; -import com.intellij.debugger.engine.evaluation.TextWithImports; -import com.intellij.debugger.impl.PositionUtil; -import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.help.HelpManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ex.AbstractDelegatingToRootTraversalPolicy; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.components.JBLabel; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; - -public class ExpressionEvaluationDialog extends EvaluationDialog { - - public ExpressionEvaluationDialog(Project project, TextWithImports defaultExpression) { - super(project, defaultExpression); - setTitle(DebuggerBundle.message("evaluate.expression.dialog.title")); - - final KeyStroke expressionStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_MASK); - final KeyStroke resultStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK); - - final JRootPane rootPane = getRootPane(); - - final AnAction anAction = new AnAction() { - public void actionPerformed(AnActionEvent e) { - getExpressionCombo().requestFocus(); - } - }; - anAction.registerCustomShortcutSet(new CustomShortcutSet(expressionStroke), rootPane); - addDisposeRunnable(new Runnable() { - public void run() { - anAction.unregisterCustomShortcutSet(rootPane); - } - }); - - final AnAction anAction2 = new AnAction() { - public void actionPerformed(AnActionEvent e) { - getEvaluationPanel().getWatchTree().requestFocus(); - } - }; - anAction2.registerCustomShortcutSet(new CustomShortcutSet(resultStroke), rootPane); - addDisposeRunnable(new Runnable() { - public void run() { - anAction2.unregisterCustomShortcutSet(rootPane); - } - }); - - init(); - } - - protected DebuggerExpressionComboBox createEditor(final CodeFragmentFactory factory) { - return new DebuggerExpressionComboBox(getProject(), PositionUtil.getContextElement(getDebuggerContext()), "evaluation", factory); - } - - protected JComponent createCenterPanel() { - final JPanel panel = new JPanel(new BorderLayout()); - - final JPanel exprPanel = new JPanel(new BorderLayout(UIUtil.DEFAULT_HGAP, 0)); - exprPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.expression")), BorderLayout.WEST); - exprPanel.add(getExpressionCombo(), BorderLayout.CENTER); - final JBLabel help = new JBLabel("Press Enter to Evaluate or Control+Enter to evaluate and add to the Watches", SwingConstants.RIGHT); - help.setBorder(IdeBorderFactory.createEmptyBorder(2,0,6,0)); - help.setComponentStyle(UIUtil.ComponentStyle.SMALL); - help.setFontColor(UIUtil.FontColor.BRIGHTER); - exprPanel.add(help, BorderLayout.SOUTH); - - - final JPanel resultPanel = new JPanel(new BorderLayout()); - //resultPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.result")), BorderLayout.NORTH); - resultPanel.add(getEvaluationPanel(), BorderLayout.CENTER); - - panel.add(exprPanel, BorderLayout.NORTH); - panel.add(resultPanel, BorderLayout.CENTER); - - panel.setFocusTraversalPolicyProvider(true); - panel.setFocusTraversalPolicy(new AbstractDelegatingToRootTraversalPolicy() { - @Override - public Component getComponentBefore(Container aContainer, Component aComponent) { - boolean focusExpressionCombo = isParent(aComponent, getEvaluationPanel()); - return focusExpressionCombo ? getExpressionCombo().getEditorComponent() : super.getComponentBefore(aContainer, aComponent); - } - - @Override - public Component getComponentAfter(Container aContainer, Component aComponent) { - boolean focusEvaluationPanel = isParent(aComponent, exprPanel); - return focusEvaluationPanel ? getEvaluationPanel().getTree() : super.getComponentAfter(aContainer, aComponent); - } - - private boolean isParent(@NotNull Component component, @NotNull Container parent) { - for (Component c = component; c != null; c = c.getParent()) { - if (c == parent) { - return true; - } - } - return false; - } - }); - - return panel; - } - - protected void initDialogData(TextWithImports text) { - super.initDialogData(text); - getExpressionCombo().selectAll(); - } - - private DebuggerExpressionComboBox getExpressionCombo() { - return (DebuggerExpressionComboBox)getEditor(); - } - - @NotNull - protected Action[] createActions() { - return new Action[] { getOKAction(), getCancelAction(), new SwitchAction(), getHelpAction() } ; - } - - @Override - protected void createDefaultActions() { - super.createDefaultActions(); - myOKAction = new OkAction(){ - @Override - public void actionPerformed(ActionEvent e) { - super.actionPerformed(e); - if ((e.getModifiers() & InputEvent.CTRL_MASK) != 0) { - addCurrentExpressionToWatches(); - } - } - }; - } - - private void addCurrentExpressionToWatches() { - final DebuggerSessionTab tab = DebuggerPanelsManager.getInstance(getProject()).getSessionTab(); - if (tab != null) { - final TextWithImports evaluate = getCodeToEvaluate(); - if (evaluate != null) { - tab.getWatchPanel().getWatchTree().addWatch(evaluate, null); - } - } - } - - protected void doHelpAction() { - HelpManager.getInstance().invokeHelp(HelpID.EVALUATE); - } - - private class SwitchAction extends AbstractAction { - public SwitchAction() { - putValue(Action.NAME, DebuggerBundle.message("action.evaluate.expression.dialog.switch.mode.description")); - } - - public void actionPerformed(ActionEvent e) { - final TextWithImports text = getEditor().getText(); - doCancelAction(); - DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { - public void run() { - EvaluateActionHandler.showEvaluationDialog(getProject(), text, DebuggerSettings.EVALUATE_FRAGMENT); - } - }); - } - } - -} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/StatementEvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/StatementEvaluationDialog.java deleted file mode 100644 index 653f24f75eb7..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/ui/StatementEvaluationDialog.java +++ /dev/null @@ -1,221 +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.debugger.ui; - -import com.intellij.debugger.DebuggerBundle; -import com.intellij.debugger.DebuggerInvocationUtil; -import com.intellij.debugger.HelpID; -import com.intellij.debugger.actions.EvaluateActionHandler; -import com.intellij.debugger.engine.evaluation.CodeFragmentFactory; -import com.intellij.debugger.engine.evaluation.TextWithImports; -import com.intellij.debugger.impl.PositionUtil; -import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.help.HelpManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Splitter; -import com.intellij.openapi.util.DimensionService; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiWhiteSpace; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; - -/** - * @author lex - */ -public class StatementEvaluationDialog extends EvaluationDialog{ - private final JPanel myPanel; - private final Action mySwitchAction = new SwitchAction(); - private static final @NonNls String STATEMENT_EDITOR_DIMENSION_KEY = "#com.intellij.debugger.ui.StatementEvaluationDialog.StatementEditor"; - private static final @NonNls String EVALUATION_PANEL_DIMENSION_KEY = "#com.intellij.debugger.ui.StatementEvaluationDialog.EvaluationPanel"; - - public StatementEvaluationDialog(final Project project, TextWithImports text) { - super(project, text); - setTitle(DebuggerBundle.message("evaluate.statement.dialog.title")); - myPanel = new JPanel(new BorderLayout()); - - final Splitter splitter = new Splitter(true); - splitter.setHonorComponentsMinimumSize(true); - - final JPanel editorPanel = new JPanel(new GridBagLayout()); - - final JLabel statementsLabel = new JLabel(DebuggerBundle.message("label.evaluation.dialog.statements")); - editorPanel.add(statementsLabel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0)); - editorPanel.add(getStatementEditor(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0)); - - splitter.setFirstComponent(editorPanel); - - final MyEvaluationPanel evaluationPanel = getEvaluationPanel(); - final JPanel ep = new JPanel(new BorderLayout()); - //final JLabel resultLabel = new JLabel(DebuggerBundle.message("label.evaluate.dialog.result")); - //ep.add(resultLabel, BorderLayout.NORTH); - ep.add(evaluationPanel, BorderLayout.CENTER); - splitter.setSecondComponent(ep); - final Dimension statementSize = DimensionService.getInstance().getSize(STATEMENT_EDITOR_DIMENSION_KEY, project); - final Dimension evaluationSize = DimensionService.getInstance().getSize(EVALUATION_PANEL_DIMENSION_KEY, project); - if (statementSize != null && evaluationSize != null) { - final float proportion = (float)statementSize.height / (float)(statementSize.height + evaluationSize.height); - splitter.setProportion(proportion); - } - myPanel.add(splitter, BorderLayout.CENTER); - - setDebuggerContext(getDebuggerContext()); - - final KeyStroke codeFragment = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.ALT_MASK); - final KeyStroke resultStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.ALT_MASK); - final KeyStroke altEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK); - - final JRootPane rootPane = getRootPane(); - final AnAction toStatementAction = new AnAction() { - public void actionPerformed(AnActionEvent e) { - getStatementEditor().requestFocus(); - } - }; - toStatementAction.registerCustomShortcutSet(new CustomShortcutSet(codeFragment), rootPane); - addDisposeRunnable(new Runnable() { - public void run() { - toStatementAction.unregisterCustomShortcutSet(rootPane); - } - }); - - final AnAction toEvaluationAction = new AnAction() { - public void actionPerformed(AnActionEvent e) { - getEvaluationPanel().getWatchTree().requestFocus(); - } - }; - toEvaluationAction.registerCustomShortcutSet(new CustomShortcutSet(resultStroke), rootPane); - addDisposeRunnable(new Runnable() { - public void run() { - toEvaluationAction.unregisterCustomShortcutSet(rootPane); - } - }); - - final AnAction okAction = new AnAction() { - public void actionPerformed(AnActionEvent e) { - doOKAction(); - } - }; - okAction.registerCustomShortcutSet(new CustomShortcutSet(altEnter), rootPane); - addDisposeRunnable(new Runnable() { - public void run() { - okAction.unregisterCustomShortcutSet(rootPane); - } - }); - - final DebuggerEditorImpl editor = getEditor(); - final DocumentAdapter docListener = new DocumentAdapter() { - public void documentChanged(final DocumentEvent e) { - DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { - public void run() { - updateSwitchButton(e.getDocument()); - } - }); - } - }; - editor.addDocumentListener(docListener); - addDisposeRunnable(new Runnable() { - public void run() { - editor.removeDocumentListener(docListener); - } - }); - - init(); - } - - private void updateSwitchButton(Document document) { - PsiDocumentManager.getInstance(getProject()).commitDocument(document); - PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document); - if (psiFile == null) { - return; - } - PsiElement[] children = psiFile.getChildren(); - int nonWhite = 0; - for (PsiElement child : children) { - if (!(child instanceof PsiWhiteSpace)) { - nonWhite++; - if (nonWhite > 1) { - mySwitchAction.setEnabled(false); - return; - } - } - } - - mySwitchAction.setEnabled(true); - } - - @NotNull - protected Action[] createActions(){ - return new Action[]{getOKAction(), getCancelAction(), mySwitchAction, getHelpAction() }; - } - - protected void doHelpAction() { - HelpManager.getInstance().invokeHelp(HelpID.EVALUATE); - } - - protected DebuggerEditorImpl createEditor(final CodeFragmentFactory factory) { - return new DebuggerStatementEditor(getProject(), PositionUtil.getContextElement(getDebuggerContext()), "evaluation", factory); - } - - public void dispose() { - try { - final DebuggerEditorImpl editor = getEditor(); - final DimensionService dimensionService = DimensionService.getInstance(); - dimensionService.setSize(STATEMENT_EDITOR_DIMENSION_KEY, editor.getSize(null), getProject()); - dimensionService.setSize(EVALUATION_PANEL_DIMENSION_KEY, getEvaluationPanel().getSize(), getProject()); - } - finally { - super.dispose(); - } - } - - protected JComponent createCenterPanel() { - return myPanel; - } - - private DebuggerStatementEditor getStatementEditor() { - return (DebuggerStatementEditor)getEditor(); - } - - private class SwitchAction extends AbstractAction { - public SwitchAction() { - putValue(NAME, DebuggerBundle.message("action.evaluate.statement.dialog.switch.mode.description")); - } - - public void actionPerformed(ActionEvent e) { - final TextWithImports text = getEditor().getText(); - doCancelAction(); - DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { - public void run() { - EvaluateActionHandler.showEvaluationDialog(getProject(), text, DebuggerSettings.EVALUATE_EXPRESSION); - } - }); - } - } - - -} diff --git a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java index fc13858daac9..d10b656ad6a8 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java +++ b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java @@ -307,7 +307,10 @@ public abstract class SourcePosition implements Navigatable{ } public static SourcePosition createFromElement(PsiElement element) { - final PsiElement navigationElement = element.getNavigationElement(); + ApplicationManager.getApplication().assertReadAccessAllowed(); + PsiElement navigationElement = element.getNavigationElement(); + final SmartPsiElementPointer pointer = + SmartPointerManager.getInstance(navigationElement.getProject()).createSmartPsiElementPointer(navigationElement); final PsiFile psiFile; if (JspPsiUtil.isInJspFile(navigationElement)) { psiFile = JspPsiUtil.getJspFile(navigationElement); @@ -318,12 +321,19 @@ public abstract class SourcePosition implements Navigatable{ return new SourcePositionCache(psiFile) { @Override protected PsiElement calcPsiElement() { - return navigationElement; + ApplicationManager.getApplication().assertReadAccessAllowed(); + return pointer.getElement(); } @Override protected int calcOffset() { - return navigationElement.getTextOffset(); + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Integer compute() { + PsiElement elem = pointer.getElement(); + return elem != null ? elem.getTextOffset() : -1; + } + }); } }; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java index 87867565f63a..466903efaf30 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/IncreaseLanguageLevelFix.java @@ -86,20 +86,20 @@ public class IncreaseLanguageLevelFix implements IntentionAction { LOG.assertTrue(virtualFile != null); final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project); final LanguageLevel moduleLevel = module == null ? null : LanguageLevelModuleExtensionImpl.getInstance(module).getLanguageLevel(); - if (moduleLevel != null && isLanguageLevelAcceptable(project, module, myLevel)) { - final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel(); - rootModel.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLevel); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + if (moduleLevel != null && isLanguageLevelAcceptable(project, module, myLevel)) { + final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel(); + rootModel.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLevel); rootModel.commit(); } - }); - } - else { - LanguageLevelProjectExtension.getInstance(project).setLanguageLevel(myLevel); - ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.INSTANCE, false, true); - } + else { + LanguageLevelProjectExtension.getInstance(project).setLanguageLevel(myLevel); + ProjectRootManagerEx.getInstanceEx(project).makeRootsChange(EmptyRunnable.INSTANCE, false, true); + } + } + }); } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java index dc392cec131b..eb9f162a909d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java @@ -263,13 +263,14 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp if (element instanceof PsiMethodCallExpression) { final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element; - final PsiMethod psiMethod = methodCall.resolveMethod(); + JavaResolveResult result = methodCall.resolveMethodGenerics(); + final PsiMethod psiMethod = (PsiMethod)result.getElement(); if (psiMethod == null) { return null; } final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); - final String qualifierByMethodCall = getQualifierTextByMethodCall(methodCall, functionalInterfaceType, parameters, psiMethod); + final String qualifierByMethodCall = getQualifierTextByMethodCall(methodCall, functionalInterfaceType, parameters, psiMethod, result.getSubstitutor()); if (qualifierByMethodCall != null) { return qualifierByMethodCall + "::" + ((PsiMethodCallExpression)element).getTypeArgumentList().getText() + methodExpression.getReferenceName(); } @@ -324,7 +325,8 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp private static String getQualifierTextByMethodCall(final PsiMethodCallExpression methodCall, final PsiType functionalInterfaceType, final PsiParameter[] parameters, - final PsiMethod psiMethod) { + final PsiMethod psiMethod, + final PsiSubstitutor substitutor) { final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression(); @@ -332,7 +334,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp LOG.assertTrue(containingClass != null); if (qualifierExpression != null) { - boolean isReceiverType = PsiMethodReferenceUtil.isReceiverType(functionalInterfaceType, containingClass, psiMethod); + boolean isReceiverType = PsiMethodReferenceUtil.isReceiverType(PsiMethodReferenceUtil.getFirstParameterType(functionalInterfaceType, methodCall), containingClass, substitutor); return isReceiverType ? composeReceiverQualifierText(parameters, psiMethod, containingClass, qualifierExpression) : qualifierExpression.getText(); } @@ -422,7 +424,6 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp if (lambdaExpression == null) return; PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType(); if (functionalInterfaceType == null || !functionalInterfaceType.isValid()) return; - String functionalTypeText = functionalInterfaceType.getCanonicalText(); final String methodRefText = createMethodReferenceText(element, functionalInterfaceType, lambdaExpression.getParameterList().getParameters()); diff --git a/java/java-impl/src/com/intellij/codeEditor/printing/MethodSeparatorProvider.java b/java/java-impl/src/com/intellij/codeEditor/printing/MethodSeparatorProvider.java deleted file mode 100644 index 80aa4d5d5d23..000000000000 --- a/java/java-impl/src/com/intellij/codeEditor/printing/MethodSeparatorProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2000-2015 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. - */ - -/* - * User: anna - * Date: 25-Jan-2008 - */ -package com.intellij.codeEditor.printing; - -import com.intellij.codeInsight.daemon.LineMarkerInfo; -import com.intellij.codeInsight.daemon.impl.LineMarkersPass; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.psi.PsiFile; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class MethodSeparatorProvider extends FileSeparatorProvider { - @Override - public List getFileSeparators(final PsiFile file, final Document document, @Nullable final Editor editor) { - final List result = new ArrayList(); - LineMarkersPass pass = new LineMarkersPass(file.getProject(), file, editor, document, file.getTextRange()); - for (LineMarkerInfo lineMarkerInfo : pass.queryLineMarkers()) { - if (lineMarkerInfo.separatorColor != null) { - result.add(lineMarkerInfo); - } - } - - Collections.sort(result, new Comparator() { - public int compare(final LineMarkerInfo i1, final LineMarkerInfo i2) { - return i1.startOffset - i2.startOffset; - } - }); - return result; - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java index 65c6777bcbbb..e4103ce1a9c9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/CodeInsightUtil.java @@ -106,7 +106,7 @@ public class CodeInsightUtil { if (parent == null) return PsiElement.EMPTY_ARRAY; while (true) { if (parent instanceof PsiStatement) { - if (!(element1 instanceof PsiComment || element2 instanceof PsiComment)) { + if (!(element1 instanceof PsiComment)) { parent = parent.getParent(); } break; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index d36c35ca6e73..90e550a75b30 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -37,9 +37,11 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Set; import static com.intellij.patterns.PsiJavaPatterns.psiClass; import static com.intellij.patterns.PsiJavaPatterns.psiElement; @@ -117,26 +119,52 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement); AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer() { - @Override - public void consume(PsiClass psiClass) { - if (filter.isAcceptable(psiClass, insertedElement)) { - if (!inJavaContext) { - consumer.consume(AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING)); - } else { - for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, - JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition() { + @Override + public void consume(PsiClass psiClass) { + processClass(psiClass, ContainerUtil.newHashSet(), ""); + } + + private void processClass(PsiClass psiClass, Set visited, String prefix) { + if (!visited.add(psiClass)) return; + + boolean isInnerClass = StringUtil.isNotEmpty(prefix); + if (isInnerClass && isProcessedIndependently(psiClass)) { + return; + } + + if (filter.isAcceptable(psiClass, insertedElement)) { + if (!inJavaContext) { + JavaPsiClassReferenceElement element = AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING); + element.setLookupString(prefix + element.getLookupString()); + consumer.consume(element); + } else { + for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, + JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition() { @Override public boolean value(PsiClass psiClass) { return filter.isAcceptable(psiClass, insertedElement) && AllClassesGetter.isAcceptableInContext(insertedElement, psiClass, filterByScope, pkgContext); } })) { - consumer.consume(element); - } + element.setLookupString(prefix + element.getLookupString()); + consumer.consume(element); + } + } + } else { + String name = psiClass.getName(); + if (name != null) { + for (PsiClass innerClass : psiClass.getInnerClasses()) { + processClass(innerClass, visited, prefix + name + "."); } } } - }); + } + + private boolean isProcessedIndependently(PsiClass psiClass) { + String innerName = psiClass.getName(); + return innerName != null && matcher.prefixMatches(innerName); + } + }); } static LookupElement highlightIfNeeded(JavaPsiClassReferenceElement element, CompletionParameters parameters) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java index 9817ce5e631d..3dca018ab61a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java @@ -664,7 +664,20 @@ public class GenerateMembersUtil { } } result = (PsiMethod)CodeStyleManager.getInstance(project).reformat(result); - PropertyUtil.annotateWithNullableStuff(field, result); + + PsiModifierListOwner listOwner = null; + if (templatesManager instanceof GetterTemplatesManager) { + listOwner = result; + } + else { + final PsiParameter[] parameters = result.getParameterList().getParameters(); + if (parameters.length == 1) { + listOwner = parameters[0]; + } + } + if (listOwner != null) { + PropertyUtil.annotateWithNullableStuff(field, listOwner); + } return generatePrototype(field, result); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PatternPackageReferenceSet.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PatternPackageReferenceSet.java index 392cacfb2ac9..c93b33068c1b 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PatternPackageReferenceSet.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/PatternPackageReferenceSet.java @@ -1,19 +1,34 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.psi.impl.source.resolve.reference.impl.providers; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPackage; -import com.intellij.psi.impl.source.resolve.reference.impl.providers.PackageReferenceSet; import com.intellij.util.PatternUtil; import com.intellij.util.Processor; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import java.util.regex.Pattern; public class PatternPackageReferenceSet extends PackageReferenceSet { + public PatternPackageReferenceSet(String packageName, PsiElement element, int startInElement) { super(packageName, element, startInElement); } @@ -24,7 +39,7 @@ public class PatternPackageReferenceSet extends PackageReferenceSet { if (packageName.contains("*")) { final Pattern pattern = PatternUtil.fromMask(packageName); - final Set packages = new HashSet(); + final Set packages = new LinkedHashSet(); processSubPackages(context, new Processor() { @Override @@ -39,13 +54,13 @@ public class PatternPackageReferenceSet extends PackageReferenceSet { return packages; } - else { - return super.resolvePackageName(context, packageName); - } + + return super.resolvePackageName(context, packageName); } - protected static boolean processSubPackages(final PsiPackage pkg, final Processor processor) { + protected static boolean processSubPackages(final PsiPackage pkg, final Processor processor) { if (!processor.process(pkg)) return false; + for (final PsiPackage aPackage : pkg.getSubPackages()) { if (!processSubPackages(aPackage, processor)) return false; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java index 1fd4e786509f..827461de6b3e 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiMethodReferenceUtil.java @@ -17,60 +17,40 @@ package com.intellij.psi; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.util.*; -import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; - /** * User: anna */ public class PsiMethodReferenceUtil { public static final Logger LOG = Logger.getInstance("#" + PsiMethodReferenceUtil.class.getName()); - public static boolean hasReceiver(PsiType[] parameterTypes, QualifierResolveResult qualifierResolveResult, PsiMethodReferenceExpression methodRef) { - if (parameterTypes.length > 0 && + public static boolean isSecondSearchPossible(PsiType[] parameterTypes, + QualifierResolveResult qualifierResolveResult, + PsiMethodReferenceExpression methodRef) { + if (parameterTypes.length > 0 && !methodRef.isConstructor() && - isReceiverType(parameterTypes[0], qualifierResolveResult.getContainingClass(), qualifierResolveResult.getSubstitutor()) && - isStaticallyReferenced(methodRef)) { + isStaticallyReferenced(methodRef) && + isReceiverType(parameterTypes[0], qualifierResolveResult.getContainingClass(), qualifierResolveResult.getSubstitutor())) { return true; } return false; } - public static String checkReturnType(PsiMethodReferenceExpression expression, JavaResolveResult result, PsiType functionalInterfaceType) { - final PsiElement resolve = result.getElement(); - if (resolve instanceof PsiMethod) { - final PsiClass containingClass = ((PsiMethod)resolve).getContainingClass(); - LOG.assertTrue(containingClass != null); - PsiSubstitutor subst = result.getSubstitutor(); - PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass(); - if (qContainingClass != null && isReceiverType(functionalInterfaceType, containingClass, (PsiMethod)resolve)) { - subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst); - LOG.assertTrue(subst != null); - } - - - final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType); - - PsiType returnType = PsiTypesUtil.patchMethodGetClassReturnType(expression, expression, - (PsiMethod)resolve, null, - PsiUtil.getLanguageLevel(expression)); - if (returnType == null) { - returnType = ((PsiMethod)resolve).getReturnType(); - } - PsiType methodReturnType = subst.substitute(returnType); - if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) { - if (methodReturnType == null) { - methodReturnType = JavaPsiFacade.getElementFactory(expression.getProject()).createType(containingClass, subst); - } - if (!TypeConversionUtil.isAssignable(interfaceReturnType, methodReturnType, false)) { - return "Bad return type in method reference: cannot convert " + methodReturnType.getCanonicalText() + " to " + interfaceReturnType.getCanonicalText(); - } - } + public static boolean isResolvedBySecondSearch(@NotNull PsiMethodReferenceExpression methodRef, + @Nullable MethodSignature signature, + boolean varArgs, + boolean isStatic, + int parametersCount) { + if (signature == null) { + return false; } - return null; + final QualifierResolveResult qualifierResolveResult = getQualifierResolveResult(methodRef); + final PsiType[] functionalMethodParameterTypes = signature.getParameterTypes(); + return (parametersCount + 1 == functionalMethodParameterTypes.length && !varArgs || + varArgs && functionalMethodParameterTypes.length > 0 && !isStatic) && + isSecondSearchPossible(functionalMethodParameterTypes, qualifierResolveResult, methodRef); } public static boolean isCorrectAssignment(PsiType[] parameterTypes, @@ -163,7 +143,7 @@ public class PsiMethodReferenceUtil { PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; final PsiExpression expression = methodReferenceExpression.getQualifierExpression(); if (expression != null) { - final PsiType expressionType = getExpandedType(expression.getType(), expression); + final PsiType expressionType = replaceArrayType(expression.getType(), expression); PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(expressionType); containingClass = result.getElement(); if (containingClass != null) { @@ -182,7 +162,7 @@ public class PsiMethodReferenceUtil { else { final PsiTypeElement typeElement = methodReferenceExpression.getQualifierType(); if (typeElement != null) { - PsiType type = getExpandedType(typeElement.getType(), typeElement); + PsiType type = replaceArrayType(typeElement.getType(), typeElement); PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type); containingClass = result.getElement(); if (containingClass != null) { @@ -202,59 +182,33 @@ public class PsiMethodReferenceUtil { return true; } - public static boolean isReceiverType(@Nullable PsiClass aClass, @Nullable PsiClass containingClass) { - return InheritanceUtil.isInheritorOrSelf(aClass, containingClass, true); - } - - public static boolean isReceiverType(PsiType receiverType, @Nullable PsiClass containingClass, PsiSubstitutor psiSubstitutor) { - if (containingClass != null) { - receiverType = getExpandedType(receiverType, containingClass); + //if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as + // if it were a method invocation expression with argument expressions of types P2, ...,Pn. + public static boolean isReceiverType(@Nullable PsiType receiverType, PsiClass containingClass, PsiSubstitutor psiSubstitutor) { + if (receiverType == null) { + return false; } - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(receiverType); - final PsiClass receiverClass = resolveResult.getElement(); - if (receiverClass != null && isReceiverType(receiverClass, containingClass)) { - if (emptyOrRaw(containingClass, psiSubstitutor)) { - return true; - } - final PsiSubstitutor derivedSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, receiverClass, psiSubstitutor); - return derivedSubstitutor != null && TypeConversionUtil.isAssignable(JavaPsiFacade.getElementFactory(containingClass.getProject()).createType(containingClass, derivedSubstitutor), receiverType); - } - return false; + return TypeConversionUtil.isAssignable(JavaPsiFacade.getElementFactory(containingClass.getProject()).createType(containingClass, psiSubstitutor), + replaceArrayType(receiverType, containingClass)); } - private static boolean emptyOrRaw(PsiClass containingClass, PsiSubstitutor psiSubstitutor) { - return PsiUtil.isRawSubstitutor(containingClass, psiSubstitutor) || - psiSubstitutor.getSubstitutionMap().isEmpty(); - } - - public static boolean isReceiverType(PsiType functionalInterfaceType, PsiClass containingClass, @Nullable PsiMethod referencedMethod) { + public static PsiType getFirstParameterType(PsiType functionalInterfaceType, PsiElement context) { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final MethodSignature function = LambdaUtil.getFunction(resolveResult.getElement()); if (function != null) { final int interfaceMethodParamsLength = function.getParameterTypes().length; if (interfaceMethodParamsLength > 0) { - final PsiType firstParamType = resolveResult.getSubstitutor().substitute(function.getParameterTypes()[0]); - boolean isReceiver = isReceiverType(firstParamType, - containingClass, PsiUtil.resolveGenericsClassInType(firstParamType).getSubstitutor()); - if (isReceiver) { - if (referencedMethod == null){ - if (interfaceMethodParamsLength == 1) return true; - return false; - } - if (referencedMethod.getParameterList().getParametersCount() != interfaceMethodParamsLength - 1) { - return false; - } - return true; - } + PsiType type = resolveResult.getSubstitutor().substitute(function.getParameterTypes()[0]); + return type != null ? PsiUtil.captureToplevelWildcards(type, context) : null; } } - return false; + return null; } - private static PsiType getExpandedType(PsiType type, @NotNull PsiElement typeElement) { + private static PsiType replaceArrayType(PsiType type, @NotNull PsiElement context) { if (type instanceof PsiArrayType) { - type = JavaPsiFacade.getElementFactory(typeElement.getProject()) - .getArrayClassType(((PsiArrayType)type).getComponentType(), PsiUtil.getLanguageLevel(typeElement)); + type = JavaPsiFacade.getElementFactory(context.getProject()) + .getArrayClassType(((PsiArrayType)type).getComponentType(), PsiUtil.getLanguageLevel(context)); } return type; } @@ -282,8 +236,15 @@ public class PsiMethodReferenceUtil { isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC); isConstructor = method.isConstructor(); - receiverReferenced = hasReceiver(methodRef, method, functionalInterfaceType); - + + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); + receiverReferenced = isResolvedBySecondSearch(methodRef, + interfaceMethod != null ? interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)) : null, + method.isVarArgs(), + isMethodStatic, + method.getParameterList().getParametersCount()); + if (method.hasModifierProperty(PsiModifier.ABSTRACT) && qualifier instanceof PsiSuperExpression) { return "Abstract method '" + method.getName() + "' cannot be accessed directly"; } @@ -322,27 +283,6 @@ public class PsiMethodReferenceUtil { return null; } - public static boolean hasReceiver(@NotNull PsiMethodReferenceExpression methodRef, - @NotNull PsiMethod method) { - return hasReceiver(methodRef, method, methodRef.getFunctionalInterfaceType()); - } - - private static boolean hasReceiver(@NotNull PsiMethodReferenceExpression methodRef, - @NotNull PsiMethod method, - PsiType functionalInterfaceType) { - final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); - final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); - final MethodSignature signature = interfaceMethod != null ? interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)) : null; - if (signature == null) { - return false; - } - final PsiType[] parameterTypes = signature.getParameterTypes(); - final QualifierResolveResult qualifierResolveResult = getQualifierResolveResult(methodRef); - return (method.getParameterList().getParametersCount() + 1 == parameterTypes.length || - method.isVarArgs() && parameterTypes.length > 0 && !method.hasModifierProperty(PsiModifier.STATIC)) && - hasReceiver(parameterTypes, qualifierResolveResult, methodRef); - } - public static String checkTypeArguments(PsiTypeElement qualifier, PsiType psiType) { if (psiType instanceof PsiClassType) { final PsiJavaCodeReferenceElement referenceElement = qualifier.getInnermostComponentReferenceElement(); @@ -357,4 +297,38 @@ public class PsiMethodReferenceUtil { } return null; } + + public static String checkReturnType(PsiMethodReferenceExpression expression, JavaResolveResult result, PsiType functionalInterfaceType) { + final PsiElement resolve = result.getElement(); + if (resolve instanceof PsiMethod) { + final PsiClass containingClass = ((PsiMethod)resolve).getContainingClass(); + LOG.assertTrue(containingClass != null); + PsiSubstitutor subst = result.getSubstitutor(); + PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass(); + if (qContainingClass != null && isReceiverType(getFirstParameterType(functionalInterfaceType, expression), qContainingClass, subst)) { + subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst); + LOG.assertTrue(subst != null); + } + + + final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType); + + PsiType returnType = PsiTypesUtil.patchMethodGetClassReturnType(expression, expression, + (PsiMethod)resolve, null, + PsiUtil.getLanguageLevel(expression)); + if (returnType == null) { + returnType = ((PsiMethod)resolve).getReturnType(); + } + PsiType methodReturnType = subst.substitute(returnType); + if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) { + if (methodReturnType == null) { + methodReturnType = JavaPsiFacade.getElementFactory(expression.getProject()).createType(containingClass, subst); + } + if (!TypeConversionUtil.isAssignable(interfaceReturnType, methodReturnType, false)) { + return "Bad return type in method reference: cannot convert " + methodReturnType.getCanonicalText() + " to " + interfaceReturnType.getCanonicalText(); + } + } + } + return null; + } } diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index 063f2b81934e..8a63eabe16e2 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -116,48 +116,36 @@ public class MethodCandidateInfo extends CandidateInfo{ return getApplicabilityLevel(); } @ApplicabilityLevelConstant int level; - Integer boxedLevel = ourOverloadGuard.doPreventingRecursion(myArgumentList, false, new Computable() { - @Override - public Integer compute() { - if (PsiUtil.isLanguageLevel8OrHigher(myArgumentList)) { - PsiSubstitutor substitutor = getSubstitutor(false); - Map map = CURRENT_CANDIDATE.get(); - if (map == null) { - map = ContainerUtil.createConcurrentWeakMap(); - CURRENT_CANDIDATE.set(map); - } - final PsiMethod method = getElement(); - final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true); - final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties); - try { - PsiType[] argumentTypes = getArgumentTypes(); - if (argumentTypes == null) { - return ApplicabilityLevel.NOT_APPLICABLE; - } - - final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel); - if (!isVarargs() && applicabilityLevel < ApplicabilityLevel.FIXED_ARITY) { - return ApplicabilityLevel.NOT_APPLICABLE; - } - return applicabilityLevel; - } - finally { - if (alreadyThere == null) { - map.remove(getMarkerList()); - } else { - map.put(getMarkerList(), alreadyThere); - } - } - } - return getApplicabilityLevelInner(); + PsiSubstitutor substitutor = getSubstitutor(false); + Map map = CURRENT_CANDIDATE.get(); + if (map == null) { + map = ContainerUtil.createConcurrentWeakMap(); + CURRENT_CANDIDATE.set(map); + } + final PsiMethod method = getElement(); + final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true); + final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties); + try { + PsiType[] argumentTypes = getArgumentTypes(); + if (argumentTypes == null) { + return ApplicabilityLevel.NOT_APPLICABLE; } - }); - if (boxedLevel == null) { - return getApplicabilityLevel(); + level = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel); + if (!isVarargs() && level < ApplicabilityLevel.FIXED_ARITY) { + return ApplicabilityLevel.NOT_APPLICABLE; + } + } + finally { + if (alreadyThere == null) { + map.remove(getMarkerList()); + } else { + map.put(getMarkerList(), alreadyThere); + } + } + if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable(false)) { + level = ApplicabilityLevel.NOT_APPLICABLE; } - level = boxedLevel; - if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable(false)) level = ApplicabilityLevel.NOT_APPLICABLE; return level; } @@ -312,17 +300,17 @@ public class MethodCandidateInfo extends CandidateInfo{ public static CurrentCandidateProperties getCurrentMethod(PsiElement context) { + if (isOverloadCheck()) { + ourOverloadGuard.prohibitResultCaching(ourOverloadGuard.currentStack().get(0)); + } final Map currentMethodCandidates = CURRENT_CANDIDATE.get(); return currentMethodCandidates != null ? currentMethodCandidates.get(context) : null; } public static void updateSubstitutor(PsiElement context, PsiSubstitutor newSubstitutor) { - final Map currentMethodCandidates = CURRENT_CANDIDATE.get(); - if (currentMethodCandidates != null) { - final CurrentCandidateProperties properties = currentMethodCandidates.get(context); - if (properties != null) { - properties.setSubstitutor(newSubstitutor); - } + CurrentCandidateProperties candidateProperties = getCurrentMethod(context); + if (candidateProperties != null) { + candidateProperties.setSubstitutor(newSubstitutor); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java index 8ed59d42b629..389c9d3c23ee 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java @@ -396,8 +396,17 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList(); } }; - if (!varargs && staticFactoryMethod.isVarArgs() && staticFactoryCandidateInfo.getPertinentApplicabilityLevel() < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) { - return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true); + if (!varargs && staticFactoryMethod.isVarArgs()) { + final Computable computable = new Computable() { + @Override + public Integer compute() { + return staticFactoryCandidateInfo.getPertinentApplicabilityLevel(); + } + }; + final Integer applicability = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(expression, true, computable); + if ((applicability != null ? applicability : staticFactoryCandidateInfo.getApplicabilityLevel()) < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) { + return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true); + } } return staticFactoryCandidateInfo.getSubstitutor(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index 67143a7b73a5..2a03a31bb3ea 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -711,6 +712,10 @@ public class PsiClassImplUtil { @Nullable public static PsiClassType correctType(PsiClassType originalType, final GlobalSearchScope resolveScope) { + if (!Registry.is("java.correct.class.type.by.place.resolve.scope")) { + return originalType; + } + final PsiClassType.ClassResolveResult originalResolveResult = originalType.resolveGenerics(); PsiClass superClass = originalResolveResult.getElement(); if (superClass == null) { @@ -746,7 +751,7 @@ public class PsiClassImplUtil { } }); if (substitute == null) return null; - + substitutor = substitutor.put(typeParameters[i], substitute); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index bd9307e5a498..f03b12bb0ab5 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -1223,8 +1223,7 @@ public class InferenceSession { PsiImplUtil.normalizeWildcardTypeByPosition(pType, reference))); } } - else if (parameters.length + 1 == functionalMethodParameters.length && !varargs || - !isStatic && varargs && functionalMethodParameters.length > 0 && PsiMethodReferenceUtil.hasReceiver(reference, method)) { //instance methods + else if (PsiMethodReferenceUtil.isResolvedBySecondSearch(reference, signature, varargs, isStatic, parameters.length)) { //instance methods initBounds(containingClass.getTypeParameters()); final PsiType pType = signature.getParameterTypes()[0]; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java index 23460fbda4fc..cf974c91f980 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -18,10 +18,12 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Function; @@ -45,7 +47,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai } @Override - public boolean reduce(InferenceSession session, List constraints) { + public boolean reduce(final InferenceSession session, List constraints) { if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) { return true; } @@ -111,7 +113,12 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai } }); if (exceptions != null) { - thrownTypes.addAll(exceptions); + thrownTypes.addAll(ContainerUtil.filter(exceptions, new Condition() { + @Override + public boolean value(PsiClassType type) { + return session.isProperType(type) && InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_EXCEPTION); + } + })); } } } else { @@ -169,7 +176,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai private static boolean isAddressed(List expectedThrownTypes, PsiType thrownType) { for (PsiType expectedThrownType : expectedThrownTypes) { - if (TypeConversionUtil.isAssignable(expectedThrownType, thrownType)) { + if (TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(thrownType), expectedThrownType)) { return true; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java index 56674fa3952b..8acbda012894 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java @@ -16,10 +16,10 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy; import com.intellij.psi.impl.source.resolve.ResolveCache; -import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.ClassCandidateInfo; @@ -38,7 +38,6 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class MethodReferenceResolver implements ResolveCache.PolyVariantContextResolver { private static final Logger LOG = Logger.getInstance("#" + MethodReferenceResolver.class.getName()); @@ -214,14 +213,14 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR @Nullable @Override - public CandidateInfo resolveConflict(@NotNull List conflicts) { + protected CandidateInfo guardedOverloadResolution(@NotNull List conflicts) { if (mySignature == null) return null; if (conflicts.size() > 1) checkSameSignatures(conflicts); if (conflicts.size() > 1) checkAccessStaticLevels(conflicts, true); final PsiType[] argTypes = mySignature.getParameterTypes(); - boolean hasReceiver = PsiMethodReferenceUtil.hasReceiver(argTypes, myQualifierResolveResult, myReferenceExpression); + boolean hasReceiver = PsiMethodReferenceUtil.isSecondSearchPossible(argTypes, myQualifierResolveResult, myReferenceExpression); final List firstCandidates = new ArrayList(); final List secondCandidates = new ArrayList(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 2408bbba5bff..e640caf1f802 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; @@ -480,7 +479,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase PsiClass qContainingClass = PsiMethodReferenceUtil.getQualifierResolveResult(this).getContainingClass(); if (qContainingClass != null && containingClass != null && - PsiMethodReferenceUtil.isReceiverType(left, containingClass, (PsiMethod)resolve)) { + PsiMethodReferenceUtil.isReceiverType(PsiMethodReferenceUtil.getFirstParameterType(left, this), qContainingClass, subst)) { subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst); LOG.assertTrue(subst != null); } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 678011e4048d..ce4e29a6781e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JavaVersionService; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Computable; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.PsiSuperMethodImplUtil; @@ -68,7 +69,17 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } @Override - public CandidateInfo resolveConflict(@NotNull List conflicts){ + public final CandidateInfo resolveConflict(@NotNull final List conflicts){ + return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, true, new Computable() { + @Override + public CandidateInfo compute() { + return guardedOverloadResolution(conflicts); + } + }); + } + + @Nullable + protected CandidateInfo guardedOverloadResolution(@NotNull List conflicts) { if (conflicts.isEmpty()) return null; if (conflicts.size() == 1) return conflicts.get(0); diff --git a/java/java-tests/testData/codeInsight/completion/normal/InnerAnnotation.java b/java/java-tests/testData/codeInsight/completion/normal/InnerAnnotation.java new file mode 100644 index 000000000000..4fd5cc0138d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/InnerAnnotation.java @@ -0,0 +1,11 @@ +final class MyModule { + @Target({FIELD,PARAMETER,METHOD}) + @Retention(RUNTIME) + public static @interface Dependency { } +} + +final class SomeService { + + SomeService(@My) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/InnerAnnotation_after.java b/java/java-tests/testData/codeInsight/completion/normal/InnerAnnotation_after.java new file mode 100644 index 000000000000..9ad5271d6b8d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/InnerAnnotation_after.java @@ -0,0 +1,11 @@ +final class MyModule { + @Target({FIELD,PARAMETER,METHOD}) + @Retention(RUNTIME) + public static @interface Dependency { } +} + +final class SomeService { + + SomeService(@MyModule.Dependency) { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java new file mode 100644 index 000000000000..476d30ab3cf2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CheckedExceptionsConstraintsSubstitutions1.java @@ -0,0 +1,38 @@ +import java.io.IOException; + +class Test { + + interface B { + K l(K k) throws E; + } + + void bar(B b) {} + + T baz(T l) throws E { + return null; + } + + { + bar(l -> baz(l)); + bar(this::baz); + } +} +class Test1 { + + interface B { + K l(K k) throws E; + } + + void bar(B b) {} + + class MyEx extends Exception{} + + T baz(T l) throws E { + return null; + } + + { + bar(l -> baz(l)); + bar(this::baz); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA136759.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA136759.java new file mode 100644 index 000000000000..50348e48038c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA136759.java @@ -0,0 +1,19 @@ + +import java.util.function.Function; +import java.util.stream.Stream; + +class Test { + + public Long getKey() { + return 0L; + } + + public static void main(Stream stream) { + stream.map(s -> Inner.of(Test::getKey, s)); + } + + public static final class Inner { + public static Inner of(final Object key, final Test value) {return null;} + public static Inner of(final Function< T, Long> keyMapper, final Test value) {return null;} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/SecondSearchIfFirstParameterIsASubtypeOfReferenceTypeFromExpressionDeclaration.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/SecondSearchIfFirstParameterIsASubtypeOfReferenceTypeFromExpressionDeclaration.java new file mode 100644 index 000000000000..a0621c1726f7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/SecondSearchIfFirstParameterIsASubtypeOfReferenceTypeFromExpressionDeclaration.java @@ -0,0 +1,28 @@ +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; + +class Test { + + static class Base { + public BigDecimal getTotal() { + return null; + } + } + + public static void foo(List list, List list1) { + System.out.println(add(list, Base::getTotal)); + list1.forEach(Base::getTotal); + } + + + public static BigDecimal add(Collection objectsThatHaveBigDecimals, Function functionToGet) { + return objectsThatHaveBigDecimals == null ? null : objectsThatHaveBigDecimals.stream().map(functionToGet).reduce(null, Test::add); + } + + public static BigDecimal add(BigDecimal... sequence) { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/regression/IDEA136856.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/regression/IDEA136856.java new file mode 100644 index 000000000000..7b75b0feba20 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/regression/IDEA136856.java @@ -0,0 +1,43 @@ +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collector; + +class Test { + public static final Collector, Optional> toSingleton() { + return Collector.of( + AtomicReference::new, + (ref, v) -> { + if (!ref.compareAndSet(null, v) && v != null) { + throw new IllegalStateException("There is only one elvis."); + } + }, + (left, right) -> setOrFail(left, right.get()), + ref -> Optional.of(ref.get()) + ); + } + + public static final Collector, Optional> toSingleton1() { + return Collector.of( + AtomicReference::new, + (ref, v) -> setOrFail(ref, v), + (left, right) -> setOrFail(left, right.get()), + ref -> Optional.of(ref.get()) + ); + } + + public static final Collector, Optional> toSingleton2() { + return Collector.of( + AtomicReference::new, + Test::setOrFail, + (left, right) -> setOrFail(left, right.get()), + ref -> Optional.of(ref.get()) + ); + } + + private static final AtomicReference setOrFail(AtomicReference ref, T v) { + if (!ref.compareAndSet(null, v) && v != null) { + throw new IllegalStateException("There is only one elvis."); + } + return ref; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/regression/IDEA136887.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/regression/IDEA136887.java new file mode 100644 index 000000000000..6015c09a1c24 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/regression/IDEA136887.java @@ -0,0 +1,9 @@ +import java.util.Collection; +import java.util.function.ToIntFunction; +import java.util.stream.Collectors; + +class Test { + public static int sum(Collection collection, ToIntFunction mapper) { + return collection.stream().collect(Collectors.summingInt(mapper)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/CachedSubstitutionDuringOverloadResolution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/CachedSubstitutionDuringOverloadResolution.java new file mode 100644 index 000000000000..8c020ce0bfdb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/CachedSubstitutionDuringOverloadResolution.java @@ -0,0 +1,19 @@ + +import java.util.function.Function; +import java.util.stream.Stream; + +class Test { + + public Long getKey() { + return 0L; + } + + public static void main(Stream stream) { + stream.map(s -> Inner.of(Test::getKey, s)); + } + + public static final class Inner { + public static Inner of(final Object key, final Test value) {return null;} + public static Inner of(final Function< T, Long> keyMapper, final Test value) {return null;} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/SecondConflictResolution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/SecondConflictResolution.java new file mode 100644 index 000000000000..ac48bcb9dc8b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/SecondConflictResolution.java @@ -0,0 +1,21 @@ + +import java.util.*; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; + +abstract class Token { + + + private static B getMode(Optional> max){ + return max + .flatMap(e -> Optional.of(new B<>(Long.valueOf(e.getValue().longValue())))) + .get(); + } + + static class B { + public B(K k) {} + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateGetterSetterTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateGetterSetterTest.groovy index 50206caa0053..b27540c6a50d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateGetterSetterTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateGetterSetterTest.groovy @@ -122,6 +122,38 @@ class Foo { ''' } + public void "test nullable stuff"() { + myFixture.addClass("package org.jetbrains.annotations;\n" + + "public @interface NotNull {}") + myFixture.configureByText 'a.java', ''' +class Foo { + @org.jetbrains.annotations.NotNull + private String myName; + + +} +''' + generateGetter() + generateSetter() + myFixture.checkResult '''import org.jetbrains.annotations.NotNull; + +class Foo { + @org.jetbrains.annotations.NotNull + private String myName; + + public void setMyName(@NotNull String myName) { + this.myName = myName; + } + + @NotNull + public String getMyName() { + + return myName; + } +} +''' + } + private void generateGetter() { WriteCommandAction.runWriteCommandAction(getProject(), { new GenerateGetterHandler() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/MultipleModuleHighlightingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/MultipleModuleHighlightingTest.groovy index 05a14ef267f0..b02d90b6d596 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/MultipleModuleHighlightingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/MultipleModuleHighlightingTest.groovy @@ -25,7 +25,7 @@ import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase */ class MultipleModuleHighlightingTest extends JavaCodeInsightFixtureTestCase { - @Bombed(day = 1, month = Calendar.MARCH) + @Bombed(day = 1, month = Calendar.APRIL) public void "test use original place classpath for reference type resolving"() { addTwoModules() @@ -60,7 +60,7 @@ class Class3 { myFixture.checkHighlighting() } - @Bombed(day = 1, month = Calendar.MARCH) + @Bombed(day = 1, month = Calendar.APRIL) public void "test use original place classpath for new expression type resolving"() { addTwoModules() diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index d8abdbd5a9e8..0852028413bf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -932,6 +932,7 @@ public class ListUtils { public void testTabReplacesMethodNameWithLocalVariableName() throws Throwable { doTest('\t'); } public void testMethodParameterAnnotationClass() throws Throwable { doTest(); } + public void testInnerAnnotation() { doTest('\n'); } public void testPrimitiveCastOverwrite() throws Throwable { doTest '\t' } public void testClassReferenceInFor() throws Throwable { doTest ' ' } public void testClassReferenceInFor2() throws Throwable { doTest ' ' } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java index 64b013d44df7..2630d5f999a6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java @@ -16,7 +16,6 @@ package com.intellij.codeInsight.daemon.lambda; import com.intellij.JavaTestUtil; -import com.intellij.idea.Bombed; import com.intellij.psi.*; import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.ReferencesSearch; @@ -25,7 +24,6 @@ import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; -import java.util.Calendar; import java.util.Collection; public class FindFunctionalInterfaceTest extends LightCodeInsightFixtureTestCase { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8RegressionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8RegressionTest.java new file mode 100644 index 000000000000..e6934f2715e7 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Java8RegressionTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2015 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.codeInsight.daemon.lambda; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; +import com.intellij.openapi.projectRoots.JavaSdkVersion; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.testFramework.IdeaTestUtil; +import org.jetbrains.annotations.NonNls; + +public class Java8RegressionTest extends LightDaemonAnalyzerTestCase { + @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/regression"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + enableInspectionTool(new UnusedDeclarationInspection()); + } + + public void testIDEA136856() throws Exception { + doTest(); + } + + public void testIDEA136887() throws Exception { + doTest(); + } + + private void doTest() { + doTest(false); + } + + private void doTest(boolean warnings) { + IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable()); + doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false); + } + + @Override + protected Sdk getProjectJDK() { + return IdeaTestUtil.getMockJdk18(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index d53205a820cb..b43b21022946 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -17,14 +17,13 @@ package com.intellij.codeInsight.daemon.lambda; import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; -import com.intellij.idea.Bombed; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.testFramework.IdeaTestUtil; +import junit.framework.Test; +import junit.framework.TestSuite; import org.jetbrains.annotations.NonNls; -import java.util.Calendar; - public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/newLambda"; @@ -80,7 +79,6 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { public void testLiftedIntersectionType() { doTest(); } public void testInferenceFromReturnStatements() { doTest(); } public void testDownUpThroughLambdaReturnStatements() { doTest(); } - @Bombed(year = 2015, month = Calendar.MARCH, day = 30) public void testIDEA124547() { doTest(); } public void testIDEA118362() { doTest(); } public void testIDEA126056() { doTest(); } @@ -139,11 +137,14 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } - @Bombed(year = 2015, month = Calendar.MARCH, day = 30) public void testCheckedExceptionsConstraintsSubstitutions() throws Exception { doTest(); } + public void testCheckedExceptionsConstraintsSubstitutions1() throws Exception { + doTest(); + } + public void testCheckedExceptionsConstraintsSubstitutionsDeepInBody() throws Exception { doTest(); } @@ -168,7 +169,6 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } - @Bombed(year = 2015, month = Calendar.MARCH, day = 30) public void testIDEA127124() throws Exception { doTest(); } @@ -177,6 +177,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA136759() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } @@ -193,7 +197,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { /* public static Test suite() { final TestSuite suite = new TestSuite(); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 1000; i++) { suite.addTestSuite(NewLambdaHighlightingTest.class); } return suite; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index 60ad003549b3..dad206251e3e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -19,15 +19,12 @@ import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; -import com.intellij.idea.Bombed; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.testFramework.IdeaTestUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import java.util.Calendar; - public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef"; @@ -373,7 +370,6 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } - @Bombed(year = 2015, month = Calendar.MARCH, day = 30) public void testIDEA132379() throws Exception { doTest(); } @@ -386,6 +382,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(false); } + public void testSecondSearchIfFirstParameterIsASubtypeOfReferenceTypeFromExpressionDeclaration() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/TypeInference18Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/TypeInference18Test.java index 8a9a451c14da..04b261cedec8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/TypeInference18Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/TypeInference18Test.java @@ -21,6 +21,7 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.ResolveTestCase; @@ -30,6 +31,18 @@ public class TypeInference18Test extends ResolveTestCase { doTest(); } + public void testSecondConflictResolution() throws Exception { + doTestMethodCall(); + } + + public void testCachedSubstitutionDuringOverloadResolution() throws Exception { + PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java"); + assertNotNull(ref); + PsiMethodReferenceExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodReferenceExpression.class, false); + assertNotNull(methodCallExpression); + assertNotNull(methodCallExpression.resolve()); + } + private LanguageLevel myOldLanguageLevel; @Override @@ -46,6 +59,14 @@ public class TypeInference18Test extends ResolveTestCase { super.tearDown(); } + private void doTestMethodCall() throws Exception { + PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java"); + assertNotNull(ref); + PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodCallExpression.class); + assertNotNull(methodCallExpression); + assertNotNull(methodCallExpression.resolveMethod()); + } + private void doTest() throws Exception { PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java"); assertNotNull(ref); diff --git a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java index 8bf2fb1d4284..384fdc3eb339 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindManagerTest.java @@ -365,6 +365,19 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { assertSize(1, findUsages(findModel)); } + public void testNonSourceContent() throws Exception { + VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(createTempDirectory()); + PsiTestUtil.addContentRoot(myModule, root); + + createFile(myModule, root, "A.txt", "goo doo"); + + FindModel findModel = FindManagerTestUtils.configureFindModel("goo"); + findModel.setProjectScope(false); + findModel.setModuleName(myModule.getName()); + + assertSize(1, findUsages(findModel)); + } + public void testReplaceRegexp() { FindModel findModel = new FindModel(); findModel.setStringToFind("bug_(?=here)"); @@ -537,6 +550,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { findModel.setFromCursor(false); findModel.setGlobal(true); findModel.setMultipleFiles(true); + findModel.setCustomScope(true); ThrowableRunnable test = new ThrowableRunnable() { @Override @@ -573,6 +587,7 @@ public class FindManagerTest extends DaemonAnalyzerTestCase { VirtualFile file = tempDirFixture.createFile("a.txt", "foo bar foo"); FindModel findModel = FindManagerTestUtils.configureFindModel("foo"); findModel.setWholeWordsOnly(true); + findModel.setCustomScope(true); findModel.setCustomScope(new LocalSearchScope(PsiManager.getInstance(myProject).findFile(file))); assertSize(2, findUsages(findModel)); } diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java index 45c38a57154f..85bdf9c1398a 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaPredefinedConfigurations.java @@ -165,7 +165,7 @@ class JavaPredefinedConfigurations { createSearchTemplateInfo(SSRBundle.message("predefined.configuration.typed.symbol"),"'Symbol <'_GenericArgument+>", GENERICS_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.generic.casts"),"( '_Type <'_GenericArgument+> ) '_Expr", GENERICS_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.type.var.substitutions.in.intanceof.with.generic.types"),"'_Expr instanceof '_Type <'Substitutions+> ", GENERICS_TYPE), - createSearchTemplateInfo(SSRBundle.message("predefined.configuration.variables.of.generic.types"),"'_Type <'_GenericArgument+> 'Var = 'Init?;", GENERICS_TYPE), + createSearchTemplateInfo(SSRBundle.message("predefined.configuration.variables.of.generic.types"),"'_Type <'_GenericArgument+> 'Var = '_Init?;", GENERICS_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.diamond.operators"), "new 'ClassName<>('_Argument*)", GENERICS_TYPE), // Add comments and metadata @@ -226,7 +226,7 @@ class JavaPredefinedConfigurations { " public void ejbRemove();\n" + "}", J2EE_TYPE), createSearchTemplateInfoSimple(SSRBundle.message("predefined.configuration.ejb.interface"),"interface 'EjbInterface extends EJBObject {\n" + - " 'Type+ 'Method+('ParamType* 'ParamName*);\n" + + " '_Type+ '_Method+('_ParamType* '_ParamName*);\n" + "}", J2EE_TYPE), createSearchTemplateInfoSimple(SSRBundle.message("predefined.configuration.servlets"),"public class 'Servlet extends '_ParentClass:*HttpServlet {\n" + " public void '_InitServletMethod?:init ();\n" + @@ -243,19 +243,19 @@ class JavaPredefinedConfigurations { // Misc types createSearchTemplateInfo(SSRBundle.message("predefined.configuration.serializable.classes.and.their.serialization.implementation"), - "class '_Class implements '_Serializable:*Serializable {\n" + - " static final long 'VersionField?:serialVersionUID = '_VersionFieldInit?;\n" + + "class 'Class implements '_Serializable:*Serializable {\n" + + " static final long '_VersionField?:serialVersionUID = '_VersionFieldInit?;\n" + " private static final ObjectStreamField[] '_persistentFields?:serialPersistentFields = '_persistentFieldInitial?; \n" + - " private void 'SerializationWriteHandler?:writeObject (ObjectOutputStream '_stream) throws IOException;\n" + - " private void 'SerializationReadHandler?:readObject (ObjectInputStream '_stream2) throws IOException, ClassNotFoundException;\n" + - " Object 'SpecialSerializationReadHandler?:readResolve () throws ObjectStreamException;\n" + - " Object 'SpecialSerializationWriteHandler?:writeReplace () throws ObjectStreamException;\n" + + " private void '_SerializationWriteHandler?:writeObject (ObjectOutputStream '_stream) throws IOException;\n" + + " private void '_SerializationReadHandler?:readObject (ObjectInputStream '_stream2) throws IOException, ClassNotFoundException;\n" + + " Object '_SpecialSerializationReadHandler?:readResolve () throws ObjectStreamException;\n" + + " Object '_SpecialSerializationWriteHandler?:writeReplace () throws ObjectStreamException;\n" + "}",MISC_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.cloneable.implementations"), "class '_Class implements '_Interface:*Cloneable {\n" + " Object 'CloningMethod:*clone ();\n" + "}",MISC_TYPE), - createSearchTemplateInfoSimple(SSRBundle.message("predefined.configuration.]junit.test.cases"),"public class 'TestCase extends 'TestCaseClazz:*TestCase {\n" + + createSearchTemplateInfoSimple(SSRBundle.message("predefined.configuration.]junit.test.cases"),"public class 'TestCase extends '_TestCaseClazz:*TestCase {\n" + " public void '_testMethod+:test.* ();\n" + "}", MISC_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.singletons"),"class 'Class {\n" + @@ -285,7 +285,7 @@ class JavaPredefinedConfigurations { createSearchTemplateInfo(SSRBundle.message("predefined.configuration.symbol"),"'Symbol",INTERESTING_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.fields.variables.read"),"'Symbol:[read]",INTERESTING_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.fields_variables.with.given.name.pattern.updated"),"'Symbol:[regex( name ) && write]",INTERESTING_TYPE), - createSearchTemplateInfo(SSRBundle.message("predefined.configuration.usage.of.derived.type.in.cast"),"('CastType:*Base ) 'Expr",INTERESTING_TYPE), + createSearchTemplateInfo(SSRBundle.message("predefined.configuration.usage.of.derived.type.in.cast"),"('CastType:*[regex( Base )]) '_Expr",INTERESTING_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.boxing.in.declarations"),"'_Type:Object|Integer|Boolean|Long|Character|Short|Byte 'Var = '_Value:[exprtype( int|boolean|long|char|short|byte )]",INTERESTING_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.unboxing.in.declarations"),"'_Type:int|boolean|long|char|short|byte 'Var = '_Value:[exprtype( Integer|Boolean|Long|Character|Short|Byte )]",INTERESTING_TYPE), createSearchTemplateInfo(SSRBundle.message("predefined.configuration.boxing.in.method.calls"),"'_Instance?.'Call('_BeforeParam*,'_Param:[ exprtype( int|boolean|long|char|short|byte ) && formal( Object|Integer|Boolean|Long|Character|Short|Byte )],'_AfterParam*)",INTERESTING_TYPE), diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index c8dca645f698..467b18f1778c 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -1205,9 +1205,10 @@ public class JavaMatchingVisitor extends JavaElementVisitor { public void visitIfStatement(final PsiIfStatement if1) { final PsiIfStatement if2 = (PsiIfStatement)myMatchingVisitor.getElement(); + final PsiStatement elseBranch = if1.getElseBranch(); myMatchingVisitor.setResult(myMatchingVisitor.match(if1.getCondition(), if2.getCondition()) && compareBody(if1.getThenBranch(), if2.getThenBranch()) && - compareBody(if1.getElseBranch(), if2.getElseBranch())); + (elseBranch == null || compareBody(elseBranch, if2.getElseBranch()))); } @Override diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java index d116c3ce30fe..0861f1ec9e5c 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/TypeConversionDescriptor.java @@ -1,6 +1,7 @@ package com.intellij.refactoring.typeMigration; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiExpression; @@ -65,7 +66,9 @@ public class TypeConversionDescriptor extends TypeConversionDescriptorBase { if (getExpression() != null) expression = getExpression(); final Project project = expression.getProject(); final ReplaceOptions options = new ReplaceOptions(); - options.setMatchOptions(new MatchOptions()); + final MatchOptions matchOptions = new MatchOptions(); + matchOptions.setFileType(StdFileTypes.JAVA); + options.setMatchOptions(matchOptions); final Replacer replacer = new Replacer(project, null); try { final String replacement = replacer.testReplace(expression.getText(), getStringToReplace(), getReplaceByString(), options); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java index 84627a339de8..afb1f271a597 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java @@ -84,7 +84,7 @@ public class CompileScopeImpl extends CompileScope { @Override public boolean isAffected(BuildTarget target, @NotNull File file) { if (myFiles.isEmpty()) {//optimization - return true; + return isAffected(target); } final Set files = myFiles.get(target); return files != null && files.contains(file); diff --git a/lib/markdown4j-2.2.jar b/lib/markdown4j-2.2.jar new file mode 100644 index 000000000000..65030fa08205 Binary files /dev/null and b/lib/markdown4j-2.2.jar differ diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java index 00fa3f0f4cff..9fc611d6dbbc 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInsight.daemon; import com.intellij.openapi.components.ServiceManager; +import com.intellij.util.xmlb.annotations.OptionTag; import com.intellij.util.xmlb.annotations.Transient; public class DaemonCodeAnalyzerSettings { @@ -26,9 +26,9 @@ public class DaemonCodeAnalyzerSettings { public boolean NEXT_ERROR_ACTION_GOES_TO_ERRORS_FIRST = true; public int AUTOREPARSE_DELAY = 300; - public boolean SHOW_ADD_IMPORT_HINTS = true; + protected boolean myShowAddImportHints = true; public String NO_AUTO_IMPORT_PATTERN = "[a-z].?"; - public boolean SUPPRESS_WARNINGS = true; + protected boolean mySuppressWarnings = true; public boolean SHOW_METHOD_SEPARATORS = false; public int ERROR_STRIPE_MARK_MIN_HEIGHT = 2; public boolean SHOW_SMALL_ICONS_IN_GUTTER = true; @@ -38,21 +38,21 @@ public class DaemonCodeAnalyzerSettings { return false; } - @Transient + @OptionTag(value = "SHOW_ADD_IMPORT_HINTS") public boolean isImportHintEnabled() { - return SHOW_ADD_IMPORT_HINTS; + return myShowAddImportHints; } public void setImportHintEnabled(boolean isImportHintEnabled) { - SHOW_ADD_IMPORT_HINTS = isImportHintEnabled; + myShowAddImportHints = isImportHintEnabled; } - @Transient + @OptionTag(value = "SUPPRESS_WARNINGS") public boolean isSuppressWarnings() { - return SUPPRESS_WARNINGS; + return mySuppressWarnings; } public void setSuppressWarnings(boolean suppressWarnings) { - SUPPRESS_WARNINGS = suppressWarnings; + mySuppressWarnings = suppressWarnings; } } diff --git a/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java b/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java index 29a8905a45b9..6e313990e112 100644 --- a/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java +++ b/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java @@ -20,7 +20,6 @@ import com.intellij.idea.Main; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.lang.UrlClassLoader; import com.intellij.util.text.StringTokenizer; @@ -28,13 +27,10 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; import java.util.regex.Pattern; /** @@ -55,14 +51,14 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore { public static ClassLoader initClassLoader(boolean updatePlugins) throws MalformedURLException { PathManager.loadProperties(); - List classpath = new ArrayList(); + Collection classpath = new LinkedHashSet(); addParentClasspath(classpath); addIDEALibraries(classpath); addAdditionalClassPath(classpath); UrlClassLoader.Builder builder = UrlClassLoader.build() - .urls(filterClassPath(classpath)) - .allowLock() + .urls(filterClassPath(new ArrayList(classpath))) + .allowLock(false) .usePersistentClasspathIndexForLocalClassDirectories() .useCache(); if (Boolean.valueOf(System.getProperty(PROPERTY_ALLOW_BOOTSTRAP_RESOURCES, "true"))) { @@ -85,68 +81,35 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore { return newClassLoader; } - private static List filterClassPath(List classpathElements) { - String ignoreProperty = System.getProperty(PROPERTY_IGNORE_CLASSPATH); - if (ignoreProperty != null) { - Pattern pattern = Pattern.compile(ignoreProperty); - for (Iterator i = classpathElements.iterator(); i.hasNext(); ) { - String url = i.next().toExternalForm(); - if (pattern.matcher(url).matches()) { - i.remove(); - } - } - } - return classpathElements; - } - - private static void addParentClasspath(List classpathElements) throws MalformedURLException { + private static void addParentClasspath(Collection classpath) throws MalformedURLException { + List loaders = new ArrayList(2); for (ClassLoader loader = BootstrapClassLoaderUtil.class.getClassLoader(); loader != null; loader = loader.getParent()) { if (loader instanceof URLClassLoader) { - ContainerUtil.addAll(classpathElements, ((URLClassLoader)loader).getURLs()); + loaders.add(0, (URLClassLoader)loader); } else { - String loaderName = loader.getClass().getName(); - try { - Class antClassLoaderClass = Class.forName("org.apache.tools.ant.AntClassLoader"); - if (antClassLoaderClass.isInstance(loader) || - "org.apache.tools.ant.AntClassLoader".equals(loaderName) || - "org.apache.tools.ant.loader.AntClassLoader2".equals(loaderName)) { - String classpath = (String)antClassLoaderClass - .getDeclaredMethod("getClasspath", ArrayUtil.EMPTY_CLASS_ARRAY) - .invoke(loader, ArrayUtil.EMPTY_OBJECT_ARRAY); - StringTokenizer tokenizer = new StringTokenizer(classpath, File.separator, false); - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - classpathElements.add(new File(token).toURI().toURL()); - } - } - else { - getLogger().warn("Unknown class loader: " + loaderName); - } - } - catch (ClassCastException e) { getLogger().warn("Unknown class loader '" + loaderName + "'", e); } - catch (ClassNotFoundException e) { getLogger().warn("Unknown class loader '" + loaderName + "'", e); } - catch (NoSuchMethodException e) { getLogger().warn("Unknown class loader '" + loaderName + "'", e); } - catch (IllegalAccessException e) { getLogger().warn("Unknown class loader '" + loaderName + "'", e); } - catch (InvocationTargetException e) { getLogger().warn("Unknown class loader '" + loaderName + "'", e); } + getLogger().warn("Unknown class loader: " + loader.getClass().getName()); } } + for (URLClassLoader loader : loaders) { + ContainerUtil.addAll(classpath, loader.getURLs()); + } } - private static void addIDEALibraries(List classpathElements) throws MalformedURLException { + private static void addIDEALibraries(Collection classpath) throws MalformedURLException { Class aClass = BootstrapClassLoaderUtil.class; String selfRoot = PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"); assert selfRoot != null; URL selfRootUrl = new File(selfRoot).getAbsoluteFile().toURI().toURL(); - classpathElements.add(selfRootUrl); + classpath.add(selfRootUrl); File libFolder = new File(PathManager.getLibPath()); - addLibraries(classpathElements, libFolder, selfRootUrl); - addLibraries(classpathElements, new File(libFolder, "ext"), selfRootUrl); - addLibraries(classpathElements, new File(libFolder, "ant/lib"), selfRootUrl); + addLibraries(classpath, libFolder, selfRootUrl); + addLibraries(classpath, new File(libFolder, "ext"), selfRootUrl); + addLibraries(classpath, new File(libFolder, "ant/lib"), selfRootUrl); } - private static void addLibraries(List classPath, File fromDir, URL selfRootUrl) throws MalformedURLException { + private static void addLibraries(Collection classPath, File fromDir, URL selfRootUrl) throws MalformedURLException { File[] files = fromDir.listFiles(); if (files == null) return; @@ -160,16 +123,30 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore { } } - private static void addAdditionalClassPath(List classPath) { + private static void addAdditionalClassPath(Collection classpath) { try { StringTokenizer tokenizer = new StringTokenizer(System.getProperty(PROPERTY_ADDITIONAL_CLASSPATH, ""), File.pathSeparator, false); while (tokenizer.hasMoreTokens()) { String pathItem = tokenizer.nextToken(); - classPath.add(new File(pathItem).toURI().toURL()); + classpath.add(new File(pathItem).toURI().toURL()); } } catch (MalformedURLException e) { getLogger().error(e); } } + + private static List filterClassPath(List classpath) { + String ignoreProperty = System.getProperty(PROPERTY_IGNORE_CLASSPATH); + if (ignoreProperty != null) { + Pattern pattern = Pattern.compile(ignoreProperty); + for (Iterator i = classpath.iterator(); i.hasNext(); ) { + String url = i.next().toExternalForm(); + if (pattern.matcher(url).matches()) { + i.remove(); + } + } + } + return classpath; + } } diff --git a/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java b/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java index 2bd3099dbf65..3e71eb849bc5 100644 --- a/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java +++ b/platform/core-api/src/com/intellij/openapi/fileEditor/FileDocumentManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -23,27 +23,52 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Tracks the correspondence between {@link VirtualFile} instances and corresponding {@link Document} instances. + * Manages the saving of changes to disk. + */ public abstract class FileDocumentManager implements SavingRequestor { @NotNull public static FileDocumentManager getInstance() { return ApplicationManager.getApplication().getComponent(FileDocumentManager.class); } + /** + * Returns the document for the specified virtual file. + * @param file the file for which the document is requested. + * @return the document, or null if the file represents a directory, or is binary without an associated decompiler, + * or is too large. + */ @Nullable public abstract Document getDocument(@NotNull VirtualFile file); + /** + * Returns the document for the specified file which has already been loaded into memory. + * + * @param file the file for which the document is requested. + * @return the document, or null if the specified virtual file hasn't been loaded into memory. + */ @Nullable public abstract Document getCachedDocument(@NotNull VirtualFile file); + /** + * Returns the virtual file corresponding to the specified document. + * + * @param document the document for which the virtual file is requested. + * @return the file, or null if the document wasn't created from a virtual file. + */ @Nullable public abstract VirtualFile getFile(@NotNull Document document); /** - * This operation can modify documents that will be saved (due to 'Trip trailing spaces on Save' functionality). + * Saves all unsaved documents to disk. This operation can modify documents that will be saved + * (due to 'Strip trailing spaces on Save' functionality). */ public abstract void saveAllDocuments(); + /** - * This operation can modify the document (due to 'Trip trailing spaces on Save' functionality). + * Saves the specified document to disk. This operation can modify the document (due to 'Strip + * trailing spaces on Save' functionality). */ public abstract void saveDocument(@NotNull Document document); @@ -52,12 +77,35 @@ public abstract class FileDocumentManager implements SavingRequestor { * @param document the document to save. */ public abstract void saveDocumentAsIs(@NotNull Document document); - + + /** + * Returns the ist of all documents that have unsaved changes. + * @return the documents that have unsaved changes. + */ @NotNull public abstract Document[] getUnsavedDocuments(); + + /** + * Checks if the document has unsaved changes. + * + * @param document the document to check. + * @return true if the document has unsaved changes, false otherwise. + */ public abstract boolean isDocumentUnsaved(@NotNull Document document); + + /** + * Checks if the document corresponding to the specified file has unsaved changes. + * + * @param file the file to check. + * @return true if the file has unsaved changes, false otherwise. + */ public abstract boolean isFileModified(@NotNull VirtualFile file); + /** + * Discards unsaved changes for the specified document and reloads it from disk. + * + * @param document the document to reload. + */ public abstract void reloadFromDisk(@NotNull Document document); @NotNull @@ -77,5 +125,10 @@ public abstract class FileDocumentManager implements SavingRequestor { return getInstance().requestWriting(document, project); } + /** + * Discards unsaved changes for the specified files. + * + * @param files the files to discard the changes for. + */ public abstract void reloadFiles(@NotNull VirtualFile... files); } diff --git a/platform/core-api/src/com/intellij/openapi/project/DumbService.java b/platform/core-api/src/com/intellij/openapi/project/DumbService.java index 68ca99133e46..efd18fbf8805 100644 --- a/platform/core-api/src/com/intellij/openapi/project/DumbService.java +++ b/platform/core-api/src/com/intellij/openapi/project/DumbService.java @@ -21,6 +21,7 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.NotNullLazyKey; import com.intellij.openapi.util.Ref; import com.intellij.util.messages.Topic; @@ -37,9 +38,6 @@ import java.util.List; * A service managing IDEA's 'dumb' mode: when indices are updated in background and the functionality is very much limited. * Only the explicitly allowed functionality is available. Usually it's allowed by implementing {@link DumbAware} interface. * - * If you want to register a toolwindow, which will be enabled during the dumb mode, please use {@link com.intellij.openapi.wm.ToolWindowManager}'s - * registration methods which have 'canWorkInDumMode' parameter. - * * @author peter */ public abstract class DumbService { @@ -50,6 +48,11 @@ public abstract class DumbService { */ public static final Topic DUMB_MODE = new Topic("dumb mode", DumbModeListener.class); + /** + * The tracker is advanced each time we enter/exit from dumb mode. + */ + public abstract ModificationTracker getModificationTracker(); + /** * @return whether IntelliJ IDEA is in dumb mode, which means that right now indices are updated in background. * IDEA offers only limited functionality at such times, e.g. plain text file editing and version control operations. diff --git a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java index d05b11e47de1..36299685bc51 100644 --- a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -29,6 +29,13 @@ import java.util.EventListener; * Manages the relationship between documents and PSI trees. */ public abstract class PsiDocumentManager { + /** + * Checks if the PSI tree for the specified document is up to date (its state reflects the latest changes made + * to the document content). + * + * @param document the document to check. + * @return true if the PSI tree for the document is up to date, false otherwise. + */ public abstract boolean isCommitted(@NotNull Document document); /** @@ -206,8 +213,22 @@ public abstract class PsiDocumentManager { */ public abstract void removeListener(@NotNull Listener listener); + /** + * Checks if the PSI tree corresponding to the specified document has been modified and the changes have not + * yet been applied to the document. Documents in that state cannot be modified directly, because such changes + * would conflict with the pending PSI changes. Changes made through PSI are always applied in the end of a write action, + * and can be applied in the middle of a write action by calling {@link #doPostponedOperationsAndUnblockDocument}. + * + * @param doc the document to check. + * @return true if the corresponding PSI has changes that haven't been applied to the document. + */ public abstract boolean isDocumentBlockedByPsi(@NotNull Document doc); + /** + * Applies pending changes made through the PSI to the specified document. + * + * @param doc the document to apply the changes to. + */ public abstract void doPostponedOperationsAndUnblockDocument(@NotNull Document doc); /** diff --git a/platform/core-api/src/com/intellij/psi/PsiFile.java b/platform/core-api/src/com/intellij/psi/PsiFile.java index 4a4cf92c965e..3f052ae59243 100644 --- a/platform/core-api/src/com/intellij/psi/PsiFile.java +++ b/platform/core-api/src/com/intellij/psi/PsiFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,7 +19,6 @@ import com.intellij.lang.FileASTNode; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * A PSI element representing a file. @@ -101,5 +100,9 @@ public interface PsiFile extends PsiFileSystemItem { @Override FileASTNode getNode(); + /** + * Called by the PSI framework when the contents of the file changes. Can be used to invalidate + * file-level caches. If you override this method, you must call the base class implementation. + */ void subtreeChanged(); } diff --git a/platform/core-impl/src/com/intellij/mock/MockDumbService.java b/platform/core-impl/src/com/intellij/mock/MockDumbService.java index b1fe7ae2a727..e97a9f64c7f3 100644 --- a/platform/core-impl/src/com/intellij/mock/MockDumbService.java +++ b/platform/core-impl/src/com/intellij/mock/MockDumbService.java @@ -22,6 +22,8 @@ import com.intellij.openapi.project.DumbModeTask; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.ModificationTracker; +import com.intellij.openapi.util.SimpleModificationTracker; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -36,6 +38,11 @@ public class MockDumbService extends DumbService { myProject = project; } + @Override + public ModificationTracker getModificationTracker() { + return new SimpleModificationTracker(); + } + @Override public boolean isDumb() { return false; diff --git a/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java index b71a7e5e4f78..816ea9595797 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java @@ -26,7 +26,6 @@ import com.intellij.diff.tools.external.ExternalDiffTool; import com.intellij.diff.tools.fragmented.OnesideDiffTool; import com.intellij.diff.tools.simple.SimpleDiffTool; import com.intellij.openapi.Disposable; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import org.jetbrains.annotations.NotNull; @@ -34,11 +33,10 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class DiffManagerImpl extends DiffManagerEx { - private static final Logger LOG = Logger.getInstance(DiffManagerImpl.class); - @Override public void showDiff(@Nullable Project project, @NotNull DiffRequest request) { showDiff(project, request, DiffDialogHints.DEFAULT); @@ -88,16 +86,11 @@ public class DiffManagerImpl extends DiffManagerEx { @Override public List getDiffTools() { List result = new ArrayList(); - result.add(SimpleDiffTool.INSTANCE); result.add(OnesideDiffTool.INSTANCE); result.add(BinaryDiffTool.INSTANCE); result.add(DirDiffTool.INSTANCE); - - for (DiffTool tool : DiffTool.EP_NAME.getExtensions()) { - result.add(tool); - } - + Collections.addAll(result, DiffTool.EP_NAME.getExtensions()); return result; } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java index 2e321952643a..4e00df7f1e41 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java @@ -42,8 +42,31 @@ public class CompareFilesAction extends BaseShowDiffAction { VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); - String text = getTemplatePresentation().getText(); - if (files != null && files.length == 1) text += "..."; + String text = "Compare Files"; + if (files != null && files.length == 1) { + text = "Compare With..."; + } + else if (files != null && files.length == 2) { + Type type1 = getType(files[0]); + Type type2 = getType(files[1]); + + if (type1 != type2) { + text = "Compare"; + } + else { + switch (type1) { + case FILE: + text = "Compare Files"; + break; + case DIRECTORY: + text = "Compare Directories"; + break; + case ARCHIEVE: + text = "Compare Archieves"; + break; + } + } + } e.getPresentation().setText(text); } @@ -93,7 +116,9 @@ public class CompareFilesAction extends BaseShowDiffAction { private static VirtualFile getOtherFile(@Nullable Project project, @NotNull VirtualFile file) { FileChooserDescriptor descriptor; String key; - if (file.isDirectory() || file.getFileType() instanceof ArchiveFileType) { + + Type type = getType(file); + if (type == Type.DIRECTORY || type == Type.ARCHIEVE) { descriptor = new FileChooserDescriptor(false, true, true, false, false, false); key = LAST_USED_FOLDER_KEY; } @@ -121,4 +146,14 @@ public class CompareFilesAction extends BaseShowDiffAction { if (project == null) return; PropertiesComponent.getInstance(project).setValue(key, file.getPath()); } + + @NotNull + private static Type getType(@Nullable VirtualFile file) { + if (file == null) return Type.FILE; + if (file.isDirectory()) return Type.DIRECTORY; + if (file.getFileType() instanceof ArchiveFileType) return Type.ARCHIEVE; + return Type.FILE; + } + + private enum Type {FILE, DIRECTORY, ARCHIEVE} } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/ErrorDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/ErrorDiffTool.java index dd0a87dd7dfc..dc0b4fae73ea 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/ErrorDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/ErrorDiffTool.java @@ -44,7 +44,7 @@ public class ErrorDiffTool implements FrameDiffTool { @NotNull @Override public String getName() { - return "Error Viewer"; + return "Error viewer"; } private static class MyViewer implements DiffViewer { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java index 542ce0779bc4..a3fe98a865a4 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java @@ -37,6 +37,6 @@ public class BinaryDiffTool implements FrameDiffTool { @NotNull @Override public String getName() { - return "Binary File Viewer"; + return "Binary file viewer"; } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/dir/DifDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/dir/DifDiffViewer.java index 98786884cb1d..b362604c5f96 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/dir/DifDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/dir/DifDiffViewer.java @@ -23,17 +23,21 @@ import com.intellij.diff.contents.EmptyContent; import com.intellij.diff.contents.FileContent; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; +import com.intellij.ide.DataManager; import com.intellij.ide.diff.DiffElement; import com.intellij.ide.diff.DirDiffSettings; import com.intellij.ide.diff.JarFileDiffElement; import com.intellij.ide.diff.VirtualFileDiffElement; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diff.impl.dir.DirDiffFrame; import com.intellij.openapi.diff.impl.dir.DirDiffPanel; import com.intellij.openapi.diff.impl.dir.DirDiffTableModel; import com.intellij.openapi.diff.impl.dir.DirDiffWindow; import com.intellij.openapi.util.Disposer; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,7 +50,8 @@ class DifDiffViewer implements FrameDiffTool.DiffViewer { @NotNull private final DiffContext myContext; @NotNull private final ContentDiffRequest myRequest; - @NotNull private final DirDiffPanel myPanel; + @NotNull private final DirDiffPanel myDirDiffPanel; + @NotNull private final JPanel myPanel; public DifDiffViewer(@NotNull DiffContext context, @NotNull ContentDiffRequest request) { myContext = context; @@ -57,7 +62,7 @@ class DifDiffViewer implements FrameDiffTool.DiffViewer { DiffElement element2 = createDiffElement(contents.get(1)); DirDiffTableModel model = new DirDiffTableModel(context.getProject(), element1, element2, new DirDiffSettings()); - myPanel = new DirDiffPanel(model, new DirDiffWindow((DirDiffFrame)null) { + myDirDiffPanel = new DirDiffPanel(model, new DirDiffWindow((DirDiffFrame)null) { @Override public Window getWindow() { return null; @@ -72,31 +77,43 @@ class DifDiffViewer implements FrameDiffTool.DiffViewer { public void setTitle(String title) { } }); + + myPanel = new JPanel(new BorderLayout()); + myPanel.add(myDirDiffPanel.getPanel(), BorderLayout.CENTER); + DataManager.registerDataProvider(myPanel, new DataProvider() { + @Override + public Object getData(@NonNls String dataId) { + if (PlatformDataKeys.HELP_ID.is(dataId)) { + return "reference.dialogs.diff.folder"; + } + return null; + } + }); } @NotNull @Override public FrameDiffTool.ToolbarComponents init() { - myPanel.setupSplitter(); + myDirDiffPanel.setupSplitter(); return new FrameDiffTool.ToolbarComponents(); } @Override public void dispose() { - Disposer.dispose(myPanel); + Disposer.dispose(myDirDiffPanel); } @NotNull @Override public JComponent getComponent() { - return myPanel.getPanel(); + return myPanel; } @Nullable @Override public JComponent getPreferredFocusedComponent() { - return myPanel.getTable(); + return myDirDiffPanel.getTable(); } // diff --git a/platform/diff-impl/src/com/intellij/diff/tools/dir/DirDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/dir/DirDiffTool.java index 4bdf3d29256f..8e5261256707 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/dir/DirDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/dir/DirDiffTool.java @@ -38,6 +38,6 @@ public class DirDiffTool implements FrameDiffTool { @NotNull @Override public String getName() { - return "Directory Viewer"; + return "Directory viewer"; } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffTool.java index b94dbefc2b54..881099ae5f91 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffTool.java @@ -37,6 +37,6 @@ public class OnesideDiffTool implements FrameDiffTool { @NotNull @Override public String getName() { - return "Oneside Viewer"; + return "Oneside viewer"; } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffTool.java index 8e450792cb30..00ad0ec846e3 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffTool.java @@ -38,6 +38,6 @@ public class SimpleDiffTool implements FrameDiffTool { @NotNull @Override public String getName() { - return "Default Viewer"; + return "Default viewer"; } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/HighlightPolicy.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/HighlightPolicy.java index 69938f66fdad..919832f93386 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/HighlightPolicy.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/HighlightPolicy.java @@ -18,10 +18,10 @@ package com.intellij.diff.tools.util.base; import org.jetbrains.annotations.NotNull; public enum HighlightPolicy { - DO_NOT_HIGHLIGHT("Do Not Highlight"), - BY_LINE("By Line"), - BY_WORD("By Word"), - BY_WORD_SPLIT("By Word In Chunks"); + DO_NOT_HIGHLIGHT("Do not highlight"), + BY_LINE("Highlight words"), + BY_WORD("Highlight lines"), + BY_WORD_SPLIT("Highlight split changes"); @NotNull private final String myText; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/IgnorePolicy.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/IgnorePolicy.java index a2317b3489ed..8c38a2af350c 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/IgnorePolicy.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/IgnorePolicy.java @@ -19,10 +19,10 @@ import com.intellij.diff.comparison.ComparisonPolicy; import org.jetbrains.annotations.NotNull; public enum IgnorePolicy { - DEFAULT("Do Not Ignore"), - TRIM_WHITESPACES("Trim Whitespaces"), - IGNORE_WHITESPACES("Ignore Whitespaces"), - IGNORE_WHITESPACES_CHUNKS("Ignore Whitespaces And Empty Lines"); + DEFAULT("Do not ignore"), + TRIM_WHITESPACES("Trim whitespaces"), + IGNORE_WHITESPACES("Ignore whitespaces"), + IGNORE_WHITESPACES_CHUNKS("Ignore whitespaces and empty lines"); @NotNull private final String myText; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.java index a583068b2668..f73a10053abe 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.java @@ -31,15 +31,15 @@ import java.util.Map; @State( name = "TextDiffSettings", - storages = {@Storage( - file = DiffUtil.DIFF_CONFIG)}) + storages = @Storage(file = DiffUtil.DIFF_CONFIG) +) public class TextDiffSettingsHolder implements PersistentStateComponent { public static final Key KEY = Key.create("TextDiffSettings"); public static final int[] CONTEXT_RANGE_MODES = {1, 2, 4, 8, -1}; public static final String[] CONTEXT_RANGE_MODE_LABELS = {"1", "2", "4", "8", "Disable"}; - private static class SharedSettings { + private final static class SharedSettings { // Fragments settings public int CONTEXT_RANGE = 4; } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java index 9f10311f68d3..a3e6cdab3d03 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsPlatformFacadeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,7 +16,6 @@ package com.intellij.dvcs; import com.intellij.ide.SaveAndSyncHandler; -import com.intellij.ide.SaveAndSyncHandlerImpl; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.application.ApplicationManager; @@ -133,7 +132,7 @@ public abstract class DvcsPlatformFacadeImpl implements DvcsPlatformFacade { @NotNull @Override public SaveAndSyncHandler getSaveAndSyncHandler() { - return SaveAndSyncHandlerImpl.getInstance(); + return SaveAndSyncHandler.getInstance(); } @Override diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java index 055fbc8ca6d7..d2f9b41fde60 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java @@ -184,7 +184,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS public static class FontFilter implements SerializationFilter { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { UISettings settings = (UISettings)bean; return !hasDefaultFontSetting(settings); } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java index f1daae220d85..91f363684185 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalProjectSettingsControl.java @@ -40,12 +40,23 @@ public abstract class AbstractExternalProjectSettingsControl filesMap) { - ExportToHTMLSettings exportToHTMLSettings = ExportToHTMLSettings.getInstance(project); + private static boolean exportPsiFile(final PsiFile psiFile, + final String outputDirectoryName, + final Project project, + final HashMap filesMap) { + final ExportToHTMLSettings exportToHTMLSettings = ExportToHTMLSettings.getInstance(project); if (psiFile instanceof PsiBinaryFile) { return true; } - TreeMap refMap = null; - for (PrintOption printOption : Extensions.getExtensions(PrintOption.EP_NAME)) { - final TreeMap map = printOption.collectReferences(psiFile, filesMap); - if (map != null) { - refMap = new TreeMap(); - refMap.putAll(map); - } - } + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + TreeMap refMap = null; + for (PrintOption printOption : Extensions.getExtensions(PrintOption.EP_NAME)) { + final TreeMap map = printOption.collectReferences(psiFile, filesMap); + if (map != null) { + refMap = new TreeMap(); + refMap.putAll(map); + } + } - String dirName = constructOutputDirectory(psiFile, outputDirectoryName); - HTMLTextPainter textPainter = new HTMLTextPainter(psiFile, project, dirName, exportToHTMLSettings.PRINT_LINE_NUMBERS); - try { - textPainter.paint(refMap, psiFile.getFileType()); - } - catch (FileNotFoundException e) { - myLastException = e; - return false; - } - return true; + String dirName = constructOutputDirectory(psiFile, outputDirectoryName); + HTMLTextPainter textPainter = new HTMLTextPainter(psiFile, project, dirName, exportToHTMLSettings.PRINT_LINE_NUMBERS); + try { + textPainter.paint(refMap, psiFile.getFileType()); + } + catch (FileNotFoundException e) { + myLastException = e; + } + } + }); + return myLastException == null; } private static String constructOutputDirectory(PsiFile psiFile, String outputDirectoryName) { @@ -241,11 +249,18 @@ class ExportToHTMLManager { final ArrayList filesList = new ArrayList(); final boolean isRecursive = myExportToHTMLSettings.isIncludeSubdirectories(); - try { - addToPsiFileList(myPsiDirectory, filesList, isRecursive, myOutputDirectoryName); - } - catch (FileNotFoundException e) { - myLastException = e; + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + try { + addToPsiFileList(myPsiDirectory, filesList, isRecursive, myOutputDirectoryName); + } + catch (FileNotFoundException e) { + myLastException = e; + } + } + }); + if (myLastException != null) { return; } HashMap filesMap = new HashMap(); diff --git a/platform/lang-impl/src/com/intellij/codeEditor/printing/FileSeparatorProvider.java b/platform/lang-impl/src/com/intellij/codeEditor/printing/FileSeparatorProvider.java index 1a1d7b0a43c1..31ec50c83606 100644 --- a/platform/lang-impl/src/com/intellij/codeEditor/printing/FileSeparatorProvider.java +++ b/platform/lang-impl/src/com/intellij/codeEditor/printing/FileSeparatorProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -21,21 +21,32 @@ package com.intellij.codeEditor.printing; import com.intellij.codeInsight.daemon.LineMarkerInfo; -import com.intellij.openapi.components.ServiceManager; +import com.intellij.codeInsight.daemon.impl.LineMarkersPass; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; public class FileSeparatorProvider { - public static FileSeparatorProvider getInstance() { - return ServiceManager.getService(FileSeparatorProvider.class); - } - @Nullable - public List getFileSeparators(PsiFile file, final Document document, @Nullable final Editor editor) { - return null; + public static List getFileSeparators(PsiFile file, final Document document) { + final List result = new ArrayList(); + LineMarkersPass pass = new LineMarkersPass(file.getProject(), file, null, document, file.getTextRange()); + for (LineMarkerInfo lineMarkerInfo : pass.queryLineMarkers()) { + if (lineMarkerInfo.separatorColor != null) { + result.add(lineMarkerInfo); + } + } + + Collections.sort(result, new Comparator() { + public int compare(final LineMarkerInfo i1, final LineMarkerInfo i2) { + return i1.startOffset - i2.startOffset; + } + }); + return result; } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeEditor/printing/HTMLTextPainter.java b/platform/lang-impl/src/com/intellij/codeEditor/printing/HTMLTextPainter.java index 22e365cc5a4f..ccb474bcadcf 100644 --- a/platform/lang-impl/src/com/intellij/codeEditor/printing/HTMLTextPainter.java +++ b/platform/lang-impl/src/com/intellij/codeEditor/printing/HTMLTextPainter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -35,7 +35,6 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.file.PsiDirectoryFactory; -import com.intellij.psi.util.PsiUtilBase; import com.intellij.ui.JBColor; import org.jetbrains.annotations.NonNls; @@ -86,8 +85,7 @@ class HTMLTextPainter { ArrayList methodSeparators = new ArrayList(); if (document != null) { - final List separators = FileSeparatorProvider.getInstance().getFileSeparators(psiFile, document, - PsiUtilBase.findEditor(psiFile)); + final List separators = FileSeparatorProvider.getFileSeparators(psiFile, document); if (separators != null) { methodSeparators.addAll(separators); } diff --git a/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java b/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java index 7c84f5e637aa..801bfdc5f819 100644 --- a/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java +++ b/platform/lang-impl/src/com/intellij/codeEditor/printing/TextPainter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -100,7 +100,7 @@ class TextPainter extends BasePainter { FileType fileType, Editor editor) { this(editorDocument, highlighter, fullFileName, shortFileName, psiFile.getProject(), fileType, - FileSeparatorProvider.getInstance().getFileSeparators(psiFile, editorDocument, editor)); + FileSeparatorProvider.getFileSeparators(psiFile, editorDocument)); } public TextPainter(@NotNull DocumentEx editorDocument, diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form index b6e07f4c8a5b..3c6a16512e86 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form @@ -107,7 +107,7 @@ - + diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java index 6dc2971b800c..cd0a9c0890f2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java @@ -51,6 +51,7 @@ public class LayoutCodeDialog extends DialogWrapper { private JPanel myActionsPanel; private JPanel myScopePanel; + private JLabel myOptionalLabel; private LayoutCodeOptions myRunOptions; @@ -127,6 +128,8 @@ public class LayoutCodeDialog extends DialogWrapper { if (canRearrangeCode) { myRearrangeCodeCb.setSelected(myLastRunOptions.isRearrangeCode(myFile.getLanguage())); } + + myOptionalLabel.setVisible(canOptimizeImports || canRearrangeCode); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettingsImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettingsImpl.java index d4889a97f802..0334f18b0931 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettingsImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettingsImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,13 +24,13 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManagerImpl; -import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; +import com.intellij.util.xmlb.SkipDefaultsSerializationFilter; import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; @State( name = "DaemonCodeAnalyzerSettings", - storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/editor.codeinsight.xml")} + storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/editor.codeinsight.xml") ) public class DaemonCodeAnalyzerSettingsImpl extends DaemonCodeAnalyzerSettings implements PersistentStateComponent, Cloneable { @Override @@ -42,7 +42,7 @@ public class DaemonCodeAnalyzerSettingsImpl extends DaemonCodeAnalyzerSettings i public DaemonCodeAnalyzerSettingsImpl clone() { DaemonCodeAnalyzerSettingsImpl settings = new DaemonCodeAnalyzerSettingsImpl(); settings.AUTOREPARSE_DELAY = AUTOREPARSE_DELAY; - settings.SHOW_ADD_IMPORT_HINTS = SHOW_ADD_IMPORT_HINTS; + settings.myShowAddImportHints = myShowAddImportHints; settings.SHOW_METHOD_SEPARATORS = SHOW_METHOD_SEPARATORS; settings.NO_AUTO_IMPORT_PATTERN = NO_AUTO_IMPORT_PATTERN; settings.SHOW_SMALL_ICONS_IN_GUTTER = SHOW_SMALL_ICONS_IN_GUTTER; @@ -51,7 +51,7 @@ public class DaemonCodeAnalyzerSettingsImpl extends DaemonCodeAnalyzerSettings i @Override public Element getState() { - Element element = XmlSerializer.serialize(this, new SkipDefaultValuesSerializationFilters()); + Element element = XmlSerializer.serialize(this, new SkipDefaultsSerializationFilter()); String profile = InspectionProfileManager.getInstance().getRootProfile().getName(); if (!"Default".equals(profile)) { element.setAttribute("profile", profile); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java index 6ae363f52f7e..e67c63bb7a50 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java @@ -109,7 +109,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM myMarkers = mergeLineMarkers(lineMarkers, myEditor); } - static List mergeLineMarkers(@NotNull List markers, Editor editor) { + static List mergeLineMarkers(@NotNull List markers, @Nullable Editor editor) { List forMerge = new ArrayList(); final Iterator iterator = markers.iterator(); while (iterator.hasNext()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java index da055a4d1044..9020b07c22c9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -40,6 +40,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.actions.EditorActionUtil; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; @@ -78,7 +79,8 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { @NotNull public static List getAvailableActions(@NotNull final Editor editor, @NotNull final PsiFile file, final int passId) { - final int offset = editor.getCaretModel().getOffset(); + final Integer expectedCaretOffset = editor.getUserData(EditorActionUtil.EXPECTED_CARET_OFFSET); + final int offset = expectedCaretOffset != null ? expectedCaretOffset : editor.getCaretModel().getOffset(); final Project project = file.getProject(); final List result = new ArrayList(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java index b6f951efb865..449f0865f793 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java @@ -356,7 +356,7 @@ public class EnterHandler extends BaseEnterHandler { commentContext.docStart = false; } else { - commentContext.docAsterisk = true; + commentContext.docAsterisk = CodeStyleSettingsManager.getSettings(getProject()).JD_LEADING_ASTERISKS_ARE_ENABLED; commentContext.docStart = false; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java index c7c05dc68d74..3f644c04fd39 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java @@ -452,12 +452,10 @@ public class TemplateSettings implements PersistentStateComponent BUTTON_KEY = Key.create("COMBOBOX_BUTTON"); public static final Icon CHECKED_ICON = new SizedIcon(AllIcons.Actions.Checked, 16, 16); public static final Icon CHECKED_SELECTED_ICON = new SizedIcon(AllIcons.Actions.Checked_selected, 16, 16); public static final Icon EMPTY_ICON = EmptyIcon.ICON_16; @Override - public void actionPerformed(final AnActionEvent e) { - final IdeFrame ideFrame = findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)); - final ComboBoxButton button = (ComboBoxButton)ideFrame.getComponent().getRootPane().getClientProperty(BUTTON_KEY); + public void actionPerformed(AnActionEvent e) { + ComboBoxButton button = (ComboBoxButton)e.getPresentation().getClientProperty(CUSTOM_COMPONENT_PROPERTY); if (button == null || !button.isShowing()) return; button.showPopup(); } - private static IdeFrame findFrame(final Component component) { - return UIUtil.getParentOfType(IdeFrame.class, component); - } - @Override - public void update(final AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - final Project project = e.getData(CommonDataKeys.PROJECT); + public void update(AnActionEvent e) { + Presentation presentation = e.getPresentation(); + ComboBoxButton button = (ComboBoxButton)presentation.getClientProperty(CUSTOM_COMPONENT_PROPERTY); + Project project = e.getData(CommonDataKeys.PROJECT); if (ActionPlaces.isMainMenuOrActionSearch(e.getPlace())) { presentation.setDescription(ExecutionBundle.message("choose.run.configuration.action.description")); - presentation.setEnabled(findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)) != null); + presentation.setEnabled(button != null); return; } try { if (project == null || project.isDisposed() || !project.isInitialized()) { - //if (ProjectManager.getInstance().getOpenProjects().length > 0) { - // // do nothing if frame is not active - // return; - //} - updateButton(null, null, null, presentation); presentation.setEnabled(false); } @@ -135,31 +119,9 @@ public class RunConfigurationsComboBoxAction extends ComboBoxAction implements D @Override public JComponent createCustomComponent(final Presentation presentation) { - final ComboBoxButton comboBoxButton = new ComboBoxButton(presentation) { - @Override - public void addNotify() { - super.addNotify(); //To change body of overriden methods use Options | File Templates.; - final IdeFrame frame = findFrame(this); - LOG.assertTrue(frame != null); - frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, this); - } - - @Override - public void removeNotify() { - final IdeFrame frame = findFrame(this); - LOG.assertTrue(frame != null); - frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, null); - presentation.setIcon(null); - setIcon(null); - super.removeNotify(); - } - }; - - final JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); - panel.add(comboBoxButton); - panel.setOpaque(false); - return panel; + ComboBoxButton button = new ComboBoxButton(presentation); + button.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); + return button; } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index 6dca47feed69..2777be242a4e 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -31,6 +31,7 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunContentManager; import com.intellij.execution.ui.RunContentManagerImpl; +import com.intellij.ide.SaveAndSyncHandler; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.impl.SimpleDataContext; @@ -45,7 +46,6 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.ui.docking.DockManager; import com.intellij.util.Alarm; import com.intellij.util.SmartList; @@ -548,7 +548,8 @@ public class ExecutionManagerImpl extends ExecutionManager implements Disposable if (myProject.isDisposed()) return; myProject.getMessageBus().syncPublisher(EXECUTION_TOPIC).processTerminated(myProfile, myProcessHandler); - VirtualFileManager.getInstance().asyncRefresh(null); + + SaveAndSyncHandler.getInstance().scheduleRefresh(); } @Override diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index a2eaae64f851..342c1ea329cf 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -1055,8 +1055,6 @@ public class ShowUsagesAction extends AnAction implements PopupAction { window.validate(); window.repaint(); - table.revalidate(); - table.repaint(); } private static Rectangle fitToScreen(@NotNull Dimension newDim, @NotNull RelativePoint popupPosition, JTable table) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java index 93e88a25e0fa..973be2bc7416 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java @@ -267,7 +267,7 @@ class FindInProjectTask { @NotNull private Collection collectFilesInScope(@NotNull final Set alreadySearched, final boolean skipIndexed) { - SearchScope customScope = myFindModel.getCustomScope(); + SearchScope customScope = myFindModel.isCustomScope() ? myFindModel.getCustomScope() : null; final GlobalSearchScope globalCustomScope = toGlobal(customScope); final ProjectFileIndex fileIndex = ProjectFileIndex.SERVICE.getInstance(myProject); @@ -432,17 +432,7 @@ class FindInProjectTask { return Collections.emptySet(); } - SearchScope customScope = myFindModel.getCustomScope(); - GlobalSearchScope scope = myPsiDirectory != null - ? GlobalSearchScopesCore.directoryScope(myPsiDirectory, myFindModel.isWithSubdirectories()) - : myModule != null - ? myModule.getModuleContentScope() - : customScope instanceof GlobalSearchScope - ? (GlobalSearchScope)customScope - : toGlobal(customScope); - if (scope == null) { - scope = ProjectScope.getContentScope(myProject); - } + GlobalSearchScope scope = toGlobal(FindInProjectUtil.getScopeFromModel(myProject, myFindModel)); final Set resultFiles = new LinkedHashSet(); diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index 17ca7e4436bf..d22071e66b8e 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -49,10 +49,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.GlobalSearchScopesCore; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.SearchScope; +import com.intellij.psi.search.*; import com.intellij.ui.content.Content; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewManager; @@ -443,7 +440,7 @@ public class FindInProjectUtil { } @NotNull - private static SearchScope getScopeFromModel(@NotNull Project project, @NotNull FindModel findModel) { + static SearchScope getScopeFromModel(@NotNull Project project, @NotNull FindModel findModel) { SearchScope customScope = findModel.getCustomScope(); PsiDirectory psiDir = getPsiDirectory(findModel, project); VirtualFile directory = psiDir == null ? null : psiDir.getVirtualFile(); @@ -452,8 +449,8 @@ public class FindInProjectUtil { // we don't have to check for myProjectFileIndex.isExcluded(file) here like FindInProjectTask.collectFilesInScope() does // because all found usages are guaranteed to be not in excluded dir directory != null ? GlobalSearchScopesCore.directoryScope(project, directory, findModel.isWithSubdirectories()) : - module != null ? GlobalSearchScope.moduleScope(module) : - findModel.isProjectScope() ? GlobalSearchScope.projectScope(project) : + module != null ? module.getModuleContentScope() : + findModel.isProjectScope() ? ProjectScope.getContentScope(project) : GlobalSearchScope.allScope(project); } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java index bed9f0267e4f..cabb8f3f2494 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java @@ -308,6 +308,7 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search if (mySearchResults.getMatchesCount() >= mySearchResults.getMatchesLimit()) return; for (FindResult range : mySearchResults.getOccurrences()) { + if (range.getEndOffset() > mySearchResults.getEditor().getDocument().getTextLength()) continue; TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES); if (range.getLength() == 0) { attributes = attributes.clone(); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/TemplateKindCombo.java b/platform/lang-impl/src/com/intellij/ide/actions/TemplateKindCombo.java index 5a76d4bd52c7..46521faff6c5 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/TemplateKindCombo.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/TemplateKindCombo.java @@ -99,8 +99,8 @@ public class TemplateKindCombo extends ComboboxWithBrowseButton { } private void scrollBy(int delta) { - if (delta == 0) return; final int size = getComboBox().getModel().getSize(); + if (delta == 0 || size == 0) return; int next = getComboBox().getSelectedIndex() + delta; if (next < 0 || next >= size) { if (!UISettings.getInstance().CYCLE_SCROLLING) { diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java index fef6554ca238..46075f81f4ae 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/ScratchFileService.java @@ -29,7 +29,11 @@ public abstract class ScratchFileService { public enum Option { existing_only, create_if_missing, create_new_always } public static ScratchFileService getInstance() { - return ServiceManager.getService(ScratchFileService.class); + return ServiceHolder.instance; + } + + private static class ServiceHolder { + static final ScratchFileService instance = ServiceManager.getService(ScratchFileService.class); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java index 9526e0c597f9..40d4640133aa 100644 --- a/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java +++ b/platform/lang-impl/src/com/intellij/openapi/file/exclude/EnforcedPlainTextFileTypeManager.java @@ -58,8 +58,7 @@ public class EnforcedPlainTextFileTypeManager implements ProjectManagerListener } } } - for (Project project : myPlainTextFileSets.keySet()) { - Collection projectSet = myPlainTextFileSets.get(project); + for (Collection projectSet : myPlainTextFileSets.values()) { if (projectSet != null && projectSet.contains(file)) return true; } return false; diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java index aea68bf6d430..24d745373d4b 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java @@ -65,7 +65,7 @@ public class DetectedIndentOptionsNotificationProvider extends EditorNotificatio CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); CommonCodeStyleSettings.IndentOptions userOptions = settings.getIndentOptions(psiFile.getFileType()); CommonCodeStyleSettings.IndentOptions detectedOptions = CodeStyleSettingsManager.getSettings(project).getIndentOptionsByFile( - psiFile, null, true, + psiFile, null, false, new Processor() { @Override public boolean process(FileIndentOptionsProvider provider) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java index 11b3a65a1318..4cae3d3eda6e 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/PersistableCodeStyleSchemes.java @@ -49,9 +49,9 @@ class PersistableCodeStyleSchemes extends CodeStyleSchemesImpl implements Persis public Element getState() { return XmlSerializer.serialize(this, new SerializationFilter() { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { if ("CURRENT_SCHEME_NAME".equals(accessor.getName())) { - return bean != null && !DEFAULT_SCHEME_NAME.equals(accessor.read(bean)); + return !DEFAULT_SCHEME_NAME.equals(accessor.read(bean)); } else { return accessor.getValueClass().equals(String.class); diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 8b6843dab3ad..66f5de4179ad 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -46,7 +46,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubUpdatingIndex"); // todo remove once we don't need this for stub-ast mismatch debug info - private static final FileAttribute INDEXED_STAMP = new FileAttribute("stubIndexStamp", 2, false); + private static final FileAttribute INDEXED_STAMP = new FileAttribute("stubIndexStamp", 2, true); public static final ID INDEX_ID = ID.create("Stubs"); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index 55586b5e8b76..f80786273af7 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -390,8 +390,8 @@ class ValueContainerImpl extends UpdatableValueContainer implement return container; } - private void ensureFileSetCapacityForValue(Value value, int count) { - if (count <= 1) return; + private @Nullable ChangeBufferingList ensureFileSetCapacityForValue(Value value, int count) { + if (count <= 1) return null; Object fileSetObject = getFileSetObject(value); if (fileSetObject != null) { @@ -399,15 +399,18 @@ class ValueContainerImpl extends UpdatableValueContainer implement ChangeBufferingList list = new ChangeBufferingList(count + 1); list.add(((Integer)fileSetObject).intValue()); resetFileSetForValue(value, list); + return list; } else if (fileSetObject instanceof ChangeBufferingList) { ChangeBufferingList list = (ChangeBufferingList)fileSetObject; list.ensureCapacity(count); + return list; } - return; + return null; } - final Object fileSet = new ChangeBufferingList(count); + final ChangeBufferingList fileSet = new ChangeBufferingList(count); attachFileSetForNewValue(value, fileSet); + return fileSet; } private void attachFileSetForNewValue(Value value, Object fileSet) { @@ -551,12 +554,13 @@ class ValueContainerImpl extends UpdatableValueContainer implement if (mapping != null) mapping.associateFileIdToValue(idCountOrSingleValue, value); } else { idCountOrSingleValue = -idCountOrSingleValue; - ensureFileSetCapacityForValue(value, idCountOrSingleValue); + ChangeBufferingList changeBufferingList = ensureFileSetCapacityForValue(value, idCountOrSingleValue); int prev = 0; for (int i = 0; i < idCountOrSingleValue; i++) { final int id = DataInputOutputUtil.readINT(stream); - addValue(prev + id, value); + if (changeBufferingList != null) changeBufferingList.add(prev + id); + else addValue(prev + id, value); if (mapping != null) mapping.associateFileIdToValue(prev + id, value); prev += id; } diff --git a/platform/platform-api/src/com/intellij/ide/GeneralSettings.java b/platform/platform-api/src/com/intellij/ide/GeneralSettings.java index 64da1496616c..16cf8e146055 100644 --- a/platform/platform-api/src/com/intellij/ide/GeneralSettings.java +++ b/platform/platform-api/src/com/intellij/ide/GeneralSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -22,7 +22,6 @@ import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.OptionTag; import com.intellij.util.xmlb.annotations.Transient; import org.intellij.lang.annotations.MagicConstant; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import java.beans.PropertyChangeListener; @@ -37,7 +36,7 @@ public class GeneralSettings implements PersistentStateComponent * {@link DiffTool#HINT_SHOW_FRAME} don't check modal window open. * Show diff in frame in any case. May help as workaround when closing - * modal dialog right before openning diff.
+ * modal dialog right before opening diff.
* {@link DiffTool#HINT_SHOW_NOT_MODAL_DIALOG} Show diff in not modal dialog
*/ public abstract DiffTool getIdeaDiffTool(); /** - * Work in progess. Don't rely on this functionality
+ * Work in progress. Don't rely on this functionality
* Adds new diff tool. - * + * * @param tool diff tool to register * @return false iff tool already registered (tool won't be registered twice). Otherwise true. * @throws NullPointerException iff tool == null @@ -53,9 +52,9 @@ public abstract class DiffManager { public abstract boolean registerDiffTool(DiffTool tool) throws NullPointerException; /** - * Work in progess. Don't rely on this functionality
- * Unregisters tool, registered with {@link #registerDiffTool(DiffTool)} - * + * Work in progress. Don't rely on this functionality
+ * Unregister tool, registered with {@link #registerDiffTool(DiffTool)} + * * @param tool diff tool to unregister */ public abstract void unregisterDiffTool(DiffTool tool); @@ -63,12 +62,11 @@ public abstract class DiffManager { public abstract MarkupEditorFilter getDiffEditorFilter(); /** - * - * @param window this window will be disposed, when user clicks on the line number - * You must call Disposer.dispose() when done. - * @param disposable - *@param parentTool @deprecated use {@link #createDiffPanel(Window, Project, Disposable)} instead + * @param window this window will be disposed, when user clicks on the line number + * You must call Disposer.dispose() when done. + * @param parentTool @deprecated use {@link #createDiffPanel(Window, Project, Disposable)} instead */ public abstract DiffPanel createDiffPanel(Window window, @NotNull Project project, DiffTool parentTool); + public abstract DiffPanel createDiffPanel(Window window, @NotNull Project project, @NotNull Disposable parentDisposable, DiffTool parentTool); } diff --git a/platform/platform-api/src/com/intellij/openapi/util/registry/RegistryState.java b/platform/platform-api/src/com/intellij/openapi/util/registry/RegistryState.java index 73743f86d796..b988c6251e2e 100644 --- a/platform/platform-api/src/com/intellij/openapi/util/registry/RegistryState.java +++ b/platform/platform-api/src/com/intellij/openapi/util/registry/RegistryState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,10 +15,12 @@ */ package com.intellij.openapi.util.registry; -import com.intellij.openapi.components.*; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.diagnostic.Logger; import org.jdom.Element; -import org.jetbrains.annotations.NotNull; import java.util.Map; import java.util.SortedMap; @@ -26,9 +28,12 @@ import java.util.TreeMap; @State( name = "Registry", - storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml") + storages = { + @Storage(file = StoragePathMacros.APP_CONFIG + "/ide.general.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true) + } ) -public class RegistryState implements BaseComponent, PersistentStateComponent { +public class RegistryState implements PersistentStateComponent { private static final Logger LOG = Logger.getInstance(RegistryState.class); @Override @@ -48,18 +53,4 @@ public class RegistryState implements BaseComponent, PersistentStateComponentid of tool window to be registered. * @param component component which represents tool window content. - * May be null. Content can be further added via content manager for this tool window (See {@link com.intellij.openapi.wm.ToolWindow#getContentManager()}) + * May be null. Content can be further added via content manager for this tool window (See {@link ToolWindow#getContentManager()}) * @param anchor the default anchor for first registration. It uses only first time the * tool window with the specified id is being registered into the window system. * After the first registration window's anchor is stored in project file * and anchor is ignored. - * @exception java.lang.IllegalArgumentException if the same window is already installed or one + * @exception IllegalArgumentException if the same window is already installed or one * of the parameters is null. * @return tool window - * @deprecated {@link com.intellij.openapi.wm.ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} + * @deprecated {@link ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} */ @Deprecated @NotNull public abstract ToolWindow registerToolWindow(@NotNull String id, @NotNull JComponent component, @NotNull ToolWindowAnchor anchor); /** - * @deprecated {@link com.intellij.openapi.wm.ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} + * @deprecated {@link ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} */ @Deprecated @NotNull @@ -62,7 +66,7 @@ public abstract class ToolWindowManager { @NotNull Disposable parentDisposable); /** - * @deprecated {@link com.intellij.openapi.wm.ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} + * @deprecated {@link ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} */ @Deprecated @NotNull @@ -72,7 +76,7 @@ public abstract class ToolWindowManager { Disposable parentDisposable, boolean canWorkInDumbMode); /** - * @deprecated {@link com.intellij.openapi.wm.ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} + * @deprecated {@link ToolWindowManager#registerToolWindow(String, boolean, ToolWindowAnchor)} */ @Deprecated @NotNull diff --git a/platform/platform-api/src/com/intellij/util/config/AbstractProperty.java b/platform/platform-api/src/com/intellij/util/config/AbstractProperty.java index 4c46e2362e33..97b6e4d882c6 100644 --- a/platform/platform-api/src/com/intellij/util/config/AbstractProperty.java +++ b/platform/platform-api/src/com/intellij/util/config/AbstractProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.config; import com.intellij.openapi.util.Comparing; @@ -28,17 +27,28 @@ public abstract class AbstractProperty { } }; - @NonNls public abstract String getName(); + @NonNls + public abstract String getName(); + public abstract T getDefault(AbstractPropertyContainer container); + public abstract T copy(T value); public boolean areEqual(T value1, T value2) { return Comparing.equal(value1, value2); } - public T get(AbstractPropertyContainer container) { return (T) container.getValueOf(this); } - public void set(AbstractPropertyContainer container, T value) { container.setValueOf(this, value); } - public final T cast(Object value) { return (T) value; } + public T get(AbstractPropertyContainer container) { + return (T)container.getValueOf(this); + } + + public void set(AbstractPropertyContainer container, T value) { + container.setValueOf(this, value); + } + + public final T cast(Object value) { + return (T)value; + } public String toString() { return getName(); @@ -60,7 +70,9 @@ public abstract class AbstractProperty { }; protected abstract Object getValueOf(PropertyImpl property); + protected abstract void setValueOf(PropertyImpl property, Object value); + public abstract boolean hasProperty(AbstractProperty property); /** @@ -73,7 +85,7 @@ public abstract class AbstractProperty { /** * Only containers can delegate to another. - * Other clients should use {@link AbstractProperty#get AbstractProperty.get} + * Other clients should use {@link AbstractProperty#get AbstractProperty.get} */ protected final T delegateGet(AbstractPropertyContainer container, AbstractProperty property) { return (T)container.getValueOf(property); diff --git a/platform/platform-api/src/com/intellij/util/config/ExternalizablePropertyContainer.java b/platform/platform-api/src/com/intellij/util/config/ExternalizablePropertyContainer.java index 3f48ecf2a4b1..25f3a173e45b 100644 --- a/platform/platform-api/src/com/intellij/util/config/ExternalizablePropertyContainer.java +++ b/platform/platform-api/src/com/intellij/util/config/ExternalizablePropertyContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,20 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.config; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.util.SmartList; +import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; -public class ExternalizablePropertyContainer extends AbstractProperty.AbstractPropertyContainer implements JDOMExternalizable { +public class ExternalizablePropertyContainer extends AbstractProperty.AbstractPropertyContainer { private static final Logger LOG = Logger.getInstance(ExternalizablePropertyContainer.class); - private final Map myValues = new HashMap(); - private final Map myExternalizers = new HashMap(); + private final Map myValues = new THashMap(); + private final Map myExternalizers = new THashMap(); public void registerProperty(AbstractProperty property, Externalizer externalizer) { String name = property.getName(); @@ -66,37 +74,34 @@ public class ExternalizablePropertyContainer extends AbstractProperty.AbstractPr registerProperty(property, itemTagName, Externalizer.FactoryBased.create(factory)); } - private Externalizer> createListExternalizer(final Externalizer itemExternalizer, final String itemTagName) { + private static Externalizer> createListExternalizer(final Externalizer itemExternalizer, final String itemTagName) { return new ListExternalizer(itemExternalizer, itemTagName); } - @Override - public void readExternal(Element element) throws InvalidDataException { - HashMap propertyByName = new HashMap(); + public void readExternal(@NotNull Element element) { + Map propertyByName = new THashMap(); for (AbstractProperty abstractProperty : myExternalizers.keySet()) { propertyByName.put(abstractProperty.getName(), abstractProperty); } - final List children = element.getChildren(); - for (Element child : children) { + for (Element child : element.getChildren()) { AbstractProperty property = propertyByName.get(child.getName()); if (property == null) { continue; } - final Externalizer externalizer = myExternalizers.get(property); + Externalizer externalizer = myExternalizers.get(property); if (externalizer == null) { continue; } try { myValues.put(property, externalizer.readValue(child)); } - catch (InvalidDataException e) { + catch (Exception e) { LOG.info(e); } } } - @Override - public void writeExternal(Element element) throws WriteExternalException { + public void writeExternal(@NotNull Element element) { if (myExternalizers.isEmpty()) { return; } @@ -147,12 +152,12 @@ public class ExternalizablePropertyContainer extends AbstractProperty.AbstractPr } @Override - public List readValue(Element dataElement) throws InvalidDataException { - ArrayList list = new ArrayList(); - List children = dataElement.getChildren(); - for (Iterator iterator = children.iterator(); iterator.hasNext();) { - Element element = iterator.next(); - if (NULL_ELEMENT.equals(element.getName())) list.add(null); + public List readValue(Element dataElement) { + List list = new SmartList(); + for (Element element : dataElement.getChildren()) { + if (NULL_ELEMENT.equals(element.getName())) { + list.add(null); + } else if (myItemTagName.equals(element.getName())) { T item = myItemExternalizer.readValue(element); if (item == null) { @@ -166,17 +171,17 @@ public class ExternalizablePropertyContainer extends AbstractProperty.AbstractPr } @Override - public void writeValue(Element dataElement, List value) throws WriteExternalException { - for (Iterator iterator = value.iterator(); iterator.hasNext();) { - T item = iterator.next(); - if (item != null) { + public void writeValue(Element dataElement, List value) { + for (T item : value) { + if (item == null) { + dataElement.addContent(new Element(NULL_ELEMENT)); + } + else { Element element = new Element(myItemTagName); myItemExternalizer.writeValue(element, item); dataElement.addContent(element); } - else dataElement.addContent(new Element(NULL_ELEMENT)); } } } - } diff --git a/platform/platform-api/src/com/intellij/util/config/Externalizer.java b/platform/platform-api/src/com/intellij/util/config/Externalizer.java index 864b5bee0e43..1fb3eca0b262 100644 --- a/platform/platform-api/src/com/intellij/util/config/Externalizer.java +++ b/platform/platform-api/src/com/intellij/util/config/Externalizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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,7 +24,6 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import java.util.Iterator; -import java.util.List; public interface Externalizer { @NonNls String VALUE_ATTRIBUTE = "value"; @@ -60,9 +59,9 @@ public interface Externalizer { } }; - T readValue(Element dataElement) throws InvalidDataException; + T readValue(Element dataElement); - void writeValue(Element dataElement, T value) throws WriteExternalException; + void writeValue(Element dataElement, T value); class FactoryBased implements Externalizer { private final Factory myFactory; @@ -72,15 +71,25 @@ public interface Externalizer { } @Override - public T readValue(Element dataElement) throws InvalidDataException { + public T readValue(Element dataElement) { T data = myFactory.create(); - data.readExternal(dataElement); + try { + data.readExternal(dataElement); + } + catch (InvalidDataException e) { + throw new RuntimeException(e); + } return data; } @Override - public void writeValue(Element dataElement, T value) throws WriteExternalException { - value.writeExternal(dataElement); + public void writeValue(Element dataElement, T value) { + try { + value.writeExternal(dataElement); + } + catch (WriteExternalException e) { + throw new RuntimeException(e); + } } public static FactoryBased create(Factory factory) { @@ -94,25 +103,25 @@ public interface Externalizer { @NonNls private static final String VALUE_ATTR = "value"; @Override - public Storage readValue(Element dataElement) throws InvalidDataException { + public Storage readValue(Element dataElement) { Storage.MapStorage storage = new Storage.MapStorage(); - List children = dataElement.getChildren(ITEM_TAG); - for (Iterator iterator = children.iterator(); iterator.hasNext();) { - Element element = iterator.next(); + for (Element element : dataElement.getChildren(ITEM_TAG)) { storage.put(element.getAttributeValue(KEY_ATTR), element.getAttributeValue(VALUE_ATTR)); } return storage; } @Override - public void writeValue(Element dataElement, Storage storage) throws WriteExternalException { + public void writeValue(Element dataElement, Storage storage) { Iterator keys = ((Storage.MapStorage)storage).getKeys(); while (keys.hasNext()) { String key = keys.next(); String value = storage.get(key); Element element = new Element(ITEM_TAG); element.setAttribute(KEY_ATTR, key); - if (value != null) element.setAttribute(VALUE_ATTR, value); + if (value != null) { + element.setAttribute(VALUE_ATTR, value); + } dataElement.addContent(element); } } diff --git a/platform/platform-impl/src/com/intellij/application/options/ShareSchemeDialog.java b/platform/platform-impl/src/com/intellij/application/options/ShareSchemeDialog.java deleted file mode 100644 index 22efc052e9ef..000000000000 --- a/platform/platform-impl/src/com/intellij/application/options/ShareSchemeDialog.java +++ /dev/null @@ -1,49 +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.application.options; - -import com.intellij.openapi.options.Scheme; -import com.intellij.openapi.ui.DialogWrapper; - -import javax.swing.*; - -public class ShareSchemeDialog extends DialogWrapper { - private final ShareSchemePanel myShareSchemePanel; - - public ShareSchemeDialog() { - super(true); - myShareSchemePanel = new ShareSchemePanel(); - setTitle("Share Scheme"); - init(); - } - - public void init(Scheme scheme){ - myShareSchemePanel.setName(scheme.getName()); - } - - protected JComponent createCenterPanel() { - return myShareSchemePanel.getPanel(); - } - - public String getName(){ - return myShareSchemePanel.getName(); - } - - public String getDescription(){ - return myShareSchemePanel.getDescription(); - } - -} diff --git a/platform/platform-impl/src/com/intellij/application/options/ShareSchemePanel.form b/platform/platform-impl/src/com/intellij/application/options/ShareSchemePanel.form deleted file mode 100644 index e1082de419f1..000000000000 --- a/platform/platform-impl/src/com/intellij/application/options/ShareSchemePanel.form +++ /dev/null @@ -1,53 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/platform/platform-impl/src/com/intellij/application/options/ShareSchemePanel.java b/platform/platform-impl/src/com/intellij/application/options/ShareSchemePanel.java deleted file mode 100644 index 708004896633..000000000000 --- a/platform/platform-impl/src/com/intellij/application/options/ShareSchemePanel.java +++ /dev/null @@ -1,41 +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.application.options; - -import javax.swing.*; - - -public class ShareSchemePanel { - private JTextField mySharedSchemeName; - private JTextArea mySharedSchemeDescription; - private JPanel myPanel; - - public String getName(){ - return mySharedSchemeName.getText(); - } - - public String getDescription(){ - return mySharedSchemeDescription.getText(); - } - - public JPanel getPanel() { - return myPanel; - } - - public void setName(final String name) { - mySharedSchemeName.setText(name); - } -} diff --git a/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java b/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java deleted file mode 100644 index 6f2a983a84e0..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.ide; - -/** - * @author Kirill Likhodedov - */ -public interface SaveAndSyncHandler { - - void blockSaveOnFrameDeactivation(); - - void unblockSaveOnFrameDeactivation(); - - void blockSyncOnFrameActivation(); - - void unblockSyncOnFrameActivation(); -} diff --git a/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandlerImpl.java b/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandlerImpl.java index e42c796ab8bb..8983f14fca72 100644 --- a/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandlerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/SaveAndSyncHandlerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -46,47 +46,35 @@ import java.util.concurrent.atomic.AtomicInteger; * @author Anton Katilin * @author Vladimir Kondratyev */ -public class SaveAndSyncHandlerImpl implements ApplicationComponent, SaveAndSyncHandler { +public class SaveAndSyncHandlerImpl extends SaveAndSyncHandler implements ApplicationComponent { private static final Logger LOG = Logger.getInstance(SaveAndSyncHandler.class); private final Runnable myIdleListener; private final PropertyChangeListener myGeneralSettingsListener; + private final GeneralSettings mySettings; private final ProgressManager myProgressManager; + private final SingleAlarm myRefreshDelayAlarm; private final AtomicInteger myBlockSaveOnFrameDeactivationCount = new AtomicInteger(); private final AtomicInteger myBlockSyncOnFrameActivationCount = new AtomicInteger(); - private final SingleAlarm myRefreshDelayAlarm = new SingleAlarm(new Runnable() { - @Override - public void run() { - if (canSyncOrSave()) { - refreshOpenFiles(); - } - maybeRefresh(ModalityState.NON_MODAL); - } - }, 300); + private volatile long myRefreshSessionId = 0; - private long myRefreshSessionId = 0; - - public static SaveAndSyncHandlerImpl getInstance() { - return (SaveAndSyncHandlerImpl)ApplicationManager.getApplication().getComponent(SaveAndSyncHandler.class); - } - - public SaveAndSyncHandlerImpl(@NotNull FrameStateManager frameStateManager, - @NotNull final FileDocumentManager fileDocumentManager, - @NotNull final GeneralSettings generalSettings, - @NotNull ProgressManager progressManager) { + public SaveAndSyncHandlerImpl(@NotNull GeneralSettings generalSettings, + @NotNull ProgressManager progressManager, + @NotNull FrameStateManager frameStateManager, + @NotNull final FileDocumentManager fileDocumentManager) { + mySettings = generalSettings; myProgressManager = progressManager; myIdleListener = new Runnable() { @Override public void run() { - if (generalSettings.isAutoSaveIfInactive() && canSyncOrSave()) { + if (mySettings.isAutoSaveIfInactive() && canSyncOrSave()) { ((FileDocumentManagerImpl)fileDocumentManager).saveAllDocuments(false); } } }; - - IdeEventQueue.getInstance().addIdleListener(myIdleListener, generalSettings.getInactiveTimeout() * 1000); + IdeEventQueue.getInstance().addIdleListener(myIdleListener, mySettings.getInactiveTimeout() * 1000); myGeneralSettingsListener = new PropertyChangeListener() { @Override @@ -99,8 +87,17 @@ public class SaveAndSyncHandlerImpl implements ApplicationComponent, SaveAndSync } } }; + mySettings.addPropertyChangeListener(myGeneralSettingsListener); - generalSettings.addPropertyChangeListener(myGeneralSettingsListener); + myRefreshDelayAlarm = new SingleAlarm(new Runnable() { + @Override + public void run() { + if (canSyncOrSave()) { + refreshOpenFiles(); + } + maybeRefresh(ModalityState.NON_MODAL); + } + }, 300); frameStateManager.addListener(new FrameStateListener() { @Override @@ -112,13 +109,9 @@ public class SaveAndSyncHandlerImpl implements ApplicationComponent, SaveAndSync @Override public void onFrameActivated() { - if (ApplicationManager.getApplication().isDisposed() || !generalSettings.isSyncOnFrameActivation()) { - return; + if (!ApplicationManager.getApplication().isDisposed() && mySettings.isSyncOnFrameActivation()) { + scheduleRefresh(); } - - LOG.debug("enter: refreshFiles()"); - myRefreshDelayAlarm.cancelAndRequest(); - LOG.debug("exit: refreshFiles()"); } }); } @@ -130,12 +123,13 @@ public class SaveAndSyncHandlerImpl implements ApplicationComponent, SaveAndSync } @Override - public void initComponent() { - } + public void initComponent() { } @Override public void disposeComponent() { - GeneralSettings.getInstance().removePropertyChangeListener(myGeneralSettingsListener); + myRefreshDelayAlarm.cancel(); + RefreshQueue.getInstance().cancelSession(myRefreshSessionId); + mySettings.removePropertyChangeListener(myGeneralSettingsListener); IdeEventQueue.getInstance().removeIdleListener(myIdleListener); } @@ -143,37 +137,34 @@ public class SaveAndSyncHandlerImpl implements ApplicationComponent, SaveAndSync return !LaterInvocator.isInModalContext() && !myProgressManager.hasModalProgressIndicator(); } - // made public for tests + @Override public void saveProjectsAndDocuments() { - if (LOG.isDebugEnabled()) { - LOG.debug("enter: save()"); - } - if (ApplicationManager.getApplication().isDisposed()) return; + LOG.debug("enter: save()"); - if (myBlockSaveOnFrameDeactivationCount.get() == 0 && GeneralSettings.getInstance().isSaveOnFrameDeactivation()) { + if (!ApplicationManager.getApplication().isDisposed() && + mySettings.isSaveOnFrameDeactivation() && + myBlockSaveOnFrameDeactivationCount.get() == 0) { FileDocumentManager.getInstance().saveAllDocuments(); - Project[] openProjects = ProjectManagerEx.getInstanceEx().getOpenProjects(); - for (Project project : openProjects) { - if (LOG.isDebugEnabled()) { - LOG.debug("save project: " + project); - } + for (Project project : ProjectManagerEx.getInstanceEx().getOpenProjects()) { + if (LOG.isDebugEnabled()) LOG.debug("saving project: " + project); project.save(); } - if (LOG.isDebugEnabled()) { - LOG.debug("save application settings"); - } + + LOG.debug("saving application settings"); ApplicationManagerEx.getApplicationEx().saveSettings(); - if (LOG.isDebugEnabled()) { - LOG.debug("exit: save()"); - } + + LOG.debug("exit: save()"); } } - public void maybeRefresh(@NotNull ModalityState modalityState) { - if (myBlockSyncOnFrameActivationCount.get() == 0 && GeneralSettings.getInstance().isSyncOnFrameActivation()) { - LOG.debug("VFS refresh started"); + @Override + public void scheduleRefresh() { + myRefreshDelayAlarm.cancelAndRequest(); + } + public void maybeRefresh(@NotNull ModalityState modalityState) { + if (myBlockSyncOnFrameActivationCount.get() == 0 && mySettings.isSyncOnFrameActivation()) { RefreshQueue queue = RefreshQueue.getInstance(); queue.cancelSession(myRefreshSessionId); @@ -181,16 +172,15 @@ public class SaveAndSyncHandlerImpl implements ApplicationComponent, SaveAndSync session.addAllFiles(ManagingFS.getInstance().getLocalRoots()); myRefreshSessionId = session.getId(); session.launch(); - - LOG.debug("VFS refresh finished"); } } - public static void refreshOpenFiles() { + @Override + public void refreshOpenFiles() { List files = ContainerUtil.newArrayList(); + for (Project project : ProjectManager.getInstance().getOpenProjects()) { - VirtualFile[] projectFiles = FileEditorManager.getInstance(project).getSelectedFiles(); - for (VirtualFile file : projectFiles) { + for (VirtualFile file : FileEditorManager.getInstance(project).getSelectedFiles()) { if (file instanceof NewVirtualFile) { files.add(file); } diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SynchronizeAction.java b/platform/platform-impl/src/com/intellij/ide/actions/SynchronizeAction.java index 942d78a81e61..525108ae518f 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SynchronizeAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/SynchronizeAction.java @@ -15,7 +15,7 @@ */ package com.intellij.ide.actions; -import com.intellij.ide.SaveAndSyncHandlerImpl; +import com.intellij.ide.SaveAndSyncHandler; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -26,9 +26,7 @@ public class SynchronizeAction extends AnAction implements DumbAware { @Override public void actionPerformed(AnActionEvent e) { FileDocumentManager.getInstance().saveAllDocuments(); - - SaveAndSyncHandlerImpl.refreshOpenFiles(); - + SaveAndSyncHandler.getInstance().refreshOpenFiles(); VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsState.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsState.java index 3a6cd2dde689..7751dd37f3ea 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsState.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -59,7 +60,7 @@ public class InstalledPluginsState { public boolean hasNewerVersion(@NotNull PluginId id) { synchronized (myLock) { - return !wasUpdated(id) && myUpdateSettings.myOutdatedPlugins.contains(id.getIdString()); + return !wasUpdated(id) && myUpdateSettings.getOutdatedPlugins().contains(id.getIdString()); } } @@ -89,13 +90,14 @@ public class InstalledPluginsState { String idString = id.getIdString(); synchronized (myLock) { + List outdatedPlugins = myUpdateSettings.getOutdatedPlugins(); if (newer) { - if (!myUpdateSettings.myOutdatedPlugins.contains(idString)) { - myUpdateSettings.myOutdatedPlugins.add(idString); + if (!outdatedPlugins.contains(idString)) { + outdatedPlugins.add(idString); } } else { - myUpdateSettings.myOutdatedPlugins.remove(idString); + outdatedPlugins.remove(idString); } } } @@ -108,7 +110,7 @@ public class InstalledPluginsState { boolean existing = PluginManager.isPluginInstalled(id); synchronized (myLock) { - myUpdateSettings.myOutdatedPlugins.remove(id.getIdString()); + myUpdateSettings.getOutdatedPlugins().remove(id.getIdString()); if (existing) { myUpdatedPlugins.put(id, descriptor); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java index 7e0c6dd10d91..2c9e18f1347c 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -67,13 +67,13 @@ public class PluginHostsConfigurable extends BaseConfigurable { public void apply() throws ConfigurationException { UpdateSettings settings = UpdateSettings.getInstance(); - settings.myPluginHosts.clear(); - settings.myPluginHosts.addAll(myUpdatesSettingsPanel.getPluginsHosts()); + settings.getStoredPluginHosts().clear(); + settings.getStoredPluginHosts().addAll(myUpdatesSettingsPanel.getPluginsHosts()); } @Override public void reset() { - myUpdatesSettingsPanel.setPluginHosts(UpdateSettings.getInstance().myPluginHosts); + myUpdatesSettingsPanel.setPluginHosts(UpdateSettings.getInstance().getStoredPluginHosts()); } @Override @@ -82,7 +82,7 @@ public class PluginHostsConfigurable extends BaseConfigurable { return false; } //noinspection EqualsBetweenInconvertibleTypes - return !UpdateSettings.getInstance().myPluginHosts.equals(myUpdatesSettingsPanel.getPluginsHosts()); + return !UpdateSettings.getInstance().getStoredPluginHosts().equals(myUpdatesSettingsPanel.getPluginsHosts()); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java index b1839c87ac10..ad6a9567885c 100644 --- a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java @@ -215,7 +215,10 @@ public class StartupManagerImpl extends StartupManagerEx { } }); - Registry.get("ide.firstStartup").setValue(false); + // otherwise will be stored - we must not create config files in tests + if (!app.isUnitTestMode()) { + Registry.get("ide.firstStartup").setValue(false); + } } public void scheduleInitialVfsRefresh() { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java index 2df9bf7f6414..e1e77fb8354f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,11 +15,8 @@ */ package com.intellij.ide.ui.laf; -import com.intellij.ide.ui.LafManager; import com.intellij.ide.ui.laf.darcula.DarculaLaf; -import com.intellij.openapi.util.SystemInfo; -import javax.swing.*; import javax.swing.plaf.metal.DefaultMetalTheme; /** @@ -36,19 +33,6 @@ public class IntelliJLaf extends DarculaLaf { return "intellijlaf"; } - @Override - public UIDefaults getDefaults() { - UIDefaults defaults = super.getDefaults(); - if (SystemInfo.isLinux) { - try { - LafManagerImpl.initFontDefaults(defaults, "Dialog", 12); - } - catch (Exception ignore) { - } - } - return defaults; - } - @Override protected DefaultMetalTheme createMetalTheme() { return new IdeaBlueMetalTheme(); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java index 779e326d2802..0a2ce8d93e67 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java @@ -560,6 +560,7 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo List myIntKeys = Arrays.asList("Tree.leftChildIndent", "Tree.rightChildIndent"); + List patched = new ArrayList(); for (Map.Entry entry : defaults.entrySet()) { Object value = entry.getValue(); String key = entry.getKey().toString(); @@ -569,10 +570,16 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo entry.setValue(JBUI.insets(((InsetsUIResource)value)).asUIResource()); } else if (value instanceof Integer) { if (key.endsWith(".maxGutterIconWidth") || myIntKeys.contains(key)) { - entry.setValue(Integer.valueOf(JBUI.scale((Integer)value))); + if (!"true".equals(defaults.get(key +".hidpi.patched"))) { + entry.setValue(Integer.valueOf(JBUI.scale((Integer)value))); + patched.add(key); + } } } } + for (String key : patched) { + defaults.put(key + ".hidpi.patched", "true"); + } } public static void updateToolWindows() { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java index 156c39657609..14b5be48ce43 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java @@ -42,10 +42,8 @@ import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; -import java.util.Arrays; +import java.util.*; import java.util.List; -import java.util.Locale; -import java.util.Properties; /** * @author Konstantin Bulenkov @@ -91,6 +89,7 @@ public class DarculaLaf extends BasicLookAndFeel { final Method superMethod = BasicLookAndFeel.class.getDeclaredMethod("getDefaults"); superMethod.setAccessible(true); final UIDefaults metalDefaults = (UIDefaults)superMethod.invoke(new MetalLookAndFeel()); + final UIDefaults defaults = (UIDefaults)superMethod.invoke(base); if (SystemInfo.isLinux) { if (!Registry.is("darcula.use.native.fonts.on.linux")) { @@ -124,6 +123,9 @@ public class DarculaLaf extends BasicLookAndFeel { if (SystemInfo.isWindows) { //JFrame.setDefaultLookAndFeelDecorated(true); } + if (SystemInfo.isLinux && JBUI.isHiDPI()) { + applySystemFonts(defaults); + } defaults.put("EditorPane.font", defaults.getFont("TextField.font")); return defaults; } @@ -133,6 +135,23 @@ public class DarculaLaf extends BasicLookAndFeel { return super.getDefaults(); } + private static void applySystemFonts(UIDefaults defaults) { + try { + String fqn = UIManager.getSystemLookAndFeelClassName(); + Object systemLookAndFeel = Class.forName(fqn).newInstance(); + final Method superMethod = BasicLookAndFeel.class.getDeclaredMethod("getDefaults"); + superMethod.setAccessible(true); + final UIDefaults systemDefaults = (UIDefaults)superMethod.invoke(systemLookAndFeel); + for (Map.Entry entry : systemDefaults.entrySet()) { + if (entry.getValue() instanceof Font) { + defaults.put(entry.getKey(), entry.getValue()); + } + } + } catch (Exception e) { + log(e); + } + } + protected DefaultMetalTheme createMetalTheme() { return new DarculaMetalTheme(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 0d2c973eb4a2..d9f965593958 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -1352,8 +1352,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App myDispatcher.getMulticaster().writeActionFinished(action); } - // public for testing purposes - public void _saveSettings() { + @Override + public void saveSettings() { + if (myDoNotSave) return; + if (mySaveSettingsIsInProgress.compareAndSet(false, true)) { try { StoreUtil.save(getStateStore(), null); @@ -1364,12 +1366,6 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } } - @Override - public void saveSettings() { - if (myDoNotSave) return; - _saveSettings(); - } - @Override public void saveAll() { if (myDoNotSave) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java index 5e78e340a581..8e15a8f61f78 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java @@ -22,7 +22,6 @@ import com.intellij.openapi.components.StateStorage.SaveSession; import com.intellij.openapi.components.impl.ComponentManagerImpl; import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession; import com.intellij.openapi.components.store.ReadOnlyModificationException; -import com.intellij.openapi.components.store.StateStorageBase; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; @@ -281,6 +280,11 @@ public abstract class ComponentStoreImpl implements IComponentStore.Reloadable { } Class stateClass = ComponentSerializationUtil.getStateClass(component.getClass()); + // todo remove assert before last EAP + if (!stateSpec.defaultStateAsResource() && getDefaultState(component, name, stateClass) != null) { + LOG.error(name + " has default state, but not marked to load it"); + } + T state = stateSpec.defaultStateAsResource() ? getDefaultState(component, name, stateClass) : null; Storage[] storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ); for (Storage storageSpec : storageSpecs) { diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java index 2b755dbde9ca..5d7cd510c347 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -58,6 +58,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl { return getStateCopy(); } + @NotNull @Override protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) { return new XmlElementStorageSaveSession(storageData) { diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java index 199d70123ca9..373d9c38f9a5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,14 +18,15 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.*; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.StateSplitter; +import com.intellij.openapi.components.StateStorageException; +import com.intellij.openapi.components.TrackingPathMacroSubstitutor; import com.intellij.openapi.components.store.ReadOnlyModificationException; -import com.intellij.openapi.components.store.StateStorageBase; import com.intellij.openapi.editor.DocumentRunnable; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -178,7 +179,7 @@ public class DirectoryBasedStorage extends StateStorageBase pair : storage.mySplitter.splitState(compositeState)) { + for (Pair pair : storage.mySplitter.splitState(element)) { removedFileNames.remove(pair.second); doSetState(componentName, pair.second, pair.first); } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java index 53ac35c58ee3..1fdc5718aeb8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -94,6 +94,7 @@ public class FileBasedStorage extends XmlElementStorage { return isUseXmlProlog(); } + @NotNull @Override protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) { return new FileSaveSession(storageData); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/SaveSessionBase.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/SaveSessionBase.java new file mode 100644 index 000000000000..9c100643314e --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/SaveSessionBase.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2015 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.components.impl.stores; + +import com.intellij.openapi.components.StateStorage; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.xmlb.SkipDefaultsSerializationFilter; +import com.intellij.util.xmlb.XmlSerializer; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +abstract class SaveSessionBase implements StateStorage.SaveSession, StateStorage.ExternalizationSession { + private SkipDefaultsSerializationFilter serializationFilter; + + @SuppressWarnings("deprecation") + @Override + public final void setState(@NotNull Object component, @NotNull String componentName, @NotNull Object state, Storage storageSpec) { + Element element; + try { + if (state instanceof Element) { + element = (Element)state; + } + else if (state instanceof JDOMExternalizable) { + element = new Element("temp_element"); + ((JDOMExternalizable)state).writeExternal(element); + } + else { + if (serializationFilter == null) { + serializationFilter = new SkipDefaultsSerializationFilter(); + } + element = XmlSerializer.serializeIfNotDefault(state, serializationFilter); + } + } + catch (WriteExternalException e) { + StateStorageBase.LOG.debug(e); + return; + } + catch (Throwable e) { + StateStorageBase.LOG.error("Unable to serialize " + componentName + " state", e); + return; + } + + setSerializedState(component, componentName, element); + } + + protected abstract void setSerializedState(@NotNull Object component, @NotNull String componentName, @Nullable Element element); +} diff --git a/platform/platform-impl/src/com/intellij/openapi/components/store/StateStorageBase.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.java similarity index 91% rename from platform/platform-impl/src/com/intellij/openapi/components/store/StateStorageBase.java rename to platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.java index da38c311e134..fb02c973e240 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/store/StateStorageBase.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.openapi.components.store; +package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.components.StateStorage; import com.intellij.openapi.components.TrackingPathMacroSubstitutor; -import com.intellij.openapi.components.impl.stores.DefaultStateSerializer; -import com.intellij.openapi.components.impl.stores.StorageDataBase; import com.intellij.openapi.diagnostic.Logger; import org.jdom.Element; import org.jetbrains.annotations.NotNull; diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index 4b6624d6cad0..f1f7f1e308e8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -17,11 +17,8 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.components.RoamingType; import com.intellij.openapi.components.StateStorageException; -import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.TrackingPathMacroSubstitutor; -import com.intellij.openapi.components.store.StateStorageBase; import com.intellij.openapi.util.JDOMUtil; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; @@ -133,6 +130,7 @@ public abstract class XmlElementStorage extends StateStorageBase { return checkIsSavingDisabled() ? null : createSaveSession(getStorageData()); } + @NotNull protected abstract XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData); @Nullable @@ -175,7 +173,7 @@ public abstract class XmlElementStorage extends StateStorageBase { } } - protected abstract class XmlElementStorageSaveSession implements SaveSession, ExternalizationSession { + protected abstract class XmlElementStorageSaveSession extends SaveSessionBase { private final StorageData myOriginalStorageData; private StorageData myCopiedStorageData; @@ -192,20 +190,7 @@ public abstract class XmlElementStorage extends StateStorageBase { } @Override - public final void setState(@NotNull Object component, @NotNull String componentName, @NotNull Object state, @Nullable Storage storageSpec) { - Element element; - try { - element = DefaultStateSerializer.serializeState(state, storageSpec); - } - catch (WriteExternalException e) { - LOG.debug(e); - return; - } - catch (Throwable e) { - LOG.error("Unable to serialize " + componentName + " state", e); - return; - } - + protected void setSerializedState(@NotNull Object component, @NotNull String componentName, @Nullable Element element) { if (myCopiedStorageData == null) { myCopiedStorageData = StorageData.setStateAndCloneIfNeed(componentName, element, myOriginalStorageData, myNewLiveStates); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelEx.java b/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelEx.java index bf07a4ad2cd1..7eb8000a7af3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/ex/DiffPanelEx.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -40,7 +40,7 @@ public interface DiffPanelEx extends DiffPanel, Disposable { DiffPanelOptions getOptions(); - void setComparisonPolicy(ComparisonPolicy comparisonPolicy); + void setComparisonPolicy(@NotNull ComparisonPolicy comparisonPolicy); ComparisonPolicy getComparisonPolicy(); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index 7d1183a233c9..fbdde51e8761 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -180,17 +180,16 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid myDataProvider = new MyGenericDataProvider(this); myPanel.setDataProvider(myDataProvider); - final ComparisonPolicy comparisonPolicy = getComparisonPolicy(); - final ComparisonPolicy defaultComparisonPolicy = DiffManagerImpl.getInstanceEx().getComparisonPolicy(); - final HighlightMode highlightMode = getHighlightMode(); - final HighlightMode defaultHighlightMode = DiffManagerImpl.getInstanceEx().getHighlightMode(); + ComparisonPolicy comparisonPolicy = getComparisonPolicy(); + if (comparisonPolicy != DiffManagerImpl.getInstanceEx().getComparisonPolicy()) { + setComparisonPolicy(comparisonPolicy); + } - if (defaultComparisonPolicy != null && comparisonPolicy != defaultComparisonPolicy) { - setComparisonPolicy(defaultComparisonPolicy); - } - if (defaultHighlightMode != null && highlightMode != defaultHighlightMode) { - setHighlightMode(defaultHighlightMode); + HighlightMode highlightMode = getHighlightMode(); + if (highlightMode != DiffManagerImpl.getInstanceEx().getHighlightMode()) { + setHighlightMode(highlightMode); } + myVisibleAreaListener = new VisibleAreaListener() { @Override public void visibleAreaChanged(VisibleAreaEvent e) { @@ -504,11 +503,11 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid return myData.getComparisonPolicy(); } - public void setComparisonPolicy(ComparisonPolicy comparisonPolicy) { + public void setComparisonPolicy(@NotNull ComparisonPolicy comparisonPolicy) { setComparisonPolicy(comparisonPolicy, true); } - private void setComparisonPolicy(ComparisonPolicy policy, boolean notifyManager) { + private void setComparisonPolicy(@NotNull ComparisonPolicy policy, boolean notifyManager) { myData.setComparisonPolicy(policy); rediff(); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/CompositeDiffTool.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/CompositeDiffTool.java index d4948e11ee1a..15d51eec5d28 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/CompositeDiffTool.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/CompositeDiffTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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,7 +18,10 @@ package com.intellij.openapi.diff.impl.external; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.diff.*; +import com.intellij.openapi.diff.DiffContent; +import com.intellij.openapi.diff.DiffRequest; +import com.intellij.openapi.diff.DiffTool; +import com.intellij.openapi.diff.DiffViewer; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.UIBasedFileType; import org.jetbrains.annotations.NotNull; @@ -26,16 +29,21 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; class CompositeDiffTool implements DiffTool { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.external.CompositeDiffTool"); private final List myTools; - public CompositeDiffTool(List tools) { + public CompositeDiffTool(@NotNull List tools) { myTools = new ArrayList(tools); } + public CompositeDiffTool(@NotNull DiffTool[] tools) { + myTools = Arrays.asList(tools); + } + public void show(DiffRequest data) { checkDiffData(data); DiffTool tool = chooseTool(data); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java index aeb362bf68fe..2a842e99041d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/DiffManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,6 +16,10 @@ package com.intellij.openapi.diff.impl.external; import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.DiffManager; import com.intellij.openapi.diff.DiffPanel; @@ -29,8 +33,11 @@ import com.intellij.openapi.diff.impl.processing.HighlightMode; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.markup.MarkupEditorFilter; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.util.SmartList; import com.intellij.util.config.*; +import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -39,8 +46,16 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; -public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { +@State( + name = "DiffManager", + storages = { + @Storage(file = StoragePathMacros.APP_CONFIG + "/diff.xml"), + @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true) + } +) +public class DiffManagerImpl extends DiffManager implements PersistentStateComponent { public static final int FULL_DIFF_DIVIDER_POLYGONS_OFFSET = 3; private static final Logger LOG = Logger.getInstance(DiffManagerImpl.class); @@ -50,7 +65,10 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { @Override public String readValue(Element dataElement) { String path = dataElement.getAttributeValue(NEW_VALUE); - if (path != null) return path; + if (path != null) { + return path; + } + String prevValue = dataElement.getAttributeValue(VALUE_ATTRIBUTE); return prevValue != null ? prevValue.trim() : null; } @@ -70,9 +88,8 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { public static final BooleanProperty ENABLE_FILES = new BooleanProperty("enableFiles", false); public static final BooleanProperty ENABLE_MERGE = new BooleanProperty("enableMerge", false); - private final ExternalizablePropertyContainer myProperties; - private final ArrayList myAdditionTools = new ArrayList(); + private final List myAdditionTools = new SmartList(); public static final DiffTool INTERNAL_DIFF = new FrameDiffTool(); public static final Key EDITOR_IS_DIFF_KEY = new Key("EDITOR_IS_DIFF_KEY"); @@ -82,8 +99,9 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { return DiffUtil.isDiffEditor(editor); } }; - private ComparisonPolicy myComparisonPolicy; - private HighlightMode myHighlightMode; + + private ComparisonPolicy myComparisonPolicy = ComparisonPolicy.DEFAULT; + private HighlightMode myHighlightMode = HighlightMode.BY_WORD; @NonNls public static final String COMPARISON_POLICY_ATTR_NAME = "COMPARISON_POLICY"; @NonNls public static final String HIGHLIGHT_MODE_ATTR_NAME = "HIGHLIGHT_MODE"; @@ -100,13 +118,15 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { } @Override - public DiffTool getIdeaDiffTool() { return INTERNAL_DIFF; } + public DiffTool getIdeaDiffTool() { + return INTERNAL_DIFF; + } @Override public DiffTool getDiffTool() { DiffTool[] standardTools; // there is inner check in multiple tool for external viewers as well - if (! ENABLE_FILES.value(myProperties) || ! ENABLE_FOLDERS.value(myProperties) || !ENABLE_MERGE.value(myProperties)) { + if (!ENABLE_FILES.value(myProperties) || !ENABLE_FOLDERS.value(myProperties) || !ENABLE_MERGE.value(myProperties)) { DiffTool[] embeddableTools = { INTERNAL_DIFF, new MergeTool(), @@ -121,7 +141,8 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { new MergeTool(), BinaryDiffTool.INSTANCE }; - } else { + } + else { standardTools = new DiffTool[]{ ExtCompareFolders.INSTANCE, ExtCompareFiles.INSTANCE, @@ -131,14 +152,22 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { BinaryDiffTool.INSTANCE }; } - ArrayList allTools = new ArrayList(myAdditionTools); - allTools.addAll(Arrays.asList(standardTools)); - return new CompositeDiffTool(allTools); + if (myAdditionTools.isEmpty()) { + return new CompositeDiffTool(standardTools); + } + else { + List allTools = new ArrayList(myAdditionTools); + ContainerUtil.addAll(allTools, standardTools); + return new CompositeDiffTool(allTools); + } } @Override public boolean registerDiffTool(@NotNull DiffTool tool) throws NullPointerException { - if (myAdditionTools.contains(tool)) return false; + if (myAdditionTools.contains(tool)) { + return false; + } + myAdditionTools.add(tool); return true; } @@ -149,7 +178,7 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { LOG.assertTrue(!myAdditionTools.contains(tool)); } - public ArrayList getAdditionTools() { + public List getAdditionTools() { return myAdditionTools; } @@ -174,28 +203,35 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { return (DiffManagerImpl)DiffManager.getInstance(); } + @Nullable @Override - public void readExternal(@NotNull Element element) throws InvalidDataException { - myProperties.readExternal(element); - readPolicy(element); - readMode(element); + public Element getState() { + Element state = new Element("state"); + myProperties.writeExternal(state); + if (myComparisonPolicy != ComparisonPolicy.DEFAULT) { + state.setAttribute(COMPARISON_POLICY_ATTR_NAME, myComparisonPolicy.getName()); + } + if (myHighlightMode != HighlightMode.BY_WORD) { + state.setAttribute(HIGHLIGHT_MODE_ATTR_NAME, myHighlightMode.name()); + } + return state; } - private void readPolicy(@NotNull final Element element) { - final String policyName = element.getAttributeValue(COMPARISON_POLICY_ATTR_NAME); + @Override + public void loadState(Element state) { + myProperties.readExternal(state); + + String policyName = state.getAttributeValue(COMPARISON_POLICY_ATTR_NAME); if (policyName != null) { - ComparisonPolicy[] policies = ComparisonPolicy.getAllInstances(); - for (ComparisonPolicy policy : policies) { + for (ComparisonPolicy policy : ComparisonPolicy.getAllInstances()) { if (policy.getName().equals(policyName)) { myComparisonPolicy = policy; break; } } } - } - private void readMode(@NotNull final Element element) { - final String modeName = element.getAttributeValue(HIGHLIGHT_MODE_ATTR_NAME); + String modeName = state.getAttributeValue(HIGHLIGHT_MODE_ATTR_NAME); if (modeName != null) { try { myHighlightMode = HighlightMode.valueOf(modeName); @@ -205,19 +241,10 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { } } - @Override - public void writeExternal(@NotNull Element element) throws WriteExternalException { - myProperties.writeExternal(element); - if (myComparisonPolicy != null) { - element.setAttribute(COMPARISON_POLICY_ATTR_NAME, myComparisonPolicy.getName()); - } - if (myHighlightMode != null) { - element.setAttribute(HIGHLIGHT_MODE_ATTR_NAME, myHighlightMode.name()); - } + public AbstractProperty.AbstractPropertyContainer getProperties() { + return myProperties; } - public AbstractProperty.AbstractPropertyContainer getProperties() { return myProperties; } - static DiffPanel createDiffPanel(DiffRequest data, Window window, @NotNull Disposable parentDisposable, FrameDiffTool tool) { DiffPanel diffPanel = null; try { @@ -236,21 +263,21 @@ public class DiffManagerImpl extends DiffManager implements JDOMExternalizable { } } - public void setComparisonPolicy(final ComparisonPolicy p) { - myComparisonPolicy = p; - } - - @Nullable + @NotNull public ComparisonPolicy getComparisonPolicy() { return myComparisonPolicy; } - public void setHighlightMode(HighlightMode highlightMode) { - myHighlightMode = highlightMode; + public void setComparisonPolicy(@NotNull ComparisonPolicy value) { + myComparisonPolicy = value; } - @Nullable + @NotNull public HighlightMode getHighlightMode() { return myHighlightMode; } + + public void setHighlightMode(@NotNull HighlightMode highlightMode) { + myHighlightMode = highlightMode; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/FrameDiffTool.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/FrameDiffTool.java index b71eeda448a1..9fbb0b2cae55 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/FrameDiffTool.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/external/FrameDiffTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -28,7 +28,6 @@ import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.FrameWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ex.MessagesEx; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -40,8 +39,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; -// Author: dyoma - public class FrameDiffTool implements DiffTool { public void show(DiffRequest request) { Collection hints = request.getHints(); @@ -161,27 +158,27 @@ public class FrameDiffTool implements DiffTool { // TODO remove check? private boolean checkNoDifferenceAndNotify(DiffPanel diffPanel, DiffRequest data, final Window window, final boolean showMessage) { - if (!diffPanel.hasDifferences() && !data.getHints().contains(HINT_ALLOW_NO_DIFFERENCES)) { - DiffManagerImpl manager = (DiffManagerImpl) DiffManager.getInstance(); - if (!Comparing.equal(manager.getComparisonPolicy(), ComparisonPolicy.DEFAULT)) { - ComparisonPolicy oldPolicy = manager.getComparisonPolicy(); - manager.setComparisonPolicy(ComparisonPolicy.DEFAULT); - Disposable parentDisposable = Disposer.newDisposable(); - DiffPanel maybeDiffPanel = DiffManagerImpl.createDiffPanel(data, window, parentDisposable, this); - manager.setComparisonPolicy(oldPolicy); - - boolean hasDiffs = maybeDiffPanel.hasDifferences(); - Disposer.dispose(parentDisposable); - - if (hasDiffs) return false; - } - - if (! showMessage) { - return true; - } - return !askForceOpenDiff(data); + if (diffPanel.hasDifferences() || data.getHints().contains(HINT_ALLOW_NO_DIFFERENCES)) { + return false; } - return false; + + DiffManagerImpl manager = (DiffManagerImpl)DiffManager.getInstance(); + ComparisonPolicy oldPolicy = manager.getComparisonPolicy(); + if (oldPolicy != ComparisonPolicy.DEFAULT) { + manager.setComparisonPolicy(ComparisonPolicy.DEFAULT); + Disposable parentDisposable = Disposer.newDisposable(); + DiffPanel maybeDiffPanel = DiffManagerImpl.createDiffPanel(data, window, parentDisposable, this); + manager.setComparisonPolicy(oldPolicy); + + boolean hasDiffs = maybeDiffPanel.hasDifferences(); + Disposer.dispose(parentDisposable); + + if (hasDiffs) { + return false; + } + } + + return !showMessage || !askForceOpenDiff(data); } private static boolean askForceOpenDiff(DiffRequest data) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java index fc26cf634e88..ccaa5190e587 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/SimpleDiffPanelState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,7 +19,10 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.ContentChangeListener; -import com.intellij.openapi.diff.impl.fragments.*; +import com.intellij.openapi.diff.impl.fragments.FragmentHighlighterImpl; +import com.intellij.openapi.diff.impl.fragments.FragmentList; +import com.intellij.openapi.diff.impl.fragments.FragmentListImpl; +import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.processing.DiffPolicy; import com.intellij.openapi.diff.impl.processing.HighlightMode; import com.intellij.openapi.diff.impl.processing.TextCompareProcessor; @@ -58,7 +61,7 @@ public abstract class SimpleDiffPanelState implements Disposable { return editorWrapper; } - public void setComparisonPolicy(ComparisonPolicy comparisonPolicy) { + public void setComparisonPolicy(@NotNull ComparisonPolicy comparisonPolicy) { myComparisonPolicy = comparisonPolicy; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/AbstractToggleUseSoftWrapsAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/AbstractToggleUseSoftWrapsAction.java index b5662c6ab49f..69e4f7b2991e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/AbstractToggleUseSoftWrapsAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/AbstractToggleUseSoftWrapsAction.java @@ -17,12 +17,12 @@ package com.intellij.openapi.editor.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.ToggleAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; +import com.intellij.openapi.project.DumbAware; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable; * @author Denis Zhdanov * @since Aug 23, 2010 11:33:35 AM */ -public abstract class AbstractToggleUseSoftWrapsAction extends ToggleAction { +public abstract class AbstractToggleUseSoftWrapsAction extends ToggleAction implements DumbAware { private final SoftWrapAppliancePlaces myAppliancePlace; private final boolean myGlobal; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java index 95a4ab25444b..866bc141d47f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java @@ -63,19 +63,6 @@ public class EditorComponentImpl extends JComponent implements Scrollable, DataP return myEditor.visualPositionToXY(magnificationPosition); } }); - putClientProperty("sun.lwawt.macosx.CInputMethod.selectPreviousGlyph.callback", new Runnable() { - @Override - public void run() { - // This is supposed to be called from sun.lwawt.macosx.CInputMethod class of a custom JDK, - // built for IntelliJ platform running on MacOS. - // This is required to support input of accented characters using press-and-hold method (http://support.apple.com/kb/PH11264). - // Non-patched JDK supports this functionality only for TextComponent/JTextComponent descendants. - int caretOffset = myEditor.getCaretModel().getOffset(); - if (caretOffset > 0) { - myEditor.getSelectionModel().setSelection(caretOffset - 1, caretOffset); - } - } - }); myApplication = (ApplicationImpl)ApplicationManager.getApplication(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index fcdbe2fc4147..ea0ce0da254b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -308,6 +308,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public final boolean myUseNewRendering = Registry.is("editor.new.rendering"); final EditorView myView; + private boolean myCharKeyPressed; + private boolean myNeedToSelectPreviousChar; + private final TIntFunction myLineNumberAreaWidthFunction = new TIntFunction() { @Override public int execute(int lineNumber) { @@ -902,9 +905,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myPanel.add(myScrollPane); } - myEditorComponent.addKeyListener(new KeyAdapter() { + myEditorComponent.addKeyListener(new KeyListener() { @Override public void keyTyped(@NotNull KeyEvent event) { + myNeedToSelectPreviousChar = false; if (event.isConsumed()) { return; } @@ -912,6 +916,18 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi event.consume(); } } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z) { + myCharKeyPressed = true; + } + } + + @Override + public void keyReleased(KeyEvent e) { + myCharKeyPressed = false; + } }); MyMouseAdapter mouseAdapter = new MyMouseAdapter(); @@ -5413,6 +5429,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @Override @Nullable public AttributedCharacterIterator getSelectedText(AttributedCharacterIterator.Attribute[] attributes) { + if (myCharKeyPressed) { + myNeedToSelectPreviousChar = true; + } String text = getSelectionModel().getSelectedText(); return text == null ? null : new AttributedString(text).getIterator(); } @@ -5457,6 +5476,22 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } private void replaceInputMethodText(@NotNull InputMethodEvent e) { + if (myNeedToSelectPreviousChar && SystemInfo.isMac && Registry.is("ide.mac.pressAndHold.workaround")) { + // This is required to support input of accented characters using press-and-hold method (http://support.apple.com/kb/PH11264). + // JDK currently properly supports this functionality only for TextComponent/JTextComponent descendants. + // For our editor component we need this workaround. + myNeedToSelectPreviousChar = false; + getCaretModel().runForEachCaret(new CaretAction() { + @Override + public void perform(Caret caret) { + int caretOffset = caret.getOffset(); + if (caretOffset > 0) { + caret.setSelection(caretOffset - 1, caretOffset); + } + } + }); + } + int commitCount = e.getCommittedCharacterCount(); AttributedCharacterIterator text = e.getText(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java index d39877081825..e234be4f0b2a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java @@ -185,6 +185,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi if ((myUseSoftWraps ^ softWrapsUsedBefore) || (tabWidthBefore >= 0 && myTabWidth != tabWidthBefore) || fontsChanged) { myApplianceManager.reset(); myDeferredFoldRegions.clear(); + myStorage.removeAll(); myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); } } @@ -286,9 +287,6 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, PrioritizedDocumentLi * @return total number of soft wrap-introduced new visual lines */ public int getSoftWrapsIntroducedLinesNumber() { - if (!isSoftWrappingEnabled()) { - return 0; - } return myStorage.getSoftWraps().size(); // Assuming that soft wrap has single line feed all the time } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java index db2e8c7a6e84..7a5d9843d3e6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java @@ -17,6 +17,7 @@ package com.intellij.openapi.fileChooser.ex; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.SaveAndSyncHandler; import com.intellij.ide.SaveAndSyncHandlerImpl; import com.intellij.ide.util.PropertiesComponent; import com.intellij.ide.util.treeView.NodeRenderer; @@ -356,7 +357,7 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD .subscribe(ApplicationActivationListener.TOPIC, new ApplicationActivationListener.Adapter() { @Override public void applicationActivated(IdeFrame ideFrame) { - SaveAndSyncHandlerImpl.getInstance().maybeRefresh(ModalityState.current()); + ((SaveAndSyncHandlerImpl)SaveAndSyncHandler.getInstance()).maybeRefresh(ModalityState.current()); } }); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java index 4a0da5a97736..ba7cf5900e0f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsEditor.java @@ -29,6 +29,7 @@ import com.intellij.openapi.ui.OnePixelDivider; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.OnePixelSplitter; import com.intellij.ui.components.panels.VerticalLayout; import com.intellij.ui.treeStructure.SimpleNode; @@ -40,9 +41,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.KeyEvent; +import java.awt.event.*; import java.util.LinkedHashMap; import java.util.Map; @@ -235,7 +234,9 @@ final class SettingsEditor extends AbstractEditor implements DataProvider { mySpotlightPainter = new SpotlightPainter(myEditor, this) { void updateNow() { Configurable configurable = myFilter.myContext.getCurrentConfigurable(); - update(myFilter, configurable, myEditor.getContent(configurable)); + if (myTreeView.myTree.hasFocus() || mySearch.getTextEditor().hasFocus()) { + update(myFilter, configurable, myEditor.getContent(configurable)); + } } }; add(BorderLayout.CENTER, mySplitter); @@ -250,6 +251,29 @@ final class SettingsEditor extends AbstractEditor implements DataProvider { myFilter.update(filter, false, true); myTreeView.select(configurable); Disposer.register(this, myTreeView); + installSpotlightRemover(); + } + + private void installSpotlightRemover() { + final FocusAdapter spotlightRemover = new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + final Component comp = e.getOppositeComponent(); + if (comp == mySearch.getTextEditor() || comp == myTreeView.myTree) { + return; + } + mySpotlightPainter.update(null, null, null); + } + + @Override + public void focusGained(FocusEvent e) { + if (!StringUtil.isEmpty(mySearch.getText())) { + mySpotlightPainter.updateNow(); + } + } + }; + myTreeView.myTree.addFocusListener(spotlightRemover); + mySearch.getTextEditor().addFocusListener(spotlightRemover); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index 4932c584a1e5..6b9b702ad443 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -49,10 +49,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Map; -public class DumbServiceImpl extends DumbService implements Disposable { +public class DumbServiceImpl extends DumbService implements Disposable, ModificationTracker { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.project.DumbServiceImpl"); private volatile boolean myDumb = false; private final DumbModeListener myPublisher; + private long myModificationCount; private final Queue myUpdatesQueue = new Queue(5); /** @@ -116,6 +117,11 @@ public class DumbServiceImpl extends DumbService implements Disposable { myAlternativeResolution.set(enabled); } + @Override + public ModificationTracker getModificationTracker() { + return null; + } + @Override public boolean isDumb() { return myDumb; @@ -209,6 +215,7 @@ public class DumbServiceImpl extends DumbService implements Disposable { @Override public Boolean compute() { myDumb = true; + myModificationCount++; try { myPublisher.enteredDumbMode(); } @@ -236,6 +243,7 @@ public class DumbServiceImpl extends DumbService implements Disposable { private void updateFinished() { myDumb = false; + myModificationCount++; if (myProject.isDisposed()) return; if (ApplicationManager.getApplication().isInternal()) LOG.info("updateFinished"); @@ -440,6 +448,11 @@ public class DumbServiceImpl extends DumbService implements Disposable { return result.get(); } + @Override + public long getModificationCount() { + return myModificationCount; + } + private class AppIconProgress extends ProgressIndicatorBase { private double lastFraction; diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index f12e25ba113d..401d3e5f9c09 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -29,12 +29,8 @@ import com.intellij.openapi.application.*; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.application.impl.ApplicationImpl; import com.intellij.openapi.components.*; -import com.intellij.openapi.components.impl.stores.ComponentStoreImpl; +import com.intellij.openapi.components.impl.stores.*; import com.intellij.openapi.components.impl.stores.ComponentStoreImpl.ReloadComponentStoreStatus; -import com.intellij.openapi.components.impl.stores.FileBasedStorage; -import com.intellij.openapi.components.impl.stores.StateStorageManager; -import com.intellij.openapi.components.impl.stores.StorageUtil; -import com.intellij.openapi.components.store.StateStorageBase; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.*; diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java index 7717de4a616d..28af087d7816 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/impl/GlassPaneDialogWrapperPeer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -41,6 +41,7 @@ import com.intellij.openapi.wm.impl.IdeGlassPaneEx; import com.intellij.ui.FocusTrackback; import com.intellij.ui.ScreenUtil; import com.intellij.ui.components.JBLayeredPane; +import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -591,7 +592,7 @@ public class GlassPaneDialogWrapperPeer extends DialogWrapperPeer implements Foc } private void createShadow() { - if (!UISettings.isRemoteDesktopConnected()) { + if (!UISettings.isRemoteDesktopConnected() && !JBUI.isHiDPI()) { shadow = ShadowBorderPainter.createShadow(this, getWidth(), getHeight()); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index bed4e4e11fe4..939eace5d54d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -631,7 +631,7 @@ public final class UpdateChecker { private static boolean ourHasFailedPlugins = false; public static void checkForUpdate(IdeaLoggingEvent event) { - if (!ourHasFailedPlugins && UpdateSettings.getInstance().CHECK_NEEDED) { + if (!ourHasFailedPlugins && UpdateSettings.getInstance().isCheckNeeded()) { final Throwable throwable = event.getThrowable(); final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(IdeErrorsDialog.findPluginId(throwable)); if (pluginDescriptor != null && !pluginDescriptor.isBundled()) { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java index f4436da4a5ee..86858309aeeb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java @@ -25,6 +25,7 @@ import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginsAdvertiser; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Alarm; import com.intellij.util.net.NetUtils; @@ -54,12 +55,13 @@ public class UpdateCheckerComponent implements ApplicationComponent { public UpdateCheckerComponent(@NotNull Application app, @NotNull UpdateSettings settings) { mySettings = settings; - if (mySettings.SECURE_CONNECTION && !NetUtils.isSniEnabled()) { + if (mySettings.isSecureConnection() && !NetUtils.isSniEnabled()) { app.invokeLater(new Runnable() { @Override public void run() { String title = IdeBundle.message("update.notifications.title"); - String message = IdeBundle.message("update.sni.disabled.notification"); + boolean tooOld = !SystemInfo.isJavaVersionAtLeast("1.7"); + String message = IdeBundle.message(tooOld ? "update.sni.not.available.notification" : "update.sni.disabled.notification"); UpdateChecker.NOTIFICATIONS.createNotification(title, message, NotificationType.ERROR, null).notify(null); } }, ModalityState.NON_MODAL); @@ -74,7 +76,7 @@ public class UpdateCheckerComponent implements ApplicationComponent { } private void scheduleOnStartCheck(@NotNull Application app) { - if (!mySettings.CHECK_NEEDED || mySettings.SECURE_CONNECTION && !NetUtils.isSniEnabled()) { + if (!mySettings.isCheckNeeded() || mySettings.isSecureConnection() && !NetUtils.isSniEnabled()) { return; } @@ -82,9 +84,9 @@ public class UpdateCheckerComponent implements ApplicationComponent { @Override public void appFrameCreated(String[] commandLineArgs, @NotNull Ref willOpenProject) { String currentBuild = ApplicationInfo.getInstance().getBuild().asString(); - long timeToNextCheck = mySettings.LAST_TIME_CHECKED + CHECK_INTERVAL - System.currentTimeMillis(); + long timeToNextCheck = mySettings.getLastTimeChecked() + CHECK_INTERVAL - System.currentTimeMillis(); - if (StringUtil.compareVersionNumbers(mySettings.LAST_BUILD_CHECKED, currentBuild) < 0 || timeToNextCheck <= 0) { + if (StringUtil.compareVersionNumbers(mySettings.getLasBuildChecked(), currentBuild) < 0 || timeToNextCheck <= 0) { myCheckRunnable.run(); } else { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java index 14d63c9d6bd5..0d6d45a99aa8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java @@ -18,15 +18,13 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.components.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.DefaultJDOMExternalizer; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.JDOMExternalizableStringList; -import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.net.NetUtils; -import org.jdom.Element; +import com.intellij.util.xmlb.annotations.CollectionBean; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -38,94 +36,128 @@ import java.util.List; @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true) } ) -public class UpdateSettings implements PersistentStateComponent, UserUpdateSettings { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.updateSettings.impl.UpdateSettings"); - - public JDOMExternalizableStringList myPluginHosts = new JDOMExternalizableStringList(); - public JDOMExternalizableStringList myKnownUpdateChannels = new JDOMExternalizableStringList(); - public JDOMExternalizableStringList myIgnoredBuildNumbers = new JDOMExternalizableStringList(); - public JDOMExternalizableStringList myOutdatedPlugins = new JDOMExternalizableStringList(); - - public boolean CHECK_NEEDED = true; - public long LAST_TIME_CHECKED = 0; - public String LAST_BUILD_CHECKED = ""; - public String UPDATE_CHANNEL_TYPE = ChannelStatus.RELEASE_CODE; - public boolean SECURE_CONNECTION = false; - - public static UpdateSettings getInstance() { - return ServiceManager.getService(UpdateSettings.class); - } +public class UpdateSettings implements PersistentStateComponent, UserUpdateSettings { + private State myState = new State(); public UpdateSettings() { updateDefaultChannel(); } + public static UpdateSettings getInstance() { + return ServiceManager.getService(UpdateSettings.class); + } + + static class State { + @CollectionBean + public final List pluginHosts = new SmartList(); + @CollectionBean + public final List knownUpdateChannels = new SmartList(); + @CollectionBean + public final List ignoredBuildNumbers = new SmartList(); + @CollectionBean + public final List outdatedPlugins = new SmartList(); + + public boolean CHECK_NEEDED = true; + public long LAST_TIME_CHECKED = 0; + + public String LAST_BUILD_CHECKED; + public String UPDATE_CHANNEL_TYPE = ChannelStatus.RELEASE_CODE; + public boolean SECURE_CONNECTION = false; + } + + @Nullable + public String getLasBuildChecked() { + return myState.LAST_BUILD_CHECKED; + } + + @NotNull + public List getStoredPluginHosts() { + return myState.pluginHosts; + } + + public boolean isCheckNeeded() { + return myState.CHECK_NEEDED; + } + + public void setCheckNeeded(boolean value) { + myState.CHECK_NEEDED = value; + } + + public boolean isSecureConnection() { + return myState.SECURE_CONNECTION; + } + + public void setSecureConnection(boolean value) { + myState.SECURE_CONNECTION = value; + } + + @NotNull + public String getUpdateChannelType() { + return myState.UPDATE_CHANNEL_TYPE; + } + + public long getLastTimeChecked() { + return myState.LAST_TIME_CHECKED; + } + + public void setUpdateChannelType(@NotNull String value) { + myState.UPDATE_CHANNEL_TYPE = value; + } + + @NotNull + public List getOutdatedPlugins() { + return myState.outdatedPlugins; + } + private void updateDefaultChannel() { if (ApplicationInfoImpl.getShadowInstance().isEAP()) { - UPDATE_CHANNEL_TYPE = ChannelStatus.EAP_CODE; + myState.UPDATE_CHANNEL_TYPE = ChannelStatus.EAP_CODE; } } - @SuppressWarnings("deprecation") @Override - public Element getState() { - Element element = new Element("state"); - try { - DefaultJDOMExternalizer.writeExternal(this, element); - } - catch (WriteExternalException e) { - LOG.info(e); - } - return element; + public State getState() { + return myState; } - @SuppressWarnings("deprecation") @Override - public void loadState(Element state) { - try { - DefaultJDOMExternalizer.readExternal(this, state); - } - catch (InvalidDataException e) { - LOG.info(e); - } + public void loadState(State state) { + myState = state; + myState.LAST_BUILD_CHECKED = StringUtil.nullize(myState.LAST_BUILD_CHECKED); updateDefaultChannel(); } @NotNull @Override public List getKnownChannelsIds() { - List ids = new ArrayList(); - for (String channel : myKnownUpdateChannels) { - ids.add(channel); - } - return ids; + return new ArrayList(myState.knownUpdateChannels); } @Override public void setKnownChannelIds(@NotNull List ids) { - myKnownUpdateChannels.clear(); + myState.knownUpdateChannels.clear(); for (String id : ids) { - myKnownUpdateChannels.add(id); + myState.knownUpdateChannels.add(id); } } public void forgetChannelId(String id) { - myKnownUpdateChannels.remove(id); + myState.knownUpdateChannels.remove(id); } @Override public List getIgnoredBuildNumbers() { - return myIgnoredBuildNumbers; + return myState.ignoredBuildNumbers; } @NotNull @Override public ChannelStatus getSelectedChannelStatus() { - return ChannelStatus.fromCode(UPDATE_CHANNEL_TYPE); + return ChannelStatus.fromCode(myState.UPDATE_CHANNEL_TYPE); } public List getPluginHosts() { - List hosts = new ArrayList(myPluginHosts); + List hosts = new ArrayList(myState.pluginHosts); String pluginHosts = System.getProperty("idea.plugin.hosts"); if (pluginHosts != null) { ContainerUtil.addAll(hosts, pluginHosts.split(";")); @@ -134,15 +166,15 @@ public class UpdateSettings implements PersistentStateComponent, UserUp } public void forceCheckForUpdateAfterRestart() { - LAST_TIME_CHECKED = 0; + myState.LAST_TIME_CHECKED = 0; } public void saveLastCheckedInfo() { - LAST_TIME_CHECKED = System.currentTimeMillis(); - LAST_BUILD_CHECKED = ApplicationInfo.getInstance().getBuild().asString(); + myState.LAST_TIME_CHECKED = System.currentTimeMillis(); + myState.LAST_BUILD_CHECKED = ApplicationInfo.getInstance().getBuild().asString(); } public boolean canUseSecureConnection() { - return SECURE_CONNECTION && NetUtils.isSniEnabled(); + return myState.SECURE_CONNECTION && NetUtils.isSniEnabled(); } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java index 9da0dbd415ea..8932a6b0425a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java @@ -25,6 +25,7 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.util.net.NetUtils; import com.intellij.util.text.DateFormatUtil; @@ -64,6 +65,7 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear return "preferences.updates"; } + @Override @NotNull public String getId() { return getHelpTopic(); @@ -79,9 +81,9 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear public void apply() throws ConfigurationException { UpdateSettings settings = UpdateSettings.getInstance(); - boolean wasEnabled = settings.CHECK_NEEDED; - settings.CHECK_NEEDED = myUpdatesSettingsPanel.myCheckForUpdates.isSelected(); - if (wasEnabled != settings.CHECK_NEEDED) { + boolean wasEnabled = settings.isCheckNeeded(); + settings.setCheckNeeded(myUpdatesSettingsPanel.myCheckForUpdates.isSelected()); + if (wasEnabled != settings.isCheckNeeded()) { UpdateCheckerComponent checker = ApplicationManager.getApplication().getComponent(UpdateCheckerComponent.class); if (checker != null) { if (wasEnabled) { @@ -93,27 +95,33 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear } } - settings.UPDATE_CHANNEL_TYPE = myUpdatesSettingsPanel.getSelectedChannelType().getCode(); - settings.SECURE_CONNECTION = myUpdatesSettingsPanel.myUseSecureConnection.isSelected(); + settings.setUpdateChannelType(myUpdatesSettingsPanel.getSelectedChannelType().getCode()); + settings.setSecureConnection(myUpdatesSettingsPanel.myUseSecureConnection.isSelected()); } @Override public void reset() { UpdateSettings settings = UpdateSettings.getInstance(); - myUpdatesSettingsPanel.myCheckForUpdates.setSelected(settings.CHECK_NEEDED); - myUpdatesSettingsPanel.myUseSecureConnection.setSelected(settings.SECURE_CONNECTION); + myUpdatesSettingsPanel.myCheckForUpdates.setSelected(settings.isCheckNeeded()); + myUpdatesSettingsPanel.myUseSecureConnection.setSelected(settings.isSecureConnection()); myUpdatesSettingsPanel.updateLastCheckedLabel(); - myUpdatesSettingsPanel.setSelectedChannelType(ChannelStatus.fromCode(settings.UPDATE_CHANNEL_TYPE)); + myUpdatesSettingsPanel.setSelectedChannelType(ChannelStatus.fromCode(settings.getUpdateChannelType())); } @Override public boolean isModified() { - if (myUpdatesSettingsPanel == null) return false; + if (myUpdatesSettingsPanel == null) { + return false; + } + UpdateSettings settings = UpdateSettings.getInstance(); - if (settings.CHECK_NEEDED != myUpdatesSettingsPanel.myCheckForUpdates.isSelected()) return true; - if (settings.SECURE_CONNECTION != myUpdatesSettingsPanel.myUseSecureConnection.isSelected()) return true; + if (settings.isCheckNeeded() != myUpdatesSettingsPanel.myCheckForUpdates.isSelected() || + settings.isSecureConnection() != myUpdatesSettingsPanel.myUseSecureConnection.isSelected()) { + return true; + } + Object channel = myUpdatesSettingsPanel.myUpdateChannels.getSelectedItem(); - return channel != null && !channel.equals(ChannelStatus.fromCode(settings.UPDATE_CHANNEL_TYPE)); + return channel != null && !channel.equals(ChannelStatus.fromCode(settings.getUpdateChannelType())); } @Override @@ -148,12 +156,13 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear myBuildNumber.setText(appInfo.getBuild().asString()); myCheckNow.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myCheckNow)); UpdateSettings settings = new UpdateSettings(); settings.loadState(UpdateSettings.getInstance().getState()); - settings.UPDATE_CHANNEL_TYPE = getSelectedChannelType().getCode(); - settings.SECURE_CONNECTION = myUseSecureConnection.isSelected(); + settings.setUpdateChannelType(getSelectedChannelType().getCode()); + settings.setSecureConnection(myUseSecureConnection.isSelected()); UpdateChecker.updateAndShowResult(project, settings); updateLastCheckedLabel(); } @@ -163,16 +172,18 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear UpdateSettings settings = UpdateSettings.getInstance(); //noinspection unchecked - myUpdateChannels.setModel(new CollectionComboBoxModel(ChannelStatus.all(), ChannelStatus.fromCode(settings.UPDATE_CHANNEL_TYPE))); + myUpdateChannels.setModel(new CollectionComboBoxModel(ChannelStatus.all(), ChannelStatus.fromCode(settings.getUpdateChannelType()))); if (!NetUtils.isSniEnabled()) { myUseSecureConnection.setEnabled(false); - myUseSecureConnection.setToolTipText(IdeBundle.message("update.sni.disabled.notification")); + boolean tooOld = !SystemInfo.isJavaVersionAtLeast("1.7"); + String message = IdeBundle.message(tooOld ? "update.sni.not.available.notification" : "update.sni.disabled.notification"); + myUseSecureConnection.setToolTipText(message); } } private void updateLastCheckedLabel() { - long time = UpdateSettings.getInstance().LAST_TIME_CHECKED; + long time = UpdateSettings.getInstance().getLastTimeChecked(); myLastCheckedDate.setText(time == 0 ? IdeBundle.message("updates.last.check.never") : DateFormatUtil.formatPrettyDateTime(time)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java index 742fc08eb103..21eede8dc417 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -220,7 +220,9 @@ public class PluginsAdvertiser implements StartupActivity { @Override public void runActivity(@NotNull final Project project) { - if (!UpdateSettings.getInstance().CHECK_NEEDED) return; + if (!UpdateSettings.getInstance().isCheckNeeded()) { + return; + } final UnknownFeaturesCollector collectorSuggester = UnknownFeaturesCollector.getInstance(project); final Set unknownFeatures = collectorSuggester.getUnknownFeatures(); final KnownExtensions extensions = loadExtensions(); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToggleReadOnlyAttributePanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToggleReadOnlyAttributePanel.java index b01c167917d9..3b89e81eb1f5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToggleReadOnlyAttributePanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/ToggleReadOnlyAttributePanel.java @@ -20,7 +20,8 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; +import com.intellij.openapi.fileEditor.impl.EditorsSplitters; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; @@ -42,13 +43,7 @@ public class ToggleReadOnlyAttributePanel implements StatusBarWidget.Multiframe, @NotNull public Icon getIcon() { - Project project = getProject(); - VirtualFile virtualFile = null; - if (project != null) { - FileEditorManager editorManager = FileEditorManager.getInstance(project); - VirtualFile[] selectedFiles = editorManager.getSelectedFiles(); - virtualFile = selectedFiles.length > 0 ? selectedFiles[0] : null; - } + VirtualFile virtualFile = getCurrentFile(); return virtualFile == null || virtualFile.isWritable() ? AllIcons.Ide.Readwrite : AllIcons.Ide.Readonly; } @@ -82,13 +77,8 @@ public class ToggleReadOnlyAttributePanel implements StatusBarWidget.Multiframe, public Consumer getClickConsumer() { return new Consumer() { public void consume(MouseEvent mouseEvent) { - final Project project = getProject(); - if (project == null) { - return; - } - final FileEditorManager editorManager = FileEditorManager.getInstance(project); - final VirtualFile[] files = editorManager.getSelectedFiles(); - if (!isReadOnlyApplicableForFiles(files)) { + final VirtualFile file = getCurrentFile(); + if (!isReadOnlyApplicableForFile(file)) { return; } FileDocumentManager.getInstance().saveAllDocuments(); @@ -96,11 +86,11 @@ public class ToggleReadOnlyAttributePanel implements StatusBarWidget.Multiframe, ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { try { - ReadOnlyAttributeUtil.setReadOnlyAttribute(files[0], files[0].isWritable()); + ReadOnlyAttributeUtil.setReadOnlyAttribute(file, file.isWritable()); myStatusBar.updateWidget(ID()); } catch (IOException e) { - Messages.showMessageDialog(project, e.getMessage(), UIBundle.message("error.dialog.title"), Messages.getErrorIcon()); + Messages.showMessageDialog(getProject(), e.getMessage(), UIBundle.message("error.dialog.title"), Messages.getErrorIcon()); } } }); @@ -109,20 +99,24 @@ public class ToggleReadOnlyAttributePanel implements StatusBarWidget.Multiframe, } private boolean isReadonlyApplicable() { - final Project project = getProject(); - if (project == null) return false; - final FileEditorManager editorManager = FileEditorManager.getInstance(project); - if (editorManager == null) return false; - VirtualFile[] selectedFiles = editorManager.getSelectedFiles(); - return isReadOnlyApplicableForFiles(selectedFiles); + VirtualFile file = getCurrentFile(); + return isReadOnlyApplicableForFile(file); } - private static boolean isReadOnlyApplicableForFiles(final VirtualFile[] files) { - return files.length > 0 && !files[0].getFileSystem().isReadOnly(); + private static boolean isReadOnlyApplicableForFile(@Nullable VirtualFile file) { + return file != null && !file.getFileSystem().isReadOnly(); } @Nullable private Project getProject() { return CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext((JComponent) myStatusBar)); } + + @Nullable + private VirtualFile getCurrentFile() { + final Project project = getProject(); + if (project == null) return null; + EditorsSplitters splitters = FileEditorManagerEx.getInstanceEx(project).getSplittersFor(myStatusBar.getComponent()); + return splitters.getCurrentFile(); + } } diff --git a/platform/platform-impl/src/com/intellij/ui/Splash.java b/platform/platform-impl/src/com/intellij/ui/Splash.java index 0bee1412af15..fcab3aa223ab 100644 --- a/platform/platform-impl/src/com/intellij/ui/Splash.java +++ b/platform/platform-impl/src/com/intellij/ui/Splash.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -47,7 +47,7 @@ public class Splash extends JDialog implements StartupProgress { @Nullable public static Rectangle BOUNDS; private final Icon myImage; - private int myProgressHeight = 2; + private int myProgressHeight = JBUI.scale(2); private Color myProgressColor = null; private int myProgressY; private float myProgress; @@ -102,7 +102,7 @@ public class Splash extends JDialog implements StartupProgress { this(info.getSplashImageUrl(), info.getSplashTextColor()); if (info instanceof ApplicationInfoImpl) { final ApplicationInfoImpl appInfo = (ApplicationInfoImpl)info; - myProgressHeight = 2; + myProgressHeight = JBUI.scale(2); myProgressColor = appInfo.getProgressColor(); myProgressY = appInfo.getProgressY(); myProgressTail = appInfo.getProgressTailIcon(); @@ -143,8 +143,8 @@ public class Splash extends JDialog implements StartupProgress { g.setColor(color); g.fillRect(1, getProgressY(), width, getProgressHeight()); if (myProgressTail != null) { - myProgressTail.paintIcon(this, g, width - (myProgressTail.getIconWidth()/2), - getProgressY() - (myProgressTail.getIconHeight() - getProgressHeight())/2); + myProgressTail.paintIcon(this, g, width - (myProgressTail.getIconWidth() / JBUI.scale(1) / 2 * JBUI.scale(1)), + getProgressY() - (myProgressTail.getIconHeight() - getProgressHeight()) / JBUI.scale(1) / 2 * JBUI.scale(1)); //I'll buy you a beer if you understand this line without playing with it } myProgressLastPosition = progressWidth; } diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index fcb584bf709f..90c4521e26c8 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -861,8 +861,8 @@ public class AbstractPopup implements JBPopup { } } }; - ListenerUtil.addMouseListener(myCaption, moveListener); - ListenerUtil.addMouseMotionListener(myCaption, moveListener); + myCaption.addMouseListener(moveListener); + myCaption.addMouseMotionListener(moveListener); final MyContentPanel saved = myContent; Disposer.register(this, new Disposable() { @Override diff --git a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java index 1415af6cbcd0..0dc92839a0f2 100644 --- a/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java +++ b/platform/platform-impl/src/org/jetbrains/io/NettyUtil.java @@ -225,6 +225,7 @@ public final class NettyUtil { .allowCredentials() .allowNullOrigin() .allowedRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE, HttpMethod.HEAD, HttpMethod.PATCH) + .allowedRequestHeaders("origin", "accept", "authorization", "content-type") .build())); } diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 727d96663ff5..89f48f1340cc 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -228,8 +228,8 @@ action.NewClass.text=Java Class action.NewFile.text=File action.NewDir.text=Directory/Package action.NewFromTemplate.text=From Template -action.CompareTwoFiles.text=Compare Two _Files -action.CompareTwoFiles.description=Compare two selected files +action.CompareTwoFiles.text=Compare _Files +action.CompareTwoFiles.description=Compare two selected files or folders action.CompareFileWithEditor.text=Co_mpare File with Editor action.CompareFileWithEditor.description=Compare selected file with editor action.ShowQuickDocAtPinnedWindowFromTooltip.text=Full documentation in a pinned window diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 0e2cdb791edb..e2d6aaca639e 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -283,7 +283,7 @@ goto.test.findUsages.subject.title=Test Subjects for {0} goto.test.notFound=No test subjects found incremental.search.tooltip.prefix=Search for: -goto.super.field.chooser.title=Choose super field +goto.super.property.chooser.title=Choose super property goto.super.method.chooser.title=Choose super method goto.super.method.of.chooser.title=Choose Super Method of {0} goto.super.method.findUsages.title=Super methods of {0} diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index b010f2373daa..806c0c72e97f 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -944,6 +944,7 @@ update.downloading.patch.error=Failed to download patch file:\n{0} update.plugins.update.action=&Update update.restart.plugins.update.action=&Update and Restart update.shutdown.plugins.update.action=&Update and Shutdown +update.sni.not.available.notification=Secure update is not supported on Java 6. Sorry. update.sni.disabled.notification=Secure update is impossible with SNI disabled hierarchy.method.next.occurence.name=Go to next method diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index e8ce7ae50d9c..a16d0325abbf 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -241,5 +241,6 @@ + diff --git a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml index 4c2a05ef506b..62afda53d807 100644 --- a/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml +++ b/platform/platform-resources/src/META-INF/PlatformLangPlugin.xml @@ -71,8 +71,6 @@ - diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index b7f76e554855..d9fe7ef3fa2b 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -1,18 +1,18 @@ // This file contains list of broken plugins. // Each line contains plugin ID and list of versions that are broken. // If plugin name or version contains a space you can quote it like in command line. -NodeJS 140.1669 140.642 139.173 139.105 139.496 139.1 139.8 138.2196 138.2254 138.1684 138.1744 138.1879 138.2051 138.1367 138.1495 138.1189 138.1145 138.937 138.1013 138.921 138.447 138.172 138.317 138.21 138.35 138.96 138.85 136.1205 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 +NodeJS 140.2045 140.1669 140.642 139.173 139.105 139.496 139.1 139.8 138.2196 138.2254 138.1684 138.1744 138.1879 138.2051 138.1367 138.1495 138.1189 138.1145 138.937 138.1013 138.921 138.447 138.172 138.317 138.21 138.35 138.96 138.85 136.1205 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 com.jetbrains.php 139.732 139.659 139.496 139.173 139.105 138.2502 138.2000.2262 138.1751 138.1806 138.1505 138.1161 138.826 136.1768 136.1672 134.1456 133.982 133.679 133.51 133.326 131.98 131.374 131.332 131.235 131.205 130.1639 130.1481 130.1176 129.91 129.814 129.672 129.362 127.67 127.100 126.334 123.66 122.875 121.62 121.390 121.215 121.12 com.jetbrains.lang.ejs 131.17 131.12 com.jetbrains.twig 133.51 130.1639 -org.jetbrains.plugins.ruby 7.0.0.20141010 7.0.0.20140915 7.0.0.20140901 7.0.0.20140807 6.0.0.20140207 6.5.2.20140512 7.0.0.20140704 7.0.0.20140707 7.0.0.20140724 +org.jetbrains.plugins.ruby 7.0.0.20150216 7.0.0.20150204 7.0.0.20141010 7.0.0.20140915 7.0.0.20140901 7.0.0.20140807 6.0.0.20140207 6.5.2.20140512 7.0.0.20140704 7.0.0.20140707 7.0.0.20140724 Pythonid 3.1 4.0.25 4.0.26 -Karma 138.1684 138.1879 138.317 138.21 134.1163 134.1039 134.686 134.31 -org.intellij.scala 1.0.93.10.EAP 1.0.93.4.EAP 1.0.93.9.EAP 1.0.58 1.0.16 1.0.14 1.0.13 0.42.28 0.42.23 0.40.20 0.40.18 0.40.16 0.32.593 0.32.562 0.32.558 0.32.550 0.32.520 0.32.512 +Karma 140.2109 138.1684 138.1879 138.317 138.21 134.1163 134.1039 134.686 134.31 +org.intellij.scala 1.2.67.3.EAP 1.3.2-14.1 1.3.3-14.1 1.0.93.10.EAP 1.0.93.4.EAP 1.0.93.9.EAP 1.0.58 1.0.16 1.0.14 1.0.13 0.42.28 0.42.23 0.40.20 0.40.18 0.40.16 0.32.593 0.32.562 0.32.558 0.32.550 0.32.520 0.32.512 org.jetbrains.kannotator 0.2.420 org.jetbrains.kotlin 0.10.555 0.10.4 0.8.1615 0.7.1360 0.7.1376 0.8.7 SBT 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.5.0 1.5.1 1.6.0 1.6.1 -"JSTestDriver Plugin" 140.1669 140.727 138.317 138.21 136.1141 134.1163 134.686 134.31 134.307 134.1039 +"JSTestDriver Plugin" 140.2109 140.1669 140.727 138.317 138.21 136.1141 134.1163 134.686 134.31 134.307 134.1039 AngularJS 139.1112 139.12 134.1243 134.1341 134.1444 135.1063 135.565 135.831 135.937 138.1242 138.1988 134.1094 0.1.8 0.1.9 com.jetbrains.plugins.ini4idea 0.4 0.5 0.6 0.7 0.8 0.8.1 0.9 0.9.1 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 130.1176 org.jetbrains.plugins.vagrant 0.1 0.2 diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java index 34f6874b9da9..0fafc897cdad 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -94,6 +94,7 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase { return myElement; } + @NotNull @Override protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) { return new XmlElementStorageSaveSession(storageData) { diff --git a/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewManagerTest.java b/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewManagerTest.java index 3e38bd2bbb4a..a4fd1b4c881b 100644 --- a/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewManagerTest.java @@ -25,6 +25,11 @@ import com.intellij.usages.UsageTarget; import com.intellij.usages.UsageViewManager; public class UsageViewManagerTest extends PlatformTestCase { + + static { + initPlatformLangPrefix(); + } + public void testScopeCreatedForFindInDirectory() { VirtualFile dir = getProject().getBaseDir(); FindModel findModel = new FindModel(); @@ -36,4 +41,14 @@ public class UsageViewManagerTest extends PlatformTestCase { SearchScope scope = manager.getMaxSearchScopeToWarnOfFallingOutOf(new UsageTarget[]{target}); assertEquals(scope, GlobalSearchScopesCore.directoryScope(getProject(), dir, true)); } + + public void testScopeCreatedForFindInModuleContent() { + FindModel findModel = new FindModel(); + findModel.setModuleName(getModule().getName()); + findModel.setProjectScope(false); + UsageTarget target = new FindInProjectUtil.StringUsageTarget(getProject(), findModel); + UsageViewManagerImpl manager = (UsageViewManagerImpl)UsageViewManager.getInstance(getProject()); + SearchScope scope = manager.getMaxSearchScopeToWarnOfFallingOutOf(new UsageTarget[]{target}); + assertEquals(scope, getModule().getModuleContentScope()); + } } diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java index 152cc036347c..0bdcbbfa6f28 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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,8 +24,12 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Storage { @NonNls String id() default "default"; + + @Deprecated boolean isDefault() default true; + @NonNls String file() default ""; + StorageScheme scheme() default StorageScheme.DEFAULT; /** @@ -39,5 +43,6 @@ public @interface Storage { RoamingType roamingType() default RoamingType.PER_USER; Class storageClass() default StateStorage.class; + Class stateSplitter() default StateSplitterEx.class; } diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java b/platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java index 0baf9e6ebd05..d00e69aae56e 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StorageId.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.openapi.components; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) +@Deprecated public @interface StorageId { String value(); } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java index d882ca15be83..3d1bb2240528 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,20 +16,14 @@ package com.intellij.openapi.components.impl.stores; import com.intellij.openapi.components.StateStorageException; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StorageId; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.JDOMUtil; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.util.ReflectionUtil; -import com.intellij.util.xmlb.Accessor; -import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; import com.intellij.util.xmlb.XmlSerializationException; import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @SuppressWarnings({"deprecation"}) @@ -39,37 +33,6 @@ public class DefaultStateSerializer { private DefaultStateSerializer() { } - @Nullable - static Element serializeState(@NotNull Object state, @Nullable final Storage storage) throws WriteExternalException { - if (state instanceof Element) { - return (Element)state; - } - else if (state instanceof JDOMExternalizable) { - Element element = new Element("temp_element"); - ((JDOMExternalizable)state).writeExternal(element); - return element; - } - else { - return XmlSerializer.serializeIfNotDefault(state, new SkipDefaultValuesSerializationFilters() { - @Override - protected boolean accepts(@NotNull Accessor accessor, @NotNull Object bean, @Nullable Object beanValue) { - if (!super.accepts(accessor, bean, beanValue)) { - return false; - } - - if (storage != null) { - StorageId storageId = accessor.getAnnotation(StorageId.class); - if (storageId != null && !storageId.value().equals(storage.id())) { - return false; - } - return storage.isDefault(); - } - return true; - } - }); - } - } - @SuppressWarnings({"unchecked"}) @Nullable public static T deserializeState(@Nullable Element stateElement, Class stateClass, @Nullable T mergeInto) throws XmlSerializationException { diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java index 397e04ef9f59..cf4d40ab9eb7 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java +++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2015 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.debugger.sourcemap; import com.google.gson.stream.JsonToken; @@ -98,7 +113,7 @@ public final class SourceMapDecoder { else if (propertyName.equals("sourceRoot")) { sourceRoot = readSourcePath(reader); if (sourceRoot != null) { - sourceRoot = UriUtil.trimLeadingSlashes(sourceRoot); + sourceRoot = UriUtil.trimTrailingSlashes(sourceRoot); } } else if (propertyName.equals("sources")) { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java index 2d67883ad6e3..be7277b31572 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java @@ -23,7 +23,7 @@ public class MatchOptions implements JDOMExternalizable { private boolean recursiveSearch; private boolean caseSensitiveMatch; private boolean resultIsContextMatch = false; - private FileType myFileType = StructuralSearchUtil.getDefaultFileType(); + private FileType myFileType = null; private Language myDialect = null; private SearchScope scope; @@ -268,8 +268,7 @@ public class MatchOptions implements JDOMExternalizable { } public int hashCode() { - int result; - result = (looseMatching ? 1 : 0); + int result = (looseMatching ? 1 : 0); result = 29 * result + (recursiveSearch ? 1 : 0); result = 29 * result + (caseSensitiveMatch ? 1 : 0); // @TODO support scope @@ -285,6 +284,9 @@ public class MatchOptions implements JDOMExternalizable { } public FileType getFileType() { + if (myFileType == null) { + myFileType = StructuralSearchUtil.getDefaultFileType(); + } return myFileType; } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/Matcher.java b/platform/structuralsearch/source/com/intellij/structuralsearch/Matcher.java index 594686e14d49..747c17625095 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/Matcher.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/Matcher.java @@ -4,7 +4,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.structuralsearch.impl.matcher.MatcherImpl; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -75,10 +75,10 @@ public class Matcher extends MatcherImpl { * @throws MalformedPatternException * @throws UnsupportedPatternException */ - @Nullable - public MatchResult isMatchedByDownUp(PsiElement element,MatchOptions options) throws + @NotNull + public List matchByDownUp(PsiElement element, MatchOptions options) throws MalformedPatternException, UnsupportedPatternException { - return super.isMatchedByDownUp(element, options); + return super.matchByDownUp(element, options); } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchUtil.java b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchUtil.java index be33189ee486..be4759d676a7 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchUtil.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchUtil.java @@ -32,6 +32,7 @@ public class StructuralSearchUtil { @Contract("null -> false") public static boolean isIdentifier(PsiElement element) { + if (element == null) return false; final StructuralSearchProfile profile = getProfileByPsiElement(element); return profile != null && profile.isIdentifier(element); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java index 678b99cf2146..02efb3e95750 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/MatcherImpl.java @@ -41,6 +41,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -627,15 +628,11 @@ public class MatcherImpl { } } - @Nullable - protected MatchResult isMatchedByDownUp(PsiElement element, final MatchOptions options) { + @NotNull + protected List matchByDownUp(PsiElement element, final MatchOptions options) { final CollectingMatchResultSink sink = new CollectingMatchResultSink(); - CompiledPattern compiledPattern = prepareMatching(sink, options); - - if (compiledPattern== null) { - assert false; - return null; - } + final CompiledPattern compiledPattern = prepareMatching(sink, options); + matchContext.setShouldRecursivelyMatch(false); PsiElement targetNode = compiledPattern.getTargetNode(); PsiElement elementToStartMatching = null; @@ -647,21 +644,26 @@ public class MatcherImpl { assert !compiledPattern.getNodes().hasNext(); compiledPattern.getNodes().rewind(); + element = element.getParent(); + if (element == null) { + return Collections.emptyList(); + } while (element.getClass() != targetNode.getClass()) { element = element.getParent(); - if (element == null) return null; + if (element == null) return Collections.emptyList(); } elementToStartMatching = element; } } else { - targetNode = StructuralSearchUtil.getProfileByPsiElement(element).extendMatchedByDownUp(targetNode); + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(element); + if (profile == null) return Collections.emptyList(); + targetNode = profile.extendMatchedByDownUp(targetNode); MatchingHandler handler = null; while (element.getClass() == targetNode.getClass() || - compiledPattern.isTypedVar(targetNode) && compiledPattern.getHandler(targetNode).canMatch(targetNode, element) - ) { + compiledPattern.isTypedVar(targetNode) && compiledPattern.getHandler(targetNode).canMatch(targetNode, element)) { handler = compiledPattern.getHandler(targetNode); handler.setPinnedElement(element); elementToStartMatching = element; @@ -670,21 +672,19 @@ public class MatcherImpl { targetNode = targetNode.getParent(); if (options.isLooseMatching()) { - element = StructuralSearchUtil.getProfileByPsiElement(element).updateCurrentNode(element); - targetNode = StructuralSearchUtil.getProfileByPsiElement(element).updateCurrentNode(targetNode); + element = profile.updateCurrentNode(element); + targetNode = profile.updateCurrentNode(targetNode); } } - if (!(handler instanceof TopLevelMatchingHandler)) return null; + if (!(handler instanceof TopLevelMatchingHandler)) return Collections.emptyList(); } assert targetNode != null : "Could not match down up when no target node"; match(elementToStartMatching); matchContext.getSink().matchingFinished(); - final int matchCount = sink.getMatches().size(); - assert matchCount <= 1; - return matchCount > 0 ? sink.getMatches().get(0) : null; + return sink.getMatches(); } private class MatchOneVirtualFile extends MatchOneFile { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java index 8d102b0b2440..869451a6b202 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java @@ -77,14 +77,15 @@ public class XmlMatchingVisitor extends XmlElementVisitor { PsiElement[] matchedNodes = another.getValue().getChildren(); if (contentChildren.length != 1) { - patternNodes = expandXmlTexts(patternNodes); - matchedNodes = expandXmlTexts(matchedNodes); + patternNodes = filterOutWhitespace(patternNodes); + matchedNodes = filterOutWhitespace(matchedNodes); } - myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially( + final boolean result = myMatchingVisitor.matchSequentially( new ArrayBackedNodeIterator(patternNodes), new ArrayBackedNodeIterator(matchedNodes) - )); + ); + myMatchingVisitor.setResult(result); } } @@ -97,34 +98,27 @@ public class XmlMatchingVisitor extends XmlElementVisitor { } } - private static PsiElement[] expandXmlTexts(PsiElement[] children) { + private static PsiElement[] filterOutWhitespace(PsiElement[] children) { final List result = new ArrayList(children.length); - for(PsiElement c:children) { - if (c instanceof XmlText) { - for(PsiElement p:c.getChildren()) { - if (!(p instanceof PsiWhiteSpace)) result.add(p); + for(PsiElement child : children) { + if (child instanceof XmlText) { + final PsiElement[] grandChildren = child.getChildren(); + if (grandChildren.length == 1 && grandChildren[0] instanceof PsiWhiteSpace) { + continue; } - } else if (!(c instanceof PsiWhiteSpace)) { - result.add(c); } + result.add(child); } return PsiUtilCore.toPsiElementArray(result); } @Override public void visitXmlText(XmlText text) { - myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(text.getFirstChild(), myMatchingVisitor.getElement().getFirstChild())); - } - - @Override public void visitXmlToken(XmlToken token) { - if (token.getTokenType() == XmlTokenType.XML_DATA_CHARACTERS) { - final String text = token.getText(); - final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(text); - - if (isTypedVar) { - myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(token, myMatchingVisitor.getElement())); - } else { - myMatchingVisitor.setResult(matches(text, myMatchingVisitor.getElement().getText())); - } + final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(text); + final PsiElement element = myMatchingVisitor.getElement(); + if (isTypedVar) { + myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(text, element)); + } else { + myMatchingVisitor.setResult(matches(text.getText(), element.getText())); } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java index 07808d33c003..6a20da7294c9 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java @@ -466,7 +466,8 @@ public class PatternCompiler { ); if (!StringUtil.isEmptyOrSpaces(constraint.getWithinConstraint())) { - MatchPredicate predicate = new WithinPredicate(Configuration.CONTEXT_VAR_NAME, constraint.getWithinConstraint(), project); + MatchPredicate predicate = + new WithinPredicate(Configuration.CONTEXT_VAR_NAME, constraint.getWithinConstraint(), options.getFileType(), project); if (constraint.isInvertWithinConstraint()) { predicate = new NotPredicate(predicate); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformer.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformer.java index 0d684503a14d..0ac16b386a19 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformer.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformer.java @@ -42,6 +42,7 @@ class StringToConstraintsTransformer { StringBuilder miscBuffer = null; int anonymousTypedVarsCount = 0; + boolean targetFound = false; for(int index=0;index < pattern.length();++index) { char ch = pattern.charAt(index); @@ -187,6 +188,10 @@ class StringToConstraintsTransformer { constraint.setMaxCount(maxOccurs); constraint.setGreedy(greedy); constraint.setPartOfSearchResults(!anonymous); + if (targetFound && !anonymous) { + throw new MalformedPatternException("Pattern may have only one target"); + } + targetFound = !anonymous; } if (index < length && pattern.charAt(index) == ':') { @@ -248,7 +253,19 @@ class StringToConstraintsTransformer { // eat complete condition miscBuffer.setLength(0); - for(++index; index < length && ((ch = pattern.charAt(index))!=']' || pattern.charAt(index-1)=='\\'); ++index) { + for(++index; index < length && ((ch = pattern.charAt(index)) != ']' || pattern.charAt(index-1) == '\\'); ++index) { + if (ch == '"') { + miscBuffer.append(ch); + for (++index; index < length && (ch = pattern.charAt(index)) != '"'; ++index) { + if (ch == '\\') { + ++index; + if (index >= length) break; + ch = pattern.charAt(index); + } + miscBuffer.append(ch); + } + if (ch != '"') throw new MalformedPatternException(SSRBundle.message("error.expected.end.quote")); + } miscBuffer.append(ch); } if (ch != ']') throw new MalformedPatternException(SSRBundle.message("error.expected.condition.or.bracket")); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java index 99917ad23240..529b9deab344 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/XmlCompilingVisitor.java @@ -5,10 +5,10 @@ import com.intellij.psi.XmlRecursiveElementVisitor; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlText; import com.intellij.psi.xml.XmlToken; +import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.structuralsearch.impl.matcher.filters.TagValueFilter; import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler; import com.intellij.structuralsearch.impl.matcher.handlers.TopLevelMatchingHandler; -import com.intellij.structuralsearch.impl.matcher.handlers.XmlTextHandler; import com.intellij.structuralsearch.impl.matcher.strategies.XmlMatchingStrategy; /** @@ -26,17 +26,15 @@ public class XmlCompilingVisitor extends XmlRecursiveElementVisitor { super.visitElement(element); } - @Override public void visitXmlToken(XmlToken token) { - super.visitXmlToken(token); + @Override + public void visitXmlToken(XmlToken token) {} - if (token.getParent() instanceof XmlText && myCompilingVisitor.getContext().getPattern().isRealTypedVar(token)) { - final MatchingHandler handler = myCompilingVisitor.getContext().getPattern().getHandler(token); - handler.setFilter(TagValueFilter.getInstance()); + @Override + public void visitXmlText(XmlText text) { + super.visitXmlText(text); - final XmlTextHandler parentHandler = new XmlTextHandler(); - myCompilingVisitor.getContext().getPattern().setHandler(token.getParent(), parentHandler); - parentHandler.setFilter(TagValueFilter.getInstance()); - } + final MatchingHandler handler = myCompilingVisitor.getContext().getPattern().getHandler(text); + handler.setFilter(TagValueFilter.getInstance()); } @Override public void visitXmlTag(XmlTag xmlTag) { @@ -45,9 +43,9 @@ public class XmlCompilingVisitor extends XmlRecursiveElementVisitor { myCompilingVisitor.setCodeBlockLevel(myCompilingVisitor.getCodeBlockLevel() - 1); if (myCompilingVisitor.getCodeBlockLevel() == 1) { - myCompilingVisitor.getContext().getPattern().setStrategy(XmlMatchingStrategy.getInstance()); - myCompilingVisitor.getContext().getPattern() - .setHandler(xmlTag, new TopLevelMatchingHandler(myCompilingVisitor.getContext().getPattern().getHandler(xmlTag))); + final CompiledPattern pattern = myCompilingVisitor.getContext().getPattern(); + pattern.setStrategy(XmlMatchingStrategy.getInstance()); + pattern.setHandler(xmlTag, new TopLevelMatchingHandler(pattern.getHandler(xmlTag))); } } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/filters/XmlLexicalNodesFilter.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/filters/XmlLexicalNodesFilter.java index 89c295ce1d80..e59447312ed7 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/filters/XmlLexicalNodesFilter.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/filters/XmlLexicalNodesFilter.java @@ -1,7 +1,8 @@ package com.intellij.structuralsearch.impl.matcher.filters; +import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.XmlElementVisitor; -import com.intellij.psi.xml.XmlText; /** * @author Eugene.Kudelevsky @@ -13,7 +14,13 @@ public class XmlLexicalNodesFilter extends XmlElementVisitor { this.myLexicalNodesFilter = lexicalNodesFilter; } - @Override public void visitXmlText(XmlText text) { + @Override + public void visitWhiteSpace(PsiWhiteSpace space) { + myLexicalNodesFilter.setResult(true); + } + + @Override + public void visitErrorElement(PsiErrorElement element) { myLexicalNodesFilter.setResult(true); } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java index 3904eb397bce..fc7984680db9 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/predicates/WithinPredicate.java @@ -1,14 +1,18 @@ package com.intellij.structuralsearch.impl.matcher.predicates; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.structuralsearch.MatchOptions; import com.intellij.structuralsearch.MatchResult; import com.intellij.structuralsearch.Matcher; import com.intellij.structuralsearch.impl.matcher.MatchContext; import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler; +import java.util.List; + /** * @author Maxim.Mossienko */ @@ -16,11 +20,12 @@ public class WithinPredicate extends AbstractStringBasedPredicate { private final MatchOptions myMatchOptions; private Matcher matcher; - public WithinPredicate(String name, String within, Project project) { + public WithinPredicate(String name, String within, FileType fileType, Project project) { super(name, within); myMatchOptions = new MatchOptions(); myMatchOptions.setLooseMatching(true); + myMatchOptions.setFileType(fileType); final String unquoted = StringUtil.stripQuotesAroundValue(within); if (!unquoted.equals(within)) { myMatchOptions.setSearchPattern(unquoted); @@ -32,7 +37,12 @@ public class WithinPredicate extends AbstractStringBasedPredicate { } public boolean match(PsiElement node, PsiElement match, int start, int end, MatchContext context) { - final MatchResult result = matcher.isMatchedByDownUp(match, myMatchOptions); - return result != null; + final List results = matcher.matchByDownUp(match, myMatchOptions); + for (MatchResult result : results) { + if (PsiTreeUtil.isAncestor(result.getMatch(), match, false)) { + return true; + } + } + return false; } } \ No newline at end of file diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java index 9a137efee3a1..2e408cab6f29 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java @@ -26,10 +26,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; -import com.intellij.structuralsearch.MatchVariableConstraint; -import com.intellij.structuralsearch.NamedScriptableDefinition; -import com.intellij.structuralsearch.ReplacementVariableDefinition; -import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.*; import com.intellij.structuralsearch.impl.matcher.CompiledPattern; import com.intellij.structuralsearch.impl.matcher.predicates.ScriptSupport; import com.intellij.structuralsearch.plugin.replace.ReplaceOptions; @@ -111,7 +108,6 @@ class EditVarConstraintsDialog extends DialogWrapper { regexprForExprType.getDocument().addDocumentListener(new MyDocumentListener(exprTypeWithinHierarchy, notExprType)); formalArgType.getDocument().addDocumentListener(new MyDocumentListener(formalArgTypeWithinHierarchy, invertFormalArgType)); - partOfSearchResults.setEnabled(!replaceContext); // todo: this doesn't do anything containedInConstraints.setVisible(false); withinCombo.getComboBox().setEditable(true); @@ -297,7 +293,16 @@ class EditVarConstraintsDialog extends DialogWrapper { varInfo.setWithinHierarchy(applyWithinTypeHierarchy.isSelected()); varInfo.setInvertRegExp(notRegexp.isSelected()); - varInfo.setPartOfSearchResults(partOfSearchResults.isEnabled() && partOfSearchResults.isSelected()); + final boolean target = partOfSearchResults.isSelected(); + if (target) { + final MatchOptions matchOptions = configuration.getMatchOptions(); + for (String name : matchOptions.getVariableConstraintNames()) { + if (!name.equals(varName)) { + matchOptions.getVariableConstraint(name).setPartOfSearchResults(false); + } + } + } + varInfo.setPartOfSearchResults(target); varInfo.setInvertExprType(notExprType.isSelected()); varInfo.setNameOfExprType(regexprForExprType.getDocument().getText()); @@ -357,7 +362,8 @@ class EditVarConstraintsDialog extends DialogWrapper { setSearchConstraintsVisible(true); } - MatchVariableConstraint varInfo = configuration.getMatchOptions().getVariableConstraint(varName); + final MatchOptions matchOptions = configuration.getMatchOptions(); + final MatchVariableConstraint varInfo = matchOptions.getVariableConstraint(varName); if (varInfo == null) { notRead.setSelected(false); @@ -371,7 +377,7 @@ class EditVarConstraintsDialog extends DialogWrapper { maxoccurs.setText("1"); maxoccursUnlimited.setSelected(false); applyWithinTypeHierarchy.setSelected(false); - partOfSearchResults.setSelected(false); + partOfSearchResults.setSelected(isTarget(varName, matchOptions)); regexprForExprType.getDocument().setText(""); notExprType.setSelected(false); @@ -406,7 +412,7 @@ class EditVarConstraintsDialog extends DialogWrapper { maxoccurs.setText(Integer.toString(varInfo.getMaxCount())); } - partOfSearchResults.setSelected( partOfSearchResults.isEnabled() && varInfo.isPartOfSearchResults() ); + partOfSearchResults.setSelected(isTarget(varName, matchOptions)); exprTypeWithinHierarchy.setSelected(varInfo.isExprTypeWithinHierarchy()); regexprForExprType.getDocument().setText(varInfo.getNameOfExprType()); @@ -427,10 +433,29 @@ class EditVarConstraintsDialog extends DialogWrapper { containedInConstraints.setVisible(contextVar); textConstraintsPanel.setVisible(!contextVar); expressionConstraints.setVisible(!contextVar); - partOfSearchResults.setVisible(!contextVar); + partOfSearchResults.setEnabled(!contextVar); occurencePanel.setVisible(!contextVar); } + private static boolean isTarget(String varName, MatchOptions matchOptions) { + if (Configuration.CONTEXT_VAR_NAME.equals(varName)) { + // Complete Match is default target + for (String name : matchOptions.getVariableConstraintNames()) { + if (!name.equals(Configuration.CONTEXT_VAR_NAME)) { + if (matchOptions.getVariableConstraint(name).isPartOfSearchResults()) { + return false; + } + } + } + return true; + } + final MatchVariableConstraint constraint = matchOptions.getVariableConstraint(varName); + if (constraint == null) { + return false; + } + return constraint.isPartOfSearchResults(); + } + private void setSearchConstraintsVisible(boolean b) { textConstraintsPanel.setVisible(b); occurencePanel.setVisible(b); diff --git a/platform/structuralsearch/source/messages/SSRBundle.properties b/platform/structuralsearch/source/messages/SSRBundle.properties index 372e456c9f8a..a59ca1d7610d 100644 --- a/platform/structuralsearch/source/messages/SSRBundle.properties +++ b/platform/structuralsearch/source/messages/SSRBundle.properties @@ -210,10 +210,11 @@ error.two.different.type.constraints=Two different type constraints error.incorrect.regexp.constraint=Incorrect reg exp constraint:{0} for {1} error.expected.character=Character expected after single quote error.overflow=Value overflow -error.expected.brace1="Digit, '}' or ',' expected" -error.expected.brace2="Digit or '}' expected" +error.expected.brace1=Digit, '}' or ',' expected +error.expected.brace2=Digit or '}' expected error.expected.condition=Condition expected after ''{0}'' error.expected.condition.or.bracket=Condition or ']' expected +error.expected.end.quote='"' expected invalid.modifier.type=Invalid modifier type {0} SSRInspection.replace.with=Replace with ''{0}'' diff --git a/platform/structuralsearch/testData/java/ReformatAndShortenClassRefPerformance_pattern.java b/platform/structuralsearch/testData/java/ReformatAndShortenClassRefPerformance_pattern.java index 1200d6f9624f..4dd5df59b3c2 100644 --- a/platform/structuralsearch/testData/java/ReformatAndShortenClassRefPerformance_pattern.java +++ b/platform/structuralsearch/testData/java/ReformatAndShortenClassRefPerformance_pattern.java @@ -1 +1 @@ -assertTrue(StrictMath.abs('v1 - 'v2) < 't); \ No newline at end of file +assertTrue(StrictMath.abs('_v1 - '_v2) < '_t); \ No newline at end of file diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSBasedInspectionTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSBasedInspectionTest.java index ff2083ebfbfa..5ea22da14d3b 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSBasedInspectionTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSBasedInspectionTest.java @@ -1,6 +1,7 @@ package com.intellij.structuralsearch; import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.structuralsearch.inspection.highlightTemplate.SSBasedInspection; import com.intellij.structuralsearch.plugin.ui.Configuration; import com.intellij.structuralsearch.plugin.ui.SearchConfiguration; @@ -20,11 +21,13 @@ public class SSBasedInspectionTest extends InspectionTestCase { List configurations = new ArrayList(); SearchConfiguration configuration = new SearchConfiguration(); MatchOptions options = new MatchOptions(); + options.setFileType(StdFileTypes.JAVA); options.setSearchPattern("int i;"); configuration.setMatchOptions(options); configurations.add(configuration); configuration = new SearchConfiguration(); options = new MatchOptions(); + options.setFileType(StdFileTypes.JAVA); options.setSearchPattern("f();"); configuration.setMatchOptions(options); configurations.add(configuration); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSRCodeInsightTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSRCodeInsightTest.java index 95cd33b0845a..2f9bf669def3 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSRCodeInsightTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/SSRCodeInsightTest.java @@ -1,5 +1,6 @@ package com.intellij.structuralsearch; +import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.structuralsearch.inspection.highlightTemplate.SSBasedInspection; import com.intellij.structuralsearch.plugin.ui.Configuration; import com.intellij.structuralsearch.plugin.ui.SearchConfiguration; @@ -60,6 +61,7 @@ public class SSRCodeInsightTest extends UsefulTestCase { //search pattern final MatchOptions options = new MatchOptions(); + options.setFileType(StdFileTypes.JAVA); options.setSearchPattern(searchPattern); configuration.setMatchOptions(options); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java index 250a57e3811c..6a656a736654 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java @@ -1,5 +1,6 @@ package com.intellij.structuralsearch; +import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.psi.CommonClassNames; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.ThrowableRunnable; @@ -12,10 +13,17 @@ import java.io.IOException; */ @SuppressWarnings({"ALL"}) public class StructuralReplaceTest extends StructuralReplaceTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + options.getMatchOptions().setFileType(StdFileTypes.JAVA); + } + public void testReplaceInLiterals() { String s1 = "String ID_SPEED = \"Speed\";"; - String s2 = "String 'name = \"'string\";"; - String s2_2 = "String 'name = \"'string:[regex( .* )]\";"; + String s2 = "String 'name = \"'_string\";"; + String s2_2 = "String 'name = \"'_string:[regex( .* )]\";"; String s3 = "VSegAttribute $name$ = new VSegAttribute(\"$string$\");"; String expectedResult = "VSegAttribute ID_SPEED = new VSegAttribute(\"Speed\");"; @@ -50,7 +58,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String s7 = "IconLoader.getIcon(\"/ant/property.png\");\n" + "IconLoader.getIcon(\"/ant/another/property.png\");\n"; - String s8 = "IconLoader.getIcon(\"/'module/'name:[regex( \\w+ )].png\");"; + String s8 = "IconLoader.getIcon(\"/'_module/'_name:[regex( \\w+ )].png\");"; String s9 = "Icons.$module$.$name$;"; String expectedResult3 = "Icons.ant.property;\n" + "IconLoader.getIcon(\"/ant/another/property.png\");\n"; @@ -93,7 +101,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " JOptionPane.showMessageDialog(null, \"MESSAGE\");\n" + " }\n" + "}"; - String s2 = "JOptionPane.'showDialog(null, 'msg);"; + String s2 = "JOptionPane.'showDialog(null, '_msg);"; String s3 = "//FIXME provide a parent frame\n" + "JOptionPane.$showDialog$(null, $msg$);"; @@ -117,7 +125,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { ); String s4 = "myButton.setText(\"Ok\");"; - String s5 = "'Instance.'MethodCall:[regex( setText )]('Parameter*:[regex( \"Ok\" )]);"; + String s5 = "'_Instance.'_MethodCall:[regex( setText )]('_Parameter*:[regex( \"Ok\" )]);"; String s6 = "$Instance$.$MethodCall$(\"OK\");"; String expectedResult2 = "myButton.setText(\"OK\");"; @@ -147,9 +155,9 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " matches = testMatcher.findMatches(s7,s8, options);\n" + " if (matches.size()!=2) return false;"; - String str2=" lastTest = 'Descr;\n" + - " matches = testMatcher.findMatches('In,'Pattern, options);\n" + - " if (matches.size()!='Number) return false;"; + String str2=" lastTest = '_Descr;\n" + + " matches = testMatcher.findMatches('_In,'_Pattern, options);\n" + + " if (matches.size()!='_Number) return false;"; String str3 = "assertEquals($Descr$,testMatcher.findMatches($In$,$Pattern$, options).size(),$Number$);"; String expectedResult1 = "// searching for several constructions\n" + " lastTest = \"several constructions match\";\n" + @@ -183,7 +191,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { assertEquals("Empty replacement",expectedResult2,actualResult); - String str5 = "testMatcher.findMatches('In,'Pattern, options).size()"; + String str5 = "testMatcher.findMatches('_In,'_Pattern, options).size()"; String str6 = "findMatchesCount($In$,$Pattern$)"; String expectedResult3="// searching for several constructions\n" + " lastTest = \"several constructions match\";\n" + @@ -212,9 +220,9 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " if (asyncMode) {\n" + " myTreeModel.nodesWereInserted(parentNode,new int[] {i} );\n" + " }"; - String str11 = " 'parentNode.insert('newNode, 'i);\n" + + String str11 = " '_parentNode.insert('_newNode, '_i);\n" + " if (asyncMode) {\n" + - " myTreeModel.nodesWereInserted('parentNode,new int[] {'i} );\n" + + " myTreeModel.nodesWereInserted('_parentNode,new int[] {'_i} );\n" + " }"; String str12 = "addChild($parentNode$,$newNode$, $i$);"; String expectedResult5 = " addChild(parentNode,compositeNode, i);"; @@ -223,7 +231,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { assertEquals( "Array initializer replacement", expectedResult5,actualResult); String str13 = " aaa(5,6,3,4,1,2);"; - String str14 = "aaa('t{2,2},3,4,'q{2,2});"; + String str14 = "aaa('_t{2,2},3,4,'_q{2,2});"; String str15 = "aaa($q$,3,4,$t$);"; String expectedResult6 = " aaa(1,2,3,4,5,6);"; @@ -231,7 +239,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { assertEquals("Parameter multiple match",expectedResult6,actualResult); String str16 = " int c = a();"; - String str17 = "'t:a ('q*,'p*)"; + String str17 = "'_t:a ('_q*,'_p*)"; String str18 = "$t$($q$,1,$p$)"; String expectedResult7 = " int c = a(1);"; @@ -247,7 +255,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { assertEquals("One substition replacement",expectedResult8,actualResult); String str22 = " instance.setAAA(anotherInstance.getBBB());"; - String str23 = " 'i.'m:set(.+) ('a.'m2:get(.+) ());"; + String str23 = " '_i.'_m:set(.+) ('_a.'_m2:get(.+) ());"; String str24 = " $a$.set$m2_1$( $i$.get$m_1$() );"; String expectedResult9 = " anotherInstance.setBBB( instance.getAAA() );"; @@ -283,7 +291,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String str28 = "UTElementNode elementNode = new UTElementNode(myProject, processedElement, psiFile,\n" + " processedElement.getTextOffset(), true,\n" + " !myUsageViewDescriptor.toMarkInvalidOrReadonlyUsages(), null);"; - String str29 = "new UTElementNode('param, 'directory, 'null, '0, 'true, !'descr.toMarkInvalidOrReadonlyUsages(),\n" + + String str29 = "new UTElementNode('_param, '_directory, '_null, '_0, '_true, !'_descr.toMarkInvalidOrReadonlyUsages(),\n" + " 'referencesWord)"; String str30 = "new UTElementNode($param$, $directory$, $null$, $0$, $true$, true,\n" + " $referencesWord$)"; @@ -306,7 +314,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { ); String s34 = "ParamChecker.isTrue(1==1, \"!!!\");"; - String s35 = "ParamChecker.isTrue('expr, 'msg)"; + String s35 = "ParamChecker.isTrue('_expr, '_msg)"; String s36 = "assert $expr$ : $msg$"; String expectedResult13 = "assert 1==1 : \"!!!\";"; @@ -338,7 +346,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { ); String s40 = "ParamChecker.instanceOf(queryKey, GroupBySqlTypePolicy.GroupKey.class);"; - String s41 = "ParamChecker.instanceOf('obj, 'class.class);"; + String s41 = "ParamChecker.instanceOf('_obj, '_class.class);"; String s42 = "assert $obj$ instanceof $class$ : \"$obj$ is an instance of \" + $obj$.getClass() + \"; expected \" + $class$.class;"; String expectedResult15 = "assert queryKey instanceof GroupBySqlTypePolicy.GroupKey : \"queryKey is an instance of \" + queryKey.getClass() + \"; expected \" + GroupBySqlTypePolicy.GroupKey.class;"; @@ -353,7 +361,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " static final String TAG_BEAN_VALUE = \"\";\n" + "}\n" + "XmlTag beanTag = rootTag.findSubTag(Wpd.TAG_BEAN_VALUE);"; - String s44 = "'Instance?.findSubTag( 'Parameter:[exprtype( *String ) ])"; + String s44 = "'_Instance?.findSubTag( '_Parameter:[exprtype( *String ) ])"; String s45 = "jetbrains.fabrique.util.XmlApiUtil.findSubTag($Instance$, $Parameter$)"; String expectedResult16 = "class Wpd {\n" + " static final String TAG_BEAN_VALUE = \"\";\n" + @@ -390,7 +398,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String s49 = "class A {}\n" + "class B extends A {}\n" + "A a = new B();"; - String s50 = "A 'b = new 'B:*A ();"; + String s50 = "A '_b = new '_B:*A ();"; String s51 = "A $b$ = new $B$(\"$b$\");"; String expectedResult18 = "class A {}\n" + "class B extends A {}\n" + @@ -422,8 +430,8 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "} catch(Exception ex) {\n" + " aaa5();\n" + "}\n"; - String s53 = "try { 'a; } finally {\n" + - " 'b;" + + String s53 = "try { '_a; } finally {\n" + + " '_b;" + "}"; String s54 = "$a$;"; String expectedResult19 = "aaa();\n" + @@ -493,7 +501,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String s64 = "int x = 42;\n" + "int y = 42; // Stuff"; - String s65 = "'Type 'Variable = 'Value; // 'Comment"; + String s65 = "'_Type '_Variable = '_Value; // '_Comment"; String s66 = "/**\n" + " *$Comment$\n" + " */\n" + @@ -513,7 +521,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { ); String s61 = "try { 1=1; } catch(Exception e) { 1=1; } catch(Throwable t) { 2=2; }"; - String s62 = "try { 'a; } catch(Exception e) { 'b; }"; + String s62 = "try { '_a; } catch(Exception e) { '_b; }"; String s63 = "try { $a$; } catch(Exception1 e) { $b$; } catch(Exception2 e) { $b$; }"; String expectedResult22 = "try { 1=1; } catch(Exception1 e) { 1=1; } catch(Exception2 e) { 1=1; } catch (Throwable t) { 2=2; }"; @@ -689,10 +697,10 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "}"; String s8 = "new Runnable() {\n" + " public void run() {\n" + - " 'l ();\n" + + " '_l ();\n" + " }\n" + - " private void 'l () {\n" + - " 'st{2,2};\n" + + " private void '_l () {\n" + + " '_st{2,2};\n" + " }\n" + "};"; String s9 = "new My() {\n" + @@ -972,7 +980,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { options.setToReformatAccordingToStyle(true); String s1 = "class A { public void b() {} }"; - String s2 = "class 'a { 'Other* }"; + String s2 = "class 'a { '_Other* }"; String s3 = "class $a$New { Logger LOG; $Other$ }"; String expectedResult = " class ANew {\n" + " Logger LOG;\n\n" + @@ -988,7 +996,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { ); String s4 = "class A { class C {} public void b() {} int f; }"; - String s5 = "class 'a { 'Other* }"; + String s5 = "class 'a { '_Other* }"; String s6 = "class $a$ { Logger LOG; $Other$ }"; String expectedResult2 = " class A {\n" + " Logger LOG;\n\n" + @@ -1007,7 +1015,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { ); String s7 = "class A extends B { int c; void b() {} { a = 1; } }"; - String s8 = "class 'A extends B { 'Other* }"; + String s8 = "class 'A extends B { '_Other* }"; String s9 = "class $A$ extends B2 { $Other$ }"; String expectedResult3 = " class A extends B2 {\n" + " int c;\n\n" + @@ -1028,7 +1036,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " public void b() {}\n" + " int f;\n" + "}"; - String s11 = "class 'a { 'Other* }"; + String s11 = "class 'a { '_Other* }"; String s12 = "public class $a$ {\n" + " $Other$\n" + "}"; @@ -1060,9 +1068,9 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "}\n" + "}"; String s14 = "class 'Class extends Thread {\n" + - " 'Class('ParameterType* 'ParameterName*) {\n" + - "\t super (CustomThreadGroup.getThreadGroup(), 'superarg* );\n" + - " 'Statement*;\n" + + " 'Class('_ParameterType* '_ParameterName*) {\n" + + "\t super (CustomThreadGroup.getThreadGroup(), '_superarg* );\n" + + " '_Statement*;\n" + " }\n" + "}"; String s15 = "class $Class$ extends CustomThread {\n" + @@ -1092,8 +1100,8 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String s16 = "public class A {}\n" + "final class B {}"; - String s17 = "class 'A { 'Other* }"; - String s17_2 = "class 'A { private Log log = LogFactory.createLog(); 'Other* }"; + String s17 = "class 'A { '_Other* }"; + String s17_2 = "class 'A { private Log log = LogFactory.createLog(); '_Other* }"; String s18 = "class $A$ { private Log log = LogFactory.createLog(); $Other$ }"; String s18_2 = "class $A$ { $Other$ }"; @@ -1108,7 +1116,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { assertEquals("Removing field",expectedResult7,actualResult); String s19 = "public class A extends Object implements Cloneable {}\n"; - String s20 = "class 'A { 'Other* }"; + String s20 = "class 'A { '_Other* }"; String s21 = "class $A$ { private Log log = LogFactory.createLog(); $Other$ }"; actualResult = replacer.testReplace(s19,s20,s21,options); @@ -1116,7 +1124,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { assertEquals("Extends / implements list for class",expectedResult8,actualResult); String s22 = "public class A { int Afield; }\n"; - String s23 = "class 'A { 'Other* }"; + String s23 = "class 'A { '_Other* }"; String s24 = "class $A$ { private Log log = LogFactory.createLog(); $Other$ }"; actualResult = replacer.testReplace(s22,s23,s24,options); @@ -1144,8 +1152,8 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String s28 = "aaa"; String s29 = "class 'Class {\n" + - " 'Class('ParameterType 'ParameterName) {\n" + - " 'Class('ParameterName);\n" + + " 'Class('_ParameterType '_ParameterName) {\n" + + " 'Class('_ParameterName);\n" + " }\n" + "}"; String s30 = "class $Class$ {\n" + @@ -1169,7 +1177,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " int c; // comment2\n" + "}"; - String s32 = "'Type 'Variable = 'Value?; //'Comment"; + String s32 = "'_Type 'Variable = '_Value?; //'_Comment"; String s33 = "/**$Comment$*/\n" + "$Type$ $Variable$ = $Value$;"; @@ -1204,7 +1212,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "}"; String s35 = "public interface 'MessageInterface {\n" + - " public static final String 'X = 'VALUE;\n" + + " public static final String '_X = '_VALUE;\n" + " 'blah*" + "}"; String s36 = "public interface $MessageInterface$ {\n" + @@ -1258,7 +1266,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " private int c = 2;\n" + "}"; - String s2 = "@Modifier(\"PackageLocal\") 'Type 'Instance = 'Init?;"; + String s2 = "@Modifier(\"PackageLocal\") '_Type '_Instance = '_Init?;"; String s3 = "public $Type$ $Instance$ = $Init$;"; String expectedResult = "class A {\n" + @@ -1340,7 +1348,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " /**\n" + " * zzz\n" + " */\n" + - " void f('t 'p){'s+;}\n" + + " void f('_t '_p){'_s+;}\n" + "}"; String s3 = "class $c$ {\n" + " /**\n" + @@ -1400,13 +1408,13 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "}"; String s2 = "/**\n" + "* Created by IntelliJ IDEA.\n" + - "* User: 'USER\n" + - "* Date: 'DATE\n" + - "* Time: 'TIME\n" + + "* User: '_USER\n" + + "* Date: '_DATE\n" + + "* Time: '_TIME\n" + "* To change this template use File | Settings | File Templates.\n" + "*/\n" + "class 'c {\n" + - " 'other*\n" + + " '_other*\n" + "}"; String s3 = "/**\n" + "* by: $USER$\n" + @@ -1461,11 +1469,11 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { public void testClassReplacement9() throws IOException { String s1 = loadFile("before1.java"); - String s2 = "class 'A extends 'TestCaseCass:[regex( .*TestCase ) ] {\n" + - " 'OtherStatement*;\n" + - " public void 'testMethod*:[regex( test.* )] () {\n" + + String s2 = "class 'A extends '_TestCaseCass:[regex( .*TestCase ) ] {\n" + + " '_OtherStatement*;\n" + + " public void '_testMethod*:[regex( test.* )] () {\n" + " }\n" + - " 'OtherStatement2*;\n" + + " '_OtherStatement2*;\n" + "}"; String s3 = "class $A$ extends $TestCaseCass$ {\n" + " $OtherStatement$;\n" + @@ -1552,7 +1560,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String actualResult; String s43 = "public @Deprecated class Foo implements Comparable {\n int x;\n void m(){}\n }"; - String s44 = "class 'Class implements 'Interface { 'Content* }"; + String s44 = "class 'Class implements '_Interface { '_Content* }"; String s45 = "@MyAnnotation\n" + "class $Class$ implements $Interface$ {$Content$}"; String expectedResult16 = "@MyAnnotation public @Deprecated\n" + @@ -1571,7 +1579,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String actualResult; String s43 = "public @Deprecated class Foo implements Comparable {\n int x;\n void m(){}\n }"; - String s44 = "class 'Class implements 'Interface {}"; + String s44 = "class 'Class implements '_Interface {}"; String s45 = "@MyAnnotation\n" + "class $Class$ implements $Interface$ {}"; String expectedResult16 = "@MyAnnotation public @Deprecated\n" + @@ -1786,7 +1794,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " catch (final Exception e)\n" + " { continue; }\n" + "}"; - String toFind = "try { 'TryStatement*; } catch(Exception 'ExceptionDcl) { 'CatchStatement*; }"; + String toFind = "try { '_TryStatement*; } catch(Exception '_ExceptionDcl) { '_CatchStatement*; }"; String replacement = "try { $TryStatement$; }\n" + "catch(Throwable $ExceptionDcl$) { $CatchStatement$; }"; String expectedResult = "for (int i = 0; i < MIMEHelper.MIME_MAP.length; i++)\n" + "{\n" + @@ -1833,7 +1841,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " Math.sin(0.5);\n" + " Math.max(1, 2);\n" + "}}"; - final String what = "Math.'m('a*)"; + final String what = "Math.'m('_a*)"; final String by = "Math.$m$($a$)"; options.setToUseStaticImport(true); @@ -1953,7 +1961,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " } catch (PersistenceException e) {\n" + " // good\n" + " }"; - String s2 = "try { 'TryStatement; } catch('ExceptionType 'ExceptionDcl) { /* 'CommentContent */ }"; + String s2 = "try { '_TryStatement; } catch('_ExceptionType '_ExceptionDcl) { /* '_CommentContent */ }"; String replacement = "try { $TryStatement$; } catch($ExceptionType$ $ExceptionDcl$) { _logger.warning(\"$CommentContent$\", $ExceptionDcl$); }"; String expected = "try { em.persist(p); } catch(PersistenceException e) { _logger.warning(\" good\", e); }"; @@ -2069,9 +2077,9 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { "a = 2;\n" + "int b = a;\n" + "b2 = 3;"; - String s2 = "int 'a = 'i;\n" + - "'st*;\n" + - "'a = 'c;"; + String s2 = "int '_a = '_i;\n" + + "'_st*;\n" + + "'_a = '_c;"; String s3 = "$st$;\n" + "$c$ = $i$;"; @@ -2084,9 +2092,9 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { actualResult ); - String s2_2 = "int 'a = 'i;\n" + - "'st*;\n" + - "int 'c = 'a;"; + String s2_2 = "int '_a = '_i;\n" + + "'_st*;\n" + + "int '_c = '_a;"; String s3_2 = "$st$;\n" + "int $c$ = $i$;"; String expected_2 = "a = 2;\nint b = 1;\nb2 = 3;"; @@ -2115,7 +2123,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { public void testReplaceMultipleFieldsInSingleDeclaration() { String source = "abstract class MyClass implements java.util.List {\n private String a, b;\n}"; - String search = "class 'Name implements java.util.List {\n 'ClassContent*\n}"; + String search = "class 'Name implements java.util.List {\n '_ClassContent*\n}"; String replace = "class $Name$ {\n $ClassContent$\n}"; String expectedResult = "abstract class MyClass {\n private String a,b;\n}"; @@ -2131,7 +2139,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { String source = "import java.io.Externalizable;\n" + "import java.io.Serializable;\n" + "abstract class MyClass implements Serializable, java.util.List, Externalizable {}"; - String search = "class 'TestCase implements java.util.List, 'others* {\n 'MyClassContent\n}"; + String search = "class 'TestCase implements java.util.List, '_others* {\n '_MyClassContent\n}"; String replace = "class $TestCase$ implements $others$ {\n $MyClassContent$\n}"; String expectedResult = "import java.io.Externalizable;\n" + "import java.io.Serializable;\n" + @@ -2150,7 +2158,7 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { " public void foo() {\n" + " }\n" + "}"; - String search = "class 'Class {\n 'Content*\n}"; + String search = "class 'Class {\n '_Content*\n}"; String replace = "class $Class$ {\n" + " void x() {}\n" + " $Content$\n" + diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 732859261018..fbc3533e6887 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -1,6 +1,5 @@ package com.intellij.structuralsearch; -import com.intellij.idea.Bombed; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.psi.*; import com.intellij.structuralsearch.impl.matcher.MatcherImplUtil; @@ -9,7 +8,6 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; /** @@ -828,7 +826,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String s10031 = "try { a(); } catch(Exception ex) {} catch(Error error) { 1=1; }\n" + "try { a(); } catch(Exception ex) {}"; - String s10032 = "try { a(); } catch('_Type+ 'Arg+) { 'Statements*; }\n"; + String s10032 = "try { a(); } catch('_Type+ 'Arg+) { '_Statements*; }\n"; assertEquals( "finally matching", 2, @@ -842,6 +840,18 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "return !(x);"; String s10034 = "return ('a);"; assertEquals("Find statement with parenthesized expr",2,findMatchesCount(s10033,s10034)); + + String in = "if (true) {" + + " System.out.println();" + + "} else {" + + " System.out.println();" + + "}" + + "if (true) System.out.println();"; + String pattern1 = "if ('_exp) { '_statement*; }"; + assertEquals("Find if statement with else", 2, findMatchesCount(in, pattern1)); + + String pattern2 = "if ('_exp) { '_statement*; } else { '_statement2{0,0}; }"; + assertEquals("Find if statement without else", 1, findMatchesCount(in, pattern2)); } public void testSearchClass() { @@ -2430,12 +2440,12 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "@Foo(value2=baz4) int a3;\n" + "}"; String s12 = "@Foo(value=baz) int 'a;)"; - String s12_2 = "@Foo(value='baz:baz2 ) int 'a;)"; - String s12_3 = "@Foo('value:value2 = baz3 ) int 'a;)"; - String s12_4 = "@Foo('value:value2 = 'baz3:baz3 ) int 'a;)"; - String s12_5 = "@Foo('value:value2 = 'baz3:baz ) int 'a;)"; - String s12_6 = "@Foo('value:value2 = 'baz3 ) int 'a;)"; - String s12_7 = "@Foo('value:value2 = ) int 'a;"; + String s12_2 = "@Foo(value='baz:baz2 ) int '_a;)"; + String s12_3 = "@Foo('value:value2 = baz3 ) int '_a;)"; + String s12_4 = "@Foo('value:value2 = '_baz3:baz3 ) int '_a;)"; + String s12_5 = "@Foo('value:value2 = '_baz3:baz ) int '_a;)"; + String s12_6 = "@Foo('value:value2 = '_baz3 ) int '_a;)"; + String s12_7 = "@Foo('value:value2 = ) int '_a;"; assertEquals("Find anno parameter value",1,findMatchesCount(s11,s12)); assertEquals("Find anno parameter value",2,findMatchesCount(s11,s12_2)); @@ -2728,12 +2738,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { options.setFileType(StdFileTypes.JAVA); for(PsiVariable var:vars) { - final MatchResult matchResult = testMatcher.isMatchedByDownUp(var, options); - if (matchResult != null) results.add(matchResult); - assertTrue( - (var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection && matchResult != null) || - matchResult == null - ); + final List matchResult = testMatcher.matchByDownUp(var, options); + results.addAll(matchResult); + assertTrue((var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection && !matchResult.isEmpty()) || + matchResult.isEmpty()); } assertEquals(2, results.size()); @@ -2752,12 +2760,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { for(PsiVariable var:vars) { final PsiTypeElement typeElement = var.getTypeElement(); - final MatchResult matchResult = testMatcher.isMatchedByDownUp(typeElement, options); - if (matchResult != null) results.add(matchResult); - assertTrue( - (var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection && matchResult != null) || - matchResult == null - ); + final List matchResult = testMatcher.matchByDownUp(typeElement, options); + results.addAll(matchResult); + assertTrue((var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection && !matchResult.isEmpty()) || + matchResult.isEmpty()); } assertEquals(1, results.size()); @@ -2766,7 +2772,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Type2", result.getMatchImage()); } - @Bombed(day = 28, description = "support it", month = Calendar.JULY, user = "maxim.mossienko") public void _testContainsPredicate() { String s1 = "{{\n" + " int a;\n" + @@ -2808,35 +2813,43 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals(2,findMatchesCount(s1, s2)); assertEquals(1,findMatchesCount(s1, s2_2)); - // TODO: xxx - //String s3 = "if (true) {\n" + - // " if (true) return;\n" + - // " int a = 1;\n" + - // "}\n else if (true) {\n" + - // " return;\n" + - // "}"; - //assertEquals(2,findMatchesCount(s3, s2)); - //assertEquals(1,findMatchesCount(s3, s2_2)); + String s3 = "if (true) {\n" + + " if (true) return;\n" + + " int a = 1;\n" + + "}\n" + + "else if (true) {\n" + + " int b = 2;\n" + + " return;\n" + + "}\n" + + "int c = 3;\n"; + assertEquals(2,findMatchesCount(s3, s2)); + assertEquals(1,findMatchesCount(s3, s2_2)); } public void testWithinPredicate2() { String s3 = "class C {\n" + " void aaa() {\n" + - " LOG.debug(true);\n" + - " LOG.debug(true);\n" + - " LOG.debug(true);\n" + - " LOG.debug(true);\n" + - " LOG.debug(true);\n" + + " LOG.debug(1);\n" + + " LOG.debug(2);\n" + + " LOG.debug(3);\n" + + " LOG.debug(4);\n" + + " LOG.debug(5);\n" + " if (true) {\n" + - " LOG.debug(true);\n" + + " LOG.debug(6);\n" + " }\n" + - " if (true) LOG.debug(true);\n" + - " if (true) { int 1 = 1; } else { LOG.debug(true); }\n" + + " if (true) LOG.debug(7);\n" + + " if (true) { int 1 = 1; } else { LOG.debug(8); }\n" + + " if (true) {\n" + + " if (true) {}\n" + + " if (true) {}\n" + + " } else{\n" + + " LOG.debug(9);\n" + + " }" + " }" + "}"; String s4 = "LOG.debug('_params*:[!within( \"if('_a) { 'st*; }\" )]);"; - assertEquals(6,findMatchesCount(s3, s4)); + assertEquals(7,findMatchesCount(s3, s4)); } public void testMultiStatementPatternWithTypedVariable() throws Exception { diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformerTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformerTest.java index dc1cbc5802f2..5cb376225ed3 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformerTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/impl/matcher/compiler/StringToConstraintsTransformerTest.java @@ -4,6 +4,7 @@ import com.intellij.structuralsearch.MalformedPatternException; import com.intellij.structuralsearch.MatchOptions; import com.intellij.structuralsearch.MatchVariableConstraint; import com.intellij.structuralsearch.UnsupportedPatternException; +import com.intellij.structuralsearch.plugin.ui.Configuration; import org.junit.Before; import org.junit.Test; @@ -121,6 +122,14 @@ public class StringToConstraintsTransformerTest { assertEquals("$a$::$b$", myOptions.getSearchPattern()); } + @Test + public void testScriptEscaping() { + test("'_type 'a:[within( \"if ('_a:[regex( .*e.* )\\]) { '_st*; }\" )] = '_b;"); + assertEquals("$type$ $a$ = $b$;", myOptions.getSearchPattern()); + final MatchVariableConstraint constraint = myOptions.getVariableConstraint(Configuration.CONTEXT_VAR_NAME); + assertEquals("\"if ('_a:[regex( .*e.* )]) { '_st*; }\"", constraint.getWithinConstraint()); + } + private void test(String pattern) { myOptions.setSearchPattern(pattern); StringToConstraintsTransformer.transformOldPattern(myOptions); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index ddb10ac6bef1..7c48c2aabbdc 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -440,7 +440,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { GutterMark findGutter(@NotNull @TestDataFile @NonNls String filePath); @NotNull - Collection findCaretGutters(); + Collection findGuttersAtCaret(); @NotNull PsiManager getPsiManager(); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 549ece165851..2e6567b28133 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -930,7 +930,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @NotNull @Override - public Collection findCaretGutters() { + public Collection findGuttersAtCaret() { CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(); findGutters(processor); return processor.getResults(); diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index c324e0870738..114892b0266e 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -159,6 +159,8 @@ ide.mac.boldEditorTabs=false ide.mac.disableMacScrollbars=false ide.mac.disableMacScrollbars.restartRequired=true ide.mac.disableMacScrollbars.description=Disables OS X overlay scrollbars +ide.mac.pressAndHold.workaround=true +ide.mac.pressAndHold.workaround.description=Enable workaround for press-and-hold input method for accented characters on Mac OS ide.perProjectModality=false ide.perProjectModality.description=New modality approach. All dialogs are DOCUMENT_MODAL expect ide-wide dialogs @@ -257,6 +259,9 @@ java.annotations.inference.nullable.method.description=Restart is required; infe java.annotations.inference.nullable.method.transitivity=true java.annotations.inference.nullable.method.transitivity.description=Restart is required; if a method result is a call to a @Nullable method, reports the caller as @Nullable as well +java.correct.class.type.by.place.resolve.scope=true +java.correct.class.type.by.place.resolve.scope.description=When resolving Java references, use the resolve scope of the currently processed source file + documentation.component.editor.font=false ide.completion.show.better.matching.classes=true diff --git a/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java b/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java index b38c827adf9f..29f1cfaa7c6c 100644 --- a/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java +++ b/platform/util/src/com/intellij/openapi/diff/impl/ComparisonPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,15 +16,16 @@ package com.intellij.openapi.diff.impl; import com.intellij.CommonBundle; -import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.diff.ex.DiffFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.Util; import com.intellij.openapi.diff.impl.processing.DiffCorrection; import com.intellij.openapi.diff.impl.processing.Formatting; import com.intellij.openapi.diff.impl.processing.Word; +import com.intellij.openapi.diff.impl.string.DiffString; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; @@ -241,8 +242,7 @@ public abstract class ComparisonPolicy { if (fragment.isOneSide()) { FragmentSide side = FragmentSide.chooseSide(fragment); DiffString text = side.getText(fragment); - DiffString trimed = text.trim(); - if (trimed.isEmpty()) { + if (StringUtil.isEmptyOrSpaces(text)) { collector.add(side.createFragment(text, DiffString.EMPTY, false)); return; } diff --git a/platform/util/src/com/intellij/openapi/util/io/ZipFileCache.java b/platform/util/src/com/intellij/openapi/util/io/ZipFileCache.java index bf98c0f63b6d..65a7ee3988a7 100644 --- a/platform/util/src/com/intellij/openapi/util/io/ZipFileCache.java +++ b/platform/util/src/com/intellij/openapi/util/io/ZipFileCache.java @@ -68,9 +68,6 @@ public class ZipFileCache { } } - private static final boolean ourEnabled = - ZipFileCache.class.getClassLoader().getResource("com/intellij/openapi/application/Application.class") != null; - private static final Object ourLock = new Object(); private static final Map ourPathCache = ContainerUtil.newTroveMap(FileUtil.PATH_HASHING_STRATEGY); private static final Map ourFileCache = ContainerUtil.newHashMap(); @@ -79,29 +76,20 @@ public class ZipFileCache { private static final ScheduledThreadPoolExecutor ourExecutor; static { - if (ourEnabled) { - ourExecutor = ConcurrencyUtil.newSingleScheduledThreadExecutor("ZipFileCache Dispose", Thread.MIN_PRIORITY); - ourExecutor.scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - List toClose = getFilesToClose(0, System.currentTimeMillis() - TIMEOUT); - if (toClose != null) { - close(toClose); - } + ourExecutor = ConcurrencyUtil.newSingleScheduledThreadExecutor("ZipFileCache Dispose", Thread.MIN_PRIORITY); + ourExecutor.scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + List toClose = getFilesToClose(0, System.currentTimeMillis() - TIMEOUT); + if (toClose != null) { + close(toClose); } - }, PERIOD, PERIOD, TimeUnit.MILLISECONDS); - } - else { - ourExecutor = null; - } + } + }, PERIOD, PERIOD, TimeUnit.MILLISECONDS); } @NotNull public static ZipFile acquire(@NotNull String path) throws IOException { - if (!ourEnabled) { - return new ZipFile(path); - } - path = FileUtil.toCanonicalPath(path); synchronized (ourLock) { @@ -178,11 +166,6 @@ public class ZipFileCache { } public static void release(@NotNull ZipFile file) { - if (!ourEnabled) { - close(file); - return; - } - synchronized (ourLock) { CacheRecord record = ourFileCache.get(file); if (record != null) { diff --git a/platform/util/src/com/intellij/openapi/util/registry/Registry.java b/platform/util/src/com/intellij/openapi/util/registry/Registry.java index dcf20c7def7c..32e2e4fe7f13 100644 --- a/platform/util/src/com/intellij/openapi/util/registry/Registry.java +++ b/platform/util/src/com/intellij/openapi/util/registry/Registry.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -35,7 +35,6 @@ public class Registry { public static final String REGISTRY_BUNDLE = "misc.registry"; private final Map myUserProperties = new LinkedHashMap(); - private final Map myLoadedUserProperties = new HashMap(); private final Map myValues = new ConcurrentHashMap(); private static final Registry ourInstance = new Registry(); @@ -119,20 +118,18 @@ public class Registry { } public void loadState(@NotNull Element state) { - final List entries = state.getChildren("entry"); - for (Object each : entries) { - final Element eachEntry = (Element) each; - final String eachKey = eachEntry.getAttributeValue("key"); - final String eachValue = eachEntry.getAttributeValue("value"); - if (eachKey != null && eachValue != null) { - myUserProperties.put(eachKey, eachValue); + myUserProperties.clear(); + for (Element eachEntry : state.getChildren("entry")) { + String key = eachEntry.getAttributeValue("key"); + String value = eachEntry.getAttributeValue("value"); + if (key != null && value != null) { + RegistryValue registryValue = get(key); + if (registryValue.isChangedFromDefault(value)) { + myUserProperties.put(key, value); + registryValue.resetCache(); + } } } - myLoadedUserProperties.putAll(myUserProperties); - - for (RegistryValue each : myValues.values()) { - each.resetCache(); - } } @NotNull @@ -165,11 +162,11 @@ public class Registry { } public boolean isInDefaultState() { - return getUserProperties().isEmpty(); + return myUserProperties.isEmpty(); } public boolean isRestartNeeded() { - return isRestartNeeded(myUserProperties) || isRestartNeeded(myLoadedUserProperties); + return isRestartNeeded(myUserProperties); } private static boolean isRestartNeeded(@NotNull Map map) { diff --git a/platform/util/src/com/intellij/openapi/util/registry/RegistryValue.java b/platform/util/src/com/intellij/openapi/util/registry/RegistryValue.java index 22e6214530cf..96ddb5330f1f 100644 --- a/platform/util/src/com/intellij/openapi/util/registry/RegistryValue.java +++ b/platform/util/src/com/intellij/openapi/util/registry/RegistryValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -109,7 +109,11 @@ public class RegistryValue { } public boolean isChangedFromDefault() { - return !asString().equals(getBundleValue(myKey, false)); + return isChangedFromDefault(asString()); + } + + boolean isChangedFromDefault(@NotNull String newValue) { + return !newValue.equals(getBundleValue(myKey, false)); } private String get(@NotNull String key, String defaultValue, boolean isValue) throws MissingResourceException { diff --git a/platform/util/src/com/intellij/util/ImageLoader.java b/platform/util/src/com/intellij/util/ImageLoader.java index 1fcc08ea333b..b8ac405c97f3 100644 --- a/platform/util/src/com/intellij/util/ImageLoader.java +++ b/platform/util/src/com/intellij/util/ImageLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -30,6 +30,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -63,7 +65,14 @@ public class ImageLoader implements Serializable { public static Image loadFromUrl(@NotNull URL url) { for (Pair each : getFileNames(url.toString())) { try { - return loadFromStream(URLUtil.openStream(new URL(each.first)), each.second); + Image image = loadFromStream(URLUtil.openStream(new URL(each.first)), each.second); + + //we can't check all 3rd party plugins and convince the authors to add @2x icons. + // isHiDPI() != isRetina() => we should scale images manually + if (image != null && JBUI.isHiDPI() && !each.first.contains("@2x")) { + image = upscale(image); + } + return image; } catch (IOException ignore) { } @@ -71,6 +80,19 @@ public class ImageLoader implements Serializable { return null; } + @NotNull + private static Image upscale(Image image) { + float scale = JBUI.scale(1f); + int width = (int)(scale * image.getWidth(null)); + int height = (int)(scale * image.getHeight(null)); + @SuppressWarnings("UndesirableClassUsage") + BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = tmp.createGraphics(); + g.drawImage(image, AffineTransform.getScaleInstance(scale, scale), null); + image = tmp; + return image; + } + @Nullable public static Image loadFromUrl(URL url, boolean dark, boolean retina) { for (Pair each : getFileNames(url.toString(), dark, retina || JBUI.isHiDPI())) { diff --git a/platform/util/src/com/intellij/util/SystemProperties.java b/platform/util/src/com/intellij/util/SystemProperties.java index 7929dd1ff629..14b6999cb868 100644 --- a/platform/util/src/com/intellij/util/SystemProperties.java +++ b/platform/util/src/com/intellij/util/SystemProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -135,4 +135,12 @@ public class SystemProperties { public static String getJavaVendor() { return System.getProperty("java.vendor"); } + + public static boolean is(String key) { + return getBooleanProperty(key, false); + } + + public static boolean has(String key) { + return System.getProperty(key) != null; + } } diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 4cb8e83f374c..9f63e177e0a6 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -815,7 +815,7 @@ public class ContainerUtil extends ContainerUtilRt { @Nullable @Contract(pure=true) - public static T find(@NotNull Iterable iterable, final T equalTo) { + public static T find(@NotNull Iterable iterable, @NotNull final T equalTo) { return find(iterable, new Condition() { @Override public boolean value(final T object) { diff --git a/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java b/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java index cfe57a2aedaf..11e953de6dcf 100644 --- a/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java @@ -96,7 +96,7 @@ public class MostlySingularMultiMap implements Serializable { return processValue(p, myMap.get(key)); } - private boolean processValue(@NotNull Processor p, Object v) { + private boolean processValue(@NotNull Processor p, Object v) { if (v instanceof Object[]) { for (Object o : (Object[])v) { if (!p.process((V)o)) return false; @@ -109,7 +109,7 @@ public class MostlySingularMultiMap implements Serializable { return true; } - public boolean processAllValues(@NotNull Processor p) { + public boolean processAllValues(@NotNull Processor p) { for (Object v : myMap.values()) { if (!processValue(p, v)) return false; } diff --git a/platform/util/src/com/intellij/util/lang/JarLoader.java b/platform/util/src/com/intellij/util/lang/JarLoader.java index 9c1fa395e6af..4a040e53ef88 100644 --- a/platform/util/src/com/intellij/util/lang/JarLoader.java +++ b/platform/util/src/com/intellij/util/lang/JarLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -64,7 +64,7 @@ class JarLoader extends Loader { if (myCanLockJar) { ZipFileCache.release(zipFile); } - else if (zipFile != null) { + else { zipFile.close(); } } @@ -72,21 +72,21 @@ class JarLoader extends Loader { @NotNull @Override public ClasspathCache.LoaderData buildData() throws IOException { - ClasspathCache.LoaderData loaderData = new ClasspathCache.LoaderData(); ZipFile zipFile = acquireZipFile(); try { + ClasspathCache.LoaderData loaderData = new ClasspathCache.LoaderData(); Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { - ZipEntry zipEntry = entries.nextElement(); - String name = zipEntry.getName(); + ZipEntry entry = entries.nextElement(); + String name = entry.getName(); loaderData.addResourceEntry(name); loaderData.addNameEntry(name); } + return loaderData; } finally { releaseZipFile(zipFile); } - return loaderData; } @Override @@ -99,15 +99,15 @@ class JarLoader extends Loader { } try { - ZipFile file = acquireZipFile(); + ZipFile zipFile = acquireZipFile(); try { - ZipEntry entry = file.getEntry(name); + ZipEntry entry = zipFile.getEntry(name); if (entry != null) { - return MemoryResource.load(getBaseURL(), file, entry); + return MemoryResource.load(getBaseURL(), zipFile, entry); } } finally { - releaseZipFile(file); + releaseZipFile(zipFile); } } catch (Exception e) { diff --git a/platform/util/src/com/intellij/util/ui/JBUI.java b/platform/util/src/com/intellij/util/ui/JBUI.java index 0c80b543d838..70f4539f958a 100644 --- a/platform/util/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/src/com/intellij/util/ui/JBUI.java @@ -17,6 +17,7 @@ package com.intellij.util.ui; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.border.CustomLineBorder; +import com.intellij.util.SystemProperties; import javax.swing.*; import javax.swing.border.Border; @@ -26,7 +27,27 @@ import java.awt.*; * @author Konstantin Bulenkov */ public class JBUI { - private static boolean IS_HIDPI = !SystemInfo.isMac && ("true".equals(System.getProperty("hidpi")) || "true".equals(System.getProperty("is.hidpi"))); + private static boolean IS_HIDPI = calculateHiDPI(); + + private static boolean calculateHiDPI() { + if (SystemInfo.isMac) { + return false; + } + + if (SystemProperties.is("hidpi")) { + return true; + } + + if (SystemProperties.has("hidpi") && !SystemProperties.is("hidpi")) { + return false; + } + + if (SystemInfo.isWindows && getSystemDPI() > 144) { + return true; + } + + return false; + } private static int getSystemDPI() { try { diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 3a8b93a92b11..566625c7378b 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1773,8 +1773,8 @@ public class UIUtil { } private static int THEME_BASED_TEXT_LCD_CONTRAST = 0; - private static int BEST_DARK_LCD_CONTRAST = 100; - private static int BEST_LIGHT_LCD_CONTRAST = 200; + private static int BEST_DARK_LCD_CONTRAST = 250; + private static int BEST_LIGHT_LCD_CONTRAST = 100; public static void setHintingForLCDText(Graphics2D g2d) { diff --git a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java index dd20dc36b0ca..76f20c182bc4 100644 --- a/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AbstractCollectionBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -31,7 +31,7 @@ import java.util.Map; abstract class AbstractCollectionBinding extends Binding implements MultiNodeBinding { private Map myElementBindings; - private final Class myElementType; + private final Class myElementType; private final String myTagName; private final AbstractCollection myAnnotation; @@ -247,7 +247,7 @@ abstract class AbstractCollectionBinding extends Binding implements MultiNodeBin return myAnnotation == null || myAnnotation.surroundWithTag() ? getCollectionTagName(target) : null; } - protected String getCollectionTagName(final Object target) { + protected String getCollectionTagName(Object target) { return myTagName; } } diff --git a/platform/util/src/com/intellij/util/xmlb/Accessor.java b/platform/util/src/com/intellij/util/xmlb/Accessor.java index 7e364b9b6105..90cedb02a8d5 100644 --- a/platform/util/src/com/intellij/util/xmlb/Accessor.java +++ b/platform/util/src/com/intellij/util/xmlb/Accessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -25,13 +25,6 @@ public interface Accessor { void write(Object o, Object value); - @Deprecated - @NotNull - /** - * @deprecated to remove in IDEA 15 - */ - Annotation[] getAnnotations(); - T getAnnotation(@NotNull Class annotationClass); String getName(); diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 884b7e2aa656..f6f7a9b7b5eb 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -21,6 +21,7 @@ import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ReflectionUtil; +import com.intellij.util.ThreeState; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import com.intellij.util.containers.MultiMap; @@ -39,7 +40,7 @@ import java.util.*; import java.util.List; class BeanBinding extends Binding { - private static final Logger LOG = Logger.getInstance(BeanBinding.class); + static final Logger LOG = Logger.getInstance(BeanBinding.class); private static final Map> ourAccessorCache = ContainerUtil.createConcurrentSoftValueMap(); @@ -47,7 +48,9 @@ class BeanBinding extends Binding { @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") private Binding[] myBindings; - private final Class myBeanClass; + final Class myBeanClass; + + ThreeState hasEqualMethod = ThreeState.UNSURE; public BeanBinding(@NotNull Class beanClass, @Nullable Accessor accessor) { super(accessor); @@ -86,7 +89,13 @@ class BeanBinding extends Binding { public Element serializeInto(@NotNull Object o, @Nullable Element element, @NotNull SerializationFilter filter) { for (Binding binding : myBindings) { Accessor accessor = binding.getAccessor(); - if (!filter.accepts(accessor, o)) { + + if (filter instanceof SkipDefaultsSerializationFilter) { + if (((SkipDefaultsSerializationFilter)filter).equal(binding, o)) { + continue; + } + } + else if (!filter.accepts(accessor, o)) { continue; } @@ -121,6 +130,16 @@ class BeanBinding extends Binding { return instance; } + boolean equalByFields(@NotNull Object currentValue, @NotNull Object defaultValue, @NotNull SkipDefaultsSerializationFilter filter) { + for (Binding binding : myBindings) { + Accessor accessor = binding.getAccessor(); + if (!filter.equal(binding, accessor.read(currentValue), accessor.read(defaultValue))) { + return false; + } + } + return true; + } + @NotNull public TObjectFloatHashMap computeBindingWeights(@NotNull LinkedHashSet accessorNameTracker) { TObjectFloatHashMap weights = new TObjectFloatHashMap(accessorNameTracker.size()); @@ -282,14 +301,17 @@ class BeanBinding extends Binding { do { for (Field field : currentClass.getDeclaredFields()) { int modifiers = field.getModifiers(); + //noinspection deprecation if (!Modifier.isStatic(modifiers) && (field.getAnnotation(OptionTag.class) != null || field.getAnnotation(Tag.class) != null || field.getAnnotation(Attribute.class) != null || field.getAnnotation(Property.class) != null || field.getAnnotation(Text.class) != null || + field.getAnnotation(CollectionBean.class) != null || (Modifier.isPublic(modifiers) && - !Modifier.isFinal(modifiers) && + // we don't want to allow final fields of all types, but only supported + (!Modifier.isFinal(modifiers) || Collection.class.isAssignableFrom(field.getType())) && !Modifier.isTransient(modifiers) && field.getAnnotation(Transient.class) == null))) { accessors.add(new FieldAccessor(field)); @@ -342,7 +364,7 @@ class BeanBinding extends Binding { return new TextBinding(accessor); } - if (binding instanceof JDOMExternalizableStringListBinding) { + if (binding instanceof CompactCollectionBinding) { return new AccessorBindingWrapper(accessor, binding); } diff --git a/platform/util/src/com/intellij/util/xmlb/CollectionBinding.java b/platform/util/src/com/intellij/util/xmlb/CollectionBinding.java index 622616bdb7fe..dda4a196eedc 100644 --- a/platform/util/src/com/intellij/util/xmlb/CollectionBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/CollectionBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -22,16 +22,13 @@ import java.lang.reflect.Type; import java.util.*; class CollectionBinding extends AbstractCollectionBinding { - public CollectionBinding(ParameterizedType type, final Accessor accessor) { + public CollectionBinding(ParameterizedType type, Accessor accessor) { super(getComponentClass(type), Constants.COLLECTION, accessor); } - private static Class getComponentClass(ParameterizedType type) { + private static Class getComponentClass(@NotNull ParameterizedType type) { Type arg = type.getActualTypeArguments()[0]; - if (arg instanceof ParameterizedType) { - return (Class)((ParameterizedType)arg).getRawType(); - } - return (Class)arg; + return arg instanceof ParameterizedType ? (Class)((ParameterizedType)arg).getRawType() : (Class)arg; } @Override @@ -58,7 +55,7 @@ class CollectionBinding extends AbstractCollectionBinding { } @Override - protected String getCollectionTagName(final Object target) { + protected String getCollectionTagName(Object target) { if (target instanceof Set) { return Constants.SET; } diff --git a/platform/util/src/com/intellij/util/xmlb/CompactCollectionBinding.java b/platform/util/src/com/intellij/util/xmlb/CompactCollectionBinding.java new file mode 100644 index 000000000000..a1686a75b16b --- /dev/null +++ b/platform/util/src/com/intellij/util/xmlb/CompactCollectionBinding.java @@ -0,0 +1,116 @@ +/* + * Copyright 2000-2015 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.util.xmlb; + +import com.intellij.util.containers.ContainerUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @see com.intellij.util.xmlb.annotations.CollectionBean + */ +class CompactCollectionBinding extends Binding { + private final String name; + + protected CompactCollectionBinding(@NotNull Accessor accessor) { + super(accessor); + + name = myAccessor.getName(); + } + + @Nullable + @Override + public Object serialize(Object o, @Nullable Object context, SerializationFilter filter) { + Element result = new Element(name); + @SuppressWarnings("unchecked") + List list = (List)o; + if (list == null || list.isEmpty()) { + return result; + } + + for (String item : list) { + result.addContent(new Element("item").setAttribute("value", item)); + } + return result; + } + + @Nullable + @Override + public Object deserialize(Object context, @NotNull Object node) { + @SuppressWarnings("unchecked") + List list = (List)context; + list.clear(); + Element element = (Element)node; + if (element.getName().equals(name)) { + for (Element item : element.getChildren("item")) { + ContainerUtil.addIfNotNull(list, item.getAttributeValue("value")); + } + } + else { + // JDOMExternalizableStringList format + Element value = element.getChild("value"); + if (value != null) { + value = value.getChild("list"); + } + if (value != null) { + for (Element item : value.getChildren("item")) { + //noinspection SpellCheckingInspection + ContainerUtil.addIfNotNull(list, item.getAttributeValue("itemvalue")); + } + } + } + return list; + } + + @Override + public boolean isBoundTo(Object node) { + if (node instanceof Element) { + Element element = (Element)node; + String elementName = element.getName(); + if (isNameEqual(elementName)) { + return true; + } + else if (elementName.equals(Constants.OPTION)) { + // JDOMExternalizableStringList format + return isNameEqual(element.getAttributeValue(Constants.NAME)); + } + } + return false; + } + + private boolean isNameEqual(@Nullable String value) { + if (value == null) { + return false; + } + else if (value.equals(name)) { + return true; + } + else if (value.length() == (name.length() + 2) && value.startsWith("my")) { + return Character.isUpperCase(value.charAt(2)) && value.regionMatches(true, 2, name, 0, name.length()); + } + else { + return false; + } + } + + @Override + public Class getBoundNodeType() { + return Element.class; + } +} diff --git a/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java b/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java index c7fd18abad65..f2b0987aa0ca 100644 --- a/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java +++ b/platform/util/src/com/intellij/util/xmlb/FieldAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import org.jetbrains.annotations.NonNls; @@ -39,7 +38,7 @@ class FieldAccessor implements Accessor { return myField.get(o); } catch (IllegalAccessException e) { - throw new XmlSerializationException("Reading "+myField, e); + throw new XmlSerializationException("Reading " + myField, e); } } @@ -52,16 +51,10 @@ class FieldAccessor implements Accessor { myField.set(o, XmlSerializerImpl.convert(value, type)); } catch (IllegalAccessException e) { - throw new XmlSerializationException("Writing "+myField,e); + throw new XmlSerializationException("Writing " + myField, e); } } - @NotNull - @Override - public Annotation[] getAnnotations() { - return myField.getAnnotations(); - } - @Override public T getAnnotation(@NotNull Class annotationClass) { return myField.getAnnotation(annotationClass); diff --git a/platform/util/src/com/intellij/util/xmlb/JDOMExternalizableStringListBinding.java b/platform/util/src/com/intellij/util/xmlb/JDOMExternalizableStringListBinding.java deleted file mode 100644 index 346c616f59f1..000000000000 --- a/platform/util/src/com/intellij/util/xmlb/JDOMExternalizableStringListBinding.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2000-2014 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.util.xmlb; - -import com.intellij.openapi.util.JDOMExternalizableStringList; -import com.intellij.util.containers.ContainerUtil; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@SuppressWarnings("deprecation") -class JDOMExternalizableStringListBinding extends Binding { - private final String myName; - - protected JDOMExternalizableStringListBinding(@NotNull Accessor accessor) { - super(accessor); - - myName = myAccessor.getName(); - } - - @Nullable - @Override - public Object serialize(Object o, @Nullable Object context, SerializationFilter filter) { - Element result = new Element(myName); - JDOMExternalizableStringList list = (JDOMExternalizableStringList)o; - if (list == null || list.isEmpty()) { - return result; - } - - for (String item : list) { - result.addContent(new Element("item").setAttribute("value", item)); - } - return result; - } - - @Nullable - @Override - public Object deserialize(Object context, @NotNull Object node) { - JDOMExternalizableStringList list = (JDOMExternalizableStringList)context; - list.clear(); - for (Element item : ((Element)node).getChildren("item")) { - ContainerUtil.addIfNotNull(list, item.getAttributeValue("value")); - } - return list; - } - - @Override - public boolean isBoundTo(Object node) { - return node instanceof Element && ((Element)node).getName().equals(myName); - } - - @Override - public Class getBoundNodeType() { - return Element.class; - } -} diff --git a/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java b/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java index 9780e683154d..3385dbc435ce 100644 --- a/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java +++ b/platform/util/src/com/intellij/util/xmlb/PropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,8 +16,6 @@ package com.intellij.util.xmlb; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -26,7 +24,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; -import java.util.List; class PropertyAccessor implements Accessor { private final String myName; @@ -80,15 +77,6 @@ class PropertyAccessor implements Accessor { } } - @Override - @NotNull - public Annotation[] getAnnotations() { - List result = new SmartList(); - ContainerUtil.addAll(result, myReadMethod.getAnnotations()); - ContainerUtil.addAll(result, myWriteMethod.getAnnotations()); - return result.toArray(new Annotation[result.size()]); - } - @Override public T getAnnotation(@NotNull Class annotationClass) { T annotation = myReadMethod.getAnnotation(annotationClass); diff --git a/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java b/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java index 01f6f68f4fd1..f12f3647952f 100644 --- a/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java +++ b/platform/util/src/com/intellij/util/xmlb/SerializationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,5 +18,5 @@ package com.intellij.util.xmlb; import org.jetbrains.annotations.NotNull; public interface SerializationFilter { - boolean accepts(@NotNull Accessor accessor, Object bean); + boolean accepts(@NotNull Accessor accessor, @NotNull Object bean); } diff --git a/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java b/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java index 7c1cb2b51795..6731bcaf7698 100644 --- a/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java +++ b/platform/util/src/com/intellij/util/xmlb/SerializationFilterBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -20,10 +20,7 @@ import org.jetbrains.annotations.Nullable; public abstract class SerializationFilterBase implements SerializationFilter { @Override - public final boolean accepts(@NotNull Accessor accessor, Object bean) { - if (bean == null) { - return true; - } + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { return accepts(accessor, bean, accessor.read(bean)); } diff --git a/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java b/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java index f44785f6991c..559ad12f8dab 100644 --- a/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java +++ b/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb; import com.intellij.openapi.util.Comparing; @@ -31,7 +30,7 @@ public class SkipDefaultValuesSerializationFilters extends SerializationFilterBa @Override protected boolean accepts(@NotNull Accessor accessor, @NotNull Object bean, @Nullable Object beanValue) { - final Object defValue = accessor.read(getDefaultBean(bean)); + Object defValue = accessor.read(getDefaultBean(bean)); if (defValue instanceof Element && beanValue instanceof Element) { return !JDOMUtil.areElementsEqual((Element)beanValue, (Element)defValue); } @@ -40,7 +39,8 @@ public class SkipDefaultValuesSerializationFilters extends SerializationFilterBa } } - private Object getDefaultBean(@NotNull Object bean) { + @NotNull + Object getDefaultBean(@NotNull Object bean) { Class c = bean.getClass(); Object o = myDefaultBeans.get(c); if (o == null) { diff --git a/platform/util/src/com/intellij/util/xmlb/SkipDefaultsSerializationFilter.java b/platform/util/src/com/intellij/util/xmlb/SkipDefaultsSerializationFilter.java new file mode 100644 index 000000000000..5d43f7c01d49 --- /dev/null +++ b/platform/util/src/com/intellij/util/xmlb/SkipDefaultsSerializationFilter.java @@ -0,0 +1,72 @@ +/* + * Copyright 2000-2015 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.util.xmlb; + +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.util.ThreeState; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class SkipDefaultsSerializationFilter extends SkipDefaultValuesSerializationFilters { + boolean equal(@NotNull Binding binding, @NotNull Object bean) { + Accessor accessor = binding.getAccessor(); + return equal(binding, accessor.read(bean), accessor.read(getDefaultBean(bean))); + } + + boolean equal(@Nullable Binding binding, @Nullable Object currentValue, @Nullable Object defaultValue) { + if (defaultValue instanceof Element && currentValue instanceof Element) { + return JDOMUtil.areElementsEqual((Element)currentValue, (Element)defaultValue); + } + else { + if (currentValue == defaultValue) { + return true; + } + if (currentValue == null || defaultValue == null) { + return false; + } + + if (binding instanceof BasePrimitiveBinding) { + Binding referencedBinding = ((BasePrimitiveBinding)binding).myBinding; + if (referencedBinding instanceof BeanBinding) { + BeanBinding classBinding = (BeanBinding)referencedBinding; + ThreeState compareByFields = classBinding.hasEqualMethod; + if (compareByFields == ThreeState.UNSURE) { + try { + classBinding.myBeanClass.getDeclaredMethod("equals", Object.class); + compareByFields = ThreeState.NO; + } + catch (NoSuchMethodException ignored) { + compareByFields = ThreeState.YES; + } + catch (Exception e) { + BeanBinding.LOG.warn(e); + } + + classBinding.hasEqualMethod = compareByFields; + } + + if (compareByFields == ThreeState.YES) { + return classBinding.equalByFields(currentValue, defaultValue, this); + } + } + } + + return Comparing.equal(currentValue, defaultValue); + } + } +} diff --git a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java index f254f451fcd1..c3af4340bf41 100644 --- a/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/SmartSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,7 +19,6 @@ import com.intellij.util.ThreeState; import gnu.trove.TObjectFloatHashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.LinkedHashSet; @@ -40,11 +39,11 @@ public final class SmartSerializer { } : new SkipDefaultValuesSerializationFilters() { @Override - protected boolean accepts(@NotNull Accessor accessor, @NotNull Object bean, @Nullable Object beanValue) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { if (mySerializedAccessorNameTracker != null && mySerializedAccessorNameTracker.contains(accessor.getName())) { return true; } - return super.accepts(accessor, bean, beanValue); + return super.accepts(accessor, bean); } }; } diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java index 97e4a35276a5..41a3e86a5a43 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -31,7 +31,7 @@ import java.util.Set; public class XmlSerializer { private static final SerializationFilter TRUE_FILTER = new SerializationFilter() { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { return true; } }; diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index f67982f670d4..11a7ef5ef885 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,12 +18,12 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.xmlb.annotations.CollectionBean; import org.jdom.*; import org.jdom.filter.Filter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.annotation.Annotation; import java.lang.ref.SoftReference; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -119,7 +119,8 @@ class XmlSerializerImpl { map.put(key, binding); try { binding.init(); - } catch (XmlSerializationException e) { + } + catch (XmlSerializationException e) { map.remove(key); throw e; } @@ -156,6 +157,12 @@ class XmlSerializerImpl { return new PrimitiveValueBinding(aClass, accessor); } if (Collection.class.isAssignableFrom(aClass) && originalType instanceof ParameterizedType) { + if (accessor != null) { + CollectionBean listBean = accessor.getAnnotation(CollectionBean.class); + if (listBean != null) { + return new CompactCollectionBinding(accessor); + } + } return new CollectionBinding((ParameterizedType)originalType, accessor); } if (accessor != null) { @@ -167,7 +174,7 @@ class XmlSerializerImpl { } //noinspection deprecation if (JDOMExternalizableStringList.class == aClass) { - return new JDOMExternalizableStringListBinding(accessor); + return new CompactCollectionBinding(accessor); } } if (Date.class.isAssignableFrom(aClass)) { @@ -179,21 +186,6 @@ class XmlSerializerImpl { return new BeanBinding(aClass, accessor); } - @Nullable - @Deprecated - @SuppressWarnings({"unchecked", "unused"}) - /** - * @deprecated to remove in IDEA 15 - */ - static T findAnnotation(Annotation[] annotations, Class aClass) { - if (annotations == null) return null; - - for (Annotation annotation : annotations) { - if (aClass.isAssignableFrom(annotation.getClass())) return (T)annotation; - } - return null; - } - @Nullable @SuppressWarnings({"unchecked"}) static T convert(Object value, Class type) { diff --git a/platform/util/src/com/intellij/util/xmlb/annotations/AbstractCollection.java b/platform/util/src/com/intellij/util/xmlb/annotations/AbstractCollection.java index 9a08e253f0e3..fc7cd5c59180 100644 --- a/platform/util/src/com/intellij/util/xmlb/annotations/AbstractCollection.java +++ b/platform/util/src/com/intellij/util/xmlb/annotations/AbstractCollection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.xmlb.annotations; import com.intellij.util.xmlb.Constants; diff --git a/platform/util/src/com/intellij/util/xmlb/annotations/CollectionBean.java b/platform/util/src/com/intellij/util/xmlb/annotations/CollectionBean.java new file mode 100644 index 000000000000..da60e05b4ef4 --- /dev/null +++ b/platform/util/src/com/intellij/util/xmlb/annotations/CollectionBean.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2015 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.util.xmlb.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +/** + * Can read serialized JDOMExternalizableStringList, but in any case will be written in this bean format. + * It is useful for application-level config, but for project-level consider to use ConverterProvider. + * + * Currently, only string element type supported. + */ +public @interface CollectionBean { +} diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index d518b9c5828a..f5e341b403a9 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -20,6 +20,7 @@ import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.SmartList; import com.intellij.util.xmlb.annotations.*; import junit.framework.AssertionFailedError; import junit.framework.TestCase; @@ -158,6 +159,13 @@ public class XmlSerializerTest extends TestCase { bean); } + public void testSubBeanSerializationAndSkipDefaults() { + BeanWithSubBean bean = new BeanWithSubBean(); + doSerializerTest( + "", + bean, new SkipDefaultsSerializationFilter()); + } + public void testNullFieldValue() { BeanWithPublicFields bean1 = new BeanWithPublicFields(); @@ -538,7 +546,7 @@ public class XmlSerializerTest extends TestCase { "", new SerializationFilter() { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { return accessor.getName().startsWith("I"); } }); @@ -851,7 +859,7 @@ public class XmlSerializerTest extends TestCase { } public static class PropertyFilterTest implements SerializationFilter { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { return !accessor.read(bean).equals("skip"); } } @@ -1195,10 +1203,10 @@ public class XmlSerializerTest extends TestCase { public void testConverterUsingSkipDefaultsFilters() { BeanWithConverter bean = new BeanWithConverter(); - doSerializerTest("", bean, new SkipDefaultValuesSerializationFilters()); + doSerializerTest("", bean, new SkipDefaultsSerializationFilter()); bean.foo = Ref.create("testValue"); - doSerializerTest("", bean, new SkipDefaultValuesSerializationFilters()); + doSerializerTest("", bean, new SkipDefaultsSerializationFilter()); bean.foo = Ref.create(); bean.bar = Ref.create("testValue2"); @@ -1237,7 +1245,7 @@ public class XmlSerializerTest extends TestCase { Bean2 bean = new Bean2(); bean.module = "module"; bean.ab = "ab"; - doSerializerTest("", bean, new SkipDefaultValuesSerializationFilters()); + doSerializerTest("", bean, new SkipDefaultsSerializationFilter()); checkSmartSerialization(new Bean2(), ""); checkSmartSerialization(new Bean2(), ""); @@ -1252,6 +1260,12 @@ public class XmlSerializerTest extends TestCase { public JDOMExternalizableStringList list = new JDOMExternalizableStringList(); } + @Tag("b") + static class Bean4 { + @CollectionBean + public final List list = new SmartList(); + } + @SuppressWarnings("deprecation") public void testJDOMExternalizableStringList() throws IOException, JDOMException { Bean3 bean = new Bean3(); @@ -1264,7 +1278,40 @@ public class XmlSerializerTest extends TestCase { " \n" + " \n" + " \n" + - "", bean, new SkipDefaultValuesSerializationFilters()); + "", bean, new SkipDefaultsSerializationFilter()); + } + + public void testCollectionBean() throws IOException, JDOMException { + Bean4 bean = new Bean4(); + bean.list.add("one"); + bean.list.add("two"); + bean.list.add("three"); + doSerializerTest("\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "", bean, new SkipDefaultsSerializationFilter()); + } + + public void testCollectionBeanReadJDOMExternalizableStringList() throws IOException, JDOMException { + @SuppressWarnings("deprecation") + JDOMExternalizableStringList list = new JDOMExternalizableStringList(); + list.add("one"); + list.add("two"); + list.add("three"); + + Element value = new Element("value"); + list.writeExternal(value); + Bean4 o = XmlSerializer.deserialize(new Element("state").addContent(new Element("option").setAttribute("name", "myList").addContent(value)), Bean4.class); + assertSerializer(o, "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "", "Deserialization failure", new SkipDefaultsSerializationFilter()); } private static void checkSmartSerialization(@NotNull Bean2 bean, @NotNull String serialized) throws IOException, JDOMException { diff --git a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java index 0e51740f4c48..f17109fe4353 100644 --- a/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java +++ b/platform/vcs-api/src/com/intellij/openapi/diff/impl/patch/PatchReader.java @@ -55,10 +55,10 @@ public class PatchReader { this(patchContent, true); } - public PatchReader(CharSequence patchContent, boolean parseHunks) { + public PatchReader(CharSequence patchContent, boolean saveHunks) { myLines = LineTokenizer.tokenizeIntoList(patchContent, false); - myAdditionalInfoParser = new AdditionalInfoParser(!parseHunks); - myPatchContentParser = new PatchContentParser(parseHunks); + myAdditionalInfoParser = new AdditionalInfoParser(!saveHunks); + myPatchContentParser = new PatchContentParser(saveHunks); } public List readAllPatches() throws PatchSyntaxException { @@ -254,15 +254,15 @@ public class PatchReader { private static class PatchContentParser implements Parser { - private final boolean myParseHunks; + private final boolean mySaveHunks; private DiffFormat myDiffFormat = null; private final List myPatches; private boolean myDiffCommandLike; private boolean myIndexLike; - private PatchContentParser(boolean parseHunks) { - myParseHunks = parseHunks; + private PatchContentParser(boolean saveHunks) { + mySaveHunks = saveHunks; myPatches = new SmartList(); } @@ -303,7 +303,7 @@ public class PatchReader { } private TextFilePatch readPatch(String curLine, ListIterator iterator) throws PatchSyntaxException { - final TextFilePatch curPatch = new TextFilePatch(null); + final TextFilePatch curPatch = mySaveHunks ? new TextFilePatch(null) : new EmptyTextFilePatch(); extractFileName(curLine, curPatch, true, myDiffCommandLike && myIndexLike); if (! iterator.hasNext()) throw new PatchSyntaxException(iterator.previousIndex(), "Second file name expected"); @@ -314,7 +314,7 @@ public class PatchReader { } extractFileName(curLine, curPatch, false, myDiffCommandLike && myIndexLike); - while (myParseHunks && iterator.hasNext()) { + while (iterator.hasNext()) { PatchHunk hunk; if (myDiffFormat == DiffFormat.UNIFIED) { hunk = readNextHunkUnified(iterator); @@ -595,4 +595,37 @@ public class PatchReader { boolean testIsStart(final String start); void parse(final String start, final ListIterator iterator) throws PatchSyntaxException; } + + private static class EmptyTextFilePatch extends TextFilePatch { + private int myHunkCount = 0; + private boolean myNew; + private boolean myDeleted; + + EmptyTextFilePatch() { + super(null); + } + + @Override + public void addHunk(PatchHunk hunk) { + if (myHunkCount == 0) { + if (hunk.isNewContent()) { + myNew = true; + } + else if (hunk.isDeletedContent()) { + myDeleted = true; + } + } + myHunkCount++; + } + + @Override + public boolean isNewFile() { + return myHunkCount == 1 && myNew; + } + + @Override + public boolean isDeletedFile() { + return myHunkCount == 1 && myDeleted; + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java index 52481d46aae0..f115c3c36f3f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java @@ -25,7 +25,6 @@ import com.intellij.diff.util.WaitingBackgroundableTaskExecutor; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -34,6 +33,7 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.changes.actions.diff.ChangeDiffRequestProducer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.*; @@ -119,12 +119,6 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor { } if (change.getBeforeRevision() instanceof FakeRevision || change.getAfterRevision() instanceof FakeRevision) { - ChangeListManager.getInstance(myProject).invokeAfterUpdate(new Runnable() { - @Override - public void run() { - refresh(); // TODO: this could cause diff init in 'hide' state - } - }, InvokeAfterUpdateMode.SILENT, "", ModalityState.current()); return new LoadingDiffRequest(ChangeDiffRequestProducer.getRequestTitle(change)); } @@ -193,9 +187,17 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor { return; } - if (selectedChanges.contains(myCurrentChange)) return; - myCurrentChange = selectedChanges.get(0); - updateRequest(); + Change selectedChange = myCurrentChange != null ? ContainerUtil.find(selectedChanges, myCurrentChange) : null; + if (selectedChange == null) { + myCurrentChange = selectedChanges.get(0); + updateRequest(); + return; + } + + if (myCurrentChange.getBeforeRevision() instanceof FakeRevision || myCurrentChange.getAfterRevision() instanceof FakeRevision) { + myCurrentChange = selectedChange; + updateRequest(); + } } @Override diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java index ce6ca72ab996..8b95fbe92c8c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedDiffRequestFromChange.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -16,7 +16,6 @@ package com.intellij.openapi.vcs.changes; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.diff.impl.ComparisonPolicy; import com.intellij.openapi.diff.impl.external.DiffManagerImpl; import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; @@ -87,11 +86,10 @@ public class FragmentedDiffRequestFromChange { filePath.hardRefresh(); file = filePath.getVirtualFile(); } - final PreparedFragmentedContent preparedFragmentedContent = new PreparedFragmentedContent(myProject, fragmentedContent, + return new PreparedFragmentedContent(myProject, fragmentedContent, filePath.getName(), filePath.getFileType(), change.getBeforeRevision() == null ? null : change.getBeforeRevision().getRevisionNumber(), change.getAfterRevision() == null ? null : change.getAfterRevision().getRevisionNumber(), filePath, file); - return preparedFragmentedContent; } private static class RangesCalculator { @@ -138,12 +136,8 @@ public class FragmentedDiffRequestFromChange { } } - ComparisonPolicy comparisonPolicy = DiffManagerImpl.getInstanceEx().getComparisonPolicy(); - if (comparisonPolicy == null) { - comparisonPolicy = ComparisonPolicy.DEFAULT; - } - final TextCompareProcessor processor = new TextCompareProcessor(comparisonPolicy); - final List lineFragments = processor.process(myOldDocument.getText(), myDocument.getText()); + TextCompareProcessor processor = new TextCompareProcessor(DiffManagerImpl.getInstanceEx().getComparisonPolicy()); + List lineFragments = processor.process(myOldDocument.getText(), myDocument.getText()); myRanges = new ArrayList>(lineFragments.size()); for (LineFragment lineFragment : lineFragments) { if (!lineFragment.isEqual()) { @@ -174,7 +168,7 @@ public class FragmentedDiffRequestFromChange { } } - private int correctRangeEnd(final int end, final Document document) { + private static int correctRangeEnd(final int end, final Document document) { if (end == 0) return end; return "\n".equals(document.getText(new TextRange(end - 1, end))) ? end - 1 : end; } @@ -187,7 +181,7 @@ public class FragmentedDiffRequestFromChange { return myException; } - private Document documentFromRevision(final ContentRevision cr) throws VcsException { + private static Document documentFromRevision(final ContentRevision cr) throws VcsException { final Document oldDocument = new DocumentImpl(StringUtil.convertLineSeparators(notNullContentRevision(cr)),true); // todo !!! a question how to show line separators in diff etc // todo currently document doesn't allow to put \r as separator @@ -195,7 +189,7 @@ public class FragmentedDiffRequestFromChange { return oldDocument; } - private String notNullContentRevision(final ContentRevision cr) throws VcsException { + private static String notNullContentRevision(final ContentRevision cr) throws VcsException { if (cr == null) return ""; String content = cr.getContent(); return content == null ? "" : content; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index ab79d9af9be1..5f5aa460d640 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -399,23 +399,25 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C @NotNull public Selection getSelection() { - return new Selection(); + return new Selection(this); } - public class Selection { + public static class Selection { private final TIntHashSet myCommits; + private final VcsLogGraphTable myTable; - public Selection() { - myCommits = getCommitsAtRows(myDataPack.getVisibleGraph(), getSelectedRows()); + public Selection(@NotNull VcsLogGraphTable table) { + myTable = table; + myCommits = getCommitsAtRows(myTable.myDataPack.getVisibleGraph(), myTable.getSelectedRows()); } public void restore(@NotNull VisibleGraph newVisibleGraph) { - TIntHashSet rowsToSelect = findNewRowsToSelect(getGraphTableModel(), newVisibleGraph, myCommits); + TIntHashSet rowsToSelect = findNewRowsToSelect(myTable.getGraphTableModel(), newVisibleGraph, myCommits); if (!rowsToSelect.isEmpty()) { rowsToSelect.forEach(new TIntProcedure() { @Override public boolean execute(int row) { - addRowSelectionInterval(row, row); + myTable.addRowSelectionInterval(row, row); return true; } }); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java index a24618215fde..f629904d14cc 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.AppUIUtil; import com.intellij.util.SmartList; +import com.intellij.util.containers.IntIntHashMap; import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; @@ -102,7 +103,7 @@ public abstract class XFetchValueActionBase extends AnAction { protected class ValueCollector { private final List values = new SmartList(); - private final List indents = new SmartList(); + private final IntIntHashMap indents = new IntIntHashMap(); private final XDebuggerTree myTree; private volatile boolean processed; @@ -111,18 +112,18 @@ public abstract class XFetchValueActionBase extends AnAction { } public void add(@NotNull String value) { - add(value, 0); + values.add(value); } public void add(@NotNull String value, int indent) { values.add(value); - indents.add(indent); + indents.put(values.size() - 1, indent); } public void finish(Project project) { if (processed && !values.contains(null) && !project.isDisposed()) { int minIndent = Integer.MAX_VALUE; - for (Integer indent : indents) { + for (int indent : indents.getValues()) { minIndent = Math.min(minIndent, indent); } StringBuilder sb = new StringBuilder(); @@ -130,8 +131,10 @@ public abstract class XFetchValueActionBase extends AnAction { if (i > 0) { sb.append("\n"); } - Integer indent = indents.get(i); - StringUtil.repeatSymbol(sb, ' ', indent - minIndent); + int indent = indents.get(i); + if (indent > 0) { + StringUtil.repeatSymbol(sb, ' ', indent - minIndent); + } sb.append(values.get(i)); } handleInCollector(project, sb.toString(), myTree); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java index 28669193d19a..9961a7103f18 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspection.java @@ -15,7 +15,6 @@ */ package com.siyeh.ig.style; -import com.intellij.codeInsight.javadoc.JavaDocUtil; import com.intellij.codeInspection.CleanupLocalInspectionTool; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.diagnostic.Logger; @@ -26,6 +25,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; +import com.intellij.psi.impl.source.codeStyle.ImportHelper; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -206,11 +206,6 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl if (element != null) { return; } - final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(reference.getProject()); - PsiDocComment containingComment = PsiTreeUtil.getParentOfType(reference, PsiDocComment.class); - if (containingComment != null && acceptFullyQualifiedNamesInJavadoc(containingComment, styleSettings)) { - return; - } final PsiFile containingFile = reference.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return; @@ -219,6 +214,11 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl if (!(target instanceof PsiClass)) { return; } + final CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(reference.getProject()); + PsiDocComment containingComment = PsiTreeUtil.getParentOfType(reference, PsiDocComment.class); + if (containingComment != null && acceptFqnInJavadoc((PsiJavaFile)containingFile, reference.getQualifiedName(), styleSettings)) { + return; + } final PsiJavaCodeReferenceElement qualifierReference = (PsiJavaCodeReferenceElement)qualifier; final PsiElement qualifierTarget = qualifierReference.resolve(); if (!(qualifierTarget instanceof PsiPackage)) { @@ -262,11 +262,14 @@ public class UnnecessaryFullyQualifiedNameInspection extends BaseInspection impl } } - public static boolean acceptFullyQualifiedNamesInJavadoc(PsiDocComment comment, CodeStyleSettings styleSettings) { - if (JavaDocUtil.isInsidePackageInfo(comment)) { + private static boolean acceptFqnInJavadoc(PsiJavaFile javaFile, String fullyQualifiedName, CodeStyleSettings styleSettings) { + if ("package-info.java".equals(javaFile.getName())) { return true; } JavaCodeStyleSettings javaSettings = styleSettings.getCustomSettings(JavaCodeStyleSettings.class); + if (javaSettings.CLASS_NAMES_IN_JAVADOC == JavaCodeStyleSettings.FULLY_QUALIFY_NAMES_IF_NOT_IMPORTED) { + return !ImportHelper.isAlreadyImported(javaFile, fullyQualifiedName); + } return javaSettings.useFqNamesInJavadocAlways(); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/DoubleQualify.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/DoubleQualify.java new file mode 100644 index 000000000000..de1e31544974 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/DoubleQualify.java @@ -0,0 +1,7 @@ +import java.util.HashMap; + +/** + * {@link java.util.HashMap} + */ +public class DoubleQualify { +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/Single.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/Single.java new file mode 100644 index 000000000000..193c25f043c5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/Single.java @@ -0,0 +1,5 @@ +/** + * {@link java.util.HashMap} + */ +public class Single { +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/expected.xml new file mode 100644 index 000000000000..05706352d657 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_fqn_javadoc_fully_qualify_if_not_imported/expected.xml @@ -0,0 +1,11 @@ + + + + + DoubleQualify.java + 4 + Unnecessary fully qualified name + Fully qualified name <code>java.util.HashMap</code> is unnecessary, and can be replaced with an import #loc + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java index 8dc9ea7b861c..1856fc662a46 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryFullyQualifiedNameInspectionTest.java @@ -10,7 +10,7 @@ public class UnnecessaryFullyQualifiedNameInspectionTest extends IGInspectionTes private static final String BASE_DIR = "com/siyeh/igtest/style/"; public void testFqnInJavadoc_Unnecessary_WhenFullyQualifyIfNotImported() throws Exception { - doTestWithFqnInJavadocSetting(BASE_DIR + "unnecessary_fully_qualified_name/", JavaCodeStyleSettings.FULLY_QUALIFY_NAMES_IF_NOT_IMPORTED); + doTestWithFqnInJavadocSetting(BASE_DIR + "unnecessary_fqn_javadoc_fully_qualify_if_not_imported", JavaCodeStyleSettings.FULLY_QUALIFY_NAMES_IF_NOT_IMPORTED); } public void testFqnInJavadoc_Unnecessary_WhenShortNamesAlways() { diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java index b2bfefce47e6..8db552b12ee6 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java @@ -76,6 +76,7 @@ public class Configuration extends SimpleModificationTracker implements Persiste @State( name = Configuration.COMPONENT_NAME, + defaultStateAsResource = true, storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)}) public static class App extends Configuration { @@ -110,8 +111,10 @@ public class Configuration extends SimpleModificationTracker implements Persiste return getState(element); } } + @State( name = Configuration.COMPONENT_NAME, + defaultStateAsResource = true, storages = { @Storage(file = StoragePathMacros.PROJECT_FILE), @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED) diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java index bffe0cd4eb8b..a9172f43150e 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceMethodRefWithLambdaIntention.java @@ -22,6 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.RedundantCastUtil; @@ -49,13 +50,25 @@ public class ReplaceMethodRefWithLambdaIntention extends Intention { final PsiMethodReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(element, PsiMethodReferenceExpression.class); LOG.assertTrue(referenceExpression != null); final PsiElement resolve = referenceExpression.resolve(); - final boolean isReceiver = resolve instanceof PsiMethod && PsiMethodReferenceUtil.hasReceiver(referenceExpression, (PsiMethod)resolve); - final PsiParameter[] psiParameters = resolve instanceof PsiMethod ? ((PsiMethod)resolve).getParameterList().getParameters() : null; final PsiType functionalInterfaceType = referenceExpression.getFunctionalInterfaceType(); final PsiClassType.ClassResolveResult functionalInterfaceResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); LOG.assertTrue(interfaceMethod != null); final PsiSubstitutor psiSubstitutor = LambdaUtil.getSubstitutor(interfaceMethod, functionalInterfaceResolveResult); + final MethodSignature signature = interfaceMethod.getSignature(psiSubstitutor); + final boolean isReceiver; + if (resolve instanceof PsiMethod){ + final PsiMethod method = (PsiMethod)resolve; + isReceiver = PsiMethodReferenceUtil.isResolvedBySecondSearch(referenceExpression, signature, + method.isVarArgs(), + method.hasModifierProperty(PsiModifier.STATIC), + method.getParameterList().getParametersCount()); + } + else { + isReceiver = false; + } + final PsiParameter[] psiParameters = resolve instanceof PsiMethod ? ((PsiMethod)resolve).getParameterList().getParameters() : null; + final StringBuilder buf = new StringBuilder("("); LOG.assertTrue(functionalInterfaceType != null); buf.append(functionalInterfaceType.getCanonicalText()).append(")("); diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AllJarsUnderDirEntry.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AllJarsUnderDirEntry.java index 08748de5af2d..54205337eee4 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AllJarsUnderDirEntry.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AllJarsUnderDirEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -20,7 +20,6 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.roots.ui.CellAppearanceEx; import com.intellij.openapi.roots.ui.FileAppearanceService; import com.intellij.openapi.roots.ui.ModifiableCellAppearanceEx; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; @@ -55,7 +54,7 @@ public class AllJarsUnderDirEntry implements AntClasspathEntry { this(new File(osPath)); } - public void writeExternal(final Element dataElement) throws WriteExternalException { + public void writeExternal(final Element dataElement) { String url = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, myDir.getAbsolutePath().replace(File.separatorChar, '/')); dataElement.setAttribute(DIR, url); } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntClasspathEntry.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntClasspathEntry.java index fb70c3728d9d..44931e324ebf 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntClasspathEntry.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntClasspathEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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,9 +18,7 @@ package com.intellij.lang.ant.config.impl; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.roots.ui.CellAppearanceEx; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.NullableFactory; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.PathUtil; @@ -35,23 +33,25 @@ import java.util.List; public interface AntClasspathEntry { Externalizer EXTERNALIZER = new Externalizer() { @Override - public AntClasspathEntry readValue(Element dataElement) throws InvalidDataException { + public AntClasspathEntry readValue(Element dataElement) { String pathUrl = dataElement.getAttributeValue(SinglePathEntry.PATH); - if (pathUrl != null) + if (pathUrl != null) { return new SinglePathEntry(PathUtil.toPresentableUrl(pathUrl)); + } String dirUrl = dataElement.getAttributeValue(AllJarsUnderDirEntry.DIR); - if (dirUrl != null) + if (dirUrl != null) { return new AllJarsUnderDirEntry(PathUtil.toPresentableUrl(dirUrl)); - throw new InvalidDataException(); + } + throw new IllegalStateException(); } @Override - public void writeValue(Element dataElement, AntClasspathEntry entry) throws WriteExternalException { + public void writeValue(Element dataElement, AntClasspathEntry entry) { entry.writeExternal(dataElement); } }; - void writeExternal(Element dataElement) throws WriteExternalException; + void writeExternal(Element dataElement); void addFilesTo(List files); @@ -60,7 +60,7 @@ public interface AntClasspathEntry { abstract class AddEntriesFactory implements NullableFactory> { private final JComponent myParentComponent; private final FileChooserDescriptor myDescriptor; - private final Function myMapper; + private final Function myMapper; public AddEntriesFactory(final JComponent parentComponent, final FileChooserDescriptor descriptor, diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntInstallation.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntInstallation.java index 12c8d141b79e..2e9405564a3d 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntInstallation.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntInstallation.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -17,8 +17,6 @@ package com.intellij.lang.ant.config.impl; import com.intellij.lang.ant.AntBundle; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.JarUtil; import com.intellij.util.config.*; import com.intellij.util.containers.Convertor; @@ -62,18 +60,18 @@ public class AntInstallation { } public static final Externalizer EXTERNALIZER = new Externalizer() { - public AntInstallation readValue(Element dataElement) throws InvalidDataException { + public AntInstallation readValue(Element dataElement) { AntInstallation antInstallation = new AntInstallation(); antInstallation.readExternal(dataElement); return antInstallation; } - public void writeValue(Element dataElement, AntInstallation antInstallation) throws WriteExternalException { + public void writeValue(Element dataElement, AntInstallation antInstallation) { antInstallation.myProperties.writeExternal(dataElement); } }; - private void readExternal(Element dataElement) throws InvalidDataException { + private void readExternal(Element dataElement) { myProperties.readExternal(dataElement); File antJar = new File(HOME_DIR.get(myProperties), PATH_TO_ANT_JAR); updateVersion(antJar); diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntReference.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntReference.java index f9f8d0d9eb9f..c3133da1350f 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntReference.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntReference.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,7 +19,6 @@ import com.intellij.execution.CantRunException; import com.intellij.lang.ant.AntBundle; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.util.config.AbstractProperty; import com.intellij.util.config.Externalizer; import org.jdom.Element; @@ -35,11 +34,13 @@ public abstract class AntReference { @NonNls private static final String BUNDLED_ANT_ATTR = "bundledAnt"; public static final Externalizer EXTERNALIZER = new Externalizer() { - public AntReference readValue(Element dataElement) throws InvalidDataException { + public AntReference readValue(Element dataElement) { if (Boolean.valueOf(dataElement.getAttributeValue(PROJECT_DEFAULT_ATTR)).booleanValue()) return PROJECT_DEFAULT; if (Boolean.valueOf(dataElement.getAttributeValue(BUNDLED_ANT_ATTR)).booleanValue()) return BUNDLED_ANT; String name = dataElement.getAttributeValue(NAME_ATTR); - if (name == null) throw new InvalidDataException(); + if (name == null) { + throw new IllegalStateException("no name"); + } return new MissingAntReference(name); } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/GlobalAntConfiguration.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/GlobalAntConfiguration.java index 43655b0463b4..d0166ffef749 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/GlobalAntConfiguration.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/GlobalAntConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -31,8 +31,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.config.*; @@ -102,24 +100,13 @@ public class GlobalAntConfiguration implements PersistentStateComponent @Override public Element getState() { Element element = new Element("state"); - try { - myProperties.writeExternal(element); - } - catch (WriteExternalException e) { - LOG.error(e); - return null; - } + myProperties.writeExternal(element); return element; } @Override public void loadState(Element state) { - try { - myProperties.readExternal(state); - } - catch (InvalidDataException e) { - LOG.error(e); - } + myProperties.readExternal(state); } public static GlobalAntConfiguration getInstance() { diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/SinglePathEntry.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/SinglePathEntry.java index 76581fd86f0c..ac982d676255 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/SinglePathEntry.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/SinglePathEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2015 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,8 +18,6 @@ package com.intellij.lang.ant.config.impl; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.roots.ui.CellAppearanceEx; import com.intellij.openapi.roots.ui.FileAppearanceService; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; @@ -51,12 +49,12 @@ public class SinglePathEntry implements AntClasspathEntry { this(new File(osPath)); } - public void readExternal(final Element element) throws InvalidDataException { + public void readExternal(final Element element) { String value = element.getAttributeValue(PATH); myFile = new File(PathUtil.toPresentableUrl(value)); } - public void writeExternal(final Element element) throws WriteExternalException { + public void writeExternal(final Element element) { String url = VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, myFile.getAbsolutePath().replace(File.separatorChar, '/')); element.setAttribute(PATH, url); } diff --git a/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java b/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java index 0756d656a55a..2a7103ceb9cf 100644 --- a/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java +++ b/plugins/coverage/src/com/intellij/coverage/view/JavaCoverageViewExtension.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2015 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.coverage.view; import com.intellij.coverage.*; @@ -235,9 +250,13 @@ public class JavaCoverageViewExtension extends CoverageViewExtension { : PsiFile.EMPTY_ARRAY; } }); - for (PsiFile file : childFiles) { + for (final PsiFile file : childFiles) { if (file instanceof PsiJavaFile) { - PsiClass[] classes = ((PsiJavaFile)file).getClasses(); + PsiClass[] classes = ApplicationManager.getApplication().runReadAction(new Computable() { + public PsiClass[] compute() { + return ((PsiJavaFile) file).getClasses(); + } + }); if (classes.length > 0) { PsiClass aClass = classes[0]; if (!(node instanceof CoverageListRootNode) && getClassCoverageInfo(aClass) == null) continue; diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java index ad1812886cc0..dd51519db9f5 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java @@ -217,15 +217,14 @@ public class GithubApiUtil { } @NotNull - public static String getReadOnlyToken(@NotNull GithubConnection connection, - @NotNull String user, - @NotNull String repo, - @NotNull String note) + public static String getTasksToken(@NotNull GithubConnection connection, + @NotNull String user, + @NotNull String repo, + @NotNull String note) throws IOException { GithubRepo repository = getDetailedRepoInfo(connection, user, repo); - // TODO: use read-only token for private repos when it will be available - List scopes = repository.isPrivate() ? Collections.singletonList("repo") : Collections.emptyList(); + List scopes = repository.isPrivate() ? Collections.singletonList("repo") : Collections.singletonList("public_repo"); return getScopedToken(connection, scopes, note); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java index a8445b7f76ac..d59ac54e3a0b 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java @@ -55,7 +55,7 @@ public class GithubRepository extends BaseRepositoryImpl { public GithubRepository(GithubRepositoryType type) { super(type); - setUrl(GithubApiUtil.DEFAULT_GITHUB_HOST); + setUrl("https://" + GithubApiUtil.DEFAULT_GITHUB_HOST); } @NotNull diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java index ba863621c969..e3e8daabb56a 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java @@ -130,7 +130,7 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControl.java index 55257bd4eec4..37a7442e3eb4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControl.java @@ -15,50 +15,14 @@ */ package org.jetbrains.plugins.gradle.service.settings; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.externalSystem.model.settings.LocationSettingType; import com.intellij.openapi.externalSystem.service.settings.AbstractExternalProjectSettingsControl; import com.intellij.openapi.externalSystem.service.settings.AbstractImportFromExternalSystemControl; -import com.intellij.openapi.externalSystem.service.ui.ExternalSystemJdkComboBox; -import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; import com.intellij.openapi.externalSystem.util.PaintAwarePanel; -import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.TextComponentAccessor; -import com.intellij.openapi.ui.TextFieldWithBrowseButton; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.components.JBLabel; -import com.intellij.ui.components.JBRadioButton; -import com.intellij.util.Alarm; -import com.intellij.util.Consumer; -import com.intellij.util.ObjectUtils; -import com.intellij.util.ui.UIUtil; -import org.gradle.util.GradleVersion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.gradle.service.GradleInstallationManager; -import org.jetbrains.plugins.gradle.settings.DistributionType; import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; -import org.jetbrains.plugins.gradle.util.GradleBundle; -import org.jetbrains.plugins.gradle.util.GradleConstants; -import org.jetbrains.plugins.gradle.util.GradleUtil; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.util.concurrent.TimeUnit; - -import static com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil.USE_PROJECT_JDK; /** * @author Denis Zhdanov @@ -66,354 +30,49 @@ import static com.intellij.openapi.externalSystem.service.execution.ExternalSyst */ public class GradleProjectSettingsControl extends AbstractExternalProjectSettingsControl { - private static final long BALLOON_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(1); - - @NotNull private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - - @NotNull private LocationSettingType myGradleHomeSettingType = LocationSettingType.UNKNOWN; - - @NotNull private final GradleInstallationManager myInstallationManager; - - @SuppressWarnings("FieldCanBeLocal") // Used implicitly by reflection at disposeUIResources() and showUi() - private JLabel myGradleHomeLabel; - @SuppressWarnings("FieldCanBeLocal") // Used implicitly by reflection at disposeUIResources() and showUi() - private JLabel myGradleJdkLabel; - private ExternalSystemJdkComboBox myGradleJdkComboBox; - private TextFieldWithBrowseButton myGradleHomePathField; - private JBRadioButton myUseWrapperButton; - private JBRadioButton myUseWrapperWithVerificationButton; - private JBLabel myUseWrapperVerificationLabel; - private JBRadioButton myUseLocalDistributionButton; - private JBRadioButton myUseBundledDistributionButton; - - private boolean myShowBalloonIfNecessary; + private final GradleProjectSettingsControlBuilder myBuilder; public GradleProjectSettingsControl(@NotNull GradleProjectSettings initialSettings) { - super(initialSettings); - myInstallationManager = ServiceManager.getService(GradleInstallationManager.class); + this(GradleSettingsControlProvider.get().getProjectSettingsControlBuilder(initialSettings)); + } + + public GradleProjectSettingsControl(@NotNull GradleProjectSettingsControlBuilder builder) { + super(null, builder.getInitialSettings(), builder.getExternalSystemSettingsControlCustomizer()); + myBuilder = builder; } @Override protected void fillExtraControls(@NotNull PaintAwarePanel content, int indentLevel) { - content.setPaintCallback(new Consumer() { - @Override - public void consume(Graphics graphics) { - showBalloonIfNecessary(); - } - }); - - content.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (!"ancestor".equals(evt.getPropertyName())) { - return; - } - - // Configure the balloon to show on initial configurable drawing. - myShowBalloonIfNecessary = evt.getNewValue() != null && evt.getOldValue() == null; - - if (evt.getNewValue() == null && evt.getOldValue() != null) { - // Cancel delayed balloons when the configurable is hidden. - myAlarm.cancelAllRequests(); - } - } - }); - - myGradleHomeLabel = new JBLabel(GradleBundle.message("gradle.settings.text.home.path")); - initGradleHome(); - myGradleJdkLabel = new JBLabel(GradleBundle.message("gradle.settings.text.jvm.path")); - myGradleJdkComboBox = new ExternalSystemJdkComboBox().withoutJre(); - - initControls(); - content.add(myUseWrapperButton, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); - content.add(myUseWrapperWithVerificationButton, ExternalSystemUiUtil.getLabelConstraints(indentLevel)); - content.add(myUseWrapperVerificationLabel, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); - //content.add(Box.createGlue(), ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); - // Hide bundled distribution option for a while - // content.add(myUseBundledDistributionButton, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); - content.add(myUseLocalDistributionButton, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); - - content.add(myGradleHomeLabel, ExternalSystemUiUtil.getLabelConstraints(indentLevel)); - content.add(myGradleHomePathField, ExternalSystemUiUtil.getFillLineConstraints(0)); - - content.add(myGradleJdkLabel, ExternalSystemUiUtil.getLabelConstraints(indentLevel)); - content.add(myGradleJdkComboBox, ExternalSystemUiUtil.getFillLineConstraints(0)); - } - - private void initControls() { - ActionListener listener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - boolean localDistributionEnabled = myUseLocalDistributionButton.isSelected(); - myGradleHomePathField.setEnabled(localDistributionEnabled); - if (localDistributionEnabled) { - if(myGradleHomePathField.getText().isEmpty()){ - deduceGradleHomeIfPossible(); - } else { - if(myInstallationManager.isGradleSdkHome(myGradleHomePathField.getText())){ - myGradleHomeSettingType = LocationSettingType.EXPLICIT_CORRECT; - } else { - myGradleHomeSettingType = LocationSettingType.EXPLICIT_INCORRECT; - myShowBalloonIfNecessary = true; - } - } - showBalloonIfNecessary(); - } - else { - myAlarm.cancelAllRequests(); - } - } - }; - - myUseWrapperButton = new JBRadioButton(GradleBundle.message("gradle.settings.text.use.default_wrapper.configured")); - myUseWrapperButton.addActionListener(listener); - myUseWrapperWithVerificationButton = new JBRadioButton(GradleBundle.message("gradle.settings.text.use.customizable_wrapper")); - myUseWrapperWithVerificationButton.addActionListener(listener); - myUseWrapperVerificationLabel = new JBLabel(GradleBundle.message("gradle.settings.text.wrapper.customization.compatibility")); - myUseWrapperVerificationLabel.setFont(UIUtil.getLabelFont(UIUtil.FontSize.MINI)); - myUseWrapperVerificationLabel.setIcon(UIUtil.getBalloonInformationIcon()); - - myUseLocalDistributionButton = new JBRadioButton(GradleBundle.message("gradle.settings.text.use.local.distribution")); - myUseLocalDistributionButton.addActionListener(listener); - - myUseBundledDistributionButton = new JBRadioButton( - GradleBundle.message("gradle.settings.text.use.bundled.distribution", GradleVersion.current().getVersion())); - myUseBundledDistributionButton.addActionListener(listener); - myUseBundledDistributionButton.setEnabled(false); - - ButtonGroup buttonGroup = new ButtonGroup(); - buttonGroup.add(myUseWrapperButton); - buttonGroup.add(myUseWrapperWithVerificationButton); - buttonGroup.add(myUseBundledDistributionButton); - buttonGroup.add(myUseLocalDistributionButton); - } - - private void initGradleHome() { - myGradleHomePathField = new TextFieldWithBrowseButton(); - - FileChooserDescriptor fileChooserDescriptor = GradleUtil.getGradleHomeFileChooserDescriptor(); - - myGradleHomePathField.addBrowseFolderListener( - "", - GradleBundle.message("gradle.settings.text.home.path"), - null, - fileChooserDescriptor, - TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT, - false - ); - myGradleHomePathField.getTextField().getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - myGradleHomePathField.getTextField().setForeground(LocationSettingType.EXPLICIT_CORRECT.getColor()); - } - - @Override - public void removeUpdate(DocumentEvent e) { - myGradleHomePathField.getTextField().setForeground(LocationSettingType.EXPLICIT_CORRECT.getColor()); - } - - @Override - public void changedUpdate(DocumentEvent e) { - } - }); + myBuilder.createAndFillControls(content, indentLevel); } @Override public boolean validate(@NotNull GradleProjectSettings settings) throws ConfigurationException { - String gradleHomePath = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); - if (myUseLocalDistributionButton.isSelected()) { - if (StringUtil.isEmpty(gradleHomePath)) { - myGradleHomeSettingType = LocationSettingType.UNKNOWN; - throw new ConfigurationException(GradleBundle.message("gradle.home.setting.type.explicit.empty", gradleHomePath)); - } - else if (!myInstallationManager.isGradleSdkHome(new File(gradleHomePath))) { - myGradleHomeSettingType = LocationSettingType.EXPLICIT_INCORRECT; - new DelayedBalloonInfo(MessageType.ERROR, myGradleHomeSettingType, 0).run(); - throw new ConfigurationException(GradleBundle.message("gradle.home.setting.type.explicit.incorrect", gradleHomePath)); - } - } - return true; + return myBuilder.validate(settings); } @Override protected void applyExtraSettings(@NotNull GradleProjectSettings settings) { - String gradleHomePath = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); - if (StringUtil.isEmpty(gradleHomePath)) { - settings.setGradleHome(null); - } - else { - settings.setGradleHome(gradleHomePath); - GradleUtil.storeLastUsedGradleHome(gradleHomePath); - } - - final String gradleJvm = FileUtil.toCanonicalPath(myGradleJdkComboBox.getSelectedValue()); - settings.setGradleJvm(StringUtil.isEmpty(gradleJvm) ? null : gradleJvm); - - if (myUseLocalDistributionButton.isSelected()) { - settings.setDistributionType(DistributionType.LOCAL); - } else if(myUseWrapperButton.isSelected()) { - settings.setDistributionType(DistributionType.DEFAULT_WRAPPED); - } else if(myUseWrapperWithVerificationButton.isSelected() || myUseBundledDistributionButton.isSelected()) { - settings.setDistributionType(DistributionType.WRAPPED); - } + myBuilder.apply(settings); } @Override protected void updateInitialExtraSettings() { - String gradleHomePath = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); - getInitialSettings().setGradleHome(StringUtil.isEmpty(gradleHomePath) ? null : gradleHomePath); - final String gradleJvm = FileUtil.toCanonicalPath(myGradleJdkComboBox.getSelectedValue()); - getInitialSettings().setGradleJvm(StringUtil.isEmpty(gradleJvm) ? null : gradleJvm); - if (myUseLocalDistributionButton.isSelected()) { - getInitialSettings().setDistributionType(DistributionType.LOCAL); - } else if(myUseWrapperButton.isSelected()) { - getInitialSettings().setDistributionType(DistributionType.DEFAULT_WRAPPED); - } else if(myUseWrapperWithVerificationButton.isSelected() || myUseBundledDistributionButton.isSelected()) { - getInitialSettings().setDistributionType(DistributionType.WRAPPED); - } + myBuilder.apply(getInitialSettings()); } @Override protected boolean isExtraSettingModified() { - DistributionType distributionType = getInitialSettings().getDistributionType(); - if (myUseBundledDistributionButton.isSelected() && distributionType != DistributionType.BUNDLED) { - return true; - } - - if (myUseWrapperButton.isSelected() && distributionType != DistributionType.DEFAULT_WRAPPED) { - return true; - } - - if (myUseWrapperWithVerificationButton.isSelected() && distributionType != DistributionType.WRAPPED) { - return true; - } - - if (myUseLocalDistributionButton.isSelected() && distributionType != DistributionType.LOCAL) { - return true; - } - - if (!StringUtil.equals(myGradleJdkComboBox.getSelectedValue(), getInitialSettings().getGradleJvm())) { - return true; - } - - String gradleHome = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); - if (StringUtil.isEmpty(gradleHome)) { - return !StringUtil.isEmpty(getInitialSettings().getGradleHome()); - } - else { - return !gradleHome.equals(getInitialSettings().getGradleHome()); - } + return myBuilder.isModified(getInitialSettings()); } @Override protected void resetExtraSettings(boolean isDefaultModuleCreation) { - String gradleHome = getInitialSettings().getGradleHome(); - myGradleHomePathField.setText(gradleHome == null ? "" : gradleHome); - myGradleHomePathField.getTextField().setForeground(LocationSettingType.EXPLICIT_CORRECT.getColor()); - - resetGradleJdkComboBox(getProject()); - - updateWrapperControls(getInitialSettings().getExternalProjectPath(), isDefaultModuleCreation); - if (!myUseLocalDistributionButton.isSelected()) { - myGradleHomePathField.setEnabled(false); - return; - } - - if (StringUtil.isEmpty(gradleHome)) { - myGradleHomeSettingType = LocationSettingType.UNKNOWN; - deduceGradleHomeIfPossible(); - } - else { - myGradleHomeSettingType = myInstallationManager.isGradleSdkHome(new File(gradleHome)) ? - LocationSettingType.EXPLICIT_CORRECT : - LocationSettingType.EXPLICIT_INCORRECT; - myAlarm.cancelAllRequests(); - if (myGradleHomeSettingType == LocationSettingType.EXPLICIT_INCORRECT && - getInitialSettings().getDistributionType() == DistributionType.LOCAL) { - new DelayedBalloonInfo(MessageType.ERROR, myGradleHomeSettingType, 0).run(); - } - } + myBuilder.reset(getProject(), getInitialSettings(), isDefaultModuleCreation); } - public void updateWrapperControls(@Nullable String linkedProjectPath, boolean isDefaultModuleCreation) { - if(StringUtil.isEmpty(linkedProjectPath) && !isDefaultModuleCreation) { - myUseLocalDistributionButton.setSelected(true); - myGradleHomePathField.setEnabled(true); - return; - } - - final boolean isGradleDefaultWrapperFilesExist = GradleUtil.isGradleDefaultWrapperFilesExist(linkedProjectPath); - if (isGradleDefaultWrapperFilesExist || isDefaultModuleCreation) { - myUseWrapperButton.setEnabled(true); - myUseWrapperButton.setSelected(true); - myGradleHomePathField.setEnabled(false); - myUseWrapperButton.setText(GradleBundle.message("gradle.settings.text.use.default_wrapper.configured")); - } else { - myUseWrapperButton.setEnabled(false); - myUseLocalDistributionButton.setSelected(true); - myGradleHomePathField.setEnabled(true); - myUseWrapperButton.setText(GradleBundle.message("gradle.settings.text.use.default_wrapper.not_configured")); - } - - if(getInitialSettings().getDistributionType() == null) { - return; - } - - switch (getInitialSettings().getDistributionType()) { - case LOCAL: - myGradleHomePathField.setEnabled(true); - myUseLocalDistributionButton.setSelected(true); - break; - case DEFAULT_WRAPPED: - myGradleHomePathField.setEnabled(false); - myUseWrapperButton.setSelected(true); - myUseWrapperButton.setEnabled(true); - break; - case WRAPPED: - myGradleHomePathField.setEnabled(false); - myUseWrapperWithVerificationButton.setSelected(true); - break; - case BUNDLED: - myGradleHomePathField.setEnabled(false); - myUseBundledDistributionButton.setSelected(true); - break; - } - } - - /** - * Updates GUI of the gradle configurable in order to show deduced path to gradle (if possible). - */ - private void deduceGradleHomeIfPossible() { - File gradleHome = myInstallationManager.getAutodetectedGradleHome(); - if (gradleHome == null) { - new DelayedBalloonInfo(MessageType.WARNING, LocationSettingType.UNKNOWN, BALLOON_DELAY_MILLIS).run(); - return; - } - myGradleHomeSettingType = LocationSettingType.DEDUCED; - new DelayedBalloonInfo(MessageType.INFO, LocationSettingType.DEDUCED, BALLOON_DELAY_MILLIS).run(); - myGradleHomePathField.setText(gradleHome.getPath()); - myGradleHomePathField.getTextField().setForeground(LocationSettingType.DEDUCED.getColor()); - } - - void showBalloonIfNecessary() { - if (!myShowBalloonIfNecessary || !myGradleHomePathField.isEnabled()) { - return; - } - myShowBalloonIfNecessary = false; - MessageType messageType = null; - switch (myGradleHomeSettingType) { - case DEDUCED: - messageType = MessageType.INFO; - break; - case EXPLICIT_INCORRECT: - case UNKNOWN: - messageType = MessageType.ERROR; - break; - default: - } - if (messageType != null) { - new DelayedBalloonInfo(messageType, myGradleHomeSettingType, BALLOON_DELAY_MILLIS).run(); - } + public void update(@Nullable String linkedProjectPath, boolean isDefaultModuleCreation) { + myBuilder.update(linkedProjectPath, getInitialSettings(), isDefaultModuleCreation); } /** @@ -421,47 +80,12 @@ public class GradleProjectSettingsControl extends AbstractExternalProjectSetting */ public void setCurrentProject(@Nullable Project project) { super.setCurrentProject(project); - resetGradleJdkComboBox(project); + myBuilder.reset(getProject(), getInitialSettings(), false); } - private void resetGradleJdkComboBox(@Nullable final Project project) { - final String gradleJvm = getInitialSettings().getGradleJvm(); - myGradleJdkComboBox.setProject(project); - - final String sdkItem = ObjectUtils.nullizeByCondition(gradleJvm, new Condition() { - @Override - public boolean value(String s) { - return (project == null && StringUtil.equals(USE_PROJECT_JDK, s)) || StringUtil.isEmpty(s); - } - }); - - myGradleJdkComboBox.refreshData(sdkItem); - } - - private class DelayedBalloonInfo implements Runnable { - private final MessageType myMessageType; - private final String myText; - private final long myTriggerTime; - - DelayedBalloonInfo(@NotNull MessageType messageType, @NotNull LocationSettingType settingType, long delayMillis) { - myMessageType = messageType; - myText = settingType.getDescription(GradleConstants.SYSTEM_ID); - myTriggerTime = System.currentTimeMillis() + delayMillis; - } - - @Override - public void run() { - long diff = myTriggerTime - System.currentTimeMillis(); - if (diff > 0) { - myAlarm.cancelAllRequests(); - myAlarm.addRequest(this, diff); - return; - } - if (myGradleHomePathField == null || !myGradleHomePathField.isShowing()) { - // Don't schedule the balloon if the configurable is hidden. - return; - } - ExternalSystemUiUtil.showBalloon(myGradleHomePathField, myMessageType, myText); - } + @Override + public void disposeUIResources() { + super.disposeUIResources(); + myBuilder.disposeUIResources(); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControlBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControlBuilder.java new file mode 100644 index 000000000000..cde018bbb636 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleProjectSettingsControlBuilder.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.gradle.service.settings; + +import com.intellij.openapi.externalSystem.service.settings.ExternalSystemSettingsControlCustomizer; +import com.intellij.openapi.externalSystem.util.PaintAwarePanel; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; + +/** + * @author Vladislav.Soroka + * @since 2/24/2015 + */ +public interface GradleProjectSettingsControlBuilder { + + GradleProjectSettings getInitialSettings(); + + IdeaGradleProjectSettingsControlBuilder addGradleHomeComponents(PaintAwarePanel content, int indentLevel); + + IdeaGradleProjectSettingsControlBuilder addGradleJdkComponents(PaintAwarePanel content, int indentLevel); + + IdeaGradleProjectSettingsControlBuilder addGradleChooserComponents(PaintAwarePanel content, int indentLevel); + + void disposeUIResources(); + + boolean validate(GradleProjectSettings settings) throws ConfigurationException; + + void apply(GradleProjectSettings settings); + + boolean isModified(GradleProjectSettings settings); + + void reset(Project project, GradleProjectSettings settings, boolean isDefaultModuleCreation); + + void createAndFillControls(PaintAwarePanel content, int indentLevel); + + void update(String linkedProjectPath, GradleProjectSettings settings, boolean isDefaultModuleCreation); + + @Nullable + ExternalSystemSettingsControlCustomizer getExternalSystemSettingsControlCustomizer(); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSettingsControlProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSettingsControlProvider.java new file mode 100644 index 000000000000..ce9cc90479ff --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSettingsControlProvider.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.gradle.service.settings; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ObjectUtils; +import com.intellij.util.PlatformUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; + +/** + * @author Vladislav.Soroka + * @since 2/24/2015 + */ +public abstract class GradleSettingsControlProvider { + + private static final ExtensionPointName EP_NAME = + ExtensionPointName.create("org.jetbrains.plugins.gradle.settingsControlProvider"); + + public abstract String getPlatformPrefix(); + + public abstract GradleProjectSettingsControlBuilder getProjectSettingsControlBuilder(@NotNull GradleProjectSettings initialSettings); + + @NotNull + public static GradleSettingsControlProvider get() { + GradleSettingsControlProvider result = null; + if (!PlatformUtils.isIntelliJ()) { + final String platformPrefix = PlatformUtils.getPlatformPrefix(); + for (GradleSettingsControlProvider provider : EP_NAME.getExtensions()) { + if (StringUtil.equals(platformPrefix, provider.getPlatformPrefix())) { + assert result == null : "Multiple GradleSettingsControlProvider extensions found"; + result = provider; + } + } + } + return ObjectUtils.notNull(result, new GradleSettingsControlProvider() { + @Override + public String getPlatformPrefix() { + return null; + } + + @Override + public GradleProjectSettingsControlBuilder getProjectSettingsControlBuilder(@NotNull GradleProjectSettings initialSettings) { + return new IdeaGradleProjectSettingsControlBuilder(initialSettings) + // Hide bundled distribution option for a while + .dropUseBundledDistributionButton(); + } + }); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/IdeaGradleProjectSettingsControlBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/IdeaGradleProjectSettingsControlBuilder.java new file mode 100644 index 000000000000..891ba0fd7f97 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/IdeaGradleProjectSettingsControlBuilder.java @@ -0,0 +1,604 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.gradle.service.settings; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.model.settings.LocationSettingType; +import com.intellij.openapi.externalSystem.service.settings.ExternalSystemSettingsControlCustomizer; +import com.intellij.openapi.externalSystem.service.ui.ExternalSystemJdkComboBox; +import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil; +import com.intellij.openapi.externalSystem.util.PaintAwarePanel; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.TextComponentAccessor; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBRadioButton; +import com.intellij.util.Alarm; +import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; +import com.intellij.util.ui.UIUtil; +import org.gradle.util.GradleVersion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.GradleInstallationManager; +import org.jetbrains.plugins.gradle.settings.DistributionType; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; +import org.jetbrains.plugins.gradle.util.GradleBundle; +import org.jetbrains.plugins.gradle.util.GradleConstants; +import org.jetbrains.plugins.gradle.util.GradleUtil; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.concurrent.TimeUnit; + +import static com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkUtil.USE_PROJECT_JDK; + +/** + * @author Vladislav.Soroka + * @since 2/24/2015 + */ +public class IdeaGradleProjectSettingsControlBuilder implements GradleProjectSettingsControlBuilder { + + private static final long BALLOON_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(1); + @NotNull + private final GradleInstallationManager myInstallationManager; + @NotNull + private final GradleProjectSettings myInitialSettings; + @NotNull + private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + @NotNull + private LocationSettingType myGradleHomeSettingType = LocationSettingType.UNKNOWN; + private boolean myShowBalloonIfNecessary; + private ActionListener myActionListener; + + + private boolean dropUseAutoImportBox; + private boolean dropCreateEmptyContentRootDirectoriesBox; + + @SuppressWarnings("FieldCanBeLocal") // Used implicitly by reflection at disposeUIResources() and showUi() + @Nullable + private JLabel myGradleHomeLabel; + @Nullable + private TextFieldWithBrowseButton myGradleHomePathField; + private boolean dropGradleHomePathComponents; + + @SuppressWarnings("FieldCanBeLocal") // Used implicitly by reflection at disposeUIResources() and showUi() + @Nullable + private JLabel myGradleJdkLabel; + @Nullable + private ExternalSystemJdkComboBox myGradleJdkComboBox; + private boolean dropGradleJdkComponents; + + @Nullable + private JBRadioButton myUseWrapperButton; + private boolean dropUseWrapperButton; + + @Nullable + private JBRadioButton myUseWrapperWithVerificationButton; + @SuppressWarnings("FieldCanBeLocal") // Used implicitly by reflection at disposeUIResources() and showUi() + @Nullable + private JBLabel myUseWrapperVerificationLabel; + private boolean dropCustomizableWrapperButton; + + @Nullable + private JBRadioButton myUseLocalDistributionButton; + private boolean dropUseLocalDistributionButton; + + @Nullable + private JBRadioButton myUseBundledDistributionButton; + private boolean dropUseBundledDistributionButton; + + public IdeaGradleProjectSettingsControlBuilder(@NotNull GradleProjectSettings initialSettings) { + myInstallationManager = ServiceManager.getService(GradleInstallationManager.class); + myInitialSettings = initialSettings; + + myActionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (myGradleHomePathField == null) return; + + boolean localDistributionEnabled = myUseLocalDistributionButton != null && myUseLocalDistributionButton.isSelected(); + myGradleHomePathField.setEnabled(localDistributionEnabled); + if (localDistributionEnabled) { + if (myGradleHomePathField.getText().isEmpty()) { + deduceGradleHomeIfPossible(); + } + else { + if (myInstallationManager.isGradleSdkHome(myGradleHomePathField.getText())) { + myGradleHomeSettingType = LocationSettingType.EXPLICIT_CORRECT; + } + else { + myGradleHomeSettingType = LocationSettingType.EXPLICIT_INCORRECT; + myShowBalloonIfNecessary = true; + } + } + showBalloonIfNecessary(); + } + else { + myAlarm.cancelAllRequests(); + } + } + }; + } + + public IdeaGradleProjectSettingsControlBuilder dropGradleJdkComponents() { + dropGradleJdkComponents = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropUseWrapperButton() { + dropUseWrapperButton = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropGradleHomePathComponents() { + dropGradleHomePathComponents = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropCustomizableWrapperButton() { + dropCustomizableWrapperButton = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropUseLocalDistributionButton() { + dropUseLocalDistributionButton = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropUseBundledDistributionButton() { + dropUseBundledDistributionButton = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropUseAutoImportBox() { + dropUseAutoImportBox = true; + return this; + } + + public IdeaGradleProjectSettingsControlBuilder dropCreateEmptyContentRootDirectoriesBox() { + dropCreateEmptyContentRootDirectoriesBox = true; + return this; + } + + @NotNull + public GradleProjectSettings getInitialSettings() { + return myInitialSettings; + } + + @Override + public ExternalSystemSettingsControlCustomizer getExternalSystemSettingsControlCustomizer() { + return new ExternalSystemSettingsControlCustomizer(dropUseAutoImportBox, dropCreateEmptyContentRootDirectoriesBox); + } + + @Override + public void createAndFillControls(PaintAwarePanel content, int indentLevel) { + content.setPaintCallback(new Consumer() { + @Override + public void consume(Graphics graphics) { + showBalloonIfNecessary(); + } + }); + + content.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (!"ancestor".equals(evt.getPropertyName())) { + return; + } + + // Configure the balloon to show on initial configurable drawing. + myShowBalloonIfNecessary = evt.getNewValue() != null && evt.getOldValue() == null; + + if (evt.getNewValue() == null && evt.getOldValue() != null) { + // Cancel delayed balloons when the configurable is hidden. + myAlarm.cancelAllRequests(); + } + } + }); + + addGradleChooserComponents(content, indentLevel); + addGradleHomeComponents(content, indentLevel); + addGradleJdkComponents(content, indentLevel); + } + + @Override + public void disposeUIResources() { + ExternalSystemUiUtil.disposeUi(this); + } + + /** + * Updates GUI of the gradle configurable in order to show deduced path to gradle (if possible). + */ + private void deduceGradleHomeIfPossible() { + if (myGradleHomePathField == null) return; + + File gradleHome = myInstallationManager.getAutodetectedGradleHome(); + if (gradleHome == null) { + new DelayedBalloonInfo(MessageType.WARNING, LocationSettingType.UNKNOWN, BALLOON_DELAY_MILLIS).run(); + return; + } + myGradleHomeSettingType = LocationSettingType.DEDUCED; + new DelayedBalloonInfo(MessageType.INFO, LocationSettingType.DEDUCED, BALLOON_DELAY_MILLIS).run(); + myGradleHomePathField.setText(gradleHome.getPath()); + myGradleHomePathField.getTextField().setForeground(LocationSettingType.DEDUCED.getColor()); + } + + @Override + public IdeaGradleProjectSettingsControlBuilder addGradleJdkComponents(PaintAwarePanel content, int indentLevel) { + if(!dropGradleJdkComponents) { + myGradleJdkLabel = new JBLabel(GradleBundle.message("gradle.settings.text.jvm.path")); + myGradleJdkComboBox = new ExternalSystemJdkComboBox().withoutJre(); + + content.add(myGradleJdkLabel, ExternalSystemUiUtil.getLabelConstraints(indentLevel)); + content.add(myGradleJdkComboBox, ExternalSystemUiUtil.getFillLineConstraints(0)); + } + return this; + } + + @Override + public IdeaGradleProjectSettingsControlBuilder addGradleChooserComponents(PaintAwarePanel content, int indentLevel) { + ButtonGroup buttonGroup = new ButtonGroup(); + + if(!dropUseWrapperButton) { + myUseWrapperButton = new JBRadioButton(GradleBundle.message("gradle.settings.text.use.default_wrapper.configured")); + myUseWrapperButton.addActionListener(myActionListener); + buttonGroup.add(myUseWrapperButton); + content.add(myUseWrapperButton, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); + } + + if(!dropCustomizableWrapperButton) { + myUseWrapperWithVerificationButton = new JBRadioButton(GradleBundle.message("gradle.settings.text.use.customizable_wrapper")); + myUseWrapperWithVerificationButton.addActionListener(myActionListener); + myUseWrapperVerificationLabel = new JBLabel(GradleBundle.message("gradle.settings.text.wrapper.customization.compatibility")); + myUseWrapperVerificationLabel.setFont(UIUtil.getLabelFont(UIUtil.FontSize.MINI)); + myUseWrapperVerificationLabel.setIcon(UIUtil.getBalloonInformationIcon()); + buttonGroup.add(myUseWrapperWithVerificationButton); + content.add(myUseWrapperWithVerificationButton, ExternalSystemUiUtil.getLabelConstraints(indentLevel)); + content.add(myUseWrapperVerificationLabel, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); + } + + if(!dropUseLocalDistributionButton) { + myUseLocalDistributionButton = new JBRadioButton(GradleBundle.message("gradle.settings.text.use.local.distribution")); + myUseLocalDistributionButton.addActionListener(myActionListener); + buttonGroup.add(myUseLocalDistributionButton); + content.add(myUseLocalDistributionButton, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); + } + + if(!dropUseBundledDistributionButton) { + myUseBundledDistributionButton = new JBRadioButton( + GradleBundle.message("gradle.settings.text.use.bundled.distribution", GradleVersion.current().getVersion())); + myUseBundledDistributionButton.addActionListener(myActionListener); + buttonGroup.add(myUseBundledDistributionButton); + //content.add(Box.createGlue(), ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); + content.add(myUseBundledDistributionButton, ExternalSystemUiUtil.getFillLineConstraints(indentLevel)); + } + + return this; + } + + @Override + public boolean validate(GradleProjectSettings settings) throws ConfigurationException { + if (myGradleHomePathField == null) return true; + + String gradleHomePath = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); + if (myUseLocalDistributionButton != null && myUseLocalDistributionButton.isSelected()) { + if (StringUtil.isEmpty(gradleHomePath)) { + myGradleHomeSettingType = LocationSettingType.UNKNOWN; + throw new ConfigurationException(GradleBundle.message("gradle.home.setting.type.explicit.empty", gradleHomePath)); + } + else if (!myInstallationManager.isGradleSdkHome(new File(gradleHomePath))) { + myGradleHomeSettingType = LocationSettingType.EXPLICIT_INCORRECT; + new DelayedBalloonInfo(MessageType.ERROR, myGradleHomeSettingType, 0).run(); + throw new ConfigurationException(GradleBundle.message("gradle.home.setting.type.explicit.incorrect", gradleHomePath)); + } + } + return true; + } + + @Override + public void apply(GradleProjectSettings settings) { + if (myGradleHomePathField != null) { + String gradleHomePath = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); + if (StringUtil.isEmpty(gradleHomePath)) { + settings.setGradleHome(null); + } + else { + settings.setGradleHome(gradleHomePath); + GradleUtil.storeLastUsedGradleHome(gradleHomePath); + } + } + + if (myGradleJdkComboBox != null) { + final String gradleJvm = FileUtil.toCanonicalPath(myGradleJdkComboBox.getSelectedValue()); + settings.setGradleJvm(StringUtil.isEmpty(gradleJvm) ? null : gradleJvm); + } + + if (myUseLocalDistributionButton != null && myUseLocalDistributionButton.isSelected()) { + settings.setDistributionType(DistributionType.LOCAL); + } + else if (myUseWrapperButton != null && myUseWrapperButton.isSelected()) { + settings.setDistributionType(DistributionType.DEFAULT_WRAPPED); + } + else if ((myUseWrapperWithVerificationButton != null && myUseWrapperWithVerificationButton.isSelected()) || + (myUseBundledDistributionButton != null && myUseBundledDistributionButton.isSelected())) { + settings.setDistributionType(DistributionType.WRAPPED); + } + } + + @Override + public boolean isModified(GradleProjectSettings settings) { + DistributionType distributionType = settings.getDistributionType(); + if (myUseBundledDistributionButton != null && + myUseBundledDistributionButton.isSelected() && + distributionType != DistributionType.BUNDLED) { + return true; + } + + if (myUseWrapperButton != null && myUseWrapperButton.isSelected() && distributionType != DistributionType.DEFAULT_WRAPPED) { + return true; + } + + if (myUseWrapperWithVerificationButton != null && + myUseWrapperWithVerificationButton.isSelected() && + distributionType != DistributionType.WRAPPED) { + return true; + } + + if (myUseLocalDistributionButton != null && myUseLocalDistributionButton.isSelected() && distributionType != DistributionType.LOCAL) { + return true; + } + + if (myGradleJdkComboBox != null && !StringUtil.equals(myGradleJdkComboBox.getSelectedValue(), settings.getGradleJvm())) { + return true; + } + + if (myGradleHomePathField == null) return false; + String gradleHome = FileUtil.toCanonicalPath(myGradleHomePathField.getText()); + if (StringUtil.isEmpty(gradleHome)) { + return !StringUtil.isEmpty(settings.getGradleHome()); + } + else { + return !gradleHome.equals(settings.getGradleHome()); + } + } + + @Override + public void reset(Project project, GradleProjectSettings settings, boolean isDefaultModuleCreation) { + String gradleHome = settings.getGradleHome(); + if (myGradleHomePathField != null) { + myGradleHomePathField.setText(gradleHome == null ? "" : gradleHome); + myGradleHomePathField.getTextField().setForeground(LocationSettingType.EXPLICIT_CORRECT.getColor()); + } + + resetGradleJdkComboBox(project, settings); + resetWrapperControls(settings.getExternalProjectPath(), settings, isDefaultModuleCreation); + + if (myUseLocalDistributionButton != null && !myUseLocalDistributionButton.isSelected()) { + myGradleHomePathField.setEnabled(false); + return; + } + + if (StringUtil.isEmpty(gradleHome)) { + myGradleHomeSettingType = LocationSettingType.UNKNOWN; + deduceGradleHomeIfPossible(); + } + else { + myGradleHomeSettingType = myInstallationManager.isGradleSdkHome(new File(gradleHome)) ? + LocationSettingType.EXPLICIT_CORRECT : + LocationSettingType.EXPLICIT_INCORRECT; + myAlarm.cancelAllRequests(); + if (myGradleHomeSettingType == LocationSettingType.EXPLICIT_INCORRECT && + settings.getDistributionType() == DistributionType.LOCAL) { + new DelayedBalloonInfo(MessageType.ERROR, myGradleHomeSettingType, 0).run(); + } + } + } + + @Override + public void update(String linkedProjectPath, GradleProjectSettings settings, boolean isDefaultModuleCreation) { + resetWrapperControls(linkedProjectPath, settings, isDefaultModuleCreation); + } + + @Override + public IdeaGradleProjectSettingsControlBuilder addGradleHomeComponents(PaintAwarePanel content, int indentLevel) { + if(dropGradleHomePathComponents) return this; + + myGradleHomeLabel = new JBLabel(GradleBundle.message("gradle.settings.text.home.path")); + myGradleHomePathField = new TextFieldWithBrowseButton(); + + myGradleHomePathField.addBrowseFolderListener( + "", + GradleBundle.message("gradle.settings.text.home.path"), + null, + GradleUtil.getGradleHomeFileChooserDescriptor(), + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT, + false + ); + myGradleHomePathField.getTextField().getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + myGradleHomePathField.getTextField().setForeground(LocationSettingType.EXPLICIT_CORRECT.getColor()); + } + + @Override + public void removeUpdate(DocumentEvent e) { + myGradleHomePathField.getTextField().setForeground(LocationSettingType.EXPLICIT_CORRECT.getColor()); + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + }); + + content.add(myGradleHomeLabel, ExternalSystemUiUtil.getLabelConstraints(indentLevel)); + content.add(myGradleHomePathField, ExternalSystemUiUtil.getFillLineConstraints(0)); + + return this; + } + + private void resetGradleJdkComboBox(@Nullable final Project project, GradleProjectSettings settings) { + if (myGradleJdkComboBox == null) return; + + final String gradleJvm = settings.getGradleJvm(); + myGradleJdkComboBox.setProject(project); + + final String sdkItem = ObjectUtils.nullizeByCondition(gradleJvm, new Condition() { + @Override + public boolean value(String s) { + return (project == null && StringUtil.equals(USE_PROJECT_JDK, s)) || StringUtil.isEmpty(s); + } + }); + + myGradleJdkComboBox.refreshData(sdkItem); + } + + private void resetWrapperControls(String linkedProjectPath, @NotNull GradleProjectSettings settings, boolean isDefaultModuleCreation) { + if (StringUtil.isEmpty(linkedProjectPath) && !isDefaultModuleCreation) { + if (myUseLocalDistributionButton != null) { + myUseLocalDistributionButton.setSelected(true); + } + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(true); + } + return; + } + + final boolean isGradleDefaultWrapperFilesExist = GradleUtil.isGradleDefaultWrapperFilesExist(linkedProjectPath); + if (myUseWrapperButton != null && (isGradleDefaultWrapperFilesExist || isDefaultModuleCreation)) { + myUseWrapperButton.setEnabled(true); + myUseWrapperButton.setSelected(true); + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(false); + } + myUseWrapperButton.setText(GradleBundle.message("gradle.settings.text.use.default_wrapper.configured")); + } + else { + if (myUseWrapperButton != null) { + myUseWrapperButton.setEnabled(false); + myUseWrapperButton.setText(GradleBundle.message("gradle.settings.text.use.default_wrapper.not_configured")); + } + if (myUseLocalDistributionButton != null) { + myUseLocalDistributionButton.setSelected(true); + } + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(true); + } + } + + if (settings.getDistributionType() == null) { + return; + } + + switch (settings.getDistributionType()) { + case LOCAL: + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(true); + } + if (myUseLocalDistributionButton != null) { + myUseLocalDistributionButton.setSelected(true); + } + break; + case DEFAULT_WRAPPED: + if (isGradleDefaultWrapperFilesExist) { + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(false); + } + if (myUseWrapperButton != null) { + myUseWrapperButton.setSelected(true); + myUseWrapperButton.setEnabled(true); + } + } + break; + case WRAPPED: + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(false); + } + if (myUseWrapperWithVerificationButton != null) { + myUseWrapperWithVerificationButton.setSelected(true); + } + break; + case BUNDLED: + if (myGradleHomePathField != null) { + myGradleHomePathField.setEnabled(false); + } + if (myUseBundledDistributionButton != null) { + myUseBundledDistributionButton.setSelected(true); + } + break; + } + } + + void showBalloonIfNecessary() { + if (!myShowBalloonIfNecessary || (myGradleHomePathField != null && !myGradleHomePathField.isEnabled())) { + return; + } + myShowBalloonIfNecessary = false; + MessageType messageType = null; + switch (myGradleHomeSettingType) { + case DEDUCED: + messageType = MessageType.INFO; + break; + case EXPLICIT_INCORRECT: + case UNKNOWN: + messageType = MessageType.ERROR; + break; + default: + } + if (messageType != null) { + new DelayedBalloonInfo(messageType, myGradleHomeSettingType, BALLOON_DELAY_MILLIS).run(); + } + } + + private class DelayedBalloonInfo implements Runnable { + private final MessageType myMessageType; + private final String myText; + private final long myTriggerTime; + + DelayedBalloonInfo(@NotNull MessageType messageType, @NotNull LocationSettingType settingType, long delayMillis) { + myMessageType = messageType; + myText = settingType.getDescription(GradleConstants.SYSTEM_ID); + myTriggerTime = System.currentTimeMillis() + delayMillis; + } + + @Override + public void run() { + long diff = myTriggerTime - System.currentTimeMillis(); + if (diff > 0) { + myAlarm.cancelAllRequests(); + myAlarm.addRequest(this, diff); + return; + } + if (myGradleHomePathField == null || !myGradleHomePathField.isShowing()) { + // Don't schedule the balloon if the configurable is hidden. + return; + } + ExternalSystemUiUtil.showBalloon(myGradleHomePathField, myMessageType, myText); + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java index 605cd3667fe3..7bfad346e353 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/ImportFromGradleControl.java @@ -52,9 +52,7 @@ public class ImportFromGradleControl @NotNull @Override protected ExternalSystemSettingsControl createProjectSettingsControl(@NotNull GradleProjectSettings settings) { - GradleProjectSettingsControl settingsControl = new GradleProjectSettingsControl(settings); - settingsControl.hideUseAutoImportBox(); - return settingsControl; + return new GradleProjectSettingsControl(settings); } @Nullable @@ -65,7 +63,7 @@ public class ImportFromGradleControl @Override protected void onLinkedProjectPathChange(@NotNull String path) { - ((GradleProjectSettingsControl)getProjectSettingsControl()).updateWrapperControls(path, false); + ((GradleProjectSettingsControl)getProjectSettingsControl()).update(path, false); } @Override diff --git a/plugins/java-i18n/src/META-INF/plugin.xml b/plugins/java-i18n/src/META-INF/plugin.xml index c3e2c5aab225..9d4fc9a8f356 100644 --- a/plugins/java-i18n/src/META-INF/plugin.xml +++ b/plugins/java-i18n/src/META-INF/plugin.xml @@ -54,6 +54,12 @@ enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.capitalization.TitleCapitalizationInspection"/> + com.intellij.codeInspection.capitalization.AnnotateCapitalizationIntention diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/SuspiciousLocalesLanguagesInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/SuspiciousLocalesLanguagesInspection.java new file mode 100644 index 000000000000..1dc726b8a2ee --- /dev/null +++ b/plugins/java-i18n/src/com/intellij/codeInspection/SuspiciousLocalesLanguagesInspection.java @@ -0,0 +1,237 @@ +/* + * Copyright 2000-2015 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.codeInspection; + +import com.intellij.codeInspection.ex.BaseLocalInspectionTool; +import com.intellij.lang.properties.*; +import com.intellij.lang.properties.ResourceBundle; +import com.intellij.lang.properties.customizeActions.DissociateResourceBundleAction; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidator; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiFile; +import com.intellij.reference.SoftLazyValue; +import com.intellij.ui.AnActionButton; +import com.intellij.ui.AnActionButtonRunnable; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.components.JBList; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; +import org.jdom.Element; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import javax.swing.*; +import java.awt.*; +import java.util.*; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class SuspiciousLocalesLanguagesInspection extends BaseLocalInspectionTool { + private static final String ADDITIONAL_LANGUAGES_ATTR_NAME = "additionalLanguages"; + private final static SoftLazyValue> JAVA_LOCALES = new SoftLazyValue>() { + @NotNull + @Override + protected Set compute() { + final Set result = new HashSet(); + for (Locale locale : Locale.getAvailableLocales()) { + result.add(locale.getLanguage()); + } + return result; + } + }; + + private final List myAdditionalLanguages = new ArrayList(); + + @Nls + @NotNull + @Override + public String getDisplayName() { + return "Suspicious resource bundle locale languages"; + } + + @TestOnly + public void setAdditionalLanguages(List additionalLanguages) { + myAdditionalLanguages.clear(); + myAdditionalLanguages.addAll(additionalLanguages); + } + + @Override + public void readSettings(@NotNull Element node) throws InvalidDataException { + final String rawLanguages = node.getAttributeValue(ADDITIONAL_LANGUAGES_ATTR_NAME); + if (rawLanguages != null) { + myAdditionalLanguages.clear(); + myAdditionalLanguages.addAll(StringUtil.split(rawLanguages, ",")); + } + } + + @Override + public void writeSettings(@NotNull Element node) throws WriteExternalException { + if (!myAdditionalLanguages.isEmpty()) { + final ArrayList uniqueLanguages = ContainerUtil.newArrayList(ContainerUtil.newHashSet(myAdditionalLanguages)); + Collections.sort(uniqueLanguages); + final String locales = StringUtil.join(uniqueLanguages, ","); + node.setAttribute(ADDITIONAL_LANGUAGES_ATTR_NAME, locales); + } + } + + @Nullable + @Override + public JComponent createOptionsPanel() { + return new MyOptions().getComponent(); + } + + @Nullable + @Override + public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) { + final PropertiesFile propertiesFile = PropertiesImplUtil.getPropertiesFile(file); + if (propertiesFile == null) { + return null; + } + final ResourceBundle resourceBundle = propertiesFile.getResourceBundle(); + final List files = resourceBundle.getPropertiesFiles(); + if (!(resourceBundle instanceof ResourceBundleImpl) || files.size() < 2) { + return null; + } + List bundleLocales = ContainerUtil.mapNotNull(files, new Function() { + @Override + public Locale fun(PropertiesFile propertiesFile) { + final Locale locale = propertiesFile.getLocale(); + return locale == ResourceBundleManager.DEFAULT_LOCALE ? null : locale; + } + }); + bundleLocales = ContainerUtil.filter(bundleLocales, new Condition() { + @Override + public boolean value(Locale locale) { + return !JAVA_LOCALES.getValue().contains(locale.getLanguage()) && !myAdditionalLanguages.contains(locale.getLanguage()); + } + }); + if (bundleLocales.isEmpty()) { + return null; + } + final ProblemDescriptor descriptor = manager.createProblemDescriptor(file, + PropertiesBundle.message( + "resource.bundle.contains.locales.with.suspicious.locale.languages.desciptor"), + new DissociateResourceBundleQuickFix(resourceBundle), + ProblemHighlightType.WEAK_WARNING, + true); + return new ProblemDescriptor[] {descriptor}; + } + + private static class DissociateResourceBundleQuickFix implements LocalQuickFix { + private final ResourceBundle myResourceBundle; + + private DissociateResourceBundleQuickFix(ResourceBundle bundle) { + myResourceBundle = bundle; + } + + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return PropertiesBundle.message("dissociate.resource.bundle.quick.fix.name"); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + DissociateResourceBundleAction.dissociate(Collections.singleton(myResourceBundle), project); + } + } + + private class MyOptions { + private JBList myAdditionalLocalesList; + + public MyOptions() { + myAdditionalLocalesList = new JBList(new MyListModel()); + myAdditionalLocalesList.setCellRenderer(new DefaultListCellRenderer()); + } + + public JPanel getComponent() { + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(new JLabel(PropertiesBundle.message("dissociate.resource.bundle.quick.fix.options.label")), BorderLayout.NORTH); + panel.add( + ToolbarDecorator.createDecorator(myAdditionalLocalesList) + .setAddAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + Messages.showInputDialog(panel, PropertiesBundle.message("dissociate.resource.bundle.quick.fix.options.input.text"), + PropertiesBundle.message("dissociate.resource.bundle.quick.fix.options.input.title"), null, "", new InputValidator() { + @Override + public boolean checkInput(String inputString) { + return 1 < inputString.length() && inputString.length() < 9 && !myAdditionalLanguages.contains(inputString); + } + + @Override + public boolean canClose(String inputString) { + if (inputString != null) { + myAdditionalLanguages.add(inputString); + ((MyListModel)myAdditionalLocalesList.getModel()).fireContentsChanged(); + } + return true; + } + }); + } + }) + .setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + final int index = myAdditionalLocalesList.getSelectedIndex(); + if (index > -1 && index < myAdditionalLanguages.size()) { + myAdditionalLanguages.remove(index); + ((MyListModel)myAdditionalLocalesList.getModel()).fireContentsChanged(); + } + } + }) + .setPreferredSize(new Dimension(-1, 100)) + .disableUpDownActions() + .createPanel(), + BorderLayout.CENTER); + return panel; + } + + private class MyListModel extends AbstractListModel { + @Override + public int getSize() { + return myAdditionalLanguages.size(); + } + + @Override + public Object getElementAt(int index) { + return myAdditionalLanguages.get(index); + } + + public void fireContentsChanged() { + fireContentsChanged(myAdditionalLanguages, -1, -1); + } + } + } +} diff --git a/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple1/p.properties b/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple1/p.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple1/p_en.properties b/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple1/p_en.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple2/p.properties b/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple2/p.properties new file mode 100644 index 000000000000..cb17b36e6685 --- /dev/null +++ b/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple2/p.properties @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple2/p_asd.properties b/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple2/p_asd.properties new file mode 100644 index 000000000000..cb17b36e6685 --- /dev/null +++ b/plugins/java-i18n/testData/inspections/suspiciousLanguages/simple2/p_asd.properties @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/java-i18n/testData/inspections/suspiciousLanguages/withAdditionalLocales/p.properties b/plugins/java-i18n/testData/inspections/suspiciousLanguages/withAdditionalLocales/p.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/java-i18n/testData/inspections/suspiciousLanguages/withAdditionalLocales/p_asd.properties b/plugins/java-i18n/testData/inspections/suspiciousLanguages/withAdditionalLocales/p_asd.properties new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/java-i18n/testSrc/com/intellij/codeInspection/SuspiciousLanguagesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/codeInspection/SuspiciousLanguagesInspectionTest.java new file mode 100644 index 000000000000..891b8fcffe34 --- /dev/null +++ b/plugins/java-i18n/testSrc/com/intellij/codeInspection/SuspiciousLanguagesInspectionTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2015 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.codeInspection; + +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.intellij.util.containers.ContainerUtil; + +import java.io.File; + +/** + * @author Dmitry Batkovich + */ +public class SuspiciousLanguagesInspectionTest extends LightCodeInsightFixtureTestCase { + @Override + protected String getBasePath() { + return PluginPathManager.getPluginHomePathRelative("java-i18n") + "/testData/inspections/suspiciousLanguages"; + } + + public void testSimple1() { + doTest("p.properties", "p_en.properties"); + } + + public void testSimple2() { + doTest("p.properties", "p_asd.properties"); + } + + public void testWithAdditionalLocales() { + doTest("p.properties", "p_asd.properties", "asd"); + } + + private void doTest(final String file1, final String file2, final String... additionalLocales) { + myFixture.configureByFile(getTestName(true) + "/" + file1); + myFixture.configureByFile(getTestName(true) + "/" + file2); + final SuspiciousLocalesLanguagesInspection inspection = new SuspiciousLocalesLanguagesInspection(); + if (additionalLocales.length != 0) { + inspection.setAdditionalLanguages(ContainerUtil.newArrayList(additionalLocales)); + } + myFixture.enableInspections(inspection); + myFixture.checkHighlighting(); + } +} diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java index 3fba1a3d9b7a..dae5c95b0241 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java @@ -41,6 +41,10 @@ public class JUnit4IdeaTestRunner implements IdeaTestRunner { final Runner testRunner = request.getRunner(); try { Description description = testRunner.getDescription(); + if (description == null) { + System.err.println("Nothing found to run. Runner " + testRunner.getClass().getName() + " provides no description."); + return -1; + } if (request instanceof ClassRequest) { description = getSuiteMethodDescription(request, description); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenSchemaProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenSchemaProvider.java index 26df2720e259..f3bcf765e5f5 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenSchemaProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenSchemaProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,7 +19,7 @@ import com.intellij.javaee.ExternalResourceManager; import com.intellij.javaee.ExternalResourceManagerEx; import com.intellij.javaee.ResourceRegistrar; import com.intellij.javaee.StandardResourceProvider; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -28,6 +28,7 @@ public class MavenSchemaProvider implements StandardResourceProvider { public static final String MAVEN_PROFILES_SCHEMA_URL = "http://maven.apache.org/xsd/profiles-1.0.0.xsd"; public static final String MAVEN_SETTINGS_SCHEMA_URL = "http://maven.apache.org/xsd/settings-1.0.0.xsd"; + @Override public void registerResources(ResourceRegistrar registrar) { registrar.addStdResource("http://maven.apache.org/maven-v4_0_0.xsd", "/schemas/maven-4.0.0.xsd", getClass()); registrar.addStdResource(MAVEN_PROJECT_SCHEMA_URL, "/schemas/maven-4.0.0.xsd", getClass()); @@ -41,7 +42,7 @@ public class MavenSchemaProvider implements StandardResourceProvider { String location = ((ExternalResourceManagerEx)ExternalResourceManager.getInstance()).getStdResource(url, null); assert location != null : "cannot find a standard resource for " + url; - VirtualFile result = VfsUtil.findRelativeFile(location, null); + VirtualFile result = VfsUtilCore.findRelativeFile(location, null); assert result != null : "cannot find a schema file for URL: " + url + " location: " + location; return result; diff --git a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties index aefabc574b38..1a58d5b832a4 100644 --- a/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties +++ b/plugins/properties/properties-psi-api/resources/messages/PropertiesBundle.properties @@ -60,3 +60,9 @@ inline.property.confirmation=Inline property ''{0}'' with value ''{1}''? alpha.unsorted.properties.file.inspection.display.name=Properties File or Resource Bundle is Alphabetically Unsorted trailing.spaces.in.property.inspection.ignore.visible.spaces=Ignore visible whitespaces + +resource.bundle.contains.locales.with.suspicious.locale.languages.desciptor=Resource bundle contains locales with suspicious locale languages +dissociate.resource.bundle.quick.fix.name=Dissociate Resource Bundle +dissociate.resource.bundle.quick.fix.options.label=Additional language codes\: +dissociate.resource.bundle.quick.fix.options.input.text=Inter language code +dissociate.resource.bundle.quick.fix.options.input.title=Additional Locale Languages diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java index 5d8487d468a2..626961e8b9f2 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleManager.java @@ -47,7 +47,7 @@ import java.util.regex.Matcher; }) public class ResourceBundleManager implements PersistentStateComponent { private final static Logger LOG = Logger.getInstance(ResourceBundleManager.class); - private final static Locale DEFAULT_LOCALE = new Locale("", "", ""); + public final static Locale DEFAULT_LOCALE = new Locale("", "", ""); private ResourceBundleManagerState myState = new ResourceBundleManagerState(); @@ -172,7 +172,11 @@ public class ResourceBundleManager implements PersistentStateComponent resourceBundles = extractResourceBundles(e); assert resourceBundles.size() > 0; - final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); - for (ResourceBundle resourceBundle : resourceBundles) { - fileEditorManager.closeFile(new ResourceBundleAsVirtualFile(resourceBundle)); - for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { - fileEditorManager.closeFile(propertiesFile.getVirtualFile()); - } - ResourceBundleManager.getInstance(e.getProject()).dissociateResourceBundle(resourceBundle); - } - ProjectView.getInstance(project).refresh(); + dissociate(resourceBundles, project); } @Override @@ -79,6 +76,32 @@ public class DissociateResourceBundleAction extends AnAction { } } + public static void dissociate(final Collection resourceBundles, final Project project) { + final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); + final Set toUpdateInProjectView = new HashSet(); + for (ResourceBundle resourceBundle : resourceBundles) { + fileEditorManager.closeFile(new ResourceBundleAsVirtualFile(resourceBundle)); + for (final PropertiesFile propertiesFile : resourceBundle.getPropertiesFiles()) { + fileEditorManager.closeFile(propertiesFile.getVirtualFile()); + PsiDirectory containingDirectory = propertiesFile.getContainingFile().getContainingDirectory(); + if (containingDirectory != null) { + toUpdateInProjectView.add(containingDirectory); + } + } + ResourceBundleManager.getInstance(project).dissociateResourceBundle(resourceBundle); + } + AbstractProjectViewPane currentProjectViewPane = ProjectView.getInstance(project).getCurrentProjectViewPane(); + if (currentProjectViewPane == null) { + return; + } + AbstractTreeBuilder treeBuilder = currentProjectViewPane.getTreeBuilder(); + if (treeBuilder != null) { + for (PsiFileSystemItem item : toUpdateInProjectView) { + treeBuilder.queueUpdateFrom(item, false); + } + } + } + @NotNull private static Collection extractResourceBundles(final AnActionEvent event) { final Set targetResourceBundles = new HashSet(); diff --git a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java index b9f61643095d..20af8439004c 100644 --- a/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java +++ b/plugins/properties/src/com/intellij/lang/properties/projectView/ResourceBundleNode.java @@ -32,6 +32,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; @@ -97,4 +98,12 @@ public class ResourceBundleNode extends ProjectViewNode{ public Comparable getTypeSortKey() { return new PsiFileNode.ExtensionSortKey(StdFileTypes.PROPERTIES.getDefaultExtension()); } + + @Override + public boolean validate() { + if (!super.validate()) { + return false; + } + return Comparing.equal(getValue().getDefaultPropertiesFile().getResourceBundle(), getValue()); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnPhantomChangeDiffRequestProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnPhantomChangeDiffRequestProvider.java index 99d2aca68ca5..3dd4744fc179 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnPhantomChangeDiffRequestProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnPhantomChangeDiffRequestProvider.java @@ -57,7 +57,7 @@ public class SvnPhantomChangeDiffRequestProvider implements ChangeDiffRequestPro @NotNull @Override public String getName() { - return "SVN Phantom Changes Viewer"; + return "SVN phantom changes viewer"; } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnTreeConflictDiffRequestProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnTreeConflictDiffRequestProvider.java index ed5245c639dc..35562e795f06 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnTreeConflictDiffRequestProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnTreeConflictDiffRequestProvider.java @@ -73,7 +73,7 @@ public class SvnTreeConflictDiffRequestProvider implements ChangeDiffRequestProv @NotNull @Override public String getName() { - return "SVN Phantom Changes Viewer"; + return "SVN tree conflict viewer"; } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/properties/SvnPropertiesDiffTool.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/properties/SvnPropertiesDiffTool.java index 5f599aa4b55b..bf95f8694bd4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/properties/SvnPropertiesDiffTool.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/properties/SvnPropertiesDiffTool.java @@ -9,7 +9,7 @@ public class SvnPropertiesDiffTool implements FrameDiffTool { @NotNull @Override public String getName() { - return "Svn Properties Viewer"; + return "SVN properties viewer"; } @Override diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/CustomTaskState.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/CustomTaskState.java new file mode 100644 index 000000000000..d875b3049281 --- /dev/null +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/CustomTaskState.java @@ -0,0 +1,130 @@ +package com.intellij.tasks; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Mikhail Golubev + */ +public class CustomTaskState { + private String myId; + private String myPresentableName; + private boolean myPredefined; + + /** + * For serialization purposes only. + */ + public CustomTaskState() { + } + + public CustomTaskState(@NotNull String id, @NotNull String name) { + myId = id; + myPresentableName = name; + } + + /** + * Unique ID (e.g. number or unique name) of this state that can be used later to update state of an issue + * in {@link TaskRepository#setTaskState(Task, CustomTaskState)}. + * + * @see TaskRepository#setTaskState(Task, CustomTaskState) + */ + @NotNull + public String getId() { + return myId; + } + + /** + * For serialization purposes only. + */ + public void setId(String id) { + myId = id; + } + + /** + * Text that describes this state and will be shown to user in UI (unlike ID it's not necessarily unique). + */ + @NotNull + public String getPresentableName() { + return myPresentableName; + } + + /** + * For serialization purposes only. + */ + public void setPresentableName(@NotNull String name) { + myPresentableName = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CustomTaskState)) return false; + + final CustomTaskState state = (CustomTaskState)o; + + return myId.equals(state.myId); + } + + @Override + public int hashCode() { + return myId.hashCode(); + } + + /** + * Creates custom state for which ID is identical to {@link TaskState#name} of the given predefined state and {@link #isPredefined()} + * returns true. If your repository provides only fixed set of available states, that are one of those described in {@link TaskState}, + * you may find this methods useful to implement {@link TaskRepository#getAvailableTaskStates(Task)}. + * + * @return custom task state that represents given predefined state + * @see #asPredefined() + * @see #isPredefined() + * @see TaskRepository#getAvailableTaskStates(Task) + */ + @NotNull + public static CustomTaskState fromPredefined(@NotNull TaskState state) { + final CustomTaskState result = new CustomTaskState(state.name(), state.getPresentableName()); + result.setPredefined(true); + return result; + } + + /** + * Returns corresponding value of {@link TaskState} that has the same name as ID of this state. + * It's intended to be used for custom states created using {@link #fromPredefined}. + * + * @return predefined task state as described or {@code null} if such state doesn't exists or {@link #isPredefined()} returns false + * @see #isPredefined() + */ + @Nullable + public TaskState asPredefined() { + if (isPredefined()) { + try { + return TaskState.valueOf(getId()); + } + catch (IllegalArgumentException ignored) { + } + } + return null; + } + + /** + * Means that this custom state can be directly mapped to legacy {@link TaskState}. If it's false, {@link #asPredefined()} returns {@code null}. + * It's intended to be used mainly for compatibility with existing repositories. + * + * @see #asPredefined() + */ + private boolean isPredefined() { + return myPredefined; + } + + /** + * For serialization purposes only. + */ + public void setPredefined(boolean predefined) { + myPredefined = predefined; + } + + @Override + public String toString() { + return "CustomTaskState(id='" + myId + '\'' + ", name='" + myPresentableName + '\'' + ", predefined=" + myPredefined + ')'; + } +} diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java index 416a7158eb26..c6e270fdef4e 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java @@ -18,6 +18,10 @@ package com.intellij.tasks; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.impl.CancellableRunnable; +import com.intellij.tasks.impl.BaseRepository; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Tag; import com.intellij.util.xmlb.annotations.Transient; @@ -26,6 +30,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Set; import java.util.concurrent.Callable; /** @@ -34,7 +39,7 @@ import java.util.concurrent.Callable; * * @author Dmitry Avdeev * @see TaskRepositoryType - * @see com.intellij.tasks.impl.BaseRepository + * @see BaseRepository */ @Tag("server") public abstract class TaskRepository { @@ -109,7 +114,7 @@ public abstract class TaskRepository { /** * Returns an object that can test connection. - * {@link com.intellij.openapi.vcs.impl.CancellableRunnable#cancel()} should cancel the process. + * {@link CancellableRunnable#cancel()} should cancel the process. * * @return null if not supported */ @@ -164,6 +169,48 @@ public abstract class TaskRepository { return getIssues(query, offset, limit, withClosed); } + /** + * Retrieve states available for task from server. One of these states will be passed later to {@link #setTaskState(Task, TaskState)}. + * @param task task to update + * @return set of available states + */ + @NotNull + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + //noinspection unchecked + return ContainerUtil.map2Set(getRepositoryType().getPossibleTaskStates(), new Function() { + @Override + public CustomTaskState fun(TaskState state) { + return CustomTaskState.fromPredefined(state); + } + }); + } + + /** + * Remember state used when opening task most recently. + * @param state preferred task state + */ + public abstract void setPreferredOpenTaskState(@Nullable CustomTaskState state); + + /** + * Task state that was used last time when opening task. + * @return preferred task state + */ + @Nullable + public abstract CustomTaskState getPreferredOpenTaskState(); + + /** + * Remember state used when closing task most recently. + * @param state preferred task state + */ + public abstract void setPreferredCloseTaskState(@Nullable CustomTaskState state); + + /** + * Task state that was used last time when closing task. + * @return preferred task state + */ + @Nullable + public abstract CustomTaskState getPreferredCloseTaskState(); + /** * @param id task ID. Don't forget to define {@link #extractId(String)}, if your server uses not PROJECT-123 format for task IDs. * @return found task or {@code null} otherwise. Basically you should return {@code null} on e.g. 404 error and throw exception with @@ -179,19 +226,39 @@ public abstract class TaskRepository { @Nullable public abstract String extractId(@NotNull String taskName); + /** - * Update state of the task on server. Don't forget to add {@link #STATE_UPDATING} in {@link #getFeatures()} and - * supported states in {@link TaskRepositoryType#getPossibleTaskStates()}. - * - * @param task issue to update - * @param state new state of the issue - * @see com.intellij.tasks.TaskRepositoryType#getPossibleTaskStates() - * @see com.intellij.tasks.TaskRepository#getFeatures() + * @deprecated Use {@link #setTaskState(Task, CustomTaskState)} instead. */ + @Deprecated public void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception { throw new UnsupportedOperationException("Setting task to state " + state + " is not supported"); } + /** + * Update state of the task on server. It's guaranteed that only issues returned by {@link #getAvailableTaskStates(Task)} + * will be passed here. + *

+ * Don't forget to add {@link #STATE_UPDATING} in {@link #getFeatures()} and supported states in {@link #getAvailableTaskStates(Task)}. + * + * @param task issue to update + * @param state new state of the issue + * @see TaskRepositoryType#getPossibleTaskStates() + * @see TaskRepository#getFeatures() + */ + public void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception { + TaskState predefinedState = null; + try { + predefinedState = TaskState.valueOf(state.getId()); + } + catch (IllegalArgumentException ignored) { + } + if (predefinedState != null) { + setTaskState(task, predefinedState); + } + } + + // for serialization public TaskRepository() { myType = null; diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepositoryType.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepositoryType.java index f348f4264c22..d4575cf3eb92 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepositoryType.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepositoryType.java @@ -67,8 +67,10 @@ public abstract class TaskRepositoryType implements Ta public abstract Class getRepositoryClass(); /** - * @return states that can be set by {@link TaskRepository#setTaskState(Task, TaskState)} + * @return states that can be set by {@link TaskRepository#setTaskState(Task, CustomTaskState)} + * @deprecated Use {@link TaskRepository#getAvailableTaskStates(Task)} instead. */ + @Deprecated public EnumSet getPossibleTaskStates() { return EnumSet.noneOf(TaskState.class); } diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskState.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskState.java index c0c0a2628b9d..79c504a44a60 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskState.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskState.java @@ -15,16 +15,30 @@ */ package com.intellij.tasks; +import org.jetbrains.annotations.NotNull; + /** + * Predefined common task states were used before {@link CustomTaskState} was introduced. + * * @author Dmitry Avdeev */ public enum TaskState { + SUBMITTED("Submitted"), + OPEN("Open"), + IN_PROGRESS("In Progress"), + REOPENED("Reopened"), + RESOLVED("Resolved"), - SUBMITTED, - OPEN, - IN_PROGRESS, - REOPENED, - RESOLVED, + OTHER("Other"); - OTHER + private String myPresentableName; + + TaskState(@NotNull String presentableName) { + myPresentableName = presentableName; + } + + @NotNull + public String getPresentableName() { + return myPresentableName; + } } diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepository.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepository.java index 8423736c8c10..0f67d4bae909 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepository.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepository.java @@ -18,6 +18,7 @@ package com.intellij.tasks.impl; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.PasswordUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.TaskRepository; import com.intellij.tasks.TaskRepositoryType; import com.intellij.util.xmlb.annotations.Tag; @@ -40,6 +41,8 @@ public abstract class BaseRepository extends TaskRepository { protected boolean myUseProxy; protected boolean myUseHttpAuthentication; protected boolean myLoginAnonymously; + protected CustomTaskState myPreferredOpenTaskState; + private CustomTaskState myPreferredCloseTaskState; public BaseRepository(TaskRepositoryType type) { super(type); @@ -135,6 +138,28 @@ public abstract class BaseRepository extends TaskRepository { myLoginAnonymously = loginAnonymously; } + @Override + public void setPreferredOpenTaskState(@Nullable CustomTaskState state) { + myPreferredOpenTaskState = state; + } + + @Nullable + @Override + public CustomTaskState getPreferredOpenTaskState() { + return myPreferredOpenTaskState; + } + + @Override + public void setPreferredCloseTaskState(@Nullable CustomTaskState state) { + myPreferredCloseTaskState = state; + } + + @Nullable + @Override + public CustomTaskState getPreferredCloseTaskState() { + return myPreferredCloseTaskState; + } + @Nullable public String extractId(@NotNull String taskName) { Matcher matcher = PATTERN.matcher(taskName); diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRemoteApi.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRemoteApi.java index 8ee9c97512a1..7b760769a0e3 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRemoteApi.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRemoteApi.java @@ -1,8 +1,8 @@ package com.intellij.tasks.jira; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.LocalTask; import com.intellij.tasks.Task; -import com.intellij.tasks.TaskState; import com.intellij.tasks.jira.rest.api2.JiraRestApi2; import com.intellij.tasks.jira.rest.api20alpha1.JiraRestApi20Alpha1; import com.intellij.tasks.jira.soap.JiraLegacyApi; @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Set; /** * Because of the number of available remote interfaces in JIRA, {@link JiraRepository} delegates @@ -29,7 +30,10 @@ public abstract class JiraRemoteApi { @Nullable public abstract Task findTask(@NotNull String key) throws Exception; - public abstract void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception; + @NotNull + public abstract Set getAvailableTaskStates(@NotNull Task task) throws Exception; + + public abstract void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception; public abstract void updateTimeSpend(@NotNull LocalTask task, @NotNull String timeSpent, String comment) throws Exception; @@ -80,6 +84,5 @@ public abstract class JiraRemoteApi { public String getVersionName() { return myVersionName; } - } } diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java index 820bb22426e0..ec0e612f4e81 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java @@ -22,10 +22,10 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.LocalTask; import com.intellij.tasks.Task; import com.intellij.tasks.TaskBundle; -import com.intellij.tasks.TaskState; import com.intellij.tasks.impl.BaseRepositoryImpl; import com.intellij.tasks.impl.gson.GsonUtil; import com.intellij.tasks.jira.rest.JiraRestApi; @@ -44,10 +44,7 @@ import org.jetbrains.annotations.Nullable; import java.io.InputStream; import java.net.URL; -import java.util.Collections; -import java.util.Hashtable; -import java.util.List; -import java.util.Vector; +import java.util.*; import java.util.regex.Pattern; /** @@ -352,10 +349,16 @@ public class JiraRepository extends BaseRepositoryImpl { } @Override - public void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception { + public void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception { myApiVersion.setTaskState(task, state); } + @NotNull + @Override + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + return myApiVersion.getAvailableTaskStates(task); + } + public void setSearchQuery(String searchQuery) { mySearchQuery = searchQuery; } @@ -371,8 +374,6 @@ public class JiraRepository extends BaseRepositoryImpl { /** * Used to preserve discovered API version for the next initialization. - * - * @return */ @SuppressWarnings("UnusedDeclaration") @Nullable diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java index 502eed083e74..78919e390d5f 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java @@ -2,8 +2,8 @@ package com.intellij.tasks.jira.rest; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.Task; -import com.intellij.tasks.TaskState; import com.intellij.tasks.jira.JiraRemoteApi; import com.intellij.tasks.jira.JiraRepository; import com.intellij.tasks.jira.JiraVersion; @@ -99,19 +99,16 @@ public abstract class JiraRestApi extends JiraRemoteApi { protected abstract JiraIssue parseIssue(String response); @Override - public void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception { + public void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception { String requestBody = getRequestForStateTransition(state); LOG.debug(String.format("Transition: %s -> %s, request: %s", task.getState(), state, requestBody)); - if (requestBody == null) { - return; - } PostMethod method = new PostMethod(myRepository.getRestUrl("issue", task.getId(), "transitions")); method.setRequestEntity(createJsonEntity(requestBody)); myRepository.executeMethod(method); } @Nullable - protected abstract String getRequestForStateTransition(@NotNull TaskState state); + protected abstract String getRequestForStateTransition(@NotNull CustomTaskState state); protected static RequestEntity createJsonEntity(String requestBody) { try { diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/JiraRestApi2.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/JiraRestApi2.java index 0c9b647ee720..b83607481fac 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/JiraRestApi2.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/JiraRestApi2.java @@ -3,11 +3,13 @@ package com.intellij.tasks.jira.rest.api2; import com.google.gson.reflect.TypeToken; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.LocalTask; -import com.intellij.tasks.TaskState; +import com.intellij.tasks.Task; import com.intellij.tasks.jira.JiraRepository; import com.intellij.tasks.jira.rest.JiraRestApi; import com.intellij.tasks.jira.rest.api2.model.JiraIssueApi2; +import com.intellij.tasks.jira.rest.api2.model.JiraTransitionsWrapperApi2; import com.intellij.tasks.jira.rest.model.JiraIssue; import com.intellij.tasks.jira.rest.model.JiraResponseWrapper; import org.apache.commons.httpclient.methods.GetMethod; @@ -18,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * This REST API version is used in JIRA 5.1.8 and above (including JIRA 6.x.x). @@ -63,21 +66,31 @@ public class JiraRestApi2 extends JiraRestApi { return JiraRepository.GSON.fromJson(response, JiraIssueApi2.class); } - @Nullable + @NotNull @Override - protected String getRequestForStateTransition(@NotNull TaskState state) { - // REST API 2.0 require double quotes both around field names and values (even numbers) - switch (state) { - case IN_PROGRESS: - return "{\"transition\": {\"id\": \"4\"}}"; - case RESOLVED: - // 5 for "Resolved", 2 for "Closed" - return "{\"transition\": {\"id\": \"5\"}, \"fields\": {\"resolution\": {\"name\": \"Fixed\"}}}"; - case REOPENED: - return "{\"transition\": {\"id\": \"3\"}}"; - default: - return null; + protected String getRequestForStateTransition(@NotNull CustomTaskState state) { + assert StringUtil.isNotEmpty(state.getId()); + final String stateId = state.getId(); + final int index = stateId.indexOf(':'); + if (index >= 0) { + return "{" + + " \"transition\": {\"id\": \"" + stateId.substring(0, index) + "\"}, " + + " \"fields\": {\"resolution\": {\"name\": \"" + stateId.substring(index + 1) + "\"}}" + + "}"; } + else { + return "{\"transition\": {\"id\": \"" + stateId + "\"}}"; + } + } + + @NotNull + @Override + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + final GetMethod method = new GetMethod(myRepository.getRestUrl("issue", task.getId(), "transitions")); + method.setQueryString("expand=transitions.fields"); + final String response = myRepository.executeMethod(method); + final JiraTransitionsWrapperApi2 wrapper = JiraRepository.GSON.fromJson(response, JiraTransitionsWrapperApi2.class); + return wrapper.getTransitions(); } @Override diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/model/JiraTransitionsWrapperApi2.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/model/JiraTransitionsWrapperApi2.java new file mode 100644 index 000000000000..a1534ab81e8a --- /dev/null +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api2/model/JiraTransitionsWrapperApi2.java @@ -0,0 +1,68 @@ +package com.intellij.tasks.jira.rest.api2.model; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.tasks.CustomTaskState; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +/** + * @author Mikhail Golubev + */ +@SuppressWarnings({"unused", "FieldMayBeFinal"}) +public class JiraTransitionsWrapperApi2 { + private static final Logger LOG = Logger.getInstance(JiraTransitionsWrapperApi2.class); + private List transitions = Collections.emptyList(); + + static class JiraTransition { + private int id; + private String name; + @SerializedName("to") + private JiraTaskState target; + private JsonObject fields; + + static class JiraTaskState { + private int id; + private String name; + } + } + + @NotNull + public Set getTransitions() { + final Set result = new LinkedHashSet(); + nextTransition: + for (JiraTransition transition : transitions) { + final String stateName = transition.target.name; + final List resolutions = new ArrayList(); + if (transition.fields != null) { + for (Map.Entry field : transition.fields.entrySet()) { + final String fieldName = field.getKey(); + final JsonObject fieldInfo = field.getValue().getAsJsonObject(); + if (fieldInfo.get("required").getAsBoolean()) { + if (fieldName.equals("resolution")) { + for (JsonElement allowedValue : fieldInfo.getAsJsonArray("allowedValues")) { + resolutions.add(allowedValue.getAsJsonObject().get("name").getAsString()); + } + } + else { + LOG.info("Unknown required field '" + fieldName + "' for transition '" + stateName + "'"); + continue nextTransition; + } + } + } + } + if (resolutions.isEmpty()) { + result.add(new CustomTaskState(String.valueOf(transition.id), stateName)); + } + else { + for (String resolution : resolutions) { + result.add(new CustomTaskState(transition.id + ":" + resolution, stateName + " (" + resolution + ")")); + } + } + } + return result; + } +} diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api20alpha1/JiraRestApi20Alpha1.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api20alpha1/JiraRestApi20Alpha1.java index 7de17945ac31..bc70d239ce73 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api20alpha1/JiraRestApi20Alpha1.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/api20alpha1/JiraRestApi20Alpha1.java @@ -2,9 +2,10 @@ package com.intellij.tasks.jira.rest.api20alpha1; import com.google.gson.reflect.TypeToken; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.LocalTask; +import com.intellij.tasks.Task; import com.intellij.tasks.TaskBundle; -import com.intellij.tasks.TaskState; import com.intellij.tasks.jira.JiraRepository; import com.intellij.tasks.jira.rest.JiraRestApi; import com.intellij.tasks.jira.rest.JiraRestTask; @@ -16,20 +17,35 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * This REST API is used in JIRA versions from 4.2 to 4.4. + * * @author Mikhail Golubev */ public class JiraRestApi20Alpha1 extends JiraRestApi { private static final Logger LOG = Logger.getInstance(JiraRestApi20Alpha1.class); - private static final Type ISSUES_WRAPPER_TYPE = new TypeToken>() { /* empty */ }.getType(); + private static final Type ISSUES_WRAPPER_TYPE = new TypeToken>() {/* empty */}.getType(); public JiraRestApi20Alpha1(JiraRepository repository) { super(repository); } + @NotNull + @Override + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + // REST API of JIRA 4.x for retrieving possible transitions is very limited: we can't fetch possible resolutions and + // names of transition destinations. So we have no other options than to hardcode them. + final HashSet result = new HashSet(); + result.add(new CustomTaskState("4", "In Progress")); + result.add(new CustomTaskState("5", "Resolved (Fixed)")); + result.add(new CustomTaskState("3", "Reopened")); + return result; + } + @Override protected JiraIssue parseIssue(String response) { return JiraRepository.GSON.fromJson(response, JiraIssueApi20Alpha1.class); @@ -57,20 +73,24 @@ public class JiraRestApi20Alpha1 extends JiraRestApi { @Nullable @Override - protected String getRequestForStateTransition(@NotNull TaskState state) { - switch (state) { - case IN_PROGRESS: - return "{\"transition\": \"4\"}"; - case RESOLVED: - // 5 for "Resolved", 2 for "Closed" - return "{\"transition\": \"5\", \"resolution\": \"Fixed\"}"; - case REOPENED: - return "{\"transition\": \"3\"}"; - default: - return null; + protected String getRequestForStateTransition(@NotNull CustomTaskState state) { + try { + switch (Integer.parseInt(state.getId())) { + case 4: // In Progress + return "{\"transition\": \"4\"}"; + case 5: // Resolved (2 for "Closed") + return "{\"transition\": \"5\", \"resolution\": \"Fixed\"}"; + case 3: // Reopened + return "{\"transition\": \"3\"}"; + } } + catch (NumberFormatException ignored) { + } + LOG.error("Unknown ID of predefined issue state: " + state.getId()); + return null; } + @Override public void updateTimeSpend(@NotNull LocalTask task, @NotNull String timeSpent, String comment) throws Exception { throw new Exception(TaskBundle.message("jira.failure.no.time.spent")); diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/soap/JiraLegacyApi.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/soap/JiraLegacyApi.java index e8cbee842cda..7f5ab27cc9a1 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/soap/JiraLegacyApi.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/soap/JiraLegacyApi.java @@ -1,10 +1,10 @@ package com.intellij.tasks.jira.soap; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.LocalTask; import com.intellij.tasks.Task; import com.intellij.tasks.TaskBundle; -import com.intellij.tasks.TaskState; import com.intellij.tasks.impl.TaskUtil; import com.intellij.tasks.jira.JiraRemoteApi; import com.intellij.tasks.jira.JiraRepository; @@ -19,7 +19,9 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.List; +import java.util.Set; /** * Legacy integration restored due to IDEA-120595. @@ -102,8 +104,14 @@ public class JiraLegacyApi extends JiraRemoteApi { return ApiType.LEGACY; } + @NotNull @Override - public void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception { + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + return Collections.emptySet(); + } + + @Override + public void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception { throw new Exception(TaskBundle.message("jira.failure.no.state.update")); } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/TaskBundle.properties b/plugins/tasks/tasks-core/src/com/intellij/tasks/TaskBundle.properties index ce617cbf01ca..4d631b7c5d20 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/TaskBundle.properties +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/TaskBundle.properties @@ -23,3 +23,5 @@ youtrack.default.query=for: me sort by: updated #Unresolved bugzilla.failure.malformed.response=Cannot decode server response. Check that XML-RPC plugin is enabled. bugzilla.failure.no.version=Cannot find Bugzilla version. Check that URL ends with "xmlrpc.cgi". +## Trello +trello.failure.write.access.required=This action requires write access to your account. Please update authorization token in settings. diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskAction.java index 6863eef78510..7bf2afa94b2f 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskAction.java @@ -41,11 +41,13 @@ public class CloseTaskAction extends BaseTaskAction { LocalTask task = taskManager.getActiveTask(); CloseTaskDialog dialog = new CloseTaskDialog(project, task); if (dialog.showAndGet()) { - if (dialog.isCloseIssue()) { + final CustomTaskState taskState = dialog.getCloseIssueState(); + if (taskState != null) { try { TaskRepository repository = task.getRepository(); assert repository != null; - repository.setTaskState(task, TaskState.RESOLVED); + repository.setTaskState(task, taskState); + repository.setPreferredCloseTaskState(taskState); } catch (Exception e1) { Messages.showErrorDialog(project, e1.getMessage(), "Cannot Resolve Issue"); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.form b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.form index 0c8600a9785b..7508f5a7dc34 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.form +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.form @@ -3,7 +3,7 @@ - + @@ -52,14 +52,6 @@ - - - - - - - - @@ -73,6 +65,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java index fa9879c05fe0..73d14d23435a 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/CloseTaskDialog.java @@ -19,42 +19,51 @@ package com.intellij.tasks.actions; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vcs.VcsType; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.LocalTask; import com.intellij.tasks.TaskManager; import com.intellij.tasks.TaskRepository; -import com.intellij.tasks.TaskState; import com.intellij.tasks.impl.TaskManagerImpl; +import com.intellij.tasks.impl.TaskStateCombo; import com.intellij.tasks.impl.TaskUtil; import com.intellij.ui.components.JBCheckBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Collection; /** * @author Dmitry Avdeev */ public class CloseTaskDialog extends DialogWrapper { - + private final Project myProject; + private final LocalTask myTask; private JCheckBox myCommitChanges; - private JCheckBox myCloseIssue; private JPanel myPanel; private JLabel myTaskLabel; private JBCheckBox myMergeBranches; private JPanel myVcsPanel; + private JLabel myStateComboBoxLabel; + private TaskStateCombo myStateCombo; private final TaskManagerImpl myTaskManager; - public CloseTaskDialog(Project project, LocalTask task) { + public CloseTaskDialog(Project project, final LocalTask task) { super(project, false); + myProject = project; + myTask = task; setTitle("Close Task"); myTaskLabel.setText(TaskUtil.getTrimmedSummary(task)); myTaskLabel.setIcon(task.getIcon()); - TaskRepository repository = task.getRepository(); - boolean visible = task.isIssue() && TaskUtil.isStateSupported(repository, TaskState.RESOLVED); - myCloseIssue.setVisible(visible); + myStateComboBoxLabel.setLabelFor(myStateCombo); + if (!TaskStateCombo.isStateSupportedFor(task)) { + myStateComboBoxLabel.setVisible(false); + myStateCombo.setVisible(false); + } myTaskManager = (TaskManagerImpl)TaskManager.getManager(project); - myCloseIssue.setSelected(visible && myTaskManager.getState().closeIssue); if (myTaskManager.isVcsEnabled()) { myCommitChanges.setEnabled(!task.getChangeLists().isEmpty()); @@ -71,6 +80,11 @@ public class CloseTaskDialog extends DialogWrapper { else { myVcsPanel.setVisible(false); } + final JComponent preferredFocusedComponent = getPreferredFocusedComponent(); + if (preferredFocusedComponent != null) { + myStateCombo.registerUpDownAction(preferredFocusedComponent); + } + myStateCombo.scheduleUpdate(); init(); } @@ -78,8 +92,15 @@ public class CloseTaskDialog extends DialogWrapper { return myPanel; } - boolean isCloseIssue() { - return myCloseIssue.isSelected(); + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myStateCombo.getComboBox(); + } + + @Nullable + CustomTaskState getCloseIssueState() { + return myStateCombo.getSelectedState(); } boolean isCommitChanges() { @@ -92,7 +113,6 @@ public class CloseTaskDialog extends DialogWrapper { @Override protected void doOKAction() { - myTaskManager.getState().closeIssue = isCloseIssue(); if (myCommitChanges.isEnabled()) { myTaskManager.getState().commitChanges = isCommitChanges(); } @@ -101,4 +121,14 @@ public class CloseTaskDialog extends DialogWrapper { } super.doOKAction(); } + + private void createUIComponents() { + myStateCombo = new TaskStateCombo(myProject, myTask) { + @Nullable + @Override + protected CustomTaskState getPreferredState(@NotNull TaskRepository repository, @NotNull Collection available) { + return repository.getPreferredCloseTaskState(); + } + }; + } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.form b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.form index fb7ab62bdaa8..64b57bd9d93b 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.form +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.form @@ -1,9 +1,9 @@

- + - + @@ -11,7 +11,7 @@ - + @@ -31,21 +31,12 @@ - - - - - - - - - - + @@ -76,7 +67,7 @@ - + @@ -124,7 +115,9 @@ - + + + @@ -137,6 +130,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java index 66c3f80540c5..485161687d68 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/OpenTaskDialog.java @@ -30,6 +30,7 @@ import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.VcsTaskHandler; import com.intellij.tasks.*; import com.intellij.tasks.impl.TaskManagerImpl; +import com.intellij.tasks.impl.TaskStateCombo; import com.intellij.tasks.impl.TaskUtil; import com.intellij.ui.ColoredListCellRenderer; import com.intellij.ui.components.JBCheckBox; @@ -42,6 +43,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.Collection; /** * @author Dmitry Avdeev @@ -53,7 +55,6 @@ public class OpenTaskDialog extends DialogWrapper { private JPanel myPanel; @BindControl(value = "clearContext", instant = true) private JCheckBox myClearContext; - private JCheckBox myMarkAsInProgressBox; private JLabel myTaskNameLabel; private JPanel myVcsPanel; private JTextField myBranchName; @@ -62,6 +63,8 @@ public class OpenTaskDialog extends DialogWrapper { private JBCheckBox myCreateChangelist; private JBLabel myFromLabel; private ComboBox myBranchFrom; + private JLabel myTaskStateLabel; + private TaskStateCombo myTaskStateCombo; private final Project myProject; private final Task myTask; @@ -81,10 +84,10 @@ public class OpenTaskDialog extends DialogWrapper { binder.bindAnnotations(this); binder.reset(); - TaskRepository repository = task.getRepository(); - myMarkAsInProgressBox.setSelected(manager.getState().markAsInProgress); - if (!TaskUtil.isStateSupported(repository, TaskState.IN_PROGRESS)) { - myMarkAsInProgressBox.setVisible(false); + myTaskStateLabel.setLabelFor(myTaskStateCombo); + if (!TaskStateCombo.isStateSupportedFor(task)) { + myTaskStateLabel.setVisible(false); + myTaskStateCombo.setVisible(false); } TaskManagerImpl.Config state = taskManager.getState(); @@ -162,6 +165,11 @@ public class OpenTaskDialog extends DialogWrapper { myChangelistName.setText(taskManager.getChangelistName(task)); updateFields(true); } + final JComponent preferredFocusedComponent = getPreferredFocusedComponent(); + if (preferredFocusedComponent != null) { + myTaskStateCombo.registerUpDownAction(preferredFocusedComponent); + } + myTaskStateCombo.scheduleUpdate(); init(); } @@ -186,14 +194,15 @@ public class OpenTaskDialog extends DialogWrapper { public void createTask() { final TaskManagerImpl taskManager = (TaskManagerImpl)TaskManager.getManager(myProject); - taskManager.getState().markAsInProgress = isMarkAsInProgress(); taskManager.getState().createChangelist = myCreateChangelist.isSelected(); taskManager.getState().createBranch = myCreateBranch.isSelected(); - TaskRepository repository = myTask.getRepository(); - if (isMarkAsInProgress() && repository != null) { + final CustomTaskState taskState = myTaskStateCombo.getSelectedState(); + final TaskRepository repository = myTask.getRepository(); + if (repository != null && taskState != null) { try { - repository.setTaskState(myTask, TaskState.IN_PROGRESS); + repository.setTaskState(myTask, taskState); + repository.setPreferredOpenTaskState(taskState); } catch (Exception ex) { Messages.showErrorDialog(myProject, ex.getMessage(), "Cannot Set State For Issue"); @@ -252,10 +261,6 @@ public class OpenTaskDialog extends DialogWrapper { return myClearContext.isSelected(); } - private boolean isMarkAsInProgress() { - return myMarkAsInProgressBox.isSelected() && myMarkAsInProgressBox.isVisible(); - } - @NonNls protected String getDimensionServiceKey() { return "SimpleOpenTaskDialog"; @@ -270,11 +275,21 @@ public class OpenTaskDialog extends DialogWrapper { return myChangelistName; } else { - return null; + return myTaskStateCombo.getComboBox(); } } protected JComponent createCenterPanel() { return myPanel; } + + private void createUIComponents() { + myTaskStateCombo = new TaskStateCombo(myProject, myTask) { + @Nullable + @Override + protected CustomTaskState getPreferredState(@NotNull TaskRepository repository, @NotNull Collection available) { + return repository.getPreferredOpenTaskState(); + } + }; + } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java index 622c47dc552c..0e6d3f3c9187 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java @@ -16,22 +16,18 @@ package com.intellij.tasks.actions; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.wm.IdeFrame; -import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.tasks.LocalTask; import com.intellij.tasks.TaskManager; import com.intellij.tasks.config.TaskSettings; -import com.intellij.util.IJSwingUtilities; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -41,34 +37,17 @@ import javax.swing.*; */ public class SwitchTaskCombo extends ComboBoxAction implements DumbAware { - private static final Key BUTTON_KEY = Key.create("SWITCH_TASK_BUTTON"); - @Override public void actionPerformed(AnActionEvent e) { - final IdeFrameImpl ideFrame = findFrame(e); - final ComboBoxButton button = (ComboBoxButton)ideFrame.getRootPane().getClientProperty(BUTTON_KEY); + ComboBoxButton button = (ComboBoxButton)e.getPresentation().getClientProperty(CUSTOM_COMPONENT_PROPERTY); if (button == null || !button.isShowing()) return; button.showPopup(); } - private static IdeFrameImpl findFrame(AnActionEvent e) { - return IJSwingUtilities.findParentOfType(e.getData(PlatformDataKeys.CONTEXT_COMPONENT), IdeFrameImpl.class); - } - - public JComponent createCustomComponent(final Presentation presentation) { - return new ComboBoxButton(presentation) { - public void addNotify() { - super.addNotify(); - final IdeFrame frame = UIUtil.getParentOfType(IdeFrame.class, this); - assert frame != null; - frame.getComponent().getRootPane().putClientProperty(BUTTON_KEY, this); - } - - @Override - protected JBPopup createPopup(Runnable onDispose) { - return SwitchTaskAction.createPopup(DataManager.getInstance().getDataContext(this), onDispose, false); - } - }; + public JComponent createCustomComponent(Presentation presentation) { + ComboBoxButton button = new ComboBoxButton(presentation); + button.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); + return button; } @NotNull @@ -79,9 +58,10 @@ public class SwitchTaskCombo extends ComboBoxAction implements DumbAware { @Override public void update(AnActionEvent e) { - Project project = e.getData(CommonDataKeys.PROJECT); Presentation presentation = e.getPresentation(); - if (project == null || project.isDisposed() || (ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) && findFrame(e) == null)) { + Project project = e.getData(CommonDataKeys.PROJECT); + ComboBoxButton button = (ComboBoxButton)presentation.getClientProperty(CUSTOM_COMPONENT_PROPERTY); + if (project == null || project.isDisposed() || button == null) { presentation.setEnabled(false); presentation.setText(""); presentation.setIcon(null); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java index ec4d81f86d2c..5dabf0b91e3b 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerBreakpointsContextProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -56,7 +56,7 @@ public class XDebuggerBreakpointsContextProvider extends WorkingContextProvider XBreakpointManagerImpl.BreakpointManagerState state = myBreakpointManager.getState(); Element serialize = XmlSerializer.serialize(state, new SerializationFilter() { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { return accessor.read(bean) != null; } }); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java index 2b39f86d30b8..12fddd63d7f8 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/context/XDebuggerWatchesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -54,7 +54,7 @@ public class XDebuggerWatchesProvider extends WorkingContextProvider { XDebuggerWatchesManager.WatchesManagerState state = myWatchesManager.getState(); Element serialize = XmlSerializer.serialize(state, new SerializationFilter() { @Override - public boolean accepts(@NotNull Accessor accessor, Object bean) { + public boolean accepts(@NotNull Accessor accessor, @NotNull Object bean) { return accessor.read(bean) != null; } }); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java index 3529dc1229e9..3a50bb8da92c 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java @@ -1034,13 +1034,11 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe public boolean createBranch = true; // close task options - public boolean closeIssue = true; public boolean commitChanges = true; public boolean mergeBranch = true; public boolean saveContextOnCommit = true; public boolean trackContextForNewChangelist = false; - public boolean markAsInProgress = false; public String changelistNameFormat = "{id} {summary}"; public String branchNameFormat = "{id}"; diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskStateCombo.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskStateCombo.java new file mode 100644 index 000000000000..2126eece9902 --- /dev/null +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskStateCombo.java @@ -0,0 +1,170 @@ +package com.intellij.tasks.impl; + +import com.intellij.ide.actions.TemplateKindCombo; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Trinity; +import com.intellij.tasks.CustomTaskState; +import com.intellij.tasks.Task; +import com.intellij.tasks.TaskRepository; +import com.intellij.tasks.impl.TaskUiUtil.ComboBoxUpdater; +import com.intellij.ui.ListCellRendererWrapper; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.Function; +import com.intellij.util.PlatformIcons; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Collection; +import java.util.List; + +/** + * @author Mikhail Golubev + */ +public abstract class TaskStateCombo extends JPanel { + private static final CustomTaskState DO_NOT_UPDATE_STATE = new CustomTaskState("", "-- do not update --"); + + public static boolean isStateSupportedFor(@Nullable Task task) { + if (task == null || !task.isIssue()) { + return false; + } + final TaskRepository repository = task.getRepository(); + return repository != null && repository.isSupported(TaskRepository.STATE_UPDATING); + } + + private final Project myProject; + private final Task myTask; + private final TemplateKindCombo myKindCombo = new TemplateKindCombo(); + + // For designer only + @SuppressWarnings("unused") + public TaskStateCombo() { + this(null, null); + } + + @SuppressWarnings({"GtkPreferredJComboBoxRenderer", "unchecked"}) + public TaskStateCombo(Project project, Task task) { + myProject = project; + myTask = task; + + final JBLabel hintButton = new JBLabel(); + hintButton.setIcon(PlatformIcons.UP_DOWN_ARROWS); + hintButton.setToolTipText("Pressing Up or Down arrows while in editor changes the state"); + final JComboBox comboBox = myKindCombo.getComboBox(); + comboBox.setPreferredSize(new Dimension(300, UIUtil.fixComboBoxHeight(comboBox.getPreferredSize().height))); + final ListCellRenderer defaultRenderer = comboBox.getRenderer(); + comboBox.setRenderer(new ListCellRenderer() { + @SuppressWarnings({"unchecked", "GtkPreferredJComboBoxRenderer"}) + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + if (value == null) { + return new ListCellRendererWrapper() { + @Override + public void customize(JList list, CustomStateTrinityAdapter value, int index, boolean selected, boolean hasFocus) { + setText("-- no states available --"); + } + }.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus); + } + return defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + }); + + setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); + add(myKindCombo); + add(hintButton); + } + + public boolean scheduleUpdate() { + if (myProject != null && isStateSupportedFor(myTask)) { + final JComboBox comboBox = myKindCombo.getComboBox(); + final TaskRepository repository = myTask.getRepository(); + assert repository != null; + new ComboBoxUpdater(myProject, "Fetching available task states...", comboBox) { + @NotNull + @Override + protected List fetch(@NotNull ProgressIndicator indicator) throws Exception { + return CustomStateTrinityAdapter.wrapList(repository.getAvailableTaskStates(myTask)); + } + + @Nullable + @Override + public CustomStateTrinityAdapter getSelectedItem() { + final CustomTaskState state = getPreferredState(repository, CustomStateTrinityAdapter.unwrapList(myResult)); + return state != null ? new CustomStateTrinityAdapter(state) : null; + } + + @Nullable + @Override + public CustomStateTrinityAdapter getExtraItem() { + return new CustomStateTrinityAdapter(DO_NOT_UPDATE_STATE); + } + }.queue(); + return true; + } + return false; + } + + /** + * @return {@code null} if no state is available at the moment or special "do not update" state was selected + */ + @Nullable + public CustomTaskState getSelectedState() { + final CustomStateTrinityAdapter item = (CustomStateTrinityAdapter)myKindCombo.getComboBox().getSelectedItem(); + if (item == null) { + return null; + } + final CustomTaskState state = item.myState; + return state == DO_NOT_UPDATE_STATE ? null : state; + } + + public void registerUpDownAction(@NotNull JComponent focusable) { + myKindCombo.registerUpDownHint(focusable); + } + + @NotNull + public JComboBox getComboBox() { + return myKindCombo.getComboBox(); + } + + /** + * Determine what state should be initially selected in the list. + * @param repository task repository to communicate with + * @param available tasks states already downloaded from the repository + * @return task state to select + */ + @Nullable + protected abstract CustomTaskState getPreferredState(@NotNull TaskRepository repository, @NotNull Collection available); + + private static class CustomStateTrinityAdapter extends Trinity { + final CustomTaskState myState; + + public CustomStateTrinityAdapter(@NotNull CustomTaskState state) { + super(state.getPresentableName(), null, state.getId()); + myState = state; + } + + @NotNull + static List wrapList(@NotNull Collection states) { + return ContainerUtil.map(states, new Function() { + @Override + public CustomStateTrinityAdapter fun(CustomTaskState state) { + return new CustomStateTrinityAdapter(state); + } + }); + } + + @NotNull + static List unwrapList(@NotNull Collection wrapped) { + return ContainerUtil.map(wrapped, new Function() { + @Override + public CustomTaskState fun(CustomStateTrinityAdapter adapter) { + return adapter.myState; + } + }); + } + } +} diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUiUtil.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUiUtil.java index d24ed38c9819..0f8e571a9e87 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUiUtil.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUiUtil.java @@ -6,14 +6,14 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.ComboBox; +import com.intellij.tasks.config.TaskRepositoryEditor; import com.intellij.ui.ListCellRendererWrapper; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.List; +import java.util.Collection; /** * @author Mikhail Golubev @@ -33,13 +33,18 @@ public class TaskUiUtil { public abstract static class RemoteFetchTask extends Task.Backgroundable { protected T myResult; protected Exception myException; - private final ModalityState myModalityState = ModalityState.current(); + private final ModalityState myModalityState; /** * Should be called only from EDT, so current modality state can be captured. */ protected RemoteFetchTask(@Nullable Project project, @NotNull String title) { + this(project, title, ModalityState.current()); + } + + protected RemoteFetchTask(@Nullable Project project, @NotNull String title, @NotNull ModalityState modalityState) { super(project, title); + myModalityState = modalityState; } @Override @@ -55,7 +60,7 @@ public class TaskUiUtil { /** * {@link #onSuccess()} can't be used for this purpose, because it doesn't consider current modality state - * which will prevent UI updating in modal dialog (e.g. in {@link com.intellij.tasks.config.TaskRepositoryEditor}). + * which will prevent UI updating in modal dialog (e.g. in {@link TaskRepositoryEditor}). */ @Nullable @Override @@ -79,11 +84,11 @@ public class TaskUiUtil { * Auxiliary remote fetcher designed to simplify updating of combo boxes in repository editors, which is * indeed a rather common task. */ - public static abstract class ComboBoxUpdater extends RemoteFetchTask> { - protected final ComboBox myComboBox; + public static abstract class ComboBoxUpdater extends RemoteFetchTask> { + protected final JComboBox myComboBox; - public ComboBoxUpdater(@Nullable Project project, @NotNull String title, @NotNull ComboBox comboBox) { - super(project, title); + public ComboBoxUpdater(@Nullable Project project, @NotNull String title, @NotNull JComboBox comboBox) { + super(project, title, ModalityState.any()); myComboBox = comboBox; } @@ -99,14 +104,23 @@ public class TaskUiUtil { /** * Return item to select after every combo box update. Default implementation select item, returned by {@link #getExtraItem()}. + * If returned value is not present in the list it will be added depending on policy set by {@link #addSelectedItemIfMissing()}. * * @return selected combo box item + * @see #addSelectedItemIfMissing() */ @Nullable public T getSelectedItem() { return getExtraItem(); } + /** + * @return whether value returned by {@link #getSelectedItem()} should be forcibly added to the combo box. + */ + protected boolean addSelectedItemIfMissing() { + return false; + } + @SuppressWarnings("unchecked") @Override protected void updateUI() { @@ -123,12 +137,20 @@ public class TaskUiUtil { final T selected = getSelectedItem(); if (selected != null) { if (!selected.equals(extra) && !myResult.contains(selected)) { - myComboBox.addItem(selected); + if (addSelectedItemIfMissing()) { + myComboBox.addItem(selected); + myComboBox.setSelectedItem(selected); + } + else { + selectFirstItem(); + } + } + else { + myComboBox.setSelectedItem(selected); } - myComboBox.setSelectedItem(selected); } - else if (myComboBox.getItemCount() > 0) { - myComboBox.setSelectedIndex(0); + else { + selectFirstItem(); } } else { @@ -136,13 +158,19 @@ public class TaskUiUtil { } } + private void selectFirstItem() { + if (myComboBox.getItemCount() > 0) { + myComboBox.setSelectedIndex(0); + } + } + protected void handleError() { myComboBox.removeAllItems(); } } /** - * Very simple wrapper around {@link com.intellij.ui.ListCellRendererWrapper} useful for + * Very simple wrapper around {@link ListCellRendererWrapper} useful for * combo boxes where each item has plain text representation with special message for * {@code null} value. */ diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/ResponseUtil.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/ResponseUtil.java index e512ff04a15b..c3fc81ec27e7 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/ResponseUtil.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/ResponseUtil.java @@ -134,14 +134,20 @@ public class ResponseUtil { if (LOG.isDebugEnabled()) { String content = getResponseContentAsString(response); TaskUtil.prettyFormatJsonToLog(LOG, content); - return myGson.fromJson(content, myClass); + return myGson.fromJson(content, myClass); + } + else { + return myGson.fromJson(getResponseContentAsReader(response), myClass); } - return myGson.fromJson(getResponseContentAsReader(response), myClass); } catch (JsonSyntaxException e) { LOG.warn("Malformed server response", e); return null; } + catch (NumberFormatException e) { + LOG.error("NFE in response: " + getResponseContentAsString(response), e); + throw new RequestFailedException("Malformed response"); + } } } @@ -175,12 +181,18 @@ public class ResponseUtil { TaskUtil.prettyFormatJsonToLog(LOG, content); return myGson.fromJson(content, myTypeToken.getType()); } - return myGson.fromJson(getResponseContentAsReader(response), myTypeToken.getType()); + else { + return myGson.fromJson(getResponseContentAsReader(response), myTypeToken.getType()); + } } catch (JsonSyntaxException e) { LOG.warn("Malformed server response", e); return Collections.emptyList(); } + catch (NumberFormatException e) { + LOG.error("NFE in response: " + getResponseContentAsString(response), e); + throw new RequestFailedException("Malformed response"); + } } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepository.java index 89d3e3d7d8f2..e2cc5b078150 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepository.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepository.java @@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.Task; import com.intellij.tasks.TaskBundle; import com.intellij.tasks.TaskRepositoryType; @@ -35,22 +36,27 @@ import com.intellij.tasks.trello.model.TrelloCard; import com.intellij.tasks.trello.model.TrelloList; import com.intellij.tasks.trello.model.TrelloUser; import com.intellij.util.Function; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xmlb.annotations.Tag; import org.apache.http.*; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestWrapper; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.utils.URIBuilder; import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EntityUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -202,7 +208,7 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { try { final URIBuilder url = new URIBuilder(getRestApiUrl("members", "me")) .addParameter("fields", TrelloUser.REQUIRED_FIELDS); - return makeRequestAndDeserializeJsonResponse(url.build(), TrelloUser.class); + return ObjectUtils.assertNotNull(makeRequestAndDeserializeJsonResponse(url.build(), TrelloUser.class)); } catch (Exception e) { LOG.warn("Error while fetching initial user info", e); @@ -218,7 +224,7 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { final URIBuilder url = new URIBuilder(getRestApiUrl("boards", id)) .addParameter("fields", TrelloBoard.REQUIRED_FIELDS); try { - return makeRequestAndDeserializeJsonResponse(url.build(), TrelloBoard.class); + return ObjectUtils.assertNotNull(makeRequestAndDeserializeJsonResponse(url.build(), TrelloBoard.class)); } catch (Exception e) { LOG.warn("Error while fetching initial board info", e); @@ -231,7 +237,7 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { final URIBuilder url = new URIBuilder(getRestApiUrl("lists", id)) .addParameter("fields", TrelloList.REQUIRED_FIELDS); try { - return makeRequestAndDeserializeJsonResponse(url.build(), TrelloList.class); + return ObjectUtils.assertNotNull(makeRequestAndDeserializeJsonResponse(url.build(), TrelloList.class)); } catch (Exception e) { LOG.warn("Error while fetching initial list info" + id, e); @@ -244,7 +250,12 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { if (myCurrentBoard == null || myCurrentBoard == UNSPECIFIED_BOARD) { throw new IllegalStateException("Board not set"); } - final URIBuilder url = new URIBuilder(getRestApiUrl("boards", myCurrentBoard.getId(), "lists")) + return fetchBoardLists(myCurrentBoard.getId()); + } + + @NotNull + private List fetchBoardLists(@NotNull String boardId) throws Exception { + final URIBuilder url = new URIBuilder(getRestApiUrl("boards", boardId, "lists")) .addParameter("fields", TrelloList.REQUIRED_FIELDS); return makeRequestAndDeserializeJsonResponse(url.build(), TrelloUtil.LIST_OF_LISTS_TYPE); } @@ -327,7 +338,7 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { return cards; } - @NotNull + @Nullable private T executeMethod(@NotNull HttpUriRequest method, @NotNull ResponseHandler handler) throws Exception { final HttpClient client = getHttpClient(); final HttpResponse response = client.execute(method); @@ -345,10 +356,11 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { @NotNull private List makeRequestAndDeserializeJsonResponse(@NotNull URI url, @NotNull TypeToken> type) throws Exception { - return executeMethod(new HttpGet(url), new GsonMultipleObjectsDeserializer(TrelloUtil.GSON, type)); + final List result = executeMethod(new HttpGet(url), new GsonMultipleObjectsDeserializer(TrelloUtil.GSON, type)); + return ObjectUtils.assertNotNull(result); } - @NotNull + @Nullable private T makeRequestAndDeserializeJsonResponse(@NotNull URI url, @NotNull Class cls) throws Exception { return executeMethod(new HttpGet(url), new GsonSingleObjectDeserializer(TrelloUtil.GSON, cls)); } @@ -424,8 +436,36 @@ public final class TrelloRepository extends NewBaseRepositoryImpl { return "https://api.trello.com"; } + @NotNull + @Override + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + final TrelloCard card = fetchCardById(task.getId()); + if (card != null) { + final List lists = fetchBoardLists(card.getIdBoard()); + final Set result = new HashSet(); + for (TrelloList list : lists) { + if (!list.getId().equals(card.getIdList())) { + result.add(new CustomTaskState(list.getId(), list.getName())); + } + } + return result; + } + return Collections.emptySet(); + } + + @Override + public void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception { + final URI url = new URIBuilder(getRestApiUrl("cards", task.getId(), "idList")).addParameter("value", state.getId()).build(); + final HttpResponse response = getHttpClient().execute(new HttpPut(url)); + if (response.getStatusLine() != null && + response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED && + EntityUtils.toString(response.getEntity()).trim().equals("unauthorized card permission requested")) { + throw new Exception(TaskBundle.message("trello.failure.write.access.required")); + } + } + @Override protected int getFeatures() { - return super.getFeatures() & ~NATIVE_SEARCH; + return super.getFeatures() & ~NATIVE_SEARCH | STATE_UPDATING; } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepositoryEditor.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepositoryEditor.java index 0ea5905cbcb2..f7dcd54d3baa 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepositoryEditor.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/TrelloRepositoryEditor.java @@ -260,6 +260,11 @@ public class TrelloRepositoryEditor extends BaseRepositoryEditor { @@ -284,5 +289,10 @@ public class TrelloRepositoryEditor extends BaseRepositoryEditor { public static final String DEVELOPER_KEY = "d6ec3709f7141007e150de64d4701181"; public static final String CLIENT_AUTHORIZATION_URL = - "https://trello.com/1/authorize?key=" + DEVELOPER_KEY +"&name=JetBrains&expiration=never&response_type=token"; + "https://trello.com/1/authorize?key=" + DEVELOPER_KEY +"&name=JetBrains&expiration=never&response_type=token&scope=read,write"; @NotNull @Override diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackOptionsTab.form b/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackOptionsTab.form deleted file mode 100644 index 8dc52a33211a..000000000000 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackOptionsTab.form +++ /dev/null @@ -1,84 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackOptionsTab.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackOptionsTab.java deleted file mode 100644 index fc084d293d52..000000000000 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackOptionsTab.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.intellij.tasks.youtrack; - -import com.intellij.ui.components.JBLabel; -import com.intellij.util.ui.UIUtil; - -import javax.swing.*; - -/** - * @author Mikhail Golubev - */ -public class YouTrackOptionsTab { - public static final String MESSAGE = "" + - "This option should be used only when \"Name\" property for \"State\" field " + - "was changed in server settings. It's not related to localized names of states." + - ""; - - private JTextField myInProgressState; - private JTextField myResolvedState; - private JPanel myRootPanel; - private JBLabel myNoteText; - - public YouTrackOptionsTab() { - myNoteText.setComponentStyle(UIUtil.ComponentStyle.SMALL); - myNoteText.setText(MESSAGE); - } - - public JTextField getInProgressState() { - return myInProgressState; - } - - public JTextField getResolvedState() { - return myResolvedState; - } - - public JPanel getRootPanel() { - return myRootPanel; - } - - -} diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepository.java index 5da18ef96d21..c67fa6834368 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepository.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepository.java @@ -25,11 +25,10 @@ import com.intellij.tasks.impl.BaseRepository; import com.intellij.tasks.impl.BaseRepositoryImpl; import com.intellij.tasks.impl.LocalTaskImpl; import com.intellij.tasks.impl.TaskUtil; +import com.intellij.util.Function; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.VersionComparatorUtil; -import com.intellij.util.xmlb.annotations.MapAnnotation; -import com.intellij.util.xmlb.annotations.Property; import com.intellij.util.xmlb.annotations.Tag; import org.apache.axis.utils.XMLChar; import org.apache.commons.httpclient.HttpClient; @@ -43,14 +42,14 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.io.InputStream; import java.io.StringReader; import java.util.Date; -import java.util.EnumMap; import java.util.List; -import java.util.Map; +import java.util.Set; /** * @author Dmitry Avdeev @@ -59,13 +58,6 @@ import java.util.Map; public class YouTrackRepository extends BaseRepositoryImpl { private String myDefaultSearch = "Assignee: me sort by: updated #Unresolved"; - private Map myCustomStateNames = new EnumMap(TaskState.class); - - // Default names for supported issues states - { - myCustomStateNames.put(TaskState.IN_PROGRESS, "In Progress"); - myCustomStateNames.put(TaskState.RESOLVED, "Fixed"); - } /** * for serialization @@ -87,7 +79,6 @@ public class YouTrackRepository extends BaseRepositoryImpl { private YouTrackRepository(YouTrackRepository other) { super(other); myDefaultSearch = other.getDefaultSearch(); - myCustomStateNames = new EnumMap(other.getCustomStateNames()); } public Task[] getIssues(@Nullable String request, int max, long since) throws Exception { @@ -98,39 +89,44 @@ public class YouTrackRepository extends BaseRepositoryImpl { } String requestUrl = "/rest/project/issues/?filter=" + encodeUrl(query) + "&max=" + max + "&updatedAfter" + since; HttpMethod method = doREST(requestUrl, false); - InputStream stream = method.getResponseBodyAsStream(); - - // todo workaround for http://youtrack.jetbrains.net/issue/JT-7984 - String s = StreamUtil.readText(stream, CharsetToolkit.UTF8_CHARSET); - for (int i = 0; i < s.length(); i++) { - if (!XMLChar.isValid(s.charAt(i))) { - s = s.replace(s.charAt(i), ' '); - } - } - - Element element; try { - //InputSource source = new InputSource(stream); - //source.setEncoding("UTF-8"); - //element = new SAXBuilder(false).build(source).getRootElement(); - element = new SAXBuilder(false).build(new StringReader(s)).getRootElement(); - } - catch (JDOMException e) { - LOG.error("Can't parse YouTrack response for " + requestUrl, e); - throw e; - } - if ("error".equals(element.getName())) { - throw new Exception("Error from YouTrack for " + requestUrl + ": '" + element.getText() + "'"); - } + InputStream stream = method.getResponseBodyAsStream(); - List children = element.getChildren("issue"); - - final List tasks = ContainerUtil.mapNotNull(children, new NullableFunction() { - public Task fun(Element o) { - return createIssue(o); + // todo workaround for http://youtrack.jetbrains.net/issue/JT-7984 + String s = StreamUtil.readText(stream, CharsetToolkit.UTF8_CHARSET); + for (int i = 0; i < s.length(); i++) { + if (!XMLChar.isValid(s.charAt(i))) { + s = s.replace(s.charAt(i), ' '); + } } - }); - return tasks.toArray(new Task[tasks.size()]); + + Element element; + try { + //InputSource source = new InputSource(stream); + //source.setEncoding("UTF-8"); + //element = new SAXBuilder(false).build(source).getRootElement(); + element = new SAXBuilder(false).build(new StringReader(s)).getRootElement(); + } + catch (JDOMException e) { + LOG.error("Can't parse YouTrack response for " + requestUrl, e); + throw e; + } + if ("error".equals(element.getName())) { + throw new Exception("Error from YouTrack for " + requestUrl + ": '" + element.getText() + "'"); + } + + List children = element.getChildren("issue"); + + final List tasks = ContainerUtil.mapNotNull(children, new NullableFunction() { + public Task fun(Element o) { + return createIssue(o); + } + }); + return tasks.toArray(new Task[tasks.size()]); + } + finally { + method.releaseConnection(); + } } @Nullable @@ -153,10 +149,16 @@ public class YouTrackRepository extends BaseRepositoryImpl { method.addParameter("password", getPassword()); client.getParams().setContentCharset("UTF-8"); client.executeMethod(method); - if (method.getStatusCode() != 200) { - throw new Exception("Cannot login: HTTP status code " + method.getStatusCode()); + String response; + try { + if (method.getStatusCode() != 200) { + throw new Exception("Cannot login: HTTP status code " + method.getStatusCode()); + } + response = method.getResponseBodyAsString(1000); + } + finally { + method.releaseConnection(); } - String response = method.getResponseBodyAsString(1000); if (response == null) { throw new NullPointerException(); } @@ -173,12 +175,23 @@ public class YouTrackRepository extends BaseRepositoryImpl { @Nullable public Task findTask(@NotNull String id) throws Exception { - HttpMethod method = doREST("/rest/issue/byid/" + id, false); - InputStream stream = method.getResponseBodyAsStream(); - Element element = new SAXBuilder(false).build(stream).getRootElement(); + final Element element = fetchRequestAsElement(id); return element.getName().equals("issue") ? createIssue(element) : null; } + @TestOnly + @NotNull + public Element fetchRequestAsElement(@NotNull String id) throws Exception { + final HttpMethod method = doREST("/rest/issue/byid/" + id, false); + try { + final InputStream stream = method.getResponseBodyAsStream(); + return new SAXBuilder(false).build(stream).getRootElement(); + } + finally { + method.releaseConnection(); + } + } + HttpMethod doREST(String request, boolean post) throws Exception { HttpClient client = login(new PostMethod(getUrl() + "/rest/user/login")); @@ -198,12 +211,28 @@ public class YouTrackRepository extends BaseRepositoryImpl { } @Override - public void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception { - String s = myCustomStateNames.get(state); - if (StringUtil.isEmpty(s)) { - s = state.name(); + public void setTaskState(@NotNull Task task, @NotNull CustomTaskState state) throws Exception { + doREST("/rest/issue/execute/" + task.getId() + "?command=" + encodeUrl("state " + state.getId()), true).releaseConnection(); + } + + @NotNull + @Override + public Set getAvailableTaskStates(@NotNull Task task) throws Exception { + final HttpMethod method = doREST("/rest/issue/" + task.getId() + "/execute/intellisense?command=" + encodeUrl("state "), false); + try { + final InputStream stream = method.getResponseBodyAsStream(); + final Element element = new SAXBuilder(false).build(stream).getRootElement(); + return ContainerUtil.map2Set(element.getChild("suggest").getChildren("item"), new Function() { + @Override + public CustomTaskState fun(Element element) { + final String stateName = element.getChildText("option"); + return new CustomTaskState(stateName, stateName); + } + }); + } + finally { + method.releaseConnection(); } - doREST("/rest/issue/execute/" + task.getId() + "?command=" + encodeUrl("state " + s), true); } @Nullable @@ -315,9 +344,7 @@ public class YouTrackRepository extends BaseRepositoryImpl { public boolean equals(Object o) { if (!super.equals(o)) return false; YouTrackRepository repository = (YouTrackRepository)o; - if (!Comparing.equal(repository.getDefaultSearch(), getDefaultSearch())) return false; - if (!Comparing.equal(repository.getCustomStateNames(), getCustomStateNames())) return false; - return true; + return Comparing.equal(repository.getDefaultSearch(), getDefaultSearch()); } private static final Logger LOG = Logger.getInstance("#com.intellij.tasks.youtrack.YouTrackRepository"); @@ -326,20 +353,30 @@ public class YouTrackRepository extends BaseRepositoryImpl { public void updateTimeSpent(@NotNull LocalTask task, @NotNull String timeSpent, @NotNull String comment) throws Exception { checkVersion(); final HttpMethod method = doREST("/rest/issue/execute/" + task.getId() + "?command=work+Today+" + timeSpent.replaceAll(" ", "+") + "+" + comment, true); - if (method.getStatusCode() != 200) { - InputStream stream = method.getResponseBodyAsStream(); - String message = new SAXBuilder(false).build(stream).getRootElement().getText(); - throw new Exception(message); + try { + if (method.getStatusCode() != 200) { + InputStream stream = method.getResponseBodyAsStream(); + String message = new SAXBuilder(false).build(stream).getRootElement().getText(); + throw new Exception(message); + } + } + finally { + method.releaseConnection(); } } private void checkVersion() throws Exception { HttpMethod method = doREST("/rest/workflow/version", false); - InputStream stream = method.getResponseBodyAsStream(); - Element element = new SAXBuilder(false).build(stream).getRootElement(); - final boolean timeTrackingAvailable = element.getName().equals("version") && VersionComparatorUtil.compare(element.getChildText("version"), "4.1") >= 0; - if (!timeTrackingAvailable) { - throw new Exception("This version of Youtrack the time tracking is not supported"); + try { + InputStream stream = method.getResponseBodyAsStream(); + Element element = new SAXBuilder(false).build(stream).getRootElement(); + final boolean timeTrackingAvailable = element.getName().equals("version") && VersionComparatorUtil.compare(element.getChildText("version"), "4.1") >= 0; + if (!timeTrackingAvailable) { + throw new Exception("This version of Youtrack the time tracking is not supported"); + } + } + finally { + method.releaseConnection(); } } @@ -347,26 +384,4 @@ public class YouTrackRepository extends BaseRepositoryImpl { protected int getFeatures() { return super.getFeatures() | TIME_MANAGEMENT | STATE_UPDATING; } - - public void setCustomStateNames(Map customStateNames) { - myCustomStateNames.putAll(customStateNames); - } - - @Tag("customStates") - @Property(surroundWithTag = false) - @MapAnnotation( - surroundWithTag = false, - keyAttributeName = "state", - valueAttributeName = "name", - surroundKeyWithTag = false, - surroundValueWithTag = false - ) - - public Map getCustomStateNames() { - return myCustomStateNames; - } - - public void setCustomStateName(TaskState state, String name) { - myCustomStateNames.put(state, name); - } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepositoryEditor.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepositoryEditor.java index db16ea5247bb..34ba0a773b5c 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepositoryEditor.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/youtrack/YouTrackRepositoryEditor.java @@ -3,10 +3,8 @@ package com.intellij.tasks.youtrack; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.tasks.TaskState; import com.intellij.tasks.config.BaseRepositoryEditor; import com.intellij.tasks.youtrack.lang.YouTrackLanguage; import com.intellij.ui.EditorTextField; @@ -17,14 +15,12 @@ import com.intellij.util.ui.FormBuilder; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Map; /** * @author Dmitry Avdeev */ public class YouTrackRepositoryEditor extends BaseRepositoryEditor { private static final Logger LOG = Logger.getInstance(YouTrackRepository.class); - private final YouTrackOptionsTab myOptions; private EditorTextField myDefaultSearch; private JBLabel mySearchLabel; @@ -36,17 +32,6 @@ public class YouTrackRepositoryEditor extends BaseRepositoryEditor states = myRepository.getCustomStateNames(); - myOptions.getInProgressState().setText(StringUtil.notNullize(states.get(TaskState.IN_PROGRESS))); - myOptions.getResolvedState().setText(StringUtil.notNullize(states.get(TaskState.RESOLVED))); - - installListener(myOptions.getInProgressState()); - installListener(myOptions.getResolvedState()); - - myTabbedPane.add("Options", myOptions.getRootPanel()); } @Override @@ -61,8 +46,6 @@ public class YouTrackRepositoryEditor extends BaseRepositoryEditor states = myRepository.getAvailableTaskStates(task); + final List stateNames = ContainerUtil.map(states, new Function() { + @Override + public String fun(CustomTaskState state) { + return state.getPresentableName(); + } + }); + assertContainsElements(stateNames, "North", "South"); + + // ? -> North + myRepository.setTaskState(task, NORTH_STATE); + Element element = myRepository.fetchRequestAsElement(REQUEST_WITH_CUSTOM_STATES_ID); + assertEquals("North", element.getAttributeValue("state")); + + // North -> Submitted + myRepository.setTaskState(task, SUBMITTED_STATE); + element = myRepository.fetchRequestAsElement(REQUEST_WITH_CUSTOM_STATES_ID); + assertEquals("Submitted", element.getAttributeValue("state")); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + myRepository = new YouTrackRepository(new YouTrackRepositoryType()); + myRepository.setUrl(YOUTRACK_4_TEST_SERVER_URL); + myRepository.setUsername("buildtest"); + myRepository.setPassword("buildtest"); + } +} diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java index 654b51261d88..d9150d342ce2 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java @@ -2,8 +2,10 @@ package com.intellij.tasks.integration.live; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.trello.TrelloRepository; import com.intellij.tasks.trello.TrelloRepositoryType; +import com.intellij.tasks.trello.TrelloTask; import com.intellij.tasks.trello.model.*; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -22,8 +24,9 @@ import static com.intellij.tasks.trello.model.TrelloLabel.LabelColor.*; */ public class TrelloIntegrationTest extends LiveIntegrationTestCase { - private static final String BOARD_1_NAME = "Board 1"; - private static final String BOARD_1_ID = "53c416a8a6e5a78753562043"; + // Basic functionality (searching, filtering, etc.) + private static final String BASIC_FUNCTIONALITY_BOARD_NAME = "Basic Functionality"; + private static final String BASIC_FUNCTIONALITY_BOARD_ID = "53c416a8a6e5a78753562043"; private static final String LIST_1_1_NAME = "List 1-1"; private static final String LIST_1_1_ID = "53c416a8a6e5a78753562044"; @@ -31,6 +34,17 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase boards = myRepository.fetchUserBoards(); - assertEquals(2, boards.size()); - assertObjectsNamed("All boards of the user should be included", boards, "Board 1", "Board 2"); + assertEquals(3, boards.size()); + assertObjectsNamed("All boards of the user should be included", boards, + BASIC_FUNCTIONALITY_BOARD_NAME, LABELS_AND_COLORS_BOARD_NAME, STATE_UPDATES_BOARD_NAME); } public void testFetchListsOfBoard() throws Exception { - TrelloBoard selectedBoard = myRepository.fetchBoardById(BOARD_1_ID); + TrelloBoard selectedBoard = myRepository.fetchBoardById(BASIC_FUNCTIONALITY_BOARD_ID); assertNotNull(selectedBoard); myRepository.setCurrentBoard(selectedBoard); List lists = myRepository.fetchBoardLists(); @@ -88,7 +103,7 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase fetchCards(@Nullable String boardId, @Nullable String listId, boolean withClosed) throws Exception { if (boardId != null) { - TrelloBoard selectedBoard = myRepository.fetchBoardById(BOARD_1_ID); + TrelloBoard selectedBoard = myRepository.fetchBoardById(BASIC_FUNCTIONALITY_BOARD_ID); assertNotNull(selectedBoard); myRepository.setCurrentBoard(selectedBoard); } @@ -108,24 +123,24 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase cards = fetchCards(BOARD_1_ID, null, true); + List cards = fetchCards(BASIC_FUNCTIONALITY_BOARD_ID, null, true); assertObjectsNamed("All cards of the board should be included", cards, "Card 1-1-1", "Card 1-1-2", "Card 1-2-1", "Card 1-3-1", "Archived Card"); } public void testCardsFilteringByMembership() throws Exception { myRepository.setIncludeAllCards(true); - List allCards = fetchCards(BOARD_1_ID, LIST_1_1_ID, true); + List allCards = fetchCards(BASIC_FUNCTIONALITY_BOARD_ID, LIST_1_1_ID, true); assertObjectsNamed("All cards of the list should be included", allCards, "Card 1-1-1", "Card 1-1-2", "Archived Card"); myRepository.setIncludeAllCards(false); - List assignedCards = fetchCards(BOARD_1_ID, LIST_1_1_ID, true); + List assignedCards = fetchCards(BASIC_FUNCTIONALITY_BOARD_ID, LIST_1_1_ID, true); assertObjectsNamed("Only cards of the list assigned to user should be included", assignedCards, "Card 1-1-1"); } public void testCardsFilteringByStatus() throws Exception { myRepository.setIncludeAllCards(true); - List allCards = fetchCards(BOARD_1_ID, LIST_1_1_NAME, true); + List allCards = fetchCards(BASIC_FUNCTIONALITY_BOARD_ID, LIST_1_1_NAME, true); assertObjectsNamed("All cards of the list should be included", allCards, "Card 1-1-1", "Card 1-1-2", "Archived Card"); TrelloCard card = ContainerUtil.find(allCards, new Condition() { @@ -139,8 +154,17 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase labels = card.getLabels(); @@ -156,13 +180,41 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase states = myRepository.getAvailableTaskStates(task); + assertEquals(1, states.size()); + final CustomTaskState inProgressState = states.iterator().next(); + assertEquals(IN_PROGRESS_LIST_ID, inProgressState.getId()); + assertEquals("In Progress", inProgressState.getPresentableName()); + + // Backlog -> In Progress + myRepository.setTaskState(task, inProgressState); + card = myRepository.fetchCardById(FEATURE_CARD_ID); + assertNotNull(card); + assertEquals(STATE_UPDATES_BOARD_ID, card.getIdBoard()); + assertEquals(IN_PROGRESS_LIST_ID, card.getIdList()); + + // Discover "Backlog" list + task = new TrelloTask(card, myRepository); + states = myRepository.getAvailableTaskStates(task); + assertEquals(1, states.size()); + final CustomTaskState backlogState = states.iterator().next(); + assertEquals(BACKLOG_LIST_ID, backlogState.getId()); + assertEquals("Backlog", backlogState.getPresentableName()); + + // In Progress -> Backlog + myRepository.setTaskState(task, backlogState); + card = myRepository.fetchCardById(FEATURE_CARD_ID); + assertNotNull(card); + assertEquals(STATE_UPDATES_BOARD_ID, card.getIdBoard()); + assertEquals(BACKLOG_LIST_ID, card.getIdList()); } static void assertObjectsNamed(@NotNull String message, @NotNull Collection objects, @NotNull String... names) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/palette/Palette.java b/plugins/ui-designer/src/com/intellij/uiDesigner/palette/Palette.java index abe744594ca7..4627efd195f0 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/palette/Palette.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/palette/Palette.java @@ -65,6 +65,7 @@ import java.util.Map; */ @State( name = "Palette2", + defaultStateAsResource = true, storages = { @Storage(file = StoragePathMacros.PROJECT_FILE), @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/uiDesigner.xml", scheme = StorageScheme.DIRECTORY_BASED) diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/StudyUtils.java index 52e83b4990dd..99e4d058c6d2 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/StudyUtils.java @@ -3,7 +3,6 @@ package com.jetbrains.edu.learning; import com.intellij.execution.RunContentExecutor; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.ProcessHandler; -import com.intellij.ide.SaveAndSyncHandlerImpl; import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; @@ -12,7 +11,6 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; @@ -21,7 +19,6 @@ import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.ui.JBColor; import com.intellij.util.ui.UIUtil; @@ -120,12 +117,6 @@ public class StudyUtils { getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW)); } - public static void synchronize() { - FileDocumentManager.getInstance().saveAllDocuments(); - SaveAndSyncHandlerImpl.refreshOpenFiles(); - VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); - } - public static void deleteFile(@NotNull final VirtualFile file) { try { file.delete(StudyUtils.class); diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/actions/StudyEditInputAction.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/actions/StudyEditInputAction.java index 26c136b48005..24d6e31f3fb6 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/actions/StudyEditInputAction.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/actions/StudyEditInputAction.java @@ -21,6 +21,7 @@ import com.intellij.ui.tabs.TabsListener; import com.intellij.ui.tabs.impl.JBEditorTabs; import com.intellij.util.PlatformIcons; import com.jetbrains.edu.EduNames; +import com.jetbrains.edu.EduUtils; import com.jetbrains.edu.courseFormat.Task; import com.jetbrains.edu.courseFormat.TaskFile; import com.jetbrains.edu.learning.StudyTaskManager; @@ -120,7 +121,7 @@ public class StudyEditInputAction extends DumbAwareAction { finally { StudyUtils.closeSilently(printWriter); } - StudyUtils.synchronize(); + EduUtils.synchronize(); } private static UserTest createUserTest(@NotNull final VirtualFile testsDir, @@ -208,7 +209,7 @@ public class StudyEditInputAction extends DumbAwareAction { File testInputFile = new File(userTest.getInput()); File testOutputFile = new File(userTest.getOutput()); if (testInputFile.delete() && testOutputFile.delete()) { - StudyUtils.synchronize(); + EduUtils.synchronize(); } else { LOG.error("failed to delete user tests"); } diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java index 912269d3b446..1a04083a612e 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java @@ -4,59 +4,21 @@ package com.jetbrains.edu.learning.editor; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.event.EditorFactoryEvent; import com.intellij.openapi.editor.event.EditorFactoryListener; -import com.intellij.openapi.editor.event.EditorMouseAdapter; -import com.intellij.openapi.editor.event.EditorMouseEvent; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.problems.WolfTheProblemSolver; -import com.intellij.ui.JBColor; -import com.jetbrains.edu.EduAnswerPlaceholderPainter; import com.jetbrains.edu.EduDocumentListener; -import com.jetbrains.edu.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.courseFormat.TaskFile; -import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.navigation.StudyNavigator; import org.jetbrains.annotations.NotNull; -import java.awt.*; - public class StudyEditorFactoryListener implements EditorFactoryListener { - /** - * draws selected task window if there is one located in mouse position - */ - private static class WindowSelectionListener extends EditorMouseAdapter { - private final TaskFile myTaskFile; - - WindowSelectionListener(@NotNull final TaskFile taskFile) { - myTaskFile = taskFile; - } - - @Override - public void mouseClicked(EditorMouseEvent e) { - final Editor editor = e.getEditor(); - final Point point = e.getMouseEvent().getPoint(); - final LogicalPosition pos = editor.xyToLogicalPosition(point); - final AnswerPlaceholder answerPlaceholder = myTaskFile.getAnswerPlaceholder(editor.getDocument(), pos); - if (answerPlaceholder != null) { - myTaskFile.setSelectedAnswerPlaceholder(answerPlaceholder); - final Project project = editor.getProject(); - assert project != null; - final JBColor color = StudyTaskManager.getInstance(project).getColor(answerPlaceholder); - EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, true, color); - } - else { - StudyUtils.drawAllWindows(editor, myTaskFile); - } - } - } - @Override public void editorCreated(@NotNull final EditorFactoryEvent event) { final Editor editor = event.getEditor(); @@ -78,7 +40,6 @@ public class StudyEditorFactoryListener implements EditorFactoryListener { final TaskFile taskFile = StudyUtils.getTaskFile(project, openedFile); if (taskFile != null) { StudyNavigator.navigateToFirstAnswerPlaceholder(editor, taskFile); - editor.addEditorMouseListener(new WindowSelectionListener(taskFile)); StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile)); WolfTheProblemSolver.getInstance(project).clearProblems(openedFile); StudyUtils.drawAllWindows(editor, taskFile); diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/run/StudySmartChecker.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/run/StudySmartChecker.java index 43928034db0f..bf2b59999b11 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/run/StudySmartChecker.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/run/StudySmartChecker.java @@ -27,25 +27,28 @@ public class StudySmartChecker { private StudySmartChecker() { } + private static final Logger LOG = Logger.getInstance(StudySmartChecker.class); public static void smartCheck(@NotNull final AnswerPlaceholder placeholder, - @NotNull final Project project, - @NotNull final VirtualFile answerFile, - @NotNull final TaskFile answerTaskFile, - @NotNull final TaskFile usersTaskFile, - @NotNull final StudyTestRunner testRunner, - @NotNull final VirtualFile virtualFile, - @NotNull final Document usersDocument) { + @NotNull final Project project, + @NotNull final VirtualFile answerFile, + @NotNull final TaskFile answerTaskFile, + @NotNull final TaskFile usersTaskFile, + @NotNull final StudyTestRunner testRunner, + @NotNull final VirtualFile virtualFile, + @NotNull final Document usersDocument) { try { final int index = placeholder.getIndex(); + String windowCopyName = answerFile.getNameWithoutExtension() + index + EduNames.WINDOW_POSTFIX + answerFile.getExtension(); final VirtualFile windowCopy = - answerFile.copy(project, answerFile.getParent(), answerFile.getNameWithoutExtension() + index + EduNames.WINDOW_POSTFIX); + answerFile.copy(project, answerFile.getParent(), windowCopyName); final FileDocumentManager documentManager = FileDocumentManager.getInstance(); final Document windowDocument = documentManager.getDocument(windowCopy); if (windowDocument != null) { - final File resourceFile = StudyUtils.copyResourceFile(virtualFile.getName(), windowCopy.getName(), project, usersTaskFile.getTask()); + final File resourceFile = + StudyUtils.copyResourceFile(virtualFile.getName(), windowCopy.getName(), project, usersTaskFile.getTask()); final TaskFile windowTaskFile = new TaskFile(); TaskFile.copy(answerTaskFile, windowTaskFile); EduDocumentListener listener = new EduDocumentListener(windowTaskFile); @@ -85,5 +88,4 @@ public class StudySmartChecker { LOG.error(e); } } - } diff --git a/python/educational/src/com/jetbrains/edu/EduAnswerPlaceholderPainter.java b/python/educational/src/com/jetbrains/edu/EduAnswerPlaceholderPainter.java index 49921f2b37eb..25d1783f74ff 100644 --- a/python/educational/src/com/jetbrains/edu/EduAnswerPlaceholderPainter.java +++ b/python/educational/src/com/jetbrains/edu/EduAnswerPlaceholderPainter.java @@ -49,7 +49,6 @@ public class EduAnswerPlaceholderPainter { g.drawRect(point.x, point.y - 2, (pointEnd.x - point.x), editor.getLineHeight() + 1); } }); - editor.getCaretModel().moveToOffset(startOffset); highlighter.setGreedyToLeft(true); highlighter.setGreedyToRight(true); } diff --git a/python/educational/src/com/jetbrains/edu/EduNames.java b/python/educational/src/com/jetbrains/edu/EduNames.java index 8295735ca9d0..882a2ef9e7ef 100644 --- a/python/educational/src/com/jetbrains/edu/EduNames.java +++ b/python/educational/src/com/jetbrains/edu/EduNames.java @@ -25,7 +25,7 @@ public class EduNames { public static final String TEST_TAB_NAME = "test"; public static final String USER_TEST_INPUT = "input"; public static final String USER_TEST_OUTPUT = "output"; - public static final String WINDOW_POSTFIX = "_window.py"; + public static final String WINDOW_POSTFIX = "_window."; public static final String TASK = "task"; public static final String USER_TESTS = "userTests"; public static final String SANDBOX_DIR = "Sandbox"; diff --git a/python/educational/src/com/jetbrains/edu/EduUtils.java b/python/educational/src/com/jetbrains/edu/EduUtils.java index ab2114f70431..3fc34c3e52e7 100644 --- a/python/educational/src/com/jetbrains/edu/EduUtils.java +++ b/python/educational/src/com/jetbrains/edu/EduUtils.java @@ -1,6 +1,6 @@ package com.jetbrains.edu; -import com.intellij.ide.SaveAndSyncHandlerImpl; +import com.intellij.ide.SaveAndSyncHandler; import com.intellij.ide.projectView.actions.MarkRootActionBase; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; @@ -131,7 +131,7 @@ public class EduUtils { public static void synchronize() { FileDocumentManager.getInstance().saveAllDocuments(); - SaveAndSyncHandlerImpl.refreshOpenFiles(); + SaveAndSyncHandler.getInstance().refreshOpenFiles(); VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); } diff --git a/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java b/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java index 161dc10b059b..38815badc45b 100644 --- a/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java +++ b/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java @@ -15,14 +15,18 @@ public class CourseInfo { private String myName; @SerializedName("summary") private String myDescription; + @SerializedName("course_format") + //course type in format "pycharm " + private String myType; private String myAuthor; - public static CourseInfo INVALID_COURSE = new CourseInfo("", "", ""); + public static CourseInfo INVALID_COURSE = new CourseInfo("", "", "", ""); - public CourseInfo(String name, String author, String description) { + public CourseInfo(String name, String author, String description, String type) { myName = name; myAuthor = author; myDescription = description; + myType = type; } public String getName() { @@ -37,6 +41,10 @@ public class CourseInfo { return myDescription; } + public String getType() { + return myType; + } + @Override public String toString() { return myName; diff --git a/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java b/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java index a6e45bbd7c03..56bd969aa9f8 100644 --- a/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java +++ b/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java @@ -41,6 +41,8 @@ public class EduStepicConnector { private static final String ourDomain = "stepic.org"; private static String ourSessionId = "524iethiwju2tjywaqmf7tbwx0p0jk1b"; private static String ourCSRFToken = "LJ9n6OyLVA7hxU94dlYWUu65MF51Nx37"; + //this prefix indicates that course can be opened by educational plugin + public static final String PYCHARM_PREFIX = "pycharm "; private EduStepicConnector() { } @@ -84,7 +86,8 @@ public class EduStepicConnector { course.setAuthor(info.getAuthor()); course.setDescription(info.getDescription()); course.setName(info.getName()); - course.setLanguage("Python"); // TODO: get from stepic + String courseType = info.getType(); + course.setLanguage(courseType.substring(PYCHARM_PREFIX.length())); course.setUpToDate(true); // TODO: get from stepic try { for (Integer section : info.sections) { diff --git a/python/ide/src/com/jetbrains/python/configuration/PyContentEntriesModuleConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyContentEntriesModuleConfigurable.java index a048894adf1a..1e8c8e24a247 100644 --- a/python/ide/src/com/jetbrains/python/configuration/PyContentEntriesModuleConfigurable.java +++ b/python/ide/src/com/jetbrains/python/configuration/PyContentEntriesModuleConfigurable.java @@ -104,8 +104,9 @@ public class PyContentEntriesModuleConfigurable extends SearchableConfigurable.P @Override public void apply() throws ConfigurationException { if (myEditor == null) return; + final boolean editorWasModified = myEditor.isModified(); myEditor.apply(); - if (myModifiableModel.isChanged()) { + if (editorWasModified) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index cd2c6e2f0b4d..fce54b4e6581 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -98,7 +98,7 @@ public class RemoteDebugger implements ProcessDebugger { if (myConnected) { try { - myDebuggerReader = createReader(mySocket); + myDebuggerReader = createReader(); } catch (Exception e) { synchronized (mySocketObject) { @@ -231,7 +231,9 @@ public class RemoteDebugger implements ProcessDebugger { private void cleanUp() { myThreads.clear(); myResponseQueue.clear(); - mySequence = -1; + synchronized (mySequenceObject) { + mySequence = -1; + } myTempVars.clear(); } @@ -477,10 +479,10 @@ public class RemoteDebugger implements ProcessDebugger { execute(command); } - public DebuggerReader createReader(@NotNull Socket socket) throws IOException { + private DebuggerReader createReader() throws IOException { synchronized (mySocketObject) { //noinspection IOResourceOpenedButNotSafelyClosed - return new DebuggerReader(socket.getInputStream()); + return new DebuggerReader(mySocket.getInputStream()); } } @@ -488,7 +490,7 @@ public class RemoteDebugger implements ProcessDebugger { private StringBuilder myTextBuilder = new StringBuilder(); private DebuggerReader(final InputStream stream) throws IOException { - super(stream, CharsetToolkit.UTF8_CHARSET); //TODO: correct encoding? + super(stream, CharsetToolkit.UTF8_CHARSET, SleepingPolicy.BLOCKING); //TODO: correct encoding? start(); } diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java index 8e2525c5bd87..a0e196237cc7 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyDocStringTypeProvider.java @@ -40,6 +40,7 @@ public class NumpyDocStringTypeProvider extends PyTypeProviderBase { static { NUMPY_ALIAS_TO_REAL_TYPE.put("ndarray", "numpy.core.multiarray.ndarray"); + NUMPY_ALIAS_TO_REAL_TYPE.put("numpy.ndarray", "numpy.core.multiarray.ndarray"); // 184 occurrences NUMPY_ALIAS_TO_REAL_TYPE.put("array_like", "collections.Iterable or int or long or float or complex"); // Parameters marked as 'data-type' actually get any Python type identifier such as 'bool' or @@ -49,7 +50,8 @@ public class NumpyDocStringTypeProvider extends PyTypeProviderBase { // 16 occurrences NUMPY_ALIAS_TO_REAL_TYPE.put("scalar", "int or long or float or complex"); // 10 occurrences - NUMPY_ALIAS_TO_REAL_TYPE.put("array", "collections.Iterable"); + NUMPY_ALIAS_TO_REAL_TYPE.put("array", "numpy.core.multiarray.ndarray"); + NUMPY_ALIAS_TO_REAL_TYPE.put("numpy.array", "numpy.core.multiarray.ndarray"); // 9 occurrences NUMPY_ALIAS_TO_REAL_TYPE.put("any", "object"); // 5 occurrences diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java index da7855a101c8..6db3ccf05b68 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java @@ -35,7 +35,7 @@ public class NumpyModuleMembersProvider extends PyModuleMembersProvider { "int8", "int16", "int32", "int64", "int128", "uint8", "uint16", "uint32", "uint64", "uint128", "float16", "float32", "float64", "float80", "float96", "float128", "float256", - "complex32", "complex64", "complex128", "complex160", "complex192", "complex256", "complex512" + "complex32", "complex64", "complex128", "complex160", "complex192", "complex256", "complex512", "double" }; @Override diff --git a/python/src/com/jetbrains/numpy/documentation/NumPyDocString.java b/python/src/com/jetbrains/numpy/documentation/NumPyDocString.java index 5bb2881d1f56..72ab80c195a0 100644 --- a/python/src/com/jetbrains/numpy/documentation/NumPyDocString.java +++ b/python/src/com/jetbrains/numpy/documentation/NumPyDocString.java @@ -17,12 +17,12 @@ package com.jetbrains.numpy.documentation; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyPsiFacade; -import com.intellij.psi.util.QualifiedName; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -283,6 +283,10 @@ public class NumPyDocString { if (index >= 0) { return typeString.substring(0, index); } + index = typeString.indexOf(" of "); // e.g. ndarray of dtype float + if (index >= 0) { + return typeString.substring(0, index); + } return typeString; } diff --git a/python/src/com/jetbrains/python/console/parsing/PyConsoleParser.java b/python/src/com/jetbrains/python/console/parsing/PyConsoleParser.java index 3f30d60aa406..100330608c73 100644 --- a/python/src/com/jetbrains/python/console/parsing/PyConsoleParser.java +++ b/python/src/com/jetbrains/python/console/parsing/PyConsoleParser.java @@ -55,7 +55,6 @@ public class PyConsoleParser extends PyParser{ StatementParsing stmt_parser = context.getStatementParser(); builder.setTokenTypeRemapper(stmt_parser); // must be done before touching the caching lexer with eof() call. - builder.setDebugMode(true); while (!builder.eof()) { stmt_parser.parseStatement(context.emptyParsingScope()); } diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 6cbae17aca64..780ac5997985 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -37,7 +37,10 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.ResolveState; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.remote.RemoteProcessHandlerBase; @@ -52,7 +55,6 @@ import com.intellij.xdebugger.frame.XValueChildrenList; import com.intellij.xdebugger.impl.XSourcePositionImpl; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; import com.jetbrains.python.PythonFileType; -import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.console.PythonDebugLanguageConsoleView; import com.jetbrains.python.console.pydev.PydevCompletionVariant; import com.jetbrains.python.debugger.pydev.*; @@ -801,7 +803,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr @Nullable - public XSourcePosition getCurrentFrameSourcePosition() { + private XSourcePosition getCurrentFrameSourcePosition() { try { PyStackFrame frame = currentFrame(); @@ -862,21 +864,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr return null; } - VirtualFile virtualFile = currentPosition.getFile(); - - final Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - if (document == null) { - return null; - } - final FileViewProvider viewProvider = PsiManager.getInstance(getProject()).findViewProvider(virtualFile); - if (viewProvider == null) { - return null; - } - final PsiFile file = viewProvider.getPsi(PythonLanguage.getInstance()); - if (file == null) { - return null; - } - return file; + return PsiManager.getInstance(getProject()).findFile(currentPosition.getFile()); } diff --git a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java index 45ae96f53caf..8c0c38f21410 100644 --- a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java +++ b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java @@ -25,6 +25,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; @@ -38,6 +39,7 @@ import com.jetbrains.python.facet.PythonPathContributingFacet; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyImportResolver; +import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -246,6 +248,9 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso if (!myWithoutRoots) { addResultsFromRoots(); } + else if (footholdFile != null) { + addRelativeImportResultsFromSkeletons(footholdFile); + } mySourceResults.addAll(myLibResults); myLibResults.clear(); @@ -268,6 +273,35 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso return results; } + /** + * Resolve relative imports from sdk root to the skeleton dir + */ + private void addRelativeImportResultsFromSkeletons(@NotNull final PsiFile foothold) { + final boolean inSource = FileIndexFacade.getInstance(foothold.getProject()).isInContent(foothold.getVirtualFile()); + if (inSource) return; + PsiDirectory containingDirectory = foothold.getContainingDirectory(); + if (myRelativeLevel > 0) { + containingDirectory = ResolveImportUtil.stepBackFrom(foothold, myRelativeLevel); + } + if (containingDirectory != null) { + final QualifiedName containingQName = QualifiedNameFinder.findCanonicalImportPath(containingDirectory, null); + if (containingQName != null && containingQName.getComponentCount() > 0) { + final QualifiedName absoluteQName = containingQName.append(myQualifiedName.toString()); + final QualifiedNameResolverImpl absoluteVisitor = + (QualifiedNameResolverImpl)new QualifiedNameResolverImpl(absoluteQName).fromElement(foothold); + + final Sdk sdk = PythonSdkType.getSdk(foothold); + if (sdk == null) return; + final VirtualFile skeletonsDir = PySdkUtil.findSkeletonsDir(sdk); + if (skeletonsDir == null) return; + final PsiDirectory directory = myContext.getPsiManager().findDirectory(skeletonsDir); + final PsiElement psiElement = absoluteVisitor.resolveModuleAt(directory); + if (psiElement != null) + myLibResults.add(psiElement); + } + } + } + private void addResultsFromRoots() { if (myVisitAllModules) { for (Module mod : ModuleManager.getInstance(myContext.getProject()).getModules()) { diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 1a75492f2985..068de2449cf8 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -22,6 +22,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; @@ -215,6 +216,10 @@ public class ResolveImportUtil { @NotNull private static List resolveRelativeImportAsAbsolute(@NotNull PsiFile foothold, @NotNull QualifiedName qualifiedName) { + final VirtualFile virtualFile = foothold.getVirtualFile(); + if (virtualFile == null) return Collections.emptyList(); + final boolean inSource = FileIndexFacade.getInstance(foothold.getProject()).isInContent(virtualFile); + if (inSource) return Collections.emptyList(); final PsiDirectory containingDirectory = foothold.getContainingDirectory(); if (containingDirectory != null) { final QualifiedName containingPath = QualifiedNameFinder.findCanonicalImportPath(containingDirectory, null); diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMembersRefactoringBaseProcessor.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMembersRefactoringBaseProcessor.java index db53fe6bebae..4a8235042137 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMembersRefactoringBaseProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/PyMembersRefactoringBaseProcessor.java @@ -18,12 +18,15 @@ package com.jetbrains.python.refactoring.classes.membersManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.refactoring.BaseRefactoringProcessor; +import com.intellij.refactoring.listeners.RefactoringEventData; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewDescriptor; +import com.intellij.util.Function; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyElement; import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -98,4 +101,27 @@ public abstract class PyMembersRefactoringBaseProcessor extends BaseRefactoringP MembersManager.moveAllMembers(myMembersToMove, myFrom, destinations.toArray(new PyClass[destinations.size()])); PyClassRefactoringUtil.optimizeImports(myFrom.getContainingFile()); // To remove unneeded imports } + + @Nullable + @Override + protected RefactoringEventData getBeforeData() { + RefactoringEventData data = new RefactoringEventData(); + data.addElement(myFrom); + data.addMembers(myMembersToMove.toArray(new PyMemberInfo[myMembersToMove.size()]), new Function() { + @Override + public PsiElement fun(PyMemberInfo info) { + return info.getMember(); + } + }); + return data; + } + + + @Nullable + @Override + protected RefactoringEventData getAfterData(UsageInfo[] usages) { + final RefactoringEventData data = new RefactoringEventData(); + data.addElements(myTo); + return data; + } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpProcessor.java b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpProcessor.java index 3b569e5d57e2..5fdb4e6f37c4 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/classes/pullUp/PyPullUpProcessor.java @@ -57,4 +57,10 @@ class PyPullUpProcessor extends PyMembersRefactoringBaseProcessor { public String getCommentReferencesText(final int usagesCount, final int filesCount) { return getCodeReferencesText(usagesCount, filesCount); } + + @Nullable + @Override + protected String getRefactoringId() { + return "refactoring.python.pull.up"; + } } diff --git a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java index f3919d39ce59..4f03783f3ccc 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java +++ b/python/src/com/jetbrains/python/refactoring/classes/pushDown/PyPushDownProcessor.java @@ -75,4 +75,10 @@ public class PyPushDownProcessor extends PyMembersRefactoringBaseProcessor { protected String getCommandName() { return PyPushDownHandler.REFACTORING_NAME; } + + @Nullable + @Override + protected String getRefactoringId() { + return "refactoring.python.push.down"; + } } diff --git a/resources-en/src/inspectionDescriptions/SuspiciousLocalesLanguages.html b/resources-en/src/inspectionDescriptions/SuspiciousLocalesLanguages.html new file mode 100644 index 000000000000..3e24e5e5951e --- /dev/null +++ b/resources-en/src/inspectionDescriptions/SuspiciousLocalesLanguages.html @@ -0,0 +1,5 @@ + + +Inspection detects locales which contain language codes not supported by Java. + + \ No newline at end of file diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 333d87167237..b9db52d3b9eb 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -273,8 +273,6 @@ - - @@ -1343,8 +1341,6 @@ - diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index 149611088058..208f77a1d8b5 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -180,7 +180,6 @@ - diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlTagNameSynchronizer.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlTagNameSynchronizer.java index b41845573d7f..8cf80b20178f 100644 --- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlTagNameSynchronizer.java +++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlTagNameSynchronizer.java @@ -30,6 +30,8 @@ import com.intellij.openapi.command.CommandAdapter; import com.intellij.openapi.command.CommandEvent; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.diagnostic.Attachment; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; @@ -58,6 +60,7 @@ import java.util.Set; * @author Dennis.Ushakov */ public class XmlTagNameSynchronizer extends CommandAdapter implements ApplicationComponent { + private static final Logger LOG = Logger.getInstance(XmlTagNameSynchronizer.class); private static final Set SUPPORTED_LANGUAGES = ContainerUtil.set(HTMLLanguage.INSTANCE.getID(), XMLLanguage.INSTANCE.getID(), XHTMLLanguage.INSTANCE.getID(), @@ -76,14 +79,14 @@ public class XmlTagNameSynchronizer extends CommandAdapter implements Applicatio @Override public void editorReleased(@NotNull EditorFactoryEvent event) { - uninstallSynchronizer(event); + uninstallSynchronizer(event.getEditor()); } }, ApplicationManager.getApplication()); processor.addCommandListener(this); } - public void uninstallSynchronizer(@NotNull EditorFactoryEvent event) { - final Document document = event.getEditor().getDocument(); + public void uninstallSynchronizer(final Editor editor) { + final Document document = editor.getDocument(); final TagNameSynchronizer synchronizer = findSynchronizer(document); if (synchronizer != null) { synchronizer.clearMarkers(); @@ -91,7 +94,7 @@ public class XmlTagNameSynchronizer extends CommandAdapter implements Applicatio document.putUserData(SYNCHRONIZER_KEY, null); } - private void installSynchronizer(Editor editor) { + private void installSynchronizer(final Editor editor) { final Project project = editor.getProject(); if (project == null) return; @@ -102,7 +105,7 @@ public class XmlTagNameSynchronizer extends CommandAdapter implements Applicatio } private static Language findXmlLikeLanguage(Project project, VirtualFile file) { - final PsiFile psiFile = file != null ? PsiManager.getInstance(project).findFile(file) : null; + final PsiFile psiFile = file != null && file.isValid() ? PsiManager.getInstance(project).findFile(file) : null; if (psiFile != null) { for (Language language : psiFile.getViewProvider().getLanguages()) { if (SUPPORTED_LANGUAGES.contains(language.getID())) return language; @@ -265,12 +268,17 @@ public class XmlTagNameSynchronizer extends CommandAdapter implements Applicatio int start = -1; int end = -1; for (int i = offset - 1; i >= Math.max(0, offset - 50); i--) { - final char c = sequence.charAt(i); - if (c == '<' || (c == '/' && i > 0 && sequence.charAt(i - 1) == '<')) { - start = i + 1; - break; + try { + final char c = sequence.charAt(i); + if (c == '<' || (c == '/' && i > 0 && sequence.charAt(i - 1) == '<')) { + start = i + 1; + break; + } + if (!XmlUtil.isValidTagNameChar(c)) break; + } catch (IndexOutOfBoundsException e) { + LOG.error("incorrect offset:" + i + ", initial: " + offset, new Attachment("document.txt", sequence.toString())); + return null; } - if (!XmlUtil.isValidTagNameChar(c)) break; } if (start < 0) return null; for (int i = offset; i < Math.min(document.getTextLength(), offset + 50); i++) { diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java index 100cc9400918..f08a52c3a63f 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java +++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java @@ -74,6 +74,7 @@ public class XmlEmmetParser extends EmmetParser { put("object", "param"); put("map", "area"); }}; + private boolean isHtml; public XmlEmmetParser(List tokens, CustomTemplateCallback callback, @@ -84,6 +85,7 @@ public class XmlEmmetParser extends EmmetParser { if (surroundWithTemplate && parentTag != null && context.getNode().getElementType() == XmlTokenType.XML_START_TAG_START) { parentTag = PsiTreeUtil.getParentOfType(parentTag, XmlTag.class); } + isHtml = generator.isHtml(callback); if (parentTag != null) { hasTagContext = true; tagLevel.push(parentTag.getName()); @@ -210,7 +212,7 @@ public class XmlEmmetParser extends EmmetParser { @Nullable private String getDefaultTemplateKey() { - return ZenCodingUtil.isHtml(myCallback) ? suggestTagName() : null; + return isHtml ? suggestTagName() : null; } @Nullable diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java index 0434ea054e07..346c1528fee9 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java +++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/XmlZenCodingGenerator.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.template.emmet.generators; import com.intellij.application.options.emmet.EmmetOptions; import com.intellij.codeInsight.template.CustomTemplateCallback; import com.intellij.codeInsight.template.emmet.ZenCodingTemplate; +import com.intellij.codeInsight.template.emmet.ZenCodingUtil; import com.intellij.codeInsight.template.emmet.tokens.TemplateToken; import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.diagnostic.AttachmentFactory; @@ -124,4 +125,9 @@ public abstract class XmlZenCodingGenerator extends ZenCodingGenerator { public void disableEmmet() { EmmetOptions.getInstance().setEmmetEnabled(false); } + + @Override + public boolean isHtml(@NotNull CustomTemplateCallback callback) { + return ZenCodingUtil.isHtml(callback); + } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java index e333a0f1bc29..025bae895a02 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java +++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/generators/ZenCodingGenerator.java @@ -148,6 +148,10 @@ public abstract class ZenCodingGenerator { return false; } + public boolean isHtml(@NotNull CustomTemplateCallback callback) { + return false; + } + public void disableEmmet() { } } diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java index f83263a72b91..be969593947e 100644 --- a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java +++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/GenerationNode.java @@ -49,6 +49,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.*; import com.intellij.util.LocalTimeCounter; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; @@ -276,6 +277,8 @@ public class GenerationNode extends UserDataHolderBase { /*assert generator == null || generator instanceof XmlZenCodingGenerator : "The generator cannot process TemplateToken because it doesn't inherit XmlZenCodingGenerator";*/ + ZenCodingGenerator zenCodingGenerator = ObjectUtils.notNull(generator, XmlZenCodingGeneratorImpl.INSTANCE); + Map attributes = token.getAttributes(); TemplateImpl template = token.getTemplate(); assert template != null; @@ -307,7 +310,7 @@ public class GenerationNode extends UserDataHolderBase { } } XmlTag tag1 = hasChildren ? expandEmptyTagIfNecessary(tag) : tag; - setAttributeValues(tag1, attributes, callback); + setAttributeValues(tag1, attributes, callback, zenCodingGenerator.isHtml(callback)); XmlFile physicalFile = (XmlFile)fileFactory.createFileFromText(HTMLLanguage.INSTANCE, tag1.getContainingFile().getText()); VirtualFile vFile = physicalFile.getVirtualFile(); if (vFile != null) { @@ -315,7 +318,6 @@ public class GenerationNode extends UserDataHolderBase { } token.setFile(physicalFile); } - ZenCodingGenerator zenCodingGenerator = generator != null ? generator : XmlZenCodingGeneratorImpl.INSTANCE; template = zenCodingGenerator.generateTemplate(token, hasChildren, callback.getContext()); removeVariablesWhichHasNoSegment(template); return template; @@ -445,7 +447,10 @@ public class GenerationNode extends UserDataHolderBase { return predefinedValues; } - private void setAttributeValues(@NotNull XmlTag tag, @NotNull final Map attributes, CustomTemplateCallback callback) { + private void setAttributeValues(@NotNull XmlTag tag, + @NotNull final Map attributes, + @NotNull CustomTemplateCallback callback, + boolean isHtml) { // default and implied attributes final String defaultAttributeValue = attributes.get(XmlEmmetParser.DEFAULT_ATTRIBUTE_NAME); if (defaultAttributeValue != null) { @@ -495,7 +500,7 @@ public class GenerationNode extends UserDataHolderBase { myContainsSurroundedTextMarker = true; } - if (isBooleanAttribute(attributeValue, xmlAttribute, callback)) { + if (isHtml && isBooleanAttribute(attributeValue, xmlAttribute, callback)) { if (HtmlUtil.isShortNotationOfBooleanAttributePreferred()) { if (xmlAttributeValueElement != null) { final PsiElement prevSibling = xmlAttributeValueElement.getPrevSibling(); @@ -536,7 +541,7 @@ public class GenerationNode extends UserDataHolderBase { if (XmlEmmetParser.BOOLEAN_ATTRIBUTE_VALUE.equals(attributeValue)) { return true; } - if (ZenCodingUtil.isHtml(callback) && StringUtil.isEmpty(attributeValue)) { + if (StringUtil.isEmpty(attributeValue)) { final XmlAttributeDescriptor descriptor = xmlAttribute.getDescriptor(); return descriptor != null && HtmlUtil.isBooleanAttribute(descriptor, callback.getContext()); } diff --git a/xml/impl/src/com/intellij/javaee/ExternalResourcesRootsProvider.java b/xml/impl/src/com/intellij/javaee/ExternalResourcesRootsProvider.java index f629e3216c03..795feb38fec3 100644 --- a/xml/impl/src/com/intellij/javaee/ExternalResourcesRootsProvider.java +++ b/xml/impl/src/com/intellij/javaee/ExternalResourcesRootsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -22,10 +22,9 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.IndexableSetContributor; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -33,16 +32,14 @@ import java.util.Set; * @author Dmitry Avdeev */ public class ExternalResourcesRootsProvider extends IndexableSetContributor { - private final NotNullLazyValue> myStandardResources = new NotNullLazyValue>() { @NotNull @Override protected Set compute() { ExternalResourceManagerExImpl manager = (ExternalResourceManagerExImpl)ExternalResourceManager.getInstance(); - Collection> resources = manager.getStandardResources(); - Set dirs = new HashSet(); - Set set = new HashSet(); - for (Map map : resources) { + Set dirs = new THashSet(); + Set set = new THashSet(); + for (Map map : manager.getStandardResources()) { for (ExternalResourceManagerExImpl.Resource resource : map.values()) { ExternalResourceManagerExImpl.Resource dir = new ExternalResourceManagerExImpl.Resource( resource.directoryName(), resource); @@ -61,8 +58,7 @@ public class ExternalResourcesRootsProvider extends IndexableSetContributor { @Override public Set getAdditionalRootsToIndex() { - - HashSet roots = new HashSet(); + Set roots = new THashSet(); for (String url : myStandardResources.getValue()) { VirtualFile file = VfsUtilCore.findRelativeFile(url, null); if (file != null) { @@ -73,7 +69,7 @@ public class ExternalResourcesRootsProvider extends IndexableSetContributor { String path = FetchExtResourceAction.getExternalResourcesPath(); VirtualFile extResources = LocalFileSystem.getInstance().findFileByPath(path); ContainerUtil.addIfNotNull(extResources, roots); - + return roots; } } diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java index ae0f18066a14..b157a254de4e 100644 --- a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java @@ -344,7 +344,7 @@ public class BreadcrumbsXmlWrapper implements BreadcrumbsItemListener> myResources = new HashMap>(); - private final Set myResourceLocations = new HashSet(); + private final Map> myResources = new THashMap>(); + private final Set myResourceLocations = new THashSet(); - private final Set myIgnoredResources = new HashSet(); + private final Set myIgnoredResources = new TreeSet(); + private final Set myStandardIgnoredResources = new TreeSet(); - private final AtomicNotNullLazyValue>> myStdResources = new AtomicNotNullLazyValue>>() { + private final NotNullLazyValue>> myStandardResources = new AtomicNotNullLazyValue>>() { @NotNull @Override protected Map> compute() { @@ -82,15 +81,14 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp protected Map> computeStdResources() { ResourceRegistrarImpl registrar = new ResourceRegistrarImpl(); - for (StandardResourceProvider provider : Extensions.getExtensions(StandardResourceProvider.EP_NAME)) { + for (StandardResourceProvider provider : StandardResourceProvider.EP_NAME.getExtensions()) { provider.registerResources(registrar); } - StandardResourceEP[] extensions = Extensions.getExtensions(StandardResourceEP.EP_NAME); - for (StandardResourceEP extension : extensions) { + for (StandardResourceEP extension : StandardResourceEP.EP_NAME.getExtensions()) { registrar.addStdResource(extension.url, extension.version, extension.resourcePath, null, extension.getLoaderForClass()); } - myIgnoredResources.addAll(registrar.getIgnored()); + myStandardIgnoredResources.addAll(registrar.getIgnored()); return registrar.getResources(); } @@ -100,7 +98,8 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp @NonNls private static final String LOCATION_ATTR = "location"; @NonNls private static final String IGNORED_RESOURCE_ELEMENT = "ignored-resource"; @NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-doctype"; - private static final String DEFAULT_VERSION = null; + + private static final String DEFAULT_VERSION = ""; @Override public boolean isStandardResource(VirtualFile file) { @@ -114,42 +113,41 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } @Nullable - static Map getMap(@NotNull final Map> resources, - @Nullable final String version, - final boolean create) { + static Map getMap(@NotNull Map> resources, @Nullable String version, boolean create) { + version = StringUtil.notNullize(version, DEFAULT_VERSION); Map map = resources.get(version); if (map == null) { if (create) { - map = ContainerUtil.newHashMap(); + map = new THashMap(); resources.put(version, map); } - else if (version == null || !version.equals(DEFAULT_VERSION)) { + else if (!version.equals(DEFAULT_VERSION)) { map = resources.get(DEFAULT_VERSION); } } - return map; } @Override - public String getResourceLocation(String url) { + public String getResourceLocation(@NotNull String url) { return getResourceLocation(url, DEFAULT_VERSION); } @Override - public String getResourceLocation(@NonNls String url, String version) { - String result = getUserResource(url, version); + public String getResourceLocation(@NotNull @NonNls String url, @Nullable String version) { + String result = getUserResource(url, StringUtil.notNullize(version, DEFAULT_VERSION)); if (result == null) { XMLCatalogManager manager = getCatalogManager(); if (manager != null) { result = manager.resolve(url); } - } - if (result == null) { - result = getStdResource(url, version); - } - if (result == null) { - result = url; + + if (result == null) { + result = getStdResource(url, version); + if (result == null) { + return url; + } + } } return result; } @@ -163,8 +161,8 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp @Override @Nullable - public String getStdResource(String url, String version) { - Map map = getMap(myStdResources.getValue(), version, false); + public String getStdResource(@NotNull String url, @Nullable String version) { + Map map = getMap(myStandardResources.getValue(), version, false); if (map != null) { Resource resource = map.get(url); return resource == null ? null : resource.getResourceUrl(); @@ -175,13 +173,13 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } @Nullable - private String getUserResource(String url, String version) { + private String getUserResource(@NotNull String url, @Nullable String version) { Map map = getMap(myResources, version, false); return map != null ? map.get(url) : null; } @Override - public String getResourceLocation(@NonNls String url, @NotNull Project project) { + public String getResourceLocation(@NotNull @NonNls String url, @NotNull Project project) { String location = getProjectResources(project).getResourceLocation(url); return location == null || location.equals(url) ? getResourceLocation(url) : location; } @@ -203,28 +201,27 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } @Override - public String[] getResourceUrls(FileType fileType, final boolean includeStandard) { + public String[] getResourceUrls(FileType fileType, boolean includeStandard) { return getResourceUrls(fileType, DEFAULT_VERSION, includeStandard); } @Override - public String[] getResourceUrls(@Nullable final FileType fileType, @NonNls final String version, final boolean includeStandard) { - final List result = new LinkedList(); + public String[] getResourceUrls(@Nullable FileType fileType, @Nullable @NonNls String version, boolean includeStandard) { + List result = new LinkedList(); addResourcesFromMap(result, version, myResources); if (includeStandard) { - addResourcesFromMap(result, version, myStdResources.getValue()); + addResourcesFromMap(result, version, myStandardResources.getValue()); } return ArrayUtil.toStringArray(result); } - private static void addResourcesFromMap(final List result, - String version, - Map> resourcesMap) { + private static void addResourcesFromMap(@NotNull List result, @Nullable String version, @NotNull Map> resourcesMap) { Map resources = getMap(resourcesMap, version, false); - if (resources == null) return; - result.addAll(resources.keySet()); + if (resources != null) { + result.addAll(resources.keySet()); + } } @TestOnly @@ -249,19 +246,19 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp }); } @Override - public void addResource(String url, String location) { + public void addResource(@NotNull String url, String location) { addResource(url, DEFAULT_VERSION, location); } @Override - public void addResource(@NonNls String url, @NonNls String version, @NonNls String location) { + public void addResource(@NotNull @NonNls String url, @NonNls String version, @NonNls String location) { ApplicationManager.getApplication().assertWriteAccessAllowed(); addSilently(url, version, location); fireExternalResourceChanged(); } - private void addSilently(String url, String version, String location) { - final Map map = getMap(myResources, version, true); + private void addSilently(@NotNull String url, @Nullable String version, String location) { + Map map = getMap(myResources, version, true); assert map != null; map.put(url, location); myResourceLocations.add(location); @@ -269,12 +266,12 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } @Override - public void removeResource(String url) { + public void removeResource(@NotNull String url) { removeResource(url, DEFAULT_VERSION); } @Override - public void removeResource(String url, String version) { + public void removeResource(@NotNull String url, @Nullable String version) { ApplicationManager.getApplication().assertWriteAccessAllowed(); Map map = getMap(myResources, version, false); if (map != null) { @@ -299,7 +296,7 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp @Override public String[] getAvailableUrls() { - Set urls = new HashSet(); + Set urls = new THashSet(); for (Map map : myResources.values()) { urls.addAll(map.keySet()); } @@ -327,19 +324,29 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } @Override - public void addIgnoredResource(String url) { + public void addIgnoredResource(@NotNull String url) { ApplicationManager.getApplication().assertWriteAccessAllowed(); - addIgnoredSilently(url); - fireExternalResourceChanged(); + if (addIgnoredSilently(url)) { + fireExternalResourceChanged(); + } } - private void addIgnoredSilently(String url) { - myIgnoredResources.add(url); - incModificationCount(); + private boolean addIgnoredSilently(@NotNull String url) { + if (myStandardIgnoredResources.contains(url)) { + return false; + } + + if (myIgnoredResources.add(url)) { + incModificationCount(); + return true; + } + else { + return false; + } } @Override - public void removeIgnoredResource(String url) { + public void removeIgnoredResource(@NotNull String url) { ApplicationManager.getApplication().assertWriteAccessAllowed(); if (myIgnoredResources.remove(url)) { incModificationCount(); @@ -348,23 +355,38 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } @Override - public boolean isIgnoredResource(String url) { - myStdResources.getValue(); // ensure ignored resources are loaded - return myIgnoredResources.contains(url) || isImplicitNamespaceDescriptor(url); + public boolean isIgnoredResource(@NotNull String url) { + if (myIgnoredResources.contains(url)) { + return true; + } + + // ensure ignored resources are loaded + myStandardResources.getValue(); + return myStandardIgnoredResources.contains(url) || isImplicitNamespaceDescriptor(url); } - private static boolean isImplicitNamespaceDescriptor(String url) { - for (ImplicitNamespaceDescriptorProvider namespaceDescriptorProvider : Extensions - .getExtensions(ImplicitNamespaceDescriptorProvider.EP_NAME)) { - if (namespaceDescriptorProvider.getNamespaceDescriptor(null, url, null) != null) return true; + private static boolean isImplicitNamespaceDescriptor(@NotNull String url) { + for (ImplicitNamespaceDescriptorProvider provider : ImplicitNamespaceDescriptorProvider.EP_NAME.getExtensions()) { + if (provider.getNamespaceDescriptor(null, url, null) != null) { + return true; + } } return false; } @Override public String[] getIgnoredResources() { - myStdResources.getValue(); // ensure ignored resources are loaded - return ArrayUtil.toStringArray(myIgnoredResources); + // ensure ignored resources are loaded + myStandardResources.getValue(); + + if (myIgnoredResources.isEmpty()) { + return ArrayUtil.toStringArray(myStandardIgnoredResources); + } + + Set set = new THashSet(myIgnoredResources.size() + myStandardIgnoredResources.size()); + set.addAll(myIgnoredResources); + set.addAll(myStandardIgnoredResources); + return ArrayUtil.toStringArray(set); } @Override @@ -372,25 +394,34 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp return getProjectResources(project).getModificationCount(); } - @Nullable @Override public Element getState() { Element element = new Element("state"); - final String[] urls = getAvailableUrls(); - for (String url : urls) { - if (url == null) continue; - String location = getResourceLocation(url); - if (location == null) continue; - final Element e = new Element(RESOURCE_ELEMENT); + Set urls = new TreeSet(); + for (Map map : myResources.values()) { + urls.addAll(map.keySet()); + } + + for (String url : urls) { + if (url == null) { + continue; + } + + String location = getResourceLocation(url); + if (location == null) { + continue; + } + + Element e = new Element(RESOURCE_ELEMENT); e.setAttribute(URL_ATTR, url); e.setAttribute(LOCATION_ATTR, location.replace(File.separatorChar, '/')); element.addContent(e); } - final String[] ignoredResources = getIgnoredResources(); - for (String ignoredResource : ignoredResources) { + myIgnoredResources.removeAll(myStandardIgnoredResources); + for (String ignoredResource : myIgnoredResources) { Element e = new Element(IGNORED_RESOURCE_ELEMENT); e.setAttribute(URL_ATTR, ignoredResource); element.addContent(e); @@ -406,30 +437,33 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp properties.setText(myCatalogPropertiesFile); element.addContent(properties); } - final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap(); + + ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap(); PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements); macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive); return element; } @Override - public void loadState(Element element) { - final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap(); + public void loadState(Element state) { + ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap(); PathMacrosImpl.getInstanceEx().addMacroExpands(macroExpands); - macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive); + macroExpands.substitute(state, SystemInfo.isFileSystemCaseSensitive); incModificationCount(); - for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) { - Element e = (Element)o1; - addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar)); + for (Element element : state.getChildren(RESOURCE_ELEMENT)) { + String url = element.getAttributeValue(URL_ATTR); + if (!StringUtil.isEmpty(url)) { + addSilently(url, DEFAULT_VERSION, element.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar)); + } } - for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) { - Element e = (Element)o; - addIgnoredSilently(e.getAttributeValue(URL_ATTR)); + myIgnoredResources.clear(); + for (Element element : state.getChildren(IGNORED_RESOURCE_ELEMENT)) { + addIgnoredSilently(element.getAttributeValue(URL_ATTR)); } - Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); + Element child = state.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); if (child != null) { String text = child.getText(); if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) { @@ -437,13 +471,12 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } myDefaultHtmlDoctype = text; } - Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT); + Element catalogElement = state.getChild(CATALOG_PROPERTIES_ELEMENT); if (catalogElement != null) { myCatalogPropertiesFile = catalogElement.getTextTrim(); } } - @Override public void addExternalResourceListener(ExternalResourceListener listener) { myListeners.add(listener); @@ -461,10 +494,9 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp } Collection> getStandardResources() { - return myStdResources.getValue().values(); + return myStandardResources.getValue().values(); } - private static final NotNullLazyKey INSTANCE_CACHE = ServiceManager.createLazyKey(ExternalResourceManagerExImpl.class); private static ExternalResourceManagerExImpl getProjectResources(Project project) { diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java b/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java index 4b9541b0ebe2..7f4a69b1847a 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,7 +15,6 @@ */ package com.intellij.javaee; -import com.intellij.application.options.PathMacrosImpl; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; @@ -29,6 +28,7 @@ import java.util.Map; */ @State(name = "ProjectResources", storages = {@Storage(file = StoragePathMacros.PROJECT_FILE)}) public class ProjectResources extends ExternalResourceManagerExImpl { + @NotNull @Override protected Map> computeStdResources() { return Collections.emptyMap(); diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java index a0fa57929f14..37462e2410b1 100644 --- a/xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.javaee; -import com.intellij.util.containers.HashMap; +import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -28,8 +28,7 @@ import java.util.Map; * @author Dmitry Avdeev */ public class ResourceRegistrarImpl implements ResourceRegistrar { - - private final Map> myResources = new HashMap>(); + private final Map> myResources = new THashMap>(); private final List myIgnored = new ArrayList(); @Override @@ -43,7 +42,7 @@ public class ResourceRegistrarImpl implements ResourceRegistrar { } public void addStdResource(@NonNls String resource, @NonNls String version, @NonNls String fileName, @Nullable Class klass, @Nullable ClassLoader classLoader) { - final Map map = ExternalResourceManagerExImpl.getMap(myResources, version, true); + Map map = ExternalResourceManagerExImpl.getMap(myResources, version, true); assert map != null; resource = new String(resource); // enforce copying; todo remove after final migration to JDK 1.7 map.put(resource, new ExternalResourceManagerExImpl.Resource(fileName, klass, classLoader)); @@ -75,10 +74,12 @@ public class ResourceRegistrarImpl implements ResourceRegistrar { addStdResource(resource, version, ExternalResourceManagerEx.STANDARD_SCHEMAS + fileName, clazz); } + @NotNull public Map> getResources() { return myResources; } + @NotNull public List getIgnored() { return myIgnored; } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java index e86f655bc6d1..c18db0fec59d 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/ComplexTypeDescriptor.java @@ -15,10 +15,10 @@ */ package com.intellij.xml.impl.schema; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.FieldCache; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.resolve.reference.impl.providers.SchemaReferencesProvider; import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.util.CachedValue; @@ -85,17 +85,21 @@ public class ComplexTypeDescriptor extends TypeDescriptor { } }; + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private final FactoryMap> myAnyAttributeCache = new ConcurrentFactoryMap>() { @Override protected CachedValue create(final String key) { return CachedValuesManager.getManager(myTag.getProject()).createCachedValue(new CachedValueProvider() { @Override public Result compute() { - THashSet dependencies = new THashSet(); + THashSet dependencies = new THashSet(); CanContainAttributeType type = _canContainAttribute(key, myTag, null, new THashSet(), dependencies); if (dependencies.isEmpty()) { dependencies.add(myTag.getContainingFile()); } + if (DumbService.isDumb(myTag.getProject())) { + dependencies.add(DumbService.getInstance(myTag.getProject()).getModificationTracker()); + } return Result.create(type, ArrayUtil.toObjectArray(dependencies)); } }, false); @@ -398,7 +402,7 @@ public class ComplexTypeDescriptor extends TypeDescriptor { XmlTag tag, @Nullable String qName, Set visited, - @Nullable Set dependencies) { + @Nullable Set dependencies) { if (XmlNSDescriptorImpl.equalsToSchemaName(tag, "anyAttribute")) { if (dependencies != null) { dependencies.add(tag.getContainingFile());