--- /dev/null
+package org.simantics.team.ui;\r
+\r
+import java.lang.reflect.Method;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+\r
+import org.eclipse.jface.viewers.ColumnLabelProvider;\r
+import org.eclipse.jface.viewers.ITreeContentProvider;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.jface.viewers.ViewerCell;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.simantics.db.ChangeSet;\r
+import org.simantics.db.ChangeSetIdentifier;\r
+import org.simantics.db.Metadata;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.common.CommentMetadata;\r
+import org.simantics.db.common.CommitMetadata;\r
+import org.simantics.db.common.UndoMetadata;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.service.ManagementSupport;\r
+import org.simantics.db.service.UndoRedoSupport;\r
+import org.simantics.team.internal.Images;\r
+import org.simantics.utils.ui.SWTUtils;\r
+\r
+public class Common {\r
+\r
+}\r
+abstract class TreeElement {\r
+ abstract boolean hasChildren();\r
+ abstract Object[] getChildren();\r
+ abstract Image getIdImage();\r
+ abstract String getIdText();\r
+ final Image getDateImage() {\r
+ return null;\r
+ }\r
+ String getDateText() {\r
+ return null;\r
+ }\r
+ final Image getCommentImage() {\r
+ return null;\r
+ }\r
+ String getCommentText() {\r
+ return null;\r
+ }\r
+}\r
+class StringElement extends TreeElement {\r
+ protected final String name;\r
+ protected final String value;\r
+ StringElement(String name, String value) {\r
+ this.name = name;\r
+ this.value = value;\r
+ }\r
+ @Override\r
+ protected Image getIdImage() {\r
+ return Images.getInstance().STRING_IMAGE;\r
+ }\r
+ @Override\r
+ protected String getIdText() {\r
+ String s = toString();\r
+ return s.substring(0, Math.min(40, s.length()));\r
+ }\r
+ public String toString() {\r
+ return name + "=" + value;\r
+ }\r
+ @Override\r
+ boolean hasChildren() {\r
+ return false;\r
+ }\r
+ @Override\r
+ Object[] getChildren() {\r
+ return new Object[0];\r
+ }\r
+}\r
+class CommentStringElement extends StringElement {\r
+ CommentStringElement(String name, String value) {\r
+ super(name, value);\r
+ }\r
+ @Override\r
+ protected String getIdText() {\r
+ return name.substring(0, Math.min(40, name.length()));\r
+ }\r
+ @Override\r
+ protected String getCommentText() {\r
+ return value;\r
+ }\r
+}\r
+class DisplayElement extends TreeElement {\r
+ protected final String name;\r
+ protected final String value;\r
+ DisplayElement(String name, String value) {\r
+ this.name = name;\r
+ this.value = value;\r
+ }\r
+ @Override\r
+ public String toString() {\r
+ return name + "=" + value;\r
+ }\r
+ @Override\r
+ protected Image getIdImage() {\r
+ return Images.getInstance().DISPLAY_IMAGE;\r
+ }\r
+ @Override\r
+ protected String getIdText() {\r
+ return name;\r
+ }\r
+ @Override\r
+ boolean hasChildren() {\r
+ return false;\r
+ }\r
+ @Override\r
+ Object[] getChildren() {\r
+ return new Object[0];\r
+ }\r
+ String getValue() {\r
+ return value;\r
+ }\r
+}\r
+class ChangeSetDisplayElement extends DisplayElement {\r
+ private final Session session;\r
+ private final long csid;\r
+ private String lazyValue;\r
+ ChangeSetDisplayElement(String name, Session session, long csid) {\r
+ super(name, "");\r
+ this.session = session;\r
+ this.csid = csid;\r
+ }\r
+ @Override\r
+ public String toString() {\r
+ return name + "=" + getValue();\r
+ }\r
+ @Override\r
+ String getValue() {\r
+ if (null == lazyValue)\r
+ lazyValue = fetchChangeSet();\r
+ return lazyValue;\r
+ }\r
+ private String fetchChangeSet() {\r
+ try {\r
+ Collection<ChangeSet> css = session.sync(new UniqueRead<Collection<ChangeSet>>() {\r
+ @Override\r
+ public Collection<ChangeSet> perform(ReadGraph graph) throws DatabaseException {\r
+ ManagementSupport ms = graph.getService(ManagementSupport.class);\r
+ return ms.fetchChangeSets(graph, csid, csid);\r
+ }\r
+ });\r
+ if (css.size() != 1)\r
+ return "<no change set (1)>";\r
+ return css.iterator().next().toString();\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ return "<no change set (2)>";\r
+ }\r
+}\r
+class ChangeSetElement extends TreeElement implements Command {\r
+ private boolean DEBUG = false;\r
+ private ChangeSetIdentifier cs;\r
+ private Map<String, byte[]> metadata = null;\r
+ private Session session;\r
+ ChangeSetElement(Session session, long csid) {\r
+ this.session = session;\r
+ this.cs = getChangeSetIdentifier(csid);\r
+ }\r
+ ChangeSetElement(Session session, ChangeSetIdentifier cs) {\r
+ this.cs = cs;\r
+ this.session = session;\r
+ }\r
+ @SuppressWarnings("unchecked")\r
+ static <T> T getMetadata(Session session, Map<String, byte[]> data, Class<? extends Metadata> dataClass) {\r
+ if (null == session || null == data || null == dataClass)\r
+ return null;\r
+ T result = null;\r
+ try {\r
+ Method m = dataClass.getMethod("deserialise", Session.class, byte[].class);\r
+ byte[] bytes = data.get(dataClass.getName());\r
+ if (null != bytes) {\r
+ Object value = m.invoke(null, session, bytes);\r
+ result = (T)value;\r
+ }\r
+ } catch (RuntimeException e) {\r
+ Logger.defaultLogError(e);\r
+ } catch (Exception e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ return result;\r
+ }\r
+ @Override\r
+ public void dumpToSelectedRevision()\r
+ throws DatabaseException {\r
+ if (null == cs)\r
+ return;\r
+ ManagementSupport ms = session.getService(ManagementSupport.class);\r
+ long csid = cs.getId();\r
+ ms.dumpRevision(csid);\r
+ if (DEBUG)\r
+ System.out.println("DEBUG: Dumped change set=" + csid + ".");\r
+ }\r
+ @Override\r
+ public void undoToSelectedRevision()\r
+ throws DatabaseException {\r
+ if (null == cs)\r
+ return;\r
+ UndoRedoSupport us = session.getService(UndoRedoSupport.class);\r
+ int n = us.undoTo(session, cs.getId());\r
+ if (DEBUG)\r
+ System.out.println("DEBUG: Reverted " + n + " change sets.");\r
+ }\r
+ @Override\r
+ public void initUndoListFromSelectedRevision()\r
+ throws DatabaseException {\r
+ if (null == cs)\r
+ return;\r
+ UndoRedoSupport us = session.getService(UndoRedoSupport.class);\r
+ int n = us.initUndoListFrom(session, cs.getId());\r
+ if (DEBUG)\r
+ System.out.println("DEBUG: Undo list initialised with " + n + " change sets.");\r
+ }\r
+ @Override\r
+ public ChangeSetIdentifier getChangeSetIdentifier() {\r
+ return cs;\r
+ }\r
+ private ChangeSetIdentifier getChangeSetIdentifier(long id) {\r
+ ManagementSupport ms = session.getService(ManagementSupport.class);\r
+ Collection<ChangeSetIdentifier> cids;\r
+ try {\r
+ cids = ms.getChangeSetIdentifiers(id, id);\r
+ } catch (DatabaseException e) {\r
+ Logger.defaultLogError(e);\r
+ return null;\r
+ }\r
+ Iterator<ChangeSetIdentifier> it = cids.iterator();\r
+ while (it.hasNext()) {\r
+ ChangeSetIdentifier cid = it.next();\r
+ if (cid.getId() == id)\r
+ return cid;\r
+ }\r
+ return null;\r
+ }\r
+ private void getMetadata() {\r
+ if(metadata != null)\r
+ return;\r
+ else if (null == cs) {\r
+ metadata = new HashMap<String, byte[]>();\r
+ return;\r
+ }\r
+ try {\r
+ metadata = cs.getMetadata();\r
+ if (null == metadata) {\r
+ ChangeSetIdentifier csid = getChangeSetIdentifier(cs.getId());\r
+ if (null != csid)\r
+ metadata = csid.getMetadata();\r
+ }\r
+ } catch (Exception e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ if (null == metadata)\r
+ metadata = new HashMap<String, byte[]>();\r
+ }\r
+// private static final Charset UTF8 = Charset.forName("UTF-8");\r
+// private String toString(byte[] data) {\r
+// if (data == null)\r
+// return "null";\r
+// CharsetDecoder decoder = UTF8.newDecoder();\r
+// ByteBuffer bbuf = ByteBuffer.wrap(data);\r
+// CharBuffer cbuf;\r
+// String s = null;\r
+// try {\r
+// cbuf = decoder.decode(bbuf);\r
+// s = cbuf.toString();\r
+// } catch (CharacterCodingException e) {\r
+// bbuf.rewind();\r
+// try {\r
+// cbuf = UTF8\r
+// .newDecoder()\r
+// .onMalformedInput(CodingErrorAction.REPLACE)\r
+// .onUnmappableCharacter(CodingErrorAction.REPLACE)\r
+// .decode(bbuf);\r
+// s = cbuf.toString();\r
+// } catch (CharacterCodingException e1) {\r
+// return "String conversion error.";\r
+// }\r
+// }\r
+// return s;\r
+// }\r
+ @Override\r
+ public String toString() {\r
+ if (null == cs)\r
+ return "<no change set>";\r
+ else\r
+ return "change set " + cs.getId();\r
+ }\r
+ @Override\r
+ boolean hasChildren() {\r
+ if (null == metadata)\r
+ getMetadata();\r
+ if (null == cs && metadata.isEmpty())\r
+ return false;\r
+ else\r
+ return true;\r
+ }\r
+ @Override\r
+ Object[] getChildren() {\r
+ if (null == metadata)\r
+ getMetadata();\r
+ if (null == cs && metadata.isEmpty())\r
+ return new Object[0];\r
+ ArrayList<Object> objects = new ArrayList<Object>();\r
+ if (!metadata.isEmpty()) {\r
+ objects.add(new CommentStringElement("Metaclass", "Count is " + metadata.size() + "."));\r
+ \r
+ CommitMetadata commitMetadata = getMetadata(session, metadata, CommitMetadata.class);\r
+ if (null != commitMetadata) {\r
+ if (commitMetadata.opid != 0 && commitMetadata.opid != cs.getId())\r
+ objects.add(new StringElement("Part of operation", "" + commitMetadata.opid));\r
+ }\r
+ \r
+ CommentMetadata commentMetadata = getMetadata(session, metadata, CommentMetadata.class);\r
+ if (null != commentMetadata)\r
+ objects.add(new DisplayElement("Comment", commentMetadata.toString()));\r
+ \r
+ UndoMetadata undoMetadata = getMetadata(session, metadata, UndoMetadata.class);\r
+ if (null != undoMetadata) {\r
+ String header = undoMetadata.getHeader();\r
+ objects.add(new DisplayElement(header, undoMetadata.toString()));\r
+ }\r
+ }\r
+ if (cs.getId() > 0)\r
+ objects.add(new ChangeSetDisplayElement("Change Set", session, cs.getId()));\r
+ \r
+ return objects.toArray();\r
+ }\r
+ Image getIdImage() {\r
+ return Images.getInstance().CHANGE_SET_IMAGE;\r
+ }\r
+ String getIdText() {\r
+ if (null != cs)\r
+ return "" + cs.getId();\r
+ else\r
+ return "<no id>";\r
+ }\r
+ String getDateText() {\r
+ if (null == metadata)\r
+ getMetadata();\r
+ if (null == cs || metadata.isEmpty())\r
+ return "<no date>";\r
+ CommitMetadata commitMetadata = getMetadata(session, metadata, CommitMetadata.class);\r
+ if (null != commitMetadata)\r
+ return commitMetadata.date.toString();\r
+ else\r
+ return "<no date>";\r
+ }\r
+ String getCommentText() {\r
+ if (null == metadata)\r
+ getMetadata();\r
+ if (null == cs || metadata.isEmpty())\r
+ return "<no comment>";\r
+ CommentMetadata commentMetadata = getMetadata(session, metadata, CommentMetadata.class);\r
+ if (null != commentMetadata) {\r
+ UndoMetadata undoMetadata = getMetadata(session, metadata, UndoMetadata.class);\r
+ String t = commentMetadata.toString();\r
+ if (null == undoMetadata)\r
+ return t;\r
+ else\r
+ return undoMetadata.getHeader() + ": " + t;\r
+ }\r
+ else\r
+ return "<no comment>";\r
+ }\r
+}\r
+abstract class AbstractColumnLabelProvider extends ColumnLabelProvider {\r
+}\r
+class IdColumnLabelProvider extends AbstractColumnLabelProvider {\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ Object element = cell.getElement();\r
+ if (!(element instanceof TreeElement))\r
+ cell.setText("");\r
+ else {\r
+ TreeElement te = (TreeElement)element;\r
+ String text = te.getIdText();\r
+ if (null != text)\r
+ cell.setText(text);\r
+ Image image = te.getIdImage();\r
+ if (null!= image)\r
+ cell.setImage(image);\r
+ }\r
+ }\r
+}\r
+class DateColumnLabelProvider extends AbstractColumnLabelProvider {\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ Object element = cell.getElement();\r
+ if (!(element instanceof TreeElement))\r
+ cell.setText("");\r
+ else {\r
+ TreeElement te = (TreeElement)element;\r
+ String text = te.getDateText();\r
+ if (null != text)\r
+ cell.setText(text);\r
+ Image image = te.getDateImage();\r
+ if (null!= image)\r
+ cell.setImage(image);\r
+ }\r
+ }\r
+}\r
+class CommentColumnLabelProvider extends AbstractColumnLabelProvider {\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ Object element = cell.getElement();\r
+ if (!(element instanceof TreeElement))\r
+ cell.setText("");\r
+ else {\r
+ TreeElement te = (TreeElement)element;\r
+ String text = te.getCommentText();\r
+ if (null != text)\r
+ cell.setText(text);\r
+ Image image = te.getCommentImage();\r
+ if (null!= image)\r
+ cell.setImage(image);\r
+ }\r
+ }\r
+}\r
+abstract class ChangeSetProvider implements ITreeContentProvider, ManagementSupport.ChangeSetListener {\r
+ static final boolean DEBUG = false;\r
+ protected final Session session;\r
+ protected final ManagementSupport managementSupport;\r
+ private boolean subscribed = false;\r
+ protected Viewer viewer;\r
+ ChangeSetProvider(Session session) {\r
+ this.session = session;\r
+ this.managementSupport = session.getService(ManagementSupport.class);\r
+ subscribe();\r
+ }\r
+ abstract public Object[] getElements(Object inputElement);\r
+ @Override\r
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+ this.viewer = viewer;\r
+ subscribe();\r
+ }\r
+ @Override\r
+ public void dispose() {\r
+ managementSupport.cancel(this);\r
+ this.subscribed = false;\r
+ }\r
+ @Override\r
+ public void onChanged(long csid) {\r
+ if (null != viewer && this.subscribed)\r
+ refresh();\r
+ }\r
+ @Override\r
+ public boolean hasChildren(Object element) {\r
+ if (element instanceof TreeElement)\r
+ return ((TreeElement)element).hasChildren();\r
+ return false;\r
+ }\r
+ @Override\r
+ public Object getParent(Object element) {\r
+ return null;\r
+ }\r
+ @Override\r
+ public Object[] getChildren(Object parentElement) {\r
+ if (parentElement instanceof TreeElement)\r
+ return ((TreeElement)parentElement).getChildren();\r
+ else\r
+ return null;\r
+ }\r
+ protected void subscribe() {\r
+ if (this.subscribed)\r
+ return;\r
+ managementSupport.subscribe(this);\r
+ this.subscribed = true;\r
+ }\r
+ protected void refresh() {\r
+ if (viewer == null)\r
+ return;\r
+ SWTUtils.asyncExec(viewer.getControl(), new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ if (!viewer.getControl().isDisposed())\r
+ viewer.refresh();\r
+ }\r
+ });\r
+ }\r
+}\r