Merge branch 'release/4.10.0'
[taxeditor.git] / eu.etaxonomy.taxeditor.bulkeditor / src / main / java / eu / etaxonomy / taxeditor / bulkeditor / BulkEditor.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.bulkeditor;
11
12 import org.eclipse.core.commands.operations.IUndoContext;
13 import org.eclipse.core.commands.operations.UndoContext;
14 import org.eclipse.core.runtime.IProgressMonitor;
15 import org.eclipse.jface.action.GroupMarker;
16 import org.eclipse.jface.action.IMenuManager;
17 import org.eclipse.jface.action.MenuManager;
18 import org.eclipse.jface.dialogs.MessageDialog;
19 import org.eclipse.jface.dialogs.MessageDialogWithToggle;
20 import org.eclipse.jface.preference.IPreferenceStore;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextSelection;
23 import org.eclipse.jface.text.TextSelection;
24 import org.eclipse.jface.text.source.Annotation;
25 import org.eclipse.jface.text.source.AnnotationModel;
26 import org.eclipse.jface.text.source.ISourceViewer;
27 import org.eclipse.jface.text.source.IVerticalRuler;
28 import org.eclipse.jface.util.IPropertyChangeListener;
29 import org.eclipse.jface.window.Window;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.custom.StyledText;
32 import org.eclipse.swt.events.MouseAdapter;
33 import org.eclipse.swt.events.MouseEvent;
34 import org.eclipse.swt.layout.GridData;
35 import org.eclipse.swt.layout.GridLayout;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Control;
38 import org.eclipse.swt.widgets.Menu;
39 import org.eclipse.ui.IEditorInput;
40 import org.eclipse.ui.IEditorSite;
41 import org.eclipse.ui.IWorkbenchActionConstants;
42 import org.eclipse.ui.PartInitException;
43 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
44
45 import eu.etaxonomy.taxeditor.annotatedlineeditor.AnnotatedLineDocumentProvider;
46 import eu.etaxonomy.taxeditor.annotatedlineeditor.AnnotatedLineEditor;
47 import eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotation;
48 import eu.etaxonomy.taxeditor.annotatedlineeditor.LineAnnotationModel;
49 import eu.etaxonomy.taxeditor.bulkeditor.input.AbstractBulkEditorInput;
50 import eu.etaxonomy.taxeditor.bulkeditor.input.OccurrenceEditorInput;
51 import eu.etaxonomy.taxeditor.bulkeditor.input.TaxonEditorInput;
52 import eu.etaxonomy.taxeditor.model.IDerivedUnitFacadePart;
53 import eu.etaxonomy.taxeditor.model.IDirtyMarkable;
54 import eu.etaxonomy.taxeditor.model.IPartContentHasDetails;
55 import eu.etaxonomy.taxeditor.model.IPartContentHasFactualData;
56 import eu.etaxonomy.taxeditor.model.IPartContentHasMedia;
57 import eu.etaxonomy.taxeditor.model.IPartContentHasSupplementalData;
58 import eu.etaxonomy.taxeditor.preference.IPreferenceKeys;
59 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
60 import eu.etaxonomy.taxeditor.store.CdmStore;
61
62 /**
63 * @author p.ciardelli
64 * @created 07.07.2009
65 * @version 1.0
66 */
67 public class BulkEditor extends AnnotatedLineEditor implements IPartContentHasDetails, IPartContentHasSupplementalData,
68 IDirtyMarkable, IDerivedUnitFacadePart, IPartContentHasFactualData, IPartContentHasMedia {
69
70 /** Constant <code>ID="bulkeditor.editor"</code> */
71 public static final String ID = "bulkeditor.editor";
72
73 private boolean isInitialFocus = true;
74
75 private BulkEditorSearch searchBar = null;
76
77 private IPropertyChangeListener markerPreferenceListener;
78
79 private boolean isDirty;
80
81 private IUndoContext undoContext;
82
83 public BulkEditor() {
84 super(CdmStore.createConversation());
85 undoContext = new UndoContext();
86 }
87
88 /** {@inheritDoc} */
89 @Override
90 protected void initializeEditor() {
91 super.initializeEditor();
92
93 // setEntityCreatorService(new BulkEditorEntityCreatorService());
94
95 setLineDisplayStrategy(new BulkEditorLineDisplay(this));
96
97 setSourceViewerConfiguration(new BulkEditorViewerConfiguration(lineDisplayStrategy));
98
99 }
100
101 /** {@inheritDoc} */
102 @Override
103 protected ISourceViewer createSourceViewer(Composite parent,
104 IVerticalRuler ruler, int styles) {
105 ISourceViewer viewer = super.createSourceViewer(parent, ruler, styles);
106 if (getEditorInput().isMergingEnabled()) {
107 addToggleMergeCandidateListener(ruler.getControl());
108 }
109 return viewer;
110 }
111
112 /** {@inheritDoc} */
113 @Override
114 public void init(IEditorSite site, IEditorInput input)
115 throws PartInitException {
116
117 if (!(input instanceof AbstractBulkEditorInput)) {
118 throw new PartInitException("Invalid Input: Must be BulkEditorInput");
119 }
120 else{
121 AbstractBulkEditorInput<?> bulkEditorInput = (AbstractBulkEditorInput<?>)input;
122 if(bulkEditorInput.getEntityUuid()!=null){
123 bulkEditorInput.performSearch(new BulkEditorQuery(bulkEditorInput.getEntityUuid().toString(), null));
124 }
125 }
126 super.init(site, input);
127 }
128
129 /** {@inheritDoc} */
130 @Override
131 public void createPartControl(Composite parent) {
132
133 parent.setLayout(new GridLayout());
134
135 Composite layoutComposite = new Composite(parent, SWT.NONE);
136 layoutComposite.setLayout(new GridLayout());
137
138 GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
139 layoutComposite.setLayoutData(gridData);
140
141 // layoutComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));
142
143
144 searchBar = new BulkEditorSearch(this, layoutComposite, SWT.NONE);
145 // layoutComposite.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
146
147 super.createPartControl(parent);
148
149 // Set viewer composite to fill grid. Unfortunately it is private and we have to do a little hack here.
150 for (Control control : parent.getChildren()) {
151 if (control instanceof Composite &&
152 !(control.equals(layoutComposite))) {
153 control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
154 }
155 }
156
157 //create context menu
158 MenuManager menuManager = new MenuManager();
159 menuManager.setRemoveAllWhenShown(true);
160 menuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
161 getSite().registerContextMenu(menuManager, getSelectionProvider());
162 Menu menu = menuManager.createContextMenu(this.getSourceViewer().getTextWidget());
163 this.getSourceViewer().getTextWidget().setMenu(menu);
164
165 }
166
167 /** {@inheritDoc} */
168 @Override
169 public void dispose() {
170 if (markerPreferenceListener != null ) {
171 PreferencesUtil.getPreferenceStore().removePropertyChangeListener(markerPreferenceListener);
172 }
173 super.dispose();
174 }
175
176
177 /** {@inheritDoc} */
178 @Override
179 public boolean isEditable() {
180 return false;
181 }
182
183 /** {@inheritDoc} */
184 @Override
185 public void setFocus() {
186 conversation.bind();
187
188 // TODO find a better place to put this - this dialog should be shown after initial contents of
189 // Editor are displayed
190 if (isInitialFocus) {
191 displayWarningDialog();
192 isInitialFocus = false;
193 }
194 super.setFocus();
195 searchBar.setFocus();
196 }
197
198 /**
199 * @return the searchBar
200 */
201 public BulkEditorSearch getSearchBar() {
202 return searchBar;
203 }
204
205 private void displayWarningDialog() {
206 IPreferenceStore prefs = PreferencesUtil.getPreferenceStore();
207 if (!prefs.getBoolean(IPreferenceKeys.HIDE_BULKEDITOR_INFO)) {
208 String msg = "The Bulk Editor allows you to edit objects used to reference other objects, such as names, references, and authors.\n\n" +
209 "Any changes you make to an object in the Bulk Editor will be displayed wherever the object is used.\n\n" +
210 "For instance, a reference may be displayed with both a name and a descriptive element. If the reference name is changed here, the display of both the name and the descriptive element will be affected.";
211 MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm
212 (getSite().getShell(), "Bulk Editor", msg, "Do not show this message again",
213 false, null, IPreferenceKeys.HIDE_BULKEDITOR_INFO);
214 if (dialog.getReturnCode() == Window.OK) {
215 prefs.setValue(IPreferenceKeys.HIDE_BULKEDITOR_INFO, dialog.getToggleState());
216 }
217 }
218 }
219
220 private void addToggleMergeCandidateListener(Control control) {
221 control.addMouseListener(new MouseAdapter() {
222 @Override
223 public void mouseDoubleClick(MouseEvent e) {
224 StyledText textWidget = getSourceViewer().getTextWidget();
225 int line = textWidget.getLineIndex(e.y);
226 toggleMergeCandidateAnnotation(line);
227 }
228 });
229 }
230
231 public void toggleMergeCandidateAnnotation(int line) {
232
233 IDocument document = getSourceViewer().getDocument();
234 LineAnnotationModel model =
235 (LineAnnotationModel) getSourceViewer().getAnnotationModel();
236
237 if(model != null){
238 Annotation annotation = model.getAnnotationAtLine(line, document);
239
240 if (annotation != null) {
241 if (annotation.getType().equals(IBulkEditorConstants.TYPE_MERGE_CANDIDATE)) {
242 model.changeAnnotationType(
243 annotation, LineAnnotation.TYPE_GENERIC);
244 } else {
245 model.changeAnnotationType(
246 annotation, IBulkEditorConstants.TYPE_MERGE_CANDIDATE);
247 }
248 }
249 }
250 }
251
252 @Override
253 public boolean isDirty() {
254 if(isDirty){
255 return isDirty;
256 }
257 else{
258 return super.isDirty();
259 }
260 }
261
262 @Override
263 public void forceDirty(){
264 isDirty = true;
265 firePropertyChange(PROP_DIRTY);
266 }
267
268
269 @Override
270 public void doSave(IProgressMonitor progressMonitor) {
271 isDirty = false;
272
273 super.doSave(progressMonitor);
274
275 this.searchBar.updateEditorInput();
276 selectFirstItem();
277
278 getSourceViewer().getTextWidget().setFocus();
279
280 }
281
282 /** {@inheritDoc} */
283 @Override
284 public void changed(Object object) {
285 // this.dirty = dirty;
286 AnnotatedLineDocumentProvider p = (AnnotatedLineDocumentProvider) getDocumentProvider();
287 p.changed(object);
288 // firePropertyChange(PROP_DIRTY);
289 }
290
291 /** {@inheritDoc} */
292 public void performSearch(BulkEditorQuery query) {
293 if (query != null) {
294
295 // TODO check if dirty, prompt save
296 if (isDirty()) {
297 String[] labels = {"Save (and Search)", "Don't save (and Search)","Cancel"};
298 MessageDialog dialog =new MessageDialog(getEditorSite().getShell(), "Save changes", null, "You have made changes that must be saved before this query can be executed. Would you like to proceed?", MessageDialog.QUESTION,labels, 0);
299 int result = dialog.open();
300 //MessageDialog.openQuestion(getEditorSite().getShell(),
301 //"Save changes", "You have made changes that must be saved before this query can be executed. Would you like to proceed?");
302 if (result == 0) {
303 doSave(null);
304 } else if (result == 2){
305 return;
306 }
307 }
308 //conversation.clear();
309 //conversation.commit(true);
310
311 getEditorInput().dispose();
312 getEditorInput().bind();
313 getEditorInput().performSearch(query);
314
315 refresh();
316
317 selectFirstItem();
318
319 getSourceViewer().getTextWidget().setFocus();
320 }
321 }
322
323 private void selectFirstItem() {
324 ITextSelection selection = new TextSelection(0, 0);
325 getSelectionProvider().setSelection(selection);
326 }
327
328 public void refresh() {
329 if(getDocumentProvider().getAnnotationModel(getEditorInput()) != null){
330 ((AnnotationModel) getDocumentProvider().getAnnotationModel(getEditorInput())).removeAllAnnotations();
331 }
332
333 setInput(getEditorInput());
334 }
335
336 /** {@inheritDoc} */
337 @Override
338 public AbstractBulkEditorInput getEditorInput() {
339 return (AbstractBulkEditorInput) super.getEditorInput();
340 }
341
342 @Override
343 protected void editorContextMenuAboutToShow(IMenuManager menu) {
344 super.editorContextMenuAboutToShow(menu);
345 menu.remove(ITextEditorActionConstants.SHIFT_RIGHT);
346 menu.remove(ITextEditorActionConstants.SHIFT_LEFT);
347 menu.remove(ITextEditorActionConstants.CONTEXT_PREFERENCES);
348 }
349
350 @Override
351 public boolean canAttachMedia() {
352 return (getEditorInput() instanceof TaxonEditorInput || getEditorInput() instanceof OccurrenceEditorInput) ?true:false;
353 }
354
355 public IUndoContext getUndoContext() {
356 return undoContext;
357 }
358
359
360 }