Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 1d73d9e5d60f6c76743325fad8cf93207605ec1e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
/*******************************************************************************
 * Copyright (c) 2011, 2014 Wind River Systems, Inc. and others. All rights reserved.
 * This program and the accompanying materials are made available under the terms
 * of the Eclipse Public License v1.0 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Wind River Systems - initial API and implementation
 *******************************************************************************/
package org.eclipse.tcf.te.ui.views.editor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.tcf.te.ui.views.editor.pages.AbstractEditorPage;
import org.eclipse.tcf.te.ui.views.extensions.EditorPageBinding;
import org.eclipse.tcf.te.ui.views.extensions.EditorPageBindingExtensionPointManager;
import org.eclipse.tcf.te.ui.views.extensions.EditorPageExtensionPointManager;
import org.eclipse.tcf.te.ui.views.interfaces.IEditorPage;
import org.eclipse.tcf.te.ui.views.interfaces.IEditorSaveAsAdapter;
import org.eclipse.tcf.te.ui.views.interfaces.IUIConstants;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPersistable;
import org.eclipse.ui.IPersistableEditor;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.internal.part.NullEditorInput;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;


/**
 * Editor implementation.
 */
@SuppressWarnings("restriction")
public final class Editor extends FormEditor implements IPersistableEditor, ITabbedPropertySheetPageContributor {

	// The reference to an memento to restore once the editor got activated
	private IMemento mementoToRestore;

	// The editor event listener instance
	private EditorEventListener listener;

	/* (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormEditor#addPages()
	 */
	@Override
	protected void addPages() {
		// Read extension point and add the contributed pages.
		IEditorInput input = getEditorInput();
		// Get all applicable editor page bindings
		EditorPageBinding[] bindings = EditorPageBindingExtensionPointManager.getInstance().getApplicableEditorPageBindings(input);
		for (EditorPageBinding binding : bindings) {
			processPageBinding(binding);
		}

		if (mementoToRestore != null) {
			// Loop over all registered pages and pass on the editor specific memento
			// to the pages which implements IPersistableEditor as well
			for (Object page : pages) {
				if (page instanceof IPersistableEditor) {
					((IPersistableEditor)page).restoreState(mementoToRestore);
				}
			}
			mementoToRestore = null;
		}
	}

