cdmlib version change
[taxeditor.git] / eu.etaxonomy.taxeditor.bulkeditor / src / main / java / eu / etaxonomy / taxeditor / annotatedlineeditor / AnnotatedLineDocumentProvider.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.taxeditor.annotatedlineeditor;
11
12 import java.util.Iterator;
13 import java.util.List;
14
15 import org.eclipse.core.runtime.Assert;
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.jface.operation.IRunnableContext;
19 import org.eclipse.jface.text.BadLocationException;
20 import org.eclipse.jface.text.Document;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.Position;
23 import org.eclipse.jface.text.source.Annotation;
24 import org.eclipse.jface.text.source.IAnnotationModel;
25 import org.eclipse.ui.IEditorInput;
26 import org.eclipse.ui.texteditor.AbstractDocumentProvider;
27
28 import eu.etaxonomy.taxeditor.bulkeditor.BulkEditorUtil;
29 import eu.etaxonomy.taxeditor.bulkeditor.input.AbstractBulkEditorInput;
30
31
32
33 /**
34 * Using an <code>IEditorPart</code>, creates a document where each line is associated
35 * with an entity. Mapping between document positions and entities is stored in
36 * <code>LineAnnotation</code>s in a <code>LineAnnotationModel</code>.
37 * <p>
38 * Requires:
39 * <ul>
40 * <li>an <code>IEntityCreator</code> to create entities for new lines;
41 * <li>an <code>IEntityPersistenceService</code> for interacting with the persistence layer; and
42 * <li>an <code>ILineDisplayStrategy</code> for various visual manifestations of the domain object.
43 * </ul>
44 *
45 * @author p.ciardelli
46 * @author n.hoffmann
47 * @created 25.06.2009
48 * @version 1.0
49 */
50 public class AnnotatedLineDocumentProvider extends AbstractDocumentProvider {
51
52 private IDocument document;
53
54 private LineAnnotationModel annotationModel;
55
56 private IEntityCreator<?> entityCreator;
57
58 private ILineDisplayStrategy lineDisplayStrategy;
59
60 private IEditorInput input;
61
62 /**
63 * <p>Constructor for AnnotatedLineDocumentProvider.</p>
64 *
65 * @param input a {@link org.eclipse.ui.IEditorInput} object.
66 */
67 public AnnotatedLineDocumentProvider(IEditorInput input){
68 this.input = input;
69 }
70
71 /** {@inheritDoc} */
72 @Override
73 public IAnnotationModel getAnnotationModel(Object element) {
74 if (element == input) {
75
76 // Create model as necessary
77 if (annotationModel == null) {
78 annotationModel = new LineAnnotationModel(getLineDisplayStrategy(element));
79 annotationModel.setEntityCreator(getEntityCreator(input));
80 }
81 return annotationModel;
82 }
83
84 return null;
85 }
86
87 /** {@inheritDoc} */
88 @Override
89 protected IAnnotationModel createAnnotationModel(Object element)
90 throws CoreException {
91 return getAnnotationModel(element);
92 }
93
94 /** {@inheritDoc} */
95 @Override
96 public IDocument getDocument(Object element) {
97 return document;
98 }
99
100 /** {@inheritDoc} */
101 @Override
102 protected IDocument createDocument(Object element) throws CoreException {
103
104 if (element instanceof IEditorInput) {
105 IEditorInput input = (IEditorInput) element;
106 document = new Document("");
107 // IAnnotationModel model = getAnnotationModel(element);
108
109 List<?> entityList = getEntityList(element);
110
111 if(entityList != null){
112 for (Object entity : entityList) {
113 try {
114 createAnnotatedLine(input, entity);
115 } catch (BadLocationException e) {
116 BulkEditorUtil.error(getClass(), "Problems creating annotated line: ", e);
117 }
118 }
119 }
120
121 return document;
122 }
123 return null;
124 }
125
126 /**
127 * Creates an annotated line at the end of the document associated with the element
128 *
129 * @throws org.eclipse.jface.text.BadLocationException if any.
130 * @param element a {@link java.lang.Object} object.
131 * @param entity a {@link java.lang.Object} object.
132 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
133 */
134 protected LineAnnotation createAnnotatedLine(Object element, Object entity) throws BadLocationException {
135
136 Document document = (Document) getDocument(element);
137 ILineDisplayStrategy lineDisplayStrategy = getLineDisplayStrategy(element);
138
139 LineAnnotation annotation = new LineAnnotation(entity, lineDisplayStrategy);
140
141 // Is document zero length, or is last char in document line delimiter?
142 int docLength = document.getLength();
143 boolean useDelimiter = false;
144 if (docLength > 0) {
145 if (docLength > 1 && !document.get(docLength - 2, 2).equals(document.getDefaultLineDelimiter())) {
146 useDelimiter = true;
147 }
148 }
149 if (useDelimiter) {
150 document.replace(docLength, 0, document.getDefaultLineDelimiter());
151 }
152
153 String text;
154 if (lineDisplayStrategy.isEntityCacheEmpty(entity)) {
155 text = lineDisplayStrategy.getEmptyCacheMessage(entity);
156 } else {
157 text = lineDisplayStrategy.getText(entity);
158 }
159 text += lineDisplayStrategy.getSupplementalText(entity);
160 docLength = document.getLength();
161 document.replace(docLength, 0, text);
162
163 Position position = new Position(docLength, text.length());
164
165 IAnnotationModel model = getAnnotationModel(element);
166 if(model != null){
167 model.addAnnotation(annotation, position);
168 }
169
170 // lineDisplayStrategy.addDisplayListener(entity,
171 // new EntityListenerImpl((LineAnnotation) annotation, element));
172 //
173 return annotation;
174 }
175
176
177 /**
178 * <p>updateLineFromAnnotation</p>
179 *
180 * @param annotation a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
181 */
182 public void updateLineFromAnnotation(LineAnnotation annotation) {
183
184 IAnnotationModel model = getAnnotationModel(input);
185 IDocument document = getDocument(input);
186 ILineDisplayStrategy lineDisplay = getLineDisplayStrategy(input);
187
188 Object entity = annotation.getEntity();
189 String text = "";
190 if (getLineDisplayStrategy(input).isEntityCacheEmpty(entity)) {
191 text = lineDisplay.getEmptyCacheMessage(entity);
192 } else {
193 text = lineDisplay.getText(entity);
194 }
195 text += lineDisplay.getSupplementalText(entity);
196
197 try {
198 if (model.getPosition(annotation) == null) {
199 return;
200 }
201 int offset = model.getPosition(annotation).getOffset();
202 int line = document.getLineOfOffset(offset);
203 int lineLength = document.getLineLength(document.getLineOfOffset(offset));
204 if (document.getLineDelimiter(line) != null) {
205 lineLength -= document.getLineDelimiter(line).length();
206 }
207 document.replace(offset, lineLength, text);
208 } catch (BadLocationException e) {
209 BulkEditorUtil.error(getClass(), "Problem updating annotated line: " ,e);
210 }
211 }
212
213 /**
214 * @param element
215 * @return
216 */
217 private List<?> getEntityList(Object element) {
218 if (element instanceof AbstractBulkEditorInput) {
219 return ((AbstractBulkEditorInput)element).getModel();
220 }
221 return null;
222 }
223
224 /** {@inheritDoc} */
225 @Override
226 protected void doSaveDocument(IProgressMonitor monitor, Object element,
227 IDocument document, boolean overwrite) throws CoreException {
228 if (element instanceof AbstractBulkEditorInput) {
229
230 IEntityPersistenceService persistenceService = (AbstractBulkEditorInput) element;
231
232 // Get new containers from annotation model
233 LineAnnotationModel model = (LineAnnotationModel) getAnnotationModel(element);
234 Iterator iterator = model.getAnnotationIterator();
235 while (iterator.hasNext()) {
236 Annotation annotation = (Annotation) iterator.next();
237 if (annotation instanceof IEntityContainer<?>) {
238 IEntityContainer<?> container = (IEntityContainer<?>) annotation;
239 if (container.isMarkedAsNew() || container.isDirty()) {
240 persistenceService.save(container.getEntity()); // save
241 container.setDirty(false);
242 container.markAsNew(false);
243 }
244 }
245 }
246 for (LineAnnotation annotation : model.getDeletedAnnotations()) {
247 if (annotation.isMarkedAsNew()) {
248 continue;
249 }
250 if (annotation.isMarkedAsMerged()) {
251 persistenceService.merge(annotation.getEntity(), annotation.getMergeTarget()); // merge
252 } else {
253 // TODO clarify w AM whether this needs to be executed on merged objects
254 persistenceService.delete(annotation.getEntity()); // delete
255 }
256 }
257 model.clearDeletedAnnotations();
258 }
259 }
260
261 /** {@inheritDoc} */
262 @Override
263 protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
264 return null;
265 }
266
267 /** {@inheritDoc} */
268 @Override
269 public boolean isModifiable(Object element) {
270 return true;
271 }
272
273 /** {@inheritDoc} */
274 @Override
275 public boolean isReadOnly(Object element) {
276 // enables copy & paste
277 return false;
278 }
279
280 /**
281 * <p>Getter for the field <code>entityCreator</code>.</p>
282 *
283 * @param element a {@link java.lang.Object} object.
284 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityCreator} object.
285 */
286 public IEntityCreator<?> getEntityCreator(IEditorInput input) {
287 if (input instanceof AbstractBulkEditorInput) {
288 entityCreator = ((AbstractBulkEditorInput) input).getEntityCreator();
289 }
290 return entityCreator;
291 }
292
293 /**
294 * <p>Setter for the field <code>lineDisplayStrategy</code>.</p>
295 *
296 * @param lineDisplayStrategy a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
297 * @param element a {@link java.lang.Object} object.
298 */
299 public void setLineDisplayStrategy(
300 ILineDisplayStrategy lineDisplayStrategy, Object element) {
301 if (element instanceof IEditorInput) {
302 this.lineDisplayStrategy = lineDisplayStrategy;
303 }
304 }
305
306 /**
307 * <p>Getter for the field <code>lineDisplayStrategy</code>.</p>
308 *
309 * @param element a {@link java.lang.Object} object.
310 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
311 */
312 protected ILineDisplayStrategy getLineDisplayStrategy(Object element) {
313 if (element instanceof IEditorInput) {
314 Assert.isNotNull(lineDisplayStrategy, "No ILineDisplayStrategy set for this element.");
315 return lineDisplayStrategy;
316 }
317 return null;
318 }
319
320 /**
321 * <p>removeAnnotatedLine</p>
322 *
323 * @param entity a {@link java.lang.Object} object.
324 */
325 public void removeAnnotatedLine(Object entity){
326 LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotation(entity);
327 removeAnnotatedLine(annotation);
328 }
329
330 /**
331 * <p>removeAnnotatedLine</p>
332 *
333 * @param lineno a int.
334 * @param element a {@link java.lang.Object} object.
335 */
336 public void removeAnnotatedLine(Object element, int lineno) {
337 LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotationAtLine(lineno, document);
338 removeAnnotatedLine(annotation);
339 }
340
341 /**
342 * <p>removeAnnotatedLine</p>
343 *
344 * @param annotation a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
345 */
346 public void removeAnnotatedLine(LineAnnotation annotation) {
347 if (annotation != null) {
348 Document document = (Document) getDocument(input);
349 LineAnnotationModel model = (LineAnnotationModel) getAnnotationModel(input);
350
351 Position position = model.getPosition(annotation);
352 int offset = position.getOffset();
353 int length = position.getLength();
354
355 Object entity = annotation.getEntity();
356 annotation.markAsDeleted();
357 model.removeAnnotation(annotation);
358
359 // Immediately followed by a delimiter?
360 int annotationEnd = offset + length;
361 try {
362 if (document.getLength() > annotationEnd + 1 && document.get(annotationEnd, 2).equals(document.getDefaultLineDelimiter())) {
363 length += 2;
364 }
365 } catch (BadLocationException e1) {
366 BulkEditorUtil.error(getClass(), "Problems removing annotated line", e1);
367 }
368
369 try {
370 document.replace(offset, length, "");
371 } catch (BadLocationException e) {
372 BulkEditorUtil.error(getClass(), "Problems removing annotated line", e);
373 }
374 }
375 }
376
377 /* (non-Javadoc)
378 * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#changed(java.lang.Object)
379 */
380 /** {@inheritDoc} */
381 @Override
382 public void changed(Object entity) {
383 LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotation(entity);
384 if(annotation != null){
385 annotation.setDirty(true);
386 updateLineFromAnnotation(annotation);
387 }
388 }
389 }