mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
@@ -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<String, List<XmlFile>> myExternalAnnotations = new ConcurrentWeakValueHashMap<String, List<XmlFile>>();
|
||||
@NotNull private final AtomicReference<ThreeState> myHasAnyAnnotationsRoots = new AtomicReference<ThreeState>(ThreeState.UNSURE);
|
||||
@NotNull private volatile ThreeState myHasAnyAnnotationsRoots = ThreeState.UNSURE;
|
||||
@NotNull private static final List<XmlFile> NULL = new ArrayList<XmlFile>();
|
||||
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<String, PsiAnnotation> result = collectExternalAnnotations(listOwner);
|
||||
@@ -135,11 +138,11 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
|
||||
@NotNull
|
||||
private Map<String, PsiAnnotation> collectExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) {
|
||||
if (hasAnyAnnotationsRoots() == ThreeState.NO) return Collections.emptyMap();
|
||||
final Map<String, PsiAnnotation> result = new HashMap<String, PsiAnnotation>();
|
||||
final List<XmlFile> files = findExternalAnnotationsFile(listOwner);
|
||||
final List<XmlFile> files = findExternalAnnotationsFiles(listOwner);
|
||||
if (files == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
final Map<String, PsiAnnotation> result = new HashMap<String, PsiAnnotation>();
|
||||
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<XmlFile> xmlFiles = findExternalAnnotationsFile(listOwner);
|
||||
final List<XmlFile> 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<XmlFile> xmlFiles = findExternalAnnotationsFile(listOwner);
|
||||
List<XmlFile> 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<XmlFile> annotationFiles = new ArrayList<XmlFile>(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<XmlFile> files = findExternalAnnotationsFile(listOwner);
|
||||
final List<XmlFile> 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 {
|
||||
"<item name=\'" + externalName + "\'>\n";
|
||||
text += createAnnotationTag(annotationFQName, values);
|
||||
text += "</item>";
|
||||
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 = " <annotation name=\'" + annotationFQName + "\'>\n";
|
||||
text += StringUtil.join(values, new Function<PsiNameValuePair, String>() {
|
||||
@NonNls
|
||||
@NotNull
|
||||
@Override
|
||||
public String fun(@NotNull PsiNameValuePair pair) {
|
||||
if (pair.getName() != null) {
|
||||
return "<val name=\"" + pair.getName() + "\" val=\"" + StringUtil.escapeXml(pair.getValue().getText()) + "\"/>";
|
||||
}
|
||||
return "<val val=\"" + StringUtil.escapeXml(pair.getValue().getText()) + "\"/>";
|
||||
return "<val" +
|
||||
(pair.getName() != null ? " name=\"" + pair.getName() + "\"" : "") +
|
||||
" val=\"" + StringUtil.escapeXml(pair.getValue().getText()) + "\"/>";
|
||||
}
|
||||
}, " \n");
|
||||
text += " </annotation>";
|
||||
@@ -572,8 +582,8 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<XmlFile> findExternalAnnotationsFile(@NotNull PsiModifierListOwner listOwner) {
|
||||
final Project project = listOwner.getProject();
|
||||
private List<XmlFile> 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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase{
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder();
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName());
|
||||
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture());
|
||||
final JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class);
|
||||
moduleFixtureBuilder.addSourceContentRoot(myFixture.getTempDirPath());
|
||||
|
||||
@@ -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<IdeaProjectTestFixture> createFixtureBuilder() {
|
||||
return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder();
|
||||
}
|
||||
public static TestFixtureBuilder<IdeaProjectTestFixture> createFixtureBuilder(@NotNull String name) {
|
||||
return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Pair<File, Module>> wrongFiles = checkAffectedFilesInCorrectModules(context, chunk, newlyAffectedFiles);
|
||||
if (!wrongFiles.isEmpty()) {
|
||||
LOG.debug("Wrong affected files for module chunk " + chunk.getName() + ": ");
|
||||
for (Pair<File, Module> 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<Pair<File, Module>> checkAffectedFilesInCorrectModules(CompileContext context, ModuleChunk currentChunk, Collection<File> affected) {
|
||||
if (affected.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Set<Module> chunkModules = currentChunk.getModules();
|
||||
final Map<Module, Set<Module>> cache = new HashMap<Module, Set<Module>>();
|
||||
final List<Pair<File, Module>> result = new ArrayList<Pair<File, Module>>();
|
||||
|
||||
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<Module> 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<Module> set1, Set<Module> set2) {
|
||||
if (set1.size() < set2.size()) {
|
||||
return new HashSet<Module>(set1).removeAll(set2);
|
||||
}
|
||||
return new HashSet<Module>(set2).removeAll(set1);
|
||||
}
|
||||
|
||||
private static boolean chunkContainsAffectedFiles(CompileContext context, ModuleChunk chunk, final Set<File> affected) throws IOException {
|
||||
final Set<Module> chunkModules = new HashSet<Module>(chunk.getModules());
|
||||
if (!chunkModules.isEmpty()) {
|
||||
|
||||
@@ -181,6 +181,16 @@ public class ProjectPaths {
|
||||
return sourcePaths;
|
||||
}
|
||||
|
||||
public static Set<Module> getModulesWithDependentsRecursively(final Module module, final boolean includeTests) {
|
||||
final Set<Module> result = new HashSet<Module>();
|
||||
collectPathsRecursively(module, ClasspathKind.compile(includeTests), new HashSet<Module>(), new PathsGetter() {
|
||||
public void apply(Module module, ClasspathKind kind) {
|
||||
result.add(module);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private interface PathsGetter {
|
||||
void apply(Module module, ClasspathKind kind);
|
||||
}
|
||||
|
||||
@@ -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<FoldingDescriptor> descriptors = new ArrayList<FoldingDescriptor>();
|
||||
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<FoldingDescriptor> descriptors) {
|
||||
List<FoldingDescriptor> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Module, String> myModulesNames = new HashMap<Module, String>();
|
||||
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<Module> modules) {
|
||||
if (myProject != project) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, String> old2newNames = new HashMap<String, String>(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<String, String> old2newNames);
|
||||
}
|
||||
+32
-5
@@ -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<VirtualFile> myDisabledHintsFiles = new THashSet<VirtualFile>();
|
||||
private final Collection<PsiFile> myDisabledHighlightingFiles = new THashSet<PsiFile>();
|
||||
private final Collection<VirtualFile> myDisabledHighlightingFiles = new THashSet<VirtualFile>();
|
||||
|
||||
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<RangeHighlighterEx>() {
|
||||
@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<RangeHighlighterEx>() {
|
||||
@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<HighlightInfo> processor) {
|
||||
return processHighlights(document, project, null, 0, document.getTextLength(), new Processor<HighlightInfo>() {
|
||||
@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<HighlightInfo> foundInfoList = new SmartList<HighlightInfo>();
|
||||
processHighlightsNearOffset(document, myProject, HighlightSeverity.INFORMATION, offset, includeFixRange, new Processor<HighlightInfo>() {
|
||||
@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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+16
-9
@@ -73,7 +73,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
|
||||
private final NewVirtualFileSystem myFS;
|
||||
|
||||
// guarded by this
|
||||
protected Object myChildren; // Either HashMap<String, VFile> or VFile[]
|
||||
private Object myChildren; // Either HashMap<String, VFile> 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<VirtualFile> 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<String[], int[]> 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<String, VirtualFileSystemEntry> 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
|
||||
|
||||
+31
-23
@@ -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<Throwable>() {
|
||||
@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<Throwable>() {
|
||||
@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);
|
||||
|
||||
-144
@@ -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<RadViewComponent> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
+72
-9
@@ -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<String, List<Property>> 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<String, List<Property>>());
|
||||
myMetaManager.setCache(target.hashString(), myCachedProperties = new HashMap<String, List<Property>>());
|
||||
}
|
||||
|
||||
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.<Property>emptyList());
|
||||
String target = model.getTarget();
|
||||
if (target == null) {
|
||||
component.setProperties(Collections.<Property>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<Property> load(Class<?> componentClass) {
|
||||
private List<Property> load(Class<?> componentClass, MetaModel model) {
|
||||
String component = componentClass.getSimpleName();
|
||||
List<Property> properties = myCachedProperties.get(component);
|
||||
|
||||
if (properties == null) {
|
||||
properties = new ArrayList<Property>();
|
||||
|
||||
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<AttributeFormat> 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<Property> 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()) {
|
||||
|
||||
+100
@@ -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<RadComponent> 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<RadComponent> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -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<Property> getProperties() {
|
||||
return myProperties;
|
||||
|
||||
@@ -21,6 +21,19 @@
|
||||
<palette title="Unknown (%tag%)" icon="/com/intellij/android/designer/icons/unknown.png"/>
|
||||
</meta>
|
||||
|
||||
<meta class="android.view.View">
|
||||
<properties
|
||||
important="id background"
|
||||
expert="tag scrollX scrollY fitsSystemWindows scrollbars scrollbarStyle isScrollContainer fadeScrollbars scrollbarFadeDuration scrollbarDefaultDelayBeforeFade scrollbarSize scrollbarThumbHorizontal scrollbarThumbVertical scrollbarTrackHorizontal scrollbarTrackVertical scrollbarAlwaysDrawHorizontalTrack scrollbarAlwaysDrawVerticalTrack fadingEdge requiresFadingEdge fadingEdgeLength nextFocusLeft nextFocusRight nextFocusUp nextFocusDown nextFocusForward saveEnabled filterTouchesWhenObscured drawingCacheQuality keepScreenOn duplicateParentState soundEffectsEnabled hapticFeedbackEnabled contentDescription overScrollMode translationX translationY transformPivotX transformPivotY rotation rotationX rotationY scaleX scaleY verticalScrollbarPosition layerType layoutDirection textDirection"
|
||||
/>
|
||||
</meta>
|
||||
|
||||
<meta class="class android.view.ViewGroup">
|
||||
<properties
|
||||
expert="animateLayoutChanges clipChildren clipToPadding layoutAnimation animationCache persistentDrawingCache alwaysDrawnWithCache addStatesFromChildren descendantFocusability splitMotionEvents"
|
||||
/>
|
||||
</meta>
|
||||
|
||||
<meta model="com.intellij.android.designer.model.RadViewComponent"
|
||||
class="android.widget.Button"
|
||||
tag="Button">
|
||||
@@ -29,6 +42,11 @@
|
||||
<palette title="Button" icon="/com/intellij/android/designer/icons/Button.png"
|
||||
tooltip="Represents a push-button widget."/>
|
||||
|
||||
<properties
|
||||
important="onClick"
|
||||
expert="editable password autoLink linksClickable numeric digits phoneNumber inputMethod autoText inputType textIsSelectable"
|
||||
/>
|
||||
|
||||
<creation>
|
||||
<![CDATA[
|
||||
<Button
|
||||
@@ -48,6 +66,11 @@
|
||||
<palette title="TextView" icon="/com/intellij/android/designer/icons/TextView.png"
|
||||
tooltip="Displays text to the user and optionally allows them to edit it."/>
|
||||
|
||||
<properties
|
||||
important="text hint textColor typeface textStyle gravity editable enabled"
|
||||
expert="bufferType textScaleX cursorVisible scrollHorizontally includeFontPadding shadowDx shadowDy shadowRadius freezesText drawableTop drawableLeft drawableStart drawablePadding lineSpacingExtra lineSpacingMultiplier imeOptions privateImeOptions imeActionLabel imeActionId editorExtras textSelectHandleLeft textSelectHandleRight textSelectHandle textEditPasteWindowLayout textEditNoPasteWindowLayout textEditSideNoPasteWindowLayout textEditSuggestionItemLayout textCursorDrawable textAllCaps maxEms ems minEms"
|
||||
/>
|
||||
|
||||
<creation>
|
||||
<![CDATA[
|
||||
<TextView
|
||||
@@ -67,6 +90,10 @@
|
||||
<palette title="LinearLayout" icon="/com/intellij/android/designer/icons/LinearLayout.png"
|
||||
tooltip="A Layout that arranges its children in a single column or a single row."/>
|
||||
|
||||
<properties
|
||||
important="orientation gravity"
|
||||
/>
|
||||
|
||||
<creation>
|
||||
<![CDATA[
|
||||
<LinearLayout
|
||||
@@ -79,6 +106,13 @@
|
||||
</meta>
|
||||
|
||||
<palette>
|
||||
<group name="Widgets">
|
||||
<item tag="Button"/>
|
||||
<item tag="TextView"/>
|
||||
</group>
|
||||
<group name="Containers">
|
||||
<item tag="LinearLayout"/>
|
||||
</group>
|
||||
</palette>
|
||||
|
||||
</meta-model>
|
||||
+134
@@ -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<RadViewComponent> {
|
||||
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<AttributeFormat> 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;
|
||||
}
|
||||
}
|
||||
+81
@@ -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<RadViewComponent> {
|
||||
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<Property> 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;
|
||||
}
|
||||
}
|
||||
+33
@@ -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);
|
||||
}
|
||||
}
|
||||
+26
@@ -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);
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -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);
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<enabled value="true"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="71b17" class="com.intellij.ui.components.JBLabel" binding="myErrorLabel">
|
||||
|
||||
+7
-1
@@ -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>(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();
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.android.actions.CreateXmlResourceDialog">
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="5" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
<xy x="20" y="20" width="288" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="82472" binding="myDeviceConfigurationWrapper" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<component id="43fab" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
@@ -48,29 +40,6 @@
|
||||
<text value="&Module:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="d6c07" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="832da"/>
|
||||
<text value="&Directory name:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="832da" class="javax.swing.JTextField" binding="myDirectoryNameField">
|
||||
<constraints>
|
||||
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="da401" class="com.intellij.ui.components.JBLabel" binding="myErrorLabel">
|
||||
<constraints>
|
||||
<grid row="5" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="21872" class="com.intellij.ui.components.JBLabel">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
@@ -88,6 +57,22 @@
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<grid id="8a4e8" binding="myDirectoriesPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<component id="d6c07" class="com.intellij.ui.components.JBLabel" binding="myDirectoriesLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="&Directories:"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
|
||||
@@ -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<String, JCheckBox> 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("<html><body><font color=\"red\">" + e.getMessage() + "</font></body></html>");
|
||||
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<VirtualFile> 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<VirtualFile>() {
|
||||
@Override
|
||||
public int compare(VirtualFile f1, VirtualFile f2) {
|
||||
return f1.getName().compareTo(f2.getName());
|
||||
}
|
||||
});
|
||||
|
||||
final Map<String, JCheckBox> oldCheckBoxes = myCheckBoxes;
|
||||
final int selectedIndex = myDirectoriesList.getSelectedIndex();
|
||||
final String selectedDirName = selectedIndex >= 0 ? myDirNames[selectedIndex] : null;
|
||||
|
||||
final List<JCheckBox> checkBoxList = new ArrayList<JCheckBox>();
|
||||
myCheckBoxes = new HashMap<String, JCheckBox>();
|
||||
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<JCheckBox>(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<String> 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<String> 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<String> 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<String> getDirNames() {
|
||||
final List<String> selectedDirs = new ArrayList<String>();
|
||||
|
||||
for (Map.Entry<String, JCheckBox> entry : myCheckBoxes.entrySet()) {
|
||||
if (entry.getValue().isSelected()) {
|
||||
selectedDirs.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
return selectedDirs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+52
-41
@@ -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<String> 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<String> 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
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
|
||||
<readWriteAccessDetector implementation="org.jetbrains.plugins.groovy.findUsages.GroovyReadWriteAccessDetector" order="before java"/>
|
||||
<findUsagesHandlerFactory implementation="org.jetbrains.plugins.groovy.findUsages.GroovyFindUsagesHandlerFactory"/>
|
||||
<highlightUsagesHandlerFactory implementation="org.jetbrains.plugins.groovy.findUsages.GrHighlightOverridingMethodsHandlerFactory"/>
|
||||
<lang.braceMatcher language="Groovy" implementationClass="org.jetbrains.plugins.groovy.highlighter.GroovyBraceMatcher"/>
|
||||
<lang.importOptimizer language="Groovy" implementationClass="org.jetbrains.plugins.groovy.lang.editor.GroovyImportOptimizer"/>
|
||||
<lang.documentationProvider language="Groovy"
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.highlighting.ChooseClassAndDoHighlightRunnable;
|
||||
import com.intellij.codeInsight.highlighting.HighlightOverridingMethodsHandler;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class GrHighlightOverridingMethodsHandler extends HighlightOverridingMethodsHandler {
|
||||
private final PsiElement myTarget;
|
||||
private final GrTypeDefinition myClass;
|
||||
|
||||
public GrHighlightOverridingMethodsHandler(final Editor editor,
|
||||
final PsiFile file,
|
||||
final PsiElement target,
|
||||
final GrTypeDefinition psiClass) {
|
||||
super(editor, file, target, psiClass);
|
||||
myTarget = target;
|
||||
myClass = psiClass;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<PsiClass> 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);
|
||||
}
|
||||
}
|
||||
+53
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
class Pair {}
|
||||
List<Pair> otherPairs = new ArrayList<Pair>();
|
||||
List<Pair> pairs = otherPairs.findAll({it != null})
|
||||
List<Date> pairs2 = <warning descr="Cannot assign 'Collection<Pair>' to 'List<Date>'">otherPairs.findAll({it != null})</warning>
|
||||
List<Date> pairs2 = <warning descr="Cannot assign 'ArrayList<Pair>' to 'List<Date>'">otherPairs.findAll({it != null})</warning>
|
||||
+4
@@ -85,6 +85,10 @@ public final class OperationContext {
|
||||
return is(PASTE);
|
||||
}
|
||||
|
||||
public boolean isTree() {
|
||||
return myArea.isTree();
|
||||
}
|
||||
|
||||
public EditableArea getArea() {
|
||||
return myArea;
|
||||
}
|
||||
|
||||
+34
-4
@@ -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<RadComponent> model = (Class<RadComponent>)classLoader.loadClass(element.getAttributeValue("model"));
|
||||
String modelValue = element.getAttributeValue("model");
|
||||
Class<RadComponent> model = modelValue == null ? null : (Class<RadComponent>)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);
|
||||
|
||||
@@ -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<String> myNormalProperties = Collections.emptyList();
|
||||
private List<String> myImportantProperties = Collections.emptyList();
|
||||
private List<String> myExpertProperties = Collections.emptyList();
|
||||
private List<String> myDeprecatedProperties = Collections.emptyList();
|
||||
|
||||
public MetaModel(Class<RadComponent> 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<String> normalProperties) {
|
||||
myNormalProperties = normalProperties;
|
||||
}
|
||||
|
||||
public boolean isImportantProperty(String name) {
|
||||
return myImportantProperties.contains(name);
|
||||
}
|
||||
|
||||
public void setImportantProperties(List<String> importantProperties) {
|
||||
myImportantProperties = importantProperties;
|
||||
}
|
||||
|
||||
public boolean isExpertProperty(String name) {
|
||||
return myExpertProperties.contains(name);
|
||||
}
|
||||
|
||||
public void setExpertProperties(List<String> expertProperties) {
|
||||
myExpertProperties = expertProperties;
|
||||
}
|
||||
|
||||
public boolean isDeprecatedProperty(String name) {
|
||||
return myDeprecatedProperties.contains(name);
|
||||
}
|
||||
|
||||
public void setDeprecatedProperties(List<String> deprecatedProperties) {
|
||||
myDeprecatedProperties = deprecatedProperties;
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,7 @@ public abstract class RadComponent {
|
||||
|
||||
public void setLayout(RadLayout layout) {
|
||||
myLayout = layout;
|
||||
myLayout.setContainer(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -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<RadComponent> selection);
|
||||
|
||||
@Nullable
|
||||
|
||||
+3
-3
@@ -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<T extends RadComponent> {
|
||||
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
|
||||
|
||||
+1
-1
@@ -333,7 +333,7 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
|
||||
}
|
||||
}
|
||||
|
||||
private static int findProperty(List<Property> properties, Property property) {
|
||||
public static int findProperty(List<Property> properties, Property property) {
|
||||
String name = property.getName();
|
||||
int size = properties.size();
|
||||
|
||||
|
||||
+6
-2
@@ -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 {
|
||||
|
||||
+74
@@ -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
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user