1 /*******************************************************************************
2  * Copyright (c) 2006, 2011 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.compare.structuremergeviewer;
15 
16 import org.eclipse.compare.IEditableContentExtension;
17 import org.eclipse.compare.ISharedDocumentAdapter;
18 import org.eclipse.compare.ITypedElement;
19 import org.eclipse.core.runtime.IAdaptable;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.swt.graphics.Image;
23 import org.eclipse.swt.widgets.Shell;
24 import org.eclipse.ui.services.IDisposable;
25 
26 /**
27  * A node that acts as the root of the tree returned from a {@link StructureCreator}.
28  * This node performs the following tasks tasks:
29  * <ol>
30  * <li>It adapts to an {@link ISharedDocumentAdapter} that provides the proper
31  * document key (@see {@link #getAdapter(Class)}).</li>
32  * <li>It invokes {@link IStructureCreator#save(IStructureComparator, Object)}
33  * when {@link #nodeChanged(DocumentRangeNode)} is called.</li>
34  * <li>It disposes of the {@link IDisposable} provided in the constructor when
35  * {@link #dispose()} is called.</li>
36  * </ol>
37  * <p>
38  * This class may be subclassed by clients.
39  *
40  * @since 3.3
41  */
42 public class StructureRootNode extends DocumentRangeNode implements IDisposable, ITypedElement {
43 	/**
44 	 * The integer constant (value <code>0</code>) that is used as the type code of the root node.
45 	 * @see #getTypeCode()
46 	 */
47 	public static final int ROOT_TYPE = 0;
48 
49 	/**
50 	 * The string constant (value <code>"root"</code>) that is used as the id of the root node.
51 	 * @see #getId()
52 	 */
53 	public static final String ROOT_ID = "root"; //$NON-NLS-1$
54 
55 	private final Object fInput;
56 	private final StructureCreator fCreator;
57 	private ISharedDocumentAdapter fAdapter;
58 
59 	/**
60 	 * Create the structure root node.
61 	 * @param document the document
62 	 * @param input the input associated with the document
63 	 * @param creator the structure creator that is creating the node
64 	 * @param adapter the shared document adapter from which the document was obtained or <code>null</code>
65 	 *    if the document was not obtained from an {@link ISharedDocumentAdapter}
66 	 */
StructureRootNode(IDocument document, Object input, StructureCreator creator, ISharedDocumentAdapter adapter)67 	public StructureRootNode(IDocument document, Object input, StructureCreator creator, ISharedDocumentAdapter adapter) {
68 		super(null, ROOT_TYPE, ROOT_ID, document, 0, document.getLength());
69 		fInput = input;
70 		fCreator = creator;
71 		fAdapter = adapter;
72 	}
73 
74 	@Override
dispose()75 	public void dispose() {
76 		if (fAdapter != null) {
77 			fAdapter.disconnect(fInput);
78 		}
79 	}
80 
81 	/**
82 	 * Override {@link IAdaptable#getAdapter(Class)} in order to provide
83 	 * an {@link ISharedDocumentAdapter} that provides the proper look up key based
84 	 * on the input from which this structure node was created.
85 	 * @param adapter the adapter class to look up
86 	 * @return the object adapted to the given class or <code>null</code>
87 	 * @see IAdaptable#getAdapter(Class)
88 	 */
89 	@Override
90 	@SuppressWarnings("unchecked")
getAdapter(Class<T> adapter)91 	public <T> T getAdapter(Class<T> adapter) {
92 		if (adapter == ISharedDocumentAdapter.class) {
93 			return (T) fAdapter;
94 		}
95 		return super.getAdapter(adapter);
96 	}
97 
98 	/**
99 	 * Override in order to invoke {@link IStructureCreator#save(IStructureComparator, Object)} when the
100 	 * contents of a node have changed.
101 	 * @param node the changed node
102 	 */
103 	@Override
nodeChanged(DocumentRangeNode node)104 	protected void nodeChanged(DocumentRangeNode node) {
105 		fCreator.save(this, fInput);
106 	}
107 
108 	@Override
replace(ITypedElement child, ITypedElement other)109 	public ITypedElement replace(ITypedElement child, ITypedElement other) {
110 		// TODO: I believe the parent implementation is flawed but didn't to remove
111 		// it in case I was missing something so I overrode it instead
112 		nodeChanged(this);
113 		return child;
114 	}
115 
116 	@Override
getImage()117 	public Image getImage() {
118 		return null;
119 	}
120 
121 	@Override
getName()122 	public String getName() {
123 		return getId();
124 	}
125 
126 	@Override
getType()127 	public String getType() {
128 		return FOLDER_TYPE;
129 	}
130 
131 	@Override
isReadOnly()132 	public boolean isReadOnly() {
133 		if (fInput instanceof IEditableContentExtension) {
134 			IEditableContentExtension ext = (IEditableContentExtension) fInput;
135 			return ext.isReadOnly();
136 		}
137 		return super.isReadOnly();
138 	}
139 
140 	@Override
validateEdit(Shell shell)141 	public IStatus validateEdit(Shell shell) {
142 		if (fInput instanceof IEditableContentExtension) {
143 			IEditableContentExtension ext = (IEditableContentExtension) fInput;
144 			return ext.validateEdit(shell);
145 		}
146 		return super.validateEdit(shell);
147 	}
148 
149 }
150