diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index b86759580bca..8722fdfd04be 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -79,14 +79,13 @@ import java.io.IOException; import java.util.*; import java.util.List; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicReference; public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { @NotNull public static final Icon ICON = IconLoader.getIcon("/modules/annotation.png"); private static final Logger LOG = Logger.getInstance("#" + ExternalAnnotationsManagerImpl.class.getName()); @NotNull private final ConcurrentMap> myExternalAnnotations = new ConcurrentWeakValueHashMap>(); - @NotNull private final AtomicReference myHasAnyAnnotationsRoots = new AtomicReference(ThreeState.UNSURE); + @NotNull private volatile ThreeState myHasAnyAnnotationsRoots = ThreeState.UNSURE; @NotNull private static final List NULL = new ArrayList(); private final PsiManager myPsiManager; @@ -94,38 +93,42 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { myPsiManager = psiManager; final MessageBusConnection connection = project.getMessageBus().connect(project); connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() { + @Override public void beforeRootsChange(ModuleRootEvent event) { } + @Override public void rootsChanged(ModuleRootEvent event) { myExternalAnnotations.clear(); - myHasAnyAnnotationsRoots.set(ThreeState.UNSURE); + myHasAnyAnnotationsRoots = ThreeState.UNSURE; } }); } private ThreeState hasAnyAnnotationsRoots() { - if (myHasAnyAnnotationsRoots.get() == ThreeState.UNSURE) { + if (myHasAnyAnnotationsRoots == ThreeState.UNSURE) { final Module[] modules = ModuleManager.getInstance(myPsiManager.getProject()).getModules(); for (Module module : modules) { for (OrderEntry entry : ModuleRootManager.getInstance(module).getOrderEntries()) { final String[] urls = AnnotationOrderRootType.getUrls(entry); if (urls.length > 0) { - myHasAnyAnnotationsRoots.set(ThreeState.YES); + myHasAnyAnnotationsRoots = ThreeState.YES; return ThreeState.YES; } } } - myHasAnyAnnotationsRoots.set(ThreeState.NO); + myHasAnyAnnotationsRoots = ThreeState.NO; } - return myHasAnyAnnotationsRoots.get(); + return myHasAnyAnnotationsRoots; } + @Override @Nullable public PsiAnnotation findExternalAnnotation(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { return collectExternalAnnotations(listOwner).get(annotationFQN); } + @Override @Nullable public PsiAnnotation[] findExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { final Map result = collectExternalAnnotations(listOwner); @@ -135,11 +138,11 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { @NotNull private Map collectExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { if (hasAnyAnnotationsRoots() == ThreeState.NO) return Collections.emptyMap(); - final Map result = new HashMap(); - final List files = findExternalAnnotationsFile(listOwner); + final List files = findExternalAnnotationsFiles(listOwner); if (files == null) { return Collections.emptyMap(); } + final Map result = new HashMap(); for (XmlFile file : files) { if (!file.isValid()) continue; final XmlDocument document = file.getDocument(); @@ -168,7 +171,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : ""); try { result.put(annotationFQN, - JavaPsiFacade.getInstance(listOwner.getProject()).getElementFactory().createAnnotationFromText( + JavaPsiFacade.getInstance(myPsiManager.getProject()).getElementFactory().createAnnotationFromText( annotationText, null)); } catch (IncorrectOperationException e) { @@ -186,11 +189,12 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { } + @Override public void annotateExternally(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQName, @NotNull final PsiFile fromFile, final PsiNameValuePair[] value) { - final Project project = listOwner.getProject(); + final Project project = myPsiManager.getProject(); final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return; @@ -215,6 +219,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return; } SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { setupRootAndAnnotateExternally(entry, project, listOwner, annotationFQName, fromFile, packageName, virtualFile, value); } @@ -240,9 +245,10 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return; } new WriteCommandAction(project) { + @Override protected void run(final Result result) throws Throwable { appendChosenAnnotationsRoot(entry, file); - final List xmlFiles = findExternalAnnotationsFile(listOwner); + final List xmlFiles = findExternalAnnotationsFiles(listOwner); if (xmlFiles != null) { //file already exists under appeared content root if (!CodeInsightUtilBase.preparePsiElementForWrite(xmlFiles.get(0))) return; annotateExternally(listOwner, annotationFQName, xmlFiles.get(0), fromFile, value); @@ -314,7 +320,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { @NotNull final PsiFile fromFile, final PsiNameValuePair[] value) { final XmlFile[] annotationsXml = new XmlFile[1]; - List xmlFiles = findExternalAnnotationsFile(listOwner); + List xmlFiles = findExternalAnnotationsFiles(listOwner); if (xmlFiles != null) { for (XmlFile xmlFile : xmlFiles) { final VirtualFile vXmlFile = xmlFile.getVirtualFile(); @@ -330,6 +336,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { final List annotationFiles = new ArrayList(xmlFiles); new WriteCommandAction(project) { + @Override protected void run(final Result result) throws Throwable { if (annotationsXml[0] == null) { annotationsXml[0] = createAnnotationsXml(file, packageName); @@ -343,8 +350,9 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { }.execute(); } + @Override public boolean deannotate(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { - final List files = findExternalAnnotationsFile(listOwner); + final List files = findExternalAnnotationsFiles(listOwner); if (files != null) { for (XmlFile file : files) { if (file.isValid()) { @@ -359,7 +367,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { if (Comparing.strEqual(className, externalName) || Comparing.strEqual(className, oldExternalName)) { for (XmlTag annotationTag : tag.getSubTags()) { if (Comparing.strEqual(annotationTag.getAttributeValue("name"), annotationFQN)) { - if (ReadonlyStatusHandler.getInstance(file.getProject()) + if (ReadonlyStatusHandler.getInstance(myPsiManager.getProject()) .ensureFilesWritable(file.getVirtualFile()).hasReadonlyFiles()) { return false; } @@ -386,11 +394,12 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return false; } + @Override @NotNull public AnnotationPlace chooseAnnotationsPlace(@NotNull final PsiElement element) { if (!element.isPhysical()) return AnnotationPlace.IN_CODE; //element just created if (!element.getManager().isInProject(element)) return AnnotationPlace.EXTERNAL; - final Project project = element.getProject(); + final Project project = myPsiManager.getProject(); final PsiFile containingFile = element.getContainingFile(); final VirtualFile virtualFile = containingFile.getVirtualFile(); LOG.assertTrue(virtualFile != null); @@ -472,7 +481,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { myExternalAnnotations.clear(); } - private static void annotateExternally(final PsiModifierListOwner listOwner, + private void annotateExternally(final PsiModifierListOwner listOwner, final String annotationFQName, @Nullable final XmlFile xmlFile, @NotNull PsiFile codeUsageFile, @@ -492,7 +501,8 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { break; } } - tag.add(XmlElementFactory.getInstance(xmlFile.getProject()).createTagFromText(createAnnotationTag(annotationFQName, values))); + tag.add(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText( + createAnnotationTag(annotationFQName, values))); return; } } @@ -500,7 +510,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { "\n"; text += createAnnotationTag(annotationFQName, values); text += ""; - rootTag.add(XmlElementFactory.getInstance(xmlFile.getProject()).createTagFromText(text)); + rootTag.add(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText(text)); } } } @@ -520,13 +530,13 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { if (values != null) { text = " \n"; text += StringUtil.join(values, new Function() { + @NonNls @NotNull @Override public String fun(@NotNull PsiNameValuePair pair) { - if (pair.getName() != null) { - return ""; - } - return ""; + return ""; } }, " \n"); text += " "; @@ -572,8 +582,8 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { } @Nullable - private List findExternalAnnotationsFile(@NotNull PsiModifierListOwner listOwner) { - final Project project = listOwner.getProject(); + private List findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) { + final Project project = myPsiManager.getProject(); final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return null; @@ -672,15 +682,18 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { init(); } + @Override protected String getOkActionName() { return ADD_IN_CODE; } + @Override @NotNull protected String getCancelActionName() { return CommonBundle.getCancelButtonText(); } + @Override @NotNull @SuppressWarnings({"NonStaticInitializer"}) protected Action[] createActions() { @@ -692,6 +705,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { assignMnemonic(externalName, this); } + @Override public void actionPerformed(final ActionEvent e) { if (canBeHidden()) { setToBeShown(toBeShown(), true); @@ -701,20 +715,24 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { }, getCancelAction()}; } + @Override protected boolean isToBeShown() { return CodeStyleSettingsManager.getSettings(myProject).USE_EXTERNAL_ANNOTATIONS; } + @Override protected void setToBeShown(boolean value, boolean onOk) { CodeStyleSettingsManager.getSettings(myProject).USE_EXTERNAL_ANNOTATIONS = value; } + @Override protected JComponent createNorthPanel() { final JPanel northPanel = (JPanel)super.createNorthPanel(); northPanel.add(new JLabel(MESSAGE), BorderLayout.CENTER); return northPanel; } + @Override protected boolean shouldSaveOptionsOnCancel() { return true; } diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java index 23afeba19ed8..2612500f018e 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java @@ -33,8 +33,6 @@ public class UnscrambleListener implements ApplicationActivationListener { @Override public void applicationActivated(final IdeFrame ideFrame) { - if (SystemInfo.isMac) return; - final Runnable processClipboard = new Runnable() { @Override public void run() { diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java index c2dd1a155a13..4fc029dcd86c 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java @@ -44,7 +44,7 @@ public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase{ protected void setUp() throws Exception { super.setUp(); - final TestFixtureBuilder projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(); + final TestFixtureBuilder projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()); myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture()); final JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class); moduleFixtureBuilder.addSourceContentRoot(myFixture.getTempDirPath()); diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java index b7b03b1de9df..5ae19176c25b 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java @@ -15,6 +15,8 @@ */ package com.intellij.testFramework.fixtures; +import org.jetbrains.annotations.NotNull; + /** * @author yole */ @@ -41,8 +43,15 @@ public abstract class JavaTestFixtureFactory { public abstract JavaCodeInsightTestFixture createCodeInsightFixture(IdeaProjectTestFixture projectFixture, TempDirTestFixture tempDirFixture); + /** + * + * @deprecated use {@link JavaTestFixtureFactory#createFixtureBuilder(String)} + */ //also implicitly initializes ourInstance and registers java module fixture builder public static TestFixtureBuilder createFixtureBuilder() { return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(); } + public static TestFixtureBuilder createFixtureBuilder(@NotNull String name) { + return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(name); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java index 106045201bee..4c4a3e7f78f4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java @@ -2,17 +2,16 @@ package org.jetbrains.jps.incremental; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; import org.jetbrains.ether.dependencyView.Mappings; import org.jetbrains.jps.Module; import org.jetbrains.jps.ModuleChunk; +import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.incremental.messages.ProgressMessage; import java.io.File; import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /** * Use {@link BuilderService} to register implementations of this class @@ -103,6 +102,18 @@ public abstract class ModuleLevelBuilder extends Builder { context.processMessage(new ProgressMessage("Found " + newlyAffectedFiles.size() + " affected files")); if (!newlyAffectedFiles.isEmpty()) { + + + if (LOG.isDebugEnabled()) { + final List> wrongFiles = checkAffectedFilesInCorrectModules(context, chunk, newlyAffectedFiles); + if (!wrongFiles.isEmpty()) { + LOG.debug("Wrong affected files for module chunk " + chunk.getName() + ": "); + for (Pair pair : wrongFiles) { + LOG.debug("\t[" + pair.second.getName() + "] " + pair.first.getPath()); + } + } + } + for (File file : newlyAffectedFiles) { context.markDirtyIfNotDeleted(file); } @@ -135,6 +146,45 @@ public abstract class ModuleLevelBuilder extends Builder { } } + + private static List> checkAffectedFilesInCorrectModules(CompileContext context, ModuleChunk currentChunk, Collection affected) { + if (affected.isEmpty()) { + return Collections.emptyList(); + } + + final Set chunkModules = currentChunk.getModules(); + final Map> cache = new HashMap>(); + final List> result = new ArrayList>(); + + for (File file : affected) { + final RootDescriptor moduleAndRoot = context.getModuleAndRoot(file); + if (moduleAndRoot == null) { + continue; + } + final Module moduleOfFile = moduleAndRoot.module; + if (chunkModules.contains(moduleOfFile)) { + continue; + } + Set moduleOfFileWithDependencies = cache.get(moduleOfFile); + if (moduleOfFileWithDependencies == null) { + moduleOfFileWithDependencies = ProjectPaths.getModulesWithDependentsRecursively(moduleOfFile, true); + cache.put(moduleOfFile, moduleOfFileWithDependencies); + } + if (intersects(moduleOfFileWithDependencies, chunkModules)) { + continue; + } + result.add(Pair.create(file, moduleOfFile)); + } + return result; + } + + private static boolean intersects(Set set1, Set set2) { + if (set1.size() < set2.size()) { + return new HashSet(set1).removeAll(set2); + } + return new HashSet(set2).removeAll(set1); + } + private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set affected) throws IOException { final Set chunkModules = new HashSet(chunk.getModules()); if (!chunkModules.isEmpty()) { diff --git a/jps/model/src/org/jetbrains/jps/ProjectPaths.java b/jps/model/src/org/jetbrains/jps/ProjectPaths.java index 2ac7addc9112..f4eb61024a37 100644 --- a/jps/model/src/org/jetbrains/jps/ProjectPaths.java +++ b/jps/model/src/org/jetbrains/jps/ProjectPaths.java @@ -181,6 +181,16 @@ public class ProjectPaths { return sourcePaths; } + public static Set getModulesWithDependentsRecursively(final Module module, final boolean includeTests) { + final Set result = new HashSet(); + collectPathsRecursively(module, ClasspathKind.compile(includeTests), new HashSet(), new PathsGetter() { + public void apply(Module module, ClasspathKind kind) { + result.add(module); + } + }); + return result; + } + private interface PathsGetter { void apply(Module module, ClasspathKind kind); } diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java index 1b5822fbe3e2..cc6c34625ef8 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java @@ -22,6 +22,7 @@ import java.util.List; public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements DumbAware { private CustomFoldingProvider myDefaultProvider; + private static final int MAX_LOOKUP_DEPTH = 10; @NotNull @Override @@ -29,7 +30,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D List descriptors = new ArrayList(); if (CustomFoldingProvider.getAllProviders().length > 0) { myDefaultProvider = null; - addCustomFoldingRegionsRecursively(null, root.getNode(), descriptors); + addCustomFoldingRegionsRecursively(null, root.getNode(), descriptors, 0); } buildLanguageFoldRegions(descriptors, root, document, quick); return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); @@ -57,7 +58,8 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D private void addCustomFoldingRegionsRecursively(@Nullable FoldingStack foldingStack, @NotNull ASTNode node, - List descriptors) { + List descriptors, + int currDepth) { FoldingStack localFoldingStack = isCustomFoldingRoot(node) || foldingStack == null ? new FoldingStack(node) : foldingStack; for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { if (isCustomRegionStart(child)) { @@ -72,7 +74,9 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D } } else { - addCustomFoldingRegionsRecursively(localFoldingStack, child, descriptors); + if (currDepth < MAX_LOOKUP_DEPTH) { + addCustomFoldingRegionsRecursively(localFoldingStack, child, descriptors, currDepth + 1); + } } } } diff --git a/platform/lang-api/src/com/intellij/openapi/project/ModuleNameTracker.java b/platform/lang-api/src/com/intellij/openapi/project/ModuleNameTracker.java new file mode 100644 index 000000000000..2b6036e1d960 --- /dev/null +++ b/platform/lang-api/src/com/intellij/openapi/project/ModuleNameTracker.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.project; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.Disposer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * User: ksafonov + */ +public abstract class ModuleNameTracker extends ModuleAdapter { + private final Map myModulesNames = new HashMap(); + private final Project myProject; + + public ModuleNameTracker(Project project) { + myProject = project; + Disposer.register(project, new Disposable() { + @Override + public void dispose() { + myModulesNames.clear(); + } + }); + } + + @Override + public void moduleAdded(final Project project, final Module module) { + if (myProject == project) { + myModulesNames.put(module, module.getName()); + } + } + + @Override + public void moduleRemoved(final Project project, final Module module) { + if (myProject == project) { + myModulesNames.remove(module); + } + } + + @Override + public void modulesRenamed(final Project project, final List modules) { + if (myProject != project) { + return; + } + + Map old2newNames = new HashMap(modules.size()); + for (Module module : modules) { + String newName = module.getName(); + String oldName = myModulesNames.put(module, newName); + old2newNames.put(oldName, newName); + } + modulesRenamed(project, old2newNames); + } + + protected abstract void modulesRenamed(final Project project, final Map old2newNames); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index 4cd590aa5898..252b26675a03 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -61,6 +61,7 @@ import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopeManager; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Alarm; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; @@ -94,7 +95,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private final Alarm myAlarm = new Alarm(); private boolean myUpdateByTimerEnabled = true; private final Collection myDisabledHintsFiles = new THashSet(); - private final Collection myDisabledHighlightingFiles = new THashSet(); + private final Collection myDisabledHighlightingFiles = new THashSet(); private final FileStatusMap myFileStatusMap; private DaemonCodeAnalyzerSettings myLastSettings; @@ -122,6 +123,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap = new FileStatusMap(myProject); myPassExecutorService = new PassExecutorService(myProject) { + @Override protected void afterApplyInformationToEditor(final TextEditorHighlightingPass pass, final FileEditor fileEditor, final ProgressIndicator updateProgress) { @@ -132,6 +134,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Override protected boolean isDisposed() { return myDisposed || super.isDisposed(); } @@ -283,14 +286,17 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myPassExecutorService.cancelAll(true); } + @Override @NotNull public String getComponentName() { return "DaemonCodeAnalyzer"; } + @Override public void initComponent() { } + @Override public void disposeComponent() { } @@ -309,6 +315,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap.markAllFilesDirty(); } + @Override public void projectClosed() { assert myInitialized : "Disposing not initialized component"; assert !myDisposed : "Double dispose"; @@ -354,6 +361,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myScopes; } + @Override public void settingsChanged() { DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance(); if (settings.isCodeHighlightingChanged(myLastSettings)) { @@ -362,11 +370,13 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myLastSettings = (DaemonCodeAnalyzerSettings)settings.clone(); } + @Override public void updateVisibleHighlighters(@NotNull Editor editor) { ApplicationManager.getApplication().assertIsDispatchThread(); // no need, will not work anyway } + @Override public void setUpdateByTimerEnabled(boolean value) { myUpdateByTimerEnabled = value; stopProcess(value); @@ -376,6 +386,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myUpdateByTimerEnabled; } + @Override public void setImportHintsEnabled(@NotNull PsiFile file, boolean value) { VirtualFile vFile = file.getVirtualFile(); if (value) { @@ -388,23 +399,27 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Override public void resetImportHintsEnabledForProject() { myDisabledHintsFiles.clear(); } + @Override public void setHighlightingEnabled(@NotNull PsiFile file, boolean value) { + VirtualFile virtualFile = PsiUtilCore.getVirtualFile(file); if (value) { - myDisabledHighlightingFiles.remove(file); + myDisabledHighlightingFiles.remove(virtualFile); } else { - myDisabledHighlightingFiles.add(file); + myDisabledHighlightingFiles.add(virtualFile); } } + @Override public boolean isHighlightingAvailable(PsiFile file) { - if (myDisabledHighlightingFiles.contains(file)) return false; - if (file == null || !file.isPhysical()) return false; + if (myDisabledHighlightingFiles.contains(PsiUtilCore.getVirtualFile(file))) return false; + if (file instanceof PsiCompiledElement) return false; final FileType fileType = file.getFileType(); if (fileType == StdFileTypes.GUI_DESIGNER_FORM){ @@ -414,14 +429,17 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return !fileType.isBinary(); } + @Override public boolean isImportHintsEnabled(@NotNull PsiFile file) { return isAutohintsAvailable(file) && !myDisabledHintsFiles.contains(file.getVirtualFile()); } + @Override public boolean isAutohintsAvailable(PsiFile file) { return isHighlightingAvailable(file) && !(file instanceof PsiCompiledElement); } + @Override public void restart() { myFileStatusMap.markAllFilesDirty(); stopProcess(true); @@ -507,6 +525,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOverlappingWith(startOffset, endOffset, new Processor() { + @Override public boolean process(RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; @@ -529,6 +548,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOutside(startOffset, endOffset, new Processor() { + @Override public boolean process(RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; @@ -548,6 +568,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx final boolean includeFixRange, @NotNull final Processor processor) { return processHighlights(document, project, null, 0, document.getTextLength(), new Processor() { + @Override public boolean process(HighlightInfo info) { if (!isOffsetInsideHighlightInfo(offset, info, includeFixRange)) return true; @@ -561,6 +582,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx public HighlightInfo findHighlightByOffset(Document document, final int offset, final boolean includeFixRange) { final List foundInfoList = new SmartList(); processHighlightsNearOffset(document, myProject, HighlightSeverity.INFORMATION, offset, includeFixRange, new Processor() { + @Override public boolean process(HighlightInfo info) { if (!foundInfoList.isEmpty()) { HighlightInfo foundInfo = foundInfoList.get(0); @@ -635,6 +657,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myLastIntentionHint; } + @Override public void writeExternal(Element parentNode) throws WriteExternalException { Element disableHintsElement = new Element(DISABLE_HINTS_TAG); parentNode.addContent(disableHintsElement); @@ -654,6 +677,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Override public void readExternal(Element parentNode) throws InvalidDataException { myDisabledHintsFiles.clear(); @@ -675,12 +699,14 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private Runnable createUpdateRunnable() { return new Runnable() { + @Override public void run() { if (myDisposed || !myProject.isInitialized()) return; if (PowerSaveMode.isEnabled()) return; Editor activeEditor = FileEditorManager.getInstance(myProject).getSelectedTextEditor(); Runnable runnable = new Runnable() { + @Override public void run() { PassExecutorService.log(myUpdateProgress, null, "Update Runnable. myUpdateByTimerEnabled:",myUpdateByTimerEnabled," something disposed:",PowerSaveMode.isEnabled() || myDisposed || !myProject.isInitialized()," activeEditors:",myProject.isDisposed() ? null : myDaemonListeners.getSelectedEditors()); if (!myUpdateByTimerEnabled) return; @@ -745,6 +771,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myDaemonListeners.canChangeFileSilently(file); } + @Override public void autoImportReferenceAtCursor(@NotNull Editor editor, @NotNull PsiFile file) { for(ReferenceImporter importer: Extensions.getExtensions(ReferenceImporter.EP_NAME)) { if (importer.autoImportReferenceAtCursor(editor, file)) break; diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java index a88b3ec7034f..bd8eecead443 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java @@ -616,7 +616,7 @@ class RunConfigurable extends BaseConfigurable { final String nameText = configurable != null ? configurable.getNameText() : configurationBean.getSettings().getName(); if (!names.add(nameText)) { TreeUtil.selectNode(myTree, node); - throw new ConfigurationException("Configuration with name \'" + nameText + "\' already exist"); + throw new ConfigurationException("Configuration with name \'" + nameText + "\' already exists"); } stableConfigurations.add(configurationBean); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 035266c4dd47..c7b2b88a308c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -73,7 +73,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { private final NewVirtualFileSystem myFS; // guarded by this - protected Object myChildren; // Either HashMap or VFile[] + private Object myChildren; // Either HashMap or VFile[] public VirtualDirectoryImpl(@NotNull String name, final VirtualDirectoryImpl parent, @NotNull NewVirtualFileSystem fs, final int id) { super(name, parent, id); @@ -379,8 +379,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @NotNull private synchronized Collection getInDbChildren() { - if (myChildren instanceof VirtualFileSystemEntry[]) { - return Arrays.asList((VirtualFile[])myChildren); + VirtualFileSystemEntry[] children = asArray(); + if (children != null) { + return Arrays.asList((VirtualFile[])children); } if (!ourPersistence.wereChildrenAccessed(this)) { @@ -404,13 +405,13 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @Override @NotNull public synchronized VirtualFile[] getChildren() { - if (myChildren instanceof VirtualFileSystemEntry[]) { - return (VirtualFileSystemEntry[])myChildren; + VirtualFileSystemEntry[] children = asArray(); + if (children != null) { + return children; } Pair pair = PersistentFS.listAll(this); final int[] childrenIds = pair.second; - VirtualFileSystemEntry[] children; if (childrenIds.length == 0) { children = EMPTY_ARRAY; } @@ -454,7 +455,10 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @Override public NewVirtualFile findChildByIdIfCached(int id) { - final VirtualFile[] a = asArray(); + final VirtualFile[] a; + synchronized (this) { + a = asArray(); + } if (a != null) { for (VirtualFile file : a) { NewVirtualFile withId = (NewVirtualFile)file; @@ -477,12 +481,15 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { return null; } + // MUST BE CALLED UNDER this LOCK @Nullable private VirtualFileSystemEntry[] asArray() { - if (myChildren instanceof VirtualFileSystemEntry[]) return (VirtualFileSystemEntry[])myChildren; + Object children = myChildren; + if (children instanceof VirtualFileSystemEntry[]) return (VirtualFileSystemEntry[])children; return null; } + // MUST BE CALLED UNDER this LOCK @Nullable private Map asMap() { if (myChildren instanceof Map) { @@ -530,7 +537,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { } public synchronized boolean allChildrenLoaded() { - return myChildren instanceof VirtualFileSystemEntry[]; + return asArray() != null; } @NotNull diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index 09dce90d853b..37a1ba1643e7 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -33,6 +33,7 @@ import com.intellij.designer.designSurface.OperationContext; import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator; import com.intellij.designer.designSurface.tools.ComponentCreationFactory; import com.intellij.designer.designSurface.tools.ComponentPasteFactory; +import com.intellij.designer.model.RadComponent; import com.intellij.designer.palette.Item; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; @@ -45,7 +46,10 @@ import com.intellij.psi.xml.XmlFile; import com.intellij.util.ThrowableRunnable; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.uipreview.*; +import org.jetbrains.android.uipreview.LayoutDeviceConfiguration; +import org.jetbrains.android.uipreview.LocaleData; +import org.jetbrains.android.uipreview.RenderUtil; +import org.jetbrains.android.uipreview.RenderingException; import org.jetbrains.android.util.AndroidSdkNotConfiguredException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -127,19 +131,22 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { createRenderer(parser.getLayoutXmlText(), new ThrowableRunnable() { @Override public void run() throws Throwable { - checkRenderer(false); + checkRenderer(); RootView rootView = new RootView(mySession.getImage(), 30, 20); parser.updateRootComponent(mySession, rootView); + RadViewComponent newRootComponent = parser.getRootComponent(); - new PropertyParser(myModule, myProfileAction.getProfileManager().getSelectedTarget()).loadRecursive(parser.getRootComponent()); + PropertyParser propertyParser = new PropertyParser(myModule, myProfileAction.getProfileManager().getSelectedTarget()); + newRootComponent.setClientProperty(PropertyParser.KEY, propertyParser); + propertyParser.loadRecursive(newRootComponent); JPanel rootPanel = new JPanel(null); rootPanel.setBackground(Color.WHITE); rootPanel.add(rootView); removeNativeRoot(); - myRootComponent = parser.getRootComponent(); + myRootComponent = newRootComponent; myLayeredPane.add(rootPanel, LAYER_COMPONENT); runnable.run(); @@ -157,24 +164,20 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { createRenderer(layoutXmlText, new ThrowableRunnable() { @Override public void run() throws Throwable { - updateRenderer(false); + checkRenderer(); + + RadViewComponent rootComponent = (RadViewComponent)myRootComponent; + RootView rootView = (RootView)rootComponent.getNativeComponent(); + rootView.setImage(mySession.getImage()); + ModelParser.updateRootComponent(rootComponent, mySession, rootView); + + myLayeredPane.repaint(); } }); } - private void updateRenderer(boolean render) throws Throwable { - checkRenderer(render); - - RadViewComponent rootComponent = (RadViewComponent)myRootComponent; - RootView rootView = (RootView)rootComponent.getNativeComponent(); - rootView.setImage(mySession.getImage()); - ModelParser.updateRootComponent(rootComponent, mySession, rootView); - - myLayeredPane.repaint(); - } - - private void checkRenderer(boolean render) throws Throwable { - Result result = render ? mySession.render() : mySession.getResult(); + private void checkRenderer() throws Throwable { + Result result = mySession.getResult(); if (!result.isSuccess()) { System.out.println( "No session: " + result.getErrorMessage() + " : " + result.getStatus() + " : " + result.getData() + " : " + result.getException()); @@ -251,7 +254,6 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { mySession = RenderUtil .createRenderSession(getProject(), layoutXmlText, myFile, manager.getSelectedTarget(), facet, config, xdpi, ydpi, manager.getSelectedTheme()); - System.out.println(mySession + " | " + mySession.getClass()); ApplicationManager.getApplication().invokeLater(new Runnable() { @Override @@ -337,8 +339,14 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @Override @NotNull - protected ComponentCreationFactory createCreationFactory(Item paletteItem) { - return null; // TODO: Auto-generated method stub + protected ComponentCreationFactory createCreationFactory(final Item paletteItem) { + return new ComponentCreationFactory() { + @NotNull + @Override + public RadComponent create() throws Exception { + return ModelParser.createComponent(null, paletteItem.getMetaModel()); + } + }; } @Override @@ -351,7 +359,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { try { myPSIChangeListener.stop(); operation.run(); - updateRenderer(true); + updateRenderer(); return true; } catch (Throwable e) { @@ -370,7 +378,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { for (EditOperation operation : operations) { operation.execute(); } - updateRenderer(true); + updateRenderer(); } catch (Throwable e) { showError("Execute command", e); diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/AttributeProperty.java b/plugins/android-designer/src/com/intellij/android/designer/model/AttributeProperty.java deleted file mode 100644 index cb5080108395..000000000000 --- a/plugins/android-designer/src/com/intellij/android/designer/model/AttributeProperty.java +++ /dev/null @@ -1,144 +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.android.designer.model; - -import com.android.ide.common.rendering.api.RenderSession; -import com.android.ide.common.rendering.api.Result; -import com.intellij.designer.propertyTable.Property; -import com.intellij.designer.propertyTable.PropertyEditor; -import com.intellij.designer.propertyTable.PropertyRenderer; -import com.intellij.designer.propertyTable.editors.AbstractTextFieldEditor; -import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.psi.xml.XmlAttribute; -import org.jetbrains.android.dom.attrs.AttributeDefinition; -import org.jetbrains.annotations.NotNull; - -/** - * @author Alexander Lobas - */ -public class AttributeProperty extends Property { - private final LabelPropertyRenderer myRenderer = new LabelPropertyRenderer(null); - private final AttributeDefinition myDefinition; - private final PropertyEditor myEditor = new AbstractTextFieldEditor() { - @Override - public Object getValue() throws Exception { - return myTextField.getText(); - } - }; - - public AttributeProperty(Property parent, @NotNull AttributeDefinition definition) { - super(parent, definition.getName()); - myDefinition = definition; - } - - @Override - public Object getValue(RadViewComponent component) throws Exception { - Object value = null; - - XmlAttribute attribute = getAttribute(component); - if (attribute != null) { - value = attribute.getValue(); - } - - if (value == null) { - Object viewObject = component.getViewInfo().getViewObject(); - RenderSession session = component.getRoot().getClientProperty(ModelParser.SESSION); - Result result = session.getProperty(viewObject, myDefinition.getName()); - if (result.isSuccess()) { - value = result.getData(); - } - } - return value; - } - - @Override - public void setValue(final RadViewComponent component, final Object value) throws Exception { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - component.getTag().setAttribute("android:" + myDefinition.getName(), (String)value); - } - }); - Object viewObject = component.getViewInfo().getViewObject(); - viewObject.getClass().getMethod("setBackgroundColor", int.class).invoke(viewObject, 0xEE09AA); - /*RenderSession session = component.getRoot().getClientProperty(ModelParser.SESSION); - Result result = session.setProperty(viewObject, myDefinition.getName(), (String)value); - if (!result.isSuccess()) { - System.out.println( - "No set property value(" + - myDefinition + - "): " + - result.getErrorMessage() + - " : " + - result.getStatus() + - " : " + - result.getData() + - " : " + - result.getException()); - }*/ - } - - @Override - public boolean isDefaultValue(RadViewComponent component) throws Exception { - return getAttribute(component) == null; - } - - @Override - public void setDefaultValue(RadViewComponent component) throws Exception { - final XmlAttribute attribute = getAttribute(component); - if (attribute != null) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - attribute.delete(); - } - }); - - Object viewObject = component.getViewInfo().getViewObject(); - RenderSession session = component.getRoot().getClientProperty(ModelParser.SESSION); - Result result = session.setProperty(viewObject, myDefinition.getName(), null); - if (!result.isSuccess()) { - System.out.println( - "No set default property value(" + - myDefinition + - "): " + - result.getErrorMessage() + - " : " + - result.getStatus() + - " : " + - result.getData() + - " : " + - result.getException()); - } - } - } - - private XmlAttribute getAttribute(RadViewComponent component) { - return component.getTag().getAttribute("android:" + myDefinition.getName()); - } - - @NotNull - @Override - public PropertyRenderer getRenderer() { - return myRenderer; - } - - @Override - public PropertyEditor getEditor() { - return myEditor; - } -} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java index 94f7ed29c95e..fa4a6a9692a5 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java @@ -21,9 +21,12 @@ import com.intellij.designer.model.MetaManager; import com.intellij.designer.model.MetaModel; import com.intellij.designer.model.RadComponent; import com.intellij.designer.model.RadLayout; +import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.psi.XmlElementFactory; import com.intellij.psi.XmlRecursiveElementVisitor; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; @@ -35,8 +38,6 @@ import java.util.List; * @author Alexander Lobas */ public class ModelParser extends XmlRecursiveElementVisitor { - public static final String SESSION = "RENDER_LIB_SESSION"; - private final MetaManager myMetaManager; private final XmlFile myXmlFile; private RadViewComponent myRootComponent; @@ -97,7 +98,7 @@ public class ModelParser extends XmlRecursiveElementVisitor { } } - private static RadViewComponent createComponent(XmlTag tag, MetaModel metaModel) throws Exception { + public static RadViewComponent createComponent(XmlTag tag, MetaModel metaModel) throws Exception { RadViewComponent component = (RadViewComponent)metaModel.getModel().newInstance(); component.setMetaModel(metaModel); component.setTag(tag); @@ -110,6 +111,26 @@ public class ModelParser extends XmlRecursiveElementVisitor { return component; } + public static void setComponentTag(final XmlTag parentTag, final RadViewComponent component, final XmlTag nextTag) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + Language language = StdFileTypes.XML.getLanguage(); + XmlTag xmlTag = + XmlElementFactory.getInstance(parentTag.getProject()).createTagFromText(component.getMetaModel().getCreation(), language); + + if (nextTag == null) { + xmlTag = parentTag.addSubTag(xmlTag, false); + } + else { + xmlTag = (XmlTag)parentTag.addBefore(xmlTag, nextTag); + } + + component.setTag(xmlTag); + } + }); + } + ////////////////////////////////////////////////////////////////////////////////////////// // // @@ -151,7 +172,6 @@ public class ModelParser extends XmlRecursiveElementVisitor { rootComponent.setNativeComponent(nativeComponent); rootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); - rootComponent.setClientProperty(SESSION, session); } private static void updateComponent(RadViewComponent component, diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java index 847b8125598e..17b16d4c4892 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -17,12 +17,17 @@ package com.intellij.android.designer.model; import com.android.ide.common.rendering.api.ViewInfo; import com.android.sdklib.IAndroidTarget; +import com.intellij.android.designer.propertyTable.AttributeProperty; +import com.intellij.android.designer.propertyTable.FlagProperty; import com.intellij.designer.model.MetaManager; +import com.intellij.designer.model.MetaModel; import com.intellij.designer.model.RadComponent; import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyTable; import com.intellij.openapi.module.Module; import org.jetbrains.android.dom.attrs.AttributeDefinition; import org.jetbrains.android.dom.attrs.AttributeDefinitions; +import org.jetbrains.android.dom.attrs.AttributeFormat; import org.jetbrains.android.dom.attrs.StyleableDefinition; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.sdk.AndroidTargetData; @@ -36,15 +41,18 @@ import java.util.*; */ @SuppressWarnings("unchecked") public class PropertyParser { + public static final String KEY = "PROPERTY_PARSER"; + + private MetaManager myMetaManager; private AttributeDefinitions myDefinitions; private ProjectClassLoader myClassLoader; private Map> myCachedProperties; public PropertyParser(Module module, IAndroidTarget target) throws Exception { - MetaManager metaManager = ViewsMetaManager.getInstance(module.getProject()); - myCachedProperties = metaManager.getCache(target.hashString()); + myMetaManager = ViewsMetaManager.getInstance(module.getProject()); + myCachedProperties = myMetaManager.getCache(target.hashString()); if (myCachedProperties == null) { - metaManager.setCache(target.hashString(), myCachedProperties = new HashMap>()); + myMetaManager.setCache(target.hashString(), myCachedProperties = new HashMap>()); } AndroidPlatform androidPlatform = AndroidPlatform.getInstance(module); @@ -65,32 +73,87 @@ public class PropertyParser { public void load(RadViewComponent component) throws Exception { ViewInfo info = component.getViewInfo(); + MetaModel model = component.getMetaModel(); if (info == null) { - component.setProperties(Collections.emptyList()); + String target = model.getTarget(); + if (target == null) { + component.setProperties(Collections.emptyList()); + } + else { + component.setProperties(load(myClassLoader.loadClass(target), model)); + } } else { - component.setProperties(load(myClassLoader.loadClass(info.getClassName()))); + component.setProperties(load(myClassLoader.loadClass(info.getClassName()), model)); } } - private List load(Class componentClass) { + private List load(Class componentClass, MetaModel model) { String component = componentClass.getSimpleName(); List properties = myCachedProperties.get(component); if (properties == null) { properties = new ArrayList(); + System.out.println("--- " + componentClass + " -----------------"); + StyleableDefinition definitions = myDefinitions.getStyleableByName(component); if (definitions != null) { for (AttributeDefinition definition : definitions.getAttributes()) { - properties.add(new AttributeProperty(null, definition)); - // TODO + String name = definition.getName(); + Set formats = definition.getFormats(); + Property property; + + if (formats.contains(AttributeFormat.Flag)) { + property = new FlagProperty(name, definition); + } + else { + property = new AttributeProperty(name, definition); + } + + if (model != null) { + property.setImportant(model.isImportantProperty(name)); + property.setExpert(model.isExpertProperty(name)); + property.setDeprecated(model.isDeprecatedProperty(name)); + } + + properties.add(property); + + System.out.println(definition + " = " + Arrays.toString(definition.getValues())); } } Class superComponentClass = componentClass.getSuperclass(); if (superComponentClass != null) { - properties.addAll(load(superComponentClass)); + List superProperties = load(superComponentClass, myMetaManager.getModelByTarget(superComponentClass.getName())); + for (Property superProperty : superProperties) { + if (PropertyTable.findProperty(properties, superProperty) == -1) { + if (model == null) { + properties.add(superProperty); + } + else { + String name = superProperty.getName(); + boolean normal = model.isNormalProperty(name); + boolean important = model.isImportantProperty(name); + boolean expert = model.isExpertProperty(name); + boolean deprecated = model.isDeprecatedProperty(name); + + if ((normal && (superProperty.isImportant() || superProperty.isExpert())) || + (important && !superProperty.isImportant()) || + (expert && !superProperty.isExpert()) || + (deprecated && !superProperty.isDeprecated())) { + Property property = superProperty.createForNewPresentation(); + property.setImportant(important); + property.setExpert(expert); + property.setDeprecated(deprecated); + properties.add(property); + } + else { + properties.add(superProperty); + } + } + } + } } if (!properties.isEmpty()) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java index 1d9f893bfc41..7edb1f0b4213 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java @@ -15,8 +15,108 @@ */ package com.intellij.android.designer.model; +import com.intellij.designer.componentTree.TreeEditOperation; +import com.intellij.designer.designSurface.EditOperation; +import com.intellij.designer.designSurface.FeedbackLayer; +import com.intellij.designer.designSurface.OperationContext; +import com.intellij.designer.designSurface.feedbacks.AlphaComponent; +import com.intellij.designer.model.RadComponent; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + /** * @author Alexander Lobas */ public class RadLinearLayout extends RadViewLayout { + @Override + public EditOperation processChildOperation(OperationContext context) { + if (context.isCreate()) { + return context.isTree() ? new TreeCreateOperation(myContainer, context) : new CreateOperation(context); + } + return null; + } + + private void addNewComponent(RadViewComponent newComponent, @Nullable RadViewComponent insertBefore) throws Exception { + RadViewComponent container = (RadViewComponent)myContainer; + newComponent.setParent(container); + + List children = container.getChildren(); + if (insertBefore == null) { + children.add(newComponent); + } + else { + children.add(children.indexOf(insertBefore), newComponent); + } + + ModelParser + .setComponentTag(container.getTag(), newComponent, insertBefore == null ? null : insertBefore.getTag()); + + PropertyParser propertyParser = container.getRoot().getClientProperty(PropertyParser.KEY); + propertyParser.load(newComponent); + } + + private class TreeCreateOperation extends TreeEditOperation { + public TreeCreateOperation(RadComponent host, OperationContext context) { + super(host, context); + } + + @Override + protected void execute(RadComponent insertBefore) throws Exception { + addNewComponent((RadViewComponent)myComponents.get(0), (RadViewComponent)insertBefore); + } + } + + private class CreateOperation implements EditOperation { + private final OperationContext myContext; + private RadComponent myComponent; + private JComponent myFeedback; + + private CreateOperation(OperationContext context) { + myContext = context; + } + + @Override + public void setComponent(RadComponent component) { + myComponent = component; + } + + @Override + public void setComponents(List components) { + } + + @Override + public void showFeedback() { + FeedbackLayer layer = myContext.getArea().getFeedbackLayer(); + + if (myFeedback == null) { + myFeedback = new AlphaComponent(Color.green); + layer.add(myFeedback); + myFeedback.setBounds(myContainer.getBounds(layer)); + layer.repaint(); + } + } + + @Override + public void eraseFeedback() { + if (myFeedback != null) { + FeedbackLayer layer = myContext.getArea().getFeedbackLayer(); + layer.remove(myFeedback); + layer.repaint(); + myFeedback = null; + } + } + + @Override + public boolean canExecute() { + return true; + } + + @Override + public void execute() throws Exception { + addNewComponent((RadViewComponent)myComponent, null); + } + } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java index c5284df9f637..9e22ed5910a7 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -18,6 +18,7 @@ package com.intellij.android.designer.model; import com.android.ide.common.rendering.api.ViewInfo; import com.intellij.designer.model.RadComponent; import com.intellij.designer.propertyTable.Property; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.xml.XmlTag; import javax.swing.*; @@ -84,6 +85,18 @@ public class RadViewComponent extends RadComponent { return SwingUtilities.convertPoint(component, x, y, myNativeComponent); } + @Override + public void delete() throws Exception { + getParent().getChildren().remove(this); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + myTag.delete(); + } + }); + } + @Override public List getProperties() { return myProperties; diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index 3c22363a76ce..81cb4c375d41 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -21,6 +21,19 @@ + + + + + + + + @@ -29,6 +42,11 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java new file mode 100644 index 000000000000..23c645a6550d --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java @@ -0,0 +1,134 @@ +/* + * 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.android.designer.propertyTable; + +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.android.designer.propertyTable.editors.BooleanEditor; +import com.intellij.android.designer.propertyTable.renderers.BooleanRenderer; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.designer.propertyTable.PropertyRenderer; +import com.intellij.designer.propertyTable.editors.AbstractTextFieldEditor; +import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.xml.XmlAttribute; +import org.jetbrains.android.dom.attrs.AttributeDefinition; +import org.jetbrains.android.dom.attrs.AttributeFormat; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +/** + * @author Alexander Lobas + */ +public class AttributeProperty extends Property { + private final AttributeDefinition myDefinition; + private final PropertyRenderer myRenderer; + private final PropertyEditor myEditor; + + public AttributeProperty(@NotNull String name, @NotNull AttributeDefinition definition) { + super(null, name); + myDefinition = definition; + + Set formats = definition.getFormats(); + if (formats.contains(AttributeFormat.Boolean)) { + myRenderer = new BooleanRenderer(); + myEditor = new BooleanEditor(); + } + else { + myRenderer = new LabelPropertyRenderer(null); + + if (formats.contains(AttributeFormat.Enum)) { + + } + else { + + } + + myEditor = new AbstractTextFieldEditor() { + @Override + public Object getValue() throws Exception { + return myTextField.getText(); + } + }; + } + } + + @Override + public Property createForNewPresentation() { + return new AttributeProperty(getName(), myDefinition); + } + + @Override + public Object getValue(RadViewComponent component) throws Exception { + Object value = null; + + XmlAttribute attribute = getAttribute(component); + if (attribute != null) { + value = attribute.getValue(); + } + + return value == null ? "" : value; + } + + @Override + public void setValue(final RadViewComponent component, final Object value) throws Exception { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + if (StringUtil.isEmpty((String)value)) { + XmlAttribute attribute = getAttribute(component); + if (attribute != null) { + attribute.delete(); + } + } + else { + component.getTag().setAttribute("android:" + myDefinition.getName(), (String)value); + } + } + }); + } + + @Override + public boolean isDefaultValue(RadViewComponent component) throws Exception { + return getAttribute(component) == null; + } + + @Override + public void setDefaultValue(RadViewComponent component) throws Exception { + if (getAttribute(component) != null) { + setValue(component, null); + } + } + + @Nullable + private XmlAttribute getAttribute(RadViewComponent component) { + return component.getTag().getAttribute("android:" + myDefinition.getName()); + } + + @NotNull + @Override + public PropertyRenderer getRenderer() { + return myRenderer; + } + + @Override + public PropertyEditor getEditor() { + return myEditor; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java new file mode 100644 index 000000000000..36bc7426b7b1 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/FlagProperty.java @@ -0,0 +1,81 @@ +/* + * 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.android.designer.propertyTable; + +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.designer.propertyTable.PropertyRenderer; +import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; +import org.jetbrains.android.dom.attrs.AttributeDefinition; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class FlagProperty extends Property { + private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null); + private final AttributeDefinition myDefinition; + + public FlagProperty(@NotNull String name, @NotNull AttributeDefinition definition) { + super(null, name); + myDefinition = definition; + } + + @Override + public Property createForNewPresentation() { + return new FlagProperty(getName(), myDefinition); + } + + @Override + public List getChildren(@Nullable RadViewComponent component) { + return super.getChildren(component); // TODO: Auto-generated method stub + } + + @Override + public Object getValue(RadViewComponent component) throws Exception { + return "[]"; + } + + @Override + public void setValue(RadViewComponent component, Object value) throws Exception { + super.setValue(component, value); // TODO: Auto-generated method stub + } + + @Override + public boolean isDefaultValue(RadViewComponent component) throws Exception { + return super.isDefaultValue(component); // TODO: Auto-generated method stub + } + + @Override + public void setDefaultValue(RadViewComponent component) throws Exception { + super.setDefaultValue(component); // TODO: Auto-generated method stub + } + + @NotNull + @Override + public PropertyRenderer getRenderer() { + return myRenderer; + } + + @Override + public PropertyEditor getEditor() { + return null; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/BooleanEditor.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/BooleanEditor.java new file mode 100644 index 000000000000..ba21dcd2c6d6 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/BooleanEditor.java @@ -0,0 +1,33 @@ +/* + * 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.android.designer.propertyTable.editors; + +import com.intellij.openapi.util.text.StringUtil; + +/** + * @author Alexander Lobas + */ +public class BooleanEditor extends com.intellij.designer.propertyTable.editors.BooleanEditor { + @Override + public Object getValue() throws Exception { + return Boolean.toString(myCheckBox.isSelected()); + } + + @Override + protected boolean getValue(Object value) { + return Boolean.parseBoolean((String)value); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/BooleanRenderer.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/BooleanRenderer.java new file mode 100644 index 000000000000..61adcd26ebb1 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/renderers/BooleanRenderer.java @@ -0,0 +1,26 @@ +/* + * 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.android.designer.propertyTable.renderers; + +/** + * @author Alexander Lobas + */ +public class BooleanRenderer extends com.intellij.designer.propertyTable.renderers.BooleanRenderer { + @Override + protected boolean getValue(Object value) { + return Boolean.parseBoolean((String)value); + } +} \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryAction.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryAction.java index 11cda9efb863..5c822b1245bf 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryAction.java @@ -1,5 +1,6 @@ package org.jetbrains.android.actions; +import com.android.resources.ResourceFolderType; import com.intellij.CommonBundle; import com.intellij.ide.actions.CreateElementActionBase; import com.intellij.openapi.actionSystem.DataContext; @@ -22,15 +23,23 @@ import java.io.File; * @author Eugene.Kudelevsky */ public class CreateResourceDirectoryAction extends CreateElementActionBase { + private final ResourceFolderType myResourceFolderType; + + @SuppressWarnings("UnusedDeclaration") public CreateResourceDirectoryAction() { + this(null); + } + + public CreateResourceDirectoryAction(@Nullable ResourceFolderType resourceFolderType) { super(AndroidBundle.message("new.resource.dir.action.title"), AndroidBundle.message("new.resource.action.description"), PlatformIcons.DIRECTORY_CLOSED_ICON); + myResourceFolderType = resourceFolderType; } @NotNull @Override - protected PsiElement[] invokeDialog(final Project project, final PsiDirectory directory) { - final CreateResourceDirectoryDialog dialog = new CreateResourceDirectoryDialog(project) { + public PsiElement[] invokeDialog(final Project project, final PsiDirectory directory) { + final CreateResourceDirectoryDialog dialog = new CreateResourceDirectoryDialog(project, myResourceFolderType) { @Override protected InputValidator createValidator() { return CreateResourceDirectoryAction.this.createValidator(project, directory); diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.form b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.form index 13ff3aa495d2..6e6d2e12dbb7 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.form +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.form @@ -47,7 +47,7 @@ - + diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.java b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.java index 4c284c98cec3..fa10c6a667c5 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateResourceDirectoryDialog.java @@ -26,6 +26,7 @@ import com.intellij.ui.components.JBLabel; import org.jetbrains.android.uipreview.DeviceConfiguratorPanel; import org.jetbrains.android.uipreview.InvalidOptionValueException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -45,7 +46,7 @@ public abstract class CreateResourceDirectoryDialog extends DialogWrapper { private final DeviceConfiguratorPanel myDeviceConfiguratorPanel; private InputValidator myValidator; - public CreateResourceDirectoryDialog(@NotNull Project project) { + public CreateResourceDirectoryDialog(@NotNull Project project, @Nullable ResourceFolderType resType) { super(project); myResourceTypeComboBox.setModel(new EnumComboBoxModel(ResourceFolderType.class)); @@ -84,6 +85,11 @@ public abstract class CreateResourceDirectoryDialog extends DialogWrapper { } }); + if (resType != null) { + myResourceTypeComboBox.setSelectedItem(resType); + myResourceTypeComboBox.setEnabled(false); + } + myDeviceConfiguratorPanel.updateAll(); setOKActionEnabled(myDirectoryNameTextField.getText().length() > 0); init(); diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.form b/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.form index e259ae3a5dad..2fc86f924add 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.form +++ b/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.form @@ -1,21 +1,13 @@
- + - + - - - - - - - - @@ -48,29 +40,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -88,6 +57,22 @@ + + + + + + + + + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java b/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java index 2138266bb93c..edcb31fb12c9 100644 --- a/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java +++ b/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java @@ -1,57 +1,68 @@ package org.jetbrains.android.actions; -import com.android.AndroidConstants; -import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.resources.ResourceFolderType; import com.android.resources.ResourceType; import com.intellij.CommonBundle; import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.fileChooser.actions.VirtualFileDeleteProvider; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; +import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; +import com.intellij.util.ArrayUtil; +import com.intellij.util.PlatformIcons; import com.intellij.util.containers.HashSet; +import com.intellij.util.containers.hash.HashMap; import org.jetbrains.android.dom.resources.ResourceElement; import org.jetbrains.android.dom.resources.Resources; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; -import org.jetbrains.android.uipreview.DeviceConfiguratorPanel; -import org.jetbrains.android.uipreview.InvalidOptionValueException; import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidResourceUtil; import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.*; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Set; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.*; /** * @author Eugene.Kudelevsky */ public class CreateXmlResourceDialog extends DialogWrapper { private JPanel myPanel; - private JPanel myDeviceConfigurationWrapper; private JTextField myNameField; private JComboBox myModuleCombo; private JBLabel myModuleLabel; - private JTextField myDirectoryNameField; - private JBLabel myErrorLabel; private JTextField myFileNameField; + private JPanel myDirectoriesPanel; + private JBLabel myDirectoriesLabel; - private final DeviceConfiguratorPanel myDeviceConfiguratorPanel; private final Module myModule; private final ResourceType myResourceType; + private Map myCheckBoxes = Collections.emptyMap(); + private String[] myDirNames = ArrayUtil.EMPTY_STRING_ARRAY; + + private final CheckBoxList myDirectoriesList; + private VirtualFile myResourceDir; + public CreateXmlResourceDialog(@NotNull Module module, @NotNull ResourceType resourceType) { super(module.getProject()); @@ -94,39 +105,189 @@ public class CreateXmlResourceDialog extends DialogWrapper { }); } - myDeviceConfiguratorPanel = new DeviceConfiguratorPanel(null) { - @Override - public void applyEditors() { - try { - doApplyEditors(); - - final FolderConfiguration config = myDeviceConfiguratorPanel.getConfiguration(); - myErrorLabel.setText(""); - myDirectoryNameField.setText(config.getFolderName(ResourceFolderType.VALUES)); - } - catch (InvalidOptionValueException e) { - myErrorLabel.setText("" + e.getMessage() + ""); - myDirectoryNameField.setText(AndroidConstants.FD_RES_VALUES); - } - } - }; - myDeviceConfigurationWrapper.add(myDeviceConfiguratorPanel, BorderLayout.CENTER); - final String defaultResFileName = AndroidResourceUtil.getDefaultResourceFileName(resourceType.getName()); if (defaultResFileName != null) { myFileNameField.setText(defaultResFileName); } - myDirectoryNameField.setText(AndroidConstants.FD_RES_VALUES); - myDeviceConfiguratorPanel.updateAll(); + + + myDirectoriesList = new CheckBoxList(); + myDirectoriesLabel.setLabelFor(myDirectoriesList); + final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myDirectoriesList); + + decorator.setEditAction(null); + decorator.disableUpDownActions(); + + decorator.setAddAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + doAddNewDirectory(); + } + }); + + decorator.setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton button) { + doDeleteDirectory(); + } + }); + + final AnActionButton selectAll = new AnActionButton("Select All", null, PlatformIcons.SELECT_ALL_ICON) { + @Override + public void actionPerformed(AnActionEvent e) { + doSelectAllDirs(); + } + }; + decorator.addExtraAction(selectAll); + + final AnActionButton unselectAll = new AnActionButton("Unselect All", null, PlatformIcons.UNSELECT_ALL_ICON) { + @Override + public void actionPerformed(AnActionEvent e) { + doUnselectAllDirs(); + } + }; + decorator.addExtraAction(unselectAll); + + myDirectoriesPanel.add(decorator.createPanel()); + + updateDirectories(); + + myModuleCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateDirectories(); + } + }); init(); } + private void doDeleteDirectory() { + if (myResourceDir == null) { + return; + } + + final int selectedIndex = myDirectoriesList.getSelectedIndex(); + if (selectedIndex < 0) { + return; + } + + final String selectedDirName = myDirNames[selectedIndex]; + final VirtualFile selectedDir = myResourceDir.findChild(selectedDirName); + if (selectedDir == null) { + return; + } + + final VirtualFileDeleteProvider provider = new VirtualFileDeleteProvider(); + provider.deleteElement(new DataContext() { + @Override + public Object getData(@NonNls String dataId) { + if (PlatformDataKeys.VIRTUAL_FILE_ARRAY.getName().equals(dataId)) { + return new VirtualFile[] {selectedDir}; + } + else { + return null; + } + } + }); + updateDirectories(); + } + + private void doSelectAllDirs() { + for (JCheckBox checkBox : myCheckBoxes.values()) { + checkBox.setSelected(true); + } + myDirectoriesList.repaint(); + } + + private void doUnselectAllDirs() { + for (JCheckBox checkBox : myCheckBoxes.values()) { + checkBox.setSelected(false); + } + myDirectoriesList.repaint(); + } + + private void doAddNewDirectory() { + if (myResourceDir == null) { + return; + } + final Module module = getModule(); + if (module == null) { + return; + } + final Project project = module.getProject(); + final PsiDirectory psiResDir = PsiManager.getInstance(project).findDirectory(myResourceDir); + + if (psiResDir != null) { + final PsiElement[] createdElements = new CreateResourceDirectoryAction(ResourceFolderType.VALUES).invokeDialog(project, psiResDir); + + if (createdElements.length > 0) { + updateDirectories(); + } + } + } + + private void updateDirectories() { + final Module module = getModule(); + List valuesDirs = Collections.emptyList(); + + if (module != null) { + final AndroidFacet facet = AndroidFacet.getInstance(module); + + if (facet != null) { + myResourceDir = AndroidRootUtil.getResourceDir(facet); + + if (myResourceDir != null) { + valuesDirs = AndroidResourceUtil.getResourceSubdirs(ResourceFolderType.VALUES.getName(), new VirtualFile[]{myResourceDir}); + } + } + } + + Collections.sort(valuesDirs, new Comparator() { + @Override + public int compare(VirtualFile f1, VirtualFile f2) { + return f1.getName().compareTo(f2.getName()); + } + }); + + final Map oldCheckBoxes = myCheckBoxes; + final int selectedIndex = myDirectoriesList.getSelectedIndex(); + final String selectedDirName = selectedIndex >= 0 ? myDirNames[selectedIndex] : null; + + final List checkBoxList = new ArrayList(); + myCheckBoxes = new HashMap(); + myDirNames = new String[valuesDirs.size()]; + + int newSelectedIndex = -1; + + int i = 0; + + for (VirtualFile dir : valuesDirs) { + final String dirName = dir.getName(); + final JCheckBox oldCheckBox = oldCheckBoxes.get(dirName); + final boolean selected = oldCheckBox != null && oldCheckBox.isSelected(); + final JCheckBox checkBox = new JCheckBox(dirName, selected); + checkBoxList.add(checkBox); + myCheckBoxes.put(dirName, checkBox); + myDirNames[i] = dirName; + + if (dirName.equals(selectedDirName)) { + newSelectedIndex = i; + } + i++; + } + myDirectoriesList.setModel(new CollectionListModel(checkBoxList)); + + if (newSelectedIndex >= 0) { + myDirectoriesList.setSelectedIndex(newSelectedIndex); + } + } + @Override protected ValidationInfo doValidate() { final String resourceName = getResourceName(); final Module selectedModule = getModule(); - final String directoryName = getDirectoryName(); + final List directoryNames = getDirNames(); final String fileName = getFileName(); if (resourceName.length() == 0) { @@ -141,23 +302,14 @@ public class CreateXmlResourceDialog extends DialogWrapper { else if (selectedModule == null) { return new ValidationInfo("specify module", myModuleCombo); } - else if (!ResourceFolderType.VALUES.getName().equals( - AndroidCommonUtils.getResourceTypeByDirName(directoryName))) { - return new ValidationInfo("directory name is not appropriate for value resources"); + else if (directoryNames.size() == 0) { + return new ValidationInfo("choose directories", myDirectoriesList); } - final ValidationInfo info = checkIfResourceAlreadyExists(selectedModule, resourceName, myResourceType, directoryName, fileName); + final ValidationInfo info = checkIfResourceAlreadyExists(selectedModule, resourceName, myResourceType, directoryNames, fileName); if (info != null) { return info; } - - try { - myDeviceConfiguratorPanel.doApplyEditors(); - } - catch (InvalidOptionValueException e) { - return new ValidationInfo("fix errors in configuration editor"); - } - return null; } @@ -165,10 +317,10 @@ public class CreateXmlResourceDialog extends DialogWrapper { private static ValidationInfo checkIfResourceAlreadyExists(@NotNull Module selectedModule, @NotNull String resourceName, @NotNull ResourceType resourceType, - @NotNull String directoryName, + @NotNull List dirNames, @NotNull String fileName) { if (resourceName.length() == 0 || - directoryName.length() == 0 || + dirNames.size() == 0 || fileName.length() == 0) { return null; } @@ -179,29 +331,31 @@ public class CreateXmlResourceDialog extends DialogWrapper { return null; } - final VirtualFile resourceSubdir = resourceDir.findChild(directoryName); - if (resourceSubdir == null) { - return null; - } + for (String directoryName : dirNames) { + final VirtualFile resourceSubdir = resourceDir.findChild(directoryName); + if (resourceSubdir == null) { + continue; + } - final VirtualFile resFile = resourceSubdir.findChild(fileName); - if (resFile == null) { - return null; - } + final VirtualFile resFile = resourceSubdir.findChild(fileName); + if (resFile == null) { + continue; + } - if (resFile.getFileType() != StdFileTypes.XML) { - return new ValidationInfo("File " + FileUtil.toSystemDependentName(resFile.getPath()) + " is not XML file"); - } + if (resFile.getFileType() != StdFileTypes.XML) { + return new ValidationInfo("File " + FileUtil.toSystemDependentName(resFile.getPath()) + " is not XML file"); + } - final Resources resources = AndroidUtils.loadDomElement(selectedModule, resFile, Resources.class); - if (resources == null) { - return new ValidationInfo(AndroidBundle.message("not.resource.file.error", FileUtil.toSystemDependentName(resFile.getPath()))); - } + final Resources resources = AndroidUtils.loadDomElement(selectedModule, resFile, Resources.class); + if (resources == null) { + return new ValidationInfo(AndroidBundle.message("not.resource.file.error", FileUtil.toSystemDependentName(resFile.getPath()))); + } - for (ResourceElement element : AndroidResourceUtil.getValueResourcesFromElement(resourceType.getName(), resources)) { - if (resourceName.equals(element.getName().getValue())) { - return new ValidationInfo("resource '" + resourceName + "' already exists in " + FileUtil.toSystemDependentName( - resFile.getPath())); + for (ResourceElement element : AndroidResourceUtil.getValueResourcesFromElement(resourceType.getName(), resources)) { + if (resourceName.equals(element.getName().getValue())) { + return new ValidationInfo("resource '" + resourceName + "' already exists in " + FileUtil.toSystemDependentName( + resFile.getPath())); + } } } return null; @@ -216,7 +370,7 @@ public class CreateXmlResourceDialog extends DialogWrapper { protected void doOKAction() { final String resourceName = getResourceName(); final String fileName = getFileName(); - final String dirName = getDirectoryName(); + final List dirNames = getDirNames(); final Module module = getModule(); if (resourceName.length() == 0) { @@ -228,8 +382,8 @@ public class CreateXmlResourceDialog extends DialogWrapper { else if (fileName.length() == 0) { Messages.showErrorDialog(myPanel, "File name is not specified", CommonBundle.getErrorTitle()); } - else if (dirName.length() == 0) { - Messages.showErrorDialog(myPanel, "Directory name is not specified", CommonBundle.getErrorTitle()); + else if (dirNames.size() == 0) { + Messages.showErrorDialog(myPanel, "Directories are not selected", CommonBundle.getErrorTitle()); } else if (module == null) { Messages.showErrorDialog(myPanel, "Module is not specified", CommonBundle.getErrorTitle()); @@ -245,8 +399,15 @@ public class CreateXmlResourceDialog extends DialogWrapper { } @NotNull - public String getDirectoryName() { - return myDirectoryNameField.getText().trim(); + public List getDirNames() { + final List selectedDirs = new ArrayList(); + + for (Map.Entry entry : myCheckBoxes.entrySet()) { + if (entry.getValue().isSelected()) { + selectedDirs.add(entry.getKey()); + } + } + return selectedDirs; } @NotNull diff --git a/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java b/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java index e6e4e54ba23b..990d166a93de 100644 --- a/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java +++ b/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java @@ -67,7 +67,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.Collections; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import static org.jetbrains.android.util.AndroidUtils.VIEW_CLASS_NAME; @@ -204,20 +206,14 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction impl return; } - final ResourceElement createdElement = - doCreate(module, dialog.getResourceName(), ResourceType.STRING, dialog.getFileName(), dialog.getDirectoryName(), value); - - if (createdElement != null) { - resName = createdElement.getName().getValue(); + resName = dialog.getResourceName(); + if (!doCreate(module, resName, ResourceType.STRING, dialog.getFileName(), dialog.getDirNames(), value)) { + return; } } else { assert ApplicationManager.getApplication().isUnitTestMode(); - doCreate(facet.getModule(), resName, ResourceType.STRING, "strings.xml", "values", value); - } - - if (resName == null) { - return; + doCreate(facet.getModule(), resName, ResourceType.STRING, "strings.xml", Collections.singletonList("values"), value); } if (file instanceof PsiJavaFile) { @@ -358,19 +354,18 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction impl return true; } - @Nullable - private static ResourceElement doCreate(@NotNull Module module, - @NotNull String resourceName, - @NotNull ResourceType resourceType, - @NotNull String fileName, - @NotNull String dirName, - @NotNull String value) { + private static boolean doCreate(@NotNull Module module, + @NotNull String resourceName, + @NotNull ResourceType resourceType, + @NotNull String fileName, + @NotNull List dirNames, + @NotNull String value) { final Project project = module.getProject(); final AndroidFacet facet = AndroidFacet.getInstance(module); assert facet != null; try { - return addValueResource(facet, resourceName, resourceType, fileName, dirName, value); + return addValueResource(facet, resourceName, resourceType, fileName, dirNames, value); } catch (Exception e) { final String message = CreateElementActionBase.filterMessage(e.getMessage()); @@ -382,36 +377,52 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction impl LOG.info(e); reportError(project, message); } - return null; + return false; } } - @Nullable - public static ResourceElement addValueResource(@NotNull AndroidFacet facet, - @NotNull String resourceName, - @NotNull ResourceType resourceType, - @NotNull String fileName, - @NotNull String dirName, - @NotNull String value) throws Exception { - final VirtualFile resFile = findOrCreateResourceFile(facet, fileName, dirName); - if (resFile == null || - !ReadonlyStatusHandler.ensureFilesWritable(facet.getModule().getProject(), resFile)) { - return null; + private static boolean addValueResource(@NotNull AndroidFacet facet, + @NotNull String resourceName, + @NotNull ResourceType resourceType, + @NotNull String fileName, + @NotNull List dirNames, + @NotNull String value) throws Exception { + if (dirNames.size() == 0) { + return false; + } + final VirtualFile[] resFiles = new VirtualFile[dirNames.size()]; + + for (int i = 0, n = dirNames.size(); i < n; i++) { + final VirtualFile resFile = findOrCreateResourceFile(facet, fileName, dirNames.get(i)); + if (resFile == null) { + return false; + } + resFiles[i] = resFile; + } + + if (!ReadonlyStatusHandler.ensureFilesWritable(facet.getModule().getProject(), resFiles)) { + return false; + } + final Resources[] resourcesElements = new Resources[resFiles.length]; + + for (int i = 0; i < resFiles.length; i++) { + final Resources resources = AndroidUtils.loadDomElement(facet.getModule(), resFiles[i], Resources.class); + if (resources == null) { + reportError(facet.getModule().getProject(), AndroidBundle.message("not.resource.file.error", fileName)); + return false; + } + resourcesElements[i] = resources; } - final Resources resources = AndroidUtils.loadDomElement(facet.getModule(), resFile, Resources.class); - if (resources == null) { - reportError(facet.getModule().getProject(), AndroidBundle.message("not.resource.file.error", fileName)); - return null; - } + for (Resources resources : resourcesElements) { + final ResourceElement element = AndroidResourceUtil.addValueResource(resourceType.getName(), resources); + element.getName().setValue(resourceName); - final ResourceElement element = AndroidResourceUtil.addValueResource(resourceType.getName(), resources); - element.getName().setValue(resourceName); - - if (value.length() > 0) { - element.setStringValue(value); + if (value.length() > 0) { + element.setStringValue(value); + } } - return element; + return true; } @Nullable diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index f0962113c606..f16a34ca5f0c 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -224,6 +224,7 @@ + getTargets() { + GrReferenceList list = + GroovyTokenTypes.kEXTENDS == myTarget.getNode().getElementType() ? myClass.getExtendsClause() : myClass.getImplementsClause(); + if (list == null) return Collections.emptyList(); + final PsiClassType[] classTypes = list.getReferenceTypes(); + return ChooseClassAndDoHighlightRunnable.resolveClasses(classTypes); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightOverridingMethodsHandlerFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightOverridingMethodsHandlerFactory.java new file mode 100644 index 000000000000..702bd4ce55cd --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightOverridingMethodsHandlerFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.findUsages; + +import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase; +import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory; +import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IElementType; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; + +/** + * @author Max Medvedev + */ +public class GrHighlightOverridingMethodsHandlerFactory implements HighlightUsagesHandlerFactory { + @Override + public HighlightUsagesHandlerBase createHighlightUsagesHandler(Editor editor, PsiFile file) { + int offset = TargetElementUtilBase.adjustOffset(editor.getDocument(), editor.getCaretModel().getOffset()); + final PsiElement target = file.findElementAt(offset); + if (target == null) return null; + + ASTNode node = target.getNode(); + if (node == null) return null; + + IElementType type = node.getElementType(); + if (type == GroovyTokenTypes.kIMPLEMENTS || type == GroovyTokenTypes.kEXTENDS) { + PsiElement parent = target.getParent(); + if (!(parent instanceof GrReferenceList)) return null; + PsiElement grand = parent.getParent(); + if (!(grand instanceof GrTypeDefinition)) return null; + return new GrHighlightOverridingMethodsHandler(editor, file, target, (GrTypeDefinition)grand); + } + return null; + } +} diff --git a/plugins/groovy/testdata/highlighting/CollectionAssignments.groovy b/plugins/groovy/testdata/highlighting/CollectionAssignments.groovy index 6a16aadade4a..03e0bada3cf2 100644 --- a/plugins/groovy/testdata/highlighting/CollectionAssignments.groovy +++ b/plugins/groovy/testdata/highlighting/CollectionAssignments.groovy @@ -1,4 +1,4 @@ class Pair {} List otherPairs = new ArrayList(); List pairs = otherPairs.findAll({it != null}) -List pairs2 = otherPairs.findAll({it != null}) \ No newline at end of file +List pairs2 = otherPairs.findAll({it != null}) \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/OperationContext.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/OperationContext.java index 20a197ee4c1a..fb49fd694d25 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/OperationContext.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/OperationContext.java @@ -85,6 +85,10 @@ public final class OperationContext { return is(PASTE); } + public boolean isTree() { + return myArea.isTree(); + } + public EditableArea getArea() { return myArea; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java index 1c6d4c5bf910..95e6a6ec50fe 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java @@ -21,6 +21,8 @@ import com.intellij.ide.palette.PaletteGroup; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; @@ -78,7 +80,8 @@ public abstract class MetaManager { @SuppressWarnings("unchecked") private void loadModel(ClassLoader classLoader, Element element) throws Exception { - Class model = (Class)classLoader.loadClass(element.getAttributeValue("model")); + String modelValue = element.getAttributeValue("model"); + Class model = modelValue == null ? null : (Class)classLoader.loadClass(modelValue); String target = element.getAttributeValue("class"); String tag = element.getAttributeValue(TAG); @@ -95,15 +98,42 @@ public abstract class MetaManager { } Element palette = element.getChild("palette"); - meta.setPaletteItem( - new Item(palette.getAttributeValue("title"), palette.getAttributeValue("icon"), palette.getAttributeValue("tooltip"))); + if (palette != null) { + meta.setPaletteItem( + new Item(palette.getAttributeValue("title"), palette.getAttributeValue("icon"), palette.getAttributeValue("tooltip"))); + } Element creation = element.getChild("creation"); if (creation != null) { meta.setCreation(creation.getTextTrim()); } - myTag2Model.put(tag, meta); + Element properties = element.getChild("properties"); + if (properties != null) { + Attribute normal = properties.getAttribute("normal"); + if (normal != null) { + meta.setNormalProperties(StringUtil.split(normal.getValue(), " ")); + } + + Attribute important = properties.getAttribute("important"); + if (important != null) { + meta.setImportantProperties(StringUtil.split(important.getValue(), " ")); + } + + Attribute expert = properties.getAttribute("expert"); + if (expert != null) { + meta.setExpertProperties(StringUtil.split(expert.getValue(), " ")); + } + + Attribute deprecated = properties.getAttribute("deprecated"); + if (deprecated != null) { + meta.setDeprecatedProperties(StringUtil.split(deprecated.getValue(), " ")); + } + } + + if (tag != null) { + myTag2Model.put(tag, meta); + } if (target != null) { myTarget2Model.put(target, meta); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java index e6e8a0ed9c08..add10d839504 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java @@ -20,6 +20,8 @@ import com.intellij.openapi.util.IconLoader; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.util.Collections; +import java.util.List; /** * @author Alexander Lobas @@ -34,6 +36,10 @@ public class MetaModel { private String myIconPath; private Icon myIcon; private String myCreation; + private List myNormalProperties = Collections.emptyList(); + private List myImportantProperties = Collections.emptyList(); + private List myExpertProperties = Collections.emptyList(); + private List myDeprecatedProperties = Collections.emptyList(); public MetaModel(Class model, String target, String tag) { myModel = model; @@ -97,4 +103,36 @@ public class MetaModel { myPaletteItem = paletteItem; myPaletteItem.setMetaModel(this); } + + public boolean isNormalProperty(String name) { + return myNormalProperties.contains(name); + } + + public void setNormalProperties(List normalProperties) { + myNormalProperties = normalProperties; + } + + public boolean isImportantProperty(String name) { + return myImportantProperties.contains(name); + } + + public void setImportantProperties(List importantProperties) { + myImportantProperties = importantProperties; + } + + public boolean isExpertProperty(String name) { + return myExpertProperties.contains(name); + } + + public void setExpertProperties(List expertProperties) { + myExpertProperties = expertProperties; + } + + public boolean isDeprecatedProperty(String name) { + return myDeprecatedProperties.contains(name); + } + + public void setDeprecatedProperties(List deprecatedProperties) { + myDeprecatedProperties = deprecatedProperties; + } } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java index b9df01a7e163..c84a5b97aa3c 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java @@ -117,6 +117,7 @@ public abstract class RadComponent { public void setLayout(RadLayout layout) { myLayout = layout; + myLayout.setContainer(this); } @Nullable diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java index 7f4e0982a868..509ed90ffdc8 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java @@ -28,6 +28,12 @@ import java.util.List; * @author Alexander Lobas */ public abstract class RadLayout { + protected RadComponent myContainer; + + public void setContainer(RadComponent container) { + myContainer = container; + } + public abstract ComponentDecorator getChildSelectionDecorator(RadComponent component, List selection); @Nullable diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/Property.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/Property.java index e1b8f1b06a13..eda3c2457be5 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/Property.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/Property.java @@ -16,7 +16,6 @@ package com.intellij.designer.propertyTable; import com.intellij.designer.model.RadComponent; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -28,16 +27,17 @@ import java.util.List; */ public abstract class Property { private final Property myParent; - @NotNull private final String myName; + private final String myName; private boolean myImportant; private boolean myExpert; private boolean myDeprecated; - public Property(Property parent, @NotNull @NonNls String name) { + public Property(@Nullable Property parent, @NotNull String name) { myParent = parent; myName = name; } + public abstract Property createForNewPresentation(); ////////////////////////////////////////////////////////////////////////////////////////// // // Hierarchy diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java index aa09202a737c..fd01b9eda4eb 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java @@ -333,7 +333,7 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi } } - private static int findProperty(List properties, Property property) { + public static int findProperty(List properties, Property property) { String name = property.getName(); int size = properties.size(); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java index 59598423eefd..1e181cc43015 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java @@ -30,7 +30,7 @@ import java.awt.event.ActionListener; * @author Vladimir Kondratyev */ public class BooleanEditor extends PropertyEditor { - private final JCheckBox myCheckBox; + protected final JCheckBox myCheckBox; private boolean myInsideChange; public BooleanEditor() { @@ -52,12 +52,16 @@ public class BooleanEditor extends PropertyEditor { return Boolean.valueOf(myCheckBox.isSelected()); } + protected boolean getValue(Object value) { + return value != null && (Boolean)value; + } + @NotNull public JComponent getComponent(@Nullable RadComponent component, Object value) { try { myInsideChange = true; myCheckBox.setBackground(UIUtil.getTableBackground()); - myCheckBox.setSelected(value != null && (Boolean)value); + myCheckBox.setSelected(getValue(value)); return myCheckBox; } finally { diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/ComboEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/ComboEditor.java new file mode 100644 index 000000000000..059121bed4c9 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/ComboEditor.java @@ -0,0 +1,74 @@ +/* + * 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.designer.propertyTable.editors; + +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.openapi.ui.ComboBox; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; + +/** + * @author Alexander Lobas + */ +public class ComboEditor extends PropertyEditor { + protected final ComboBox myCombo; + + public ComboEditor() { + myCombo = new ComboBox(-1); + myCombo.setBorder(null); + myCombo.addPopupMenuListener(new PopupMenuListener() { + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + // TODO: Auto-generated method stub + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + // TODO: Auto-generated method stub + } + + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + // TODO: Auto-generated method stub + } + }); + } + + @Override + public void updateUI() { + SwingUtilities.updateComponentTreeUI(myCombo); + ListCellRenderer renderer = myCombo.getRenderer(); + if (renderer instanceof JComponent) { + SwingUtilities.updateComponentTreeUI((JComponent)renderer); + } + } + + @Override + public Object getValue() throws Exception { + return null; // TODO: Auto-generated method stub + } + + @NotNull + @Override + public JComponent getComponent(@Nullable RadComponent component, Object value) { + return null; // TODO: Auto-generated method stub + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/renderers/BooleanRenderer.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/renderers/BooleanRenderer.java index 87f0ef2da5c0..c3b8f1b72110 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/renderers/BooleanRenderer.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/renderers/BooleanRenderer.java @@ -28,6 +28,10 @@ import javax.swing.*; * @author Vladimir Kondratyev */ public class BooleanRenderer extends JCheckBox implements PropertyRenderer { + protected boolean getValue(Object value) { + return value != null && (Boolean)value; + } + @NotNull public JComponent getComponent(@Nullable RadComponent component, @Nullable Object value, boolean selected, boolean hasFocus) { if (selected) { @@ -39,7 +43,7 @@ public class BooleanRenderer extends JCheckBox implements PropertyRenderer { setBackground(UIUtil.getTableBackground()); } - setSelected(value != null && (Boolean)value); + setSelected(getValue(value)); return this; } } \ No newline at end of file