3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.annotatedlineeditor
;
12 import java
.util
.Iterator
;
13 import java
.util
.List
;
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
;
28 import eu
.etaxonomy
.taxeditor
.bulkeditor
.BulkEditorUtil
;
29 import eu
.etaxonomy
.taxeditor
.bulkeditor
.input
.AbstractBulkEditorInput
;
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>.
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.
50 public class AnnotatedLineDocumentProvider
extends AbstractDocumentProvider
{
52 private IDocument document
;
54 private LineAnnotationModel annotationModel
;
56 private IEntityCreator entityCreator
;
58 private ILineDisplayStrategy lineDisplayStrategy
;
60 private IEditorInput input
;
62 public AnnotatedLineDocumentProvider(IEditorInput input
){
67 public IAnnotationModel
getAnnotationModel(Object element
) {
68 if (element
== input
) {
70 // Create model as necessary
71 if (annotationModel
== null) {
72 annotationModel
= new LineAnnotationModel(getLineDisplayStrategy(element
));
73 annotationModel
.setEntityCreator(getEntityCreator(element
));
75 return annotationModel
;
82 protected IAnnotationModel
createAnnotationModel(Object element
)
83 throws CoreException
{
84 return getAnnotationModel(element
);
88 public IDocument
getDocument(Object element
) {
93 protected IDocument
createDocument(Object element
) throws CoreException
{
95 if (element
instanceof IEditorInput
) {
96 IEditorInput input
= (IEditorInput
) element
;
97 document
= new Document("");
98 // IAnnotationModel model = getAnnotationModel(element);
100 List
<?
> entityList
= getEntityList(element
);
102 if(entityList
!= null){
103 for (Object entity
: entityList
) {
105 createAnnotatedLine(input
, entity
);
106 } catch (BadLocationException e
) {
107 BulkEditorUtil
.error(getClass(), "Problems creating annotated line: ", e
);
118 * Creates an annotated line at the end of the document associated with the element
120 * @throws BadLocationException
122 protected LineAnnotation
createAnnotatedLine(Object element
, Object entity
) throws BadLocationException
{
124 Document document
= (Document
) getDocument(element
);
125 ILineDisplayStrategy lineDisplayStrategy
= getLineDisplayStrategy(element
);
127 LineAnnotation annotation
= new LineAnnotation(entity
, lineDisplayStrategy
);
129 // Is document zero length, or is last char in document line delimiter?
130 int docLength
= document
.getLength();
131 boolean useDelimiter
= false;
133 if (docLength
> 1 && !document
.get(docLength
- 2, 2).equals(document
.getDefaultLineDelimiter())) {
138 document
.replace(docLength
, 0, document
.getDefaultLineDelimiter());
142 if (lineDisplayStrategy
.isEntityCacheEmpty(entity
)) {
143 text
= lineDisplayStrategy
.getEmptyCacheMessage(entity
);
145 text
= lineDisplayStrategy
.getText(entity
);
147 text
+= lineDisplayStrategy
.getSupplementalText(entity
);
148 docLength
= document
.getLength();
149 document
.replace(docLength
, 0, text
);
151 Position position
= new Position(docLength
, text
.length());
153 IAnnotationModel model
= getAnnotationModel(element
);
154 model
.addAnnotation(annotation
, position
);
156 // lineDisplayStrategy.addDisplayListener(entity,
157 // new EntityListenerImpl((LineAnnotation) annotation, element));
163 public void updateLineFromAnnotation(LineAnnotation annotation
) {
165 IAnnotationModel model
= getAnnotationModel(input
);
166 IDocument document
= getDocument(input
);
167 ILineDisplayStrategy lineDisplay
= getLineDisplayStrategy(input
);
169 Object entity
= annotation
.getEntity();
171 if (getLineDisplayStrategy(input
).isEntityCacheEmpty(entity
)) {
172 text
= lineDisplay
.getEmptyCacheMessage(entity
);
174 text
= lineDisplay
.getText(entity
);
176 text
+= lineDisplay
.getSupplementalText(entity
);
179 if (model
.getPosition(annotation
) == null) {
182 int offset
= model
.getPosition(annotation
).getOffset();
183 int line
= document
.getLineOfOffset(offset
);
184 int lineLength
= document
.getLineLength(document
.getLineOfOffset(offset
));
185 if (document
.getLineDelimiter(line
) != null) {
186 lineLength
-= document
.getLineDelimiter(line
).length();
188 document
.replace(offset
, lineLength
, text
);
189 } catch (BadLocationException e
) {
190 BulkEditorUtil
.error(getClass(), "Problem updating annotated line: " ,e
);
194 // class EntityListenerImpl extends EntityListener {
196 // private LineAnnotation lineAnnotation;
197 // private Object element;
199 // EntityListenerImpl(LineAnnotation lineAnnotation, Object element) {
200 // this.lineAnnotation = lineAnnotation;
201 // this.element = element;
204 // * @see eu.etaxonomy.taxeditor.annotatedlineeditor.EntityDisplayListener#updateDisplay()
207 // protected void updateEntity() {
208 // lineAnnotation.setDirty(true);
209 // updateLineFromAnnotation(element, lineAnnotation);
217 private List
<?
> getEntityList(Object element
) {
218 if (element
instanceof AbstractBulkEditorInput
) {
219 return ((AbstractBulkEditorInput
)element
).listEntities();
225 protected void doSaveDocument(IProgressMonitor monitor
, Object element
,
226 IDocument document
, boolean overwrite
) throws CoreException
{
227 if (element
instanceof AbstractBulkEditorInput
) {
229 IEntityPersistenceService persistenceService
= (AbstractBulkEditorInput
) element
;
231 // Get new containers from annotation model
232 LineAnnotationModel model
= (LineAnnotationModel
) getAnnotationModel(element
);
233 Iterator iterator
= model
.getAnnotationIterator();
234 while (iterator
.hasNext()) {
235 Annotation annotation
= (Annotation
) iterator
.next();
236 if (annotation
instanceof IEntityContainer
<?
>) {
237 IEntityContainer
<?
> container
= (IEntityContainer
<?
>) annotation
;
238 if (container
.isMarkedAsNew() || container
.isDirty()) {
239 persistenceService
.save(container
.getEntity()); // save
240 container
.setDirty(false);
241 container
.markAsNew(false);
245 for (LineAnnotation annotation
: model
.getDeletedAnnotations()) {
246 if (annotation
.isMarkedAsNew()) {
249 if (annotation
.isMarkedAsMerged()) {
250 persistenceService
.merge(annotation
.getEntity(), annotation
.getMergeTarget()); // merge
252 // TODO clarify w AM whether this needs to be executed on merged objects
253 persistenceService
.delete(annotation
.getEntity()); // delete
256 model
.clearDeletedAnnotations();
261 protected IRunnableContext
getOperationRunner(IProgressMonitor monitor
) {
266 public boolean isModifiable(Object element
) {
271 public boolean isReadOnly(Object element
) {
272 // enables copy & paste
277 * @param entityCreator
280 public void setEntityCreator(IEntityCreator
<?
> entityCreator
, Object element
) {
281 if (element
instanceof IEditorInput
) {
282 this.entityCreator
= entityCreator
;
290 public IEntityCreator
<?
> getEntityCreator(Object element
) {
291 if (element
instanceof IEditorInput
) {
292 // Assert.isNotNull(entityCreator, "No IEntityCreator set for this element.");
293 return entityCreator
;
299 * @param lineDisplayStrategy
302 public void setLineDisplayStrategy(
303 ILineDisplayStrategy lineDisplayStrategy
, Object element
) {
304 if (element
instanceof IEditorInput
) {
305 this.lineDisplayStrategy
= lineDisplayStrategy
;
313 protected ILineDisplayStrategy
getLineDisplayStrategy(Object element
) {
314 if (element
instanceof IEditorInput
) {
315 Assert
.isNotNull(lineDisplayStrategy
, "No ILineDisplayStrategy set for this element.");
316 return lineDisplayStrategy
;
321 public void removeAnnotatedLine(Object entity
){
322 LineAnnotation annotation
= (LineAnnotation
) annotationModel
.getAnnotation(entity
);
323 removeAnnotatedLine(annotation
);
330 public void removeAnnotatedLine(Object element
, int lineno
) {
331 LineAnnotation annotation
= (LineAnnotation
) annotationModel
.getAnnotationAtLine(lineno
, document
);
332 removeAnnotatedLine(annotation
);
335 public void removeAnnotatedLine(LineAnnotation annotation
) {
336 if (annotation
!= null) {
337 Document document
= (Document
) getDocument(input
);
338 LineAnnotationModel model
= (LineAnnotationModel
) getAnnotationModel(input
);
340 Position position
= model
.getPosition(annotation
);
341 int offset
= position
.getOffset();
342 int length
= position
.getLength();
344 Object entity
= annotation
.getEntity();
345 annotation
.markAsDeleted();
346 model
.removeAnnotation(annotation
);
348 // Immediately followed by a delimiter?
349 int annotationEnd
= offset
+ length
;
351 if (document
.getLength() > annotationEnd
+ 1 && document
.get(annotationEnd
, 2).equals(document
.getDefaultLineDelimiter())) {
354 } catch (BadLocationException e1
) {
355 BulkEditorUtil
.error(getClass(), "Problems removing annotated line", e1
);
359 document
.replace(offset
, length
, "");
360 } catch (BadLocationException e
) {
361 BulkEditorUtil
.error(getClass(), "Problems removing annotated line", e
);
367 * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#changed(java.lang.Object)
370 public void changed(Object entity
) {
371 LineAnnotation annotation
= (LineAnnotation
) annotationModel
.getAnnotation(entity
);
372 if(annotation
!= null){
373 annotation
.setDirty(true);
374 updateLineFromAnnotation(annotation
);