/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.team.ui; import java.util.Map; import java.util.Vector; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.ToolTip; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.ViewPart; import org.simantics.browsing.ui.GraphExplorer; import org.simantics.browsing.ui.graph.impl.SessionContextInputSource; import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver; import org.simantics.browsing.ui.swt.GraphExplorerFactory; import org.simantics.browsing.ui.swt.ViewArgumentUtils; import org.simantics.db.Session; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.db.management.ISessionContextChangedListener; import org.simantics.db.management.ISessionContextProvider; import org.simantics.db.management.SessionContextChangedEvent; import org.simantics.db.service.TeamSupport; import org.simantics.project.ProjectKeys; import org.simantics.team.Utils; import org.simantics.team.internal.Images; import org.simantics.ui.SimanticsUI; import org.simantics.utils.datastructures.disposable.DisposeState; import org.simantics.utils.datastructures.hints.HintListenerAdapter; import org.simantics.utils.datastructures.hints.HintTracker; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintListener; import org.simantics.utils.datastructures.hints.IHintObservable; import org.simantics.utils.datastructures.hints.IHintTracker; import org.simantics.utils.ui.LayoutUtils; /** * @author Kalle Kondelin */ public class StagingView extends ViewPart { public StagingView() { } public class SessionContextProjectTracker extends HintTracker { public SessionContextProjectTracker() { IHintListener activeProjectListener = new HintListenerAdapter() { @Override public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { applySessionContext(getSessionContext()); } }; addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener); } } protected LocalResourceManager resourceManager; protected Composite parent; protected TreeViewer treeViewer; private Map args; private ISessionContextProvider contextProvider; private ISessionContext sessionContext; protected IMemento memento; private IHintTracker sessionContextTracker = new SessionContextProjectTracker(); private DisposeState disposeState = DisposeState.Alive; protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() { @Override public void sessionContextChanged(SessionContextChangedEvent event) { sessionContext = event.getNewValue(); sessionContextTracker.track(sessionContext); } }; protected void setSessionContextTracker(IHintTracker tracker) { this.sessionContextTracker = tracker; } protected Map getViewArguments() { return args; } protected DisposeState getDisposeState() { return disposeState; } public ISessionContext getSessionContext() { return sessionContext; } public ISessionContextProvider getSessionContextProvider() { return contextProvider; } @Override public void createPartControl(Composite parent) { this.parent = parent; this.treeViewer = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION); this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), treeViewer.getTree()); Images.getInstance(JFaceResources.getResources()); TreeColumnLayout ad = new TreeColumnLayout(); parent.setLayout(ad); treeViewer.getTree().setHeaderVisible(true); TreeViewerColumn nameColumn = new TreeViewerColumn(treeViewer, SWT.LEFT); nameColumn.getColumn().setText("Comment"); nameColumn.getColumn().setWidth(200); // TreeViewerColumn typeColumn = new TreeViewerColumn(treeViewer, SWT.LEFT); nameColumn.setLabelProvider(new MyColumnLabelProvider()); // typeColumn.setLabelProvider(new MyColumnLabelProvider()); ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(80, 100)); // typeColumn.getColumn().setText("Comment"); // typeColumn.getColumn().setWidth(20); // ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(20, 120)); createControls(parent); attachToSession(); } /** * Invoked when this viewpart is disposed. Unhooks the view from its * ISessionContextProvider. Overriding is allowed but super.dispose() must * be called. * * @see org.eclipse.ui.part.WorkbenchPart#dispose() */ @Override public void dispose() { disposeState = DisposeState.Disposing; try { if (contextProvider != null) { contextProvider.removeContextChangedListener(contextChangeListener); contextProvider = null; } sessionContextTracker.untrack(); resourceManager.dispose(); resourceManager = null; args = null; sessionContext = null; parent = null; super.dispose(); } finally { disposeState = DisposeState.Disposed; } } @Override public void setFocus() { } @Override public void init(IViewSite site) throws PartInitException { super.init(site); this.args = ViewArgumentUtils.parseViewArguments(this); } @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); this.args = ViewArgumentUtils.parseViewArguments(this); this.memento = memento; } @Override public void saveState(IMemento memento) { if (this.memento != null) { memento.putMemento(this.memento); } } protected final void attachToSession() { // Track active ISessionContext changes contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow()); contextProvider.addContextChangedListener(contextChangeListener); // Perform first-time initialization of the explorer and its input. applySessionContext(contextProvider.getSessionContext()); } private abstract class NameAndDescriptionToolTip extends ToolTip { public NameAndDescriptionToolTip(Control control, int style) { super(control, style, false); } protected abstract Object getModelElement(Event event); /** * Adds logic to only show a tooltip if a meaningful item is under the cursor. */ @Override protected boolean shouldCreateToolTip(Event event) { if (!super.shouldCreateToolTip(event)) return false; Object tableElement = getModelElement(event); return tableElement != null && tableElement instanceof DisplayElement; } @Override protected Composite createToolTipContentArea(Event event, Composite parent) { Object modelElement = getModelElement(event); Image iconImage = null; String nameString = "no name"; if (modelElement instanceof DisplayElement) { iconImage = null; nameString = "name"; } // Create the content area Composite composite = new Composite(parent, SWT.NONE); composite.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_INFO_BACKGROUND)); composite.setLayout(new GridLayout(2, false)); // The title area with the icon (if there is one) and label. Label title = createEntry(composite, iconImage, nameString); // title.setFont(tooltipHeading); GridDataFactory.createFrom((GridData)title.getLayoutData()) .hint(SWT.DEFAULT, SWT.DEFAULT) // .minSize(MIN_TOOLTIP_WIDTH, 1) .applyTo(title); // The description (if there is one) // String descriptionString = "description"; // if (descriptionString != null) // createEntry(composite, null, descriptionString); // Other Content to add addContent(composite, modelElement); return composite; } /** * Adds a line of information to parent. If * icon is not null, an icon is placed on the * left, and then a label with text. * * @param parent * the composite to add the entry to * @param icon * the icon to place next to the text. null for * none. * @param text * the text to display * @return the created label */ protected Label createEntry(Composite parent, Image icon, String text) { if (icon != null) { Label iconLabel = new Label(parent, SWT.NONE); iconLabel.setImage(icon); iconLabel.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_INFO_BACKGROUND)); iconLabel.setData(new GridData()); } Label textLabel = new Label(parent, SWT.WRAP); if(icon == null) { GridDataFactory.generate(textLabel, 2, 1); } else { GridDataFactory.generate(textLabel, 1, 1); } textLabel.setText(text); textLabel.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_INFO_BACKGROUND)); return textLabel; } /** * Adds a line of information to parent. If * icon is not null, an icon is placed on the * left, and then a label with text, which supports using * anchor tags to creates links * * @param parent * the composite to add the entry to * @param icon * the icon to place next to the text. null for * none. * @param text * the text to display * @return the created link */ protected Text createEntryWithText(Composite parent, Image icon, String text) { if (icon != null) { Label iconLabel = new Label(parent, SWT.NONE); iconLabel.setImage(icon); iconLabel.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_INFO_BACKGROUND)); iconLabel.setData(new GridData()); } Text texts = new Text(parent, SWT.READ_ONLY | SWT.MULTI | SWT.V_SCROLL); if(icon == null) { GridDataFactory.generate(texts, 2, 1); } texts.setText(text); texts.setBackground(parent.getDisplay().getSystemColor( SWT.COLOR_INFO_BACKGROUND)); return texts; } protected void addContent(Composite destination, Object modelElement) { } } private class ItemDetailToolTip extends NameAndDescriptionToolTip { private final boolean DEBUG = false; private TreeViewer viewer; private Tree tree; private ItemDetailToolTip(TreeViewer viewer, Tree tree, ViewerFilter filter) { super(tree,NO_RECREATE); this.tree = tree; this.viewer = viewer; this.setHideOnMouseDown(false); } @Override public Point getLocation(Point tipSize, Event event) { // try to position the tooltip at the bottom of the cell ViewerCell cell = viewer.getCell(new Point(event.x, event.y)); if( cell != null ) return tree.toDisplay(event.x,cell.getBounds().y+cell.getBounds().height); return super.getLocation(tipSize, event); } @Override protected Object getToolTipArea(Event event) { // Ensure that the tooltip is hidden when the cell is left return viewer.getCell(new Point(event.x, event.y)); } @Override protected void addContent(Composite destination, Object modelElement) { final DisplayElement item = (DisplayElement)modelElement; if (DEBUG) System.out.println("add content"); String text = null; if (null != item) { text = modelElement.toString(); createEntryWithText(destination, null, text.toString()); } } @Override protected Object getModelElement(Event event) { org.eclipse.swt.widgets.TreeItem treeItem = tree.getItem(new Point(event.x, event.y)); if (treeItem == null) return null; return treeItem.getData(); } } class MyColumnLabelProvider extends ColumnLabelProvider { @Override public void update(ViewerCell cell) { //NodeProxy proxy = (NodeProxy) cell.getElement(); cell.setText("Kraa"); cell.setImage(Images.getInstance().OTHER_IMAGE); } } protected void createControls(final Composite parent) { parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false)); GridDataFactory.fillDefaults().grab(true, true).applyTo(treeViewer.getTree()); treeViewer.setContentProvider(new CommentContentProvider(SimanticsUI.getSession())); treeViewer.setLabelProvider(new LabelProvider() { @Override public Image getImage(Object element) { if (element instanceof ChangeSetElement) return Images.getInstance().CHANGE_SET_IMAGE; else if (element instanceof DisplayElement) return Images.getInstance().DISPLAY_IMAGE; else if (element instanceof ResourceElement) return Images.getInstance().RESOURCE_IMAGE; else if (element instanceof StringElement) return Images.getInstance().STRING_IMAGE; else if (element instanceof UndoCombinedElement) return Images.getInstance().COMBINED_IMAGE; else if (element instanceof RedoContextElement) return Images.getInstance().REDO_IMAGE; else if (element instanceof UndoContextElement) return Images.getInstance().UNDO_IMAGE; else return Images.getInstance().OTHER_IMAGE; } @Override public String getText(Object element) { return element.toString(); } }); //viewer.setSorter(new ViewerSorter()); treeViewer.setInput(this); // getViewSite().getActionBars().getToolBarManager().add(new Action("GetIncoming", Activator.DOOR_IN_ICON) { // @Override // public void run() { // treeViewer.setContentProvider(new IncomingContentProvider(SimanticsUI.getSession(), parent.getShell())); // } // }); new ItemDetailToolTip(treeViewer, treeViewer.getTree(), null); } /** * @param parent * @return */ protected GraphExplorer createExplorerControl(Composite parent) { return GraphExplorerFactory.getInstance().selectionDataResolver(new DefaultSelectionDataResolver()).create(parent); } /** * Invoke this to reinitialize the explorer and reset its input. The input * will be resolved from the specified ISessionContext based on the * {@link SessionContextInputSource} that is currently in use. If the input * is identical to the previous input, nothing will be done. * * @param context */ protected final boolean applySessionContext(ISessionContext context) { // If control is not alive anymore, do nothing. if (disposeState != DisposeState.Alive) return false; this.sessionContext = context; // Start tracking the session context. // This will cause IHintListeners of the sessionContextTracker to fire. // For this we need the above input equality (identity) checking. sessionContextTracker.track(sessionContext); return true; } } class CommentContentProvider implements ITreeContentProvider { protected Viewer viewer = null; private final Vectorcomments = new Vector(); private final Session session; private final TeamSupport teamSupport; CommentContentProvider(Session session) { this.session = session; teamSupport = this.session.getService(TeamSupport.class); try { teamSupport.getComments(Utils.getTeamFolder(), comments); } catch (DatabaseException e) { comments.add(e.getMessage()); } } protected Object[] getElements() { final int SIZE = comments.size(); Object[] objects = new Object[SIZE]; for (int i=0; i