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
;
38 import java
.text
.DateFormat
;
39 import java
.text
.SimpleDateFormat
;
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();
64 public void acceptAntElementVisitor(@NotNull final AntElementVisitor visitor
) {
65 visitor
.visitAntProperty(this);
68 public String
toString() {
69 final @NonNls StringBuilder builder
= StringBuilderSpinAllocator
.alloc();
71 builder
.append("AntProperty[");
72 if (getName() != null) {
73 builder
.append(getName());
74 builder
.append(" = ");
75 builder
.append(getValue(null));
78 final String propFile
= getFileName();
79 if (propFile
!= null) {
80 builder
.append("file: ");
81 builder
.append(propFile
);
84 builder
.append(getSourceElement().getName());
88 return builder
.toString();
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"})
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();
127 else if ("dirname".equals(tagName
)) {
128 return getDirnameValue();
130 else if (isTstamp()) {
131 return getTstampValue(propName
);
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);
146 public String
getFileName() {
147 return computeAttributeValue(getSourceElement().getAttributeValue(AntFileImpl
.FILE_ATTR
));
151 public PropertiesFile
getPropertiesFile() {
152 synchronized (PsiLock
.LOCK
) {
153 if (myPropertiesFile
== null) {
154 myPropertiesFile
= AntElementImpl
.ourNull
;
155 final String name
= getFileName();
157 final PsiFile psiFile
= findFileByName(name
, null);
158 if (psiFile
instanceof PropertiesFile
) {
159 myPropertiesFile
= psiFile
;
163 return (myPropertiesFile
== AntElementImpl
.ourNull
) ?
null : (PropertiesFile
)myPropertiesFile
;
168 public String
getPrefix() {
169 return computeAttributeValue(getSourceElement().getAttributeValue(AntFileImpl
.PREFIX_ATTR
));
173 public String
getEnvironment() {
174 return computeAttributeValue(getSourceElement().getAttributeValue("environment"));
178 public String
[] getNames() {
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());
188 for (final Property importedProp
: propList
) {
189 names
[idx
++] = prefix
!= null? prefix
+ "." + importedProp
.getName() : importedProp
.getName();
194 final String name
= getName();
196 if (getAntFile().isEnvironmentProperty(name
)) {
197 return getEnvironmentNames(name
);
199 return new String
[]{name
};
204 public void clearCaches() {
205 synchronized (PsiLock
.LOCK
) {
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
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
))) {
242 private String
getPropertyValue() {
243 final XmlTag sourceElement
= getSourceElement();
244 String value
= sourceElement
.getAttributeValue("value");
246 value
= sourceElement
.getAttributeValue("location");
248 value
= sourceElement
.getAttributeValue("defaultvalue");
251 return value
;/*computeAttributeValue(value);*/
255 private String
getDirnameValue() {
256 final XmlTag sourceElement
= getSourceElement();
257 final String value
= computeAttributeValue(sourceElement
.getAttributeValue(AntFileImpl
.FILE_ATTR
));
259 return new File(value
).getParent();
264 @SuppressWarnings({"HardCodedStringLiteral"})
265 private String
getTstampValue(final String propName
) {
266 final XmlTag se
= getSourceElement();
268 final XmlTag formatTag
= se
.findFirstSubTag(AntFileImpl
.FORMAT_TAG
);
269 if (formatTag
!= null) {
270 final String offsetStr
= formatTag
.getAttributeValue("offset");
272 if (offsetStr
!= null) {
274 offset
= Integer
.parseInt(offsetStr
);
276 catch (NumberFormatException e
) {
279 final String unitStr
= formatTag
.getAttributeValue("unit");
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();
307 cal
.add(unit
, offset
);
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
);
330 final DateFormat format
= (pattern
!= null) ?
new SimpleDateFormat(pattern
) : DateFormat
.getTimeInstance();
331 final String tz
= formatTag
.getAttributeValue(TSTAMP_TIMEZONE_ATTRIBUTE_NAME
);
333 format
.setTimeZone(TimeZone
.getTimeZone(tz
));
335 return format
.format(d
);
337 catch (IllegalArgumentException ignored
) {
346 private XmlAttributeValue
[] getTstampPropertyAttributeValues() {
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();
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();
370 String prefix
= getSourceElement().getAttributeValue(AntFileImpl
.PREFIX_ATTR
);
371 if (prefix
== null) {
372 strings
.add("DSTAMP");
373 strings
.add("TSTAMP");
374 strings
.add("TODAY");
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
);
389 strings
.add(prefix
+ additionalProperty
);
393 return strings
.toArray(new String
[strings
.size()]);
396 StringSetSpinAllocator
.dispose(strings
);
400 private String
[] getEnvironmentNames(final String name
) {
401 @NonNls final Set
<String
> strings
= StringSetSpinAllocator
.alloc();
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()]);
410 StringSetSpinAllocator
.dispose(strings
);