package org.simantics.team.ui; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.util.Collection; import java.util.Iterator; import java.util.Vector; import org.eclipse.jface.action.Action; import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.simantics.Simantics; import org.simantics.db.Operation; import org.simantics.db.Session; import org.simantics.db.UndoContext; import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.service.UndoRedoSupport; import org.simantics.db.service.UndoRedoSupport.ChangeListener; import org.simantics.team.Activator; import org.simantics.team.internal.Images; import org.simantics.utils.ui.dialogs.ShowError; /** * @author Kalle Kondelin */ public class UndoView extends TreeView { @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); //treeViewer.getTree().setLinesVisible(true); //treeViewer.setUseHashlookup(true); //treeViewer.setAutoExpandLevel(3); TreeViewerColumn idColumn = new TreeViewerColumn(treeViewer, SWT.LEFT); TreeViewerColumn dateColumn = new TreeViewerColumn(treeViewer, SWT.LEFT); TreeViewerColumn commentColumn = new TreeViewerColumn(treeViewer, SWT.LEFT); idColumn.setLabelProvider(new IdColumnLabelProvider()); dateColumn.setLabelProvider(new DateColumnLabelProvider()); commentColumn.setLabelProvider(new CommentColumnLabelProvider()); idColumn.getColumn().setText("Id"); idColumn.getColumn().setWidth(20); ad.setColumnData(idColumn.getColumn(), new ColumnWeightData(50, 20)); dateColumn.getColumn().setText("Date"); dateColumn.getColumn().setWidth(20); ad.setColumnData(dateColumn.getColumn(), new ColumnWeightData(50, 40)); commentColumn.getColumn().setText("Comment"); commentColumn.getColumn().setWidth(20); ad.setColumnData(commentColumn.getColumn(), new ColumnWeightData(50, 50)); final UndoContentProvider contentProvider = new UndoContentProvider(Simantics.getSession()); treeViewer.setContentProvider(contentProvider); treeViewer.setInput(this); getViewSite().getActionBars().getToolBarManager().add(new Action("Remove All", Activator.REMOVE_ALL_ICON) { @Override public void run() { contentProvider.removeAll(); } }); getViewSite().getActionBars().getToolBarManager().add(new Action("Get Undo History", Activator.REFRESH_ICON) { @Override public void run() { treeViewer.setContentProvider(contentProvider); } }); new ItemDetailToolTip(treeViewer, treeViewer.getTree(), null); } } abstract class UndoViewElement extends TreeElement { protected Session session; UndoViewElement(Session session) { this.session = session; } protected static final Charset UTF8 = Charset.forName("UTF-8"); protected 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 boolean hasChildren() { return false; } @Override Object[] getChildren() { return new Object[0]; } } class UndoContextElement extends UndoViewElement { protected String name = "Undo"; protected WeakReference contextRef; UndoContextElement(Session session, UndoContext context) { super(session); this.contextRef = new WeakReference(context); } @Override protected Image getIdImage() { return Images.getInstance().OTHER_IMAGE; } @Override protected String getIdText() { String s = toString(); return s.substring(0, Math.min(10, s.length())); } @Override boolean hasChildren() { UndoContext c = contextRef.get(); if (null == c) return false; try { return c.getAll().size() > 0; } catch (DatabaseException e) { Logger.defaultLogError(e); return false; } } @Override public String toString() { UndoContext c = contextRef.get(); if (null == c) return name + "@no context"; return name + "@" + c; } @Override Object[] getChildren() { UndoContext c = contextRef.get(); if (null == c) return new Object[0]; Collection operations; try { operations = c.getAll(); } catch (DatabaseException e) { Logger.defaultLogError(e); return new Object[0]; } if (operations.size() < 1) return new Object[0]; Object[] objects = new Object[operations.size()]; Iterator it = operations.iterator(); int i = operations.size(); while (it.hasNext()) { Operation op = it.next(); objects[--i] = new UndoCombinedElement(session, op); } assert(0==i); return objects; } } class RedoContextElement extends UndoContextElement { RedoContextElement(Session session, UndoContext context) { super(session, context); this.name = "Redo"; } @Override boolean hasChildren() { UndoContext c = contextRef.get(); if (null == c) return false; try { return c.getRedoList().size() > 0; } catch (DatabaseException e) { Logger.defaultLogError(e); return false; } } @Override Object[] getChildren() { UndoContext c = contextRef.get(); if (null == c) return new Object[0]; Collection operations; try { operations = c.getRedoList(); } catch (DatabaseException e) { Logger.defaultLogError(e); operations = null; } if (operations.size() < 1) return new Object[0]; Object[] objects = new Object[operations.size()]; Iterator it = operations.iterator(); int i = operations.size(); while (it.hasNext()) { Operation op = it.next(); objects[--i] = new UndoCombinedElement(session, op); } assert(0 == i); return objects; } } class UndoCombinedElement extends UndoViewElement { private final Operation operation; private final Vector elements = new Vector(); private String comment = null; UndoCombinedElement(Session session, Operation op) { super(session); operation = op; } @Override protected Image getIdImage() { return Images.getInstance().UNDO_IMAGE; } @Override protected String getIdText() { return "" + operation.getId(); } @Override protected String getDateText() { if (elements.size() == 0) getChildren(); if (elements.size() > 0) return elements.firstElement().getDateText(); else return null; } @Override protected String getCommentText() { if (elements.size() == 0) getChildren(); if (elements.size() > 0) return elements.firstElement().getCommentText(); else return null; } @Override boolean hasChildren() { return operation.getOperations().size() > 0; } @Override Object[] getChildren() { Collection ops = operation.getOperations(); final int SIZE = ops.size(); if (SIZE < 1) return new Object[0]; elements.clear(); Iterator it = ops.iterator(); for (int i=0; i