blob: 3501ed2322dc5dcc52fb47739533761da6019ec3 [file] [log] [blame]
david_williams96213482004-11-11 09:07:12 +00001/*******************************************************************************
2 * Copyright (c) 2001, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Jens Lukowski/Innoopract - initial renaming/restructuring
11 *
12 *******************************************************************************/
13package org.eclipse.wst.xml.core.internal.document;
14
david_williamsc9113882005-04-09 03:19:38 +000015import org.eclipse.wst.sse.core.internal.model.AbstractStructuredModel;
david_williams4ad020f2005-04-18 08:00:30 +000016import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
17import org.eclipse.wst.sse.core.internal.provisional.events.IStructuredDocumentListener;
18import org.eclipse.wst.sse.core.internal.provisional.events.NewDocumentEvent;
19import org.eclipse.wst.sse.core.internal.provisional.events.NoChangeEvent;
20import org.eclipse.wst.sse.core.internal.provisional.events.RegionChangedEvent;
21import org.eclipse.wst.sse.core.internal.provisional.events.RegionsReplacedEvent;
22import org.eclipse.wst.sse.core.internal.provisional.events.StructuredDocumentRegionsReplacedEvent;
23import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
24import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
25import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegionList;
26import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
27import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
david_williams425ffe72004-12-07 21:46:39 +000028import org.eclipse.wst.xml.core.internal.Logger;
david_williams4ad020f2005-04-18 08:00:30 +000029import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
30import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
31import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
32import org.eclipse.wst.xml.core.internal.provisional.document.ISourceGenerator;
david_williams96213482004-11-11 09:07:12 +000033import org.w3c.dom.Attr;
34import org.w3c.dom.DOMException;
35import org.w3c.dom.DOMImplementation;
36import org.w3c.dom.Document;
37import org.w3c.dom.DocumentType;
38import org.w3c.dom.Element;
39import org.w3c.dom.Node;
40
41
42/**
43 * XMLModelImpl class
44 */
david_williams56777022005-04-11 06:21:55 +000045public class DOMModelImpl extends AbstractStructuredModel implements IStructuredDocumentListener, IDOMModel, DOMImplementation {
david_williams96213482004-11-11 09:07:12 +000046 private static String TRACE_PARSER_MANAGEMENT_EXCEPTION = "parserManagement"; //$NON-NLS-1$
47 private Object active = null;
david_williams63f5c322005-03-15 06:02:57 +000048 private DocumentImpl document = null;
david_williams6a8e3892005-04-05 05:21:12 +000049 private ISourceGenerator generator = null;
david_williams96213482004-11-11 09:07:12 +000050 private XMLModelNotifier notifier = null;
51 private XMLModelParser parser = null;
52 private boolean refresh = false;
53 private XMLModelUpdater updater = null;
54
55 /**
56 * XMLModelImpl constructor
57 */
david_williams56777022005-04-11 06:21:55 +000058 public DOMModelImpl() {
david_williams96213482004-11-11 09:07:12 +000059 super();
60 this.document = (DocumentImpl) internalCreateDocument();
61 }
62
63 /**
64 * This API allows clients to declare that they are about to make a
65 * "large" change to the model. This change might be in terms of content
66 * or it might be in terms of the model id or base location.
67 *
68 * Note that in the case of embedded calls, notification to listners is
69 * sent only once.
70 *
71 * Note that the client who is making these changes has the responsibility
72 * to restore the models state once finished with the changes. See
73 * getMemento and restoreState.
74 *
75 * The method isModelStateChanging can be used by a client to determine if
76 * the model is already in a change sequence.
77 */
78 public void aboutToChangeModel() {
79 super.aboutToChangeModel();
80 // technically, no need to call beginChanging so often,
81 // since aboutToChangeModel can be nested.
82 // but will leave as is for this release.
83 // see modelChanged, and be sure stays coordinated there.
84 getModelNotifier().beginChanging();
85 }
86
87 public void aboutToReinitializeModel() {
88 XMLModelNotifier notifier = getModelNotifier();
89 notifier.cancelPending();
90 super.aboutToReinitializeModel();
91 }
92
93 /**
94 * attrReplaced method
95 *
96 * @param element
97 * org.w3c.dom.Element
98 * @param newAttr
99 * org.w3c.dom.Attr
100 * @param oldAttr
101 * org.w3c.dom.Attr
102 */
103 protected void attrReplaced(Element element, Attr newAttr, Attr oldAttr) {
104 if (element == null)
105 return;
106 if (getActiveParser() == null) {
107 XMLModelUpdater updater = getModelUpdater();
108 setActive(updater);
109 updater.initialize();
110 updater.replaceAttr(element, newAttr, oldAttr);
111 setActive(null);
112 }
113 getModelNotifier().attrReplaced(element, newAttr, oldAttr);
114 }
115
116 /**
117 * This API allows a client controlled way of notifying all ModelEvent
118 * listners that the model has been changed. This method is a matched pair
119 * to aboutToChangeModel, and must be called after aboutToChangeModel ...
120 * or some listeners could be left waiting indefinitely for the changed
121 * event. So, its suggested that changedModel always be in a finally
122 * clause. Likewise, a client should never call changedModel without
123 * calling aboutToChangeModel first.
124 *
125 * In the case of embedded calls, the notification is just sent once.
david_williams26f5ed42005-04-10 04:54:13 +0000126 *
david_williams96213482004-11-11 09:07:12 +0000127 */
128 public void changedModel() {
129 // NOTE: the order of 'changedModel' and 'endChanging' is significant.
130 // By calling changedModel first, this basically decrements the
131 // "isChanging" counter
132 // in super class and when zero all listeners to model state events
133 // will be notified
134 // that the model has been changed. 'endChanging' will notify all
135 // deferred adapters.
136 // So, the significance of order is that adapters (and methods they
137 // call)
138 // can count on the state of model "isChanging" to be accurate.
139 // But, remember, that this means the "modelChanged" event can be
140 // received before all
141 // adapters have finished their processing.
142 // NOTE NOTE: The above note is obsolete in fact (though still states
143 // issue correctly).
144 // Due to popular demand, the order of these calls were reversed and
145 // behavior
146 // changed on 07/22/2004.
147 //
148 // see also
149 // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=4302
150 // for motivation for this 'on verge of' call.
151 // this could be improved in future if notifier also used counting
152 // flag to avoid nested calls. If/when changed be sure to check if
153 // aboutToChangeModel needs any changes too.
154 if (isModelChangeStateOnVergeOfEnding()) {
155 // end lock before noticiation loop, since directly or indirectly
156 // we may be "called from foriegn code" during notification.
157 endLock();
david_williamse2ed76e2005-12-06 07:31:36 +0000158 // we null out here to avoid spurious"warning" message while debug
159 // tracing is enabled
david_williams6f9dcdd2005-10-09 05:14:55 +0000160 fLockObject = null;
david_williams96213482004-11-11 09:07:12 +0000161 // the notifier is what controls adaper notification, which
162 // should be sent out before the 'modelChanged' event.
163 getModelNotifier().endChanging();
164 }
165 // changedModel handles 'nesting', so only one event sent out
166 // when mulitple calls to 'aboutToChange/Changed'.
167 super.changedModel();
168 handleRefresh();
169 }
170
171 /**
172 * childReplaced method
173 *
174 * @param parentNode
175 * org.w3c.dom.Node
176 * @param newChild
177 * org.w3c.dom.Node
178 * @param oldChild
179 * org.w3c.dom.Node
180 */
181 protected void childReplaced(Node parentNode, Node newChild, Node oldChild) {
182 if (parentNode == null)
183 return;
184 if (getActiveParser() == null) {
185 XMLModelUpdater updater = getModelUpdater();
186 setActive(updater);
187 updater.initialize();
188 updater.replaceChild(parentNode, newChild, oldChild);
189 setActive(null);
190 }
191 getModelNotifier().childReplaced(parentNode, newChild, oldChild);
192 }
193
194 /**
195 * Creates an XML <code>Document</code> object of the specified type
196 * with its document element. HTML-only DOM implementations do not need to
197 * implement this method.
198 *
199 * @param namespaceURIThe
200 * namespace URI of the document element to create.
201 * @param qualifiedNameThe
202 * qualified name of the document element to be created.
203 * @param doctypeThe
204 * type of document to be created or <code>null</code>. When
205 * <code>doctype</code> is not <code>null</code>, its
206 * <code>Node.ownerDocument</code> attribute is set to the
207 * document being created.
208 * @return A new <code>Document</code> object.
209 * @exception DOMException
210 * INVALID_CHARACTER_ERR: Raised if the specified qualified
211 * name contains an illegal character. <br>
212 * NAMESPACE_ERR: Raised if the <code>qualifiedName</code>
213 * is malformed, if the <code>qualifiedName</code> has a
214 * prefix and the <code>namespaceURI</code> is
215 * <code>null</code>, or if the
216 * <code>qualifiedName</code> has a prefix that is "xml"
217 * and the <code>namespaceURI</code> is different from "
218 * http://www.w3.org/XML/1998/namespace" .<br>
219 * WRONG_DOCUMENT_ERR: Raised if <code>doctype</code> has
220 * already been used with a different document or was
221 * created from a different implementation.
david_williams6cb26392005-06-24 20:13:29 +0000222 * @see DOM Level 2
david_williams96213482004-11-11 09:07:12 +0000223 */
224 public Document createDocument(String namespaceURI, String qualifiedName, DocumentType doctype) throws DOMException {
225 return null;
226 }
227
228 /**
229 * Creates an empty <code>DocumentType</code> node. Entity declarations
230 * and notations are not made available. Entity reference expansions and
231 * default attribute additions do not occur. It is expected that a future
232 * version of the DOM will provide a way for populating a
233 * <code>DocumentType</code>.<br>
234 * HTML-only DOM implementations do not need to implement this method.
235 *
236 * @param qualifiedNameThe
237 * qualified name of the document type to be created.
238 * @param publicIdThe
239 * external subset public identifier.
240 * @param systemIdThe
241 * external subset system identifier.
242 * @return A new <code>DocumentType</code> node with
243 * <code>Node.ownerDocument</code> set to <code>null</code>.
244 * @exception DOMException
245 * INVALID_CHARACTER_ERR: Raised if the specified qualified
246 * name contains an illegal character. <br>
247 * NAMESPACE_ERR: Raised if the <code>qualifiedName</code>
248 * is malformed.
david_williams6cb26392005-06-24 20:13:29 +0000249 * @see DOM Level 2
david_williams96213482004-11-11 09:07:12 +0000250 */
251 public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId) throws DOMException {
252 DocumentTypeImpl documentType = new DocumentTypeImpl();
253 documentType.setName(qualifiedName);
254 documentType.setPublicId(publicId);
255 documentType.setSystemId(systemId);
256 return documentType;
257 }
258
259 /**
260 */
261 protected void documentTypeChanged() {
262 if (this.refresh)
263 return;
264 // unlike 'resfresh', 'reinitialize' finishes loop
265 // and flushes remaining notification que before
266 // actually reinitializing.
david_williamse5a37012005-02-09 23:42:12 +0000267 // ISSUE: should reinit be used instead of handlerefresh?
268 // this.setReinitializeNeeded(true);
269 if (this.active != null || getModelNotifier().isChanging())
270 return; // defer
271 handleRefresh();
david_williams96213482004-11-11 09:07:12 +0000272 }
273
274 protected void editableChanged(Node node) {
275 if (node != null) {
276 getModelNotifier().editableChanged(node);
277 }
278 }
279
280 /**
281 */
282 protected void endTagChanged(Element element) {
283 if (element == null)
284 return;
285 if (getActiveParser() == null) {
286 XMLModelUpdater updater = getModelUpdater();
287 setActive(updater);
288 updater.initialize();
289 updater.changeEndTag(element);
290 setActive(null);
291 }
292 getModelNotifier().endTagChanged(element);
293 }
294
295 /**
296 */
297 private XMLModelParser getActiveParser() {
298 if (this.parser == null)
299 return null;
300 if (this.parser != this.active)
301 return null;
302 return this.parser;
303 }
304
305 /**
306 */
307 private XMLModelUpdater getActiveUpdater() {
308 if (this.updater == null)
309 return null;
310 if (this.updater != this.active)
311 return null;
312 return this.updater;
313 }
314
315 /*
316 * (non-Javadoc)
317 *
318 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
319 */
320 public Object getAdapter(Class adapter) {
321 if (Document.class.equals(adapter))
322 return getDocument();
323 return super.getAdapter(adapter);
324 }
325
326 /**
327 * getDocument method
328 *
329 * @return XMLDocument
330 */
david_williamsc39caaf2005-04-05 06:07:16 +0000331 public IDOMDocument getDocument() {
david_williams96213482004-11-11 09:07:12 +0000332 return this.document;
333 }
334
david_williams6a8e3892005-04-05 05:21:12 +0000335 public ISourceGenerator getGenerator() {
david_williams96213482004-11-11 09:07:12 +0000336 if (this.generator == null) {
337 this.generator = XMLGeneratorImpl.getInstance();
338 }
339 return this.generator;
340 }
341
342 /**
343 * getNode method
344 *
345 * @param offset
346 * int
347 */
348 public IndexedRegion getIndexedRegion(int offset) {
349 if (this.document == null)
350 return null;
351 // search in document children
david_williamsc39caaf2005-04-05 06:07:16 +0000352 IDOMNode parent = null;
david_williams96213482004-11-11 09:07:12 +0000353 int length = this.document.getEndOffset();
354 if (offset * 2 < length) {
355 // search from the first
david_williamsc39caaf2005-04-05 06:07:16 +0000356 IDOMNode child = (IDOMNode) this.document.getFirstChild();
david_williams96213482004-11-11 09:07:12 +0000357 while (child != null) {
358 if (child.getEndOffset() <= offset) {
david_williamsc39caaf2005-04-05 06:07:16 +0000359 child = (IDOMNode) child.getNextSibling();
david_williams96213482004-11-11 09:07:12 +0000360 continue;
361 }
362 if (child.getStartOffset() > offset) {
363 break;
364 }
365 IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
366 if (startStructuredDocumentRegion != null) {
367 if (startStructuredDocumentRegion.getEnd() > offset)
368 return child;
369 }
370 IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion();
371 if (endStructuredDocumentRegion != null) {
372 if (endStructuredDocumentRegion.getStart() <= offset)
373 return child;
374 }
375 // dig more
376 parent = child;
david_williamsc39caaf2005-04-05 06:07:16 +0000377 child = (IDOMNode) parent.getFirstChild();
david_williams96213482004-11-11 09:07:12 +0000378 }
david_williams26f5ed42005-04-10 04:54:13 +0000379 }
380 else {
david_williams96213482004-11-11 09:07:12 +0000381 // search from the last
david_williamsc39caaf2005-04-05 06:07:16 +0000382 IDOMNode child = (IDOMNode) this.document.getLastChild();
david_williams96213482004-11-11 09:07:12 +0000383 while (child != null) {
384 if (child.getStartOffset() > offset) {
david_williamsc39caaf2005-04-05 06:07:16 +0000385 child = (IDOMNode) child.getPreviousSibling();
david_williams96213482004-11-11 09:07:12 +0000386 continue;
387 }
388 if (child.getEndOffset() <= offset) {
389 break;
390 }
391 IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
392 if (startStructuredDocumentRegion != null) {
393 if (startStructuredDocumentRegion.getEnd() > offset)
394 return child;
395 }
396 IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion();
397 if (endStructuredDocumentRegion != null) {
398 if (endStructuredDocumentRegion.getStart() <= offset)
399 return child;
400 }
401 // dig more
402 parent = child;
david_williamsc39caaf2005-04-05 06:07:16 +0000403 child = (IDOMNode) parent.getLastChild();
david_williams96213482004-11-11 09:07:12 +0000404 }
405 }
406 return parent;
407 }
408
409 /**
410 */
411 public XMLModelNotifier getModelNotifier() {
412 if (this.notifier == null) {
413 this.notifier = new XMLModelNotifierImpl();
414 }
415 return this.notifier;
416 }
417
418 /**
419 */
420 private XMLModelParser getModelParser() {
421 if (this.parser == null) {
david_williams63f5c322005-03-15 06:02:57 +0000422 this.parser = createModelParser();
david_williams96213482004-11-11 09:07:12 +0000423 }
424 return this.parser;
425 }
426
david_williams63f5c322005-03-15 06:02:57 +0000427 protected XMLModelParser createModelParser() {
428 return new XMLModelParser(this);
429 }
430
david_williams96213482004-11-11 09:07:12 +0000431 /**
432 */
433 private XMLModelUpdater getModelUpdater() {
434 if (this.updater == null) {
david_williams63f5c322005-03-15 06:02:57 +0000435 this.updater = createModelUpdater();
david_williams96213482004-11-11 09:07:12 +0000436 }
437 return this.updater;
438 }
439
david_williams63f5c322005-03-15 06:02:57 +0000440 protected XMLModelUpdater createModelUpdater() {
441 return new XMLModelUpdater(this);
442 }
443
david_williams96213482004-11-11 09:07:12 +0000444 /**
445 */
446 private void handleRefresh() {
447 if (!this.refresh)
448 return;
449 XMLModelNotifier notifier = getModelNotifier();
450 boolean isChanging = notifier.isChanging();
451 if (!isChanging)
452 notifier.beginChanging(true);
453 XMLModelParser parser = getModelParser();
454 setActive(parser);
455 this.document.removeChildNodes();
456 try {
457 parser.replaceStructuredDocumentRegions(getStructuredDocument().getRegionList(), null);
david_williams26f5ed42005-04-10 04:54:13 +0000458 }
459 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000460 Logger.logException(ex);
david_williams26f5ed42005-04-10 04:54:13 +0000461 }
462 finally {
david_williams96213482004-11-11 09:07:12 +0000463 setActive(null);
464 if (!isChanging)
465 notifier.endChanging();
466 this.refresh = false;
467 }
468 }
469
470 /**
471 * Test if the DOM implementation implements a specific feature.
472 *
473 * @param featureThe
474 * name of the feature to test (case-insensitive). The values
475 * used by DOM features are defined throughout the DOM Level 2
476 * specifications and listed in the section. The name must be
477 * an XML name. To avoid possible conflicts, as a convention,
478 * names referring to features defined outside the DOM
479 * specification should be made unique by reversing the name of
480 * the Internet domain name of the person (or the organization
481 * that the person belongs to) who defines the feature,
482 * component by component, and using this as a prefix. For
483 * instance, the W3C SVG Working Group defines the feature
484 * "org.w3c.dom.svg".
485 * @param versionThis
486 * is the version number of the feature to test. In Level 2,
487 * the string can be either "2.0" or "1.0". If the version is
488 * not specified, supporting any version of the feature causes
489 * the method to return <code>true</code>.
490 * @return <code>true</code> if the feature is implemented in the
491 * specified version, <code>false</code> otherwise.
492 */
493 public boolean hasFeature(String feature, String version) {
494 if (feature == null)
495 return false;
496 if (version != null) {
497 if (!version.equals("1.0") && !version.equals("2.0")) { //$NON-NLS-2$//$NON-NLS-1$
498 return false;
499 }
500 }
501 if (feature.equalsIgnoreCase("Core")) //$NON-NLS-1$
502 return true; //$NON-NLS-1$
503 if (feature.equalsIgnoreCase("XML")) //$NON-NLS-1$
504 return true; //$NON-NLS-1$
505 return false;
506 }
507
508 /**
509 * createDocument method
510 *
511 * @return org.w3c.dom.Document
512 */
513 protected Document internalCreateDocument() {
514 DocumentImpl document = new DocumentImpl();
515 document.setModel(this);
516 return document;
517 }
518
519 boolean isReparsing() {
520 return (active != null);
521 }
522
523 /**
524 * nameChanged method
525 *
526 * @param node
527 * org.w3c.dom.Node
528 */
529 protected void nameChanged(Node node) {
530 if (node == null)
531 return;
532 if (getActiveParser() == null) {
533 XMLModelUpdater updater = getModelUpdater();
534 setActive(updater);
535 updater.initialize();
536 updater.changeName(node);
537 setActive(null);
538 }
539 // notification is already sent
540 }
541
542 /**
543 * newModel method
544 *
david_williams96213482004-11-11 09:07:12 +0000545 */
546 public void newModel(NewDocumentEvent structuredDocumentEvent) {
547 if (structuredDocumentEvent == null)
548 return;
549 IStructuredDocument structuredDocument = structuredDocumentEvent.getStructuredDocument();
550 if (structuredDocument == null)
551 return;
552 // this should not happen, but for the case
david_williamse2ed76e2005-12-06 07:31:36 +0000553 if (fStructuredDocument != null && fStructuredDocument != structuredDocument)
david_williams96213482004-11-11 09:07:12 +0000554 setStructuredDocument(structuredDocument);
david_williamse2ed76e2005-12-06 07:31:36 +0000555
556 internalSetNewDocument(structuredDocument);
557 }
558
559 private void internalSetNewDocument(IStructuredDocument structuredDocument) {
560 if (structuredDocument == null)
561 return;
david_williams96213482004-11-11 09:07:12 +0000562 IStructuredDocumentRegionList flatNodes = structuredDocument.getRegionList();
david_williams26f5ed42005-04-10 04:54:13 +0000563 if ((flatNodes == null) || (flatNodes.getLength() == 0)) {
david_williams96213482004-11-11 09:07:12 +0000564 return;
david_williams26f5ed42005-04-10 04:54:13 +0000565 }
david_williams96213482004-11-11 09:07:12 +0000566 if (this.document == null)
567 return; // being constructed
568 XMLModelUpdater updater = getActiveUpdater();
569 if (updater != null) { // being updated
570 try {
571 updater.replaceStructuredDocumentRegions(flatNodes, null);
david_williams26f5ed42005-04-10 04:54:13 +0000572 }
573 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000574 Logger.logException(ex);
575 this.refresh = true;
576 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000577 }
578 finally {
david_williams96213482004-11-11 09:07:12 +0000579 setActive(null);
580 }
david_williams26f5ed42005-04-10 04:54:13 +0000581 // // for new model, we might need to
582 // // re-init, e.g. if someone calls setText
583 // // on an existing model
584 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000585 return;
586 }
587 XMLModelNotifier notifier = getModelNotifier();
588 boolean isChanging = notifier.isChanging();
589 // call even if changing to notify doing new model
590 getModelNotifier().beginChanging(true);
591 XMLModelParser parser = getModelParser();
592 setActive(parser);
593 this.document.removeChildNodes();
594 try {
595 parser.replaceStructuredDocumentRegions(flatNodes, null);
david_williams26f5ed42005-04-10 04:54:13 +0000596 }
597 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000598 Logger.logException(ex);
599 // meaningless to refresh, because the result might be the same
david_williams26f5ed42005-04-10 04:54:13 +0000600 }
601 finally {
david_williams96213482004-11-11 09:07:12 +0000602 setActive(null);
603 if (!isChanging) {
604 getModelNotifier().endChanging();
605 }
606 // ignore refresh
607 this.refresh = false;
608 }
david_williams96213482004-11-11 09:07:12 +0000609 }
610
611 /**
612 */
613 public void noChange(NoChangeEvent event) {
614 XMLModelUpdater updater = getActiveUpdater();
615 if (updater != null) { // being updated
616 // cleanup updater staffs
617 try {
618 updater.replaceStructuredDocumentRegions(null, null);
david_williams26f5ed42005-04-10 04:54:13 +0000619 }
620 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000621 Logger.logException(ex);
622 this.refresh = true;
623 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000624 }
625 finally {
david_williams96213482004-11-11 09:07:12 +0000626 setActive(null);
627 }
628 // I guess no chanage means the model could not need re-init
david_williams26f5ed42005-04-10 04:54:13 +0000629 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000630 return;
631 }
632 }
633
634 /**
635 * nodesReplaced method
636 *
david_williams96213482004-11-11 09:07:12 +0000637 */
638 public void nodesReplaced(StructuredDocumentRegionsReplacedEvent event) {
639 if (event == null)
640 return;
641 IStructuredDocumentRegionList oldStructuredDocumentRegions = event.getOldStructuredDocumentRegions();
642 IStructuredDocumentRegionList newStructuredDocumentRegions = event.getNewStructuredDocumentRegions();
643 XMLModelUpdater updater = getActiveUpdater();
644 if (updater != null) { // being updated
645 try {
646 updater.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
david_williams26f5ed42005-04-10 04:54:13 +0000647 }
648 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000649 if (ex.getClass().equals(StructuredDocumentRegionManagementException.class)) {
650 Logger.traceException(TRACE_PARSER_MANAGEMENT_EXCEPTION, ex);
david_williams26f5ed42005-04-10 04:54:13 +0000651 }
652 else {
david_williams96213482004-11-11 09:07:12 +0000653 Logger.logException(ex);
654 }
655 this.refresh = true;
656 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000657 }
658 finally {
david_williams96213482004-11-11 09:07:12 +0000659 setActive(null);
660 }
david_williams26f5ed42005-04-10 04:54:13 +0000661 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000662 return;
663 }
664 XMLModelNotifier notifier = getModelNotifier();
665 boolean isChanging = notifier.isChanging();
666 if (!isChanging)
667 notifier.beginChanging();
668 XMLModelParser parser = getModelParser();
669 setActive(parser);
670 try {
671 parser.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
david_williams26f5ed42005-04-10 04:54:13 +0000672 }
673 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000674 Logger.logException(ex);
675 this.refresh = true;
676 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000677 }
678 finally {
david_williams96213482004-11-11 09:07:12 +0000679 setActive(null);
680 if (!isChanging) {
681 notifier.endChanging();
682 handleRefresh();
683 }
684 }
685
686 }
687
688 /**
689 * regionChanged method
690 *
691 * @param structuredDocumentEvent
david_williams96213482004-11-11 09:07:12 +0000692 */
693 public void regionChanged(RegionChangedEvent event) {
694 if (event == null)
695 return;
696 IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
697 if (flatNode == null)
698 return;
699 ITextRegion region = event.getRegion();
700 if (region == null)
701 return;
702 XMLModelUpdater updater = getActiveUpdater();
703 if (updater != null) { // being updated
704 try {
705 updater.changeRegion(flatNode, region);
david_williams26f5ed42005-04-10 04:54:13 +0000706 }
707 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000708 Logger.logException(ex);
709 this.refresh = true;
710 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000711 }
712 finally {
david_williams96213482004-11-11 09:07:12 +0000713 setActive(null);
714 }
david_williams26f5ed42005-04-10 04:54:13 +0000715 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000716 return;
717 }
718 XMLModelNotifier notifier = getModelNotifier();
719 boolean isChanging = notifier.isChanging();
720 if (!isChanging)
721 notifier.beginChanging();
722 XMLModelParser parser = getModelParser();
723 setActive(parser);
724 try {
725 parser.changeRegion(flatNode, region);
david_williams26f5ed42005-04-10 04:54:13 +0000726 }
727 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000728 Logger.logException(ex);
729 this.refresh = true;
730 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000731 }
732 finally {
david_williams96213482004-11-11 09:07:12 +0000733 setActive(null);
734 if (!isChanging) {
735 notifier.endChanging();
736 handleRefresh();
737 }
738 }
david_williams26f5ed42005-04-10 04:54:13 +0000739 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000740 }
741
742 /**
743 * regionsReplaced method
744 *
745 * @param event
david_williams96213482004-11-11 09:07:12 +0000746 */
747 public void regionsReplaced(RegionsReplacedEvent event) {
748 if (event == null)
749 return;
750 IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
751 if (flatNode == null)
752 return;
753 ITextRegionList oldRegions = event.getOldRegions();
754 ITextRegionList newRegions = event.getNewRegions();
755 if (oldRegions == null && newRegions == null)
756 return;
757 XMLModelUpdater updater = getActiveUpdater();
758 if (updater != null) { // being updated
759 try {
760 updater.replaceRegions(flatNode, newRegions, oldRegions);
david_williams26f5ed42005-04-10 04:54:13 +0000761 }
762 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000763 Logger.logException(ex);
764 this.refresh = true;
765 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000766 }
767 finally {
david_williams96213482004-11-11 09:07:12 +0000768 setActive(null);
769 }
david_williams26f5ed42005-04-10 04:54:13 +0000770 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000771 return;
772 }
773 XMLModelNotifier notifier = getModelNotifier();
774 boolean isChanging = notifier.isChanging();
775 if (!isChanging)
776 notifier.beginChanging();
777 XMLModelParser parser = getModelParser();
778 setActive(parser);
779 try {
780 parser.replaceRegions(flatNode, newRegions, oldRegions);
david_williams26f5ed42005-04-10 04:54:13 +0000781 }
782 catch (Exception ex) {
david_williams96213482004-11-11 09:07:12 +0000783 Logger.logException(ex);
784 this.refresh = true;
785 handleRefresh();
david_williams26f5ed42005-04-10 04:54:13 +0000786 }
787 finally {
david_williams96213482004-11-11 09:07:12 +0000788 setActive(null);
789 if (!isChanging) {
790 notifier.endChanging();
791 handleRefresh();
792 }
793 }
david_williams26f5ed42005-04-10 04:54:13 +0000794 // checkForReinit();
david_williams96213482004-11-11 09:07:12 +0000795 }
796
797 /**
798 */
799 public void releaseFromEdit() {
800 if (!isShared()) {
david_williams26f5ed42005-04-10 04:54:13 +0000801 // this.document.releaseStyleSheets();
david_williamsb2de2de2005-07-16 16:44:06 +0000802 // this.document.releaseDocumentType();
david_williams96213482004-11-11 09:07:12 +0000803 }
804 super.releaseFromEdit();
805 }
806
807 /**
808 */
809 public void releaseFromRead() {
810 if (!isShared()) {
david_williams26f5ed42005-04-10 04:54:13 +0000811 // this.document.releaseStyleSheets();
david_williamsb2de2de2005-07-16 16:44:06 +0000812 // this.document.releaseDocumentType();
david_williams96213482004-11-11 09:07:12 +0000813 }
814 super.releaseFromRead();
815 }
816
817 /**
818 */
819 private void setActive(Object active) {
820 this.active = active;
821 // side effect
822 // when ever becomes active, besure tagNameCache is cleared
823 // (and not used)
824 if (active == null) {
825 document.activateTagNameCache(true);
david_williams26f5ed42005-04-10 04:54:13 +0000826 }
827 else {
david_williams96213482004-11-11 09:07:12 +0000828 document.activateTagNameCache(false);
829 }
830
831 }
832
833 /**
834 */
david_williams6a8e3892005-04-05 05:21:12 +0000835 public void setGenerator(ISourceGenerator generator) {
david_williams96213482004-11-11 09:07:12 +0000836 this.generator = generator;
837 }
838
839 /**
840 */
841 public void setModelNotifier(XMLModelNotifier notifier) {
842 this.notifier = notifier;
843 }
844
845 /**
846 */
847 public void setModelParser(XMLModelParser parser) {
848 this.parser = parser;
849 }
850
851 /**
852 */
853 public void setModelUpdater(XMLModelUpdater updater) {
854 this.updater = updater;
855 }
856
857 /**
858 * setStructuredDocument method
859 *
860 * @param structuredDocument
david_williams96213482004-11-11 09:07:12 +0000861 */
862 public void setStructuredDocument(IStructuredDocument structuredDocument) {
david_williams4fe85312005-12-06 08:43:39 +0000863 IStructuredDocument oldStructuredDocument = super.getStructuredDocument();
864 if (structuredDocument == oldStructuredDocument)
865 return; // nothing to do
866 if (oldStructuredDocument != null)
867 oldStructuredDocument.removeDocumentChangingListener(this);
868 super.setStructuredDocument(structuredDocument);
869 if (structuredDocument != null) {
870 internalSetNewDocument(structuredDocument);
871 structuredDocument.addDocumentChangingListener(this);
david_williamsb2de2de2005-07-16 16:44:06 +0000872 }
david_williams96213482004-11-11 09:07:12 +0000873 }
874
875 /**
876 */
877 protected void startTagChanged(Element element) {
878 if (element == null)
879 return;
880 if (getActiveParser() == null) {
881 XMLModelUpdater updater = getModelUpdater();
882 setActive(updater);
883 updater.initialize();
884 updater.changeStartTag(element);
885 setActive(null);
886 }
887 getModelNotifier().startTagChanged(element);
888 }
889
890 /**
891 * valueChanged method
892 *
893 * @param node
894 * org.w3c.dom.Node
895 */
896 protected void valueChanged(Node node) {
897 if (node == null)
898 return;
899 if (getActiveParser() == null) {
900 XMLModelUpdater updater = getModelUpdater();
901 setActive(updater);
902 updater.initialize();
903 updater.changeValue(node);
904 setActive(null);
905 }
906 getModelNotifier().valueChanged(node);
907 }
david_williams838590b2005-04-14 14:05:08 +0000908
909 /**
910 * NOT IMPLEMENTED. Is defined here in preparation of DOM 3.
911 */
912 public Object getFeature(String feature, String version) {
nitindedf5a442005-05-17 18:23:07 +0000913 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Not implemented in this version."); //$NON-NLS-1$
david_williams838590b2005-04-14 14:05:08 +0000914 }
david_williams96213482004-11-11 09:07:12 +0000915}