Project

General

Profile

Download (11.8 KB) Statistics
| Branch: | Tag: | Revision:
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.dataimport.SpecimenEditorInput;
30
import eu.etaxonomy.taxeditor.model.AbstractUtility;
31

    
32

    
33

    
34
/**
35
 * Using an <code>IEditorPart</code>, creates a document where each line is associated
36
 * with an entity. Mapping between document positions and entities is stored in
37
 * <code>LineAnnotation</code>s in a <code>LineAnnotationModel</code>.
38
 * <p>
39
 * Requires:
40
 * <ul>
41
 * <li>an <code>IEntityCreator</code> to create entities for new lines;
42
 * <li>an <code>IEntityPersistenceService</code> for interacting with the persistence layer; and
43
 * <li>an <code>ILineDisplayStrategy</code> for various visual manifestations of the domain object.
44
 * </ul>
45
 *
46
 * @author p.ciardelli
47
 * @author n.hoffmann
48
 * @created 25.06.2009
49
 * @version 1.0
50
 */
51
public class AnnotatedLineDocumentProvider extends AbstractDocumentProvider {
52

    
53
	private IDocument document;
54

    
55
	private LineAnnotationModel annotationModel;
56

    
57
	private IEntityCreator<?> entityCreator;
58

    
59
	private ILineDisplayStrategy lineDisplayStrategy;
60

    
61
	private IEditorInput input;
62

    
63
	/**
64
	 * <p>Constructor for AnnotatedLineDocumentProvider.</p>
65
	 *
66
	 * @param input a {@link org.eclipse.ui.IEditorInput} object.
67
	 */
68
	public AnnotatedLineDocumentProvider(IEditorInput input){
69
		this.input = input;
70
	}
71

    
72
	/** {@inheritDoc} */
73
	@Override
74
	public IAnnotationModel getAnnotationModel(Object element) {
75
		if (element == input) {
76

    
77
			// Create model as necessary
78
			if (annotationModel == null) {
79
				annotationModel = new LineAnnotationModel(getLineDisplayStrategy(element));
80
				annotationModel.setEntityCreator(getEntityCreator(input));
81
			}
82
			return annotationModel;
83
		}
84

    
85
		return null;
86
	}
87

    
88
	/** {@inheritDoc} */
89
	@Override
90
	protected IAnnotationModel createAnnotationModel(Object element)
91
			throws CoreException {
92
		return getAnnotationModel(element);
93
	}
94

    
95
	/** {@inheritDoc} */
96
	@Override
97
	public IDocument getDocument(Object element) {
98
		return document;
99
	}
100

    
101
	/** {@inheritDoc} */
102
	@Override
103
	protected IDocument createDocument(Object element) throws CoreException {
104

    
105
		if (element instanceof IEditorInput) {
106
			IEditorInput input = (IEditorInput) element;
107
			document = new Document("");
108
//			IAnnotationModel model = getAnnotationModel(element);
109

    
110
			List<?> entityList = getEntityList(element);
111

    
112
			if(entityList != null){
113
				for (Object entity : entityList) {
114
					try {
115
						createAnnotatedLine(input, entity);
116
					} catch (BadLocationException e) {
117
						AbstractUtility.error(getClass(), "Problems creating annotated line: ", e);
118
					}
119
				}
120
			}
121

    
122
			return document;
123
		}
124
		return null;
125
	}
126

    
127
	/**
128
	 * Creates an annotated line at the end of the document associated with the element
129
	 *
130
	 * @throws org.eclipse.jface.text.BadLocationException if any.
131
	 * @param element a {@link java.lang.Object} object.
132
	 * @param entity a {@link java.lang.Object} object.
133
	 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
134
	 */
135
	protected LineAnnotation createAnnotatedLine(Object element, Object entity) throws BadLocationException {
136

    
137
		Document document = (Document) getDocument(element);
138
		ILineDisplayStrategy lineDisplayStrategy = getLineDisplayStrategy(element);
139

    
140
		LineAnnotation annotation = new LineAnnotation(entity, lineDisplayStrategy);
141

    
142
		// Is document zero length, or is last char in document line delimiter?
143
		int docLength = document.getLength();
144
		boolean useDelimiter = false;
145
		if (docLength > 0) {
146
			if (docLength > 1 && !document.get(docLength - 2, 2).equals(document.getDefaultLineDelimiter())) {
147
				useDelimiter = true;
148
			}
149
		}
150
		if (useDelimiter) {
151
			document.replace(docLength, 0, document.getDefaultLineDelimiter());
152
		}
153

    
154
		String text;
155
		if (lineDisplayStrategy.isEntityCacheEmpty(entity)) {
156
			text = lineDisplayStrategy.getEmptyCacheMessage(entity);
157
		} else {
158
			text = lineDisplayStrategy.getText(entity);
159
		}
160
		text += lineDisplayStrategy.getSupplementalText(entity);
161
		docLength = document.getLength();
162
		document.replace(docLength, 0, text);
163

    
164
		Position position = new Position(docLength, text.length());
165

    
166
		IAnnotationModel model = getAnnotationModel(element);
167
		if(model != null){
168
			model.addAnnotation(annotation, position);
169
		}
170

    
171
//		lineDisplayStrategy.addDisplayListener(entity,
172
//						new EntityListenerImpl((LineAnnotation) annotation, element));
173
//
174
		return annotation;
175
	}
176

    
177

    
178
	/**
179
	 * <p>updateLineFromAnnotation</p>
180
	 *
181
	 * @param annotation a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
182
	 */
183
	public void updateLineFromAnnotation(LineAnnotation annotation) {
184

    
185
		IAnnotationModel model = getAnnotationModel(input);
186
		IDocument document = getDocument(input);
187
		ILineDisplayStrategy lineDisplay = getLineDisplayStrategy(input);
188

    
189
		Object entity = annotation.getEntity();
190
		String text = "";
191
		if (getLineDisplayStrategy(input).isEntityCacheEmpty(entity)) {
192
			text = lineDisplay.getEmptyCacheMessage(entity);
193
		} else {
194
			text = lineDisplay.getText(entity);
195
		}
196
		text += lineDisplay.getSupplementalText(entity);
197

    
198
		try {
199
			if (model.getPosition(annotation) == null) {
200
				return;
201
			}
202
			int offset = model.getPosition(annotation).getOffset();
203
			int line = document.getLineOfOffset(offset);
204
			int lineLength = document.getLineLength(document.getLineOfOffset(offset));
205
			if (document.getLineDelimiter(line) != null) {
206
				lineLength -= document.getLineDelimiter(line).length();
207
			}
208
			document.replace(offset, lineLength, text);
209
		} catch (BadLocationException e) {
210
			AbstractUtility.error(getClass(), "Problem updating annotated line: " ,e);
211
		}
212
	}
213

    
214
	/**
215
	 * @param element
216
	 * @return
217
	 */
218
	private List<?> getEntityList(Object element) {
219
		if (element instanceof AbstractBulkEditorInput) {
220
			return ((AbstractBulkEditorInput)element).getModel();
221
		}
222
		else if(element instanceof SpecimenEditorInput){
223
		    return ((SpecimenEditorInput) element).getResults();
224
		}
225
		return null;
226
	}
227

    
228
	/** {@inheritDoc} */
229
	@Override
230
	protected void doSaveDocument(IProgressMonitor monitor, Object element,
231
			IDocument document, boolean overwrite) throws CoreException {
232
		if (element instanceof AbstractBulkEditorInput) {
233

    
234
			IEntityPersistenceService persistenceService = (AbstractBulkEditorInput) element;
235

    
236
			// Get new containers from annotation model
237
			LineAnnotationModel model = (LineAnnotationModel) getAnnotationModel(element);
238
			Iterator iterator = model.getAnnotationIterator();
239
			while (iterator.hasNext()) {
240
				Annotation annotation = (Annotation) iterator.next();
241
				if (annotation instanceof IEntityContainer<?>) {
242
					IEntityContainer<?> container = (IEntityContainer<?>) annotation;
243
					if (container.isMarkedAsNew() || container.isDirty()) {
244
						persistenceService.save(container.getEntity()); // save
245
						container.setDirty(false);
246
						container.markAsNew(false);
247
					}
248
				}
249
			}
250
			for (LineAnnotation annotation : model.getDeletedAnnotations()) {
251
				if (annotation.isMarkedAsNew()) {
252
					continue;
253
				}
254
				if (annotation.isMarkedAsMerged()) {
255
					persistenceService.merge(annotation.getEntity(), annotation.getMergeTarget()); //  merge
256
				} else {
257
					// TODO clarify w AM whether this needs to be executed on merged objects
258
					//persistenceService.delete(annotation.getEntity()); // delete
259
				}
260
			}
261
			model.clearDeletedAnnotations();
262
		}
263
	}
264

    
265
	/** {@inheritDoc} */
266
	@Override
267
	protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
268
		return null;
269
	}
