001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: */
013: package org.pentaho.designstudio.editors.xmleditor;
014:
015: import org.dom4j.Document;
016: import org.dom4j.DocumentHelper;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.jface.text.DocumentEvent;
019: import org.eclipse.jface.text.IDocument;
020: import org.eclipse.jface.text.IDocumentListener;
021: import org.eclipse.jface.text.IDocumentPartitioner;
022: import org.eclipse.jface.text.rules.FastPartitioner;
023: import org.eclipse.jface.util.ListenerList;
024: import org.eclipse.jface.util.SafeRunnable;
025: import org.eclipse.ui.editors.text.TextFileDocumentProvider;
026: import org.pentaho.designstudio.controls.IXmlModificationListener;
027: import org.pentaho.designstudio.controls.XmlModificationEvent;
028: import org.pentaho.designstudio.util.XmlHelper;
029:
030: public class XMLDocumentProvider extends TextFileDocumentProvider
031: implements IXMLDocumentProvider {
032: private Document xmlDocument = null;
033: private long xmlChanged = 0;
034: private long textChanged = 0;
035:
036: Object inputFile;
037: private ListenerList xmlListeners = new ListenerList(1);
038: IDocumentListener docListener = null;
039:
040: public void connect(Object element) throws CoreException {
041: super .connect(element);
042: inputFile = element;
043: xmlDocument = null;
044: IDocument textDocument = getDocument(element);
045: if (textDocument != null) {
046: IDocumentPartitioner partitioner = new FastPartitioner(
047: new XMLPartitionScanner(), new String[] {
048: XMLPartitionScanner.XML_TAG,
049: XMLPartitionScanner.XML_COMMENT });
050: partitioner.connect(textDocument);
051: textDocument.setDocumentPartitioner(partitioner);
052: docListener = new IDocumentListener() {
053: public void documentChanged(DocumentEvent event) {
054: textChanged();
055: }
056:
057: public void documentAboutToBeChanged(DocumentEvent event) {
058: //System.out.println( "textAboutToChange: " + event );
059: }
060: };
061: textDocument.addDocumentListener(docListener);
062:
063: updateXmlDocument();
064: aboutToChange(element);
065: }
066: }
067:
068: protected void updateXmlDocument() {
069: try {
070: xmlDocument = DocumentHelper.parseText(getDocument(
071: inputFile).get());
072: } catch (Exception e) {
073: xmlDocument = null;
074: }
075: resetChanged();
076: }
077:
078: protected void updateTextDocument() {
079: if (xmlDocument != null) {
080: getDocument(inputFile)
081: .set(prettyPrint(xmlDocument).asXML());
082: }
083: resetChanged();
084: }
085:
086: public void prettyPrint() {
087: syncChanges();
088: if (xmlDocument != null) {
089: xmlDocument = prettyPrint(xmlDocument);
090: getDocument(inputFile).set(xmlDocument.asXML());
091: resetChanged();
092: }
093: }
094:
095: public Document prettyPrint(Document doc) {
096: return (XmlHelper.prettyPrint(doc));
097: }
098:
099: private void resetChanged() {
100: textChanged = xmlChanged = 0;
101: }
102:
103: private void textChanged() {
104: textChanged = System.currentTimeMillis();
105: }
106:
107: public void xmlChanged() {
108: if (textChanged == xmlChanged) {
109: if (docListener != null) {
110: getDocument(inputFile).removeDocumentListener(
111: docListener);
112: getDocument(inputFile)
113: .set(getDocument(inputFile).get()); // Hack to set the save flag
114: getDocument(inputFile).addDocumentListener(docListener);
115: }
116: }
117: xmlChanged = System.currentTimeMillis();
118: }
119:
120: public void syncChanges() {
121: if (xmlChanged > textChanged) {
122: updateTextDocument();
123: } else if (xmlChanged < textChanged) {
124: updateXmlDocument();
125: }
126: }
127:
128: public boolean isChanged() {
129: return (textChanged != xmlChanged);
130: }
131:
132: public Document getDocument() {
133: if (xmlChanged < textChanged) {
134: updateXmlDocument();
135: }
136: return (xmlDocument);
137: }
138:
139: public void setChanged() {
140: xmlChanged();
141: }
142:
143: /**
144: * Tests the document for errors valid. Returns the exception or null if ok.
145: *
146: * @return true if the document is valid
147: */
148: ///////// IXMLDocumentProvider
149: public String getDocErrors() {
150: // Assume that the Dom4j version is always valid XML
151: if (xmlChanged < textChanged) {
152: try {
153: DocumentHelper.parseText(getDocument(inputFile).get());
154: } catch (Exception e) {
155: return (XmlHelper.getNestedErrorMessage(e));
156: }
157: syncChanges(); // Parsed ok, lets update everyone
158: }
159: return (null);
160: }
161:
162: public void addXmlModificationListener(
163: IXmlModificationListener listener) {
164: xmlListeners.add(listener);
165: }
166:
167: public void removeXmlModificationListener(
168: IXmlModificationListener listener) {
169: xmlListeners.remove(listener);
170: }
171:
172: public void fireXmlModificationEvent(
173: final XmlModificationEvent event) {
174: Object[] listeners = xmlListeners.getListeners();
175: for (int i = 0; i < listeners.length; ++i) {
176: final IXmlModificationListener l = (IXmlModificationListener) listeners[i];
177: SafeRunnable.run(new SafeRunnable() {
178: public void run() {
179: l.contentChanged(event);
180: }
181: });
182: }
183: }
184: }
|