Refactored description editor per #577
[taxeditor.git] / eclipseprojects / eu.etaxonomy.taxeditor / src / eu / etaxonomy / taxeditor / editor / description / DescriptionElementComposite.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.editor.description;
11
12 import org.apache.log4j.Logger;
13 import org.eclipse.core.commands.operations.IUndoContext;
14 import org.eclipse.core.commands.operations.IUndoableOperation;
15 import org.eclipse.core.runtime.Assert;
16 import org.eclipse.jface.action.Action;
17 import org.eclipse.jface.resource.ImageDescriptor;
18 import org.eclipse.jface.text.Document;
19 import org.eclipse.jface.text.source.SourceViewer;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.FocusAdapter;
22 import org.eclipse.swt.events.FocusEvent;
23 import org.eclipse.swt.graphics.Font;
24 import org.eclipse.swt.graphics.Image;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.ui.forms.IManagedForm;
27 import org.eclipse.ui.forms.widgets.TableWrapData;
28 import org.eclipse.ui.views.properties.IPropertySource;
29
30 import eu.etaxonomy.cdm.model.common.Language;
31 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
32 import eu.etaxonomy.cdm.model.description.TextData;
33 import eu.etaxonomy.taxeditor.ITaxEditorConstants;
34 import eu.etaxonomy.taxeditor.TaxEditorPlugin;
35 import eu.etaxonomy.taxeditor.controller.EditorController;
36 import eu.etaxonomy.taxeditor.controller.GlobalController;
37 import eu.etaxonomy.taxeditor.editor.ContextMenu;
38 import eu.etaxonomy.taxeditor.editor.GroupedComposite;
39 import eu.etaxonomy.taxeditor.editor.LineWrapSupport;
40 import eu.etaxonomy.taxeditor.editor.ParseListener;
41 import eu.etaxonomy.taxeditor.operations.description.RemoveElementOperation;
42 import eu.etaxonomy.taxeditor.propertysheet.description.DescriptionElementPropertySource;
43
44 /**
45 * @author p.ciardelli
46 * @created 02.06.2008
47 * @version 1.0
48 */
49 public class DescriptionElementComposite extends GroupedComposite {
50 private static final Logger logger = Logger.getLogger(DescriptionElementComposite.class);
51
52 /**
53 * ************ COMPOSITE TYPES ************
54 */
55 public static final String TEXT_DATA = "text_data";
56 public static final String COMMON_TAXON_NAME = "common_taxon_name";
57 public static final String DISTRIBUTION = "distribution";
58
59 /**
60 * ************ INDENTATIONS ************
61 */
62 // public static final int ACCEPTED_INDENT = 0;
63
64 /**
65 * ************ FONTS ************
66 */
67 public static final Font ELEMENT_FONT = TaxEditorPlugin.getDefault()
68 .getFont(ITaxEditorConstants.SYNONYM_FONT);
69
70 /**
71 * ************ ICONS ************
72 */
73 public static final Image BLACK_SQUARE_ICON = TaxEditorPlugin.getDefault()
74 .getImage(ITaxEditorConstants.BLACK_SQUARE_ICON);
75
76 /**
77 * ************ TRANSFORMATIONS ************
78 */
79 // public static final String ADD_GROUP_BASIONYM = "add_group_basionym";
80
81 /**
82 * ************ MENU ACTIONS ************
83 */
84 public Action CHANGE_TAXON_TO_SYNONYM_ACTION;
85
86 private DescriptionElementBase element;
87
88 private IUndoContext undoContext;
89
90 private static final String EMPTY_NAME_PROMPT = "Click to add descriptive element text";
91
92 /**
93 * The constructor for a <code>DescriptionElementComposite</code>. Takes a parent
94 * <code>Composite</code> on which to create itself, and an <code>IManagedForm</code> for
95 * <code>Composite</code> life cycle methods, i.e. drawing borders, creating other
96 * <code>Composite</code>s, creating line wrap support, etc.
97 *
98 * @param parent
99 * @param managedForm
100 */
101 public DescriptionElementComposite(Composite parent, IManagedForm managedForm,
102 DescriptionElementBase element) {
103 super(parent, managedForm);
104
105 this.element = element;
106
107 this.undoContext = EditorController.getUndoContext(taxon);
108
109 createTextViewer();
110 createBorderSupport();
111 createLineWrapSupport();
112
113 setData(element);
114 transform(null);
115
116 createEmptyViewerPrompt(EMPTY_NAME_PROMPT);
117 setFocus();
118 }
119
120 public DescriptionElementBase getElement() {
121 return element;
122 }
123
124 protected void createLineWrapSupport() {
125 new LineWrapSupport(getTextViewer(), managedForm);
126 }
127
128 /**
129 * All cosmetic - non-data-related, i.e. icons, fonts, etc. -
130 * transformations take place in this method.
131 *
132 * @param transformation
133 */
134 public void transform(String transformation) {
135 setIsDraggable(true);
136 setFont(ELEMENT_FONT);
137 setIcon(BLACK_SQUARE_ICON);
138
139 createMenu();
140
141 managedForm.getForm().getBody().layout();
142 }
143
144 /**
145 * Override of Composite.setData() which passes data along to
146 * DescriptionElementComposite's TextViewer where appropriate.
147 *
148 * @see org.eclipse.swt.widgets.Widget#setData(java.lang.Object)
149 */
150 public void setData(Object data) {
151 super.setData(data);
152
153 Assert.isTrue((data instanceof DescriptionElementBase),
154 "DescriptionElementComposite's data field must contain a DescriptionElementBase object");
155
156 DescriptionElementBase element = (DescriptionElementBase) data;
157
158 String text = null;
159 if (element instanceof TextData) {
160 text = ((TextData) element).getText(Language.DEFAULT());
161 }
162 if (text == null) {
163 text = "";
164 }
165
166 getTextViewer().getTextWidget().setText(text);
167 }
168
169 private void createTextViewer() {
170 this.textViewer = new SourceViewer(this, null, SWT.WRAP | SWT.MULTI | SWT.RESIZE);
171 this.textViewer.setDocument(new Document(""));
172 this.textViewer.getTextWidget().setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB));
173 this.textViewer.getTextWidget().addModifyListener(new ParseListener() {
174
175 @Override
176 public void parse(String text) {
177 Assert.isTrue((getData() instanceof DescriptionElementBase),
178 "DescriptionElementComposite's data field must contain a DescriptionElementBase object");
179
180 DescriptionElementBase element = (DescriptionElementBase) getData();
181
182 if (element instanceof TextData) {
183 ((TextData) element).putText(text, Language.DEFAULT());
184 }
185
186 setDirty(true);
187 }
188 });
189 this.textViewer.getTextWidget().addFocusListener(new FocusAdapter() {
190 public void focusGained(FocusEvent e) {
191 setFocus();
192 }
193 });
194 }
195
196 private void createMenu() {
197 ContextMenu contextMenu = new ContextMenu(getDraggableLabel());
198
199 // Delete this description element
200 String text = "Delete description element";
201 ImageDescriptor image = TaxEditorPlugin.getDefault()
202 .getImageDescriptor(ITaxEditorConstants.ACTIVE_DELETE_ICON);
203 contextMenu.addAction(new Action(text, image){
204
205 public void run() {
206 IUndoableOperation operation = new RemoveElementOperation
207 (this.getText(), undoContext, taxon, element);
208
209 GlobalController.executeOperation(operation);
210 }
211 });
212 }
213
214 @Override
215 public void dispose() {
216
217 Composite featureComponent = this.getParent();
218
219 super.dispose();
220
221 // If feature only has 1 child that is not DescriptionElementComposite,
222 // composite is empty
223 if (!(featureComponent instanceof DescriptionFeatureGroupComposite)) {
224 return;
225 }
226
227 if (featureComponent.getChildren().length == 1 &&
228 !(featureComponent.getChildren()[0] instanceof
229 DescriptionElementComposite)) {
230 Composite grandParent = featureComponent.getParent();
231 featureComponent.dispose();
232 grandParent.layout();
233 }
234
235 managedForm.getForm().getBody().layout();
236 }
237
238 @Override
239 public IPropertySource getPropertySource() {
240 return new DescriptionElementPropertySource((DescriptionElementBase) getData());
241 }
242
243 @Override
244 protected Font getViewerFont() {
245 // TODO Auto-generated method stub
246 return null;
247 }
248 }