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