X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.team.ui%2Fsrc%2Forg%2Fsimantics%2Fteam%2Fui%2FStagingView.java;fp=bundles%2Forg.simantics.team.ui%2Fsrc%2Forg%2Fsimantics%2Fteam%2Fui%2FStagingView.java;h=231d54d50f910f510ff290edcdfb8ac5c2bfb971;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.team.ui/src/org/simantics/team/ui/StagingView.java b/bundles/org.simantics.team.ui/src/org/simantics/team/ui/StagingView.java new file mode 100644 index 000000000..231d54d50 --- /dev/null +++ b/bundles/org.simantics.team.ui/src/org/simantics/team/ui/StagingView.java @@ -0,0 +1,550 @@ +/******************************************************************************* + * 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