001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.runtime.registry;
011:
012: import java.util.ArrayList;
013:
014: import org.eclipse.core.runtime.IExtension;
015: import org.eclipse.core.runtime.IExtensionDelta;
016: import org.eclipse.core.runtime.IExtensionPoint;
017: import org.eclipse.core.runtime.IRegistryChangeEvent;
018: import org.eclipse.core.runtime.IRegistryChangeListener;
019: import org.eclipse.core.runtime.Platform;
020: import org.eclipse.jface.action.Action;
021: import org.eclipse.jface.action.IMenuListener;
022: import org.eclipse.jface.action.IMenuManager;
023: import org.eclipse.jface.action.IToolBarManager;
024: import org.eclipse.jface.action.MenuManager;
025: import org.eclipse.jface.action.Separator;
026: import org.eclipse.jface.viewers.TreeViewer;
027: import org.eclipse.jface.viewers.Viewer;
028: import org.eclipse.jface.viewers.ViewerComparator;
029: import org.eclipse.jface.viewers.ViewerFilter;
030: import org.eclipse.pde.internal.runtime.IHelpContextIds;
031: import org.eclipse.pde.internal.runtime.PDERuntimeMessages;
032: import org.eclipse.pde.internal.runtime.PDERuntimePlugin;
033: import org.eclipse.pde.internal.runtime.PDERuntimePluginImages;
034: import org.eclipse.swt.SWT;
035: import org.eclipse.swt.custom.BusyIndicator;
036: import org.eclipse.swt.layout.GridData;
037: import org.eclipse.swt.layout.GridLayout;
038: import org.eclipse.swt.widgets.Composite;
039: import org.eclipse.swt.widgets.Menu;
040: import org.eclipse.swt.widgets.Tree;
041: import org.eclipse.swt.widgets.TreeItem;
042: import org.eclipse.ui.IActionBars;
043: import org.eclipse.ui.IMemento;
044: import org.eclipse.ui.IViewSite;
045: import org.eclipse.ui.PartInitException;
046: import org.eclipse.ui.PlatformUI;
047: import org.eclipse.ui.XMLMemento;
048: import org.eclipse.ui.dialogs.FilteredTree;
049: import org.eclipse.ui.dialogs.PatternFilter;
050: import org.eclipse.ui.part.DrillDownAdapter;
051: import org.eclipse.ui.part.ViewPart;
052: import org.osgi.framework.Bundle;
053: import org.osgi.framework.BundleEvent;
054: import org.osgi.framework.BundleListener;
055: import org.osgi.framework.Constants;
056:
057: public class RegistryBrowser extends ViewPart implements
058: BundleListener, IRegistryChangeListener {
059:
060: public static final String SHOW_RUNNING_PLUGINS = "RegistryView.showRunning.label"; //$NON-NLS-1$
061:
062: private FilteredTree fFilteredTree;
063: private TreeViewer fTreeViewer;
064: private IMemento fMemento;
065: private int fTotalBundles = 0;
066:
067: // menus and action items
068: private Action fRefreshAction;
069: private Action fShowPluginsAction;
070: private Action fCollapseAllAction;
071: private Action fRemoveAction;
072: private Action fAddAction;
073: private DrillDownAdapter drillDownAdapter;
074: private ViewerFilter fActiveFilter = new ViewerFilter() {
075: public boolean select(Viewer viewer, Object parentElement,
076: Object element) {
077: if (element instanceof PluginObjectAdapter)
078: element = ((PluginObjectAdapter) element).getObject();
079: if (element instanceof Bundle)
080: return ((Bundle) element).getState() == Bundle.ACTIVE;
081: return true;
082: }
083: };
084:
085: /*
086: * customized DrillDownAdapter which modifies enabled state of showing active/inactive
087: * plug-ins action - see Bug 58467
088: */
089: class RegistryDrillDownAdapter extends DrillDownAdapter {
090: public RegistryDrillDownAdapter(TreeViewer tree) {
091: super (tree);
092: }
093:
094: public void goInto() {
095: super .goInto();
096: fShowPluginsAction.setEnabled(!canGoHome());
097: }
098:
099: public void goBack() {
100: super .goBack();
101: fShowPluginsAction.setEnabled(!canGoHome());
102: }
103:
104: public void goHome() {
105: super .goHome();
106: fShowPluginsAction.setEnabled(!canGoHome());
107: }
108:
109: public void goInto(Object newInput) {
110: super .goInto(newInput);
111: fShowPluginsAction.setEnabled(!canGoHome());
112: }
113: }
114:
115: public RegistryBrowser() {
116: super ();
117: }
118:
119: public void init(IViewSite site, IMemento memento)
120: throws PartInitException {
121: super .init(site, memento);
122: if (memento == null)
123: this .fMemento = XMLMemento.createWriteRoot("REGISTRYVIEW"); //$NON-NLS-1$
124: else
125: this .fMemento = memento;
126: initializeMemento();
127: }
128:
129: private void initializeMemento() {
130: // show all plug-ins by default (i.e. not just activated ones)
131: if (fMemento.getString(SHOW_RUNNING_PLUGINS) == null)
132: fMemento.putString(SHOW_RUNNING_PLUGINS, "false"); //$NON-NLS-1$
133: }
134:
135: public void dispose() {
136: Platform.getExtensionRegistry().removeRegistryChangeListener(
137: this );
138: PDERuntimePlugin.getDefault().getBundleContext()
139: .removeBundleListener(this );
140: super .dispose();
141: }
142:
143: public void createPartControl(Composite parent) {
144: // create the sash form that will contain the tree viewer & text viewer
145: Composite composite = new Composite(parent, SWT.NONE);
146: GridLayout layout = new GridLayout();
147: layout.marginHeight = layout.marginWidth = 0;
148: composite.setLayout(layout);
149: composite.setLayoutData(new GridData(GridData.FILL_BOTH));
150: makeActions();
151: createTreeViewer(composite);
152: fillToolBar();
153: updateTitle();
154:
155: Platform.getExtensionRegistry().addRegistryChangeListener(this );
156: PDERuntimePlugin.getDefault().getBundleContext()
157: .addBundleListener(this );
158: }
159:
160: private void createTreeViewer(Composite parent) {
161: Composite composite = new Composite(parent, SWT.NONE);
162: GridLayout layout = new GridLayout();
163: layout.marginHeight = layout.marginWidth = 0;
164: composite.setLayout(layout);
165: composite.setLayoutData(new GridData(GridData.FILL_BOTH));
166:
167: fFilteredTree = new RegistryFilteredTree(composite, SWT.MULTI,
168: new PatternFilter());
169: fFilteredTree.setBackground(parent.getDisplay().getSystemColor(
170: SWT.COLOR_LIST_BACKGROUND));
171: Tree tree = fFilteredTree.getViewer().getTree();
172: GridData gd = new GridData(GridData.FILL_BOTH);
173: fFilteredTree.setLayoutData(gd);
174: fTreeViewer = fFilteredTree.getViewer();
175: fTreeViewer
176: .setContentProvider(new RegistryBrowserContentProvider(
177: fTreeViewer));
178: fTreeViewer.setLabelProvider(new RegistryBrowserLabelProvider(
179: fTreeViewer));
180: fTreeViewer.setUseHashlookup(true);
181: fTreeViewer.setComparator(new ViewerComparator() {
182: public int compare(Viewer viewer, Object e1, Object e2) {
183: if (e1 instanceof PluginObjectAdapter)
184: e1 = ((PluginObjectAdapter) e1).getObject();
185: if (e2 instanceof PluginObjectAdapter)
186: e2 = ((PluginObjectAdapter) e2).getObject();
187: if (e1 instanceof IBundleFolder
188: && e2 instanceof IBundleFolder)
189: return ((IBundleFolder) e1).getFolderId()
190: - ((IBundleFolder) e2).getFolderId();
191: if (e1 instanceof Bundle && e2 instanceof Bundle) {
192: e1 = ((Bundle) e1).getSymbolicName();
193: e2 = ((Bundle) e2).getSymbolicName();
194: }
195: return super .compare(viewer, e1, e2);
196: }
197: });
198: if (fMemento.getString(SHOW_RUNNING_PLUGINS).equals("true")) //$NON-NLS-1$)
199: fTreeViewer.addFilter(fActiveFilter);
200:
201: PluginObjectAdapter[] adapters = getBundles();
202: fTotalBundles = adapters.length;
203: fTreeViewer.setInput(new PluginObjectAdapter(adapters));
204:
205: PlatformUI.getWorkbench().getHelpSystem()
206: .setHelp(fTreeViewer.getControl(),
207: IHelpContextIds.REGISTRY_VIEW);
208:
209: getViewSite().setSelectionProvider(fTreeViewer);
210:
211: MenuManager popupMenuManager = new MenuManager();
212: IMenuListener listener = new IMenuListener() {
213: public void menuAboutToShow(IMenuManager mng) {
214: fillContextMenu(mng);
215: }
216: };
217: popupMenuManager.setRemoveAllWhenShown(true);
218: popupMenuManager.addMenuListener(listener);
219: Menu menu = popupMenuManager.createContextMenu(tree);
220: tree.setMenu(menu);
221: }
222:
223: private PluginObjectAdapter[] getBundles() {
224: Bundle[] bundles = PDERuntimePlugin.getDefault()
225: .getBundleContext().getBundles();
226: ArrayList list = new ArrayList();
227: for (int i = 0; i < bundles.length; i++)
228: if (bundles[i].getHeaders().get(Constants.FRAGMENT_HOST) == null)
229: list.add(new PluginObjectAdapter(bundles[i]));
230: return (PluginObjectAdapter[]) list
231: .toArray(new PluginObjectAdapter[list.size()]);
232: }
233:
234: private void fillToolBar() {
235: drillDownAdapter = new RegistryDrillDownAdapter(fTreeViewer);
236: IActionBars bars = getViewSite().getActionBars();
237: IToolBarManager mng = bars.getToolBarManager();
238: drillDownAdapter.addNavigationActions(mng);
239: mng.add(fRefreshAction);
240: mng.add(new Separator());
241: mng.add(fCollapseAllAction);
242: IMenuManager mgr = bars.getMenuManager();
243: mgr.add(new Separator());
244: mgr.add(fShowPluginsAction);
245: }
246:
247: public void fillContextMenu(IMenuManager manager) {
248: manager.add(fRefreshAction);
249: Tree tree = getUndisposedTree();
250: // TODO remove testing actions from code after delta is fixed
251: // bug 130655
252: if (tree != null && false) {
253: TreeItem[] selection = tree.getSelection();
254: boolean allRemoveable = true;
255: boolean canAdd = true;
256: for (int i = 0; i < selection.length; i++) {
257: Object obj = selection[i].getData();
258: if (obj instanceof PluginObjectAdapter)
259: obj = ((PluginObjectAdapter) obj).getObject();
260: if (!(obj instanceof Bundle)
261: || ((Bundle) obj).getState() < Bundle.RESOLVED)
262: canAdd = false;
263: if (!(obj instanceof IExtensionPoint)
264: && !(obj instanceof IExtension)) {
265: allRemoveable = false;
266: break;
267: }
268: }
269: if (allRemoveable)
270: manager.add(fRemoveAction);
271: if (canAdd && selection.length == 1)
272: manager.add(fAddAction);
273: }
274: manager.add(new Separator());
275: drillDownAdapter.addNavigationActions(manager);
276: manager.add(new Separator());
277: manager.add(fShowPluginsAction);
278: }
279:
280: public TreeViewer getTreeViewer() {
281: return fTreeViewer;
282: }
283:
284: public void saveState(IMemento memento) {
285: if (memento == null || this .fMemento == null
286: || fTreeViewer == null)
287: return;
288: boolean showRunning = fShowPluginsAction.isChecked();
289: if (showRunning)
290: this .fMemento.putString(SHOW_RUNNING_PLUGINS, Boolean
291: .toString(true));
292: else
293: this .fMemento.putString(SHOW_RUNNING_PLUGINS, Boolean
294: .toString(false));
295: memento.putMemento(this .fMemento);
296: }
297:
298: public void setFocus() {
299: fFilteredTree.getFilterControl().setFocus();
300: }
301:
302: /*
303: * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
304: */
305: public void bundleChanged(final BundleEvent event) {
306: final Tree tree = getUndisposedTree();
307: if (tree == null)
308: return;
309:
310: final Bundle bundle = event.getBundle();
311: tree.getDisplay().asyncExec(new Runnable() {
312: public void run() {
313: Object data = null;
314: switch (event.getType()) {
315: case BundleEvent.INSTALLED:
316: data = findTreeBundleData(bundle);
317: if (data == null) { // bundle doesn't exist in tree - add it
318: fTreeViewer.add(fTreeViewer.getInput(),
319: new PluginObjectAdapter(bundle));
320: fTotalBundles += 1;
321: updateTitle();
322: }
323: break;
324: case BundleEvent.LAZY_ACTIVATION:
325: break;
326: case BundleEvent.RESOLVED:
327: break;
328: case BundleEvent.STARTED:
329: // TODO - look over this (installing new bundles during runtime results in bad "location")
330: // removing and adding the tree item to update it with a platform bundle object
331: data = findTreeBundleData(bundle);
332: final Bundle platformBundle = Platform
333: .getBundle(bundle.getSymbolicName());
334: if (data != null && platformBundle != null) {
335: fTreeViewer.remove(data);
336: fTreeViewer
337: .add(fTreeViewer.getInput(),
338: new PluginObjectAdapter(
339: platformBundle));
340: }
341: break;
342: case BundleEvent.STARTING:
343: break;
344: case BundleEvent.STOPPED:
345: data = findTreeBundleData(bundle);
346: if (data != null)
347: fTreeViewer.update(data, null);
348: break;
349: case BundleEvent.STOPPING:
350: break;
351: case BundleEvent.UNINSTALLED:
352: data = findTreeBundleData(bundle);
353: if (data != null) {
354: fTreeViewer.remove(data);
355: fTotalBundles -= 1;
356: updateTitle();
357: }
358: break;
359: case BundleEvent.UNRESOLVED:
360: break;
361: case BundleEvent.UPDATED:
362: break;
363: }
364: }
365:
366: private Object findTreeBundleData(Bundle bundle) {
367: Object data = null;
368: boolean found = false;
369: TreeItem[] items = tree.getItems();
370: if (items == null)
371: return null;
372: for (int i = 0; i < items.length; i++) {
373: Object object = items[i].getData();
374: data = object;
375: if (object instanceof PluginObjectAdapter)
376: object = ((PluginObjectAdapter) object)
377: .getObject();
378: if (bundle.equals(object)) {
379: found = true;
380: break;
381: }
382: }
383: return found ? data : null;
384: }
385: });
386: }
387:
388: /*
389: * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
390: */
391: public void registryChanged(IRegistryChangeEvent event) {
392: Tree tree = getUndisposedTree();
393: if (tree == null)
394: return;
395: final IExtensionDelta[] deltas = event.getExtensionDeltas();
396: tree.getDisplay().syncExec(new Runnable() {
397: public void run() {
398: if (getUndisposedTree() == null)
399: return;
400: for (int i = 0; i < deltas.length; i++)
401: handleDelta(deltas[i]);
402: }
403: });
404: }
405:
406: private void handleDelta(IExtensionDelta delta) {
407: IExtension ext = delta.getExtension();
408: IExtensionPoint extPoint = delta.getExtensionPoint();
409: if (delta.getKind() == IExtensionDelta.ADDED) {
410: addToTree(ext);
411: addToTree(extPoint);
412: } else if (delta.getKind() == IExtensionDelta.REMOVED) {
413: removeFromTree(ext);
414: removeFromTree(extPoint);
415: }
416: }
417:
418: private void addToTree(Object object) {
419: String namespace = getNamespaceIdentifier(object);
420: if (namespace == null)
421: return;
422: TreeItem[] bundles = fTreeViewer.getTree().getItems();
423: for (int i = 0; i < bundles.length; i++) {
424: Object data = bundles[i].getData();
425: Object adapted = null;
426: if (data instanceof PluginObjectAdapter)
427: adapted = ((PluginObjectAdapter) data).getObject();
428: if (adapted instanceof Bundle
429: && ((Bundle) adapted).getSymbolicName().equals(
430: namespace)) {
431: // TODO fix this method
432: if (true) {
433: fTreeViewer.refresh(data);
434: return;
435: }
436: TreeItem[] folders = bundles[i].getItems();
437: for (int j = 0; j < folders.length; j++) {
438: IBundleFolder folder = (IBundleFolder) folders[j]
439: .getData();
440: if (correctFolder(folder, object)) {
441: fTreeViewer.add(folder, object);
442: return;
443: }
444: }
445: // folder not found - 1st extension - refresh bundle item
446: fTreeViewer.refresh(data);
447: }
448: }
449: }
450:
451: private String getNamespaceIdentifier(Object object) {
452: if (object instanceof IExtensionPoint)
453: return ((IExtensionPoint) object).getNamespaceIdentifier();
454: if (object instanceof IExtension)
455: return ((IExtension) object).getContributor().getName();
456: return null;
457: }
458:
459: private boolean correctFolder(IBundleFolder folder, Object child) {
460: if (folder == null)
461: return false;
462: if (child instanceof IExtensionPoint)
463: return folder.getFolderId() == IBundleFolder.F_EXTENSION_POINTS;
464: if (child instanceof IExtension)
465: return folder.getFolderId() == IBundleFolder.F_EXTENSIONS;
466: return false;
467: }
468:
469: private void removeFromTree(Object object) {
470: String namespace = getNamespaceIdentifier(object);
471: if (namespace == null)
472: return;
473: TreeItem[] bundles = fTreeViewer.getTree().getItems();
474: for (int i = 0; i < bundles.length; i++) {
475: Object data = bundles[i].getData();
476: Object adapted = null;
477: if (data instanceof PluginObjectAdapter)
478: adapted = ((PluginObjectAdapter) data).getObject();
479: if (adapted instanceof Bundle
480: && ((Bundle) adapted).getSymbolicName().equals(
481: namespace)) {
482: TreeItem[] folders = bundles[i].getItems();
483: // TODO fix this method
484: if (true) {
485: fTreeViewer.refresh(data);
486: return;
487: }
488: for (int j = 0; j < folders.length; j++) {
489: IBundleFolder folder = (IBundleFolder) folders[j]
490: .getData();
491: if (correctFolder(folder, object)) {
492: fTreeViewer.remove(object);
493: return;
494: }
495: }
496: // folder not found - 1st extension - refresh bundle item
497: fTreeViewer.refresh(data);
498: }
499: }
500: }
501:
502: /*
503: * toolbar and context menu actions
504: */
505: public void makeActions() {
506: fRefreshAction = new Action("refresh") { //$NON-NLS-1$
507: public void run() {
508: BusyIndicator.showWhile(fTreeViewer.getTree()
509: .getDisplay(), new Runnable() {
510: public void run() {
511: fTreeViewer.refresh();
512: }
513: });
514: }
515: };
516: fRefreshAction
517: .setText(PDERuntimeMessages.RegistryView_refresh_label);
518: fRefreshAction
519: .setToolTipText(PDERuntimeMessages.RegistryView_refresh_tooltip);
520: fRefreshAction
521: .setImageDescriptor(PDERuntimePluginImages.DESC_REFRESH);
522: fRefreshAction
523: .setDisabledImageDescriptor(PDERuntimePluginImages.DESC_REFRESH_DISABLED);
524:
525: fShowPluginsAction = new Action(
526: PDERuntimeMessages.RegistryView_showRunning_label) {
527: public void run() {
528: if (fShowPluginsAction.isChecked())
529: fTreeViewer.addFilter(fActiveFilter);
530: else
531: fTreeViewer.removeFilter(fActiveFilter);
532: updateTitle();
533: }
534: };
535: fShowPluginsAction.setChecked(fMemento.getString(
536: SHOW_RUNNING_PLUGINS).equals("true")); //$NON-NLS-1$
537:
538: fRemoveAction = new Action("Remove") { //$NON-NLS-1$
539: public void run() {
540: // Tree tree = getUndisposedTree();
541: // if (tree == null)
542: // return;
543: // IExtensionRegistry registry = Platform.getExtensionRegistry();
544: // Object token = ((ExtensionRegistry)registry).getTemporaryUserToken();
545: // TreeItem[] selection = tree.getSelection();
546: // for (int i = 0; i < selection.length; i++) {
547: // Object obj = selection[i].getData();
548: // if (obj instanceof ParentAdapter)
549: // obj = ((ParentAdapter)obj).getObject();
550: // if (obj instanceof IExtensionPoint)
551: // registry.removeExtensionPoint((IExtensionPoint)obj, token);
552: // else if (obj instanceof IExtension)
553: // registry.removeExtension((IExtension)obj, token);
554: // }
555:
556: }
557: };
558:
559: fAddAction = new Action("Add...") { //$NON-NLS-1$
560: public void run() {
561: // Tree tree = getUndisposedTree();
562: // if (tree == null)
563: // return;
564: // FileDialog dialog = new FileDialog(getSite().getShell(), SWT.OPEN);
565: // String input = dialog.open();
566: // if (input == null)
567: // return;
568: // Object selection = tree.getSelection()[0].getData();
569: // if (selection instanceof PluginObjectAdapter)
570: // selection = ((PluginObjectAdapter)selection).getObject();
571: // if (!(selection instanceof Bundle))
572: // return;
573: // IContributor contributor = ContributorFactoryOSGi.createContributor((Bundle)selection);
574: // IExtensionRegistry registry = Platform.getExtensionRegistry();
575: // Object token = ((ExtensionRegistry)registry).getTemporaryUserToken();
576: // try {
577: // registry.addContribution(new FileInputStream(input), contributor, false, null, null, token);
578: // } catch (FileNotFoundException e) {
579: // }
580: }
581: };
582:
583: fCollapseAllAction = new Action("collapseAll") { //$NON-NLS-1$
584: public void run() {
585: fTreeViewer.collapseAll();
586: }
587: };
588: fCollapseAllAction
589: .setText(PDERuntimeMessages.RegistryView_collapseAll_label);
590: fCollapseAllAction
591: .setImageDescriptor(PDERuntimePluginImages.DESC_COLLAPSE_ALL);
592: fCollapseAllAction
593: .setToolTipText(PDERuntimeMessages.RegistryView_collapseAll_tooltip);
594: }
595:
596: public void updateTitle() {
597: if (fTreeViewer == null
598: || fTreeViewer.getContentProvider() == null)
599: return;
600: setContentDescription(((RegistryBrowserContentProvider) fTreeViewer
601: .getContentProvider()).getTitleSummary(fTotalBundles));
602: }
603:
604: private Tree getUndisposedTree() {
605: if (fTreeViewer == null || fTreeViewer.getTree() == null
606: || fTreeViewer.getTree().isDisposed())
607: return null;
608: return fTreeViewer.getTree();
609: }
610: }
|