270

    
271
	/** {@inheritDoc} */
272
	@Override
273
	public boolean isModifiable(Object element) {
274
		return true;
275
	}
276

    
277
	/** {@inheritDoc} */
278
	@Override
279
	public boolean isReadOnly(Object element) {
280
		// enables copy & paste
281
		return false;
282
	}
283

    
284
	/**
285
	 * <p>Getter for the field <code>entityCreator</code>.</p>
286
	 *
287
	 * @param element a {@link java.lang.Object} object.
288
	 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityCreator} object.
289
	 */
290
	public IEntityCreator<?> getEntityCreator(IEditorInput input) {
291
		if (input instanceof AbstractBulkEditorInput) {
292
			entityCreator = ((AbstractBulkEditorInput) input).getEntityCreator();
293
		}
294
		return entityCreator;
295
	}
296

    
297
	/**
298
	 * <p>Setter for the field <code>lineDisplayStrategy</code>.</p>
299
	 *
300
	 * @param lineDisplayStrategy a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
301
	 * @param element a {@link java.lang.Object} object.
302
	 */
303
	public void setLineDisplayStrategy(
304
			ILineDisplayStrategy lineDisplayStrategy, Object element) {
305
		if (element instanceof IEditorInput) {
306
			this.lineDisplayStrategy = lineDisplayStrategy;
307
		}
308
	}
