1 package org.simantics.team.ui;
3 import java.lang.reflect.Method;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.HashMap;
7 import java.util.Iterator;
10 import org.eclipse.jface.viewers.ColumnLabelProvider;
11 import org.eclipse.jface.viewers.ITreeContentProvider;
12 import org.eclipse.jface.viewers.Viewer;
13 import org.eclipse.jface.viewers.ViewerCell;
14 import org.eclipse.swt.graphics.Image;
15 import org.simantics.db.ChangeSet;
16 import org.simantics.db.ChangeSetIdentifier;
17 import org.simantics.db.Metadata;
18 import org.simantics.db.ReadGraph;
19 import org.simantics.db.Session;
20 import org.simantics.db.common.CommentMetadata;
21 import org.simantics.db.common.CommitMetadata;
22 import org.simantics.db.common.UndoMetadata;
23 import org.simantics.db.common.request.UniqueRead;
24 import org.simantics.db.common.utils.Logger;
25 import org.simantics.db.exception.DatabaseException;
26 import org.simantics.db.service.ManagementSupport;
27 import org.simantics.db.service.UndoRedoSupport;
28 import org.simantics.team.internal.Images;
29 import org.simantics.utils.ui.SWTUtils;
34 abstract class TreeElement {
35 abstract boolean hasChildren();
36 abstract Object[] getChildren();
37 abstract Image getIdImage();
38 abstract String getIdText();
39 final Image getDateImage() {
42 String getDateText() {
45 final Image getCommentImage() {
48 String getCommentText() {
52 class StringElement extends TreeElement {
53 protected final String name;
54 protected final String value;
55 StringElement(String name, String value) {
60 protected Image getIdImage() {
61 return Images.getInstance().STRING_IMAGE;
64 protected String getIdText() {
65 String s = toString();
66 return s.substring(0, Math.min(40, s.length()));
68 public String toString() {
69 return name + "=" + value;
72 boolean hasChildren() {
76 Object[] getChildren() {
80 class CommentStringElement extends StringElement {
81 CommentStringElement(String name, String value) {
85 protected String getIdText() {
86 return name.substring(0, Math.min(40, name.length()));
89 protected String getCommentText() {
93 class DisplayElement extends TreeElement {
94 protected final String name;
95 protected final String value;
96 DisplayElement(String name, String value) {
101 public String toString() {
102 return name + "=" + value;
105 protected Image getIdImage() {
106 return Images.getInstance().DISPLAY_IMAGE;
109 protected String getIdText() {
113 boolean hasChildren() {
117 Object[] getChildren() {
118 return new Object[0];
124 class ChangeSetDisplayElement extends DisplayElement {
125 private final Session session;
126 private final long csid;
127 private String lazyValue;
128 ChangeSetDisplayElement(String name, Session session, long csid) {
130 this.session = session;
134 public String toString() {
135 return name + "=" + getValue();
139 if (null == lazyValue)
140 lazyValue = fetchChangeSet();
143 private String fetchChangeSet() {
145 Collection<ChangeSet> css = session.sync(new UniqueRead<Collection<ChangeSet>>() {
147 public Collection<ChangeSet> perform(ReadGraph graph) throws DatabaseException {
148 ManagementSupport ms = graph.getService(ManagementSupport.class);
149 return ms.fetchChangeSets(graph, csid, csid);
153 return "<no change set (1)>";
154 return css.iterator().next().toString();
155 } catch (DatabaseException e) {
156 Logger.defaultLogError(e);
158 return "<no change set (2)>";
161 class ChangeSetElement extends TreeElement implements Command {
162 private boolean DEBUG = false;
163 private ChangeSetIdentifier cs;
164 private Map<String, byte[]> metadata = null;
165 private Session session;
166 ChangeSetElement(Session session, long csid) {
167 this.session = session;
168 this.cs = getChangeSetIdentifier(csid);
170 ChangeSetElement(Session session, ChangeSetIdentifier cs) {
172 this.session = session;
174 @SuppressWarnings("unchecked")
175 static <T> T getMetadata(Session session, Map<String, byte[]> data, Class<? extends Metadata> dataClass) {
176 if (null == session || null == data || null == dataClass)
180 Method m = dataClass.getMethod("deserialise", Session.class, byte[].class);
181 byte[] bytes = data.get(dataClass.getName());
183 Object value = m.invoke(null, session, bytes);
186 } catch (RuntimeException e) {
187 Logger.defaultLogError(e);
188 } catch (Exception e) {
189 Logger.defaultLogError(e);
194 public void dumpToSelectedRevision()
195 throws DatabaseException {
198 ManagementSupport ms = session.getService(ManagementSupport.class);
199 long csid = cs.getId();
200 ms.dumpRevision(csid);
202 System.out.println("DEBUG: Dumped change set=" + csid + ".");
205 public void undoToSelectedRevision()
206 throws DatabaseException {
209 UndoRedoSupport us = session.getService(UndoRedoSupport.class);
210 int n = us.undoTo(session, cs.getId());
212 System.out.println("DEBUG: Reverted " + n + " change sets.");
215 public void initUndoListFromSelectedRevision()
216 throws DatabaseException {
219 UndoRedoSupport us = session.getService(UndoRedoSupport.class);
220 int n = us.initUndoListFrom(session, cs.getId());
222 System.out.println("DEBUG: Undo list initialised with " + n + " change sets.");
225 public ChangeSetIdentifier getChangeSetIdentifier() {
228 private ChangeSetIdentifier getChangeSetIdentifier(long id) {
229 ManagementSupport ms = session.getService(ManagementSupport.class);
230 Collection<ChangeSetIdentifier> cids;
232 cids = ms.getChangeSetIdentifiers(id, id);
233 } catch (DatabaseException e) {
234 Logger.defaultLogError(e);
237 Iterator<ChangeSetIdentifier> it = cids.iterator();
238 while (it.hasNext()) {
239 ChangeSetIdentifier cid = it.next();
240 if (cid.getId() == id)
245 private void getMetadata() {
248 else if (null == cs) {
249 metadata = new HashMap<String, byte[]>();
253 metadata = cs.getMetadata();
254 if (null == metadata) {
255 ChangeSetIdentifier csid = getChangeSetIdentifier(cs.getId());
257 metadata = csid.getMetadata();
259 } catch (Exception e) {
260 Logger.defaultLogError(e);
262 if (null == metadata)
263 metadata = new HashMap<String, byte[]>();
265 // private static final Charset UTF8 = Charset.forName("UTF-8");
266 // private String toString(byte[] data) {
269 // CharsetDecoder decoder = UTF8.newDecoder();
270 // ByteBuffer bbuf = ByteBuffer.wrap(data);
274 // cbuf = decoder.decode(bbuf);
275 // s = cbuf.toString();
276 // } catch (CharacterCodingException e) {
281 // .onMalformedInput(CodingErrorAction.REPLACE)
282 // .onUnmappableCharacter(CodingErrorAction.REPLACE)
284 // s = cbuf.toString();
285 // } catch (CharacterCodingException e1) {
286 // return "String conversion error.";
292 public String toString() {
294 return "<no change set>";
296 return "change set " + cs.getId();
299 boolean hasChildren() {
300 if (null == metadata)
302 if (null == cs && metadata.isEmpty())
308 Object[] getChildren() {
309 if (null == metadata)
311 if (null == cs && metadata.isEmpty())
312 return new Object[0];
313 ArrayList<Object> objects = new ArrayList<Object>();
314 if (!metadata.isEmpty()) {
315 objects.add(new CommentStringElement("Metaclass", "Count is " + metadata.size() + "."));
317 CommitMetadata commitMetadata = getMetadata(session, metadata, CommitMetadata.class);
318 if (null != commitMetadata) {
319 if (commitMetadata.opid != 0 && commitMetadata.opid != cs.getId())
320 objects.add(new StringElement("Part of operation", "" + commitMetadata.opid));
323 CommentMetadata commentMetadata = getMetadata(session, metadata, CommentMetadata.class);
324 if (null != commentMetadata)
325 objects.add(new DisplayElement("Comment", commentMetadata.toString()));
327 UndoMetadata undoMetadata = getMetadata(session, metadata, UndoMetadata.class);
328 if (null != undoMetadata) {
329 String header = undoMetadata.getHeader();
330 objects.add(new DisplayElement(header, undoMetadata.toString()));
334 objects.add(new ChangeSetDisplayElement("Change Set", session, cs.getId()));
336 return objects.toArray();
339 return Images.getInstance().CHANGE_SET_IMAGE;
343 return "" + cs.getId();
347 String getDateText() {
348 if (null == metadata)
350 if (null == cs || metadata.isEmpty())
352 CommitMetadata commitMetadata = getMetadata(session, metadata, CommitMetadata.class);
353 if (null != commitMetadata)
354 return commitMetadata.date.toString();
358 String getCommentText() {
359 if (null == metadata)
361 if (null == cs || metadata.isEmpty())
362 return "<no comment>";
363 CommentMetadata commentMetadata = getMetadata(session, metadata, CommentMetadata.class);
364 if (null != commentMetadata) {
365 UndoMetadata undoMetadata = getMetadata(session, metadata, UndoMetadata.class);
366 String t = commentMetadata.toString();
367 if (null == undoMetadata)
370 return undoMetadata.getHeader() + ": " + t;
373 return "<no comment>";
376 abstract class AbstractColumnLabelProvider extends ColumnLabelProvider {
378 class IdColumnLabelProvider extends AbstractColumnLabelProvider {
380 public void update(ViewerCell cell) {
381 Object element = cell.getElement();
382 if (!(element instanceof TreeElement))
385 TreeElement te = (TreeElement)element;
386 String text = te.getIdText();
389 Image image = te.getIdImage();
391 cell.setImage(image);
395 class DateColumnLabelProvider extends AbstractColumnLabelProvider {
397 public void update(ViewerCell cell) {
398 Object element = cell.getElement();
399 if (!(element instanceof TreeElement))
402 TreeElement te = (TreeElement)element;
403 String text = te.getDateText();
406 Image image = te.getDateImage();
408 cell.setImage(image);
412 class CommentColumnLabelProvider extends AbstractColumnLabelProvider {
414 public void update(ViewerCell cell) {
415 Object element = cell.getElement();
416 if (!(element instanceof TreeElement))
419 TreeElement te = (TreeElement)element;
420 String text = te.getCommentText();
423 Image image = te.getCommentImage();
425 cell.setImage(image);
429 abstract class ChangeSetProvider implements ITreeContentProvider, ManagementSupport.ChangeSetListener {
430 static final boolean DEBUG = false;
431 protected final Session session;
432 protected final ManagementSupport managementSupport;
433 private boolean subscribed = false;
434 protected Viewer viewer;
435 ChangeSetProvider(Session session) {
436 this.session = session;
437 this.managementSupport = session.getService(ManagementSupport.class);
440 abstract public Object[] getElements(Object inputElement);
442 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
443 this.viewer = viewer;
447 public void dispose() {
448 managementSupport.cancel(this);
449 this.subscribed = false;
452 public void onChanged(long csid) {
453 if (null != viewer && this.subscribed)
457 public boolean hasChildren(Object element) {
458 if (element instanceof TreeElement)
459 return ((TreeElement)element).hasChildren();
463 public Object getParent(Object element) {
467 public Object[] getChildren(Object parentElement) {
468 if (parentElement instanceof TreeElement)
469 return ((TreeElement)parentElement).getChildren();
473 protected void subscribe() {
476 managementSupport.subscribe(this);
477 this.subscribed = true;
479 protected void refresh() {
482 SWTUtils.asyncExec(viewer.getControl(), new Runnable() {
485 if (!viewer.getControl().isDisposed())