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