/******************************************************************************* * Copyright (c) 2015, 2016 Pivotal, Inc. * 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: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.boot.dash.views.properties; import static org.springsource.ide.eclipse.commons.ui.UiUtil.openUrl; import java.util.List; import org.eclipse.jdt.core.IMethod; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; import org.springframework.ide.eclipse.boot.dash.model.BootDashElement; import org.springframework.ide.eclipse.boot.dash.model.requestmappings.RequestMapping; import org.springframework.ide.eclipse.boot.dash.util.Utils; import org.springframework.ide.eclipse.boot.dash.views.RequestMappingLabelProvider; import org.springframework.ide.eclipse.boot.dash.views.RequestMappingsColumn; import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable; import org.springsource.ide.eclipse.commons.livexp.ui.Stylers; import org.springsource.ide.eclipse.commons.ui.SpringUIUtils; /** * Tabbed properties view section for live request mappings * * @author Alex Boyko * @author Kris De Volder */ public class RequestMappingPropertiesSection extends AbstractBdePropertiesSection { private class DoubleClickListener extends MouseAdapter { DoubleClickListener(TableViewer tv) { tv.getTable().addMouseListener(this); } @Override public void mouseDoubleClick(MouseEvent e) { ViewerCell cell = tv.getCell(new Point(e.x, e.y)); if (cell!=null) { Object clicked = cell.getElement(); if (clicked instanceof RequestMapping){ RequestMapping rm = (RequestMapping) clicked; int colIdx = cell.getColumnIndex(); RequestMappingsColumn col = RequestMappingsColumn.values()[colIdx]; switch (col) { case PATH: BootDashElement bde = input.getValue(); String url = Utils.createUrl(bde.getLiveHost(), bde.getLivePort(), rm.getPath()); if (url!=null) { openUrl(url); } break; case SRC: IMethod method = rm.getMethod(); if (method!=null) { SpringUIUtils.openInEditor(method); } default: break; } // MessageDialog.openInformation(page.getShell(), "clickety click!", // "Double-click on : "+ clicked); } } } } private Label labelText; private LiveVariable<BootDashElement> input = new LiveVariable<>(); private static final Object[] NO_ELEMENTS = new Object[0]; private TabbedPropertySheetPage page; private Composite composite; private TableViewer tv; private RequestMappingLabelProvider labelProvider; private Stylers stylers; private ViewerComparator sorter = new ViewerComparator() { @Override public int compare(Viewer viewer, Object e1, Object e2) { if (e1 instanceof RequestMapping && e2 instanceof RequestMapping) { RequestMapping rm1 = (RequestMapping) e1; RequestMapping rm2 = (RequestMapping) e2; int cat1 = getCategory(rm1); int cat2 = getCategory(rm2); if (cat1!=cat2) { return cat1-cat2; } else { return rm1.getPath().compareTo(rm2.getPath()); } } return 0; } private int getCategory(RequestMapping rm) { if (rm.isUserDefined()) { return 0; } else { return 1; } } }; public void createControls(Composite parent, TabbedPropertySheetPage aTabbedPropertySheetPage) { super.createControls(parent, aTabbedPropertySheetPage); this.page = aTabbedPropertySheetPage; composite = getWidgetFactory().createFlatFormComposite(parent); page.getControl().setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_RED)); FormData data; labelText = getWidgetFactory().createLabel(composite, "", SWT.WRAP); //$NON-NLS-1$ data = new FormData(); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); data.top = new FormAttachment(0, ITabbedPropertyConstants.VSPACE); labelText.setLayoutData(data); this.tv = new TableViewer(composite, SWT.BORDER|SWT.FULL_SELECTION|SWT.NO_SCROLL); tv.setContentProvider(new ContentProvider()); tv.setComparator(sorter); // tv.setLabelProvider(labelProvider = new RequestMappingLabelProvider(tv.getTable().getFont(), input)); tv.setInput(input.getValue()); tv.getTable().setHeaderVisible(true); stylers = new Stylers(tv.getTable().getFont()); refreshControlsVisibility(); for (RequestMappingsColumn colType : RequestMappingsColumn.values()) { TableViewerColumn col = new TableViewerColumn(tv, colType.getAlignment()); col.setLabelProvider(new RequestMappingLabelProvider(stylers, input, colType)); TableColumn colWidget = col.getColumn(); colWidget.setText(colType.getLabel()); colWidget.setWidth(colType.getDefaultWidth()); } createContextMenu(tv); new DoubleClickListener(tv); } public void setInput(IWorkbenchPart part, ISelection selection) { super.setInput(part, selection); input.setValue(getBootDashElement()); tv.setInput(getBootDashElement()); } public void refresh() { refreshControlsVisibility(); BootDashElement bde = getBootDashElement(); if (bde == null) { labelText.setText("Select single element in Boot Dashboard to see Request Mappings"); } else if (bde.getLiveRequestMappings() == null) { labelText.setText("'" + bde.getName() + "' must be running with JMX enabled; and actuator 'mappings' endpoint must be enabled to obtain request mappings."); } else { labelText.setText(""); } tv.refresh(); reflow(page); } private void reflow(TabbedPropertySheetPage page) { final Composite target = getReflowTarget(page); if (target!=null) { target.getDisplay().asyncExec(new Runnable() { public void run() { target.layout(true, true); } }); } } private Composite getReflowTarget(TabbedPropertySheetPage page) { return page.getControl().getParent(); // Control c = page.getControl(); // Composite composite = null; // while (c!=null) { // if (c instanceof Composite) { // composite = (Composite) c; // } // c = c.getParent(); // } // return composite; } private void refreshControlsVisibility() { BootDashElement bde = getBootDashElement(); if (bde == null || bde.getLiveRequestMappings() == null) { tv.getControl().setVisible(false); FormData data = new FormData(); data.left = new FormAttachment(0, 0); data.top = new FormAttachment(0, 0); data.right = new FormAttachment(0, 0); data.bottom = new FormAttachment(0, 0); tv.getControl().setLayoutData(data); labelText.setVisible(true); } else { tv.getControl().setVisible(true); FormData data = new FormData(); data.left = new FormAttachment(0, 0); data.top = new FormAttachment(0, ITabbedPropertyConstants.VSPACE); data.right = new FormAttachment(100, 0); data.bottom = new FormAttachment(100, 0); tv.getControl().setLayoutData(data); labelText.setVisible(false); } } @Override public void dispose() { if (labelProvider!=null) { labelProvider.dispose(); labelProvider = null; } if (stylers!=null) { stylers.dispose(); stylers = null; } super.dispose(); } public class ContentProvider implements IStructuredContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { /* * Nothing. Rely on the section refresh mechanism that should refresh the table */ } @Override public Object[] getElements(Object inputElement) { if (inputElement instanceof BootDashElement) { BootDashElement el = (BootDashElement) inputElement; List<RequestMapping> elements = el.getLiveRequestMappings(); if (elements!=null) { return elements.toArray(); } else { //null means we couldn't determine the request mappings. return new Object[] { "'"+el.getName()+"' must be running...", "and the actuator 'mappings' ...", "endpoint must be enabled ...", "to obtain request mappings.", }; } } return NO_ELEMENTS; } } private void createContextMenu(Viewer viewer) { MenuManager contextMenu = new MenuManager("#ViewerMenu"); //$NON-NLS-1$ contextMenu.setRemoveAllWhenShown(true); contextMenu.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager mgr) { fillContextMenu(mgr); } }); Menu menu = contextMenu.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); } private void fillContextMenu(IMenuManager contextMenu) { if (getStructuredSelection().size() == 1) { final RequestMapping rm = (RequestMapping) getStructuredSelection().getFirstElement(); final BootDashElement bde = getBootDashElement(); Action makeDefaultAction = new Action("Make Default") { @Override public void run() { bde.setDefaultRequestMappingPath(rm.getPath()); tv.refresh(); /* * Just refresh doesn't cause repaint for some reason */ tv.getTable().redraw(); } }; makeDefaultAction.setEnabled(!rm.getPath().equals(bde.getDefaultRequestMappingPath())); contextMenu.add(makeDefaultAction); } } private IStructuredSelection getStructuredSelection() { //Watch out, this is not Eclipse 4.4 api: //return tv.getStructuredSelection(); //So do this instead: return (IStructuredSelection) tv.getSelection(); } }