	/**
	 * Override this method to delegate the setFocus to
	 * the active form page.
	 */
	@Override
	public void setFocus() {
		IFormPage fpage = getActivePageInstance();
		if(fpage != null) {
			fpage.setFocus();
		}
		else {
			super.setFocus();
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.WorkbenchPart#setTitleImage(org.eclipse.swt.graphics.Image)
	 */
	@Override
	public void setTitleImage(Image titleImage) {
	    super.setTitleImage(titleImage);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormEditor#getActivePageInstance()
	 */
	@Override
	public IFormPage getActivePageInstance() {
		int index = getActivePage();
		if (index != -1) {
			return getPage(index);
		}
		return super.getActivePageInstance();
	}

	/**
	 * Returns the page which has the specified index.
	 *
	 * @param index The page's index.
	 * @return The page object or null if it does not exists.
	 */
	private IFormPage getPage(int index) {
		for (int i = 0; i < pages.size(); i++) {
			Object page = pages.get(i);
			if (page instanceof IFormPage) {
				IFormPage fpage = (IFormPage) page;
				if (fpage.getIndex() == index) {
					return fpage;
				}
			}
		}
		return null;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormEditor#setActivePage(int)
	 */
	@Override
	public void setActivePage(int pageIndex) {
		if (getPage(pageIndex) != null) {
			super.setActivePage(pageIndex);
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.MultiPageEditorPart#getEditor(int)
	 */
	@Override
	protected IEditorPart getEditor(int pageIndex) {
	    return getPage(pageIndex) != null ? super.getEditor(pageIndex) : null;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormEditor#createPageContainer(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	protected Composite createPageContainer(Composite parent) {
		// Create page container is the first method called by the final
		// MultiPageEditorPart#createPartControl. Use it as hook to close
		// editors with a NullEditorInput.
		if (getEditorInput() instanceof NullEditorInput) {
//			DisplayUtil.safeAsyncExec(new Runnable() {
//				@Override
//				public void run() {
//					close(false);
//				}
//			});
			close(false);
		}

	    return super.createPageContainer(parent);
	}

	/**
	 * Update the editor page list. Pages which are not longer valid
	 * will be removed and pages now being valid gets added.
	 */
	public void updatePageList() {
		// Remember the currently active page
		String activePageId = getActivePageInstance() != null ? getActivePageInstance().getId() : null;
		String activePageTitle = getActivePageInstance() != null ? getActivePageInstance().getTitle() : null;
		// Get the editor input object
		IEditorInput input = getEditorInput();
		// Get all applicable editor page bindings
		List<EditorPageBinding> bindings = new ArrayList<EditorPageBinding>(Arrays.asList(EditorPageBindingExtensionPointManager.getInstance().getApplicableEditorPageBindings(input)));
		// Get a copy of the currently added pages
		List<Object> oldPages = pages != null ? new ArrayList<Object>(Arrays.asList(pages.toArray())) : new ArrayList<Object>();
		// Loop through the old pages and determine if the page is still applicable
		Iterator<Object> iterator = oldPages.iterator();
		while (iterator.hasNext()) {
			Object element = iterator.next();
			// Skip over pages not being a form page.
			if (!(element instanceof IFormPage)) {
				continue;
			}
			IFormPage page = (IFormPage)element;
			// Find the corresponding page binding
			EditorPageBinding binding = null;
			for (EditorPageBinding candidate : bindings) {
				if (candidate.getPageId().equals(page.getId())) {
					binding = candidate;
					break;
				}
			}
			if (binding != null) {
				// Found binding -> page is still applicable
				bindings.remove(binding);
			} else {
				// No binding found -> page is not longer applicable
				removePage(pages.indexOf(page));
			}
		}
		// If the are remaining bindings left, this are new pages.
		// --> Process them now
		for (EditorPageBinding binding : bindings) {
			processPageBinding(binding);
		}
		// If possible, restore the active page
		if (activePageId != null) {
			int index = getIndexOf(activePageId);
			if (index == -1 && activePageTitle != null) {
				index = getIndexOfByTitle(activePageTitle);
			}
			if (index != -1) setActivePage(index);
		}
	}

	/**
	 * Process the given editor page binding.
	 *
	 * @param binding The editor page binding. Must not be <code>null</code>.
	 */
	protected void processPageBinding(EditorPageBinding binding) {
		Assert.isNotNull(binding);

		String pageId = binding.getPageId();
		if (pageId != null) {
			// Get the corresponding editor page instance
			IEditorPage page = EditorPageExtensionPointManager.getInstance().getEditorPage(pageId, true);
			if (page != null) {
				try {
					// Associate this editor with the page instance.
					// This is typically done in the constructor, but we are
					// utilizing a default constructor to instantiate the page.
					page.initialize(this);

					// Read in the "insertBefore" and "insertAfter" properties of the binding
					String insertBefore = binding.getInsertBefore().trim();
					String insertAfter = binding.getInsertAfter().trim();

					boolean pageAdded = false;

					// insertBefore will be processed before insertAfter.
					if (!"".equals(insertBefore)) { //$NON-NLS-1$
						String[] pageIds = insertBefore.split(","); //$NON-NLS-1$
						for (String insertBeforePageId : pageIds) {
							// If it is "first", we insert the page at index 0
							if ("first".equalsIgnoreCase(insertBeforePageId)) { //$NON-NLS-1$
								if (getIndexOf(page.getId()) == -1) {
									addPage(0, page);
								}
								pageAdded = true;
								break;
							}

							// Find the index of the page we shall insert this page before
							int index = getIndexOf(insertBeforePageId);
							if (index != -1) {
								if (getIndexOf(page.getId()) == -1) {
									addPage(index, page);
								}
								pageAdded = true;
								break;
							}
						}
					}

					// If the page hasn't been added till now, process insertAfter
					if (!pageAdded && !"".equals(insertAfter)) { //$NON-NLS-1$
						String[] pageIds = insertAfter.split(","); //$NON-NLS-1$
						for (String insertAfterPageId : pageIds) {
							// If it is "last", we insert the page at the end
							if ("last".equalsIgnoreCase(insertAfterPageId)) { //$NON-NLS-1$
								if (getIndexOf(page.getId()) == -1) {
									addPage(page);
								}
								pageAdded = true;
								break;
							}

							// Find the index of the page we shall insert this page after
							int index = getIndexOf(insertAfterPageId);
							if (index != -1 && index + 1 < pages.size()) {
								if (getIndexOf(page.getId()) == -1) {
									addPage(index + 1, page);
								}
								pageAdded = true;
								break;
							}
						}
					}

					// Add the page to the end if not added otherwise
					if (!pageAdded && getIndexOf(page.getId()) == -1) {
						addPage(page);
					}

				} catch (PartInitException e) { /* ignored on purpose */ }
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormEditor#configurePage(int, org.eclipse.ui.forms.editor.IFormPage)
	 */
	@Override
	protected void configurePage(int index, IFormPage page) throws PartInitException {
	    super.configurePage(index, page);
	    // Update the page text as it may have changed after initializing
	    // the editor input
		setPageText(index, page.getTitle());
	}

	/**
	 * Returns the index of the page with the given id.
	 *
	 * @param pageId The page id. Must not be <code>null</code>.
	 * @return The page index or <code>-1</code> if not found.
	 */
	private int getIndexOf(String pageId) {
		Assert.isNotNull(pageId);
		for (int i = 0; i < pages.size(); i++) {
			Object page = pages.get(i);
			if (page instanceof IFormPage) {
				IFormPage fpage = (IFormPage)page;
				if (fpage.getId().equals(pageId)) {
					return i;
				}
			}
		}
		return -1;
	}

	/**
	 * Returns the index of the page with the given title.
	 *
	 * @param pageTitle The page title. Must not be <code>null</code>.
	 * @return The page index or <code>-1</code> if not found.
	 */
	private int getIndexOfByTitle(String pageTitle) {
		Assert.isNotNull(pageTitle);
		for (int i = 0; i < pages.size(); i++) {
			Object page = pages.get(i);
			if (page instanceof IFormPage) {
				IFormPage fpage = (IFormPage)page;
				if (fpage.getTitle().equals(pageTitle)) {
					return i;
				}
			}
		}
		return -1;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormPage#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
	 */
	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		super.init(site, input);

		// Update the part name
		if (!"".equals(input.getName())) { //$NON-NLS-1$
			setPartName(input.getName());
		}

		// Dispose an existing event listener instance
		if (listener != null) { listener.dispose(); listener = null; }
		// Create the event listener. The event listener does register itself.
		listener = new EditorEventListener(this);
	}

	/**
	 * Update the editor part name based on the current editor input.
	 */
	public void updatePartName() {
		IEditorInput input = getEditorInput();
		String oldPartName = getPartName();

		if (input instanceof EditorInput) {
			// Reset the editor input name to trigger recalculation
			((EditorInput)input).name = null;
			// If the name changed, apply the new name
			if (!oldPartName.equals(input.getName())) {
				setPartName(input.getName());
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.forms.editor.FormEditor#dispose()
	 */
	@Override
	public void dispose() {
		// Dispose an existing event listener instance
		if (listener != null) { listener.dispose(); listener = null; }

		super.dispose();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
	 */
	@Override
	public void doSave(IProgressMonitor monitor) {
		// The pages may require some save pre processing
		for (Object page : pages) {
			if (page instanceof AbstractEditorPage) {
				((AbstractEditorPage)page).preDoSave(monitor);
			}
		}
		// Commit the page changes
		commitPages(true);
		// The pages may require some save post processing
		for (Object page : pages) {
			if (page instanceof AbstractEditorPage) {
				((AbstractEditorPage)page).postDoSave(monitor);
			}
		}
		editorDirtyStateChanged();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
	 */
	@Override
	public void doSaveAs() {
		IEditorSaveAsAdapter adapter = getEditorInput() != null ? (IEditorSaveAsAdapter)Platform.getAdapterManager().getAdapter(getEditorInput(), IEditorSaveAsAdapter.class) : null;
		if (adapter != null) {
			Object newNode = adapter.doSaveAs(getEditorInput());
			if (newNode != null) {
				setInput(new EditorInput(newNode));
				updatePartName();
				updatePageList();
				for (Object page : pages) {
					if (page instanceof AbstractEditorPage) {
						((AbstractEditorPage) page).init(getEditorSite(), getEditorInput());
					}
				}
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
	 */
	@Override
	public boolean isSaveAsAllowed() {
		IEditorSaveAsAdapter adapter = getEditorInput() != null ? (IEditorSaveAsAdapter)Platform.getAdapterManager().getAdapter(getEditorInput(), IEditorSaveAsAdapter.class) : null;
		if (adapter != null) {
			return adapter.isSaveAsAllowed(getEditorInput());
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.IPersistableEditor#restoreState(org.eclipse.ui.IMemento)
	 */
	@Override
	public void restoreState(IMemento memento) {
		// Get the editor specific memento
		mementoToRestore = internalGetMemento(memento);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)
	 */
	@Override
	public void saveState(IMemento memento) {
		// Get the editor specific memento
		memento = internalGetMemento(memento);
		// Loop over all registered pages and pass on the editor specific memento
		// to the pages which implements IPersistable as well
		for (Object page : pages) {
			if (page instanceof IPersistable) {
				((IPersistable)page).saveState(memento);
			}
		}
	}

	/**
	 * Internal helper method accessing our editor local child memento
	 * from the given parent memento.
	 */
	private IMemento internalGetMemento(IMemento memento) {
		// Assume the editor memento to be the same as the parent memento
		IMemento editorMemento = memento;

		// If the parent memento is not null, create a child within the parent
		if (memento != null) {
			editorMemento = memento.getChild(Editor.class.getName());
			if (editorMemento == null) {
				editorMemento = memento.createChild(Editor.class.getName());
			}
		} else {
			// The parent memento is null. Create a new internal instance
			// of a XMLMemento. This case is happening if the user switches
			// to another perspective an the view becomes visible by this switch.
			editorMemento = XMLMemento.createWriteRoot(Editor.class.getName());
		}

		return editorMemento;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.part.MultiPageEditorPart#getAdapter(java.lang.Class)
	 */
	@Override
	public Object getAdapter(Class adapter) {
		if (adapter == IPropertySheetPage.class) {
			return new TabbedPropertySheetPage(this);
		}
		// We pass on the adapt request to the currently active page
		Object adapterInstance = getActivePageInstance() != null ? getActivePageInstance().getAdapter(adapter) : null;
		if (adapterInstance == null) {
			// If failed to adapt via the currently active page, pass on to the super implementation
			adapterInstance = super.getAdapter(adapter);
		}
		return adapterInstance;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor#getContributorId()
	 */
	@Override
	public String getContributorId() {
		return IUIConstants.TABBED_PROPERTIES_CONTRIBUTOR_ID;
	}

	/**
	 * Fires a property changed event.
	 *
	 * @param propertyId the id of the property that changed
	 */
	@Override
	public final void firePropertyChange(final int propertyId) {
		super.firePropertyChange(propertyId);
	}
}

Back to the top