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