Source code: com/trapezium/vrml/node/PROTObase.java
1 /*
2 * @(#)PROTObase.java
3 *
4 * Copyright (c) 1998-1999 by Trapezium Development LLC. All Rights Reserved.
5 *
6 * The information in this file is the property of Trapezium Development LLC
7 * and may be used only in accordance with the terms of the license granted
8 * by Trapezium.
9 *
10 */
11 package com.trapezium.vrml.node;
12
13 import java.util.Vector;
14 import com.trapezium.vrml.VrmlElement;
15 import com.trapezium.vrml.NodeTypeId;
16 import com.trapezium.vrml.fields.Field;
17 import com.trapezium.vrml.fields.ISField;
18 import com.trapezium.vrml.Scene;
19 import com.trapezium.vrml.grammar.Spelling;
20 import com.trapezium.vrml.grammar.FieldDescriptor;
21 import com.trapezium.vrml.grammar.VRML97;
22 import com.trapezium.parse.TokenEnumerator;
23 import java.util.Enumeration;
24
25 /**
26 * Base class for PROTO and EXTERNPROTO scene graph components.
27 *
28 * @author Johannes N. Johannsen
29 * @version 1.21 22 August 1998, added url via IS enumeration access
30 * 1.12, 7 April 1998, added "getFieldNames"
31 * 28 March 1998, added "getInterfaceCount" method
32 * @version 1.1, 14 Jan 1998
33 *
34 * @since 1.0
35 */
36 abstract public class PROTObase extends Node {
37 /** a list of the fields in the PROTO interface */
38 Vector protoInterface;
39
40 /** a list of interface fields mapped to node fields via IS syntax */
41 Vector isList;
42
43 /** flag to indicate whether or not unused interface existence check done */
44 boolean unusedInterfaceCheckComplete;
45 boolean unusedInterfacesExist;
46
47 /** Create a PROTO or EXTERNPROTO starting at a token */
48 public PROTObase( int tokenOffset ) {
49 super( tokenOffset );
50 unusedInterfaceCheckComplete = false;
51 unusedInterfacesExist = false;
52 }
53
54 /** Check for unused interfaces */
55 public boolean hasUnusedInterfaces() {
56 checkForUnusedInterfaces();
57 return( unusedInterfacesExist );
58 }
59
60 void checkForUnusedInterfaces() {
61 if ( !unusedInterfaceCheckComplete && ( protoInterface != null )) {
62 int interfaceSize = protoInterface.size();
63 for ( int i = 0; i < interfaceSize; i++ ) {
64 Field testField = (Field)protoInterface.elementAt( i );
65 String error = testField.getError();
66 if ( error != null ) {
67 if ( error.indexOf( "not referenced" ) > 0 ) {
68 unusedInterfacesExist = true;
69 break;
70 }
71 }
72 }
73 unusedInterfaceCheckComplete = true;
74 }
75 }
76
77 /** Add a mapping from a proto interface field to a specific node field,
78 * mapping is defined in the <B>ISField</B>.
79 */
80 public void addISField( ISField is ) {
81 if ( isList == null ) {
82 isList = new Vector();
83 }
84 isList.addElement( is );
85 }
86
87
88 /** Get the number of IS fields in the PROTOBase
89 */
90 public int getNumberISfields() {
91 if ( isList == null ) {
92 return( 0 );
93 }
94 return( isList.size() );
95 }
96
97 /** Get a specific IS field in the PROTOBase
98 */
99 public ISField getISfield( int offset ) {
100 return( (ISField)isList.elementAt( offset ));
101 }
102
103 /** Get the list of ISfields */
104 public Vector getISfields() {
105 return( isList );
106 }
107
108 public FieldDescriptor getFieldDescriptor( String fieldName ) {
109 if ( isList == null ) {
110 return( null );
111 }
112 int n = isList.size();
113 for ( int i = 0; i < n; i++ ) {
114 ISField is = (ISField)isList.elementAt( i );
115 String isFieldId = is.getFieldId();
116 if ( isFieldId != null ) {
117 if ( isFieldId.compareTo( fieldName ) == 0 ) {
118 Field nodeField = is.getNodeField();
119 String nodeParentBaseName = null;
120 String nodeFieldId = null;
121 if ( nodeField != null ) {
122 VrmlElement nodeFieldParent = nodeField.getParent();
123 if ( nodeFieldParent instanceof Node ) {
124 nodeParentBaseName = ((Node)nodeFieldParent).getBaseName();
125 }
126 nodeFieldId = nodeField.getFieldId();
127 }
128 if (( nodeParentBaseName != null ) && ( nodeFieldId != null )) {
129 return( VRML97.getFieldDescriptor( nodeParentBaseName, nodeFieldId ));
130 }
131 }
132 }
133 }
134 return( null );
135 }
136
137 /** Get the vector of interface fields.
138 *
139 * @return null if there is no interface for the PROTO, otherwise
140 * a vector of interface fields.
141 */
142 public Vector getInterfaceVector() {
143 return( protoInterface );
144 }
145
146 /** Get a list of field names defined for the PROTO.
147 */
148 public String[] getFieldNames() {
149 if ( protoInterface == null ) {
150 return( null );
151 } else {
152 int size = protoInterface.size();
153 if ( size == 0 ) {
154 return( null );
155 }
156 String[] results = new String[ size ];
157 for ( int i = 0; i < size; i++ ) {
158 Field testField = (Field)protoInterface.elementAt( i );
159 results[ i ] = testField.getFieldId();
160 }
161 return( results );
162 }
163 }
164
165 /** Get the Scene representing the body of the PROTO declaration */
166 public Scene getPROTObody() {
167 int nChildren = numberChildren();
168 for ( int i = 0; i < nChildren; i++ ) {
169 VrmlElement vle = getChildAt( i );
170 if ( vle instanceof Scene ) {
171 return( (Scene)vle );
172 }
173 }
174 return( null );
175 }
176
177 /** Get the first node of the PROTO, indicate type for the PROTO */
178 public Node getPROTONodeType() {
179 return( getNodeAt( 0 ));
180 }
181
182 /** Get a specific Node in the PROTO */
183 public Node getNodeAt( int offset ) {
184 Scene s = getPROTObody();
185 if ( s != null ) {
186 VrmlElement firstNode = s.getChildAt( offset );
187 if ( firstNode instanceof Node ) {
188 return( (Node)firstNode );
189 }
190 }
191 return( null );
192 }
193
194
195
196 /**
197 * Get the interface declaration based on the name of the field. "IS" fields refer
198 * to the Field returned by this call.
199 */
200 public Field getInterfaceDeclaration( String fieldName ) {
201 if ( protoInterface == null ) {
202 return( null );
203 }
204 int interfaceSize = protoInterface.size();
205 for ( int i = 0; i < interfaceSize; i++ ) {
206 Field testField = (Field)protoInterface.elementAt( i );
207 if ( testField.getFieldId().compareTo( fieldName ) == 0 ) {
208 return( testField );
209 }
210 }
211 return( null );
212 }
213
214 /** Is the field name included in the PROTO interface */
215 public boolean isValidFieldId( String fieldName ) {
216 if ( protoInterface == null ) {
217 return( false );
218 }
219 int interfaceSize = protoInterface.size();
220 for ( int i = 0; i < interfaceSize; i++ ) {
221 Field testField = (Field)protoInterface.elementAt( i );
222 if ( testField.getFieldId().compareTo( fieldName ) == 0 ) {
223 return( true );
224 }
225 }
226 return( false );
227 }
228
229 /** Get string identifying PROTO */
230 public String getId() {
231 VrmlElement v = getChildAt( 0 );
232 if ( v instanceof NodeTypeId ) {
233 NodeTypeId nodeId = (NodeTypeId)v;
234 return( nodeId.getName() );
235 } else {
236 return( null );
237 }
238 }
239
240 /** Set the id of a PROTO, effectively renaming it. Note this
241 * does not rename instances.
242 */
243 public void setId( String newId ) {
244 VrmlElement v = getChildAt( 0 );
245 if ( v instanceof NodeTypeId ) {
246 VrmlElement root = getRoot();
247 if ( root instanceof Scene ) {
248 Scene sroot = (Scene)root;
249 TokenEnumerator te = sroot.getTokenEnumerator();
250 te.replace( v.getFirstTokenOffset(), newId );
251 }
252 }
253 }
254
255 public String getNodeName() {
256 return( "PROTO " + getId() );
257 }
258
259 /** Get the built in node type for the PROTO or EXTERNPROTO */
260 abstract public String getBuiltInNodeType();
261
262 /** Add interface declaration to PROTO/EXTERNPROTO interface list */
263 public void addInterface( Field f ) {
264 if ( protoInterface == null ) {
265 protoInterface = new Vector();
266 }
267 protoInterface.addElement( f );
268 }
269
270 /** Get the number of interface fields of a particular type */
271 public int getInterfaceCount( int type ) {
272 int count = 0;
273 if ( protoInterface != null ) {
274 int size = protoInterface.size();
275 for ( int i = 0; i < size; i++ ) {
276 Field f = (Field)protoInterface.elementAt( i );
277 if ( f.getInterfaceType() == type ) {
278 count++;
279 }
280 }
281 }
282 return( count );
283 }
284
285 /** Get the field id closest to the unknown field id parameter */
286 public String getClosestFieldId( String test ) {
287 if ( protoInterface == null ) {
288 return( null );
289 }
290 int interfaceSize = protoInterface.size();
291 int testScore = 0;
292 String result = null;
293 for ( int i = 0; i < interfaceSize; i++ ) {
294 Field f = (Field)protoInterface.elementAt( i );
295 String testId = f.getFieldId();
296 int score = Spelling.getMatchScore( testId, test );
297 if ( score > testScore ) {
298 result = testId;
299 testScore = score;
300 }
301 }
302 return( result );
303 }
304 }