Merge branch 'release/4.5.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.bulkeditor / src / main / java / eu / etaxonomy / taxeditor / annotatedlineeditor / LineAnnotationModel.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.annotatedlineeditor;
11
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.Comparator;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Set;
19
20 import org.apache.log4j.Logger;
21 import org.eclipse.jface.text.BadLocationException;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.Position;
24 import org.eclipse.jface.text.source.Annotation;
25 import org.eclipse.jface.text.source.AnnotationModel;
26 import org.eclipse.jface.text.source.AnnotationModelEvent;
27
28 import eu.etaxonomy.taxeditor.model.MessagingUtils;
29
30 /**
31 * An <code>AnnotationModel</code> which holds <code>LineAnnotation</code>'s.
32 * <p>
33 * Major difference with <code>AnnotationModel</code> is that <code>removeAnnotation(Annotation annotation,
34 * boolean fireModelChanged)</code> adds annotations marked for removal to a collection for further
35 * processing, i.e. when the document is saved. This collection is accessed via <code>getDeletedAnnotations()</code>
36 * and <code>clearDeletedAnnotations()</code>.
37 *
38 * @author p.ciardelli
39 * @created 25.06.2009
40 * @version 1.0
41 */
42 public class LineAnnotationModel extends AnnotationModel {
43
44 private Comparator<Annotation> comparator;
45 private IEntityCreator<?> entityCreator;
46 private Set<LineAnnotation> deletedAnnotations = new HashSet<LineAnnotation>();
47
48 private ILineDisplayStrategy lineDisplayStrategy;
49
50 /**
51 * <p>Constructor for LineAnnotationModel.</p>
52 *
53 * @param lineDisplayStrategy a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.ILineDisplayStrategy} object.
54 */
55 public LineAnnotationModel(ILineDisplayStrategy lineDisplayStrategy) {
56 super();
57 this.lineDisplayStrategy = lineDisplayStrategy;
58 }
59
60 /**
61 * Changes the annotation's type and fires model changed
62 * notification. Resulting redraw will cause any change
63 * in annotation's decoration to be displayed.
64 *
65 * @param annotation a {@link org.eclipse.jface.text.source.Annotation} object.
66 * @param type a {@link java.lang.String} object.
67 */
68 public void changeAnnotationType(Annotation annotation, String type) {
69 annotation.setType(type);
70 fireModelChanged(new AnnotationModelEvent(this));
71 }
72
73 /* (non-Javadoc)
74 * @see org.eclipse.jface.text.source.AnnotationModel#removeAnnotation(org.eclipse.jface.text.source.Annotation, boolean)
75 */
76 /** {@inheritDoc} */
77 protected void removeAnnotation(Annotation annotation,
78 boolean fireModelChanged) {
79 // Set data model element for deletion
80 annotation.markDeleted(true);
81 if (annotation instanceof LineAnnotation) {
82 deletedAnnotations.add((LineAnnotation) annotation);
83 }
84 super.removeAnnotation(annotation, fireModelChanged);
85 }
86
87 /**
88 * <p>removeTypeFromAllAnnotations</p>
89 *
90 * @param type a {@link java.lang.String} object.
91 */
92 public void removeTypeFromAllAnnotations(String type) {
93 Iterator<?> iterator = getAnnotationIterator();
94 while (iterator.hasNext()) {
95 Annotation annotation = ((Annotation) iterator.next());
96 if (annotation.getType().equals(type)) {
97 annotation.setType(Annotation.TYPE_UNKNOWN);
98 }
99 }
100 }
101
102 /**
103 * <p>getAllAnnotationsOfType</p>
104 *
105 * @param type a {@link java.lang.String} object.
106 * @return a {@link java.util.Set} object.
107 */
108 public Set<LineAnnotation> getAllAnnotationsOfType(String type) {
109 Set<LineAnnotation> candidates = new HashSet<LineAnnotation>();
110 Iterator<?> iterator = getAnnotationIterator();
111 while (iterator.hasNext()) {
112 LineAnnotation annotation = ((LineAnnotation) iterator.next());
113 if (annotation.getType().equals(type)) {
114 candidates.add(annotation);
115 }
116 }
117 return candidates;
118 }
119
120 /**
121 * <p>getFirstAnnotationOfType</p>
122 *
123 * @param type a {@link java.lang.String} object.
124 * @return a {@link org.eclipse.jface.text.source.Annotation} object.
125 */
126 public Annotation getFirstAnnotationOfType(String type) {
127 Iterator<?> iterator = getAnnotationIterator();
128 while (iterator.hasNext()) {
129 Annotation annotation = ((Annotation) iterator.next());
130 if (annotation.getType().equals(type)) {
131 return annotation;
132 }
133 }
134 return null;
135 }
136
137 /**
138 * Gets first LineAnnotation in line
139 *
140 * @param line a int.
141 * @param document a {@link org.eclipse.jface.text.IDocument} object.
142 * @return a {@link org.eclipse.jface.text.source.Annotation} object.
143 */
144 public Annotation getAnnotationAtLine(int line, IDocument document) {
145 // Annotation annotation = null;
146 try {
147 int offset = document.getLineOffset(line);
148 int length = document.getLineLength(line);
149
150 Iterator<?> iterator = getAnnotationIterator(offset, length, true, true);
151 while (iterator.hasNext()) {
152 Object next = iterator.next();
153 if (next instanceof LineAnnotation) {
154 return (LineAnnotation) next;
155 }
156 // annotation = (Annotation) iterator.next();
157 }
158 } catch (BadLocationException e) {
159 // do nothing
160 }
161 return null;
162 }
163
164 /**
165 * <p>getOrderedAnnotations</p>
166 *
167 * @return a {@link java.util.List} object.
168 */
169 public List<Annotation> getOrderedAnnotations() {
170 List<Annotation> list = new ArrayList<Annotation>();
171 Iterator<?> iterator = getAnnotationIterator();
172 while (iterator.hasNext()) {
173 list.add((Annotation) iterator.next());
174 }
175 Collections.sort(list, getAnnotationComparator());
176 return list;
177 }
178
179 /**
180 * <p>printAnnotations</p>
181 */
182 public void printAnnotations() {
183 Logger logger = MessagingUtils.getLog4JLogger(getClass());
184 logger.debug("------------------------");
185 logger.debug("Active annotations");
186 logger.debug("------------------------");
187 List<Annotation> list = getOrderedAnnotations();
188
189 for (Annotation annotation : list) {
190 logger.debug(
191 (annotation.isMarkedDeleted() ? "DELETED " : "") +
192 (((LineAnnotation) annotation).isMarkedAsMerged() ? "MERGED " : "") +
193 (((LineAnnotation) annotation).isDirty() ? "DIRTY " : "") +
194 (((LineAnnotation) annotation).isMarkedAsNew() ? "NEW " : "") +
195 annotation.getText() + ": o " +
196 getPosition(annotation).getOffset() + ", l " +
197 getPosition(annotation).getLength());
198 }
199 logger.debug("------------------------");
200 logger.debug("Deleted annotations");
201 logger.debug("------------------------");
202 for (LineAnnotation annotation : deletedAnnotations) {
203 logger.debug(
204 (annotation.isMarkedDeleted() ? "DELETED " : "") +
205 (((LineAnnotation) annotation).isMarkedAsMerged() ? "MERGED " : "") +
206 (((LineAnnotation) annotation).isDirty() ? "DIRTY " : "") +
207 (((LineAnnotation) annotation).isMarkedAsNew() ? "NEW " : "") +
208 annotation.getText() + ": o ");
209 }
210 }
211
212 /**
213 * <p>getUndeletedAnnotations</p>
214 *
215 * @param offset a int.
216 * @param length a int.
217 * @return a {@link java.util.List} object.
218 */
219 public List<LineAnnotation> getUndeletedAnnotations(int offset, int length) {
220
221 List<LineAnnotation> list = new ArrayList<LineAnnotation>();
222
223 Iterator<?> iterator = getAnnotationIterator(offset, length, true, true);
224 while (iterator.hasNext()) {
225 Object next = iterator.next();
226 if (next instanceof LineAnnotation && !((Annotation) next).isMarkedDeleted()) {
227 list.add((LineAnnotation) next);
228 }
229 }
230 Collections.sort(list, getAnnotationComparator());
231 return list;
232 }
233
234 /**
235 * <p>Getter for the field <code>deletedAnnotations</code>.</p>
236 *
237 * @return a {@link java.util.Set} object.
238 */
239 public Set<LineAnnotation> getDeletedAnnotations() {
240 return deletedAnnotations;
241 }
242
243 /**
244 * <p>clearDeletedAnnotations</p>
245 */
246 public void clearDeletedAnnotations() {
247 deletedAnnotations.clear();
248 }
249
250 private Comparator<Annotation> getAnnotationComparator() {
251 if (comparator == null) {
252 this.comparator = new AnnotationComparator();
253 }
254 return comparator;
255 }
256
257 class AnnotationComparator implements Comparator<Annotation> {
258
259 /* (non-Javadoc)
260 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
261 */
262 public int compare(Annotation annotation1, Annotation annotation2) {
263 if (annotation1.isMarkedDeleted() && !annotation2.isMarkedDeleted()) {
264 return 1;
265 }
266 if (!annotation1.isMarkedDeleted() && annotation2.isMarkedDeleted()) {
267 return -1;
268 }
269 int offset1 = LineAnnotationModel.this.
270 getPosition(annotation1).getOffset();
271 int offset2 = LineAnnotationModel.this.
272 getPosition(annotation2).getOffset();
273 if (offset1 > offset2) {
274 return 1;
275 } else if (offset1 < offset2) {
276 return -1;
277 } else {
278 return 0;
279 }
280 }
281 }
282
283 /**
284 * The annotation model is assigned responsibility for creating new containers
285 * from blocks of text.
286 *
287 * @param entityCreator a {@link eu.etaxonomy.taxeditor.annotatedlineeditor.IEntityCreator} object.
288 */
289 public void setEntityCreator(IEntityCreator<?> entityCreator) {
290 this.entityCreator = entityCreator;
291 }
292
293 /**
294 * Creates an annotation without adding it to the model.
295 *
296 * This object must have its <code>cdmEntityCreator</code> set.
297 *
298 * @param text a {@link java.lang.String} object.
299 * @return a {@link org.eclipse.jface.text.source.Annotation} object.
300 */
301 public Annotation createAnnotation(String text) {
302 LineAnnotation annotation = null;
303 if (entityCreator != null) {
304 annotation = new LineAnnotation(entityCreator.createEntity(text), lineDisplayStrategy);
305 annotation.markAsNew(true);
306 }
307 return annotation;
308 }
309
310 /**
311 * Creates an annotation without adding it to the model.
312 *
313 * @param entity a {@link java.lang.Object} object.
314 * @return a {@link org.eclipse.jface.text.source.Annotation} object.
315 */
316 public Annotation createAnnotation(Object entity) {
317 LineAnnotation annotation = new LineAnnotation(entity, lineDisplayStrategy);
318 annotation.markAsNew(true);
319 return annotation;
320 }
321
322 /* (non-Javadoc)
323 * @see org.eclipse.jface.text.source.AnnotationModel#addAnnotation(org.eclipse.jface.text.source.Annotation, org.eclipse.jface.text.Position)
324 */
325 /** {@inheritDoc} */
326 @Override
327 public void addAnnotation(Annotation annotation, Position position) {
328 super.addAnnotation(annotation, position);
329 }
330
331 /**
332 * <p>getAnnotation</p>
333 *
334 * @param entity a {@link java.lang.Object} object.
335 * @return a {@link org.eclipse.jface.text.source.Annotation} object.
336 */
337 public Annotation getAnnotation(Object entity) {
338 if (entity != null) {
339 Iterator iterator = getAnnotationIterator();
340 while (iterator.hasNext()) {
341 LineAnnotation annotation = (LineAnnotation) iterator.next();
342 if (entity.equals(annotation.getEntity())) {
343 return annotation;
344 }
345 }
346 }
347 return null;
348 }
349 }