309

    
310
	/**
311
	 * <p>Getter for the field <code>lineDisplayStrategy</code>.</p>
312
	 *
313
	 * @param element a {@link java.lang.Object} object.
314
	 * @return a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
315
	 */
316
	protected ILineDisplayStrategy getLineDisplayStrategy(Object element) {
317
		if (element instanceof IEditorInput) {
318
			Assert.isNotNull(lineDisplayStrategy, "No ILineDisplayStrategy set for this element.");
319
			return lineDisplayStrategy;
320
		}
321
		return null;
322
	}
323

    
324
	/**
325
	 * <p>removeAnnotatedLine</p>
326
	 *
327
	 * @param entity a {@link java.lang.Object} object.
328
	 */
329
	public void removeAnnotatedLine(Object entity){
330
		LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotation(entity);
331
		removeAnnotatedLine(annotation);
332
	}
333

    
334
	/**
335
	 * <p>removeAnnotatedLine</p>
336
	 *
337
	 * @param lineno a int.
338
	 * @param element a {@link java.lang.Object} object.
339
	 */
340
	public void removeAnnotatedLine(Object element, int lineno) {
341
		LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotationAtLine(lineno, document);
342
		removeAnnotatedLine(annotation);
343
	}
344

    
345
	/**
346
	 * <p>removeAnnotatedLine</p>
347
	 *
348
	 * @param annotation a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation} object.
349
	 */
350
	public void removeAnnotatedLine(LineAnnotation annotation) {
351
		if (annotation != null) {
352
			Document document = (Document) getDocument(input);
353
			LineAnnotationModel model = (LineAnnotationModel) getAnnotationModel(input);
354

    
355
			Position position = model.getPosition(annotation);
356
			int offset = position.getOffset();
357
			int length = position.getLength();
358

    
359
			Object entity = annotation.getEntity();
360
			annotation.markAsDeleted();
361
			model.removeAnnotation(annotation);
362

    
363
			// Immediately followed by a delimiter?
364
			int annotationEnd = offset + length;
365
			try {
366
				if (document.getLength() > annotationEnd + 1 && document.get(annotationEnd, 2).equals(document.getDefaultLineDelimiter())) {
367
					length += 2;
368
				}
369
			} catch (BadLocationException e1) {
370
				AbstractUtility.error(getClass(), "Problems removing annotated line", e1);
371
			}
372

    
373
			try {
374
				document.replace(offset, length, "");
375
			} catch (BadLocationException e) {
376
				AbstractUtility.error(getClass(), "Problems removing annotated line", e);
377
			}
378
		}
379
	}
380

    
381
	/* (non-Javadoc)
382
	 * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#changed(java.lang.Object)
383
	 */
384
	/** {@inheritDoc} */
385
	@Override
386
	public void changed(Object entity) {
387
		LineAnnotation annotation = (LineAnnotation) annotationModel.getAnnotation(entity);
388
		if(annotation != null){
389
			annotation.setDirty(true);
390
			updateLineFromAnnotation(annotation);
391
		}
392
	}
393
}
(1-1/16)