package com.netifera.platform.ui.internal.spaces.visualizations; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IContributionManager; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.jface.viewers.ContentViewer; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceAdapter; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TreeItem; import com.netifera.platform.api.model.IEntity; import com.netifera.platform.api.model.IShadowEntity; import com.netifera.platform.api.model.ISpace; import com.netifera.platform.api.model.layers.IGroupLayerProvider; import com.netifera.platform.api.model.layers.ILayerProvider; import com.netifera.platform.api.model.layers.ITreeLayerProvider; import com.netifera.platform.model.FolderEntity; import com.netifera.platform.model.TreeStructureContext; import com.netifera.platform.ui.api.actions.ISpaceAction; import com.netifera.platform.ui.api.inputbar.IInputBarActionProviderService; import com.netifera.platform.ui.dnd.EntityTransfer; import com.netifera.platform.ui.internal.spaces.Activator; import com.netifera.platform.ui.spaces.actions.ActionHover; import com.netifera.platform.ui.spaces.actions.SelectLayersAction; import com.netifera.platform.ui.spaces.tree.SpaceTreeContentProvider; import com.netifera.platform.ui.spaces.tree.SpaceTreeLabelProvider; import com.netifera.platform.ui.spaces.tree.TreeBuilder; import com.netifera.platform.ui.spaces.tree.TreeViewerComparator; import com.netifera.platform.ui.spaces.visualizations.ISpaceVisualization; import com.netifera.platform.ui.util.MouseTracker; import com.netifera.platform.ui.util.TreeAction; public class SpaceTreeVisualization implements ISpaceVisualization { final private ISpace space; private TreeViewer viewer; private SpaceTreeContentProvider contentProvider; public SpaceTreeVisualization(ISpace space) { this.space = space; } public void addContributions(IContributionManager contributions) { contributions.add(new SelectLayersAction() { @Override protected void disableLayer(ILayerProvider provider) { contentProvider.removeLayer(provider); } @Override protected void enableLayer(ILayerProvider provider) { contentProvider.addLayer(provider); } @Override protected List<ILayerProvider> getActiveLayers() { List<ILayerProvider> answer = new ArrayList<ILayerProvider>(); for (ILayerProvider layerProvider: contentProvider.getLayers()) { if (layerProvider instanceof ITreeLayerProvider) answer.add(layerProvider); } return answer; } @Override protected List<ILayerProvider> getLayers() { List<ILayerProvider> answer = new ArrayList<ILayerProvider>(); for (ILayerProvider layerProvider: Activator.getDefault().getModel().getLayerProviders()) { if (layerProvider instanceof ITreeLayerProvider) answer.add(layerProvider); } return answer; } }); contributions.add(new SelectLayersAction("Select Folders", Activator.getDefault().getImageCache().getDescriptor("icons/folders.png")) { @Override protected void disableLayer(ILayerProvider provider) { contentProvider.removeLayer(provider); } @Override protected void enableLayer(ILayerProvider provider) { contentProvider.addLayer(provider); } @Override protected List<ILayerProvider> getActiveLayers() { List<ILayerProvider> answer = new ArrayList<ILayerProvider>(); for (ILayerProvider layerProvider: contentProvider.getLayers()) { if (layerProvider instanceof IGroupLayerProvider) answer.add(layerProvider); } return answer; } @Override protected List<ILayerProvider> getLayers() { List<ILayerProvider> answer = new ArrayList<ILayerProvider>(); for (ILayerProvider layerProvider: Activator.getDefault().getModel().getLayerProviders()) { if (layerProvider instanceof IGroupLayerProvider) answer.add(layerProvider); } return answer; } }); contributions.add(TreeAction.collapseAll(viewer)); contributions.add(TreeAction.expandAll(viewer)); } public ContentViewer createViewer(Composite parent) { viewer = new TreeViewer(parent, SWT.MULTI); // Multi-font support only works in JFace 3.5 and above (specifically, 3.5 M4 and above). // With JFace 3.4, the font information (bold in this example) will be ignored. // FontData[] boldFontData= getModifiedFontData(viewer.getTree().getFont().getFontData(), SWT.BOLD); // Font boldFont = new Font(Display.getCurrent(), boldFontData); final SpaceTreeLabelProvider labelProvider = new SpaceTreeLabelProvider(); // Work around for bug #19 if(isOSX()) { viewer.getTree().setHeaderVisible(true); } contentProvider = new SpaceTreeContentProvider(); viewer.setContentProvider(contentProvider); viewer.setLabelProvider(labelProvider); viewer.setInput(space); viewer.setComparator(new TreeViewerComparator()); /* implement the mouse tracker the action hover handlers*/ final MouseTracker mouseTracker = new MouseTracker(viewer.getTree()) { private PopupDialog informationControl; @Override protected Object getItemAt(Point point) { TreeItem treeItem = viewer.getTree().getItem(point); if (treeItem == null) return null; IShadowEntity targetEntity = (IShadowEntity)treeItem.getData(); IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); List<IShadowEntity> selectionList = selection.toList(); if (selectionList.contains(targetEntity) && selectionList.size()>1) { FolderEntity folder = new FolderEntity(targetEntity.getRealmId(), null, "Selection"); IShadowEntity folderShadow = TreeStructureContext.createRoot(folder); for (IShadowEntity entity: selectionList) ((TreeStructureContext)folderShadow.getStructureContext()).addChild(entity); return folderShadow; } return targetEntity; } @Override protected Rectangle getAreaOfItemAt(Point point) { TreeItem treeItem = viewer.getTree().getItem(point); if (treeItem != null) { Rectangle treeItemArea = treeItem.getBounds(); /* * the TreeItem getBounds rectangle only includes the text. But * getItem(point) returns the rectangle for any point in the * tree row. */ return expandedItemArea(treeItemArea); } return super.getAreaOfItemAt(point); } @Override protected Rectangle getAreaOfSelectedItem() { TreeItem[] selection = viewer.getTree().getSelection(); if(selection != null && selection.length > 0) { return selection[0].getBounds(); } return null; } private Rectangle expandedItemArea(Rectangle itemArea) { return new Rectangle(Math.max(itemArea.x - 12, 2), Math.max(itemArea.y - EPSILON * 2, 0), itemArea.width + 12 * 2, itemArea.height + EPSILON * 2 * 2); } @Override protected void showInformationControl(Shell parent, Point location, Object input, Object item) { informationControl = new ActionHover(parent, location, input, item); informationControl.open(); } @Override protected void hideInformationControl() { if(informationControl != null) { informationControl.close(); } } @Override protected boolean focusInformationControl() { if(informationControl != null) { Shell shell = informationControl.getShell(); if(shell != null) { return shell.setFocus(); } } return false; } @Override protected Rectangle getInformationControlArea() { if(informationControl != null) { Shell shell = informationControl.getShell(); if(shell != null) { return shell.getBounds(); } } return null; } }; viewer.getControl().addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent event) { mouseTracker.stop(); } }); viewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, new Transfer[] {EntityTransfer.getInstance() /*, TextTransfer.getInstance()*/}, new ViewerDropAdapter(viewer) { @Override public boolean performDrop(Object data) { System.out.println("drop "+data); if (data instanceof IEntity[]) { for (IEntity entity: (IEntity[])data) { space.addEntity(entity); } return true; } else if (data instanceof String) { IInputBarActionProviderService actionProvider = Activator.getDefault().getInputBarActionProvider(); for (String line: ((String) data).split("[\\r\\n]+")) { List<IAction> actions = actionProvider.getActions(space.getProbeId(), space.getId(), line); if (actions.size() > 0) { IAction action = actions.get(0); System.out.println("run "+action); if (action instanceof ISpaceAction) ((ISpaceAction) action).setSpace(space); try { action.run(); } catch (Exception e) { e.printStackTrace(); } } } return true; } return false; } @Override public boolean validateDrop(Object target, int op, TransferData type) { setFeedbackEnabled(false); setExpandEnabled(false); setSelectionFeedbackEnabled(false); return EntityTransfer.getInstance().isSupportedType(type) || TextTransfer.getInstance().isSupportedType(type); } }); viewer.addDragSupport(DND.DROP_COPY | DND.DROP_MOVE, new Transfer[] {TextTransfer.getInstance(), EntityTransfer.getInstance()}, new DragSourceAdapter() { @Override public void dragSetData(DragSourceEvent event) { if (EntityTransfer.getInstance().isSupportedType(event.dataType)) { IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); List<IEntity> entities = new ArrayList<IEntity>(); Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { Object o = iterator.next(); if (o instanceof IShadowEntity) { IEntity e = ((IShadowEntity)o).getRealEntity(); // if (!entities.contains(e)) entities.add(e); } } event.data = entities.toArray(new IEntity[entities.size()]); } else if (TextTransfer.getInstance().isSupportedType(event.dataType)) { StringBuffer buffer = new StringBuffer(); IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { buffer.append(labelProvider.getText(iterator.next())); buffer.append("\n"); } event.data = buffer.toString(); } } }); return viewer; } /* private static FontData[] getModifiedFontData(FontData[] originalData, int additionalStyle) { FontData[] styleData = new FontData[originalData.length]; for (int i = 0; i < styleData.length; i++) { FontData base = originalData[i]; styleData[i] = new FontData(base.getName(), base.getHeight(), base.getStyle() | additionalStyle); } return styleData; } */ private boolean isOSX() { final String os = System.getProperty("osgi.os"); return (os != null && os.equals("macosx")); } public void focusEntity(IEntity entity) { TreeBuilder tb = contentProvider.getTreeBuilder(); if (entity instanceof FolderEntity) return; List<IShadowEntity> shadows = tb.getShadows(entity.getId()); IShadowEntity lastShadow = null; for(IShadowEntity s : shadows) { viewer.reveal(s); viewer.expandToLevel(s, 10); lastShadow = s; } if (lastShadow != null) { viewer.setSelection(new StructuredSelection(lastShadow), true); } else { viewer.setSelection(new StructuredSelection(), false); } } }