1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.team.ui;
15 import java.util.Vector;
17 import org.eclipse.jface.layout.GridDataFactory;
18 import org.eclipse.jface.layout.TreeColumnLayout;
19 import org.eclipse.jface.resource.JFaceResources;
20 import org.eclipse.jface.resource.LocalResourceManager;
21 import org.eclipse.jface.viewers.ColumnLabelProvider;
22 import org.eclipse.jface.viewers.ColumnWeightData;
23 import org.eclipse.jface.viewers.ITreeContentProvider;
24 import org.eclipse.jface.viewers.LabelProvider;
25 import org.eclipse.jface.viewers.TreeViewer;
26 import org.eclipse.jface.viewers.TreeViewerColumn;
27 import org.eclipse.jface.viewers.Viewer;
28 import org.eclipse.jface.viewers.ViewerCell;
29 import org.eclipse.jface.viewers.ViewerFilter;
30 import org.eclipse.jface.window.ToolTip;
31 import org.eclipse.swt.SWT;
32 import org.eclipse.swt.graphics.Image;
33 import org.eclipse.swt.graphics.Point;
34 import org.eclipse.swt.layout.GridData;
35 import org.eclipse.swt.layout.GridLayout;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Control;
38 import org.eclipse.swt.widgets.Event;
39 import org.eclipse.swt.widgets.Label;
40 import org.eclipse.swt.widgets.Text;
41 import org.eclipse.swt.widgets.Tree;
42 import org.eclipse.ui.IMemento;
43 import org.eclipse.ui.IViewSite;
44 import org.eclipse.ui.PartInitException;
45 import org.eclipse.ui.part.ViewPart;
46 import org.simantics.Simantics;
47 import org.simantics.browsing.ui.GraphExplorer;
48 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
49 import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;
50 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
51 import org.simantics.browsing.ui.swt.ViewArgumentUtils;
52 import org.simantics.db.Session;
53 import org.simantics.db.exception.DatabaseException;
54 import org.simantics.db.management.ISessionContext;
55 import org.simantics.db.management.ISessionContextChangedListener;
56 import org.simantics.db.management.ISessionContextProvider;
57 import org.simantics.db.management.SessionContextChangedEvent;
58 import org.simantics.db.service.TeamSupport;
59 import org.simantics.project.ProjectKeys;
60 import org.simantics.team.Utils;
61 import org.simantics.team.internal.Images;
62 import org.simantics.ui.SimanticsUI;
63 import org.simantics.utils.datastructures.disposable.DisposeState;
64 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
65 import org.simantics.utils.datastructures.hints.HintTracker;
66 import org.simantics.utils.datastructures.hints.IHintContext.Key;
67 import org.simantics.utils.datastructures.hints.IHintListener;
68 import org.simantics.utils.datastructures.hints.IHintObservable;
69 import org.simantics.utils.datastructures.hints.IHintTracker;
70 import org.simantics.utils.ui.LayoutUtils;
73 * @author Kalle Kondelin
75 public class StagingView extends ViewPart {
77 public StagingView() {
80 public class SessionContextProjectTracker extends HintTracker {
81 public SessionContextProjectTracker() {
82 IHintListener activeProjectListener = new HintListenerAdapter() {
84 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
85 applySessionContext(getSessionContext());
88 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
92 protected LocalResourceManager resourceManager;
93 protected Composite parent;
94 protected TreeViewer treeViewer;
95 private Map<String, String> args;
96 private ISessionContextProvider contextProvider;
97 private ISessionContext sessionContext;
98 protected IMemento memento;
99 private IHintTracker sessionContextTracker = new SessionContextProjectTracker();
100 private DisposeState disposeState = DisposeState.Alive;
102 protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
104 public void sessionContextChanged(SessionContextChangedEvent event) {
105 sessionContext = event.getNewValue();
106 sessionContextTracker.track(sessionContext);
110 protected void setSessionContextTracker(IHintTracker tracker) {
111 this.sessionContextTracker = tracker;
114 protected Map<String, String> getViewArguments() {
118 protected DisposeState getDisposeState() {
122 public ISessionContext getSessionContext() {
123 return sessionContext;
126 public ISessionContextProvider getSessionContextProvider() {
127 return contextProvider;
131 public void createPartControl(Composite parent) {
132 this.parent = parent;
133 this.treeViewer = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION);
134 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), treeViewer.getTree());
135 Images.getInstance(JFaceResources.getResources());
136 TreeColumnLayout ad = new TreeColumnLayout();
137 parent.setLayout(ad);
138 treeViewer.getTree().setHeaderVisible(true);
139 TreeViewerColumn nameColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);
140 nameColumn.getColumn().setText("Comment");
141 nameColumn.getColumn().setWidth(200);
142 // TreeViewerColumn typeColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);
144 nameColumn.setLabelProvider(new MyColumnLabelProvider());
145 // typeColumn.setLabelProvider(new MyColumnLabelProvider());
147 ad.setColumnData(nameColumn.getColumn(), new ColumnWeightData(80, 100));
148 // typeColumn.getColumn().setText("Comment");
149 // typeColumn.getColumn().setWidth(20);
150 // ad.setColumnData(typeColumn.getColumn(), new ColumnWeightData(20, 120));
152 createControls(parent);
158 * Invoked when this viewpart is disposed. Unhooks the view from its
159 * ISessionContextProvider. Overriding is allowed but super.dispose() must
162 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
165 public void dispose() {
166 disposeState = DisposeState.Disposing;
168 if (contextProvider != null) {
169 contextProvider.removeContextChangedListener(contextChangeListener);
170 contextProvider = null;
172 sessionContextTracker.untrack();
173 resourceManager.dispose();
174 resourceManager = null;
176 sessionContext = null;
180 disposeState = DisposeState.Disposed;
185 public void setFocus() {
190 public void init(IViewSite site) throws PartInitException {
192 this.args = ViewArgumentUtils.parseViewArguments(this);
196 public void init(IViewSite site, IMemento memento) throws PartInitException {
197 super.init(site, memento);
198 this.args = ViewArgumentUtils.parseViewArguments(this);
199 this.memento = memento;
203 public void saveState(IMemento memento) {
204 if (this.memento != null) {
205 memento.putMemento(this.memento);
209 protected final void attachToSession() {
210 // Track active ISessionContext changes
211 contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
212 contextProvider.addContextChangedListener(contextChangeListener);
214 // Perform first-time initialization of the explorer and its input.
215 applySessionContext(contextProvider.getSessionContext());
218 private abstract class NameAndDescriptionToolTip extends ToolTip {
219 public NameAndDescriptionToolTip(Control control, int style) {
220 super(control, style, false);
223 protected abstract Object getModelElement(Event event);
226 * Adds logic to only show a tooltip if a meaningful item is under the cursor.
229 protected boolean shouldCreateToolTip(Event event) {
230 if (!super.shouldCreateToolTip(event))
232 Object tableElement = getModelElement(event);
233 return tableElement != null && tableElement instanceof DisplayElement;
237 protected Composite createToolTipContentArea(Event event, Composite parent) {
238 Object modelElement = getModelElement(event);
240 Image iconImage = null;
241 String nameString = "no name";
243 if (modelElement instanceof DisplayElement) {
248 // Create the content area
249 Composite composite = new Composite(parent, SWT.NONE);
250 composite.setBackground(parent.getDisplay().getSystemColor(
251 SWT.COLOR_INFO_BACKGROUND));
252 composite.setLayout(new GridLayout(2, false));
254 // The title area with the icon (if there is one) and label.
255 Label title = createEntry(composite, iconImage, nameString);
256 // title.setFont(tooltipHeading);
257 GridDataFactory.createFrom((GridData)title.getLayoutData())
258 .hint(SWT.DEFAULT, SWT.DEFAULT)
259 // .minSize(MIN_TOOLTIP_WIDTH, 1)
262 // The description (if there is one)
263 // String descriptionString = "description";
264 // if (descriptionString != null)
265 // createEntry(composite, null, descriptionString);
267 // Other Content to add
268 addContent(composite, modelElement);
274 * Adds a line of information to <code>parent</code>. If
275 * <code>icon</code> is not <code>null</code>, an icon is placed on the
276 * left, and then a label with <code>text</code>.
279 * the composite to add the entry to
281 * the icon to place next to the text. <code>null</code> for
284 * the text to display
285 * @return the created label
287 protected Label createEntry(Composite parent, Image icon, String text) {
289 Label iconLabel = new Label(parent, SWT.NONE);
290 iconLabel.setImage(icon);
291 iconLabel.setBackground(parent.getDisplay().getSystemColor(
292 SWT.COLOR_INFO_BACKGROUND));
293 iconLabel.setData(new GridData());
296 Label textLabel = new Label(parent, SWT.WRAP);
299 GridDataFactory.generate(textLabel, 2, 1);
301 GridDataFactory.generate(textLabel, 1, 1);
304 textLabel.setText(text);
305 textLabel.setBackground(parent.getDisplay().getSystemColor(
306 SWT.COLOR_INFO_BACKGROUND));
311 * Adds a line of information to <code>parent</code>. If
312 * <code>icon</code> is not <code>null</code>, an icon is placed on the
313 * left, and then a label with <code>text</code>, which supports using
314 * anchor tags to creates links
317 * the composite to add the entry to
319 * the icon to place next to the text. <code>null</code> for
322 * the text to display
323 * @return the created link
325 protected Text createEntryWithText(Composite parent, Image icon, String text) {
327 Label iconLabel = new Label(parent, SWT.NONE);
328 iconLabel.setImage(icon);
329 iconLabel.setBackground(parent.getDisplay().getSystemColor(
330 SWT.COLOR_INFO_BACKGROUND));
331 iconLabel.setData(new GridData());
333 Text texts = new Text(parent, SWT.READ_ONLY | SWT.MULTI | SWT.V_SCROLL);
335 GridDataFactory.generate(texts, 2, 1);
338 texts.setBackground(parent.getDisplay().getSystemColor(
339 SWT.COLOR_INFO_BACKGROUND));
343 protected void addContent(Composite destination, Object modelElement) {
347 private class ItemDetailToolTip extends NameAndDescriptionToolTip {
348 private final boolean DEBUG = false;
349 private TreeViewer viewer;
351 private ItemDetailToolTip(TreeViewer viewer, Tree tree, ViewerFilter filter) {
352 super(tree,NO_RECREATE);
354 this.viewer = viewer;
355 this.setHideOnMouseDown(false);
358 public Point getLocation(Point tipSize, Event event) {
359 // try to position the tooltip at the bottom of the cell
360 ViewerCell cell = viewer.getCell(new Point(event.x, event.y));
362 return tree.toDisplay(event.x,cell.getBounds().y+cell.getBounds().height);
363 return super.getLocation(tipSize, event);
366 protected Object getToolTipArea(Event event) {
367 // Ensure that the tooltip is hidden when the cell is left
368 return viewer.getCell(new Point(event.x, event.y));
371 protected void addContent(Composite destination, Object modelElement) {
372 final DisplayElement item = (DisplayElement)modelElement;
374 System.out.println("add content");
377 text = modelElement.toString();
378 createEntryWithText(destination, null, text.toString());
382 protected Object getModelElement(Event event) {
383 org.eclipse.swt.widgets.TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
384 if (treeItem == null)
386 return treeItem.getData();
389 class MyColumnLabelProvider extends ColumnLabelProvider {
391 public void update(ViewerCell cell) {
392 //NodeProxy proxy = (NodeProxy) cell.getElement();
393 cell.setText("Kraa");
394 cell.setImage(Images.getInstance().OTHER_IMAGE);
397 protected void createControls(final Composite parent) {
398 parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false));
399 GridDataFactory.fillDefaults().grab(true, true).applyTo(treeViewer.getTree());
400 treeViewer.setContentProvider(new CommentContentProvider(Simantics.getSession()));
401 treeViewer.setLabelProvider(new LabelProvider() {
403 public Image getImage(Object element) {
404 if (element instanceof ChangeSetElement)
405 return Images.getInstance().CHANGE_SET_IMAGE;
406 else if (element instanceof DisplayElement)
407 return Images.getInstance().DISPLAY_IMAGE;
408 else if (element instanceof ResourceElement)
409 return Images.getInstance().RESOURCE_IMAGE;
410 else if (element instanceof StringElement)
411 return Images.getInstance().STRING_IMAGE;
412 else if (element instanceof UndoCombinedElement)
413 return Images.getInstance().COMBINED_IMAGE;
414 else if (element instanceof RedoContextElement)
415 return Images.getInstance().REDO_IMAGE;
416 else if (element instanceof UndoContextElement)
417 return Images.getInstance().UNDO_IMAGE;
419 return Images.getInstance().OTHER_IMAGE;
422 public String getText(Object element) {
423 return element.toString();
426 //viewer.setSorter(new ViewerSorter());
427 treeViewer.setInput(this);
428 // getViewSite().getActionBars().getToolBarManager().add(new Action("GetIncoming", Activator.DOOR_IN_ICON) {
430 // public void run() {
431 // treeViewer.setContentProvider(new IncomingContentProvider(Simantics.getSession(), parent.getShell()));
434 new ItemDetailToolTip(treeViewer, treeViewer.getTree(), null);
441 protected GraphExplorer createExplorerControl(Composite parent) {
442 return GraphExplorerFactory.getInstance().selectionDataResolver(new DefaultSelectionDataResolver()).create(parent);
446 * Invoke this to reinitialize the explorer and reset its input. The input
447 * will be resolved from the specified ISessionContext based on the
448 * {@link SessionContextInputSource} that is currently in use. If the input
449 * is identical to the previous input, nothing will be done.
453 protected final boolean applySessionContext(ISessionContext context) {
454 // If control is not alive anymore, do nothing.
455 if (disposeState != DisposeState.Alive)
458 this.sessionContext = context;
460 // Start tracking the session context.
461 // This will cause IHintListeners of the sessionContextTracker to fire.
462 // For this we need the above input equality (identity) checking.
463 sessionContextTracker.track(sessionContext);
467 class CommentContentProvider implements ITreeContentProvider {
468 protected Viewer viewer = null;
469 private final Vector<String >comments = new Vector<String>();
470 private final Session session;
471 private final TeamSupport teamSupport;
472 CommentContentProvider(Session session) {
473 this.session = session;
474 teamSupport = this.session.getService(TeamSupport.class);
476 teamSupport.getComments(Utils.getTeamFolder(), comments);
477 } catch (DatabaseException e) {
478 comments.add(e.getMessage());
481 protected Object[] getElements() {
482 final int SIZE = comments.size();
483 Object[] objects = new Object[SIZE];
484 for (int i=0; i<SIZE; ++i)
485 objects[i] = new StagingContextElement(i, comments.get(i));
489 public void dispose() {
493 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
494 this.viewer = viewer;
497 public Object[] getElements(Object inputElement) {
498 return getElements();
501 public Object[] getChildren(Object parentElement) {
502 if (parentElement instanceof TreeElement)
503 return ((TreeElement)parentElement).getChildren();
508 public Object getParent(Object childElement) {
512 public boolean hasChildren(Object element) {
513 if (element instanceof TreeElement)
514 return ((TreeElement)element).hasChildren();
519 abstract class StagingViewElement extends TreeElement {
520 StagingViewElement() {
523 boolean hasChildren() {
527 Object[] getChildren() {
528 return new Object[0];
532 class StagingContextElement extends StagingViewElement {
533 protected String name = "Staging";
534 private final String comment;
535 StagingContextElement(int index, String comment) {
536 this.comment = comment;
539 protected Image getIdImage() {
540 return Images.getInstance().OTHER_IMAGE;
543 protected String getIdText() {
544 String s = toString();
545 return s.substring(0, Math.min(10, s.length()));
548 public String toString() {