merge
[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.input.AbstractBulkEditorInput;
29 import eu.etaxonomy.taxeditor.model.MessagingUtils;
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 final 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 MessagingUtils.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 MessagingUtils.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 Object entity = persistenceService.save(container.getEntity()); // save
241 container.setEntity(entity);
242 container.setDirty(false);
243 container.markAsNew(false);
244 }
245 }
246 }
247 for (LineAnnotation annotation : model.getDeletedAnnotations()) {
248 if (annotation.isMarkedAsNew()) {
249 continue;
250 }
251 if (annotation.isMarkedAsMerged()) {
252 persistenceService.merge(annotation.getEntity(), annotation.getMergeTarget()); // merge
253 } else {
254 // TODO clarify w AM whether this needs to be executed on merged objects
255 //persistenceService.delete(annotation.getEntity()); // delete
256 }
257 }
258 model.clearDeletedAnnotations();
259 }
260 }
261
262 /** {@inheritDoc} */
263 @Override
264 protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
265 return null;
266 }
267
268 /** {@inheritDoc} */
269 @Override
270 public boolean isModifiable(Object element) {
271 return true;
272 }
273
274 /** {@inheritDoc} */
275 @Override
276 public boolean isReadOnly(Object element) {
277 // enables copy & paste
278 return false;
279 }
280
281 /**
282 * <p>Getter for the field <code>entityCreator</code>.</p>
283 *
284 * @param element a {@link java.lang.Object} object.
285 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityCreator} object.
286 */
287 public IEntityCreator<?> getEntityCreator(IEditorInput input) {
288 if (input instanceof AbstractBulkEditorInput) {
289 entityCreator = ((AbstractBulkEditorInput) input).getEntityCreator();
290 }
291 return entityCreator;
292 }
293
294 /**
295 * <p>Setter for the field <code>lineDisplayStrategy</code>.</p>
296 *
297 * @param lineDisplayStrategy a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
298 * @param element a {@link java.lang.Object} object.
299 */
300 public void setLineDisplayStrategy(
301 ILineDisplayStrategy lineDisplayStrategy, Object element) {
302 if (element instanceof IEditorInput) {
303 this.lineDisplayStrategy = lineDisplayStrategy;
304 }
305 }
306
307 /**
308 * <p>Getter for the field <code>lineDisplayStrategy</code>.</p>
309 *
310 * @param element a {@link java.lang.Object} object.
311 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
312 */
313 protected ILineDisplayStrategy getLineDisplayStrategy(Object element) {
314 if (element instanceof IEditorInput) {
315 Assert.isNotNull(lineDisplayStrategy, "No ILineDisplayStrategy set for this element.");
316 return lineDisplayStrategy;
317 }
318 return null;
319 }
320
321 /**
322 * <p>removeAnnotatedLine</p>
323 *
324 * @param entity a {@link java.lang.Object} object.
325 */
326 public void removeAnnotatedLine(Object entity){
327 LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotation(entity);
328 removeAnnotatedLine(annotation);
329 }
330
331 /**
332 * <p>removeAnnotatedLine</p>
333 *
334 * @param lineno a int.
335 * @param element a {@link java.lang.Object} object.
336 */
337 public void removeAnnotatedLine(Object element, int lineno) {
338 LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotationAtLine(lineno, document);
339 removeAnnotatedLine(annotation);
340 }
341
342 /**
343 * <p>removeAnnotatedLine</p>
344 *
345 * @param annotation a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
346 */
347 public void removeAnnotatedLine(LineAnnotation annotation) {
348 if (annotation != null) {
349 Document document = (Document) getDocument(input);
350 LineAnnotationModel model = (LineAnnotationModel) getAnnotationModel(input);
351
352 Position position = model.getPosition(annotation);
353 int offset = position.getOffset();
354 int length = position.getLength();
355
356 Object entity = annotation.getEntity();
357 annotation.markAsDeleted();
358 model.removeAnnotation(annotation);
359
360 // Immediately followed by a delimiter?
361 int annotationEnd = offset + length;
362 try {
363 if (document.getLength() > annotationEnd + 1 && document.get(annotationEnd, 2).equals(document.getDefaultLineDelimiter())) {
364 length += 2;
365 }
366 } catch (BadLocationException e1) {
367 MessagingUtils.error(getClass(), "Problems removing annotated line", e1);
368 }
369
370 try {
371 document.replace(offset, length, "");
372 } catch (BadLocationException e) {
373 MessagingUtils.error(getClass(), "Problems removing annotated line", e);
374 }
375 }
376 }
377
378 /* (non-Javadoc)
379 * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#changed(java.lang.Object)
380 */
381 /** {@inheritDoc} */
382 @Override
383 public void changed(Object entity) {
384 LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotation(entity);
385 if(annotation != null){
386 annotation.setDirty(true);
387 updateLineFromAnnotation(annotation);
388 }
389 }
390 }