/******************************************************************************* * Copyright (c) 2009, 2011 SpringSource, a divison of VMware, 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: * SpringSource, a division of VMware, Inc. - initial API and implementation * SAP AG - moving to Eclipse Libra project and enhancements *******************************************************************************/ package org.eclipse.libra.framework.editor.ui.dependencies; import java.lang.reflect.InvocationTargetException; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.libra.framework.editor.core.IOSGiFrameworkAdmin; import org.eclipse.libra.framework.editor.core.model.IBundle; import org.eclipse.libra.framework.editor.ui.internal.AbstractBundleEditorPage; import org.eclipse.libra.framework.editor.ui.internal.EditorUIPlugin; import org.eclipse.libra.framework.editor.ui.internal.SearchControl; import org.eclipse.libra.framework.editor.ui.internal.SearchTextHistory; import org.eclipse.libra.framework.editor.ui.internal.dependencies.BundleDependencyContentProvider; import org.eclipse.libra.framework.editor.ui.internal.dependencies.BundleDependencyLabelProvider; import org.eclipse.libra.framework.editor.ui.internal.dependencies.FocusedBundleDependencyLayoutAlgorithm; import org.eclipse.libra.framework.editor.ui.overview.BundleInformationEditorPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Spinner; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.ManagedForm; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.internal.browser.ImageResource; import org.eclipse.wst.server.ui.ServerUICore; import org.eclipse.wst.server.ui.internal.editor.ServerEditorPartInput; import org.eclipse.wst.server.ui.internal.editor.ServerResourceCommandManager; import org.eclipse.zest.core.viewers.AbstractZoomableViewer; import org.eclipse.zest.core.viewers.GraphViewer; import org.eclipse.zest.core.viewers.IZoomableWorkbenchPart; import org.eclipse.zest.core.viewers.ZoomContributionViewItem; import org.eclipse.zest.core.widgets.ZestStyles; import org.eclipse.zest.layouts.LayoutAlgorithm; import org.eclipse.zest.layouts.LayoutStyles; import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm; import org.eclipse.zest.layouts.algorithms.HorizontalShift; import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm; /** * @author Christian Dupuis * @author Kaloyan Raev */ @SuppressWarnings("restriction") public class BundleDependencyEditorPage extends AbstractBundleEditorPage implements IZoomableWorkbenchPart { GraphViewer viewer; BundleDependencyContentProvider contentProvider; private BundleDependencyLabelProvider labelProvider; private ZoomContributionViewItem zoomContributionItem; SearchControl searchControl; private Action refreshAction; IToolBarManager toolBarManager; final SearchTextHistory history = new SearchTextHistory(); Action forwardAction; Action backAction; private ServerResourceCommandManager commandManager; @Override protected void createBundleContent(Composite parent) { mform = new ManagedForm(parent); setManagedForm(mform); sform = mform.getForm(); FormToolkit toolkit = mform.getToolkit(); sform.setText("Bundle Dependency Graph"); sform.setImage(ServerUICore.getLabelProvider().getImage(getServer())); sform.setExpandHorizontal(true); sform.setExpandVertical(true); toolkit.decorateFormHeading(sform.getForm()); Composite body = sform.getBody(); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 0; layout.marginWidth = 0; body.setLayout(layout); Composite configComposite = toolkit.createComposite(body); layout.marginLeft = 6; layout.marginTop = 6; layout.numColumns = 2; configComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL)); configComposite.setLayout(layout); Section expandableComposite = toolkit.createSection(configComposite, ExpandableComposite.TITLE_BAR | ExpandableComposite.FOCUS_TITLE); layout = new GridLayout(); expandableComposite.setLayout(layout); expandableComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING)); expandableComposite.setFont(body.getFont()); expandableComposite.setBackground(body.getBackground()); expandableComposite.setText("Configuration"); Composite composite = toolkit.createComposite(expandableComposite, SWT.NONE); layout = new GridLayout(); layout.numColumns = 1; layout.marginHeight = 0; layout.marginRight = 0; composite.setLayout(layout); expandableComposite.setClient(composite); final Button servicesButton = toolkit.createButton(composite, "Services", SWT.RADIO); servicesButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { contentProvider.setShowServices(servicesButton.getSelection()); new BundleDependencyUpdateJob(false).schedule(200); } }); final Button packagesButton = toolkit.createButton(composite, "Packages", SWT.RADIO); packagesButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { contentProvider.setShowPackage(packagesButton.getSelection()); new BundleDependencyUpdateJob(false).schedule(200); } }); packagesButton.setSelection(true); toolkit.createLabel(composite, "", SWT.NONE); Label dependenciesLabel = toolkit.createLabel(composite, "Dependencies"); dependenciesLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); toolkit.createLabel(composite, "Incoming"); final Spinner incomingSpinner = new Spinner(composite, SWT.NONE); incomingSpinner.setMinimum(0); incomingSpinner.setIncrement(1); incomingSpinner.setMaximum(20); incomingSpinner.setSelection(1); GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END); // data.widthHint = 20; incomingSpinner.setLayoutData(data); incomingSpinner.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { contentProvider.setIncomingDependencyDegree(incomingSpinner.getSelection()); new BundleDependencyUpdateJob(false).schedule(200); } }); toolkit.createLabel(composite, "Outgoing"); final Spinner outgoingSpinner = new Spinner(composite, SWT.NONE); outgoingSpinner.setMinimum(0); outgoingSpinner.setIncrement(1); outgoingSpinner.setMaximum(20); outgoingSpinner.setSelection(1); data = new GridData(GridData.HORIZONTAL_ALIGN_END); // data.widthHint = 20; outgoingSpinner.setLayoutData(data); outgoingSpinner.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { contentProvider.setOutgoingDependencyDegree(outgoingSpinner.getSelection()); new BundleDependencyUpdateJob(false).schedule(200); } }); Label separator = new Label(configComposite, SWT.NONE); // separator.setBackground(toolkit.getColors().getColor(IFormColors.TB_BG)); separator.setForeground(toolkit.getColors().getColor(IFormColors.H_BOTTOM_KEYLINE1)); data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.FILL_VERTICAL); data.widthHint = 1; separator.setLayoutData(data); toolkit.paintBordersFor(expandableComposite); layout = new GridLayout(2, false); layout.marginHeight = 0; layout.marginWidth = 0; body.setLayout(layout); viewer = new GraphViewer(body, SWT.NONE); viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); viewer.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED); CompositeLayoutAlgorithm layoutAlgorithm = new CompositeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING | LayoutStyles.ENFORCE_BOUNDS, // new LayoutAlgorithm[] { // new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING | LayoutStyles.ENFORCE_BOUNDS), // new HorizontalShift(LayoutStyles.NO_LAYOUT_NODE_RESIZING | LayoutStyles.ENFORCE_BOUNDS) }); searchControl = new SearchControl("Find", getManagedForm()); contentProvider = new BundleDependencyContentProvider(viewer, searchControl); FocusedBundleDependencyLayoutAlgorithm la = new FocusedBundleDependencyLayoutAlgorithm( LayoutStyles.NO_LAYOUT_NODE_RESIZING | LayoutStyles.ENFORCE_BOUNDS, layoutAlgorithm, contentProvider); viewer.setLayoutAlgorithm(la); viewer.setContentProvider(contentProvider); viewer.addSelectionChangedListener(contentProvider); viewer.setFilters(new ViewerFilter[] {}); labelProvider = new BundleDependencyLabelProvider(contentProvider, toolkit); viewer.setLabelProvider(labelProvider); viewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event) { Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement(); if (selection instanceof IBundle) { IBundle bundle = (IBundle) selection; setSelection(bundle); } } }); toolBarManager = sform.getToolBarManager(); toolBarManager.add(searchControl); backAction = new Action("Back") { @Override public void run() { searchControl.getSearchText().setText(history.back()); setEnabled(history.canBack()); forwardAction.setEnabled(history.canForward()); toolBarManager.update(true); new BundleDependencyUpdateJob(true).schedule(); } }; backAction.setImageDescriptor(ImageResource .getImageDescriptor(org.eclipse.ui.internal.browser.ImageResource.IMG_ELCL_NAV_BACKWARD)); backAction.setHoverImageDescriptor(ImageResource.getImageDescriptor(ImageResource.IMG_CLCL_NAV_BACKWARD)); backAction.setDisabledImageDescriptor(ImageResource.getImageDescriptor(ImageResource.IMG_DLCL_NAV_BACKWARD)); backAction.setEnabled(false); toolBarManager.add(backAction); forwardAction = new Action("Forward") { @Override public void run() { searchControl.getSearchText().setText(history.forward()); setEnabled(history.canForward()); backAction.setEnabled(history.canBack()); toolBarManager.update(true); new BundleDependencyUpdateJob(true).schedule(); } }; forwardAction.setImageDescriptor(ImageResource.getImageDescriptor(ImageResource.IMG_ELCL_NAV_FORWARD)); forwardAction.setHoverImageDescriptor(ImageResource.getImageDescriptor(ImageResource.IMG_CLCL_NAV_FORWARD)); forwardAction.setDisabledImageDescriptor(ImageResource.getImageDescriptor(ImageResource.IMG_DLCL_NAV_FORWARD)); forwardAction.setEnabled(false); toolBarManager.add(forwardAction); refreshAction = new Action("Refresh from server", ImageResource.getImageDescriptor(ImageResource.IMG_ELCL_NAV_REFRESH)) { @Override public void run() { IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("Updating bundle status from server", 1); Display.getDefault().asyncExec(new Runnable() { public void run() { clearStatus(); IOSGiFrameworkAdmin admin = (IOSGiFrameworkAdmin) getServer().getOriginal() .loadAdapter(IOSGiFrameworkAdmin.class, monitor); if (admin == null) { IStatus status = EditorUIPlugin.newErrorStatus("Bundle Dependency Graph editor part is not integrated with the runtime."); EditorUIPlugin.log(status); setStatus(status); return ; } try { Map<Long, IBundle> allBundles = admin.getBundles(monitor); refresh(allBundles); } catch (CoreException e) { EditorUIPlugin.log(e); setStatus(e.getStatus()); } } }); monitor.worked(1); } }; try { IRunnableContext context = new ProgressMonitorDialog(Display.getCurrent().getActiveShell()); context.run(true, true, runnable); } catch (InvocationTargetException e1) { e1.printStackTrace(); } catch (InterruptedException e2) { e2.printStackTrace(); } } }; toolBarManager.add(refreshAction); sform.updateToolBar(); initPopupMenu(); searchControl.getSearchText().addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.character == SWT.CR || e.character == SWT.LF) { if (!"type filter text".equals(searchControl.getSearchText().getText())) { history.add(searchControl.getSearchText().getText()); forwardAction.setEnabled(history.canForward()); backAction.setEnabled(history.canBack()); toolBarManager.update(true); new BundleDependencyUpdateJob(true).schedule(); } } } }); searchControl.getSearchText().addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { if ("".equals(searchControl.getSearchText().getText())) { new BundleDependencyUpdateJob(true).schedule(); } } }); } void setSelection(IBundle bundle) { setSelection(bundle.getSymbolicName(), bundle.getVersion()); } private void setSelection(String bundle, String version) { String filterText = bundle + " (" + version + ")"; searchControl.getSearchText().setText(filterText); history.add(filterText); forwardAction.setEnabled(history.canForward()); backAction.setEnabled(history.canBack()); toolBarManager.update(true); new BundleDependencyUpdateJob(true).schedule(); } public AbstractZoomableViewer getZoomableViewer() { return viewer; } private void initPopupMenu() { zoomContributionItem = new ZoomContributionViewItem(this); MenuManager menuMgr = new MenuManager("#PopupMenu"); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fillContextMenu(manager); } }); Menu menu = menuMgr.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, viewer); } void fillContextMenu(IMenuManager manager) { manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); if (!viewer.getSelection().isEmpty()) { manager.add(new Action("Show Bundle Overview") { @Override public void run() { Object obj = ((IStructuredSelection) viewer.getSelection()).getFirstElement(); if (obj instanceof IBundle) { openDependencyPage((IBundle) obj); } } }); manager.add(new Separator()); } manager.add(zoomContributionItem); } @Override public void init(IEditorSite site, IEditorInput input) { super.init(site, input); commandManager = ((ServerEditorPartInput) input).getServerCommandManager(); } public void showDependenciesForBundle(String bundle, String version) { setSelection(bundle, version); } public void openDependencyPage(IBundle bundle) { BundleInformationEditorPage infoPage = openInformationPage(); if (infoPage != null) { commandManager.getServerEditor().setActiveEditor(infoPage); infoPage.showOverviewForBundle(bundle); } } public void refresh(Map<Long, IBundle> bundles) { if (bundles != null && !bundles.equals(viewer.getInput())) { contentProvider.setBundles(bundles); viewer.setInput(bundles.values()); BundleInformationEditorPage infoPage = openInformationPage(); if (infoPage != null) { infoPage.refresh(bundles); } } } private BundleInformationEditorPage openInformationPage() { IEditorPart[] parts = commandManager.getServerEditor().findEditors(getEditorInput()); for (IEditorPart part : parts) { if (part instanceof BundleInformationEditorPage) { return (BundleInformationEditorPage) part; } } return null; } @Override protected void enablePage() { super.enablePage(); setInfoStatus("Click the 'Refresh' button for fetching data from server."); } class BundleDependencyUpdateJob extends Job { final boolean deleteSelection; public BundleDependencyUpdateJob(boolean deleteSelection) { super("Updating Bundle Dependency Graph"); this.deleteSelection = deleteSelection; } @Override protected IStatus run(IProgressMonitor monitor) { Display.getDefault().asyncExec(new Runnable() { public void run() { contentProvider.clearSelection(); if (deleteSelection) { viewer.setSelection(new StructuredSelection()); } viewer.refresh(true); viewer.getGraphControl().applyLayout(); } }); return Status.OK_STATUS; } } }