1
|
/*******************************************************************************
|
2
|
* Copyright (c) 2006, 2010 IBM Corporation and others.
|
3
|
* All rights reserved. This program and the accompanying materials
|
4
|
* are made available under the terms of the Eclipse Public License v1.0
|
5
|
* which accompanies this distribution, and is available at
|
6
|
* http://www.eclipse.org/legal/epl-v10.html
|
7
|
*
|
8
|
* Contributors:
|
9
|
* IBM Corporation - initial API and implementation
|
10
|
*******************************************************************************/
|
11
|
|
12
|
package org.eclipse.ui.internal.navigator;
|
13
|
|
14
|
import java.util.ArrayList;
|
15
|
import java.util.Arrays;
|
16
|
import java.util.HashMap;
|
17
|
import java.util.HashSet;
|
18
|
import java.util.Iterator;
|
19
|
import java.util.List;
|
20
|
import java.util.Map;
|
21
|
import java.util.Set;
|
22
|
import java.util.TreeMap;
|
23
|
|
24
|
import org.eclipse.core.runtime.Platform;
|
25
|
import org.eclipse.jface.viewers.IStructuredSelection;
|
26
|
import org.eclipse.jface.viewers.ITreeContentProvider;
|
27
|
import org.eclipse.jface.viewers.ITreePathContentProvider;
|
28
|
import org.eclipse.jface.viewers.ITreeSelection;
|
29
|
import org.eclipse.jface.viewers.StructuredViewer;
|
30
|
import org.eclipse.jface.viewers.TreePath;
|
31
|
import org.eclipse.swt.events.DisposeEvent;
|
32
|
import org.eclipse.swt.events.DisposeListener;
|
33
|
import org.eclipse.swt.widgets.Display;
|
34
|
import org.eclipse.ui.ISaveablesLifecycleListener;
|
35
|
import org.eclipse.ui.ISaveablesSource;
|
36
|
import org.eclipse.ui.Saveable;
|
37
|
import org.eclipse.ui.SaveablesLifecycleEvent;
|
38
|
import org.eclipse.ui.internal.navigator.VisibilityAssistant.VisibilityListener;
|
39
|
import org.eclipse.ui.internal.navigator.extensions.ExtensionSequenceNumberComparator;
|
40
|
import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor;
|
41
|
import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension;
|
42
|
import org.eclipse.ui.navigator.INavigatorContentDescriptor;
|
43
|
import org.eclipse.ui.navigator.INavigatorSaveablesService;
|
44
|
import org.eclipse.ui.navigator.SaveablesProvider;
|
45
|
import org.osgi.framework.Bundle;
|
46
|
import org.osgi.framework.BundleEvent;
|
47
|
|
48
|
/**
|
49
|
* Implementation of INavigatorSaveablesService.
|
50
|
* <p>
|
51
|
* Implementation note: all externally callable methods are synchronized. The
|
52
|
* private helper methods are not synchronized since they can only be called
|
53
|
* from methods that already hold the lock.
|
54
|
* </p>
|
55
|
* @since 3.2
|
56
|
*
|
57
|
*/
|
58
|
public class NavigatorSaveablesService implements INavigatorSaveablesService, VisibilityListener {
|
59
|
|
60
|
private NavigatorContentService contentService;
|
61
|
|
62
|
private static List instances = new ArrayList();
|
63
|
|
64
|
/**
|
65
|
* @param contentService
|
66
|
*/
|
67
|
public NavigatorSaveablesService(NavigatorContentService contentService) {
|
68
|
this.contentService = contentService;
|
69
|
}
|
70
|
|
71
|
private static void addInstance(NavigatorSaveablesService saveablesService) {
|
72
|
synchronized (instances) {
|
73
|
instances.add(saveablesService);
|
74
|
}
|
75
|
}
|
76
|
|
77
|
private static void removeInstance(
|
78
|
NavigatorSaveablesService saveablesService) {
|
79
|
synchronized (instances) {
|
80
|
instances.remove(saveablesService);
|
81
|
}
|
82
|
}
|
83
|
|
84
|
/**
|
85
|
* @param event
|
86
|
*/
|
87
|
/* package */ static void bundleChanged(BundleEvent event) {
|
88
|
synchronized(instances) {
|
89
|
if (event.getType() == BundleEvent.STARTED) {
|
90
|
// System.out.println("bundle started: " + event.getBundle().getSymbolicName()); //$NON-NLS-1$
|
91
|
for (Iterator it = instances.iterator(); it.hasNext();) {
|
92
|
NavigatorSaveablesService instance = (NavigatorSaveablesService) it
|
93
|
.next();
|
94
|
instance.handleBundleStarted(event.getBundle()
|
95
|
.getSymbolicName());
|
96
|
}
|
97
|
} else if (event.getType() == BundleEvent.STOPPED) {
|
98
|
// System.out.println("bundle stopped: " + event.getBundle().getSymbolicName()); //$NON-NLS-1$
|
99
|
for (Iterator it = instances.iterator(); it.hasNext();) {
|
100
|
NavigatorSaveablesService instance = (NavigatorSaveablesService) it
|
101
|
.next();
|
102
|
instance.handleBundleStopped(event.getBundle()
|
103
|
.getSymbolicName());
|
104
|
}
|
105
|
}
|
106
|
}
|
107
|
}
|
108
|
|
109
|
private class LifecycleListener implements ISaveablesLifecycleListener {
|
110
|
public void handleLifecycleEvent(SaveablesLifecycleEvent event) {
|
111
|
Saveable[] saveables = event.getSaveables();
|
112
|
Saveable[] shownSaveables = null;
|
113
|
// synchronize in the same order as in the init method.
|
114
|
synchronized (instances) {
|
115
|
synchronized (NavigatorSaveablesService.this) {
|
116
|
if (isDisposed())
|
117
|
return;
|
118
|
switch (event.getEventType()) {
|
119
|
case SaveablesLifecycleEvent.POST_OPEN:
|
120
|
recomputeSaveablesAndNotify(false, null);
|
121
|
break;
|
122
|
case SaveablesLifecycleEvent.POST_CLOSE:
|
123
|
recomputeSaveablesAndNotify(false, null);
|
124
|
break;
|
125
|
case SaveablesLifecycleEvent.DIRTY_CHANGED:
|
126
|
Set result = new HashSet(Arrays.asList(currentSaveables));
|
127
|
result.retainAll(Arrays.asList(saveables));
|
128
|
shownSaveables = (Saveable[]) result.toArray(new Saveable[result.size()]);
|
129
|
break;
|
130
|
}
|
131
|
}
|
132
|
}
|
133
|
|
134
|
// Notify outside of synchronization
|
135
|
if (shownSaveables != null && shownSaveables.length > 0) {
|
136
|
outsideListener.handleLifecycleEvent(new SaveablesLifecycleEvent(saveablesSource, SaveablesLifecycleEvent.DIRTY_CHANGED,
|
137
|
shownSaveables, false));
|
138
|
}
|
139
|
}
|
140
|
}
|
141
|
|
142
|
private Saveable[] currentSaveables;
|
143
|
|
144
|
private ISaveablesLifecycleListener outsideListener;
|
145
|
|
146
|
private ISaveablesLifecycleListener saveablesLifecycleListener = new LifecycleListener();
|
147
|
|
148
|
private ISaveablesSource saveablesSource;
|
149
|
|
150
|
private StructuredViewer viewer;
|
151
|
|
152
|
private SaveablesProvider[] saveablesProviders;
|
153
|
|
154
|
private DisposeListener disposeListener = new DisposeListener() {
|
155
|
|
156
|
public void widgetDisposed(DisposeEvent e) {
|
157
|
// synchronize in the same order as in the init method.
|
158
|
synchronized (instances) {
|
159
|
synchronized (NavigatorSaveablesService.this) {
|
160
|
if (saveablesProviders != null) {
|
161
|
for (int i = 0; i < saveablesProviders.length; i++) {
|
162
|
saveablesProviders[i].dispose();
|
163
|
}
|
164
|
}
|
165
|
removeInstance(NavigatorSaveablesService.this);
|
166
|
contentService = null;
|
167
|
currentSaveables = null;
|
168
|
outsideListener = null;
|
169
|
saveablesLifecycleListener = null;
|
170
|
saveablesSource = null;
|
171
|
viewer = null;
|
172
|
saveablesProviders = null;
|
173
|
disposeListener = null;
|
174
|
}
|
175
|
}
|
176
|
}
|
177
|
};
|
178
|
|
179
|
private Map inactivePluginsWithSaveablesProviders;
|
180
|
|
181
|
/**
|
182
|
* a TreeMap (NavigatorContentDescriptor->SaveablesProvider) which uses
|
183
|
* ExtensionPriorityComparator.INSTANCE as its Comparator
|
184
|
*/
|
185
|
private Map saveablesProviderMap;
|
186
|
|
187
|
/**
|
188
|
* Implementation note: This is not synchronized at the method level because it needs to
|
189
|
* synchronize on "instances" first, then on "this", to avoid potential deadlock.
|
190
|
*
|
191
|
* @param saveablesSource
|
192
|
* @param viewer
|
193
|
* @param outsideListener
|
194
|
*
|
195
|
*/
|
196
|
public void init(final ISaveablesSource saveablesSource,
|
197
|
final StructuredViewer viewer,
|
198
|
ISaveablesLifecycleListener outsideListener) {
|
199
|
// Synchronize on instances to make sure that we don't miss bundle started events.
|
200
|
synchronized (instances) {
|
201
|
// Synchronize on this because we are calling computeSaveables.
|
202
|
// Synchronization must remain in this order to avoid deadlock.
|
203
|
// This might not be necessary because at this time, no other
|
204
|
// concurrent calls should be possible, but it doesn't hurt either.
|
205
|
// For example, the initialization sequence might change in the
|
206
|
// future.
|
207
|
synchronized (this) {
|
208
|
this.saveablesSource = saveablesSource;
|
209
|
this.viewer = viewer;
|
210
|
this.outsideListener = outsideListener;
|
211
|
currentSaveables = computeSaveables();
|
212
|
// add this instance after we are fully inialized.
|
213
|
addInstance(this);
|
214
|
}
|
215
|
}
|
216
|
viewer.getControl().addDisposeListener(disposeListener);
|
217
|
}
|
218
|
|
219
|
private boolean isDisposed() {
|
220
|
return contentService == null;
|
221
|
}
|
222
|
|
223
|
/** helper to compute the saveables for which elements are part of the tree.
|
224
|
* Must be called from a synchronized method.
|
225
|
*
|
226
|
* @return the saveables
|
227
|
*/
|
228
|
private Saveable[] computeSaveables() {
|
229
|
ITreeContentProvider contentProvider = (ITreeContentProvider) viewer
|
230
|
.getContentProvider();
|
231
|
boolean isTreepathContentProvider = contentProvider instanceof ITreePathContentProvider;
|
232
|
Object viewerInput = viewer.getInput();
|
233
|
List result = new ArrayList();
|
234
|
Set roots = new HashSet(Arrays.asList(contentProvider
|
235
|
.getElements(viewerInput)));
|
236
|
SaveablesProvider[] saveablesProviders = getSaveablesProviders();
|
237
|
for (int i = 0; i < saveablesProviders.length; i++) {
|
238
|
SaveablesProvider saveablesProvider = saveablesProviders[i];
|
239
|
Saveable[] saveables = saveablesProvider.getSaveables();
|
240
|
for (int j = 0; j < saveables.length; j++) {
|
241
|
Saveable saveable = saveables[j];
|
242
|
Object[] elements = saveablesProvider.getElements(saveable);
|
243
|
// the saveable is added to the result if at least one of the
|
244
|
// elements representing the saveable appears in the tree, i.e.
|
245
|
// if its parent chain leads to a root node.
|
246
|
boolean foundRoot = false;
|
247
|
for (int k = 0; !foundRoot && k < elements.length; k++) {
|
248
|
Object element = elements[k];
|
249
|
if (roots.contains(element)) {
|
250
|
result.add(saveable);
|
251
|
foundRoot = true;
|
252
|
} else if (isTreepathContentProvider) {
|
253
|
ITreePathContentProvider treePathContentProvider = (ITreePathContentProvider) contentProvider;
|
254
|
TreePath[] parentPaths = treePathContentProvider.getParents(element);
|
255
|
for (int l = 0; !foundRoot && l < parentPaths.length; l++) {
|
256
|
TreePath parentPath = parentPaths[l];
|
257
|
for (int m = 0; !foundRoot && m < parentPath.getSegmentCount(); m++) {
|
258
|
if (roots.contains(parentPath.getSegment(m))) {
|
259
|
result.add(saveable);
|
260
|
foundRoot = true;
|
261
|
}
|
262
|
}
|
263
|
}
|
264
|
} else {
|
265
|
while (!foundRoot && element != null) {
|
266
|
if (roots.contains(element)) {
|
267
|
// found a parent chain leading to a root. The
|
268
|
// saveable is part of the tree.
|
269
|
result.add(saveable);
|
270
|
foundRoot = true;
|
271
|
} else {
|
272
|
element = contentProvider.getParent(element);
|
273
|
}
|
274
|
}
|
275
|
}
|
276
|
}
|
277
|
}
|
278
|
}
|
279
|
return (Saveable[]) result.toArray(new Saveable[result.size()]);
|
280
|
}
|
281
|
|
282
|
public synchronized Saveable[] getActiveSaveables() {
|
283
|
ITreeContentProvider contentProvider = (ITreeContentProvider) viewer
|
284
|
.getContentProvider();
|
285
|
IStructuredSelection selection = (IStructuredSelection) viewer
|
286
|
.getSelection();
|
287
|
if (selection instanceof ITreeSelection) {
|
288
|
return getActiveSaveablesFromTreeSelection((ITreeSelection) selection);
|
289
|
} else if (contentProvider instanceof ITreePathContentProvider) {
|
290
|
return getActiveSaveablesFromTreePathProvider(selection, (ITreePathContentProvider) contentProvider);
|
291
|
} else {
|
292
|
return getActiveSaveablesFromTreeProvider(selection, contentProvider);
|
293
|
}
|
294
|
}
|
295
|
|
296
|
/**
|
297
|
* @param selection
|
298
|
* @return the active saveables
|
299
|
*/
|
300
|
private Saveable[] getActiveSaveablesFromTreeSelection(
|
301
|
ITreeSelection selection) {
|
302
|
Set result = new HashSet();
|
303
|
TreePath[] paths = selection.getPaths();
|
304
|
for (int i = 0; i < paths.length; i++) {
|
305
|
TreePath path = paths[i];
|
306
|
Saveable saveable = findSaveable(path);
|
307
|
if (saveable != null) {
|
308
|
result.add(saveable);
|
309
|
}
|
310
|
}
|
311
|
return (Saveable[]) result.toArray(new Saveable[result.size()]);
|
312
|
}
|
313
|
|
314
|
/**
|
315
|
* @param selection
|
316
|
* @param provider
|
317
|
* @return the active saveables
|
318
|
*/
|
319
|
private Saveable[] getActiveSaveablesFromTreePathProvider(
|
320
|
IStructuredSelection selection, ITreePathContentProvider provider) {
|
321
|
Set result = new HashSet();
|
322
|
for (Iterator it = selection.iterator(); it.hasNext();) {
|
323
|
Object element = it.next();
|
324
|
Saveable saveable = getSaveable(element);
|
325
|
if (saveable != null) {
|
326
|
result.add(saveable);
|
327
|
} else {
|
328
|
TreePath[] paths = provider.getParents(element);
|
329
|
saveable = findSaveable(paths);
|
330
|
if (saveable != null) {
|
331
|
result.add(saveable);
|
332
|
}
|
333
|
}
|
334
|
}
|
335
|
return (Saveable[]) result.toArray(new Saveable[result.size()]);
|
336
|
}
|
337
|
|
338
|
/**
|
339
|
* @param selection
|
340
|
* @param contentProvider
|
341
|
* @return the active saveables
|
342
|
*/
|
343
|
private Saveable[] getActiveSaveablesFromTreeProvider(
|
344
|
IStructuredSelection selection, ITreeContentProvider contentProvider) {
|
345
|
Set result = new HashSet();
|
346
|
for (Iterator it = selection.iterator(); it.hasNext();) {
|
347
|
Object element = it.next();
|
348
|
Saveable saveable = findSaveable(element, contentProvider);
|
349
|
if (saveable != null) {
|
350
|
result.add(saveable);
|
351
|
}
|
352
|
}
|
353
|
return (Saveable[]) result.toArray(new Saveable[result.size()]);
|
354
|
}
|
355
|
|
356
|
/**
|
357
|
* @param element
|
358
|
* @param contentProvider
|
359
|
* @return the saveable, or null
|
360
|
*/
|
361
|
private Saveable findSaveable(Object element,
|
362
|
ITreeContentProvider contentProvider) {
|
363
|
while (element != null) {
|
364
|
Saveable saveable = getSaveable(element);
|
365
|
if (saveable != null) {
|
366
|
return saveable;
|
367
|
}
|
368
|
element = contentProvider.getParent(element);
|
369
|
}
|
370
|
return null;
|
371
|
}
|
372
|
|
373
|
/**
|
374
|
* @param paths
|
375
|
* @return the saveable, or null
|
376
|
*/
|
377
|
private Saveable findSaveable(TreePath[] paths) {
|
378
|
for (int i = 0; i < paths.length; i++) {
|
379
|
Saveable saveable = findSaveable(paths[i]);
|
380
|
if (saveable != null) {
|
381
|
return saveable;
|
382
|
}
|
383
|
}
|
384
|
return null;
|
385
|
}
|
386
|
|
387
|
/**
|
388
|
* @param path
|
389
|
* @return a saveable, or null
|
390
|
*/
|
391
|
private Saveable findSaveable(TreePath path) {
|
392
|
int count = path.getSegmentCount();
|
393
|
for (int j = count - 1; j >= 0; j--) {
|
394
|
Object parent = path.getSegment(j);
|
395
|
Saveable saveable = getSaveable(parent);
|
396
|
if (saveable != null) {
|
397
|
return saveable;
|
398
|
}
|
399
|
}
|
400
|
return null;
|
401
|
}
|
402
|
|
403
|
/**
|
404
|
* @param element
|
405
|
* @return the saveable associated with the given element
|
406
|
*/
|
407
|
private Saveable getSaveable(Object element) {
|
408
|
if (saveablesProviderMap==null) {
|
409
|
// has the side effect of recomputing saveablesProviderMap:
|
410
|
getSaveablesProviders();
|
411
|
}
|
412
|
for(Iterator sItr = saveablesProviderMap.keySet().iterator(); sItr.hasNext();) {
|
413
|
NavigatorContentDescriptor descriptor = (NavigatorContentDescriptor) sItr.next();
|
414
|
if(descriptor.isTriggerPoint(element) || descriptor.isPossibleChild(element)) {
|
415
|
SaveablesProvider provider = (SaveablesProvider) saveablesProviderMap.get(descriptor);
|
416
|
Saveable saveable = provider.getSaveable(element);
|
417
|
if(saveable != null) {
|
418
|
return saveable;
|
419
|
}
|
420
|
}
|
421
|
}
|
422
|
return null;
|
423
|
}
|
424
|
|
425
|
/**
|
426
|
* @return the saveables
|
427
|
*/
|
428
|
public synchronized Saveable[] getSaveables() {
|
429
|
return currentSaveables;
|
430
|
}
|
431
|
|
432
|
/**
|
433
|
* @return all SaveablesProvider objects
|
434
|
*/
|
435
|
private SaveablesProvider[] getSaveablesProviders() {
|
436
|
// TODO optimize this
|
437
|
if (saveablesProviders == null) {
|
438
|
inactivePluginsWithSaveablesProviders = new HashMap();
|
439
|
saveablesProviderMap = new TreeMap(ExtensionSequenceNumberComparator.INSTANCE);
|
440
|
INavigatorContentDescriptor[] descriptors = contentService
|
441
|
.getActiveDescriptorsWithSaveables();
|
442
|
List result = new ArrayList();
|
443
|
for (int i = 0; i < descriptors.length; i++) {
|
444
|
NavigatorContentDescriptor descriptor = (NavigatorContentDescriptor) descriptors[i];
|
445
|
String pluginId = ((NavigatorContentDescriptor) descriptor)
|
446
|
.getContribution().getPluginId();
|
447
|
if (Platform.getBundle(pluginId).getState() != Bundle.ACTIVE) {
|
448
|
List inactiveDescriptors = (List) inactivePluginsWithSaveablesProviders
|
449
|
.get(pluginId);
|
450
|
if (inactiveDescriptors == null) {
|
451
|
inactiveDescriptors = new ArrayList();
|
452
|
inactivePluginsWithSaveablesProviders.put(pluginId,
|
453
|
inactiveDescriptors);
|
454
|
}
|
455
|
inactiveDescriptors.add(descriptor);
|
456
|
} else {
|
457
|
SaveablesProvider saveablesProvider = createSaveablesProvider(descriptor);
|
458
|
if (saveablesProvider != null) {
|
459
|
saveablesProvider.init(saveablesLifecycleListener);
|
460
|
result.add(saveablesProvider);
|
461
|
saveablesProviderMap.put(descriptor, saveablesProvider);
|
462
|
}
|
463
|
}
|
464
|
}
|
465
|
saveablesProviders = (SaveablesProvider[]) result
|
466
|
.toArray(new SaveablesProvider[result.size()]);
|
467
|
}
|
468
|
return saveablesProviders;
|
469
|
}
|
470
|
|
471
|
/**
|
472
|
* @param descriptor
|
473
|
* @return the SaveablesProvider, or null
|
474
|
*/
|
475
|
private SaveablesProvider createSaveablesProvider(NavigatorContentDescriptor descriptor) {
|
476
|
NavigatorContentExtension extension = contentService
|
477
|
.getExtension(descriptor, true);
|
478
|
// Use getContentProvider to get the client objects, this is important
|
479
|
// for the adaptation below. See bug 306545
|
480
|
ITreeContentProvider contentProvider = extension
|
481
|
.getContentProvider();
|
482
|
|
483
|
return (SaveablesProvider)AdaptabilityUtility.getAdapter(contentProvider, SaveablesProvider.class);
|
484
|
}
|
485
|
|
486
|
private void recomputeSaveablesAndNotify(boolean recomputeProviders,
|
487
|
String startedBundleIdOrNull) {
|
488
|
if (recomputeProviders && startedBundleIdOrNull == null
|
489
|
&& saveablesProviders != null) {
|
490
|
// a bundle was stopped, dispose of all saveablesProviders and
|
491
|
// recompute
|
492
|
// TODO optimize this
|
493
|
for (int i = 0; i < saveablesProviders.length; i++) {
|
494
|
saveablesProviders[i].dispose();
|
495
|
}
|
496
|
saveablesProviders = null;
|
497
|
} else if (startedBundleIdOrNull != null){
|
498
|
if(inactivePluginsWithSaveablesProviders.containsKey(startedBundleIdOrNull)) {
|
499
|
updateSaveablesProviders(startedBundleIdOrNull);
|
500
|
}
|
501
|
}
|
502
|
Set oldSaveables = new HashSet(Arrays.asList(currentSaveables));
|
503
|
currentSaveables = computeSaveables();
|
504
|
Set newSaveables = new HashSet(Arrays.asList(currentSaveables));
|
505
|
final Set removedSaveables = new HashSet(oldSaveables);
|
506
|
removedSaveables.removeAll(newSaveables);
|
507
|
final Set addedSaveables = new HashSet(newSaveables);
|
508
|
addedSaveables.removeAll(oldSaveables);
|
509
|
if (addedSaveables.size() > 0) {
|
510
|
Display.getDefault().asyncExec(new Runnable() {
|
511
|
public void run() {
|
512
|
if (isDisposed()) {
|
513
|
return;
|
514
|
}
|
515
|
outsideListener.handleLifecycleEvent(new SaveablesLifecycleEvent(
|
516
|
saveablesSource, SaveablesLifecycleEvent.POST_OPEN,
|
517
|
(Saveable[]) addedSaveables
|
518
|
.toArray(new Saveable[addedSaveables.size()]),
|
519
|
false));
|
520
|
}
|
521
|
});
|
522
|
}
|
523
|
// TODO this will make the closing of saveables non-cancelable.
|
524
|
// Ideally, we should react to PRE_CLOSE events and fire
|
525
|
// an appropriate PRE_CLOSE
|
526
|
if (removedSaveables.size() > 0) {
|
527
|
Display.getDefault().asyncExec(new Runnable() {
|
528
|
public void run() {
|
529
|
if (isDisposed()) {
|
530
|
return;
|
531
|
}
|
532
|
outsideListener
|
533
|
.handleLifecycleEvent(new SaveablesLifecycleEvent(
|
534
|
saveablesSource,
|
535
|
SaveablesLifecycleEvent.PRE_CLOSE,
|
536
|
(Saveable[]) removedSaveables
|
537
|
.toArray(new Saveable[removedSaveables
|
538
|
.size()]), true));
|
539
|
outsideListener
|
540
|
.handleLifecycleEvent(new SaveablesLifecycleEvent(
|
541
|
saveablesSource,
|
542
|
SaveablesLifecycleEvent.POST_CLOSE,
|
543
|
(Saveable[]) removedSaveables
|
544
|
.toArray(new Saveable[removedSaveables
|
545
|
.size()]), false));
|
546
|
}
|
547
|
});
|
548
|
}
|
549
|
}
|
550
|
|
551
|
/**
|
552
|
* @param startedBundleId
|
553
|
*/
|
554
|
private void updateSaveablesProviders(String startedBundleId) {
|
555
|
List result = new ArrayList(Arrays.asList(saveablesProviders));
|
556
|
List descriptors = (List) inactivePluginsWithSaveablesProviders
|
557
|
.get(startedBundleId);
|
558
|
for (Iterator it = descriptors.iterator(); it.hasNext();) {
|
559
|
NavigatorContentDescriptor descriptor = (NavigatorContentDescriptor) it
|
560
|
.next();
|
561
|
SaveablesProvider saveablesProvider = createSaveablesProvider(descriptor);
|
562
|
if (saveablesProvider != null) {
|
563
|
saveablesProvider.init(saveablesLifecycleListener);
|
564
|
result.add(saveablesProvider);
|
565
|
saveablesProviderMap.put(descriptor, saveablesProvider);
|
566
|
}
|
567
|
}
|
568
|
saveablesProviders = (SaveablesProvider[]) result
|
569
|
.toArray(new SaveablesProvider[result.size()]);
|
570
|
}
|
571
|
|
572
|
/**
|
573
|
* @param symbolicName
|
574
|
*/
|
575
|
private synchronized void handleBundleStarted(String symbolicName) {
|
576
|
if (!isDisposed()) {
|
577
|
if (inactivePluginsWithSaveablesProviders.containsKey(symbolicName)) {
|
578
|
recomputeSaveablesAndNotify(true, symbolicName);
|
579
|
}
|
580
|
}
|
581
|
}
|
582
|
|
583
|
/**
|
584
|
* @param symbolicName
|
585
|
*/
|
586
|
private synchronized void handleBundleStopped(String symbolicName) {
|
587
|
if (!isDisposed()) {
|
588
|
recomputeSaveablesAndNotify(true, null);
|
589
|
}
|
590
|
}
|
591
|
|
592
|
/* (non-Javadoc)
|
593
|
* @see org.eclipse.ui.internal.navigator.VisibilityAssistant.VisibilityListener#onVisibilityOrActivationChange()
|
594
|
*/
|
595
|
public synchronized void onVisibilityOrActivationChange() {
|
596
|
if (!isDisposed()) {
|
597
|
recomputeSaveablesAndNotify(true, null);
|
598
|
}
|
599
|
}
|
600
|
|
601
|
}
|