-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.debug.ui;\r
-\r
-import java.io.File;\r
-import java.io.FileNotFoundException;\r
-import java.io.IOException;\r
-import java.lang.reflect.Array;\r
-import java.net.URI;\r
-import java.net.URISyntaxException;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Comparator;\r
-import java.util.HashMap;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.UUID;\r
-import java.util.concurrent.CopyOnWriteArrayList;\r
-\r
-import org.eclipse.core.runtime.Assert;\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.eclipse.core.runtime.IPath;\r
-import org.eclipse.core.runtime.Path;\r
-import org.eclipse.jface.action.IStatusLineManager;\r
-import org.eclipse.jface.dialogs.Dialog;\r
-import org.eclipse.jface.dialogs.IDialogConstants;\r
-import org.eclipse.jface.dialogs.IDialogSettings;\r
-import org.eclipse.jface.dialogs.IInputValidator;\r
-import org.eclipse.jface.dialogs.InputDialog;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.resource.ColorDescriptor;\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.SWTError;\r
-import org.eclipse.swt.browser.Browser;\r
-import org.eclipse.swt.browser.LocationAdapter;\r
-import org.eclipse.swt.browser.LocationEvent;\r
-import org.eclipse.swt.dnd.DND;\r
-import org.eclipse.swt.dnd.DropTarget;\r
-import org.eclipse.swt.dnd.DropTargetAdapter;\r
-import org.eclipse.swt.dnd.DropTargetEvent;\r
-import org.eclipse.swt.dnd.TextTransfer;\r
-import org.eclipse.swt.dnd.Transfer;\r
-import org.eclipse.swt.events.DisposeEvent;\r
-import org.eclipse.swt.events.DisposeListener;\r
-import org.eclipse.swt.events.FocusEvent;\r
-import org.eclipse.swt.events.FocusListener;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.ModifyEvent;\r
-import org.eclipse.swt.events.ModifyListener;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.events.SelectionListener;\r
-import org.eclipse.swt.graphics.Color;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.RGB;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Button;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Label;\r
-import org.eclipse.swt.widgets.Text;\r
-import org.eclipse.ui.IWorkbenchSite;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.Databoard;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.serialization.Serializer;\r
-import org.simantics.databoard.type.ArrayType;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.type.StringType;\r
-import org.simantics.databoard.util.ObjectUtils;\r
-import org.simantics.db.AsyncRequestProcessor;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.Statement;\r
-import org.simantics.db.VirtualGraph;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.common.ResourceArray;\r
-import org.simantics.db.common.procedure.adapter.ProcedureAdapter;\r
-import org.simantics.db.common.request.Queries;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.common.request.WriteRequest;\r
-import org.simantics.db.common.uri.ResourceToPossibleURI;\r
-import org.simantics.db.common.utils.ListUtils;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.common.utils.OrderedSetUtils;\r
-import org.simantics.db.event.ChangeEvent;\r
-import org.simantics.db.event.ChangeListener;\r
-import org.simantics.db.exception.AdaptionException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ResourceNotFoundException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.layer0.adapter.StringModifier;\r
-import org.simantics.db.layer0.variable.RVI;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.db.service.ClusteringSupport;\r
-import org.simantics.db.service.GraphChangeListenerSupport;\r
-import org.simantics.db.service.SerialisationSupport;\r
-import org.simantics.db.service.VirtualGraphSupport;\r
-import org.simantics.db.service.XSupport;\r
-import org.simantics.debug.ui.internal.Activator;\r
-import org.simantics.debug.ui.internal.DebugUtils;\r
-import org.simantics.debug.ui.internal.HashMultiMap;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.ui.dnd.LocalObjectTransfer;\r
-import org.simantics.ui.dnd.ResourceReferenceTransfer;\r
-import org.simantics.ui.dnd.ResourceTransferUtils;\r
-import org.simantics.ui.utils.ResourceAdaptionUtils;\r
-import org.simantics.utils.Container;\r
-import org.simantics.utils.FileUtils;\r
-import org.simantics.utils.datastructures.BijectionMap;\r
-import org.simantics.utils.datastructures.Callback;\r
-import org.simantics.utils.strings.AlphanumComparator;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-import org.simantics.utils.ui.PathUtils;\r
-import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
-\r
-\r
-public class GraphDebugger extends Composite {\r
-\r
- public interface HistoryListener {\r
- void historyChanged();\r
- }\r
-\r
- private static final String STATEMENT_PART_SEPARATOR = ",";\r
- private final static String DEFAULT_DEBUGGER_CSS_FILE = "debugger.css";\r
- private final static String DEFAULT_DEBUGGER_CSS_PATH = "css/" + DEFAULT_DEBUGGER_CSS_FILE;\r
-\r
- private static int RESOURCE_NAME_MAX_LENGTH = 1000;\r
- private static int RESOURCE_VALUE_MAX_SIZE = 16384;\r
-\r
- private final LocalResourceManager resourceManager;\r
-\r
- private String cssPath;\r
-\r
- private Browser browser;\r
- private final ColorDescriptor green = ColorDescriptor.createFrom(new RGB(0x57, 0xbc, 0x95));\r
-\r
- private final boolean displayClusters = true;\r
-\r
- private final BijectionMap<String, Resource> links = new BijectionMap<String, Resource>();\r
- private final LinkedList<Resource> backHistory = new LinkedList<Resource>();\r
- private final LinkedList<Resource> forwardHistory = new LinkedList<Resource>();\r
- private Resource currentElement = null;\r
-\r
- /**\r
- * The Session used to access the graph. Received from outside of this\r
- * class and therefore it is not disposed here, just used.\r
- */\r
- private final Session session;\r
-\r
- private final CopyOnWriteArrayList<HistoryListener> historyListeners = new CopyOnWriteArrayList<HistoryListener>();\r
-\r
- private final AsyncRequestProcessor updater;\r
-\r
- protected Layer0 L0;\r
-\r
- protected IWorkbenchSite site;\r
-\r
- private final ChangeListener changeListener = new ChangeListener() {\r
- @Override\r
- public void graphChanged(ChangeEvent e) {\r
- // This makes sure that the transaction for updating this\r
- // GraphDebugger get executed in a serialized fashion.\r
- updater.asyncRequest(new ReadRequest() {\r
-\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- updateContent(graph, currentElement);\r
- }\r
-\r
- });\r
-\r
- }\r
- };\r
-\r
- /**\r
- * @param parent\r
- * @param style\r
- * @param session\r
- * @param resource the initial resource to debug or <code>null</code> for\r
- * initially blank UI.\r
- * @param site the workbench site that contains this debugger, for workbench\r
- * service access\r
- */\r
- public GraphDebugger(Composite parent, int style, final Session session, Resource resource, IWorkbenchSite site) {\r
- this(parent, style, session, resource);\r
- this.site = site;\r
- }\r
-\r
- /**\r
- * @param parent\r
- * @param style\r
- * @param session\r
- * @param resource the initial resource to debug or <code>null</code> for\r
- * initially blank UI.\r
- */\r
- public GraphDebugger(Composite parent, int style, final Session session, Resource resource) {\r
- super(parent, style);\r
- Assert.isNotNull(session, "session is null");\r
- this.session = session;\r
- this.currentElement = resource;\r
- this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);\r
-\r
- updater = session;//.getService(MergingGraphRequestProcessor.class);\r
-\r
- initializeCSS();\r
-\r
- addDisposeListener(new DisposeListener() {\r
- @Override\r
- public void widgetDisposed(DisposeEvent e) {\r
- GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);\r
- support.removeListener(changeListener);\r
- }\r
- });\r
- }\r
-\r
- /**\r
- * When given to setStatus, indicates that the message shouldn't be touched\r
- * since <code>null</code> has a different meaning.\r
- */\r
- private static final String DONT_TOUCH = "DONT_TOUCH";\r
-\r
- protected void setStatus(String message, String error) {\r
- IStatusLineManager status = WorkbenchUtils.getStatusLine(site);\r
- if (status != null) {\r
- if (message != DONT_TOUCH)\r
- status.setMessage(message);\r
- if (error != DONT_TOUCH)\r
- status.setErrorMessage(error);\r
- }\r
- }\r
-\r
- public void defaultInitializeUI() {\r
- setLayout(new GridLayout(2, false));\r
- setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
-\r
- createResourceText(this);\r
- createDropLabel(this);\r
- createBrowser(this);\r
-\r
- }\r
-\r
- protected void initializeCSS() {\r
- // Extract default css to a temporary location if necessary.\r
- try {\r
- IPath absolutePath = PathUtils.getAbsolutePath(Activator.PLUGIN_ID, DEFAULT_DEBUGGER_CSS_PATH);\r
- if (absolutePath != null) {\r
- cssPath = absolutePath.toFile().toURI().toString();\r
- } else {\r
- File tempDir = FileUtils.getOrCreateTemporaryDirectory(false);\r
- File css = new File(tempDir, DEFAULT_DEBUGGER_CSS_FILE);\r
- if (!css.exists()) {\r
- URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(DEFAULT_DEBUGGER_CSS_PATH), null);\r
- if (url == null)\r
- throw new FileNotFoundException("Could not find '" + DEFAULT_DEBUGGER_CSS_PATH + "' in bundle '" + Activator.PLUGIN_ID + "'");\r
- cssPath = FileUtils.copyResource(url, css, true).toURI().toString();\r
- } else {\r
- cssPath = css.toURI().toString();\r
- }\r
- }\r
- } catch (IOException e) {\r
- // CSS extraction failed, let's just live without it then.\r
- ErrorLogger.defaultLogWarning(e);\r
- }\r
- }\r
-\r
- private static final String PROMPT_TEXT = "Enter resource ID (RID) or URI";\r
-\r
- public void createResourceText(final Composite parent) {\r
- final Text text = new Text(parent, SWT.BORDER);\r
- text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));\r
- text.setText(PROMPT_TEXT);\r
- GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(text);\r
- \r
- text.addFocusListener(new FocusListener() { \r
- @Override\r
- public void focusLost(FocusEvent e) {\r
- if (text.getText().trim().equals("")) {\r
- text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));\r
- text.setText(PROMPT_TEXT);\r
- }\r
- }\r
- @Override\r
- public void focusGained(FocusEvent e) {\r
- if (text.getText().trim().equals(PROMPT_TEXT)) {\r
- text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK));\r
- text.setText("");\r
- }\r
- text.selectAll();\r
- }\r
- });\r
- text.addKeyListener(new KeyAdapter() {\r
- @Override\r
- public void keyPressed(KeyEvent e) {\r
- if (e.keyCode == SWT.CR) {\r
- String input = text.getText();\r
- setLookupInput(input);\r
- }\r
- }\r
- });\r
-\r
- final Button button = new Button(parent, SWT.FLAT);\r
- button.setText("&Lookup");\r
- button.setEnabled(false);\r
- GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo(button);\r
-\r
- text.addKeyListener(new KeyAdapter() {\r
- \r
- @Override\r
- public void keyPressed(KeyEvent e) {\r
- if (e.keyCode == 13) {\r
- String input = text.getText();\r
- setLookupInput(input);\r
- button.setFocus();\r
- }\r
- }\r
- });\r
- \r
- button.addSelectionListener(new SelectionListener() {\r
- @Override\r
- public void widgetDefaultSelected(SelectionEvent e) {\r
- widgetSelected(e);\r
- }\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- String input = text.getText();\r
- setLookupInput(input);\r
- }\r
- });\r
- \r
- text.addModifyListener(new ModifyListener() {\r
- @Override\r
- public void modifyText(ModifyEvent e) {\r
- String input = text.getText().trim();\r
- if (!input.equals(PROMPT_TEXT) && !input.equals(""))\r
- button.setEnabled(true);\r
- else\r
- button.setEnabled(false);\r
- }\r
- });\r
- }\r
-\r
- public void setLookupInput(String input) {\r
- // There's no harm in trimming out spaces from both ends of the input.\r
- input = input.trim();\r
-\r
- SerialisationSupport support = session.getService(SerialisationSupport.class);\r
- if (input.startsWith("$")) {\r
- try {\r
- Resource r = support.getResource(Long.parseLong(input.substring(1)));\r
- changeLocation(r);\r
- } catch (NumberFormatException e1) {\r
- // Ignore, may happen for crap input\r
- setStatus(DONT_TOUCH, "Invalid '$'-prefixed input, expected resource ID");\r
- } catch (Exception e1) {\r
- ErrorLogger.defaultLogError(e1);\r
- setStatus(DONT_TOUCH, "Resource ID lookup failed. See Error Log.");\r
- }\r
- return;\r
- }\r
-\r
- String[] parts = input.split("-");\r
-\r
- if (parts.length == 1) {\r
- try {\r
- int resourceKey = Integer.parseInt(parts[0].trim());\r
- Resource r = support.getResource(resourceKey);\r
- // Some validation, not enough though\r
- ClusteringSupport cs = session.getService(ClusteringSupport.class);\r
- long cluster = cs.getCluster(r);\r
- if(cluster > 0) {\r
- changeLocation(r);\r
- }\r
- } catch (NumberFormatException e1) {\r
- // Ignore, may happen for crap input\r
- setStatus(DONT_TOUCH, "Invalid input, expected transient resource ID");\r
- } catch (Exception e1) {\r
- ErrorLogger.defaultLogError(e1);\r
- setStatus(DONT_TOUCH, "Transient resource ID lookup failed. See Error Log.");\r
- }\r
- } else if (parts.length == 2) {\r
- try {\r
- int resourceIndex = Integer.parseInt(parts[1]);\r
- long clusterId = Long.parseLong(parts[0]);\r
- ClusteringSupport cs = session.getService(ClusteringSupport.class);\r
- Resource r = cs.getResourceByIndexAndCluster(resourceIndex, clusterId);\r
- changeLocation(r);\r
- } catch (NumberFormatException e1) {\r
- // Ignore, may happen for crap input\r
- setStatus(DONT_TOUCH, "Invalid input, expected index & cluster IDs");\r
- } catch (Exception e1) {\r
- ErrorLogger.defaultLogError(e1);\r
- setStatus(DONT_TOUCH, "Index & cluster -based lookup failed. See Error Log.");\r
- }\r
- }\r
-\r
- // Try to see if the input data is an URI reference\r
- try {\r
- // First check that the input really is a proper URI.\r
- String uri = input;\r
- if (!input.equals("http:/") && input.endsWith("/"))\r
- uri = input.substring(0, input.length() - 1);\r
- new URI(uri);\r
- Resource r = session.syncRequest( Queries.resource( uri ) );\r
- changeLocation(r);\r
- return;\r
- } catch (URISyntaxException e) {\r
- // Ignore, this is not a proper URI at all.\r
- } catch (ResourceNotFoundException e1) {\r
- // Ok, this was an URI, but no resource was found.\r
- setStatus(DONT_TOUCH, "Resource for URI '" + input + "' not found");\r
- return;\r
- } catch (DatabaseException e1) {\r
- setStatus(DONT_TOUCH, "URI lookup failed. See Error Log.");\r
- ErrorLogger.defaultLogError(e1);\r
- }\r
-\r
- setStatus(DONT_TOUCH, "Invalid input, resource ID or URI expected");\r
- }\r
-\r
- public Label createDropLabel(Composite parent) {\r
- final Label label = new Label(parent, SWT.BORDER);\r
- label.setAlignment(SWT.CENTER);\r
- label.setText("Drag a resource here to examine it in this debugger!");\r
- label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));\r
- GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(2, 1).grab(true, false).applyTo(label);\r
-\r
- // Add resource id drop support to the drop-area.\r
- DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY);\r
- dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });\r
- dropTarget.addDropListener(new DropTargetAdapter() {\r
- @Override\r
- public void dragEnter(DropTargetEvent event) {\r
- event.detail = DND.DROP_LINK;\r
- label.setBackground((Color) resourceManager.get(green));\r
- return;\r
- }\r
- @Override\r
- public void dragLeave(DropTargetEvent event) {\r
- label.setBackground(null);\r
- }\r
-\r
- @Override\r
- public void drop(DropTargetEvent event) {\r
- label.setBackground(null);\r
- ResourceArray[] data = parseEventData(event);\r
- if (data == null || data.length != 1) {\r
- event.detail = DND.DROP_NONE;\r
- return;\r
- }\r
- final ResourceArray array = data[0];\r
- final Resource r = array.resources[array.resources.length - 1];\r
-\r
- changeLocation(r);\r
- }\r
-\r
- private ResourceArray[] parseEventData(DropTargetEvent event) {\r
- //System.out.println("DATA: " + event.data);\r
- if (event.data instanceof String) {\r
- try {\r
- SerialisationSupport support = session.getService(SerialisationSupport.class);\r
- return ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray();\r
- } catch (IllegalArgumentException e) {\r
- ErrorLogger.defaultLogError(e);\r
- } catch (DatabaseException e) {\r
- ErrorLogger.defaultLogError(e);\r
- }\r
- }\r
- ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data);\r
- if (ret.length > 0)\r
- return ret;\r
- return null;\r
- }\r
- });\r
-\r
- return label;\r
- }\r
-\r
- public Browser createBrowser(Composite parent) {\r
- try {\r
- browser = new Browser(parent, SWT.MOZILLA);\r
- } catch (SWTError e) {\r
- //System.out.println("Could not instantiate Browser: " + e.getMessage());\r
- browser = new Browser(parent, SWT.NONE);\r
- }\r
- GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(browser);\r
-\r
- // Left/right arrows for back/forward\r
- browser.addKeyListener(new KeyAdapter() {\r
-// \r
-// @Override\r
-// public void keyPressed(KeyEvent e) {\r
-// if (e.keyCode == SWT.F5) {\r
-// refreshBrowser();\r
-// }\r
-// }\r
-// }\r
- @Override\r
- public void keyReleased(KeyEvent e) {\r
-// System.out.println("key, char: " + e.keyCode + ", " + (int) e.character + " (" + e.character + ")");\r
- if (e.keyCode == SWT.BS) {\r
- back();\r
- }\r
- \r
- if (e.keyCode == SWT.F5) {\r
- refreshBrowser();\r
- }\r
- \r
- if ((e.stateMask & SWT.ALT) != 0) {\r
- if (e.keyCode == SWT.ARROW_RIGHT)\r
- forward();\r
- if (e.keyCode == SWT.ARROW_LEFT)\r
- back();\r
- }\r
- }\r
- });\r
-\r
- // Add listener for debugging functionality\r
- browser.addLocationListener(new LocationAdapter() {\r
- @Override\r
- public void changing(LocationEvent event) {\r
- String location = event.location;\r
- if (location.startsWith("simantics:browser"))\r
- location = "about:" + location.substring(17);\r
- //System.out.println("changing: location=" + location);\r
-\r
- // Do not follow links that are meant as actions that are\r
- // handled below.\r
- event.doit = false;\r
- if ("about:blank".equals(location)) {\r
- // Just changing to the same old blank url is ok since it\r
- // allows the browser to refresh itself.\r
- event.doit = true;\r
- }\r
-\r
- if (location.startsWith("about:-link")) {\r
- String target = location.replace("about:-link", "");\r
- Resource element = links.getRight(target);\r
- if (element == currentElement) {\r
- event.doit = false;\r
- return;\r
- }\r
- changeLocation(element);\r
- } else if (location.startsWith("about:-remove")) {\r
- String target = location.replace("about:-remove", "");\r
- String n[] = target.split(STATEMENT_PART_SEPARATOR);\r
- if (n.length != 3)\r
- return;\r
-\r
- final Resource s = links.getRight(n[0]);\r
- final Resource p = links.getRight(n[1]);\r
- final Resource o = links.getRight(n[2]);\r
-\r
- // Make sure this is what the use wants.\r
- MessageDialog md = new MessageDialog(\r
- getShell(),\r
- "Confirm action...",\r
- null,\r
- "This action will remove the selected statement.\nAre you sure you want to proceed with this action?",\r
- MessageDialog.QUESTION, new String[] { "Cancel", "Continue" }, 0);\r
- if (md.open() != 1) {\r
- return;\r
- }\r
-\r
- session.asyncRequest(new WriteRequest() {\r
-\r
- @Override\r
- public void perform(WriteGraph g) throws DatabaseException {\r
- try {\r
- List<Resource> ls = OrderedSetUtils.toList(g, s);\r
- if(ls.contains(o))\r
- OrderedSetUtils.remove(g, s, o);\r
- } catch (DatabaseException e) {\r
- \r
- }\r
- try {\r
- List<Resource> ls = ListUtils.toList(g, s);\r
- if(ls.contains(o))\r
- ListUtils.removeElement(g, s, o);\r
- } catch (DatabaseException e) {\r
- \r
- }\r
- g.denyStatement(s, p, o);\r
- }\r
-\r
- }, new Callback<DatabaseException>() {\r
-\r
- @Override\r
- public void run(DatabaseException parameter) {\r
- refreshBrowser();\r
- }\r
-\r
- });\r
- } else if (location.startsWith("about:-edit-value")) {\r
- String target = location.replace("about:-edit-value", "");\r
- final Resource o = links.getRight(target);\r
-\r
- session.asyncRequest(new ReadRequest() {\r
-\r
- String previousValue;\r
-\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
-\r
- previousValue = getResourceName(graph, o);\r
- final StringModifier modifier = graph.adapt(o, StringModifier.class);\r
- getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- InputDialog dialog = new InputDialog(\r
- getShell(),\r
- "Edit Value",\r
- null,\r
- previousValue,\r
- new IInputValidator() {\r
- @Override\r
- public String isValid(String newText) {\r
- return modifier.isValid(newText);\r
- }\r
- }) {\r
- private static final String DIALOG = "DebuggerEditValueDialog"; //$NON-NLS-1$\r
- private IDialogSettings dialogBoundsSettings;\r
- @Override\r
- protected IDialogSettings getDialogBoundsSettings() {\r
- if (dialogBoundsSettings == null) {\r
- IDialogSettings settings = Activator.getDefault().getDialogSettings();\r
- dialogBoundsSettings = settings.getSection(DIALOG);\r
- if (dialogBoundsSettings == null)\r
- dialogBoundsSettings = settings.addNewSection(DIALOG);\r
- }\r
- return dialogBoundsSettings;\r
- }\r
- @Override\r
- protected Point getInitialSize() {\r
- Point defaultSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);\r
- Point result = super.getInitialSize();\r
- if (defaultSize.equals(result))\r
- return new Point(600, 400);\r
- return result;\r
- }\r
- protected int getShellStyle() {\r
- return super.getShellStyle() | SWT.RESIZE;\r
- }\r
- protected org.eclipse.swt.widgets.Control createDialogArea(Composite parent) {\r
- Composite composite = (Composite) super.createDialogArea(parent);\r
- getText().setLayoutData(\r
- new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL\r
- | GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));\r
- {\r
- Label label = new Label(composite, SWT.NONE);\r
- label.moveAbove(getText());\r
- label.setText("Input new property value. For numeric vector values, separate numbers with comma (',').");\r
- GridData data = new GridData(GridData.GRAB_HORIZONTAL\r
- | GridData.HORIZONTAL_ALIGN_FILL\r
- | GridData.VERTICAL_ALIGN_CENTER);\r
- data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
- label.setLayoutData(data);\r
- label.setFont(parent.getFont());\r
- }\r
- return composite;\r
- }\r
- protected int getInputTextStyle() {\r
- return SWT.MULTI | SWT.BORDER;\r
- }\r
- };\r
- int ok = dialog.open();\r
- if (ok != Dialog.OK)\r
- return;\r
-\r
- final String value = dialog.getValue();\r
- session.asyncRequest(new WriteRequest() {\r
- @Override\r
- public void perform(WriteGraph g) throws DatabaseException {\r
- //modifier.modify( g, htmlEscape( value ) );\r
- modifier.modify( g, value );\r
- }\r
- }, new Callback<DatabaseException>() {\r
- @Override\r
- public void run(DatabaseException parameter) {\r
- if (parameter != null)\r
- ErrorLogger.defaultLogError(parameter);\r
- refreshBrowser();\r
- }\r
- });\r
- return;\r
- }\r
- });\r
- }\r
-\r
- }, new ProcedureAdapter<Object>() {\r
- @Override\r
- public void exception(Throwable t) {\r
- ErrorLogger.defaultLogError(t);\r
- }\r
- });\r
-\r
- }\r
- }\r
- });\r
-\r
- // Schedule a request that updates the browser content.\r
- refreshBrowser();\r
- GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);\r
- support.removeListener(changeListener);\r
-\r
- return browser;\r
- }\r
-\r
- public void refreshBrowser() {\r
- if (currentElement == null)\r
- return;\r
-\r
- // Schedule a request that updates the browser content.\r
- updater.asyncRequest(new ReadRequest() {\r
-\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
- updateContent(graph, currentElement);\r
- }\r
-\r
- });\r
-\r
- }\r
-\r
- public Resource getDebuggerLocation() {\r
- return currentElement;\r
- }\r
-\r
- public void changeLocation(Resource element) {\r
- if (currentElement != null) {\r
- backHistory.addLast(currentElement);\r
- }\r
- currentElement = element;\r
- forwardHistory.clear();\r
-\r
- refreshBrowser();\r
- setStatus(DONT_TOUCH, null);\r
- fireHistoryChanged();\r
- }\r
-\r
- public void addHistoryListener(HistoryListener l) {\r
- historyListeners.add(l);\r
- }\r
-\r
- public void removeHistoryListener(HistoryListener l) {\r
- historyListeners.remove(l);\r
- }\r
-\r
- private void fireHistoryChanged() {\r
- for (HistoryListener l : historyListeners)\r
- l.historyChanged();\r
- }\r
-\r
- public boolean hasBackHistory() {\r
- return backHistory.isEmpty();\r
- }\r
-\r
- public boolean hasForwardHistory() {\r
- return forwardHistory.isEmpty();\r
- }\r
-\r
- public void back() {\r
- if (backHistory.isEmpty())\r
- return;\r
-\r
- forwardHistory.addFirst(currentElement);\r
- currentElement = backHistory.removeLast();\r
-\r
- refreshBrowser();\r
- fireHistoryChanged();\r
- }\r
-\r
- public void forward() {\r
- if (forwardHistory.isEmpty())\r
- return;\r
-\r
- backHistory.addLast(currentElement);\r
- currentElement = forwardHistory.removeFirst();\r
-\r
- refreshBrowser();\r
- fireHistoryChanged();\r
- }\r
-\r
- protected String toName(Object o) {\r
- Class<?> clazz = o.getClass();\r
- if (clazz.isArray()) {\r
- int length = Array.getLength(o);\r
- if (length > RESOURCE_NAME_MAX_LENGTH) {\r
- if (o instanceof byte[]) {\r
- byte[] arr = (byte[]) o;\r
- byte[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("byte", Arrays.toString(arr2), arr.length);\r
- } else if (o instanceof int[]) {\r
- int[] arr = (int[]) o;\r
- int[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("int", Arrays.toString(arr2), arr.length);\r
- } else if (o instanceof long[]) {\r
- long[] arr = (long[]) o;\r
- long[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("long", Arrays.toString(arr2), arr.length);\r
- } else if (o instanceof float[]) {\r
- float[] arr = (float[]) o;\r
- float[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("float", Arrays.toString(arr2), arr.length);\r
- } else if (o instanceof double[]) {\r
- double[] arr = (double[]) o;\r
- double[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("double", Arrays.toString(arr2), arr.length);\r
- } else if (o instanceof boolean[]) {\r
- boolean[] arr = (boolean[]) o;\r
- boolean[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("boolean", Arrays.toString(arr2), arr.length);\r
- } else if (o instanceof Object[]) {\r
- Object[] arr = (Object[]) o;\r
- Object[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);\r
- return truncated("Object", Arrays.toString(arr2), arr.length);\r
- } else {\r
- return "Unknown big array " + o.getClass();\r
- }\r
- } else {\r
- return o.getClass().getComponentType() + "[" + length + "] = " + ObjectUtils.toString(o);\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- protected String truncated(String type, String string, int originalLength) {\r
- return type + "[" + RESOURCE_NAME_MAX_LENGTH + "/" + originalLength + "] = " + string;\r
- }\r
- \r
- public static String htmlEscape(String s)\r
- {\r
- return s.replace("&", "&").replace("<", "<").replace(">", ">").replace("\n", "<br/>");\r
- }\r
-\r
- /**\r
- * Get resource name(?) \r
- * \r
- * @param graph\r
- * @param r\r
- * @return\r
- */\r
- protected String getResourceName(ReadGraph graph, Resource r) {\r
- try {\r
-\r
- String name = null;\r
- //System.out.println("hasValue(" + NameUtils.getSafeName(graph, r, true));\r
- if (graph.hasValue(r)) {\r
- // too large array may cause application to run out of memory.\r
- //System.out.println("getValue(" + NameUtils.getSafeName(graph, r, true));\r
- Datatype type = graph.getPossibleRelatedValue(r, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));\r
- if (type!=null) {\r
- Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );\r
- if (type.equals( rviBinding.type() )) {\r
- RVI rvi = graph.getValue(r, rviBinding);\r
- \r
- try {\r
- Variable v = Variables.getConfigurationContext( graph, currentElement );\r
- name = rvi.asString(graph, v);\r
-// name = rvi.resolve(graph, v).getURI(graph);\r
- } catch (DatabaseException dbe ) {\r
- name = rvi.toString( graph );\r
- }\r
- } else {\r
- long valueSize = NameUtils.getPossibleValueSize(graph, r);\r
- if (valueSize > RESOURCE_NAME_MAX_LENGTH) {\r
-// Binding b = Bindings.getBinding(type);\r
-// Object v = graph.getValue(r, b);\r
-// Serializer s = Bindings.getSerializerUnchecked(b);\r
-// int size = s.getSize(v);\r
- name = "Approx. " + valueSize + " byte literal of type " + type.toSingleLineString();\r
- } else { \r
- Binding b = Bindings.getBinding(type);\r
- Object v = graph.getValue(r, b);\r
- if (b.type() instanceof StringType) {\r
- name = (String) graph.getValue(r, b);\r
- } else {\r
- name = b.toString(v, false);\r
- }\r
- if (type instanceof ArrayType){\r
- name = name.substring(1, name.length()-1);\r
- }\r
- }\r
- }\r
- } else {\r
- Object o = graph.getValue(r);\r
- name = toName(o);\r
- }\r
- \r
- if(name.isEmpty()) {\r
- name = "<empty value>";\r
- }\r
- \r
- }\r
- // Does resource have a file ??\r
- if (name == null) {\r
-// try {\r
-// Accessor accessor = graph.getAccessor(r);\r
-// name = "File of type " + accessor.type().toSingleLineString();\r
-// } catch (DatabaseException e) {\r
-// // No file, try next alternative.\r
-// }\r
- }\r
- if (name == null) {\r
- //name = graph.adapt(r, String.class);\r
- //if(name.isEmpty())\r
- name = DebugUtils.getSafeLabel(graph, r);\r
- if (name.isEmpty())\r
- name = "<empty name>";\r
- }\r
-// ClusteringSupport support = graph.getSession().getService(ClusteringSupport.class);\r
-// if(name == null)\r
-// return "[" + r.getResourceId() + " - " + support.getCluster(r) + "]";\r
- if(displayClusters) {\r
-// SessionDebug debug = graph.getSession().getDebug();\r
-// name += " (" + debug.getCluster(r) + ")";\r
- }\r
- return name;\r
- } catch (AdaptionException e) {\r
-// e.printStackTrace();\r
- String name = safeReadableString(graph, r);\r
-// try {\r
-// MessageService.defaultLog(new DetailStatus(IDetailStatus.DEBUG, Activator.PLUGIN_ID, 0, NLS.bind(Messages.Name_adaption_problem, MessageUtil.resource(session, r, "this resource")), e));\r
-// } catch (ReferenceSerializationException e1) {\r
-// e1.printStackTrace();\r
-// ErrorLogger.defaultLogWarning(e1);\r
-// }\r
- return name;\r
- } catch (Exception e) {\r
- ErrorLogger.defaultLogError(e);\r
- String name = safeReadableString(graph, r);\r
-// try {\r
-// MessageService.defaultLog(new DetailStatus(IDetailStatus.DEBUG, Activator.PLUGIN_ID, 0, NLS.bind(Messages.Name_formulation_problem, MessageUtil.resource(session, r, "this resource")), e));\r
-// } catch (ReferenceSerializationException e1) {\r
-// e1.printStackTrace();\r
-// ErrorLogger.defaultLogWarning(e1);\r
-// }\r
- return name;\r
- }\r
- }\r
-\r
- private String getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {\r
- String name;\r
- try {\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- if (graph.isInstanceOf(r, L0.Assertion)) {\r
- Resource pred = graph.getSingleObject(r, L0.HasPredicate);\r
- Resource obj = graph.getSingleObject(r, L0.HasObject);\r
- String tmp = htmlEscape( getResourceName(graph, pred) + " -> " + getResourceName(graph, obj) + " (Assertion)" );\r
- name = tmp.substring(0, Math.min(80, tmp.length()));\r
- } else {\r
- String resourceName = getResourceName(graph, r);\r
- if(resourceName.equals("Inverse")) {\r
- Resource inverse = graph.getPossibleInverse(r);\r
- if(inverse != null && graph.hasStatement(inverse, L0.ConsistsOf, r))\r
- resourceName = getResourceName(graph, inverse) + "/Inverse";\r
- }\r
- String tmp = htmlEscape( resourceName );\r
- name = tmp.substring(0, Math.min(80, tmp.length()));\r
- }\r
- \r
- } catch (OutOfMemoryError e) {\r
- name = "OutOfMemoryError";\r
- }\r
- String ret = "<a href=\"simantics:browser-link" + getLinkString(r) + "\">"\r
- + name\r
- + "</a>";\r
- if (graph.isInstanceOf(r, L0.Literal)) {\r
- ret += " <a class=\"edit-link\" href=\"simantics:browser-edit-value" + getLinkString(r) + "\">"\r
- + "(edit)"\r
- + "</a>";\r
- }\r
- return ret;\r
- }\r
-\r
- private String getStatementRemoveRef(Resource s, Resource p, Resource o) {\r
- return "<a href=\"simantics:browser-remove" + getStatementString(s, p, o)\r
- + "\" title=\"Remove this statement\">X</a>";\r
- }\r
-\r
- private void updatePred(StringBuffer content, ReadGraph graph, Resource subj, Resource pred, List<Resource[]> stats) throws DatabaseException {\r
- // Generate output content from statements\r
- String[][] objects = new String[stats.size()][];\r
- for (int i = 0; i < stats.size(); ++i) {\r
- Resource stmSubject = stats.get(i)[0];\r
- Resource object = stats.get(i)[1];\r
-\r
- objects[i] = new String[4];\r
- objects[i][0] = getLinkString(object);\r
- objects[i][1] = htmlEscape( getResourceName(graph, object) );\r
- objects[i][2] = getResourceRef(graph, object);\r
-\r
- // Make a note if the statement was acquired.\r
- if(!stmSubject.equals(subj)) {\r
- objects[i][3] = " (in " + getResourceRef(graph, stmSubject) + ")";\r
- }\r
- }\r
-\r
- // Sort statements by object name\r
- Arrays.sort(objects, new Comparator<String[]>() {\r
- @Override\r
- public int compare(String[] o1, String[] o2) {\r
- return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1[1], o2[1]);\r
- }\r
- });\r
-\r
- // Output table rows\r
- for (int i = 0; i < objects.length; ++i) {\r
- content.append("<tr>");\r
- // Predicate column\r
- if (i == 0)\r
- content.append("<td rowspan=\"").append(objects.length).append("\" valign=\"top\">").append(getResourceRef(graph, pred)).append("</td>");\r
-\r
- // Object column\r
- if (objects[i][3] == null) content.append("<td>");\r
- else content.append("<td class=\"acquired\">");\r
-\r
- content.append(objects[i][2]);\r
- if (objects[i][3] != null)\r
- content.append(objects[i][3]);\r
-\r
- content.append("</td>");\r
- \r
- VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);\r
- VirtualGraph vg = vgs.getGraph(graph, subj, pred, links.getRight(objects[i][0]));\r
- \r
- if(vg != null) {\r
- content.append("<td>").append(vg.toString()).append("</td>");\r
- } else {\r
- content.append("<td>DB</td>");\r
- }\r
- \r
-\r
- // Statement remove -link column\r
- // Only allowed for non-acquired statements.\r
- if (objects[i][3] == null) {\r
- content.append("<td class=\"remove\">");\r
- content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));\r
- content.append("</td>");\r
- }\r
- content.append("</tr>");\r
- }\r
- }\r
-\r
- private void updateTag(StringBuffer content, ReadGraph graph, Resource subj, Resource tag) throws DatabaseException {\r
-\r
- // Generate output content from statements\r
- String ref = getResourceRef(graph, tag);\r
-\r
- content.append("<tr>");\r
- content.append("<td rowspan=\"1\" colspan=\"3\" valign=\"top\">").append(ref).append("</td>");\r
- //content.append("<td>" + name + "</td>");\r
- content.append("<td class=\"remove\">");\r
- content.append(getStatementRemoveRef(subj, tag, subj));\r
- content.append("</td>");\r
- content.append("</tr>");\r
-\r
- }\r
-\r
- private void updateOrderedSet(StringBuffer content, ReadGraph graph, Resource subj) throws DatabaseException {\r
- //List<Resource> list = OrderedSetUtils.toList(graph, subj);\r
- /*\r
- // Generate output content from statements\r
- String[][] objects = new String[stats.size()][];\r
- for (int i = 0; i < stats.size(); ++i) {\r
- Resource stmSubject = stats.get(i)[0];\r
- Resource object = stats.get(i)[1];\r
-\r
- objects[i] = new String[4];\r
- objects[i][0] = getLinkString(object);\r
- objects[i][1] = getResourceName(graph, object);\r
- objects[i][2] = getResourceRef(graph, object);\r
-\r
- // Make a note if the statement was acquired.\r
- if(!stmSubject.equals(subj)) {\r
- objects[i][3] = " (acquired from " + getResourceRef(graph, stmSubject) + ")";\r
- }\r
- }\r
-\r
- // Sort statements by object name\r
- Arrays.sort(objects, new Comparator<String[]>() {\r
- @Override\r
- public int compare(String[] o1, String[] o2) {\r
- return o1[1].compareTo(o2[1]);\r
- }\r
- });*/\r
-\r
- List<String> list = new ArrayList<String>();\r
- Resource cur = subj;\r
- while(true) {\r
- try {\r
- cur = OrderedSetUtils.next(graph, subj, cur);\r
- } catch(DatabaseException e) {\r
- list.add("<span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span>");\r
- Resource inv = graph.getPossibleInverse(subj);\r
- for(Statement stat : graph.getStatements(cur, L0.IsRelatedTo)) {\r
- if(stat.getSubject().equals(cur)) {\r
- if(stat.getPredicate().equals(subj)) {\r
- list.add("next " + getResourceRef(graph, stat.getObject()));\r
- }\r
- else if(stat.getPredicate().equals(inv)) {\r
- list.add("prev " + getResourceRef(graph, stat.getObject()));\r
- }\r
- }\r
- }\r
- break;\r
- }\r
- if(cur.equals(subj))\r
- break;\r
- list.add(getResourceRef(graph, cur));\r
- }\r
-\r
- // Output table rows\r
- for (int i = 0; i < list.size() ; ++i) {\r
- content.append("<tr>");\r
- // Predicate column\r
- if (i == 0)\r
- content.append("<td rowspan=\"").append(list.size()).append("\" valign=\"top\">Ordered Set Elements</td>");\r
-\r
- // Object column\r
- content.append("<td>");\r
- content.append(list.get(i));\r
- content.append("</td>");\r
-\r
- // Statement remove -link column\r
- // Only allowed for non-acquired statements.\r
- /*if (objects[i][3] == null) {\r
- content.append("<td class=\"remove\">");\r
- content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));\r
- content.append("</td>");\r
- }*/\r
- content.append("</tr>");\r
- }\r
- }\r
-\r
- private void updateLinkedList(StringBuffer content, ReadGraph graph, Resource subj) throws DatabaseException {\r
-\r
- List<String> list = new ArrayList<String>();\r
- \r
- try {\r
- List<Resource> resources = ListUtils.toList(graph, subj);\r
- for(Resource element : resources) {\r
- list.add(getResourceRef(graph, element));\r
- }\r
- } catch (DatabaseException e) {\r
- throw new ValidationException(e);\r
- }\r
-\r
- // Output table rows\r
- for (int i = 0; i < list.size() ; ++i) {\r
- content.append("<tr>");\r
- // Predicate column\r
- if (i == 0)\r
- content.append("<td rowspan=\"").append(list.size()).append("\" valign=\"top\">Linked List Elements</td>");\r
-\r
- // Object column\r
- content.append("<td>");\r
- content.append(list.get(i));\r
- content.append("</td><td>DB</td>");\r
-\r
- // Statement remove -link column\r
- // Only allowed for non-acquired statements.\r
- /*if (objects[i][3] == null) {\r
- content.append("<td class=\"remove\">");\r
- content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));\r
- content.append("</td>");\r
- }*/\r
- content.append("</tr>");\r
- }\r
- }\r
-\r
- protected synchronized void updateContent(final ReadGraph graph, Resource... resources) throws DatabaseException {\r
- L0 = Layer0.getInstance(graph);\r
-\r
- links.clear();\r
- StringBuffer content = new StringBuffer();\r
-\r
- // Generate HTML -page\r
- content.append("<html>\n<head>\n")\r
- .append(getHead())\r
- .append("\n</head>\n")\r
- .append("<body>\n")\r
- .append("<div id=\"mainContent\">\n\n");\r
-\r
- for (Resource r : resources) {\r
- if (r == null)\r
- continue;\r
-\r
- String uri = null;\r
- try {\r
- uri = graph.syncRequest(new ResourceToPossibleURI(r));\r
- } catch (Exception e) {\r
- ErrorLogger.defaultLogError(e);\r
- uri = "Cannot get URI: " + e.getMessage();\r
- }\r
-\r
- // Top DIV\r
- content.append("<div id=\"top\">\n");\r
- content.append("<table class=\"top\">\n");\r
- if (uri != null) {\r
- content.append("<tr><td class=\"top_key\">URI</td><td class=\"top_value\"><span id=\"uri\">").append(uri).append("</span></td></tr>\n");\r
- }\r
-\r
- XSupport xs = graph.getService(XSupport.class);\r
- boolean immutable = xs.getImmutable(r);\r
-\r
- Collection<Statement> statements = graph.getStatements(r, L0.IsWeaklyRelatedTo);\r
- HashMultiMap<Resource, Resource[]> map = new HashMultiMap<Resource, Resource[]>();\r
- for(org.simantics.db.Statement statement : statements) {\r
- Resource predicate = null;\r
- Resource subject = null;\r
- Resource obj = null;\r
- try {\r
- predicate = statement.getPredicate();\r
- subject = statement.getSubject();\r
- obj = statement.getObject();\r
- map.add(predicate, new Resource[] {subject, obj});\r
- } catch (Throwable e) {\r
- ErrorLogger.defaultLogError("Cannot find statement " + subject + " " + predicate + " " + obj, e);\r
- }\r
- }\r
- SerialisationSupport ss = graph.getSession().getService(SerialisationSupport.class);\r
- ClusteringSupport support = graph.getSession().getService(ClusteringSupport.class);\r
- content.append("<tr><td class=\"top_key\">Identifiers</td><td class=\"top_value\">");\r
- content.append("<span id=\"resource_id\">")\r
- .append(" RID = $").append(r.getResourceId())\r
- .append(" Resource Key = ").append(ss.getTransientId(r))\r
- .append(" CID = ").append(support.getCluster(r));\r
- content.append("</span></td>");\r
- if (immutable)\r
- content.append("<td class=\"remove\">[IMMUTABLE]</td>");\r
- content.append("</tr>\n");\r
- \r
- boolean isClusterSet = support.isClusterSet(r);\r
- Resource parentSet = support.getClusterSetOfCluster(r);\r
- String parentSetURI = parentSet != null ? graph.getPossibleURI(parentSet) : null;\r
- \r
- content.append("<tr><td class=\"top_key\">Clustering</td><td class=\"top_value\">");\r
- content.append("<span id=\"resource_id\">");\r
- \r
- if(parentSetURI != null)\r
- content.append(" Containing cluster set = ").append(parentSetURI);\r
- else if (parentSet != null)\r
- content.append(" Containing cluster set = ").append(parentSet.toString());\r
- else \r
- content.append(" Not in any cluster set ");\r
- \r
- content.append("</span></td>");\r
- if (isClusterSet)\r
- content.append("<td class=\"remove\">[CLUSTER SET]</td>");\r
- content.append("</tr>\n");\r
- \r
- // If the resource has a value, show it.\r
- String resourceValue = getResourceValue(graph, r);\r
- if (resourceValue != null) {\r
- content\r
- .append("<tr><td class=\"top_key\">Attached value</td><td class=\"top_value\">")\r
- .append(htmlEscape(resourceValue))\r
- .append("</td></tr>\n");\r
- }\r
-\r
- // Close #top\r
- content.append("</table>\n");\r
- content.append("</div>\n");\r
-\r
- content.append("\n<div id=\"data\">\n");\r
- content.append("<table>\n")\r
- .append("<tr><th>Predicate</th><th>Object</th><th>Graph</th></tr>")\r
- .append("<tr><td class=\"subtitle\" colspan=\"3\">Basic information</td></tr>");\r
-\r
- boolean isOrderedSet = graph.isInstanceOf(r, L0.OrderedSet);\r
- boolean isLinkedList = graph.isInstanceOf(r, L0.List);\r
-// map.remove(r);\r
-\r
- // BASIC INFORMATION:\r
- for (Resource pred :\r
- new Resource[] {L0.HasName, L0.InstanceOf,\r
- L0.Inherits, L0.SubrelationOf,\r
- L0.PartOf, L0.ConsistsOf})\r
- if (map.containsKey(pred))\r
- updatePred(content, graph, r, pred, map.remove(pred));\r
-\r
- // TAGS\r
- content.append("<tr><td class=\"subtitle\" colspan=\"3\">Tags</td></tr>");\r
- for(Statement stm : statements) {\r
- if(stm.getSubject().equals(stm.getObject())) {\r
- updateTag(content, graph, r, stm.getPredicate());\r
- map.remove(stm.getPredicate());\r
- }\r
- }\r
-\r
- // ORDERED SETS\r
- content.append("<tr><td class=\"subtitle\" colspan=\"3\">Ordered Sets</td></tr>");\r
- for(Statement stm : statements) {\r
- Resource predicate = stm.getPredicate();\r
- if(graph.isInstanceOf(stm.getPredicate(), L0.OrderedSet)) {\r
- updateTag(content, graph, r, stm.getPredicate());\r
- if(map.get(stm.getPredicate()) != null && map.get(stm.getPredicate()).size() == 1)\r
- map.remove(stm.getPredicate());\r
- }\r
- Resource inverse = graph.getPossibleInverse(predicate);\r
- if (inverse != null) {\r
- if(graph.isInstanceOf(inverse, L0.OrderedSet)) {\r
- if(map.get(stm.getPredicate()) != null && map.get(stm.getPredicate()).size() == 1)\r
- map.remove(stm.getPredicate());\r
- }\r
- } else {\r
- // FIXME : should we infor missing inverse\r
- }\r
- }\r
-\r
- // IS RELATED TO\r
- content.append("<tr><td class=\"subtitle\" colspan=\"3\">Is Related To</td></tr>");\r
-\r
- // ELEMENTS OF ORDERED SET\r
- if(isOrderedSet) {\r
- //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");\r
- try {\r
- updateOrderedSet(content, graph, r);\r
- } catch (ValidationException e) {\r
- content.append("<td colspan=\"3\"><span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">").append(e.getMessage()).append("</span></td>");\r
- }\r
- }\r
-\r
- // ELEMENTS OF LINKED LIST\r
- if(isLinkedList) {\r
- //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");\r
- try {\r
- updateLinkedList(content, graph, r);\r
- } catch (ValidationException e) {\r
- content.append("<td colspan=\"3\"><span style=\"color:red;font-weight:bold\">BROKEN LINKED LIST:<br/></span><span style=\"color:red\">").append(e.getMessage()).append("</span></td>");\r
- }\r
- }\r
-\r
- // IS RELATED TO (other)\r
- Resource[] preds = map.keySet().toArray(new Resource[0]);\r
- final Map<Resource, String> strmap = new HashMap<Resource, String>(preds.length);\r
- for(Resource pred : preds) {\r
- String str = htmlEscape( getResourceName(graph, pred) );\r
- if(str == null)\r
- str = "<null>";\r
- strmap.put(pred, str);\r
- }\r
- Arrays.sort(preds, new Comparator<Resource>() {\r
- @Override\r
- public int compare(Resource o1, Resource o2) {\r
- return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(strmap.get(o1), strmap.get(o2));\r
- }\r
- });\r
- for(Resource pred : preds)\r
- if(graph.isSubrelationOf(pred, L0.IsRelatedTo))\r
- updatePred(content, graph, r, pred, map.get(pred));\r
-\r
- // OTHER STATEMENTS\r
- content.append("<tr><td class=\"subtitle\" colspan=\"3\">Other statements</td></tr>");\r
- for(Resource pred : preds)\r
- if(!graph.isSubrelationOf(pred, L0.IsRelatedTo))\r
- updatePred(content, graph, r, pred, map.get(pred));\r
- content.append("</table>\n");\r
- }\r
- // Close #data\r
- content.append("</div>\n\n");\r
- // Close #mainContent\r
- content.append("</div>\n");\r
- content.append("</body>\n</html>\n");\r
-\r
- // Update content\r
- final String finalContent = content.toString();\r
- if (!isDisposed()) {\r
- getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (!browser.isDisposed())\r
- browser.setText(finalContent);\r
- }\r
- });\r
- }\r
- }\r
-\r
- private String getResourceValue(ReadGraph graph, Resource r) {\r
- try {\r
- if (graph.hasValue(r)) {\r
- // too large array may cause application to run out of memory.\r
- //System.out.println("getValue(" + NameUtils.getSafeName(graph, r, true));\r
- Datatype type = graph.getPossibleRelatedValue(r, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));\r
- if (type != null) {\r
- Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );\r
- if (type.equals( rviBinding.type() )) {\r
- RVI rvi = graph.getValue(r, rviBinding);\r
- try {\r
- Variable v = Variables.getConfigurationContext( graph, r );\r
- return rvi.asString(graph, v);\r
- } catch (DatabaseException dbe ) {\r
- return rvi.toString( graph );\r
- }\r
- } else {\r
- Binding b = Bindings.getBinding(type);\r
- Object v = graph.getValue(r, b);\r
- Serializer s = Bindings.getSerializerUnchecked(b);\r
- int size = s.getSize(v);\r
- if (size > RESOURCE_VALUE_MAX_SIZE) {\r
- return "Approx. " + size + " byte literal of type " + type.toSingleLineString();\r
- } else {\r
- return b.toString(v, false);\r
- }\r
- }\r
- } else {\r
- Object o = graph.getValue(r);\r
- return toName(o);\r
- }\r
- }\r
- return null;\r
- } catch (DatabaseException e) {\r
- return e.getMessage();\r
- } catch (IOException e) {\r
- return e.getMessage();\r
- } catch (BindingException e) {\r
- return e.getMessage();\r
- }\r
- }\r
-\r
- private static String safeReadableString(ReadGraph g, Resource r) {\r
- try {\r
- return NameUtils.getSafeName(g, r);\r
- } catch(Throwable throwable) {\r
- ErrorLogger.defaultLogError(throwable);\r
- return "<font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font>";\r
- }\r
- }\r
-\r
-// private static String safeReadableString(IEntity t) {\r
-// try {\r
-// return ResourceDebugUtils.getReadableNameForEntity(t);\r
-// } catch(Throwable throwable) {\r
-// throwable.printStackTrace();\r
-// return "<font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font>";\r
-// }\r
-// }\r
-\r
- private String getLinkString(Container<Resource> t) {\r
- String link = links.getLeft(t.get());\r
- if(link == null) {\r
- link = UUID.randomUUID().toString();\r
- links.map(link, t.get());\r
- }\r
- return link;\r
- }\r
-\r
-// private String getPropertyEditString(Container<Resource> t) {\r
-// String link = links.getLeft(t.get());\r
-// if(link == null) {\r
-// link = UUID.randomUUID().toString();\r
-// links.map(link, t.get());\r
-// }\r
-// return link;\r
-// }\r
-\r
- private String getStatementString(Resource _s, Resource _p, Resource _o) {\r
- String s = getLinkString(_s);\r
- String p = getLinkString(_p);\r
- String o = getLinkString(_o);\r
- return s + STATEMENT_PART_SEPARATOR + p + STATEMENT_PART_SEPARATOR + o;\r
- }\r
-\r
-// private String getStatementString(Statement stm) {\r
-// String s = getLinkString(stm.getSubject());\r
-// String p = getLinkString(stm.getPredicate());\r
-// String o = getLinkString(stm.getObject());\r
-// return s + STATEMENT_PART_SEPARATOR + p + STATEMENT_PART_SEPARATOR + o;\r
-// }\r
-\r
-// private String toOutgoingTableRow(IEntity subject, Statement stm) {\r
-// boolean isAcquired = !subject.equals(stm.getSubject());\r
-//\r
-// String plainCell = "%s";\r
-// String hrefCell = "<a href=\"%s\">%s</a>";\r
-// String formatTemplate = isAcquired\r
-// ? "<tr>\n<td class=\"acquired\">{0}</td>\n<td class=\"acquired\">{1}</td>\n<td class=\"acquired\">{1}</td>\n<td class=\"acquired\">{1}</td>\n</tr>"\r
-// : "<tr>\n<td>{1}</td>\n<td>{1}</td>\n<td>{1}</td>\n<td>{1}</td>\n</tr>";\r
-// String format = NLS.bind(formatTemplate, plainCell, hrefCell);\r
-//// System.out.println("format: " + format);\r
-//\r
-// IEntity s = stm.getSubject();\r
-// IEntity p = stm.getPredicate();\r
-// IEntity o = stm.getObject();\r
-//\r
-//// String timePart = "[" + timeToString(t.getBegin()) + ", " + timeToString(t.getEnd()) + "]";\r
-//\r
-// try {\r
-// return !isAcquired\r
-// ? String.format(format,\r
-// "about:blank-remove" + getStatementString(stm), "Remove",\r
-// "about:blank-link" + getLinkString(s), safeReadableString(s),\r
-// "about:blank-link" + getLinkString(p), safeReadableString(p),\r
-// "about:blank-link" + getLinkString(o), safeReadableString(o))\r
-// : String.format(format,\r
-// "Acquired",\r
-// "about:blank-link" + getLinkString(s), safeReadableString(s),\r
-// "about:blank-link" + getLinkString(p), safeReadableString(p),\r
-// "about:blank-link" + getLinkString(o), safeReadableString(o)\r
-// );\r
-// } catch (Throwable throwable) {\r
-// return "<tr><td colspan=\"4\"><font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font></td></tr>";\r
-// }\r
-// }\r
-\r
-// private String intervalToString(Interval time) {\r
-// return timeToString(time.getBegin()) + ", " + timeToString(time.getEnd());\r
-// }\r
-//\r
-// DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);\r
-//\r
-// private String timeToString(long time) {\r
-// if (time == Long.MIN_VALUE)\r
-// return "-∞";\r
-// if (time == Long.MAX_VALUE)\r
-// return "+∞";\r
-// //return String.valueOf(time);\r
-// Date d = new Date(time);\r
-// return dateTimeFormat.format(d);\r
-// }\r
-\r
- private String getHead() {\r
- String result = "";\r
- if (cssPath != null) {\r
- result = "<link href=\"" + cssPath + "\" rel=\"stylesheet\" type=\"text/css\">";\r
- }\r
- return result;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.debug.ui;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.ColorDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.LocationAdapter;
+import org.eclipse.swt.browser.LocationEvent;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchSite;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.Databoard;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.serialization.Serializer;
+import org.simantics.databoard.type.ArrayType;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.type.StringType;
+import org.simantics.databoard.util.ObjectUtils;
+import org.simantics.db.AsyncRequestProcessor;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.Statement;
+import org.simantics.db.VirtualGraph;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.ResourceArray;
+import org.simantics.db.common.procedure.adapter.ProcedureAdapter;
+import org.simantics.db.common.request.Queries;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.uri.ResourceToPossibleURI;
+import org.simantics.db.common.utils.ListUtils;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.common.utils.OrderedSetUtils;
+import org.simantics.db.event.ChangeEvent;
+import org.simantics.db.event.ChangeListener;
+import org.simantics.db.exception.AdaptionException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ResourceNotFoundException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.layer0.adapter.StringModifier;
+import org.simantics.db.layer0.variable.RVI;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.db.service.ClusteringSupport;
+import org.simantics.db.service.GraphChangeListenerSupport;
+import org.simantics.db.service.SerialisationSupport;
+import org.simantics.db.service.VirtualGraphSupport;
+import org.simantics.db.service.XSupport;
+import org.simantics.debug.ui.internal.Activator;
+import org.simantics.debug.ui.internal.DebugUtils;
+import org.simantics.debug.ui.internal.HashMultiMap;
+import org.simantics.layer0.Layer0;
+import org.simantics.ui.dnd.LocalObjectTransfer;
+import org.simantics.ui.dnd.ResourceReferenceTransfer;
+import org.simantics.ui.dnd.ResourceTransferUtils;
+import org.simantics.ui.utils.ResourceAdaptionUtils;
+import org.simantics.utils.Container;
+import org.simantics.utils.FileUtils;
+import org.simantics.utils.datastructures.BijectionMap;
+import org.simantics.utils.strings.AlphanumComparator;
+import org.simantics.utils.ui.ErrorLogger;
+import org.simantics.utils.ui.PathUtils;
+import org.simantics.utils.ui.workbench.WorkbenchUtils;
+
+
+public class GraphDebugger extends Composite {
+
+ public interface HistoryListener {
+ void historyChanged();
+ }
+
+ private static final String STATEMENT_PART_SEPARATOR = ",";
+ private final static String DEFAULT_DEBUGGER_CSS_FILE = "debugger.css";
+ private final static String DEFAULT_DEBUGGER_CSS_PATH = "css/" + DEFAULT_DEBUGGER_CSS_FILE;
+
+ private static int RESOURCE_NAME_MAX_LENGTH = 1000;
+ private static int RESOURCE_VALUE_MAX_SIZE = 16384;
+
+ private final LocalResourceManager resourceManager;
+
+ private String cssPath;
+
+ private Browser browser;
+ private final ColorDescriptor green = ColorDescriptor.createFrom(new RGB(0x57, 0xbc, 0x95));
+
+ private final boolean displayClusters = true;
+
+ private final BijectionMap<String, Resource> links = new BijectionMap<String, Resource>();
+ private final LinkedList<Resource> backHistory = new LinkedList<Resource>();
+ private final LinkedList<Resource> forwardHistory = new LinkedList<Resource>();
+ private Resource currentElement = null;
+
+ /**
+ * The Session used to access the graph. Received from outside of this
+ * class and therefore it is not disposed here, just used.
+ */
+ private final Session session;
+
+ private final CopyOnWriteArrayList<HistoryListener> historyListeners = new CopyOnWriteArrayList<HistoryListener>();
+
+ private final AsyncRequestProcessor updater;
+
+ protected Layer0 L0;
+
+ protected IWorkbenchSite site;
+
+ private final ChangeListener changeListener = new ChangeListener() {
+ @Override
+ public void graphChanged(ChangeEvent e) {
+ // This makes sure that the transaction for updating this
+ // GraphDebugger get executed in a serialized fashion.
+ updater.asyncRequest(new ReadRequest() {
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ updateContent(graph, currentElement);
+ }
+
+ });
+
+ }
+ };
+
+ /**
+ * @param parent
+ * @param style
+ * @param session
+ * @param resource the initial resource to debug or <code>null</code> for
+ * initially blank UI.
+ * @param site the workbench site that contains this debugger, for workbench
+ * service access
+ */
+ public GraphDebugger(Composite parent, int style, final Session session, Resource resource, IWorkbenchSite site) {
+ this(parent, style, session, resource);
+ this.site = site;
+ }
+
+ /**
+ * @param parent
+ * @param style
+ * @param session
+ * @param resource the initial resource to debug or <code>null</code> for
+ * initially blank UI.
+ */
+ public GraphDebugger(Composite parent, int style, final Session session, Resource resource) {
+ super(parent, style);
+ Assert.isNotNull(session, "session is null");
+ this.session = session;
+ this.currentElement = resource;
+ this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
+
+ updater = session;//.getService(MergingGraphRequestProcessor.class);
+
+ initializeCSS();
+
+ addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);
+ support.removeListener(changeListener);
+ }
+ });
+ }
+
+ /**
+ * When given to setStatus, indicates that the message shouldn't be touched
+ * since <code>null</code> has a different meaning.
+ */
+ private static final String DONT_TOUCH = "DONT_TOUCH";
+
+ protected void setStatus(String message, String error) {
+ IStatusLineManager status = WorkbenchUtils.getStatusLine(site);
+ if (status != null) {
+ if (message != DONT_TOUCH)
+ status.setMessage(message);
+ if (error != DONT_TOUCH)
+ status.setErrorMessage(error);
+ }
+ }
+
+ public void defaultInitializeUI() {
+ setLayout(new GridLayout(2, false));
+ setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ createResourceText(this);
+ createDropLabel(this);
+ createBrowser(this);
+
+ }
+
+ protected void initializeCSS() {
+ // Extract default css to a temporary location if necessary.
+ try {
+ IPath absolutePath = PathUtils.getAbsolutePath(Activator.PLUGIN_ID, DEFAULT_DEBUGGER_CSS_PATH);
+ if (absolutePath != null) {
+ cssPath = absolutePath.toFile().toURI().toString();
+ } else {
+ File tempDir = FileUtils.getOrCreateTemporaryDirectory(false);
+ File css = new File(tempDir, DEFAULT_DEBUGGER_CSS_FILE);
+ if (!css.exists()) {
+ URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(DEFAULT_DEBUGGER_CSS_PATH), null);
+ if (url == null)
+ throw new FileNotFoundException("Could not find '" + DEFAULT_DEBUGGER_CSS_PATH + "' in bundle '" + Activator.PLUGIN_ID + "'");
+ cssPath = FileUtils.copyResource(url, css, true).toURI().toString();
+ } else {
+ cssPath = css.toURI().toString();
+ }
+ }
+ } catch (IOException e) {
+ // CSS extraction failed, let's just live without it then.
+ ErrorLogger.defaultLogWarning(e);
+ }
+ }
+
+ private static final String PROMPT_TEXT = "Enter resource ID (RID) or URI";
+
+ public void createResourceText(final Composite parent) {
+ final Text text = new Text(parent, SWT.BORDER);
+ text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
+ text.setText(PROMPT_TEXT);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(text);
+
+ text.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (text.getText().trim().equals("")) {
+ text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
+ text.setText(PROMPT_TEXT);
+ }
+ }
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (text.getText().trim().equals(PROMPT_TEXT)) {
+ text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ text.setText("");
+ }
+ text.selectAll();
+ }
+ });
+ text.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.keyCode == SWT.CR) {
+ String input = text.getText();
+ setLookupInput(input);
+ }
+ }
+ });
+
+ final Button button = new Button(parent, SWT.FLAT);
+ button.setText("&Lookup");
+ button.setEnabled(false);
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo(button);
+
+ text.addKeyListener(new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.keyCode == 13) {
+ String input = text.getText();
+ setLookupInput(input);
+ button.setFocus();
+ }
+ }
+ });
+
+ button.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ }
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String input = text.getText();
+ setLookupInput(input);
+ }
+ });
+
+ text.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ String input = text.getText().trim();
+ if (!input.equals(PROMPT_TEXT) && !input.equals(""))
+ button.setEnabled(true);
+ else
+ button.setEnabled(false);
+ }
+ });
+ }
+
+ public void setLookupInput(String input) {
+ // There's no harm in trimming out spaces from both ends of the input.
+ input = input.trim();
+
+ SerialisationSupport support = session.getService(SerialisationSupport.class);
+ if (input.startsWith("$")) {
+ try {
+ Resource r = support.getResource(Long.parseLong(input.substring(1)));
+ changeLocation(r);
+ } catch (NumberFormatException e1) {
+ // Ignore, may happen for crap input
+ setStatus(DONT_TOUCH, "Invalid '$'-prefixed input, expected resource ID");
+ } catch (Exception e1) {
+ ErrorLogger.defaultLogError(e1);
+ setStatus(DONT_TOUCH, "Resource ID lookup failed. See Error Log.");
+ }
+ return;
+ }
+
+ String[] parts = input.split("-");
+
+ if (parts.length == 1) {
+ try {
+ int resourceKey = Integer.parseInt(parts[0].trim());
+ Resource r = support.getResource(resourceKey);
+ // Some validation, not enough though
+ ClusteringSupport cs = session.getService(ClusteringSupport.class);
+ long cluster = cs.getCluster(r);
+ if(cluster > 0) {
+ changeLocation(r);
+ }
+ } catch (NumberFormatException e1) {
+ // Ignore, may happen for crap input
+ setStatus(DONT_TOUCH, "Invalid input, expected transient resource ID");
+ } catch (Exception e1) {
+ ErrorLogger.defaultLogError(e1);
+ setStatus(DONT_TOUCH, "Transient resource ID lookup failed. See Error Log.");
+ }
+ } else if (parts.length == 2) {
+ try {
+ int resourceIndex = Integer.parseInt(parts[1]);
+ long clusterId = Long.parseLong(parts[0]);
+ ClusteringSupport cs = session.getService(ClusteringSupport.class);
+ Resource r = cs.getResourceByIndexAndCluster(resourceIndex, clusterId);
+ changeLocation(r);
+ } catch (NumberFormatException e1) {
+ // Ignore, may happen for crap input
+ setStatus(DONT_TOUCH, "Invalid input, expected index & cluster IDs");
+ } catch (Exception e1) {
+ ErrorLogger.defaultLogError(e1);
+ setStatus(DONT_TOUCH, "Index & cluster -based lookup failed. See Error Log.");
+ }
+ }
+
+ // Try to see if the input data is an URI reference
+ try {
+ // First check that the input really is a proper URI.
+ String uri = input;
+ if (!input.equals("http:/") && input.endsWith("/"))
+ uri = input.substring(0, input.length() - 1);
+ new URI(uri);
+ Resource r = session.syncRequest( Queries.resource( uri ) );
+ changeLocation(r);
+ return;
+ } catch (URISyntaxException e) {
+ // Ignore, this is not a proper URI at all.
+ } catch (ResourceNotFoundException e1) {
+ // Ok, this was an URI, but no resource was found.
+ setStatus(DONT_TOUCH, "Resource for URI '" + input + "' not found");
+ return;
+ } catch (DatabaseException e1) {
+ setStatus(DONT_TOUCH, "URI lookup failed. See Error Log.");
+ ErrorLogger.defaultLogError(e1);
+ }
+
+ setStatus(DONT_TOUCH, "Invalid input, resource ID or URI expected");
+ }
+
+ public Label createDropLabel(Composite parent) {
+ final Label label = new Label(parent, SWT.BORDER);
+ label.setAlignment(SWT.CENTER);
+ label.setText("Drag a resource here to examine it in this debugger!");
+ label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(2, 1).grab(true, false).applyTo(label);
+
+ // Add resource id drop support to the drop-area.
+ DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY);
+ dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });
+ dropTarget.addDropListener(new DropTargetAdapter() {
+ @Override
+ public void dragEnter(DropTargetEvent event) {
+ event.detail = DND.DROP_LINK;
+ label.setBackground((Color) resourceManager.get(green));
+ return;
+ }
+ @Override
+ public void dragLeave(DropTargetEvent event) {
+ label.setBackground(null);
+ }
+
+ @Override
+ public void drop(DropTargetEvent event) {
+ label.setBackground(null);
+ ResourceArray[] data = parseEventData(event);
+ if (data == null || data.length != 1) {
+ event.detail = DND.DROP_NONE;
+ return;
+ }
+ final ResourceArray array = data[0];
+ final Resource r = array.resources[array.resources.length - 1];
+
+ changeLocation(r);
+ }
+
+ private ResourceArray[] parseEventData(DropTargetEvent event) {
+ //System.out.println("DATA: " + event.data);
+ if (event.data instanceof String) {
+ try {
+ SerialisationSupport support = session.getService(SerialisationSupport.class);
+ return ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray();
+ } catch (IllegalArgumentException e) {
+ ErrorLogger.defaultLogError(e);
+ } catch (DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+ }
+ ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data);
+ if (ret.length > 0)
+ return ret;
+ return null;
+ }
+ });
+
+ return label;
+ }
+
+ public Browser createBrowser(Composite parent) {
+ try {
+ browser = new Browser(parent, SWT.MOZILLA);
+ } catch (SWTError e) {
+ //System.out.println("Could not instantiate Browser: " + e.getMessage());
+ browser = new Browser(parent, SWT.NONE);
+ }
+ GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(browser);
+
+ // Left/right arrows for back/forward
+ browser.addKeyListener(new KeyAdapter() {
+//
+// @Override
+// public void keyPressed(KeyEvent e) {
+// if (e.keyCode == SWT.F5) {
+// refreshBrowser();
+// }
+// }
+// }
+ @Override
+ public void keyReleased(KeyEvent e) {
+// System.out.println("key, char: " + e.keyCode + ", " + (int) e.character + " (" + e.character + ")");
+ if (e.keyCode == SWT.BS) {
+ back();
+ }
+
+ if (e.keyCode == SWT.F5) {
+ refreshBrowser();
+ }
+
+ if ((e.stateMask & SWT.ALT) != 0) {
+ if (e.keyCode == SWT.ARROW_RIGHT)
+ forward();
+ if (e.keyCode == SWT.ARROW_LEFT)
+ back();
+ }
+ }
+ });
+
+ // Add listener for debugging functionality
+ browser.addLocationListener(new LocationAdapter() {
+ @Override
+ public void changing(LocationEvent event) {
+ String location = event.location;
+ if (location.startsWith("simantics:browser"))
+ location = "about:" + location.substring(17);
+ //System.out.println("changing: location=" + location);
+
+ // Do not follow links that are meant as actions that are
+ // handled below.
+ event.doit = false;
+ if ("about:blank".equals(location)) {
+ // Just changing to the same old blank url is ok since it
+ // allows the browser to refresh itself.
+ event.doit = true;
+ }
+
+ if (location.startsWith("about:-link")) {
+ String target = location.replace("about:-link", "");
+ Resource element = links.getRight(target);
+ if (element == currentElement) {
+ event.doit = false;
+ return;
+ }
+ changeLocation(element);
+ } else if (location.startsWith("about:-remove")) {
+ String target = location.replace("about:-remove", "");
+ String n[] = target.split(STATEMENT_PART_SEPARATOR);
+ if (n.length != 3)
+ return;
+
+ final Resource s = links.getRight(n[0]);
+ final Resource p = links.getRight(n[1]);
+ final Resource o = links.getRight(n[2]);
+
+ // Make sure this is what the use wants.
+ MessageDialog md = new MessageDialog(
+ getShell(),
+ "Confirm action...",
+ null,
+ "This action will remove the selected statement.\nAre you sure you want to proceed with this action?",
+ MessageDialog.QUESTION, new String[] { "Cancel", "Continue" }, 0);
+ if (md.open() != 1) {
+ return;
+ }
+
+ session.asyncRequest(new WriteRequest() {
+
+ @Override
+ public void perform(WriteGraph g) throws DatabaseException {
+ try {
+ List<Resource> ls = OrderedSetUtils.toList(g, s);
+ if(ls.contains(o))
+ OrderedSetUtils.remove(g, s, o);
+ } catch (DatabaseException e) {
+
+ }
+ try {
+ List<Resource> ls = ListUtils.toList(g, s);
+ if(ls.contains(o))
+ ListUtils.removeElement(g, s, o);
+ } catch (DatabaseException e) {
+
+ }
+ g.denyStatement(s, p, o);
+ }
+
+ }, parameter -> refreshBrowser()
+ );
+ } else if (location.startsWith("about:-edit-value")) {
+ String target = location.replace("about:-edit-value", "");
+ final Resource o = links.getRight(target);
+
+ session.asyncRequest(new ReadRequest() {
+
+ String previousValue;
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+
+ previousValue = getResourceName(graph, o);
+ final StringModifier modifier = graph.adapt(o, StringModifier.class);
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ InputDialog dialog = new InputDialog(
+ getShell(),
+ "Edit Value",
+ null,
+ previousValue,
+ new IInputValidator() {
+ @Override
+ public String isValid(String newText) {
+ return modifier.isValid(newText);
+ }
+ }) {
+ private static final String DIALOG = "DebuggerEditValueDialog"; //$NON-NLS-1$
+ private IDialogSettings dialogBoundsSettings;
+ @Override
+ protected IDialogSettings getDialogBoundsSettings() {
+ if (dialogBoundsSettings == null) {
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();
+ dialogBoundsSettings = settings.getSection(DIALOG);
+ if (dialogBoundsSettings == null)
+ dialogBoundsSettings = settings.addNewSection(DIALOG);
+ }
+ return dialogBoundsSettings;
+ }
+ @Override
+ protected Point getInitialSize() {
+ Point defaultSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+ Point result = super.getInitialSize();
+ if (defaultSize.equals(result))
+ return new Point(600, 400);
+ return result;
+ }
+ protected int getShellStyle() {
+ return super.getShellStyle() | SWT.RESIZE;
+ }
+ protected org.eclipse.swt.widgets.Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ getText().setLayoutData(
+ new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL
+ | GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));
+ {
+ Label label = new Label(composite, SWT.NONE);
+ label.moveAbove(getText());
+ label.setText("Input new property value. For numeric vector values, separate numbers with comma (',').");
+ GridData data = new GridData(GridData.GRAB_HORIZONTAL
+ | GridData.HORIZONTAL_ALIGN_FILL
+ | GridData.VERTICAL_ALIGN_CENTER);
+ data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
+ label.setLayoutData(data);
+ label.setFont(parent.getFont());
+ }
+ return composite;
+ }
+ protected int getInputTextStyle() {
+ return SWT.MULTI | SWT.BORDER;
+ }
+ };
+ int ok = dialog.open();
+ if (ok != Dialog.OK)
+ return;
+
+ final String value = dialog.getValue();
+ session.asyncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph g) throws DatabaseException {
+ //modifier.modify( g, htmlEscape( value ) );
+ modifier.modify( g, value );
+ }
+ }, parameter -> {
+ if (parameter != null)
+ ErrorLogger.defaultLogError(parameter);
+ refreshBrowser();
+ });
+ return;
+ }
+ });
+ }
+
+ }, new ProcedureAdapter<Object>() {
+ @Override
+ public void exception(Throwable t) {
+ ErrorLogger.defaultLogError(t);
+ }
+ });
+
+ }
+ }
+ });
+
+ // Schedule a request that updates the browser content.
+ refreshBrowser();
+ GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);
+ support.removeListener(changeListener);
+
+ return browser;
+ }
+
+ public void refreshBrowser() {
+ if (currentElement == null)
+ return;
+
+ // Schedule a request that updates the browser content.
+ updater.asyncRequest(new ReadRequest() {
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ updateContent(graph, currentElement);
+ }
+
+ });
+
+ }
+
+ public Resource getDebuggerLocation() {
+ return currentElement;
+ }
+
+ public void changeLocation(Resource element) {
+ if (currentElement != null) {
+ backHistory.addLast(currentElement);
+ }
+ currentElement = element;
+ forwardHistory.clear();
+
+ refreshBrowser();
+ setStatus(DONT_TOUCH, null);
+ fireHistoryChanged();
+ }
+
+ public void addHistoryListener(HistoryListener l) {
+ historyListeners.add(l);
+ }
+
+ public void removeHistoryListener(HistoryListener l) {
+ historyListeners.remove(l);
+ }
+
+ private void fireHistoryChanged() {
+ for (HistoryListener l : historyListeners)
+ l.historyChanged();
+ }
+
+ public boolean hasBackHistory() {
+ return backHistory.isEmpty();
+ }
+
+ public boolean hasForwardHistory() {
+ return forwardHistory.isEmpty();
+ }
+
+ public void back() {
+ if (backHistory.isEmpty())
+ return;
+
+ forwardHistory.addFirst(currentElement);
+ currentElement = backHistory.removeLast();
+
+ refreshBrowser();
+ fireHistoryChanged();
+ }
+
+ public void forward() {
+ if (forwardHistory.isEmpty())
+ return;
+
+ backHistory.addLast(currentElement);
+ currentElement = forwardHistory.removeFirst();
+
+ refreshBrowser();
+ fireHistoryChanged();
+ }
+
+ protected String toName(Object o) {
+ Class<?> clazz = o.getClass();
+ if (clazz.isArray()) {
+ int length = Array.getLength(o);
+ if (length > RESOURCE_NAME_MAX_LENGTH) {
+ if (o instanceof byte[]) {
+ byte[] arr = (byte[]) o;
+ byte[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("byte", Arrays.toString(arr2), arr.length);
+ } else if (o instanceof int[]) {
+ int[] arr = (int[]) o;
+ int[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("int", Arrays.toString(arr2), arr.length);
+ } else if (o instanceof long[]) {
+ long[] arr = (long[]) o;
+ long[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("long", Arrays.toString(arr2), arr.length);
+ } else if (o instanceof float[]) {
+ float[] arr = (float[]) o;
+ float[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("float", Arrays.toString(arr2), arr.length);
+ } else if (o instanceof double[]) {
+ double[] arr = (double[]) o;
+ double[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("double", Arrays.toString(arr2), arr.length);
+ } else if (o instanceof boolean[]) {
+ boolean[] arr = (boolean[]) o;
+ boolean[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("boolean", Arrays.toString(arr2), arr.length);
+ } else if (o instanceof Object[]) {
+ Object[] arr = (Object[]) o;
+ Object[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
+ return truncated("Object", Arrays.toString(arr2), arr.length);
+ } else {
+ return "Unknown big array " + o.getClass();
+ }
+ } else {
+ return o.getClass().getComponentType() + "[" + length + "] = " + ObjectUtils.toString(o);
+ }
+ }
+ return null;
+ }
+
+ protected String truncated(String type, String string, int originalLength) {
+ return type + "[" + RESOURCE_NAME_MAX_LENGTH + "/" + originalLength + "] = " + string;
+ }
+
+ public static String htmlEscape(String s)
+ {
+ return s.replace("&", "&").replace("<", "<").replace(">", ">").replace("\n", "<br/>");
+ }
+
+ /**
+ * Get resource name(?)
+ *
+ * @param graph
+ * @param r
+ * @return
+ */
+ protected String getResourceName(ReadGraph graph, Resource r) {
+ try {
+
+ String name = null;
+ //System.out.println("hasValue(" + NameUtils.getSafeName(graph, r, true));
+ if (graph.hasValue(r)) {
+ // too large array may cause application to run out of memory.
+ //System.out.println("getValue(" + NameUtils.getSafeName(graph, r, true));
+ Datatype type = graph.getPossibleRelatedValue(r, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
+ if (type!=null) {
+ Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );
+ if (type.equals( rviBinding.type() )) {
+ RVI rvi = graph.getValue(r, rviBinding);
+
+ try {
+ Variable v = Variables.getConfigurationContext( graph, currentElement );
+ name = rvi.asString(graph, v);
+// name = rvi.resolve(graph, v).getURI(graph);
+ } catch (DatabaseException dbe ) {
+ name = rvi.toString( graph );
+ }
+ } else {
+ long valueSize = NameUtils.getPossibleValueSize(graph, r);
+ if (valueSize > RESOURCE_NAME_MAX_LENGTH) {
+// Binding b = Bindings.getBinding(type);
+// Object v = graph.getValue(r, b);
+// Serializer s = Bindings.getSerializerUnchecked(b);
+// int size = s.getSize(v);
+ name = "Approx. " + valueSize + " byte literal of type " + type.toSingleLineString();
+ } else {
+ Binding b = Bindings.getBinding(type);
+ Object v = graph.getValue(r, b);
+ if (b.type() instanceof StringType) {
+ name = (String) graph.getValue(r, b);
+ } else {
+ name = b.toString(v, false);
+ }
+ if (type instanceof ArrayType){
+ name = name.substring(1, name.length()-1);
+ }
+ }
+ }
+ } else {
+ Object o = graph.getValue(r);
+ name = toName(o);
+ }
+
+ if(name.isEmpty()) {
+ name = "<empty value>";
+ }
+
+ }
+ // Does resource have a file ??
+ if (name == null) {
+// try {
+// Accessor accessor = graph.getAccessor(r);
+// name = "File of type " + accessor.type().toSingleLineString();
+// } catch (DatabaseException e) {
+// // No file, try next alternative.
+// }
+ }
+ if (name == null) {
+ //name = graph.adapt(r, String.class);
+ //if(name.isEmpty())
+ name = DebugUtils.getSafeLabel(graph, r);
+ if (name.isEmpty())
+ name = "<empty name>";
+ }
+// ClusteringSupport support = graph.getSession().getService(ClusteringSupport.class);
+// if(name == null)
+// return "[" + r.getResourceId() + " - " + support.getCluster(r) + "]";
+ if(displayClusters) {
+// SessionDebug debug = graph.getSession().getDebug();
+// name += " (" + debug.getCluster(r) + ")";
+ }
+ return name;
+ } catch (AdaptionException e) {
+// e.printStackTrace();
+ String name = safeReadableString(graph, r);
+// try {
+// MessageService.defaultLog(new DetailStatus(IDetailStatus.DEBUG, Activator.PLUGIN_ID, 0, NLS.bind(Messages.Name_adaption_problem, MessageUtil.resource(session, r, "this resource")), e));
+// } catch (ReferenceSerializationException e1) {
+// e1.printStackTrace();
+// ErrorLogger.defaultLogWarning(e1);
+// }
+ return name;
+ } catch (Exception e) {
+ ErrorLogger.defaultLogError(e);
+ String name = safeReadableString(graph, r);
+// try {
+// MessageService.defaultLog(new DetailStatus(IDetailStatus.DEBUG, Activator.PLUGIN_ID, 0, NLS.bind(Messages.Name_formulation_problem, MessageUtil.resource(session, r, "this resource")), e));
+// } catch (ReferenceSerializationException e1) {
+// e1.printStackTrace();
+// ErrorLogger.defaultLogWarning(e1);
+// }
+ return name;
+ }
+ }
+
+ private String getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {
+ String name;
+ try {
+ Layer0 L0 = Layer0.getInstance(graph);
+ if (graph.isInstanceOf(r, L0.Assertion)) {
+ Resource pred = graph.getSingleObject(r, L0.HasPredicate);
+ // Don't know how I encountered this but it seems to be possible in some cases..
+ // Resource obj = graph.getSingleObject(r, L0.HasObject);
+ Resource obj = graph.getPossibleObject(r, L0.HasObject);
+ String tmp = htmlEscape( getResourceName(graph, pred) + " -> " + (obj == null ? "No object ?" : getResourceName(graph, obj)) + " (Assertion)" );
+ name = tmp.substring(0, Math.min(80, tmp.length()));
+ } else {
+ String resourceName = getResourceName(graph, r);
+ if(resourceName.equals("Inverse")) {
+ Resource inverse = graph.getPossibleInverse(r);
+ if(inverse != null && graph.hasStatement(inverse, L0.ConsistsOf, r))
+ resourceName = getResourceName(graph, inverse) + "/Inverse";
+ }
+ String tmp = htmlEscape( resourceName );
+ name = tmp.substring(0, Math.min(80, tmp.length()));
+ }
+
+ } catch (OutOfMemoryError e) {
+ name = "OutOfMemoryError";
+ }
+ String ret = "<a href=\"simantics:browser-link" + getLinkString(r) + "\">"
+ + name
+ + "</a>";
+ if (graph.isInstanceOf(r, L0.Literal)) {
+ ret += " <a class=\"edit-link\" href=\"simantics:browser-edit-value" + getLinkString(r) + "\">"
+ + "(edit)"
+ + "</a>";
+ }
+ return ret;
+ }
+
+ private String getStatementRemoveRef(Resource s, Resource p, Resource o) {
+ return "<a href=\"simantics:browser-remove" + getStatementString(s, p, o)
+ + "\" title=\"Remove this statement\">X</a>";
+ }
+
+ private void updatePred(StringBuffer content, ReadGraph graph, Resource subj, Resource pred, List<Resource[]> stats) throws DatabaseException {
+ // Generate output content from statements
+ String[][] objects = new String[stats.size()][];
+ for (int i = 0; i < stats.size(); ++i) {
+ Resource stmSubject = stats.get(i)[0];
+ Resource object = stats.get(i)[1];
+
+ objects[i] = new String[4];
+ objects[i][0] = getLinkString(object);
+ objects[i][1] = htmlEscape( getResourceName(graph, object) );
+ objects[i][2] = getResourceRef(graph, object);
+
+ // Make a note if the statement was acquired.
+ if(!stmSubject.equals(subj)) {
+ objects[i][3] = " (in " + getResourceRef(graph, stmSubject) + ")";
+ }
+ }
+
+ // Sort statements by object name
+ Arrays.sort(objects, new Comparator<String[]>() {
+ @Override
+ public int compare(String[] o1, String[] o2) {
+ return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1[1], o2[1]);
+ }
+ });
+
+ // Output table rows
+ for (int i = 0; i < objects.length; ++i) {
+ content.append("<tr>");
+ // Predicate column
+ if (i == 0)
+ content.append("<td rowspan=\"").append(objects.length).append("\" valign=\"top\">").append(getResourceRef(graph, pred)).append("</td>");
+
+ // Object column
+ if (objects[i][3] == null) content.append("<td>");
+ else content.append("<td class=\"acquired\">");
+
+ content.append(objects[i][2]);
+ if (objects[i][3] != null)
+ content.append(objects[i][3]);
+
+ content.append("</td>");
+
+ VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);
+ VirtualGraph vg = vgs.getGraph(graph, subj, pred, links.getRight(objects[i][0]));
+
+ if(vg != null) {
+ content.append("<td>").append(vg.toString()).append("</td>");
+ } else {
+ content.append("<td>DB</td>");
+ }
+
+
+ // Statement remove -link column
+ // Only allowed for non-acquired statements.
+ if (objects[i][3] == null) {
+ content.append("<td class=\"remove\">");
+ content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
+ content.append("</td>");
+ }
+ content.append("</tr>");
+ }
+ }
+
+ private void updateTag(StringBuffer content, ReadGraph graph, Resource subj, Resource tag) throws DatabaseException {
+
+ // Generate output content from statements
+ String ref = getResourceRef(graph, tag);
+
+ content.append("<tr>");
+ content.append("<td rowspan=\"1\" colspan=\"3\" valign=\"top\">").append(ref).append("</td>");
+ //content.append("<td>" + name + "</td>");
+ content.append("<td class=\"remove\">");
+ content.append(getStatementRemoveRef(subj, tag, subj));
+ content.append("</td>");
+ content.append("</tr>");
+
+ }
+
+ private void updateOrderedSet(StringBuffer content, ReadGraph graph, Resource subj) throws DatabaseException {
+ //List<Resource> list = OrderedSetUtils.toList(graph, subj);
+ /*
+ // Generate output content from statements
+ String[][] objects = new String[stats.size()][];
+ for (int i = 0; i < stats.size(); ++i) {
+ Resource stmSubject = stats.get(i)[0];
+ Resource object = stats.get(i)[1];
+
+ objects[i] = new String[4];
+ objects[i][0] = getLinkString(object);
+ objects[i][1] = getResourceName(graph, object);
+ objects[i][2] = getResourceRef(graph, object);
+
+ // Make a note if the statement was acquired.
+ if(!stmSubject.equals(subj)) {
+ objects[i][3] = " (acquired from " + getResourceRef(graph, stmSubject) + ")";
+ }
+ }
+
+ // Sort statements by object name
+ Arrays.sort(objects, new Comparator<String[]>() {
+ @Override
+ public int compare(String[] o1, String[] o2) {
+ return o1[1].compareTo(o2[1]);
+ }
+ });*/
+
+ List<String> list = new ArrayList<String>();
+ Resource cur = subj;
+ while(true) {
+ try {
+ cur = OrderedSetUtils.next(graph, subj, cur);
+ } catch(DatabaseException e) {
+ list.add("<span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span>");
+ Resource inv = graph.getPossibleInverse(subj);
+ for(Statement stat : graph.getStatements(cur, L0.IsRelatedTo)) {
+ if(stat.getSubject().equals(cur)) {
+ if(stat.getPredicate().equals(subj)) {
+ list.add("next " + getResourceRef(graph, stat.getObject()));
+ }
+ else if(stat.getPredicate().equals(inv)) {
+ list.add("prev " + getResourceRef(graph, stat.getObject()));
+ }
+ }
+ }
+ break;
+ }
+ if(cur.equals(subj))
+ break;
+ list.add(getResourceRef(graph, cur));
+ }
+
+ // Output table rows
+ for (int i = 0; i < list.size() ; ++i) {
+ content.append("<tr>");
+ // Predicate column
+ if (i == 0)
+ content.append("<td rowspan=\"").append(list.size()).append("\" valign=\"top\">Ordered Set Elements</td>");
+
+ // Object column
+ content.append("<td>");
+ content.append(list.get(i));
+ content.append("</td>");
+
+ // Statement remove -link column
+ // Only allowed for non-acquired statements.
+ /*if (objects[i][3] == null) {
+ content.append("<td class=\"remove\">");
+ content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
+ content.append("</td>");
+ }*/
+ content.append("</tr>");
+ }
+ }
+
+ private void updateLinkedList(StringBuffer content, ReadGraph graph, Resource subj) throws DatabaseException {
+
+ List<String> list = new ArrayList<String>();
+
+ try {
+ List<Resource> resources = ListUtils.toList(graph, subj);
+ for(Resource element : resources) {
+ list.add(getResourceRef(graph, element));
+ }
+ } catch (DatabaseException e) {
+ throw new ValidationException(e);
+ }
+
+ // Output table rows
+ for (int i = 0; i < list.size() ; ++i) {
+ content.append("<tr>");
+ // Predicate column
+ if (i == 0)
+ content.append("<td rowspan=\"").append(list.size()).append("\" valign=\"top\">Linked List Elements</td>");
+
+ // Object column
+ content.append("<td>");
+ content.append(list.get(i));
+ content.append("</td><td>DB</td>");
+
+ // Statement remove -link column
+ // Only allowed for non-acquired statements.
+ /*if (objects[i][3] == null) {
+ content.append("<td class=\"remove\">");
+ content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
+ content.append("</td>");
+ }*/
+ content.append("</tr>");
+ }
+ }
+
+ protected synchronized void updateContent(final ReadGraph graph, Resource... resources) throws DatabaseException {
+ L0 = Layer0.getInstance(graph);
+
+ links.clear();
+ StringBuffer content = new StringBuffer();
+
+ // Generate HTML -page
+ content.append("<html>\n<head>\n")
+ .append(getHead())
+ .append("\n</head>\n")
+ .append("<body>\n")
+ .append("<div id=\"mainContent\">\n\n");
+
+ for (Resource r : resources) {
+ if (r == null)
+ continue;
+
+ String uri = null;
+ try {
+ uri = graph.syncRequest(new ResourceToPossibleURI(r));
+ } catch (Exception e) {
+ ErrorLogger.defaultLogError(e);
+ uri = "Cannot get URI: " + e.getMessage();
+ }
+
+ // Top DIV
+ content.append("<div id=\"top\">\n");
+ content.append("<table class=\"top\">\n");
+ if (uri != null) {
+ content.append("<tr><td class=\"top_key\">URI</td><td class=\"top_value\"><span id=\"uri\">").append(uri).append("</span></td></tr>\n");
+ }
+
+ XSupport xs = graph.getService(XSupport.class);
+ boolean immutable = xs.getImmutable(r);
+
+ Collection<Statement> statements = graph.getStatements(r, L0.IsWeaklyRelatedTo);
+ HashMultiMap<Resource, Resource[]> map = new HashMultiMap<Resource, Resource[]>();
+ for(org.simantics.db.Statement statement : statements) {
+ Resource predicate = null;
+ Resource subject = null;
+ Resource obj = null;
+ try {
+ predicate = statement.getPredicate();
+ subject = statement.getSubject();
+ obj = statement.getObject();
+ map.add(predicate, new Resource[] {subject, obj});
+ } catch (Throwable e) {
+ ErrorLogger.defaultLogError("Cannot find statement " + subject + " " + predicate + " " + obj, e);
+ }
+ }
+ SerialisationSupport ss = graph.getSession().getService(SerialisationSupport.class);
+ ClusteringSupport support = graph.getSession().getService(ClusteringSupport.class);
+ content.append("<tr><td class=\"top_key\">Identifiers</td><td class=\"top_value\">");
+ content.append("<span id=\"resource_id\">")
+ .append(" RID = $").append(r.getResourceId())
+ .append(" Resource Key = ").append(ss.getTransientId(r))
+ .append(" CID = ").append(support.getCluster(r));
+ content.append("</span></td>");
+ if (immutable)
+ content.append("<td class=\"remove\">[IMMUTABLE]</td>");
+ content.append("</tr>\n");
+
+ boolean isClusterSet = support.isClusterSet(r);
+ Resource parentSet = support.getClusterSetOfCluster(r);
+ String parentSetURI = parentSet != null ? graph.getPossibleURI(parentSet) : null;
+
+ content.append("<tr><td class=\"top_key\">Clustering</td><td class=\"top_value\">");
+ content.append("<span id=\"resource_id\">");
+
+ if(parentSetURI != null)
+ content.append(" Containing cluster set = ").append(parentSetURI);
+ else if (parentSet != null)
+ content.append(" Containing cluster set = ").append(parentSet.toString());
+ else
+ content.append(" Not in any cluster set ");
+
+ content.append("</span></td>");
+ if (isClusterSet)
+ content.append("<td class=\"remove\">[CLUSTER SET]</td>");
+ content.append("</tr>\n");
+
+ // If the resource has a value, show it.
+ String resourceValue = getResourceValue(graph, r);
+ if (resourceValue != null) {
+ content
+ .append("<tr><td class=\"top_key\">Attached value</td><td class=\"top_value\">")
+ .append(htmlEscape(resourceValue))
+ .append("</td></tr>\n");
+ }
+
+ // Close #top
+ content.append("</table>\n");
+ content.append("</div>\n");
+
+ content.append("\n<div id=\"data\">\n");
+ content.append("<table>\n")
+ .append("<tr><th>Predicate</th><th>Object</th><th>Graph</th></tr>")
+ .append("<tr><td class=\"subtitle\" colspan=\"3\">Basic information</td></tr>");
+
+ boolean isOrderedSet = graph.isInstanceOf(r, L0.OrderedSet);
+ boolean isLinkedList = graph.isInstanceOf(r, L0.List);
+// map.remove(r);
+
+ // BASIC INFORMATION:
+ for (Resource pred :
+ new Resource[] {L0.HasName, L0.InstanceOf,
+ L0.Inherits, L0.SubrelationOf,
+ L0.PartOf, L0.ConsistsOf})
+ if (map.containsKey(pred))
+ updatePred(content, graph, r, pred, map.remove(pred));
+
+ // TAGS
+ content.append("<tr><td class=\"subtitle\" colspan=\"3\">Tags</td></tr>");
+ for(Statement stm : statements) {
+ if(stm.getSubject().equals(stm.getObject())) {
+ updateTag(content, graph, r, stm.getPredicate());
+ map.remove(stm.getPredicate());
+ }
+ }
+
+ // ORDERED SETS
+ content.append("<tr><td class=\"subtitle\" colspan=\"3\">Ordered Sets</td></tr>");
+ for(Statement stm : statements) {
+ Resource predicate = stm.getPredicate();
+ if(graph.isInstanceOf(stm.getPredicate(), L0.OrderedSet)) {
+ updateTag(content, graph, r, stm.getPredicate());
+ if(map.get(stm.getPredicate()) != null && map.get(stm.getPredicate()).size() == 1)
+ map.remove(stm.getPredicate());
+ }
+ Resource inverse = graph.getPossibleInverse(predicate);
+ if (inverse != null) {
+ if(graph.isInstanceOf(inverse, L0.OrderedSet)) {
+ if(map.get(stm.getPredicate()) != null && map.get(stm.getPredicate()).size() == 1)
+ map.remove(stm.getPredicate());
+ }
+ } else {
+ // FIXME : should we infor missing inverse
+ }
+ }
+
+ // IS RELATED TO
+ content.append("<tr><td class=\"subtitle\" colspan=\"3\">Is Related To</td></tr>");
+
+ // ELEMENTS OF ORDERED SET
+ if(isOrderedSet) {
+ //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");
+ try {
+ updateOrderedSet(content, graph, r);
+ } catch (ValidationException e) {
+ content.append("<td colspan=\"3\"><span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">").append(e.getMessage()).append("</span></td>");
+ }
+ }
+
+ // ELEMENTS OF LINKED LIST
+ if(isLinkedList) {
+ //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");
+ try {
+ updateLinkedList(content, graph, r);
+ } catch (ValidationException e) {
+ content.append("<td colspan=\"3\"><span style=\"color:red;font-weight:bold\">BROKEN LINKED LIST:<br/></span><span style=\"color:red\">").append(e.getMessage()).append("</span></td>");
+ }
+ }
+
+ // IS RELATED TO (other)
+ Resource[] preds = map.keySet().toArray(new Resource[0]);
+ final Map<Resource, String> strmap = new HashMap<Resource, String>(preds.length);
+ for(Resource pred : preds) {
+ String str = htmlEscape( getResourceName(graph, pred) );
+ if(str == null)
+ str = "<null>";
+ strmap.put(pred, str);
+ }
+ Arrays.sort(preds, new Comparator<Resource>() {
+ @Override
+ public int compare(Resource o1, Resource o2) {
+ return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(strmap.get(o1), strmap.get(o2));
+ }
+ });
+ for(Resource pred : preds)
+ if(graph.isSubrelationOf(pred, L0.IsRelatedTo))
+ updatePred(content, graph, r, pred, map.get(pred));
+
+ // OTHER STATEMENTS
+ content.append("<tr><td class=\"subtitle\" colspan=\"3\">Other statements</td></tr>");
+ for(Resource pred : preds)
+ if(!graph.isSubrelationOf(pred, L0.IsRelatedTo))
+ updatePred(content, graph, r, pred, map.get(pred));
+ content.append("</table>\n");
+ }
+ // Close #data
+ content.append("</div>\n\n");
+ // Close #mainContent
+ content.append("</div>\n");
+ content.append("</body>\n</html>\n");
+
+ // Update content
+ final String finalContent = content.toString();
+ if (!isDisposed()) {
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!browser.isDisposed())
+ browser.setText(finalContent);
+ }
+ });
+ }
+ }
+
+ private String getResourceValue(ReadGraph graph, Resource r) {
+ try {
+ if (graph.hasValue(r)) {
+ // too large array may cause application to run out of memory.
+ //System.out.println("getValue(" + NameUtils.getSafeName(graph, r, true));
+ Datatype type = graph.getPossibleRelatedValue(r, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
+ if (type != null) {
+ Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );
+ if (type.equals( rviBinding.type() )) {
+ RVI rvi = graph.getValue(r, rviBinding);
+ try {
+ Variable v = Variables.getConfigurationContext( graph, r );
+ return rvi.asString(graph, v);
+ } catch (DatabaseException dbe ) {
+ return rvi.toString( graph );
+ }
+ } else {
+ Binding b = Bindings.getBinding(type);
+ Object v = graph.getValue(r, b);
+ Serializer s = Bindings.getSerializerUnchecked(b);
+ int size = s.getSize(v);
+ if (size > RESOURCE_VALUE_MAX_SIZE) {
+ return "Approx. " + size + " byte literal of type " + type.toSingleLineString();
+ } else {
+ return b.toString(v, false);
+ }
+ }
+ } else {
+ Object o = graph.getValue(r);
+ return toName(o);
+ }
+ }
+ return null;
+ } catch (DatabaseException e) {
+ return e.getMessage();
+ } catch (IOException e) {
+ return e.getMessage();
+ } catch (BindingException e) {
+ return e.getMessage();
+ }
+ }
+
+ private static String safeReadableString(ReadGraph g, Resource r) {
+ try {
+ return NameUtils.getSafeName(g, r);
+ } catch(Throwable throwable) {
+ ErrorLogger.defaultLogError(throwable);
+ return "<font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font>";
+ }
+ }
+
+// private static String safeReadableString(IEntity t) {
+// try {
+// return ResourceDebugUtils.getReadableNameForEntity(t);
+// } catch(Throwable throwable) {
+// throwable.printStackTrace();
+// return "<font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font>";
+// }
+// }
+
+ private String getLinkString(Container<Resource> t) {
+ String link = links.getLeft(t.get());
+ if(link == null) {
+ link = UUID.randomUUID().toString();
+ links.map(link, t.get());
+ }
+ return link;
+ }
+
+// private String getPropertyEditString(Container<Resource> t) {
+// String link = links.getLeft(t.get());
+// if(link == null) {
+// link = UUID.randomUUID().toString();
+// links.map(link, t.get());
+// }
+// return link;
+// }
+
+ private String getStatementString(Resource _s, Resource _p, Resource _o) {
+ String s = getLinkString(_s);
+ String p = getLinkString(_p);
+ String o = getLinkString(_o);
+ return s + STATEMENT_PART_SEPARATOR + p + STATEMENT_PART_SEPARATOR + o;
+ }
+
+// private String getStatementString(Statement stm) {
+// String s = getLinkString(stm.getSubject());
+// String p = getLinkString(stm.getPredicate());
+// String o = getLinkString(stm.getObject());
+// return s + STATEMENT_PART_SEPARATOR + p + STATEMENT_PART_SEPARATOR + o;
+// }
+
+// private String toOutgoingTableRow(IEntity subject, Statement stm) {
+// boolean isAcquired = !subject.equals(stm.getSubject());
+//
+// String plainCell = "%s";
+// String hrefCell = "<a href=\"%s\">%s</a>";
+// String formatTemplate = isAcquired
+// ? "<tr>\n<td class=\"acquired\">{0}</td>\n<td class=\"acquired\">{1}</td>\n<td class=\"acquired\">{1}</td>\n<td class=\"acquired\">{1}</td>\n</tr>"
+// : "<tr>\n<td>{1}</td>\n<td>{1}</td>\n<td>{1}</td>\n<td>{1}</td>\n</tr>";
+// String format = NLS.bind(formatTemplate, plainCell, hrefCell);
+//// System.out.println("format: " + format);
+//
+// IEntity s = stm.getSubject();
+// IEntity p = stm.getPredicate();
+// IEntity o = stm.getObject();
+//
+//// String timePart = "[" + timeToString(t.getBegin()) + ", " + timeToString(t.getEnd()) + "]";
+//
+// try {
+// return !isAcquired
+// ? String.format(format,
+// "about:blank-remove" + getStatementString(stm), "Remove",
+// "about:blank-link" + getLinkString(s), safeReadableString(s),
+// "about:blank-link" + getLinkString(p), safeReadableString(p),
+// "about:blank-link" + getLinkString(o), safeReadableString(o))
+// : String.format(format,
+// "Acquired",
+// "about:blank-link" + getLinkString(s), safeReadableString(s),
+// "about:blank-link" + getLinkString(p), safeReadableString(p),
+// "about:blank-link" + getLinkString(o), safeReadableString(o)
+// );
+// } catch (Throwable throwable) {
+// return "<tr><td colspan=\"4\"><font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font></td></tr>";
+// }
+// }
+
+// private String intervalToString(Interval time) {
+// return timeToString(time.getBegin()) + ", " + timeToString(time.getEnd());
+// }
+//
+// DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
+//
+// private String timeToString(long time) {
+// if (time == Long.MIN_VALUE)
+// return "-∞";
+// if (time == Long.MAX_VALUE)
+// return "+∞";
+// //return String.valueOf(time);
+// Date d = new Date(time);
+// return dateTimeFormat.format(d);
+// }
+
+ private String getHead() {
+ String result = "";
+ if (cssPath != null) {
+ result = "<link href=\"" + cssPath + "\" rel=\"stylesheet\" type=\"text/css\">";
+ }
+ return result;
+ }
+
+}