KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > compare > structuremergeviewer > StructureCreator


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 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  *******************************************************************************/

11 package org.eclipse.compare.structuremergeviewer;
12
13 import java.io.UnsupportedEncodingException JavaDoc;
14
15 import org.eclipse.compare.*;
16 import org.eclipse.compare.contentmergeviewer.IDocumentRange;
17 import org.eclipse.compare.internal.CompareUIPlugin;
18 import org.eclipse.compare.internal.Utilities;
19 import org.eclipse.core.resources.ResourcesPlugin;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.jface.text.*;
23 import org.eclipse.ui.IEditorInput;
24 import org.eclipse.ui.services.IDisposable;
25 import org.eclipse.ui.texteditor.IDocumentProvider;
26
27 /**
28  * An {@link IStructureCreator2} that attempts to use an {@link IDocumentProvider}
29  * to obtain a shared document for an {@link ITypedElement}.
30  * <p>
31  * Clients may subclass this class.
32  * </p>
33  *
34  * @since 3.3
35  */

36 public abstract class StructureCreator implements IStructureCreator2 {
37
38     /* (non-Javadoc)
39      * @see org.eclipse.compare.structuremergeviewer.IStructureCreator#getStructure(java.lang.Object)
40      */

41     public IStructureComparator getStructure(Object JavaDoc input) {
42         String JavaDoc contents= null;
43         IDocument doc= CompareUI.getDocument(input);
44         if (doc == null) {
45             if (input instanceof IStreamContentAccessor) {
46                 IStreamContentAccessor sca= (IStreamContentAccessor) input;
47                 try {
48                     contents= Utilities.readString(sca);
49                 } catch (CoreException e) {
50                     // return null indicates the error.
51
CompareUIPlugin.log(e);
52                     return null;
53                 }
54             }
55             
56             if (contents == null) {
57                 // Node has no contents
58
return null;
59             }
60             
61             doc= new Document(contents);
62             setupDocument(doc);
63         }
64         
65         try {
66             return createStructureComparator(input, doc, null, null);
67         } catch (CoreException e) {
68             CompareUIPlugin.log(e);
69             return null;
70         }
71     }
72
73     /* (non-Javadoc)
74      * @see org.eclipse.compare.structuremergeviewer.IStructureCreator2#createStructure(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
75      */

76     public IStructureComparator createStructure(final Object JavaDoc element, final IProgressMonitor monitor) throws CoreException {
77         final IStructureComparator[] result = new IStructureComparator[] { null };
78         Runnable JavaDoc runnable = new Runnable JavaDoc() {
79             public void run() {
80                 result[0] = internalCreateStructure(element, monitor);
81             }
82         };
83         Utilities.runInUIThread(runnable);
84         return result[0];
85     }
86
87     /*
88      * We need to create the structure in the UI thread since IDocument requires this
89      */

90     private IStructureComparator internalCreateStructure(Object JavaDoc element,
91             IProgressMonitor monitor) {
92         final ISharedDocumentAdapter sda = SharedDocumentAdapterWrapper.getAdapter(element);
93         if (sda != null) {
94             final IEditorInput input = sda.getDocumentKey(element);
95             if (input != null) {
96                 final IDocumentProvider provider = SharedDocumentAdapter.getDocumentProvider(input);
97                 if (provider != null) {
98                     try {
99                         sda.connect(provider, input);
100                         IDocument document = provider.getDocument(input);
101                         setupDocument(document);
102                         return createStructureComparator(element, document, wrapSharedDocumentAdapter(sda, element, document), monitor);
103                     } catch (CoreException e) {
104                         // Connection to the document provider failed.
105
// Log and fall through to use simple structure
106
CompareUIPlugin.log(e);
107                     }
108                 }
109             }
110         }
111         return getStructure(element);
112     }
113     
114     /**
115      * Create an {@link IStructureComparator} for the given element using the
116      * contents available in the given document. If the provided
117      * {@link ISharedDocumentAdapter} is not <code>null</code> then the
118      * {@link IStructureComparator} returned by this method must implement the
119      * {@link IDisposable} interface and disconnect from the adapter when the
120      * comparator is disposed. The {@link StructureDiffViewer} class will call
121      * dispose if the {@link IStructureComparator} also implements
122      * {@link IDisposable}. Other clients must do the same.
123      * <p>
124      * It should be noted that the provided {@link ISharedDocumentAdapter}
125      * will provide the key associated with the given element when
126      * {@link ISharedDocumentAdapter#getDocumentKey(Object)} is called
127      * for any {@link IDocumentRange} node whose document matches the
128      * provided document. Thus, this adapter should also be returned
129      * by the structure comparator and its children when they are adapted
130      * to an {@link ISharedDocumentAdapter}.
131      * @param element the element
132      * @param document the document that has the contents for the element
133      * @param sharedDocumentAdapter the shared document adapter from which the
134      * document was obtained or <code>null</code> if the document
135      * is not shared.
136      * @param monitor a progress monitor or <code>null</code> if progress is not required
137      *
138      * @return a structure comparator
139      * @throws CoreException
140      */

141     protected abstract IStructureComparator createStructureComparator(
142             final Object JavaDoc element, IDocument document,
143             final ISharedDocumentAdapter sharedDocumentAdapter,
144             IProgressMonitor monitor) throws CoreException;
145
146     /**
147      * Setup the newly created document as appropriate. Any document partitioners
148      * should be added to a custom slot using the {@link IDocumentExtension3} interface
149      * in case the document is shared via a file buffer.
150      * @param document a document
151      */

152     protected void setupDocument(IDocument document) {
153         String JavaDoc partitioning = getDocumentPartitioning();
154         if (partitioning == null || !(document instanceof IDocumentExtension3)) {
155             if (document.getDocumentPartitioner() == null) {
156                 IDocumentPartitioner partitioner= getDocumentPartitioner();
157                 if (partitioner != null) {
158                     document.setDocumentPartitioner(partitioner);
159                     partitioner.connect(document);
160                 }
161             }
162         } else {
163             IDocumentExtension3 ex3 = (IDocumentExtension3) document;
164             if (ex3.getDocumentPartitioner(partitioning) == null) {
165                 IDocumentPartitioner partitioner= getDocumentPartitioner();
166                 if (partitioner != null) {
167                     ex3.setDocumentPartitioner(partitioning, partitioner);
168                     partitioner.connect(document);
169                 }
170             }
171         }
172     }
173     
174     /**
175      * Return the partitioner to be associated with the document or
176      * <code>null</code> is partitioning is not needed or if the subclass
177      * overrode {@link #setupDocument(IDocument)} directly.
178      * @return a partitioner
179      */

180     protected IDocumentPartitioner getDocumentPartitioner() {
181         return null;
182     }
183
184     /**
185      * Return the partitioning to which the partitioner returned from
186      * {@link #getDocumentPartitioner()} is to be associated. Return <code>null</code>
187      * only if partitioning is not needed or if the subclass
188      * overrode {@link #setupDocument(IDocument)} directly.
189      * @see IDocumentExtension3
190      * @return a partitioning
191      */

192     protected String JavaDoc getDocumentPartitioning() {
193         return null;
194     }
195     
196     /**
197      * Default implementation of save that extracts the contents from
198      * the document of an {@link IDocumentRange} and sets it on the
199      * input. If the input is an {@link IEncodedStreamContentAccessor},
200      * the charset of the input is used to extract the contents from the
201      * document. If the input adapts to {@link ISharedDocumentAdapter} and
202      * the document of the {@link IDocumentRange} matches that of the
203      * input, then the save is issued through the shared document adapter.
204      * @see org.eclipse.compare.structuremergeviewer.IStructureCreator#save(org.eclipse.compare.structuremergeviewer.IStructureComparator, java.lang.Object)
205      */

206     public void save(IStructureComparator node, Object JavaDoc input) {
207         if (node instanceof IDocumentRange && input instanceof IEditableContent) {
208             IDocument document= ((IDocumentRange)node).getDocument();
209             // First check to see if we have a shared document
210
final ISharedDocumentAdapter sda = SharedDocumentAdapterWrapper.getAdapter(input);
211             if (sda != null) {
212                 IEditorInput key = sda.getDocumentKey(input);
213                 if (key != null) {
214                     IDocumentProvider provider = SharedDocumentAdapter.getDocumentProvider(key);
215                     if (provider != null) {
216                         IDocument providerDoc = provider.getDocument(key);
217                         // We have to make sure that the document we are saving is the same as the shared document
218
if (providerDoc != null && providerDoc == document) {
219                             if (save(provider, document, input, sda, key))
220                                 return;
221                         }
222                     }
223                 }
224             }
225             IEditableContent bca= (IEditableContent) input;
226             String JavaDoc contents= document.get();
227             String JavaDoc encoding= null;
228             if (input instanceof IEncodedStreamContentAccessor) {
229                 try {
230                     encoding= ((IEncodedStreamContentAccessor)input).getCharset();
231                 } catch (CoreException e1) {
232                     // ignore
233
}
234             }
235             if (encoding == null)
236                 encoding= ResourcesPlugin.getEncoding();
237             byte[] bytes;
238             try {
239                 bytes= contents.getBytes(encoding);
240             } catch (UnsupportedEncodingException JavaDoc e) {
241                 bytes= contents.getBytes();
242             }
243             bca.setContent(bytes);
244         }
245     }
246
247     private boolean save(final IDocumentProvider provider, final IDocument document,
248             final Object JavaDoc input, final ISharedDocumentAdapter sda, final IEditorInput key) {
249         try {
250             sda.flushDocument(provider, key, document, false);
251             return true;
252         } catch (CoreException e) {
253             CompareUIPlugin.log(e);
254         }
255         return false;
256     }
257     
258     /**
259      * Create an {@link ISharedDocumentAdapter} that will provide the document key for the given input
260      * object for any {@link DocumentRangeNode} instances whose document is the same as the
261      * provided document.
262      * @param input the input element
263      * @param document the document associated with the input element
264      * @return a shared document adapter that provides the proper document key for document range nodes
265      */

266     private final ISharedDocumentAdapter wrapSharedDocumentAdapter(ISharedDocumentAdapter elementAdapter, final Object JavaDoc input, final IDocument document) {
267         // We need to wrap the adapter so that the proper document key gets returned
268
return new SharedDocumentAdapterWrapper(elementAdapter) {
269             public IEditorInput getDocumentKey(Object JavaDoc element) {
270                 if (hasSameDocument(element)) {
271                     return super.getDocumentKey(input);
272                 }
273                 return super.getDocumentKey(element);
274             }
275             private boolean hasSameDocument(Object JavaDoc element) {
276                 if (element instanceof DocumentRangeNode) {
277                     DocumentRangeNode drn = (DocumentRangeNode) element;
278                     return drn.getDocument() == document;
279                 }
280                 return false;
281             }
282         };
283     }
284     
285     /**
286      * Default implementation of {@link #createElement(Object, Object, IProgressMonitor)}
287      * that uses {@link #getPath(Object, Object)} to determine the
288      * path for the element, {@link #createStructure(Object, IProgressMonitor)} to create the structure
289      * and {@link #findElement(IStructureComparator, String[])} to find the
290      * element in the structure. Subclasses may override.
291      * @param element the element
292      * @param input the containing input
293      * @param monitor a progress monitor
294      * @return the sub-structure element in the input for the given element
295      * @throws CoreException if a parse error occurred
296      */

297     public ITypedElement createElement(Object JavaDoc element, Object JavaDoc input, IProgressMonitor monitor)
298             throws CoreException {
299         String JavaDoc[] path= getPath(element, input);
300         if (path == null) {
301             // TODO: Temporary code until subclasses are updated
302
IStructureComparator locate = locate(element, input);
303             if (locate instanceof ITypedElement) {
304                 return (ITypedElement)locate;
305             }
306             return null;
307         }
308
309         // Build the structure
310
IStructureComparator structure= createStructure(input, monitor);
311         if (structure == null) // we couldn't parse the structure
312
return null; // so we can't find anything
313

314         // find the path in the tree
315
return findElement(structure, path);
316     }
317     
318     /**
319      * Default implementation of {@link #locate(Object, Object)} that
320      * uses {@link #getPath(Object, Object)} to determine the
321      * path for the element, {@link #getStructure(Object)} to create the structure
322      * and {@link #findElement(IStructureComparator, String[])} to find the
323      * element in the structure. Subclasses may override.
324      * @param element the element
325      * @param input the containing input
326      * @return the sub-structure element in the input for the given element
327      */

328     public IStructureComparator locate(Object JavaDoc element, Object JavaDoc input) {
329         String JavaDoc[] path= getPath(element, input);
330         if (path == null)
331             return null;
332         // Build the structure
333
IStructureComparator structure= getStructure(input);
334         if (structure == null) // we couldn't parse the structure
335
return null; // so we can't find anything
336

337         // find the path in the tree
338
return (IStructureComparator)findElement(structure, path);
339     }
340     
341     /**
342      * Find the element at the given path in the given structure.
343      * This method is invoked from the {@link #createElement(Object, Object, IProgressMonitor)}
344      * and {@link #locate(Object, Object)} methods to find the element for
345      * the given path.
346      * @param structure the structure
347      * @param path the path of an element in the structure
348      * @return the element at the given path in the structure or <code>null</code>
349      */

350     protected ITypedElement findElement(IStructureComparator structure, String JavaDoc[] path) {
351         return (ITypedElement)find(structure, path, 0);
352     }
353
354     /**
355      * Recursively extracts the given path from the tree.
356      */

357     private IStructureComparator find(IStructureComparator tree, String JavaDoc[] path, int index) {
358         if (tree != null) {
359             Object JavaDoc[] children= tree.getChildren();
360             if (children != null) {
361                 for (int i= 0; i < children.length; i++) {
362                     IStructureComparator child= (IStructureComparator) children[i];
363                     if (child instanceof ITypedElement && child instanceof DocumentRangeNode) {
364                         String JavaDoc n1= null;
365                         if (child instanceof DocumentRangeNode)
366                             n1= ((DocumentRangeNode)child).getId();
367                         if (n1 == null)
368                             n1= ((ITypedElement)child).getName();
369                         String JavaDoc n2= path[index];
370                         if (n1.equals(n2)) {
371                             if (index == path.length-1)
372                                 return child;
373                             IStructureComparator result= find(child, path, index+1);
374                             if (result != null)
375                                 return result;
376                         }
377                     }
378                 }
379             }
380         }
381         return null;
382     }
383     
384     /**
385      * Return the path of the element in the structure of it's containing input
386      * or <code>null</code> if the element is not contained in the input. This method is
387      * invoked from {@link #createElement(Object, Object, IProgressMonitor)} and
388      * {@link #locate(Object, Object)} methods to determine
389      * the path to be passed to {@link #findElement(IStructureComparator, String[])}.
390      * By default, <code>null</code> is returned. Subclasses may override.
391      * @param element the element
392      * @param input the input
393      * @return the path of the element in the structure of it's containing input
394      * or <code>null</code>
395      */

396     protected String JavaDoc[] getPath(Object JavaDoc element, Object JavaDoc input) {
397         return null;
398     }
399
400     /* (non-Javadoc)
401      * @see org.eclipse.compare.structuremergeviewer.IStructureCreator2#destroy(java.lang.Object)
402      */

403     public void destroy(Object JavaDoc object) {
404         IDisposable disposable = getDisposable(object);
405         if (disposable != null)
406             disposable.dispose();
407     }
408
409     private IDisposable getDisposable(Object JavaDoc object) {
410         if (object instanceof IDisposable) {
411             return (IDisposable) object;
412         }
413         if (object instanceof DocumentRangeNode) {
414             DocumentRangeNode node = (DocumentRangeNode) object;
415             return getDisposable(node.getParentNode());
416         }
417         return null;
418     }
419 }
420
Popular Tags