1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.debug.ui;
\r
14 import java.io.File;
\r
15 import java.io.FileNotFoundException;
\r
16 import java.io.IOException;
\r
17 import java.lang.reflect.Array;
\r
18 import java.net.URI;
\r
19 import java.net.URISyntaxException;
\r
20 import java.net.URL;
\r
21 import java.util.ArrayList;
\r
22 import java.util.Arrays;
\r
23 import java.util.Collection;
\r
24 import java.util.Comparator;
\r
25 import java.util.HashMap;
\r
26 import java.util.LinkedList;
\r
27 import java.util.List;
\r
28 import java.util.Map;
\r
29 import java.util.UUID;
\r
30 import java.util.concurrent.CopyOnWriteArrayList;
\r
32 import org.eclipse.core.runtime.Assert;
\r
33 import org.eclipse.core.runtime.FileLocator;
\r
34 import org.eclipse.core.runtime.IPath;
\r
35 import org.eclipse.core.runtime.Path;
\r
36 import org.eclipse.jface.action.IStatusLineManager;
\r
37 import org.eclipse.jface.dialogs.Dialog;
\r
38 import org.eclipse.jface.dialogs.IDialogConstants;
\r
39 import org.eclipse.jface.dialogs.IDialogSettings;
\r
40 import org.eclipse.jface.dialogs.IInputValidator;
\r
41 import org.eclipse.jface.dialogs.InputDialog;
\r
42 import org.eclipse.jface.dialogs.MessageDialog;
\r
43 import org.eclipse.jface.layout.GridDataFactory;
\r
44 import org.eclipse.jface.resource.ColorDescriptor;
\r
45 import org.eclipse.jface.resource.JFaceResources;
\r
46 import org.eclipse.jface.resource.LocalResourceManager;
\r
47 import org.eclipse.swt.SWT;
\r
48 import org.eclipse.swt.SWTError;
\r
49 import org.eclipse.swt.browser.Browser;
\r
50 import org.eclipse.swt.browser.LocationAdapter;
\r
51 import org.eclipse.swt.browser.LocationEvent;
\r
52 import org.eclipse.swt.dnd.DND;
\r
53 import org.eclipse.swt.dnd.DropTarget;
\r
54 import org.eclipse.swt.dnd.DropTargetAdapter;
\r
55 import org.eclipse.swt.dnd.DropTargetEvent;
\r
56 import org.eclipse.swt.dnd.TextTransfer;
\r
57 import org.eclipse.swt.dnd.Transfer;
\r
58 import org.eclipse.swt.events.DisposeEvent;
\r
59 import org.eclipse.swt.events.DisposeListener;
\r
60 import org.eclipse.swt.events.FocusEvent;
\r
61 import org.eclipse.swt.events.FocusListener;
\r
62 import org.eclipse.swt.events.KeyAdapter;
\r
63 import org.eclipse.swt.events.KeyEvent;
\r
64 import org.eclipse.swt.events.ModifyEvent;
\r
65 import org.eclipse.swt.events.ModifyListener;
\r
66 import org.eclipse.swt.events.SelectionEvent;
\r
67 import org.eclipse.swt.events.SelectionListener;
\r
68 import org.eclipse.swt.graphics.Color;
\r
69 import org.eclipse.swt.graphics.Point;
\r
70 import org.eclipse.swt.graphics.RGB;
\r
71 import org.eclipse.swt.layout.GridData;
\r
72 import org.eclipse.swt.layout.GridLayout;
\r
73 import org.eclipse.swt.widgets.Button;
\r
74 import org.eclipse.swt.widgets.Composite;
\r
75 import org.eclipse.swt.widgets.Label;
\r
76 import org.eclipse.swt.widgets.Text;
\r
77 import org.eclipse.ui.IWorkbenchSite;
\r
78 import org.simantics.databoard.Bindings;
\r
79 import org.simantics.databoard.Databoard;
\r
80 import org.simantics.databoard.binding.Binding;
\r
81 import org.simantics.databoard.binding.error.BindingException;
\r
82 import org.simantics.databoard.serialization.Serializer;
\r
83 import org.simantics.databoard.type.ArrayType;
\r
84 import org.simantics.databoard.type.Datatype;
\r
85 import org.simantics.databoard.type.StringType;
\r
86 import org.simantics.databoard.util.ObjectUtils;
\r
87 import org.simantics.db.AsyncRequestProcessor;
\r
88 import org.simantics.db.ReadGraph;
\r
89 import org.simantics.db.Resource;
\r
90 import org.simantics.db.Session;
\r
91 import org.simantics.db.Statement;
\r
92 import org.simantics.db.VirtualGraph;
\r
93 import org.simantics.db.WriteGraph;
\r
94 import org.simantics.db.common.ResourceArray;
\r
95 import org.simantics.db.common.procedure.adapter.ProcedureAdapter;
\r
96 import org.simantics.db.common.request.Queries;
\r
97 import org.simantics.db.common.request.ReadRequest;
\r
98 import org.simantics.db.common.request.WriteRequest;
\r
99 import org.simantics.db.common.uri.ResourceToPossibleURI;
\r
100 import org.simantics.db.common.utils.ListUtils;
\r
101 import org.simantics.db.common.utils.NameUtils;
\r
102 import org.simantics.db.common.utils.OrderedSetUtils;
\r
103 import org.simantics.db.event.ChangeEvent;
\r
104 import org.simantics.db.event.ChangeListener;
\r
105 import org.simantics.db.exception.AdaptionException;
\r
106 import org.simantics.db.exception.DatabaseException;
\r
107 import org.simantics.db.exception.ResourceNotFoundException;
\r
108 import org.simantics.db.exception.ValidationException;
\r
109 import org.simantics.db.layer0.adapter.StringModifier;
\r
110 import org.simantics.db.layer0.variable.RVI;
\r
111 import org.simantics.db.layer0.variable.Variable;
\r
112 import org.simantics.db.layer0.variable.Variables;
\r
113 import org.simantics.db.service.ClusteringSupport;
\r
114 import org.simantics.db.service.GraphChangeListenerSupport;
\r
115 import org.simantics.db.service.SerialisationSupport;
\r
116 import org.simantics.db.service.VirtualGraphSupport;
\r
117 import org.simantics.db.service.XSupport;
\r
118 import org.simantics.debug.ui.internal.Activator;
\r
119 import org.simantics.debug.ui.internal.DebugUtils;
\r
120 import org.simantics.debug.ui.internal.HashMultiMap;
\r
121 import org.simantics.layer0.Layer0;
\r
122 import org.simantics.ui.dnd.LocalObjectTransfer;
\r
123 import org.simantics.ui.dnd.ResourceReferenceTransfer;
\r
124 import org.simantics.ui.dnd.ResourceTransferUtils;
\r
125 import org.simantics.ui.utils.ResourceAdaptionUtils;
\r
126 import org.simantics.utils.Container;
\r
127 import org.simantics.utils.FileUtils;
\r
128 import org.simantics.utils.datastructures.BijectionMap;
\r
129 import org.simantics.utils.datastructures.Callback;
\r
130 import org.simantics.utils.strings.AlphanumComparator;
\r
131 import org.simantics.utils.ui.ErrorLogger;
\r
132 import org.simantics.utils.ui.PathUtils;
\r
133 import org.simantics.utils.ui.workbench.WorkbenchUtils;
\r
136 public class GraphDebugger extends Composite {
\r
138 public interface HistoryListener {
\r
139 void historyChanged();
\r
142 private static final String STATEMENT_PART_SEPARATOR = ",";
\r
143 private final static String DEFAULT_DEBUGGER_CSS_FILE = "debugger.css";
\r
144 private final static String DEFAULT_DEBUGGER_CSS_PATH = "css/" + DEFAULT_DEBUGGER_CSS_FILE;
\r
146 private static int RESOURCE_NAME_MAX_LENGTH = 1000;
\r
147 private static int RESOURCE_VALUE_MAX_SIZE = 16384;
\r
149 private final LocalResourceManager resourceManager;
\r
151 private String cssPath;
\r
153 private Browser browser;
\r
154 private final ColorDescriptor green = ColorDescriptor.createFrom(new RGB(0x57, 0xbc, 0x95));
\r
156 private final boolean displayClusters = true;
\r
158 private final BijectionMap<String, Resource> links = new BijectionMap<String, Resource>();
\r
159 private final LinkedList<Resource> backHistory = new LinkedList<Resource>();
\r
160 private final LinkedList<Resource> forwardHistory = new LinkedList<Resource>();
\r
161 private Resource currentElement = null;
\r
164 * The Session used to access the graph. Received from outside of this
\r
165 * class and therefore it is not disposed here, just used.
\r
167 private final Session session;
\r
169 private final CopyOnWriteArrayList<HistoryListener> historyListeners = new CopyOnWriteArrayList<HistoryListener>();
\r
171 private final AsyncRequestProcessor updater;
\r
173 protected Layer0 L0;
\r
175 protected IWorkbenchSite site;
\r
177 private final ChangeListener changeListener = new ChangeListener() {
\r
179 public void graphChanged(ChangeEvent e) {
\r
180 // This makes sure that the transaction for updating this
\r
181 // GraphDebugger get executed in a serialized fashion.
\r
182 updater.asyncRequest(new ReadRequest() {
\r
185 public void run(ReadGraph graph) throws DatabaseException {
\r
186 updateContent(graph, currentElement);
\r
198 * @param resource the initial resource to debug or <code>null</code> for
\r
199 * initially blank UI.
\r
200 * @param site the workbench site that contains this debugger, for workbench
\r
203 public GraphDebugger(Composite parent, int style, final Session session, Resource resource, IWorkbenchSite site) {
\r
204 this(parent, style, session, resource);
\r
212 * @param resource the initial resource to debug or <code>null</code> for
\r
213 * initially blank UI.
\r
215 public GraphDebugger(Composite parent, int style, final Session session, Resource resource) {
\r
216 super(parent, style);
\r
217 Assert.isNotNull(session, "session is null");
\r
218 this.session = session;
\r
219 this.currentElement = resource;
\r
220 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
\r
222 updater = session;//.getService(MergingGraphRequestProcessor.class);
\r
226 addDisposeListener(new DisposeListener() {
\r
228 public void widgetDisposed(DisposeEvent e) {
\r
229 GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);
\r
230 support.removeListener(changeListener);
\r
236 * When given to setStatus, indicates that the message shouldn't be touched
\r
237 * since <code>null</code> has a different meaning.
\r
239 private static final String DONT_TOUCH = "DONT_TOUCH";
\r
241 protected void setStatus(String message, String error) {
\r
242 IStatusLineManager status = WorkbenchUtils.getStatusLine(site);
\r
243 if (status != null) {
\r
244 if (message != DONT_TOUCH)
\r
245 status.setMessage(message);
\r
246 if (error != DONT_TOUCH)
\r
247 status.setErrorMessage(error);
\r
251 public void defaultInitializeUI() {
\r
252 setLayout(new GridLayout(2, false));
\r
253 setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
\r
255 createResourceText(this);
\r
256 createDropLabel(this);
\r
257 createBrowser(this);
\r
261 protected void initializeCSS() {
\r
262 // Extract default css to a temporary location if necessary.
\r
264 IPath absolutePath = PathUtils.getAbsolutePath(Activator.PLUGIN_ID, DEFAULT_DEBUGGER_CSS_PATH);
\r
265 if (absolutePath != null) {
\r
266 cssPath = absolutePath.toFile().toURI().toString();
\r
268 File tempDir = FileUtils.getOrCreateTemporaryDirectory(false);
\r
269 File css = new File(tempDir, DEFAULT_DEBUGGER_CSS_FILE);
\r
270 if (!css.exists()) {
\r
271 URL url = FileLocator.find(Activator.getDefault().getBundle(), new Path(DEFAULT_DEBUGGER_CSS_PATH), null);
\r
273 throw new FileNotFoundException("Could not find '" + DEFAULT_DEBUGGER_CSS_PATH + "' in bundle '" + Activator.PLUGIN_ID + "'");
\r
274 cssPath = FileUtils.copyResource(url, css, true).toURI().toString();
\r
276 cssPath = css.toURI().toString();
\r
279 } catch (IOException e) {
\r
280 // CSS extraction failed, let's just live without it then.
\r
281 ErrorLogger.defaultLogWarning(e);
\r
285 private static final String PROMPT_TEXT = "Enter resource ID (RID) or URI";
\r
287 public void createResourceText(final Composite parent) {
\r
288 final Text text = new Text(parent, SWT.BORDER);
\r
289 text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
\r
290 text.setText(PROMPT_TEXT);
\r
291 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, false).applyTo(text);
\r
293 text.addFocusListener(new FocusListener() {
\r
295 public void focusLost(FocusEvent e) {
\r
296 if (text.getText().trim().equals("")) {
\r
297 text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
\r
298 text.setText(PROMPT_TEXT);
\r
302 public void focusGained(FocusEvent e) {
\r
303 if (text.getText().trim().equals(PROMPT_TEXT)) {
\r
304 text.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_BLACK));
\r
310 text.addKeyListener(new KeyAdapter() {
\r
312 public void keyPressed(KeyEvent e) {
\r
313 if (e.keyCode == SWT.CR) {
\r
314 String input = text.getText();
\r
315 setLookupInput(input);
\r
320 final Button button = new Button(parent, SWT.FLAT);
\r
321 button.setText("&Lookup");
\r
322 button.setEnabled(false);
\r
323 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo(button);
\r
325 text.addKeyListener(new KeyAdapter() {
\r
328 public void keyPressed(KeyEvent e) {
\r
329 if (e.keyCode == 13) {
\r
330 String input = text.getText();
\r
331 setLookupInput(input);
\r
337 button.addSelectionListener(new SelectionListener() {
\r
339 public void widgetDefaultSelected(SelectionEvent e) {
\r
343 public void widgetSelected(SelectionEvent e) {
\r
344 String input = text.getText();
\r
345 setLookupInput(input);
\r
349 text.addModifyListener(new ModifyListener() {
\r
351 public void modifyText(ModifyEvent e) {
\r
352 String input = text.getText().trim();
\r
353 if (!input.equals(PROMPT_TEXT) && !input.equals(""))
\r
354 button.setEnabled(true);
\r
356 button.setEnabled(false);
\r
361 public void setLookupInput(String input) {
\r
362 // There's no harm in trimming out spaces from both ends of the input.
\r
363 input = input.trim();
\r
365 SerialisationSupport support = session.getService(SerialisationSupport.class);
\r
366 if (input.startsWith("$")) {
\r
368 Resource r = support.getResource(Long.parseLong(input.substring(1)));
\r
370 } catch (NumberFormatException e1) {
\r
371 // Ignore, may happen for crap input
\r
372 setStatus(DONT_TOUCH, "Invalid '$'-prefixed input, expected resource ID");
\r
373 } catch (Exception e1) {
\r
374 ErrorLogger.defaultLogError(e1);
\r
375 setStatus(DONT_TOUCH, "Resource ID lookup failed. See Error Log.");
\r
380 String[] parts = input.split("-");
\r
382 if (parts.length == 1) {
\r
384 int resourceKey = Integer.parseInt(parts[0].trim());
\r
385 Resource r = support.getResource(resourceKey);
\r
386 // Some validation, not enough though
\r
387 ClusteringSupport cs = session.getService(ClusteringSupport.class);
\r
388 long cluster = cs.getCluster(r);
\r
392 } catch (NumberFormatException e1) {
\r
393 // Ignore, may happen for crap input
\r
394 setStatus(DONT_TOUCH, "Invalid input, expected transient resource ID");
\r
395 } catch (Exception e1) {
\r
396 ErrorLogger.defaultLogError(e1);
\r
397 setStatus(DONT_TOUCH, "Transient resource ID lookup failed. See Error Log.");
\r
399 } else if (parts.length == 2) {
\r
401 int resourceIndex = Integer.parseInt(parts[1]);
\r
402 long clusterId = Long.parseLong(parts[0]);
\r
403 ClusteringSupport cs = session.getService(ClusteringSupport.class);
\r
404 Resource r = cs.getResourceByIndexAndCluster(resourceIndex, clusterId);
\r
406 } catch (NumberFormatException e1) {
\r
407 // Ignore, may happen for crap input
\r
408 setStatus(DONT_TOUCH, "Invalid input, expected index & cluster IDs");
\r
409 } catch (Exception e1) {
\r
410 ErrorLogger.defaultLogError(e1);
\r
411 setStatus(DONT_TOUCH, "Index & cluster -based lookup failed. See Error Log.");
\r
415 // Try to see if the input data is an URI reference
\r
417 // First check that the input really is a proper URI.
\r
418 String uri = input;
\r
419 if (!input.equals("http:/") && input.endsWith("/"))
\r
420 uri = input.substring(0, input.length() - 1);
\r
422 Resource r = session.syncRequest( Queries.resource( uri ) );
\r
425 } catch (URISyntaxException e) {
\r
426 // Ignore, this is not a proper URI at all.
\r
427 } catch (ResourceNotFoundException e1) {
\r
428 // Ok, this was an URI, but no resource was found.
\r
429 setStatus(DONT_TOUCH, "Resource for URI '" + input + "' not found");
\r
431 } catch (DatabaseException e1) {
\r
432 setStatus(DONT_TOUCH, "URI lookup failed. See Error Log.");
\r
433 ErrorLogger.defaultLogError(e1);
\r
436 setStatus(DONT_TOUCH, "Invalid input, resource ID or URI expected");
\r
439 public Label createDropLabel(Composite parent) {
\r
440 final Label label = new Label(parent, SWT.BORDER);
\r
441 label.setAlignment(SWT.CENTER);
\r
442 label.setText("Drag a resource here to examine it in this debugger!");
\r
443 label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
\r
444 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).hint(SWT.DEFAULT, 20).span(2, 1).grab(true, false).applyTo(label);
\r
446 // Add resource id drop support to the drop-area.
\r
447 DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY);
\r
448 dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });
\r
449 dropTarget.addDropListener(new DropTargetAdapter() {
\r
451 public void dragEnter(DropTargetEvent event) {
\r
452 event.detail = DND.DROP_LINK;
\r
453 label.setBackground((Color) resourceManager.get(green));
\r
457 public void dragLeave(DropTargetEvent event) {
\r
458 label.setBackground(null);
\r
462 public void drop(DropTargetEvent event) {
\r
463 label.setBackground(null);
\r
464 ResourceArray[] data = parseEventData(event);
\r
465 if (data == null || data.length != 1) {
\r
466 event.detail = DND.DROP_NONE;
\r
469 final ResourceArray array = data[0];
\r
470 final Resource r = array.resources[array.resources.length - 1];
\r
475 private ResourceArray[] parseEventData(DropTargetEvent event) {
\r
476 //System.out.println("DATA: " + event.data);
\r
477 if (event.data instanceof String) {
\r
479 SerialisationSupport support = session.getService(SerialisationSupport.class);
\r
480 return ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray();
\r
481 } catch (IllegalArgumentException e) {
\r
482 ErrorLogger.defaultLogError(e);
\r
483 } catch (DatabaseException e) {
\r
484 ErrorLogger.defaultLogError(e);
\r
487 ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data);
\r
488 if (ret.length > 0)
\r
497 public Browser createBrowser(Composite parent) {
\r
499 browser = new Browser(parent, SWT.MOZILLA);
\r
500 } catch (SWTError e) {
\r
501 //System.out.println("Could not instantiate Browser: " + e.getMessage());
\r
502 browser = new Browser(parent, SWT.NONE);
\r
504 GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(browser);
\r
506 // Left/right arrows for back/forward
\r
507 browser.addKeyListener(new KeyAdapter() {
\r
510 // public void keyPressed(KeyEvent e) {
\r
511 // if (e.keyCode == SWT.F5) {
\r
512 // refreshBrowser();
\r
517 public void keyReleased(KeyEvent e) {
\r
518 // System.out.println("key, char: " + e.keyCode + ", " + (int) e.character + " (" + e.character + ")");
\r
519 if (e.keyCode == SWT.BS) {
\r
523 if (e.keyCode == SWT.F5) {
\r
527 if ((e.stateMask & SWT.ALT) != 0) {
\r
528 if (e.keyCode == SWT.ARROW_RIGHT)
\r
530 if (e.keyCode == SWT.ARROW_LEFT)
\r
536 // Add listener for debugging functionality
\r
537 browser.addLocationListener(new LocationAdapter() {
\r
539 public void changing(LocationEvent event) {
\r
540 String location = event.location;
\r
541 if (location.startsWith("simantics:browser"))
\r
542 location = "about:" + location.substring(17);
\r
543 //System.out.println("changing: location=" + location);
\r
545 // Do not follow links that are meant as actions that are
\r
547 event.doit = false;
\r
548 if ("about:blank".equals(location)) {
\r
549 // Just changing to the same old blank url is ok since it
\r
550 // allows the browser to refresh itself.
\r
554 if (location.startsWith("about:-link")) {
\r
555 String target = location.replace("about:-link", "");
\r
556 Resource element = links.getRight(target);
\r
557 if (element == currentElement) {
\r
558 event.doit = false;
\r
561 changeLocation(element);
\r
562 } else if (location.startsWith("about:-remove")) {
\r
563 String target = location.replace("about:-remove", "");
\r
564 String n[] = target.split(STATEMENT_PART_SEPARATOR);
\r
568 final Resource s = links.getRight(n[0]);
\r
569 final Resource p = links.getRight(n[1]);
\r
570 final Resource o = links.getRight(n[2]);
\r
572 // Make sure this is what the use wants.
\r
573 MessageDialog md = new MessageDialog(
\r
575 "Confirm action...",
\r
577 "This action will remove the selected statement.\nAre you sure you want to proceed with this action?",
\r
578 MessageDialog.QUESTION, new String[] { "Cancel", "Continue" }, 0);
\r
579 if (md.open() != 1) {
\r
583 session.asyncRequest(new WriteRequest() {
\r
586 public void perform(WriteGraph g) throws DatabaseException {
\r
588 List<Resource> ls = OrderedSetUtils.toList(g, s);
\r
590 OrderedSetUtils.remove(g, s, o);
\r
591 } catch (DatabaseException e) {
\r
595 List<Resource> ls = ListUtils.toList(g, s);
\r
597 ListUtils.removeElement(g, s, o);
\r
598 } catch (DatabaseException e) {
\r
601 g.denyStatement(s, p, o);
\r
604 }, new Callback<DatabaseException>() {
\r
607 public void run(DatabaseException parameter) {
\r
612 } else if (location.startsWith("about:-edit-value")) {
\r
613 String target = location.replace("about:-edit-value", "");
\r
614 final Resource o = links.getRight(target);
\r
616 session.asyncRequest(new ReadRequest() {
\r
618 String previousValue;
\r
621 public void run(ReadGraph graph) throws DatabaseException {
\r
623 previousValue = getResourceName(graph, o);
\r
624 final StringModifier modifier = graph.adapt(o, StringModifier.class);
\r
625 getDisplay().asyncExec(new Runnable() {
\r
627 public void run() {
\r
628 InputDialog dialog = new InputDialog(
\r
633 new IInputValidator() {
\r
635 public String isValid(String newText) {
\r
636 return modifier.isValid(newText);
\r
639 private static final String DIALOG = "DebuggerEditValueDialog"; //$NON-NLS-1$
\r
640 private IDialogSettings dialogBoundsSettings;
\r
642 protected IDialogSettings getDialogBoundsSettings() {
\r
643 if (dialogBoundsSettings == null) {
\r
644 IDialogSettings settings = Activator.getDefault().getDialogSettings();
\r
645 dialogBoundsSettings = settings.getSection(DIALOG);
\r
646 if (dialogBoundsSettings == null)
\r
647 dialogBoundsSettings = settings.addNewSection(DIALOG);
\r
649 return dialogBoundsSettings;
\r
652 protected Point getInitialSize() {
\r
653 Point defaultSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
\r
654 Point result = super.getInitialSize();
\r
655 if (defaultSize.equals(result))
\r
656 return new Point(600, 400);
\r
659 protected int getShellStyle() {
\r
660 return super.getShellStyle() | SWT.RESIZE;
\r
662 protected org.eclipse.swt.widgets.Control createDialogArea(Composite parent) {
\r
663 Composite composite = (Composite) super.createDialogArea(parent);
\r
664 getText().setLayoutData(
\r
665 new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL
\r
666 | GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));
\r
668 Label label = new Label(composite, SWT.NONE);
\r
669 label.moveAbove(getText());
\r
670 label.setText("Input new property value. For numeric vector values, separate numbers with comma (',').");
\r
671 GridData data = new GridData(GridData.GRAB_HORIZONTAL
\r
672 | GridData.HORIZONTAL_ALIGN_FILL
\r
673 | GridData.VERTICAL_ALIGN_CENTER);
\r
674 data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
\r
675 label.setLayoutData(data);
\r
676 label.setFont(parent.getFont());
\r
680 protected int getInputTextStyle() {
\r
681 return SWT.MULTI | SWT.BORDER;
\r
684 int ok = dialog.open();
\r
685 if (ok != Dialog.OK)
\r
688 final String value = dialog.getValue();
\r
689 session.asyncRequest(new WriteRequest() {
\r
691 public void perform(WriteGraph g) throws DatabaseException {
\r
692 //modifier.modify( g, htmlEscape( value ) );
\r
693 modifier.modify( g, value );
\r
695 }, new Callback<DatabaseException>() {
\r
697 public void run(DatabaseException parameter) {
\r
698 if (parameter != null)
\r
699 ErrorLogger.defaultLogError(parameter);
\r
708 }, new ProcedureAdapter<Object>() {
\r
710 public void exception(Throwable t) {
\r
711 ErrorLogger.defaultLogError(t);
\r
719 // Schedule a request that updates the browser content.
\r
721 GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);
\r
722 support.removeListener(changeListener);
\r
727 public void refreshBrowser() {
\r
728 if (currentElement == null)
\r
731 // Schedule a request that updates the browser content.
\r
732 updater.asyncRequest(new ReadRequest() {
\r
735 public void run(ReadGraph graph) throws DatabaseException {
\r
736 updateContent(graph, currentElement);
\r
743 public Resource getDebuggerLocation() {
\r
744 return currentElement;
\r
747 public void changeLocation(Resource element) {
\r
748 if (currentElement != null) {
\r
749 backHistory.addLast(currentElement);
\r
751 currentElement = element;
\r
752 forwardHistory.clear();
\r
755 setStatus(DONT_TOUCH, null);
\r
756 fireHistoryChanged();
\r
759 public void addHistoryListener(HistoryListener l) {
\r
760 historyListeners.add(l);
\r
763 public void removeHistoryListener(HistoryListener l) {
\r
764 historyListeners.remove(l);
\r
767 private void fireHistoryChanged() {
\r
768 for (HistoryListener l : historyListeners)
\r
769 l.historyChanged();
\r
772 public boolean hasBackHistory() {
\r
773 return backHistory.isEmpty();
\r
776 public boolean hasForwardHistory() {
\r
777 return forwardHistory.isEmpty();
\r
780 public void back() {
\r
781 if (backHistory.isEmpty())
\r
784 forwardHistory.addFirst(currentElement);
\r
785 currentElement = backHistory.removeLast();
\r
788 fireHistoryChanged();
\r
791 public void forward() {
\r
792 if (forwardHistory.isEmpty())
\r
795 backHistory.addLast(currentElement);
\r
796 currentElement = forwardHistory.removeFirst();
\r
799 fireHistoryChanged();
\r
802 protected String toName(Object o) {
\r
803 Class<?> clazz = o.getClass();
\r
804 if (clazz.isArray()) {
\r
805 int length = Array.getLength(o);
\r
806 if (length > RESOURCE_NAME_MAX_LENGTH) {
\r
807 if (o instanceof byte[]) {
\r
808 byte[] arr = (byte[]) o;
\r
809 byte[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
810 return truncated("byte", Arrays.toString(arr2), arr.length);
\r
811 } else if (o instanceof int[]) {
\r
812 int[] arr = (int[]) o;
\r
813 int[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
814 return truncated("int", Arrays.toString(arr2), arr.length);
\r
815 } else if (o instanceof long[]) {
\r
816 long[] arr = (long[]) o;
\r
817 long[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
818 return truncated("long", Arrays.toString(arr2), arr.length);
\r
819 } else if (o instanceof float[]) {
\r
820 float[] arr = (float[]) o;
\r
821 float[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
822 return truncated("float", Arrays.toString(arr2), arr.length);
\r
823 } else if (o instanceof double[]) {
\r
824 double[] arr = (double[]) o;
\r
825 double[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
826 return truncated("double", Arrays.toString(arr2), arr.length);
\r
827 } else if (o instanceof boolean[]) {
\r
828 boolean[] arr = (boolean[]) o;
\r
829 boolean[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
830 return truncated("boolean", Arrays.toString(arr2), arr.length);
\r
831 } else if (o instanceof Object[]) {
\r
832 Object[] arr = (Object[]) o;
\r
833 Object[] arr2 = Arrays.copyOf(arr, RESOURCE_NAME_MAX_LENGTH);
\r
834 return truncated("Object", Arrays.toString(arr2), arr.length);
\r
836 return "Unknown big array " + o.getClass();
\r
839 return o.getClass().getComponentType() + "[" + length + "] = " + ObjectUtils.toString(o);
\r
845 protected String truncated(String type, String string, int originalLength) {
\r
846 return type + "[" + RESOURCE_NAME_MAX_LENGTH + "/" + originalLength + "] = " + string;
\r
849 public static String htmlEscape(String s)
\r
851 return s.replace("&", "&").replace("<", "<").replace(">", ">").replace("\n", "<br/>");
\r
855 * Get resource name(?)
\r
861 protected String getResourceName(ReadGraph graph, Resource r) {
\r
864 String name = null;
\r
865 //System.out.println("hasValue(" + NameUtils.getSafeName(graph, r, true));
\r
866 if (graph.hasValue(r)) {
\r
867 // too large array may cause application to run out of memory.
\r
868 //System.out.println("getValue(" + NameUtils.getSafeName(graph, r, true));
\r
869 Datatype type = graph.getPossibleRelatedValue(r, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
\r
871 Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );
\r
872 if (type.equals( rviBinding.type() )) {
\r
873 RVI rvi = graph.getValue(r, rviBinding);
\r
876 Variable v = Variables.getConfigurationContext( graph, currentElement );
\r
877 name = rvi.asString(graph, v);
\r
878 // name = rvi.resolve(graph, v).getURI(graph);
\r
879 } catch (DatabaseException dbe ) {
\r
880 name = rvi.toString( graph );
\r
883 long valueSize = NameUtils.getPossibleValueSize(graph, r);
\r
884 if (valueSize > RESOURCE_NAME_MAX_LENGTH) {
\r
885 // Binding b = Bindings.getBinding(type);
\r
886 // Object v = graph.getValue(r, b);
\r
887 // Serializer s = Bindings.getSerializerUnchecked(b);
\r
888 // int size = s.getSize(v);
\r
889 name = "Approx. " + valueSize + " byte literal of type " + type.toSingleLineString();
\r
891 Binding b = Bindings.getBinding(type);
\r
892 Object v = graph.getValue(r, b);
\r
893 if (b.type() instanceof StringType) {
\r
894 name = (String) graph.getValue(r, b);
\r
896 name = b.toString(v, false);
\r
898 if (type instanceof ArrayType){
\r
899 name = name.substring(1, name.length()-1);
\r
904 Object o = graph.getValue(r);
\r
908 if(name.isEmpty()) {
\r
909 name = "<empty value>";
\r
913 // Does resource have a file ??
\r
914 if (name == null) {
\r
916 // Accessor accessor = graph.getAccessor(r);
\r
917 // name = "File of type " + accessor.type().toSingleLineString();
\r
918 // } catch (DatabaseException e) {
\r
919 // // No file, try next alternative.
\r
922 if (name == null) {
\r
923 //name = graph.adapt(r, String.class);
\r
924 //if(name.isEmpty())
\r
925 name = DebugUtils.getSafeLabel(graph, r);
\r
926 if (name.isEmpty())
\r
927 name = "<empty name>";
\r
929 // ClusteringSupport support = graph.getSession().getService(ClusteringSupport.class);
\r
930 // if(name == null)
\r
931 // return "[" + r.getResourceId() + " - " + support.getCluster(r) + "]";
\r
932 if(displayClusters) {
\r
933 // SessionDebug debug = graph.getSession().getDebug();
\r
934 // name += " (" + debug.getCluster(r) + ")";
\r
937 } catch (AdaptionException e) {
\r
938 // e.printStackTrace();
\r
939 String name = safeReadableString(graph, r);
\r
941 // MessageService.defaultLog(new DetailStatus(IDetailStatus.DEBUG, Activator.PLUGIN_ID, 0, NLS.bind(Messages.Name_adaption_problem, MessageUtil.resource(session, r, "this resource")), e));
\r
942 // } catch (ReferenceSerializationException e1) {
\r
943 // e1.printStackTrace();
\r
944 // ErrorLogger.defaultLogWarning(e1);
\r
947 } catch (Exception e) {
\r
948 ErrorLogger.defaultLogError(e);
\r
949 String name = safeReadableString(graph, r);
\r
951 // MessageService.defaultLog(new DetailStatus(IDetailStatus.DEBUG, Activator.PLUGIN_ID, 0, NLS.bind(Messages.Name_formulation_problem, MessageUtil.resource(session, r, "this resource")), e));
\r
952 // } catch (ReferenceSerializationException e1) {
\r
953 // e1.printStackTrace();
\r
954 // ErrorLogger.defaultLogWarning(e1);
\r
960 private String getResourceRef(ReadGraph graph, Resource r) throws DatabaseException {
\r
963 Layer0 L0 = Layer0.getInstance(graph);
\r
964 if (graph.isInstanceOf(r, L0.Assertion)) {
\r
965 Resource pred = graph.getSingleObject(r, L0.HasPredicate);
\r
966 // Don't know how I encountered this but it seems to be possible in some cases..
\r
967 // Resource obj = graph.getSingleObject(r, L0.HasObject);
\r
968 Resource obj = graph.getPossibleObject(r, L0.HasObject);
\r
969 String tmp = htmlEscape( getResourceName(graph, pred) + " -> " + (obj == null ? "No object ?" : getResourceName(graph, obj)) + " (Assertion)" );
\r
970 name = tmp.substring(0, Math.min(80, tmp.length()));
\r
972 String resourceName = getResourceName(graph, r);
\r
973 if(resourceName.equals("Inverse")) {
\r
974 Resource inverse = graph.getPossibleInverse(r);
\r
975 if(inverse != null && graph.hasStatement(inverse, L0.ConsistsOf, r))
\r
976 resourceName = getResourceName(graph, inverse) + "/Inverse";
\r
978 String tmp = htmlEscape( resourceName );
\r
979 name = tmp.substring(0, Math.min(80, tmp.length()));
\r
982 } catch (OutOfMemoryError e) {
\r
983 name = "OutOfMemoryError";
\r
985 String ret = "<a href=\"simantics:browser-link" + getLinkString(r) + "\">"
\r
988 if (graph.isInstanceOf(r, L0.Literal)) {
\r
989 ret += " <a class=\"edit-link\" href=\"simantics:browser-edit-value" + getLinkString(r) + "\">"
\r
996 private String getStatementRemoveRef(Resource s, Resource p, Resource o) {
\r
997 return "<a href=\"simantics:browser-remove" + getStatementString(s, p, o)
\r
998 + "\" title=\"Remove this statement\">X</a>";
\r
1001 private void updatePred(StringBuffer content, ReadGraph graph, Resource subj, Resource pred, List<Resource[]> stats) throws DatabaseException {
\r
1002 // Generate output content from statements
\r
1003 String[][] objects = new String[stats.size()][];
\r
1004 for (int i = 0; i < stats.size(); ++i) {
\r
1005 Resource stmSubject = stats.get(i)[0];
\r
1006 Resource object = stats.get(i)[1];
\r
1008 objects[i] = new String[4];
\r
1009 objects[i][0] = getLinkString(object);
\r
1010 objects[i][1] = htmlEscape( getResourceName(graph, object) );
\r
1011 objects[i][2] = getResourceRef(graph, object);
\r
1013 // Make a note if the statement was acquired.
\r
1014 if(!stmSubject.equals(subj)) {
\r
1015 objects[i][3] = " (in " + getResourceRef(graph, stmSubject) + ")";
\r
1019 // Sort statements by object name
\r
1020 Arrays.sort(objects, new Comparator<String[]>() {
\r
1022 public int compare(String[] o1, String[] o2) {
\r
1023 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(o1[1], o2[1]);
\r
1027 // Output table rows
\r
1028 for (int i = 0; i < objects.length; ++i) {
\r
1029 content.append("<tr>");
\r
1030 // Predicate column
\r
1032 content.append("<td rowspan=\"").append(objects.length).append("\" valign=\"top\">").append(getResourceRef(graph, pred)).append("</td>");
\r
1035 if (objects[i][3] == null) content.append("<td>");
\r
1036 else content.append("<td class=\"acquired\">");
\r
1038 content.append(objects[i][2]);
\r
1039 if (objects[i][3] != null)
\r
1040 content.append(objects[i][3]);
\r
1042 content.append("</td>");
\r
1044 VirtualGraphSupport vgs = graph.getService(VirtualGraphSupport.class);
\r
1045 VirtualGraph vg = vgs.getGraph(graph, subj, pred, links.getRight(objects[i][0]));
\r
1048 content.append("<td>").append(vg.toString()).append("</td>");
\r
1050 content.append("<td>DB</td>");
\r
1054 // Statement remove -link column
\r
1055 // Only allowed for non-acquired statements.
\r
1056 if (objects[i][3] == null) {
\r
1057 content.append("<td class=\"remove\">");
\r
1058 content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
\r
1059 content.append("</td>");
\r
1061 content.append("</tr>");
\r
1065 private void updateTag(StringBuffer content, ReadGraph graph, Resource subj, Resource tag) throws DatabaseException {
\r
1067 // Generate output content from statements
\r
1068 String ref = getResourceRef(graph, tag);
\r
1070 content.append("<tr>");
\r
1071 content.append("<td rowspan=\"1\" colspan=\"3\" valign=\"top\">").append(ref).append("</td>");
\r
1072 //content.append("<td>" + name + "</td>");
\r
1073 content.append("<td class=\"remove\">");
\r
1074 content.append(getStatementRemoveRef(subj, tag, subj));
\r
1075 content.append("</td>");
\r
1076 content.append("</tr>");
\r
1080 private void updateOrderedSet(StringBuffer content, ReadGraph graph, Resource subj) throws DatabaseException {
\r
1081 //List<Resource> list = OrderedSetUtils.toList(graph, subj);
\r
1083 // Generate output content from statements
\r
1084 String[][] objects = new String[stats.size()][];
\r
1085 for (int i = 0; i < stats.size(); ++i) {
\r
1086 Resource stmSubject = stats.get(i)[0];
\r
1087 Resource object = stats.get(i)[1];
\r
1089 objects[i] = new String[4];
\r
1090 objects[i][0] = getLinkString(object);
\r
1091 objects[i][1] = getResourceName(graph, object);
\r
1092 objects[i][2] = getResourceRef(graph, object);
\r
1094 // Make a note if the statement was acquired.
\r
1095 if(!stmSubject.equals(subj)) {
\r
1096 objects[i][3] = " (acquired from " + getResourceRef(graph, stmSubject) + ")";
\r
1100 // Sort statements by object name
\r
1101 Arrays.sort(objects, new Comparator<String[]>() {
\r
1103 public int compare(String[] o1, String[] o2) {
\r
1104 return o1[1].compareTo(o2[1]);
\r
1108 List<String> list = new ArrayList<String>();
\r
1109 Resource cur = subj;
\r
1112 cur = OrderedSetUtils.next(graph, subj, cur);
\r
1113 } catch(DatabaseException e) {
\r
1114 list.add("<span style=\"color:red;font-weight:bold\">BROKEN ORDERED SET:<br/></span><span style=\"color:red\">" + e.getMessage() + "</span>");
\r
1115 Resource inv = graph.getPossibleInverse(subj);
\r
1116 for(Statement stat : graph.getStatements(cur, L0.IsRelatedTo)) {
\r
1117 if(stat.getSubject().equals(cur)) {
\r
1118 if(stat.getPredicate().equals(subj)) {
\r
1119 list.add("next " + getResourceRef(graph, stat.getObject()));
\r
1121 else if(stat.getPredicate().equals(inv)) {
\r
1122 list.add("prev " + getResourceRef(graph, stat.getObject()));
\r
1128 if(cur.equals(subj))
\r
1130 list.add(getResourceRef(graph, cur));
\r
1133 // Output table rows
\r
1134 for (int i = 0; i < list.size() ; ++i) {
\r
1135 content.append("<tr>");
\r
1136 // Predicate column
\r
1138 content.append("<td rowspan=\"").append(list.size()).append("\" valign=\"top\">Ordered Set Elements</td>");
\r
1141 content.append("<td>");
\r
1142 content.append(list.get(i));
\r
1143 content.append("</td>");
\r
1145 // Statement remove -link column
\r
1146 // Only allowed for non-acquired statements.
\r
1147 /*if (objects[i][3] == null) {
\r
1148 content.append("<td class=\"remove\">");
\r
1149 content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
\r
1150 content.append("</td>");
\r
1152 content.append("</tr>");
\r
1156 private void updateLinkedList(StringBuffer content, ReadGraph graph, Resource subj) throws DatabaseException {
\r
1158 List<String> list = new ArrayList<String>();
\r
1161 List<Resource> resources = ListUtils.toList(graph, subj);
\r
1162 for(Resource element : resources) {
\r
1163 list.add(getResourceRef(graph, element));
\r
1165 } catch (DatabaseException e) {
\r
1166 throw new ValidationException(e);
\r
1169 // Output table rows
\r
1170 for (int i = 0; i < list.size() ; ++i) {
\r
1171 content.append("<tr>");
\r
1172 // Predicate column
\r
1174 content.append("<td rowspan=\"").append(list.size()).append("\" valign=\"top\">Linked List Elements</td>");
\r
1177 content.append("<td>");
\r
1178 content.append(list.get(i));
\r
1179 content.append("</td><td>DB</td>");
\r
1181 // Statement remove -link column
\r
1182 // Only allowed for non-acquired statements.
\r
1183 /*if (objects[i][3] == null) {
\r
1184 content.append("<td class=\"remove\">");
\r
1185 content.append(getStatementRemoveRef(subj, pred, links.getRight(objects[i][0])));
\r
1186 content.append("</td>");
\r
1188 content.append("</tr>");
\r
1192 protected synchronized void updateContent(final ReadGraph graph, Resource... resources) throws DatabaseException {
\r
1193 L0 = Layer0.getInstance(graph);
\r
1196 StringBuffer content = new StringBuffer();
\r
1198 // Generate HTML -page
\r
1199 content.append("<html>\n<head>\n")
\r
1200 .append(getHead())
\r
1201 .append("\n</head>\n")
\r
1202 .append("<body>\n")
\r
1203 .append("<div id=\"mainContent\">\n\n");
\r
1205 for (Resource r : resources) {
\r
1209 String uri = null;
\r
1211 uri = graph.syncRequest(new ResourceToPossibleURI(r));
\r
1212 } catch (Exception e) {
\r
1213 ErrorLogger.defaultLogError(e);
\r
1214 uri = "Cannot get URI: " + e.getMessage();
\r
1218 content.append("<div id=\"top\">\n");
\r
1219 content.append("<table class=\"top\">\n");
\r
1220 if (uri != null) {
\r
1221 content.append("<tr><td class=\"top_key\">URI</td><td class=\"top_value\"><span id=\"uri\">").append(uri).append("</span></td></tr>\n");
\r
1224 XSupport xs = graph.getService(XSupport.class);
\r
1225 boolean immutable = xs.getImmutable(r);
\r
1227 Collection<Statement> statements = graph.getStatements(r, L0.IsWeaklyRelatedTo);
\r
1228 HashMultiMap<Resource, Resource[]> map = new HashMultiMap<Resource, Resource[]>();
\r
1229 for(org.simantics.db.Statement statement : statements) {
\r
1230 Resource predicate = null;
\r
1231 Resource subject = null;
\r
1232 Resource obj = null;
\r
1234 predicate = statement.getPredicate();
\r
1235 subject = statement.getSubject();
\r
1236 obj = statement.getObject();
\r
1237 map.add(predicate, new Resource[] {subject, obj});
\r
1238 } catch (Throwable e) {
\r
1239 ErrorLogger.defaultLogError("Cannot find statement " + subject + " " + predicate + " " + obj, e);
\r
1242 SerialisationSupport ss = graph.getSession().getService(SerialisationSupport.class);
\r
1243 ClusteringSupport support = graph.getSession().getService(ClusteringSupport.class);
\r
1244 content.append("<tr><td class=\"top_key\">Identifiers</td><td class=\"top_value\">");
\r
1245 content.append("<span id=\"resource_id\">")
\r
1246 .append(" RID = $").append(r.getResourceId())
\r
1247 .append(" Resource Key = ").append(ss.getTransientId(r))
\r
1248 .append(" CID = ").append(support.getCluster(r));
\r
1249 content.append("</span></td>");
\r
1251 content.append("<td class=\"remove\">[IMMUTABLE]</td>");
\r
1252 content.append("</tr>\n");
\r
1254 boolean isClusterSet = support.isClusterSet(r);
\r
1255 Resource parentSet = support.getClusterSetOfCluster(r);
\r
1256 String parentSetURI = parentSet != null ? graph.getPossibleURI(parentSet) : null;
\r
1258 content.append("<tr><td class=\"top_key\">Clustering</td><td class=\"top_value\">");
\r
1259 content.append("<span id=\"resource_id\">");
\r
1261 if(parentSetURI != null)
\r
1262 content.append(" Containing cluster set = ").append(parentSetURI);
\r
1263 else if (parentSet != null)
\r
1264 content.append(" Containing cluster set = ").append(parentSet.toString());
\r
1266 content.append(" Not in any cluster set ");
\r
1268 content.append("</span></td>");
\r
1270 content.append("<td class=\"remove\">[CLUSTER SET]</td>");
\r
1271 content.append("</tr>\n");
\r
1273 // If the resource has a value, show it.
\r
1274 String resourceValue = getResourceValue(graph, r);
\r
1275 if (resourceValue != null) {
\r
1277 .append("<tr><td class=\"top_key\">Attached value</td><td class=\"top_value\">")
\r
1278 .append(htmlEscape(resourceValue))
\r
1279 .append("</td></tr>\n");
\r
1283 content.append("</table>\n");
\r
1284 content.append("</div>\n");
\r
1286 content.append("\n<div id=\"data\">\n");
\r
1287 content.append("<table>\n")
\r
1288 .append("<tr><th>Predicate</th><th>Object</th><th>Graph</th></tr>")
\r
1289 .append("<tr><td class=\"subtitle\" colspan=\"3\">Basic information</td></tr>");
\r
1291 boolean isOrderedSet = graph.isInstanceOf(r, L0.OrderedSet);
\r
1292 boolean isLinkedList = graph.isInstanceOf(r, L0.List);
\r
1295 // BASIC INFORMATION:
\r
1296 for (Resource pred :
\r
1297 new Resource[] {L0.HasName, L0.InstanceOf,
\r
1298 L0.Inherits, L0.SubrelationOf,
\r
1299 L0.PartOf, L0.ConsistsOf})
\r
1300 if (map.containsKey(pred))
\r
1301 updatePred(content, graph, r, pred, map.remove(pred));
\r
1304 content.append("<tr><td class=\"subtitle\" colspan=\"3\">Tags</td></tr>");
\r
1305 for(Statement stm : statements) {
\r
1306 if(stm.getSubject().equals(stm.getObject())) {
\r
1307 updateTag(content, graph, r, stm.getPredicate());
\r
1308 map.remove(stm.getPredicate());
\r
1313 content.append("<tr><td class=\"subtitle\" colspan=\"3\">Ordered Sets</td></tr>");
\r
1314 for(Statement stm : statements) {
\r
1315 Resource predicate = stm.getPredicate();
\r
1316 if(graph.isInstanceOf(stm.getPredicate(), L0.OrderedSet)) {
\r
1317 updateTag(content, graph, r, stm.getPredicate());
\r
1318 if(map.get(stm.getPredicate()) != null && map.get(stm.getPredicate()).size() == 1)
\r
1319 map.remove(stm.getPredicate());
\r
1321 Resource inverse = graph.getPossibleInverse(predicate);
\r
1322 if (inverse != null) {
\r
1323 if(graph.isInstanceOf(inverse, L0.OrderedSet)) {
\r
1324 if(map.get(stm.getPredicate()) != null && map.get(stm.getPredicate()).size() == 1)
\r
1325 map.remove(stm.getPredicate());
\r
1328 // FIXME : should we infor missing inverse
\r
1333 content.append("<tr><td class=\"subtitle\" colspan=\"3\">Is Related To</td></tr>");
\r
1335 // ELEMENTS OF ORDERED SET
\r
1336 if(isOrderedSet) {
\r
1337 //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");
\r
1339 updateOrderedSet(content, graph, r);
\r
1340 } catch (ValidationException e) {
\r
1341 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
1345 // ELEMENTS OF LINKED LIST
\r
1346 if(isLinkedList) {
\r
1347 //content.append("<tr><td class=\"subtitle\" colspan=\"2\">Ordered set</td></tr>");
\r
1349 updateLinkedList(content, graph, r);
\r
1350 } catch (ValidationException e) {
\r
1351 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
1355 // IS RELATED TO (other)
\r
1356 Resource[] preds = map.keySet().toArray(new Resource[0]);
\r
1357 final Map<Resource, String> strmap = new HashMap<Resource, String>(preds.length);
\r
1358 for(Resource pred : preds) {
\r
1359 String str = htmlEscape( getResourceName(graph, pred) );
\r
1362 strmap.put(pred, str);
\r
1364 Arrays.sort(preds, new Comparator<Resource>() {
\r
1366 public int compare(Resource o1, Resource o2) {
\r
1367 return AlphanumComparator.CASE_INSENSITIVE_COMPARATOR.compare(strmap.get(o1), strmap.get(o2));
\r
1370 for(Resource pred : preds)
\r
1371 if(graph.isSubrelationOf(pred, L0.IsRelatedTo))
\r
1372 updatePred(content, graph, r, pred, map.get(pred));
\r
1374 // OTHER STATEMENTS
\r
1375 content.append("<tr><td class=\"subtitle\" colspan=\"3\">Other statements</td></tr>");
\r
1376 for(Resource pred : preds)
\r
1377 if(!graph.isSubrelationOf(pred, L0.IsRelatedTo))
\r
1378 updatePred(content, graph, r, pred, map.get(pred));
\r
1379 content.append("</table>\n");
\r
1382 content.append("</div>\n\n");
\r
1383 // Close #mainContent
\r
1384 content.append("</div>\n");
\r
1385 content.append("</body>\n</html>\n");
\r
1388 final String finalContent = content.toString();
\r
1389 if (!isDisposed()) {
\r
1390 getDisplay().asyncExec(new Runnable() {
\r
1392 public void run() {
\r
1393 if (!browser.isDisposed())
\r
1394 browser.setText(finalContent);
\r
1400 private String getResourceValue(ReadGraph graph, Resource r) {
\r
1402 if (graph.hasValue(r)) {
\r
1403 // too large array may cause application to run out of memory.
\r
1404 //System.out.println("getValue(" + NameUtils.getSafeName(graph, r, true));
\r
1405 Datatype type = graph.getPossibleRelatedValue(r, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
\r
1406 if (type != null) {
\r
1407 Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );
\r
1408 if (type.equals( rviBinding.type() )) {
\r
1409 RVI rvi = graph.getValue(r, rviBinding);
\r
1411 Variable v = Variables.getConfigurationContext( graph, r );
\r
1412 return rvi.asString(graph, v);
\r
1413 } catch (DatabaseException dbe ) {
\r
1414 return rvi.toString( graph );
\r
1417 Binding b = Bindings.getBinding(type);
\r
1418 Object v = graph.getValue(r, b);
\r
1419 Serializer s = Bindings.getSerializerUnchecked(b);
\r
1420 int size = s.getSize(v);
\r
1421 if (size > RESOURCE_VALUE_MAX_SIZE) {
\r
1422 return "Approx. " + size + " byte literal of type " + type.toSingleLineString();
\r
1424 return b.toString(v, false);
\r
1428 Object o = graph.getValue(r);
\r
1433 } catch (DatabaseException e) {
\r
1434 return e.getMessage();
\r
1435 } catch (IOException e) {
\r
1436 return e.getMessage();
\r
1437 } catch (BindingException e) {
\r
1438 return e.getMessage();
\r
1442 private static String safeReadableString(ReadGraph g, Resource r) {
\r
1444 return NameUtils.getSafeName(g, r);
\r
1445 } catch(Throwable throwable) {
\r
1446 ErrorLogger.defaultLogError(throwable);
\r
1447 return "<font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font>";
\r
1451 // private static String safeReadableString(IEntity t) {
\r
1453 // return ResourceDebugUtils.getReadableNameForEntity(t);
\r
1454 // } catch(Throwable throwable) {
\r
1455 // throwable.printStackTrace();
\r
1456 // return "<font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font>";
\r
1460 private String getLinkString(Container<Resource> t) {
\r
1461 String link = links.getLeft(t.get());
\r
1462 if(link == null) {
\r
1463 link = UUID.randomUUID().toString();
\r
1464 links.map(link, t.get());
\r
1469 // private String getPropertyEditString(Container<Resource> t) {
\r
1470 // String link = links.getLeft(t.get());
\r
1471 // if(link == null) {
\r
1472 // link = UUID.randomUUID().toString();
\r
1473 // links.map(link, t.get());
\r
1478 private String getStatementString(Resource _s, Resource _p, Resource _o) {
\r
1479 String s = getLinkString(_s);
\r
1480 String p = getLinkString(_p);
\r
1481 String o = getLinkString(_o);
\r
1482 return s + STATEMENT_PART_SEPARATOR + p + STATEMENT_PART_SEPARATOR + o;
\r
1485 // private String getStatementString(Statement stm) {
\r
1486 // String s = getLinkString(stm.getSubject());
\r
1487 // String p = getLinkString(stm.getPredicate());
\r
1488 // String o = getLinkString(stm.getObject());
\r
1489 // return s + STATEMENT_PART_SEPARATOR + p + STATEMENT_PART_SEPARATOR + o;
\r
1492 // private String toOutgoingTableRow(IEntity subject, Statement stm) {
\r
1493 // boolean isAcquired = !subject.equals(stm.getSubject());
\r
1495 // String plainCell = "%s";
\r
1496 // String hrefCell = "<a href=\"%s\">%s</a>";
\r
1497 // String formatTemplate = isAcquired
\r
1498 // ? "<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
1499 // : "<tr>\n<td>{1}</td>\n<td>{1}</td>\n<td>{1}</td>\n<td>{1}</td>\n</tr>";
\r
1500 // String format = NLS.bind(formatTemplate, plainCell, hrefCell);
\r
1501 //// System.out.println("format: " + format);
\r
1503 // IEntity s = stm.getSubject();
\r
1504 // IEntity p = stm.getPredicate();
\r
1505 // IEntity o = stm.getObject();
\r
1507 //// String timePart = "[" + timeToString(t.getBegin()) + ", " + timeToString(t.getEnd()) + "]";
\r
1510 // return !isAcquired
\r
1511 // ? String.format(format,
\r
1512 // "about:blank-remove" + getStatementString(stm), "Remove",
\r
1513 // "about:blank-link" + getLinkString(s), safeReadableString(s),
\r
1514 // "about:blank-link" + getLinkString(p), safeReadableString(p),
\r
1515 // "about:blank-link" + getLinkString(o), safeReadableString(o))
\r
1516 // : String.format(format,
\r
1518 // "about:blank-link" + getLinkString(s), safeReadableString(s),
\r
1519 // "about:blank-link" + getLinkString(p), safeReadableString(p),
\r
1520 // "about:blank-link" + getLinkString(o), safeReadableString(o)
\r
1522 // } catch (Throwable throwable) {
\r
1523 // return "<tr><td colspan=\"4\"><font color=\"red\"><i>"+throwable.getClass().getName()+"</i> "+throwable.getMessage()+"</font></td></tr>";
\r
1527 // private String intervalToString(Interval time) {
\r
1528 // return timeToString(time.getBegin()) + ", " + timeToString(time.getEnd());
\r
1531 // DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
\r
1533 // private String timeToString(long time) {
\r
1534 // if (time == Long.MIN_VALUE)
\r
1535 // return "-∞";
\r
1536 // if (time == Long.MAX_VALUE)
\r
1537 // return "+∞";
\r
1538 // //return String.valueOf(time);
\r
1539 // Date d = new Date(time);
\r
1540 // return dateTimeFormat.format(d);
\r
1543 private String getHead() {
\r
1544 String result = "";
\r
1545 if (cssPath != null) {
\r
1546 result = "<link href=\"" + cssPath + "\" rel=\"stylesheet\" type=\"text/css\">";
\r