update copyright
[fedora-idea.git] / plugins / ant / src / com / intellij / lang / ant / psi / impl / AntPropertyImpl.java
blobac373b1dd9a7afc0cc9041847d122a66fbad2007
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.lang.ant.psi.impl;
18 import com.intellij.lang.ant.AntElementRole;
19 import com.intellij.lang.ant.psi.*;
20 import com.intellij.lang.ant.psi.introspection.AntTypeDefinition;
21 import com.intellij.lang.properties.psi.PropertiesFile;
22 import com.intellij.lang.properties.psi.Property;
23 import com.intellij.psi.PsiElement;
24 import com.intellij.psi.PsiFile;
25 import com.intellij.psi.PsiLock;
26 import com.intellij.psi.xml.XmlAttribute;
27 import com.intellij.psi.xml.XmlAttributeValue;
28 import com.intellij.psi.xml.XmlTag;
29 import com.intellij.util.IncorrectOperationException;
30 import com.intellij.util.StringBuilderSpinAllocator;
31 import com.intellij.util.StringSetSpinAllocator;
32 import com.intellij.util.ArrayUtil;
33 import org.jetbrains.annotations.NonNls;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
37 import java.io.File;
38 import java.text.DateFormat;
39 import java.text.SimpleDateFormat;
40 import java.util.*;
42 public class AntPropertyImpl extends AntTaskImpl implements AntProperty {
44 private PsiElement myPropertiesFile;
46 public AntPropertyImpl(final AntElement parent,
47 final XmlTag sourceElement,
48 final AntTypeDefinition definition,
49 @NonNls final String nameElementAttribute) {
50 super(parent, sourceElement, definition, nameElementAttribute);
53 public AntPropertyImpl(final AntElement parent, final XmlTag sourceElement, final AntTypeDefinition definition) {
54 this(parent, sourceElement, definition, AntFileImpl.NAME_ATTR);
57 public PsiElement setName(@NotNull final String name) throws IncorrectOperationException {
58 final AntProperty element = (AntProperty)super.setName(name);
59 final AntFile antFile = getAntFile();
60 antFile.invalidateProperties();
61 return element;
64 public void acceptAntElementVisitor(@NotNull final AntElementVisitor visitor) {
65 visitor.visitAntProperty(this);
68 public String toString() {
69 final @NonNls StringBuilder builder = StringBuilderSpinAllocator.alloc();
70 try {
71 builder.append("AntProperty[");
72 if (getName() != null) {
73 builder.append(getName());
74 builder.append(" = ");
75 builder.append(getValue(null));
77 else {
78 final String propFile = getFileName();
79 if (propFile != null) {
80 builder.append("file: ");
81 builder.append(propFile);
83 else {
84 builder.append(getSourceElement().getName());
87 builder.append("]");
88 return builder.toString();
90 finally {
91 StringBuilderSpinAllocator.dispose(builder);
95 public String getName() {
96 final XmlAttributeValue[] values = getTstampPropertyAttributeValues();
97 return (values.length == 1) ? values[0].getValue() : super.getName();
100 public AntElementRole getRole() {
101 return AntElementRole.PROPERTY_ROLE;
104 public boolean canRename() {
105 return super.canRename() && (!isTstamp() || getTstampPropertyAttributeValues().length > 0);
108 @SuppressWarnings({"HardCodedStringLiteral"})
109 @Nullable
110 public String getValue(final String propName) {
111 synchronized (PsiLock.LOCK) {
112 final XmlTag se = getSourceElement();
113 final String tagName = se.getName();
114 if (AntFileImpl.PROPERTY.equals(tagName) || "param".equals(tagName) || "condition".equals(tagName) || "input".equals(tagName)) { // todo: support conditions separately
115 String value = getPropertyValue();
116 if (value == null && propName != null) {
117 final PropertiesFile propertiesFile = getPropertiesFile();
118 if (propertiesFile != null) {
119 final Property fileProperty = propertiesFile.findPropertyByKey(cutPrefix(propName));
120 if (fileProperty != null) {
121 value = fileProperty.getValue();
125 return value;
127 else if ("dirname".equals(tagName)) {
128 return getDirnameValue();
130 else if (isTstamp()) {
131 return getTstampValue(propName);
133 return null;
137 private String cutPrefix(@NotNull final String propName) {
138 final String prefix = getPrefix();
139 if (prefix != null && propName.startsWith(prefix) && prefix.length() < propName.length() && propName.charAt(prefix.length()) == '.') {
140 return propName.substring(prefix.length() + 1);
142 return propName;
145 @Nullable
146 public String getFileName() {
147 return computeAttributeValue(getSourceElement().getAttributeValue(AntFileImpl.FILE_ATTR));
150 @Nullable
151 public PropertiesFile getPropertiesFile() {
152 synchronized (PsiLock.LOCK) {
153 if (myPropertiesFile == null) {
154 myPropertiesFile = AntElementImpl.ourNull;
155 final String name = getFileName();
156 if (name != null) {
157 final PsiFile psiFile = findFileByName(name, null);
158 if (psiFile instanceof PropertiesFile) {
159 myPropertiesFile = psiFile;
163 return (myPropertiesFile == AntElementImpl.ourNull) ? null : (PropertiesFile)myPropertiesFile;
167 @Nullable
168 public String getPrefix() {
169 return computeAttributeValue(getSourceElement().getAttributeValue(AntFileImpl.PREFIX_ATTR));
172 @Nullable
173 public String getEnvironment() {
174 return computeAttributeValue(getSourceElement().getAttributeValue("environment"));
177 @Nullable
178 public String[] getNames() {
179 if (isTstamp()) {
180 return getTstampNames();
182 final PropertiesFile propertiesFile = getPropertiesFile();
183 if (propertiesFile != null) {
184 final List<Property> propList = propertiesFile.getProperties();
185 final String prefix = getPrefix();
186 final String[] names = ArrayUtil.newStringArray(propList.size());
187 int idx = 0;
188 for (final Property importedProp : propList) {
189 names[idx++] = prefix != null? prefix + "." + importedProp.getName() : importedProp.getName();
191 return names;
194 final String name = getName();
195 if (name != null) {
196 if (getAntFile().isEnvironmentProperty(name)) {
197 return getEnvironmentNames(name);
199 return new String[]{name};
201 return null;
204 public void clearCaches() {
205 synchronized (PsiLock.LOCK) {
206 super.clearCaches();
207 final AntFile antFile = getAntFile();
208 if (antFile != null) {
209 antFile.clearCaches();
211 myPropertiesFile = null;
215 public int getTextOffset() {
216 final XmlAttributeValue[] values = getTstampPropertyAttributeValues();
217 return (values.length == 1) ? values[0].getTextOffset() : super.getTextOffset();
221 * @return <format> element for the <tstamp> property
222 * @param propName
224 @Nullable
225 @SuppressWarnings({"HardCodedStringLiteral"})
226 public AntElement getFormatElement(final String propName) {
227 for (final AntElement child : getChildren()) {
228 if (child instanceof AntStructuredElement) {
229 final AntStructuredElement se = (AntStructuredElement)child;
230 final XmlTag tag = se.getSourceElement();
231 if (AntFileImpl.FORMAT_TAG.equals(tag.getName())) {
232 if (propName.equals(tag.getAttributeValue(AntFileImpl.PROPERTY))) {
233 return child;
238 return this;
241 @Nullable
242 private String getPropertyValue() {
243 final XmlTag sourceElement = getSourceElement();
244 String value = sourceElement.getAttributeValue("value");
245 if (value == null) {
246 value = sourceElement.getAttributeValue("location");
247 if (value == null) {
248 value = sourceElement.getAttributeValue("defaultvalue");
251 return value;/*computeAttributeValue(value);*/
254 @Nullable
255 private String getDirnameValue() {
256 final XmlTag sourceElement = getSourceElement();
257 final String value = computeAttributeValue(sourceElement.getAttributeValue(AntFileImpl.FILE_ATTR));
258 if (value != null) {
259 return new File(value).getParent();
261 return value;
264 @SuppressWarnings({"HardCodedStringLiteral"})
265 private String getTstampValue(final String propName) {
266 final XmlTag se = getSourceElement();
267 Date d = new Date();
268 final XmlTag formatTag = se.findFirstSubTag(AntFileImpl.FORMAT_TAG);
269 if (formatTag != null) {
270 final String offsetStr = formatTag.getAttributeValue("offset");
271 int offset;
272 if (offsetStr != null) {
273 try {
274 offset = Integer.parseInt(offsetStr);
276 catch (NumberFormatException e) {
277 offset = 0;
279 final String unitStr = formatTag.getAttributeValue("unit");
280 int unit = 0;
281 if (unitStr != null) {
282 if ("millisecond".equals(unitStr)) {
283 unit = Calendar.MILLISECOND;
285 else if ("second".equals(unitStr)) {
286 unit = Calendar.SECOND;
288 else if ("minute".equals(unitStr)) {
289 unit = Calendar.MINUTE;
291 else if ("hour".equals(unitStr)) {
292 unit = Calendar.HOUR_OF_DAY;
294 else if ("day".equals(unitStr)) {
295 unit = Calendar.DAY_OF_MONTH;
297 else if ("week".equals(unitStr)) {
298 unit = Calendar.WEEK_OF_YEAR;
300 else if ("year".equals(unitStr)) {
301 unit = Calendar.YEAR;
304 if (offset != 0 && unit != 0) {
305 final Calendar cal = Calendar.getInstance();
306 cal.setTime(d);
307 cal.add(unit, offset);
308 d = cal.getTime();
312 final String _propName = propName != null? cutPrefix(propName) : null;
313 if (_propName != null) {
314 if (_propName.equals("DSTAMP")) {
315 return new SimpleDateFormat("yyyyMMdd").format(d);
317 else if (_propName.equals("TSTAMP")) {
318 return new SimpleDateFormat("HHmm").format(d);
320 else if (_propName.equals("TODAY")) {
321 return new SimpleDateFormat("MMMM d yyyy", Locale.US).format(d);
325 for (XmlAttributeValue value : getTstampPropertyAttributeValues()) {
326 if (value != null && (_propName == null || _propName.equals(value.getValue()))) {
327 if (formatTag != null) {
328 final String pattern = formatTag.getAttributeValue(TSTAMP_PATTERN_ATTRIBUTE_NAME);
329 try {
330 final DateFormat format = (pattern != null) ? new SimpleDateFormat(pattern) : DateFormat.getTimeInstance();
331 final String tz = formatTag.getAttributeValue(TSTAMP_TIMEZONE_ATTRIBUTE_NAME);
332 if (tz != null) {
333 format.setTimeZone(TimeZone.getTimeZone(tz));
335 return format.format(d);
337 catch (IllegalArgumentException ignored) {
338 return null;
343 return null;
346 private XmlAttributeValue[] getTstampPropertyAttributeValues() {
347 if (isTstamp()) {
348 final List<XmlAttributeValue> elements = new ArrayList<XmlAttributeValue>();
349 for (XmlTag formatTag : getSourceElement().findSubTags(AntFileImpl.FORMAT_TAG)) {
350 final XmlAttribute propAttr = formatTag.getAttribute(AntFileImpl.PROPERTY, null);
351 if (propAttr != null) {
352 final XmlAttributeValue value = propAttr.getValueElement();
353 if (value != null) {
354 elements.add(value);
358 return elements.toArray(new XmlAttributeValue[elements.size()]);
360 return new XmlAttributeValue[0];
363 public boolean isTstamp() {
364 return TSTAMP_TAG.equals(getSourceElement().getName());
367 private String[] getTstampNames() {
368 @NonNls final Set<String> strings = StringSetSpinAllocator.alloc();
369 try {
370 String prefix = getSourceElement().getAttributeValue(AntFileImpl.PREFIX_ATTR);
371 if (prefix == null) {
372 strings.add("DSTAMP");
373 strings.add("TSTAMP");
374 strings.add("TODAY");
376 else {
377 prefix += '.';
378 strings.add(prefix + "DSTAMP");
379 strings.add(prefix + "TSTAMP");
380 strings.add(prefix + "TODAY");
382 for (XmlAttributeValue value : getTstampPropertyAttributeValues()) {
383 if (value != null && value.getValue() != null) {
384 final String additionalProperty = value.getValue();
385 if (prefix == null) {
386 strings.add(additionalProperty);
388 else {
389 strings.add(prefix + additionalProperty);
393 return strings.toArray(new String[strings.size()]);
395 finally {
396 StringSetSpinAllocator.dispose(strings);
400 private String[] getEnvironmentNames(final String name) {
401 @NonNls final Set<String> strings = StringSetSpinAllocator.alloc();
402 try {
403 final String sourceName = name.substring(AntFileImpl.DEFAULT_ENVIRONMENT_PREFIX.length());
404 for (final String prefix : getAntFile().getEnvironmentPrefixes()) {
405 strings.add(prefix + sourceName);
407 return strings.toArray(new String[strings.size()]);
409 finally {
410 StringSetSpinAllocator.dispose(strings);