From: luukkainen Date: Wed, 16 Jan 2013 10:42:17 +0000 (+0000) Subject: Sysdyn charts component as a separate plug-in. X-Git-Tag: simantics-1.10.1~77 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=8d1bcba9132798480b0fa32892adad3356f2e7f0;p=simantics%2Fsysdyn.git Sysdyn charts component as a separate plug-in. refs #3988 git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@26617 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.jfreechart/.classpath b/org.simantics.jfreechart/.classpath new file mode 100644 index 00000000..8a8f1668 --- /dev/null +++ b/org.simantics.jfreechart/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.jfreechart/.project b/org.simantics.jfreechart/.project new file mode 100644 index 00000000..9c948e2d --- /dev/null +++ b/org.simantics.jfreechart/.project @@ -0,0 +1,28 @@ + + + org.simantics.jfreechart + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.jfreechart/.settings/org.eclipse.jdt.core.prefs b/org.simantics.jfreechart/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f287d53c --- /dev/null +++ b/org.simantics.jfreechart/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/org.simantics.jfreechart/META-INF/MANIFEST.MF b/org.simantics.jfreechart/META-INF/MANIFEST.MF new file mode 100644 index 00000000..945a09d6 --- /dev/null +++ b/org.simantics.jfreechart/META-INF/MANIFEST.MF @@ -0,0 +1,37 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Jfreechart +Bundle-SymbolicName: org.simantics.jfreechart;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.jfreechart.internal.Activator +Bundle-Vendor: VTT +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.jfree.jchart;bundle-version="1.0.13", + org.jfree.jcommon;bundle-version="1.0.16", + org.simantics.jfreechart.ontology;bundle-version="1.0.0", + org.simantics.db;bundle-version="1.1.0", + org.simantics.db.layer0;bundle-version="1.1.0", + org.simantics.layer0;bundle-version="1.1.0", + org.simantics.diagram;bundle-version="1.1.1", + org.simantics.diagram.ontology;bundle-version="2.2.0", + org.simantics.modeling;bundle-version="1.1.1", + org.simantics.ui;bundle-version="1.0.0", + org.simantics.browsing.ui.common;bundle-version="1.1.0", + org.simantics.browsing.ui.ontology;bundle-version="1.1.0", + org.simantics.browsing.ui.swt;bundle-version="1.1.0", + org.simantics.modeling.ui;bundle-version="1.1.1", + org.simantics.layer0.utils;bundle-version="1.1.0", + org.simantics.scenegraph.swing;bundle-version="1.0.0", + org.simantics.browsing.ui.model;bundle-version="1.0.0", + org.simantics.selectionview;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.jfreechart, + org.simantics.jfreechart.chart, + org.simantics.jfreechart.chart.element, + org.simantics.jfreechart.chart.ge, + org.simantics.jfreechart.chart.properties, + org.simantics.jfreechart.chart.properties.bar, + org.simantics.jfreechart.chart.properties.pie, + org.simantics.jfreechart.chart.properties.xyline diff --git a/org.simantics.jfreechart/adapters.xml b/org.simantics.jfreechart/adapters.xml new file mode 100644 index 00000000..b6a4e8f0 --- /dev/null +++ b/org.simantics.jfreechart/adapters.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.simantics.jfreechart/build.properties b/org.simantics.jfreechart/build.properties new file mode 100644 index 00000000..6f20375d --- /dev/null +++ b/org.simantics.jfreechart/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.simantics.jfreechart/icons/chart_bar_light.png b/org.simantics.jfreechart/icons/chart_bar_light.png new file mode 100644 index 00000000..6069b5c9 Binary files /dev/null and b/org.simantics.jfreechart/icons/chart_bar_light.png differ diff --git a/org.simantics.jfreechart/icons/chart_line_light.png b/org.simantics.jfreechart/icons/chart_line_light.png new file mode 100644 index 00000000..2a77b242 Binary files /dev/null and b/org.simantics.jfreechart/icons/chart_line_light.png differ diff --git a/org.simantics.jfreechart/icons/chart_pie_light.png b/org.simantics.jfreechart/icons/chart_pie_light.png new file mode 100644 index 00000000..fa553c29 Binary files /dev/null and b/org.simantics.jfreechart/icons/chart_pie_light.png differ diff --git a/org.simantics.jfreechart/icons/close.gif b/org.simantics.jfreechart/icons/close.gif new file mode 100644 index 00000000..1aca259d Binary files /dev/null and b/org.simantics.jfreechart/icons/close.gif differ diff --git a/org.simantics.jfreechart/icons/maximize.gif b/org.simantics.jfreechart/icons/maximize.gif new file mode 100644 index 00000000..5e5999be Binary files /dev/null and b/org.simantics.jfreechart/icons/maximize.gif differ diff --git a/org.simantics.jfreechart/icons/minimize.gif b/org.simantics.jfreechart/icons/minimize.gif new file mode 100644 index 00000000..7402dc9f Binary files /dev/null and b/org.simantics.jfreechart/icons/minimize.gif differ diff --git a/org.simantics.jfreechart/plugin.xml b/org.simantics.jfreechart/plugin.xml new file mode 100644 index 00000000..9db7546b --- /dev/null +++ b/org.simantics.jfreechart/plugin.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartDropTarget.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartDropTarget.java new file mode 100644 index 00000000..e62bf98c --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartDropTarget.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetAdapter; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.simantics.db.Resource; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Drop target for dropping charts in chart panel + * @author Teemu Lempinen + * + */ +public class ChartDropTarget extends DropTargetAdapter { + + private Composite separator; + private ChartPanelElement element; + private Display display; + private ChartPanel panel; + + public ChartDropTarget(Composite separator, ChartPanelElement element, ChartPanel panel) { + this.separator = separator; + this.display = separator.getDisplay(); + this.element = element; + this.panel = panel; + } + + + + /** + * Display effect on the composite when drag entered + */ + @Override + public void dragEnter(DropTargetEvent event) { + if ((event.operations & DND.DROP_COPY) != 0) { + event.detail = DND.DROP_COPY; + } else if ((event.operations & DND.DROP_MOVE) != 0) { + event.detail = DND.DROP_MOVE; + } else { + event.detail = DND.DROP_NONE; + } + separator.setBackground(display.getSystemColor(SWT.COLOR_DARK_GRAY)); + } + + /** + * Revert effect when drag leaves + */ + @Override + public void dragLeave(DropTargetEvent event) { + separator.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); + } + + /** + * Drop the data to chart panel + */ + @Override + public void drop(DropTargetEvent event) { + Resource chartResource = AdaptionUtils.adaptToSingle(event.data, Resource.class); + if(chartResource != null) + panel.addChart(chartResource, element); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanel.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanel.java new file mode 100644 index 00000000..a698efe8 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanel.java @@ -0,0 +1,471 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart; + +import java.util.ArrayList; +import java.util.LinkedHashMap; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +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.Transfer; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.part.ViewPart; +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.AsyncListener; +import org.simantics.db.request.Read; +import org.simantics.jfreechart.internal.Activator; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.dnd.LocalObjectTransfer; +import org.simantics.utils.RunnableWithObject; + +/** + * Chart panel displays multiple charts in a single view. The view can be oriented + * vertically or horizontally, the default is vertical. Charts can be added, removed + * minimized or expanded. The order of the charts can be changed by dragging the charts. + * + * @author Teemu Lempinen + * + */ +public class ChartPanel extends ViewPart { + + private Composite body; + private ScrolledComposite sc; + + private IDialogSettings settings; + private LinkedHashMap charts; + private ArrayList minimizedResources; + + private ArrayList chartElements; + + public static final String CHART_PANEL_SETTINGS = "CHART_PANEL_SETTINGS"; + public static final String CHARTS = "CHART_PANEL_CHARTS"; + public static final String MINIMIZED_CHARTS = "CHART_PANEL_MINIMIZED_CHARTS"; + public static final String CHART_PANEL_ORIENTATION = "CHART_PANEL_ORIENTATION"; + + public static final String CHART_PANEL_VERTICAL = "CHART_PANEL_ORIENTATION_VERTICAL"; + public static final String CHART_PANEL_HORIZONTAL = "CHART_PANEL_ORIENTATION_HORIZONTAL"; + + private boolean vertical = true; + + /** + * Initialize the view. Load charts that have previously been open (if there are any). + */ + @Override + public void init(IViewSite site, IMemento memento) throws PartInitException { + super.init(site, memento); + + minimizedResources = new ArrayList(); + + settings = Activator.getDefault().getDialogSettings().getSection(CHART_PANEL_SETTINGS); + + // Initialize settings if there are no settings + if (settings == null) { + settings = Activator.getDefault().getDialogSettings().addNewSection(CHART_PANEL_SETTINGS); + } + + if(settings.getArray(CHARTS) == null) { + String[] chartUris = new String[] {}; + settings.put(CHARTS, chartUris); + } + + if(settings.getArray(MINIMIZED_CHARTS) == null) { + String[] minimizedChartUris = new String[] {}; + settings.put(MINIMIZED_CHARTS, minimizedChartUris); + } + + // initialize chart lists + charts = new LinkedHashMap(); + + // add chart resources to chart lists from settings + try { + SimanticsUI.getSession().syncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Resource chart = null; + String[] chartURIs = settings.getArray(CHARTS); + for(String uri : chartURIs) { + chart = graph.getPossibleResource(uri); + if(chart != null && graph.isInstanceOf(chart, jfree.Chart)) { + charts.put(chart, null); + setChartExistingListener(chart); + } + } + + String[] minimizedUris = settings.getArray(MINIMIZED_CHARTS); + for(String uri : minimizedUris) { + chart = graph.getPossibleResource(uri); + if(chart != null && graph.isInstanceOf(chart, jfree.Chart)) { + minimizedResources.add(chart); + } + } + } + }); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + + // set the orientation of the panel + String orientation = settings.get(CHART_PANEL_ORIENTATION); + if(CHART_PANEL_VERTICAL.equals(orientation)) + this.vertical = true; + else if(CHART_PANEL_HORIZONTAL.equals(orientation)) + this.vertical = false; + + } + + /** + * Create a scrolled composite that will contain all the charts, then call the actual + * content creator. + */ + @Override + public void createPartControl(Composite parent) { + sc = new ScrolledComposite(parent, SWT.NONE | SWT.H_SCROLL | SWT.V_SCROLL); + GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(sc); + GridDataFactory.fillDefaults().grab(true, true).applyTo(sc); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + sc.getVerticalBar().setIncrement(sc.getVerticalBar().getIncrement()*3); + sc.getHorizontalBar().setIncrement(sc.getHorizontalBar().getIncrement()*3); + + body = new Composite(sc, SWT.NONE); + GridLayoutFactory.fillDefaults().margins(3, 0).spacing(0, 0).applyTo(body); + GridDataFactory.fillDefaults().grab(true, true).applyTo(body); + + sc.setContent(body); + createContents(); + + setupDropTarget(); + + } + + /** + * Creates the contents of this chart panel. + * Removes all old contents before creating new content + */ + private void createContents() { + chartElements = new ArrayList(); + + for(Control child : body.getChildren()) { + child.dispose(); + } + + // Set the initial layout + ElementContainer elementHolder; + for(Resource e : charts.keySet()) { + elementHolder = new ElementContainer(body, SWT.NONE); + elementHolder.setBackground(new Color(elementHolder.getDisplay(), 255, 0, 0)); + ChartPanelElement element = new ChartPanelElement(elementHolder, this, e, SWT.NONE); + elementHolder.setLayout(GridLayoutFactory.copyLayout((GridLayout)element.getLayout())); + chartElements.add(element); + charts.put(e, element); + if(minimizedResources.contains(e)) { + element.toggleMinimize(); + } + } + + elementHolder = new ElementContainer(body, SWT.NONE); + elementHolder.setBackground(new Color(elementHolder.getDisplay(), 0, 255, 0)); + ChartPanelElement element = new ChartPanelElement(elementHolder, this, null, SWT.NONE); // Last element is empty -> only the separator + elementHolder.setLayout(GridLayoutFactory.copyLayout((GridLayout)element.getLayout())); + chartElements.add(element); + + layout(); + saveState(); + + } + + /** + * Lays out this panel (the body composite) + */ + public void layout() { + if(vertical) { + GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(body); + GridDataFactory.fillDefaults().grab(true, true).applyTo(body); + } else { + // Need to calculate horizontal elements for gridLayout + int chartPanels = chartElements.size(); + GridLayoutFactory.fillDefaults().spacing(0, 0).numColumns(chartPanels).applyTo(body); + GridDataFactory.fillDefaults().grab(true, true).applyTo(body); + } + body.layout(); + sc.setMinSize(body.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + } + + @Override + public void setFocus() { + if(!sc.isDisposed()) + sc.setFocus(); + } + + @Override + public void saveState(IMemento memento) { + super.saveState(memento); + saveState(); + } + + /** + * Save the current state of the view to IDialogSettings + */ + public void saveState() { + try { + SimanticsUI.getSession().syncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + if (settings != null) { + String[] uris = new String[chartElements.size() - 1]; + ArrayList minimized = new ArrayList(); + minimizedResources.clear(); + for(int i = 0; i < uris.length; i++) { + ChartPanelElement e = chartElements.get(i); + Resource r = e.getResource(); + if(r != null) { + uris[i] = graph.getURI(r); + if(e.isMinimized()) { + minimized.add(uris[i]); + minimizedResources.add(r); + } + } else { + uris[i] = ""; + } + } + settings.put(CHARTS, uris); + if(!minimized.isEmpty()) + settings.put(MINIMIZED_CHARTS, minimized.toArray(new String[minimized.size()])); + else + settings.put(MINIMIZED_CHARTS, new String[0]); + + if(vertical) + settings.put(CHART_PANEL_ORIENTATION, CHART_PANEL_VERTICAL); + else + settings.put(CHART_PANEL_ORIENTATION, CHART_PANEL_HORIZONTAL); + } + } + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + + /** + * Set the orientation for this chart panel. + * + * @param orientation Orientation (ChartPanel.CHART_PANEL_VERTICAL or ChartPanel.CHART_PANEL_HORIZONTAL) + */ + public void setOrientation(String orientation) { + if(CHART_PANEL_VERTICAL.equals(orientation)) + this.vertical = true; + else { + this.vertical = false; + } + createContents(); + } + + /** + * Removes a chart from this panel + * + * @param chart The chart to be removed + */ + public void removeChart(Resource chart) { + ChartPanelElement element = charts.get(chart); + chartElements.remove(element); + element.getParent().dispose(); + charts.remove(chart); + minimizedResources.remove(chart); + saveState(); + layout(); + } + + /** + * Sets up drag-scrolling for a scrolled composite + * + * @param control + */ + protected void setupDropTarget() { + DropTarget target = new DropTarget(sc, DND.DROP_MOVE); + target.setTransfer(new Transfer[] { LocalObjectTransfer.getTransfer() }); + + target.addDropListener(new DropTargetAdapter() { + + private int activeMargin = 20; + private int moveAmount = 1; + + @Override + public void dragOver(DropTargetEvent event) { + Point original = sc.getOrigin(); + Point origin = sc.getOrigin(); + Point pointer = sc.toControl(event.x, event.y); + Rectangle bounds = sc.getBounds(); + + if(pointer.y < activeMargin) + origin.y = origin.y - moveAmount; + else if(bounds.height - pointer.y < activeMargin) + origin.y = origin.y + moveAmount; + if(pointer.x < activeMargin) + origin.x = origin.x - moveAmount; + else if(bounds.width - pointer.x < activeMargin) + origin.x = origin.x + moveAmount; + + if(origin != original) { + sc.setOrigin (origin.x, origin.y); + sc.redraw(); + } + } + + }); + + DropTarget target2 = new DropTarget(body, DND.DROP_COPY | DND.DROP_MOVE); + target2.setTransfer(new Transfer[] { LocalObjectTransfer.getTransfer() }); + target2.addDropListener(new ChartDropTarget(body, null, this)); + + } + + /** + * Is the panel vertically oriented + * @return Is the panel vertically oriented + */ + public boolean isVertical() { + return vertical; + } + + /** + * Adds chart after given element. If element == null, adds chart to the top. + * + * @param element To which place the chart will be placed. (null allowed) + */ + public void addChart(Resource chartResource, ChartPanelElement element) { + addChart(chartResource, element, true); + } + + /** + * Adds chart after given element. If element == null, adds chart to the top. + * + * @param element To which place the chart will be placed. (null allowed) + * @param layout refresh layout. use with vertical layout. + */ + public void addChart(Resource chartResource, ChartPanelElement element, boolean layout) { + if(element == null) + element = chartElements.get(chartElements.size() - 1); + int index = chartElements.indexOf(element); + if(index >= 0) { + ChartPanelElement e = chartElements.get(index); + ChartPanelElement newElement; + + if(charts.containsKey(chartResource)) { + // Old element being moved to a new place + newElement = charts.get(chartResource); + int oldIndex = chartElements.indexOf(newElement); + if(newElement.equals(element) || oldIndex == index - 1) + return; // Not moving anywhere, do nothing + Composite oldParent = newElement.getParent(); + newElement.setParent(e.getParent()); + oldParent.dispose(); + if(oldIndex < index) + index--; + chartElements.remove(newElement); + } else { + newElement = new ChartPanelElement(e.getParent(), this, chartResource, SWT.NONE); + } + + // Add a new chart element to the location of the old element + chartElements.add(index, newElement); + charts.put(chartResource, newElement); + + ElementContainer elementHolder; + // Move elements back after index + for(int i = index + 1 /*indexes after the new element*/; i < chartElements.size(); i++) { + e = chartElements.get(i); + if(i == chartElements.size() - 1) { + // last element (the empty element) element to a new container + elementHolder = new ElementContainer(body, SWT.NONE); + elementHolder.setBackground(new Color(elementHolder.getDisplay(), 0, 0, 255)); + elementHolder.setLayout(GridLayoutFactory.copyLayout((GridLayout)e.getLayout())); + e.setParent(elementHolder); + } else { + // element to the next elements container + elementHolder = (ElementContainer)chartElements.get(i + 1).getParent(); + e.setParent(elementHolder); + } + } + + layout(); + saveState(); + } + } + + /** + * Set a listener to listen if the chart resource has been removed. + * If the resource has been removed, close also the chart element in this panel. + * + * @param chart Listened chart resource + */ + private void setChartExistingListener(final Resource chart) { + SimanticsUI.getSession().asyncRequest(new Read() { + + @Override + public Boolean perform(ReadGraph graph) throws DatabaseException { + return graph.hasStatement(chart); + } + }, new AsyncListener() { + + boolean disposed = false; + + @Override + public void execute(AsyncReadGraph graph, Boolean result) { + if(result != null && result == false && body != null && !body.isDisposed()) { + body.getDisplay().asyncExec(new RunnableWithObject(chart){ + public void run() { + removeChart((Resource)getObject()); + } + }) ; + disposed = true; + } + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return !disposed && !charts.containsKey(chart); + } + }); + } + + public ArrayList getElements() { + return chartElements; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelElement.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelElement.java new file mode 100644 index 00000000..3102514d --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelElement.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.simantics.db.Resource; +import org.simantics.jfreechart.chart.ChartComposite; +import org.simantics.ui.dnd.LocalObjectTransfer; + +/** + * This class represents an expanded chart element in {@link ChartPanel}. It contains + * a header {@link ChartPanelHeader} and the actual chart. + * + * @author Teemu Lempinen + * + */ +public class ChartPanelElement extends Composite { + + public static int CHART_MINIMUM_WIDTH = 300; + public static int CHART_MINIMUM_HEIGHT = 200; + + private ChartPanel panel; + private ChartComposite chartComposite; + private Resource chartResource; + private boolean minimized = false; + + public Resource getResource() { + return chartResource; + } + + @Override + public Object getLayoutData () { + checkWidget(); + Object oldData = super.getLayoutData(); + if(oldData == null || !(oldData instanceof GridData)) { + oldData = GridDataFactory.fillDefaults().create(); + } + + int size = panel.getElements().size(); + GridData data = (GridData) oldData; + // Horizontal data + data.widthHint = CHART_MINIMUM_WIDTH; + if(getResource() == null && size == 1) { + data.grabExcessHorizontalSpace = true; + } else if(getResource() == null && !panel.isVertical()){ + data.grabExcessHorizontalSpace = false; + data.widthHint = SWT.DEFAULT; + } else if(minimized && !panel.isVertical()) { + data.grabExcessHorizontalSpace = false; + data.widthHint = SWT.DEFAULT; + } else { + data.grabExcessHorizontalSpace = true; + } + + // Vertical data + if(getResource() == null && size == 1) { + data.grabExcessVerticalSpace = true; + } else if(!minimized && getResource() != null) { + data.grabExcessVerticalSpace = true; + data.heightHint = CHART_MINIMUM_HEIGHT; + } else if(!panel.isVertical()){ + data.grabExcessVerticalSpace = true; + } else { + data.grabExcessVerticalSpace = false; + data.heightHint = SWT.DEFAULT; + } + return data; + } + + /** + * Creates an expanded chart panel element into parent composite. + * + * @param parent The parent composite where the chart element is created + * @param panel The {@link ChartPanel} containing the chart element + * @param name The name of the chart + * @param style The Style of the created chart element + */ + public ChartPanelElement(Composite parent, ChartPanel panel, Resource chartResource, int style) { + this(parent, panel, chartResource, false, style); + } + + /** + * Creates a chart panel element into parent composite. + * @param parent The parent composite where the chart element is created + * @param panel The {@link ChartPanel} containing the chart element + * @param name The name of the chart + * @param minimized Is the chart-section minimized + * @param style The Style of the created chart element + */ + public ChartPanelElement(Composite parent, ChartPanel panel, Resource chartResource, boolean minimized, int style) { + super(parent, style | SWT.NONE ); + + this.panel = panel; + this.chartResource = chartResource; + this.minimized = minimized; + + if(panel.isVertical() || getResource() == null) + GridLayoutFactory.fillDefaults().spacing(0,0).applyTo(this); + else + GridLayoutFactory.fillDefaults().numColumns(2).spacing(0,0).applyTo(this); + + GridDataFactory.fillDefaults().applyTo(this); + + // Separator for dropping other elements + ChartPanelSeparator separator = new ChartPanelSeparator(this, panel, this, SWT.NONE); + + if (chartResource != null) { + Composite c = new Composite(this, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(c); + GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(c); + // Header + new ChartPanelHeader(c, this, chartResource, SWT.BORDER); + + // Chart + chartComposite = new ChartComposite(c, chartResource, SWT.BORDER); + } + + DropTarget target = new DropTarget(this, DND.DROP_COPY | DND.DROP_MOVE); + target.setTransfer(new Transfer[] { LocalObjectTransfer.getTransfer() }); + target.addDropListener(new ChartDropTarget(separator, this, panel)); + + } + + /** + * Returns the chart resource associated with this element + * @return chart resource + */ + public Resource getChartResource() { + return this.chartResource; + } + + /** + * Returns the minimized state of this element + * @return is the element minimized + */ + public boolean isMinimized() { + return minimized; + } + + /** + * Change the minimized state of this element + */ + public void toggleMinimize() { + toggleMinimize(false); + } + /** + * Change the minimized state of this element + */ + public void toggleMinimize(boolean callSave) { + minimized = Boolean.FALSE.equals(minimized); + GridData data = (GridData) chartComposite.getLayoutData(); + if(panel.isVertical()) + data.exclude = minimized; + else + data.exclude = false; + chartComposite.setVisible(!minimized); + + Composite parent = getParent(); + data = (GridData) getLayoutData(); + GridData parentData = (GridData)parent.getLayoutData(); + parentData.grabExcessHorizontalSpace = data.grabExcessHorizontalSpace; + parentData.grabExcessVerticalSpace = data.grabExcessVerticalSpace; + parentData.heightHint = data.heightHint; + + if(callSave) { + panel.saveState(); + } + panel.layout(); + } + + /** + * Remove this chart panel element from its panel + */ + public void remove() { + panel.removeChart(chartResource); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelHeader.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelHeader.java new file mode 100644 index 00000000..5935c34f --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelHeader.java @@ -0,0 +1,397 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.Read; +import org.simantics.jfreechart.internal.Activator; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.dnd.LocalObjectTransfer; +import org.simantics.utils.datastructures.Pair; + +/** + * Header of a chart element in {@link ChartPanel}. Only this header is + * shown if a chart is minimized. If a chart is expanded, this header is added + * to the charts {@link ChartPanelElement}. + * + * @author Teemu Lempinen + * + */ +public class ChartPanelHeader extends Composite { + + public static int HEADER_MINIMUM_WIDTH = 250; + private ChartPanelElement element; + private Resource resource; + private Label name; + private Canvas iconCanvas; + private Image icon; + private ToolItem minimize, remove; + private Color defaultColor, darker, evenDarker; + private Image gradientBackgroundImage, borderImage; + + private static ImageDescriptor closeDescriptor = ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/close.gif")); + private static Image closeImage = closeDescriptor.createImage(); + + private static ImageDescriptor minimizeDescriptor = ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/minimize.gif")); + private static Image minimizeImage = minimizeDescriptor.createImage(); + + private static ImageDescriptor maximizeDescriptor = ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/maximize.gif")); + private static Image maximizeImage = maximizeDescriptor.createImage(); + + private static ImageDescriptor lineChartDescriptor = ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/chart_line_light.png")); + private static Image lineChartImage = lineChartDescriptor.createImage(); + + private static ImageDescriptor barChartDescriptor = ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/chart_bar_light.png")); + private static Image barChartImage = barChartDescriptor.createImage(); + + private static ImageDescriptor pieChartDescriptor = ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/chart_pie_light.png")); + private static Image pieChartImage = pieChartDescriptor.createImage(); + + + /** + * Chart panel header with minimize and close buttons. + * + * @param parent The composite where the header is added + * @param panel The {@link ChartPanel} containing the header + * @param name The name of the chart + * @param style he Style of the created chart element + */ + public ChartPanelHeader(Composite c, ChartPanelElement element, Resource chartResource, int style) { + super(c, style); + this.resource = chartResource; + this.element = element; + + GridLayoutFactory.fillDefaults().margins(3, 0).numColumns(3).applyTo(this); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this); + + // Colors + + // Chart icon + iconCanvas = new Canvas (this, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).hint(16, 16).applyTo(iconCanvas); + iconCanvas.addPaintListener (new PaintListener() { + + @Override + public void paintControl(PaintEvent e) { + if(icon != null) + e.gc.drawImage (icon, 0, 0); + } + }); + + // Label for the chart name (also minimize/expand) + name = new Label(this, SWT.NONE); + + try { + // name updater + Pair result = SimanticsUI.getSession().syncRequest(new Read>() { + + @Override + public Pair perform(ReadGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + String label = graph.getPossibleRelatedValue(resource, l0.HasLabel); + Image image = null; + Resource plot = graph.syncRequest(new PossibleObjectWithType(resource, l0.ConsistsOf, jfree.Plot)); + if(plot != null) { + if(graph.isInstanceOf(plot, jfree.CategoryPlot)) + image = barChartImage; + else if(graph.isInstanceOf(plot, jfree.PiePlot)) + image = pieChartImage; + else + image = lineChartImage; + } + return new Pair(label, image); + } + + }, new Listener>() { + + @Override + public void execute(final Pair result) { + if(result == null) + return; + + name.getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + if(!name.isDisposed() && result.first != null) + name.setText(result.first); + + if(!iconCanvas.isDisposed() && result.second != null) { + icon = result.second; + iconCanvas.redraw(); + ChartPanelHeader.this.layout(); + } + } + }); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return name.isDisposed(); + } + + }); + name.setText(result.first); + } catch (DatabaseException e) { + e.printStackTrace(); + name.setText("No label"); + } + GridDataFactory.fillDefaults().grab(true, false).applyTo(name); + + ToolBar toolbar = new ToolBar(this, SWT.FLAT); + // item for minimizing/expanding chart + minimize = new ToolItem(toolbar, SWT.PUSH); + minimize.addSelectionListener(new MinimizeListener()); + if(isMinimized()) { + minimize.setToolTipText("Expand"); + minimize.setImage(maximizeImage); + } else { + minimize.setToolTipText("Minimize"); + minimize.setImage(minimizeImage); + } + + // item for closing/removing the chart + remove = new ToolItem(toolbar, SWT.PUSH); + remove.setImage(closeImage); + remove.addSelectionListener(new RemoveChartListener()); + remove.setToolTipText("Remove"); + + + /* ******************************** + * DnD + * ********************************/ + + // Allow data to be copied or moved from the drag source + int operations = DND.DROP_MOVE; + source = new DragSource(name, operations); + + // Provide data in Text format + Transfer[] types = new Transfer[] { LocalObjectTransfer.getTransfer() }; + source.setTransfer(types); + dragSourceListener = new DragSourceListener() { + + @Override + public void dragStart(DragSourceEvent event) { + if(name.isDisposed()) + event.doit = false; + event.detail = DND.DROP_LINK; + + } + + @Override + public void dragSetData(DragSourceEvent event) { + event.data = new StructuredSelection(resource); + } + + @Override + public void dragFinished(DragSourceEvent event) { + } + }; + source.addDragListener(dragSourceListener); + + name.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + if(dragSourceListener != null && source != null && !source.isDisposed()) { + source.removeDragListener(dragSourceListener); + } + } + }); + this.setBackgroundImage(getGradientBackgroundImage()); + this.setBackgroundMode(SWT.INHERIT_FORCE); + + this.addListener(SWT.MouseEnter, new EnterListener()); + this.addListener(SWT.MouseExit, new ExitListener()); + + for(Control child : this.getChildren()) { + child.addListener(SWT.MouseEnter, new EnterListener()); + child.addListener(SWT.MouseExit, new ExitListener()); + + } + } + + private class EnterListener implements org.eclipse.swt.widgets.Listener { + public void handleEvent(Event event) { + ChartPanelHeader.this.setBackgroundImage(getHighlightedGradientBackgroundImage()); + } + } + + private class ExitListener implements org.eclipse.swt.widgets.Listener { + public void handleEvent(Event event) { + ChartPanelHeader.this.setBackgroundImage(getGradientBackgroundImage()); + } + } + + private void createColors() { + if(defaultColor == null) { + defaultColor = getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + try { + defaultColor = new Color(getDisplay(), defaultColor.getRed() + 500, defaultColor.getGreen() + 10, defaultColor.getBlue() + 10); + } catch (IllegalArgumentException e) { + // Do nothing, use the default color + } + } + + if(darker == null) { + try { + darker = new Color(getDisplay(), defaultColor.getRed() - 30, defaultColor.getGreen() - 30, defaultColor.getBlue() - 30); + } catch (IllegalArgumentException e) { + // Do nothing, use the default color + darker = defaultColor; + } + } + + if(evenDarker == null) { + try { + evenDarker = new Color(getDisplay(), defaultColor.getRed() - 50, defaultColor.getGreen() - 50, defaultColor.getBlue() - 50); + } catch (IllegalArgumentException e) { + // Do nothing, use the default color + evenDarker = defaultColor; + } + } + + } + + private Image getHighlightedGradientBackgroundImage() { + createColors(); + this.layout(); + Point size = this.getSize(); + + borderImage = new Image(this.getDisplay(), 1, Math.max(1, size.y)); + GC gc = new GC(borderImage); + gc.setForeground(defaultColor); + gc.setBackground(evenDarker); + gc.fillGradientRectangle(0, 0, 1, size.y, true); + gc.dispose(); + + return borderImage; + } + + private Image getGradientBackgroundImage() { + createColors(); + this.layout(); + Point size = this.computeSize(SWT.DEFAULT, SWT.DEFAULT); + if(gradientBackgroundImage == null) { + gradientBackgroundImage = new Image(this.getDisplay(), 1, Math.max(1, size.y)); + GC gc = new GC(gradientBackgroundImage); + gc.setForeground(defaultColor); + gc.setBackground(darker); + gc.fillGradientRectangle(0, 0, 1, size.y, true); + gc.dispose(); + } + + return gradientBackgroundImage; + } + + private DragSourceListener dragSourceListener; + private DragSource source; + + /** + * Return true if this element is minimized, false if expanded + * @return true if this element is minimized, false if expanded + */ + private boolean isMinimized() { + return element.isMinimized(); + } + + /** + * Listener to minimize chart button. Expands and minimizes + * the chart of this header. + * + * @author Teemu Lempinen + * + */ + private class MinimizeListener implements SelectionListener { + @Override + public void widgetSelected(SelectionEvent e) { + if(ChartPanelHeader.this.isDisposed()) + return; + + element.toggleMinimize(true); + + if(!name.isDisposed() && !minimize.isDisposed()) { + if(isMinimized()) { + minimize.setToolTipText("Expand"); + } else { + minimize.setToolTipText("Minimize"); + } + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + } + + /** + * Listener for removing this chart from the chart panel. + * + * @author Teemu Lempinen + * + */ + private class RemoveChartListener implements SelectionListener { + @Override + public void widgetSelected(SelectionEvent e) { + if(!ChartPanelHeader.this.isDisposed()) { + element.remove(); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelSeparator.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelSeparator.java new file mode 100644 index 00000000..5f7e5e0b --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/ChartPanelSeparator.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; + +/** + * Class for separating charts in {@link ChartPanel}. Acts as a drop participant for adding + * and moving charts in {@link ChartPanel}. + * + * @author Teemu Lempinen + * + */ +public class ChartPanelSeparator extends Composite { + + private ChartPanel panel; + + @Override + public Object getLayoutData() { + checkWidget(); + Object oldData = super.getLayoutData(); + if(oldData == null || !(oldData instanceof GridData)) { + oldData = GridDataFactory.fillDefaults().create(); + } + GridData data = (GridData) oldData; + // Empty panel -> drop area the size of the whole panel + if(panel.getElements().size() == 1 && panel.getElements().get(0).getResource() == null) { + data.grabExcessHorizontalSpace = true; + data.grabExcessVerticalSpace = true; + } + else { + if(panel.isVertical()) { + data.grabExcessHorizontalSpace = true; + data.grabExcessVerticalSpace = false; + } else { + data.grabExcessHorizontalSpace = false; + data.grabExcessVerticalSpace = true; + } + } + return data; + } + + /** + * Set up a small horizontal or vertical separator depending on SWT style + * + * @param parent + * @param style + */ + public ChartPanelSeparator(Composite parent, ChartPanel panel, ChartPanelElement element, int style) { + super(parent, style); + GridLayoutFactory.fillDefaults().margins(2, 2).applyTo(this); + GridDataFactory.fillDefaults().applyTo(this); + this.panel = panel; + addMouseListener(new SCFocusListener(panel)); + } + + + /** + * Listener for directing focus to scrollableComposite + * @author Teemu Lempinen + * + */ + private class SCFocusListener extends MouseAdapter { + ChartPanel panel; + public SCFocusListener(ChartPanel panel) { + this.panel = panel; + } + public void mouseDown(MouseEvent e) { + panel.setFocus(); + } + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/ElementContainer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/ElementContainer.java new file mode 100644 index 00000000..37753607 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/ElementContainer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** + * Container for a chart panel element. Needed for + * moving chart panel elements around using setParent() + * @author Teemu Lempinen + * + */ +public class ElementContainer extends Composite { + + @Override + public Object getLayoutData () { + Control[] children = getChildren(); + if(children.length == 1) { + if(children[0] instanceof ChartPanelElement) { + ChartPanelElement element = (ChartPanelElement)children[0]; + return element.getLayoutData(); + } + } + return super.getLayoutData(); + } + + public ElementContainer(Composite parent, int style) { + super(parent, style); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractAxis.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractAxis.java new file mode 100644 index 00000000..4439a9ca --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractAxis.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import java.awt.Color; + +import org.jfree.chart.axis.Axis; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.G2DUtils; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Abstract axis class for all JFreeChart axis + * @author Teemu Lempinen + * + */ +public abstract class AbstractAxis implements IAxis { + + protected Axis axis; + protected String label; + protected Boolean tMarksVisible, tLabelsVisible, labelVisible, lineVisible; + protected Color color; + protected Double min, max, rotate; + + /** + * Creates a new axis + * @param graph ReadGraph + * @param axisResource resource of type JFreeChart.NumberAxis + */ + public AbstractAxis(ReadGraph graph, Resource axisResource) { + try { + /* + * Axis is practically always called from a listener, + * so it is safe to always create a new axis every time. + * + * The parent listener takes care that the axis is updated. + * (And the code stays much more readable) + */ + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + label = graph.getPossibleRelatedValue(axisResource, l0.HasLabel); + tMarksVisible = graph.getPossibleRelatedValue(axisResource, jfree.Axis_visibleTickMarks, Bindings.BOOLEAN); + tLabelsVisible = graph.getPossibleRelatedValue(axisResource, jfree.Axis_visibleTickLabels, Bindings.BOOLEAN); + labelVisible = graph.getPossibleRelatedValue(axisResource, jfree.Axis_visibleLabel, Bindings.BOOLEAN); + lineVisible = graph.getPossibleRelatedValue(axisResource, jfree.Axis_visibleAxisLine, Bindings.BOOLEAN); + Resource c = graph.getPossibleObject(axisResource, jfree.color); + color = c == null ? null : G2DUtils.getColor(graph, c); + min = graph.getPossibleRelatedValue(axisResource, jfree.Axis_min, Bindings.DOUBLE); + max = graph.getPossibleRelatedValue(axisResource, jfree.Axis_max, Bindings.DOUBLE); + rotate = graph.getPossibleRelatedValue(axisResource, jfree.Axis_rotateLabelDegrees, Bindings.DOUBLE); + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + + @Override + public void dispose() { + + } + + @Override + public Axis getAxis() { + if(tMarksVisible != null && tMarksVisible == false) + axis.setTickMarksVisible(false); + if(tLabelsVisible != null && tLabelsVisible == false) + axis.setTickLabelsVisible(false); + if(lineVisible != null && lineVisible == false) + axis.setAxisLineVisible(false); + + if(color != null) { + axis.setAxisLinePaint(color); + axis.setLabelPaint(color); + axis.setTickLabelPaint(color); + axis.setTickMarkPaint(color); + } + // label exists and its visibility == null or true + if((labelVisible == null || labelVisible == true) && label != null) + axis.setLabel(label); + return axis; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractDataset.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractDataset.java new file mode 100644 index 00000000..3ff63afb --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractDataset.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + + +/** + * Abstract dataset class for all JFreeChart datasets + * + * @author Teemu Lempinen + * + */ +public abstract class AbstractDataset implements IDataset { + + protected Resource resource; + + public AbstractDataset(ReadGraph graph, Resource resource) { + this.resource = resource; + } + + @Override + public void dispose() { + + } + + @Override + public Resource getResource() { + return resource; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractPlot.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractPlot.java new file mode 100644 index 00000000..c00907da --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractPlot.java @@ -0,0 +1,212 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import java.util.ArrayList; +import java.util.HashMap; + +import javax.swing.SwingUtilities; + +import org.jfree.chart.axis.Axis; +import org.jfree.chart.plot.Plot; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.Read; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; + +/** + * Abstract plot class for all JFreeChart plots + * + * @author Teemu Lempinen + * + */ +public abstract class AbstractPlot implements IPlot { + + protected Resource resource; + protected Plot plot; + protected PlotProperties currentProperties; + private PlotPropertyListener listener; + + + public AbstractPlot(ReadGraph graph, Resource resource) { + this.resource = resource; + } + + @Override + public void dispose() { + if(currentProperties != null) { + for(IAxis axis : currentProperties.ranges) + axis.dispose(); + + for(IAxis axis : currentProperties.domains) + axis.dispose(); + + for(IDataset dataset : currentProperties.datasets) + dataset.dispose(); + } + if(listener != null) + listener.dispose(); + } + + @Override + public Resource getResource() { + return resource; + } + + protected abstract Plot newPlot(); + protected abstract void setPlotProperties(PlotProperties properties); + protected abstract void getOtherProperties(ReadGraph graph, PlotProperties properties) throws DatabaseException; + + @Override + public Plot getPlot() { + if(plot == null) + plot = newPlot(); + + if(listener == null || listener.isDisposed()) { + listener = new PlotPropertyListener(); + SimanticsUI.getSession().asyncRequest(new Read() { + + @Override + public PlotProperties perform(ReadGraph graph) throws DatabaseException { + + PlotProperties properties = new PlotProperties(); + + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + + HashMap axisMap = new HashMap(); + + // Get all range axis + Resource rangeList = graph.getPossibleObject(resource, jfree.Plot_rangeAxisList); + if(rangeList != null) { + for(Resource axisResource : ListUtils.toList(graph, rangeList)) { + IAxis axis = graph.adapt(axisResource, IAxis.class); + if(axis.getAxis() instanceof Axis) { + properties.ranges.add(axis); + axisMap.put(axisResource, axis); + } + } + } + + // Get all domain axis + // There usually is only one domain axis, but this supports also multiple domain axis + for(Resource axisResource : graph.syncRequest(new ObjectsWithType(resource, jfree.Plot_domainAxis, jfree.Axis))) { + IAxis axis = graph.adapt(axisResource, IAxis.class); + if(axis.getAxis() instanceof Axis) { + properties.domains.add(axis); + axisMap.put(axisResource, axis); + } + } + + // Get all datasets and map them to axis + for(Resource datasetResource : graph.syncRequest(new ObjectsWithType(resource, l0.ConsistsOf, jfree.Dataset))) { + IDataset dataset = graph.adapt(datasetResource, IDataset.class); + if(dataset != null) { + properties.datasets.add(dataset); + Resource axisResource = graph.getPossibleObject(datasetResource, jfree.Dataset_mapToRangeAxis); + IAxis axis; + if(axisMap.containsKey(axisResource)) { + axis = axisMap.get(axisResource); + properties.rangeMappings.put(dataset, axis); + } + + axisResource = graph.getPossibleObject(datasetResource, jfree.Dataset_mapToDomainAxis); + if(axisMap.containsKey(axisResource)) { + axis = axisMap.get(axisResource); + properties.domainMappings.put(dataset, axis); + } + } + } + getOtherProperties(graph, properties); + return properties; + + } + }, listener); + } + + return plot; + } + + protected class PlotProperties { + public ArrayList ranges; + public ArrayList domains; + public ArrayList datasets; + public HashMap rangeMappings; + public HashMap domainMappings; + public HashMap otherProperties; + + public PlotProperties() { + datasets = new ArrayList(); + rangeMappings = new HashMap(); + domainMappings = new HashMap(); + ranges = new ArrayList(); + domains = new ArrayList(); + otherProperties = new HashMap(); + } + + @Override + public boolean equals(Object other) { + if(!this.getClass().equals(other.getClass())) + return false; + PlotProperties p = (PlotProperties)other; + if(!ranges.equals(p.ranges)) + return false; + if(!domains.equals(p.domains)) + return false; + if(!datasets.equals(p.datasets)) + return false; + if(!rangeMappings.equals(p.rangeMappings)) + return false; + if(!domainMappings.equals(p.domainMappings)) + return false; + if(!otherProperties.equals(p.otherProperties)) + return false; + return true; + } + } + + private class PlotPropertyListener implements Listener { + + private boolean disposed = false; + + public void dispose() { + disposed = true; + } + @Override + public void execute(final PlotProperties result) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + setPlotProperties(result); + } + }); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return disposed; + } + + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractRenderer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractRenderer.java new file mode 100644 index 00000000..7621c357 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/AbstractRenderer.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +/** + * Abstract renderer class for all JFreeChart renderers + * @author Teemu Lempinen + * + */ +public abstract class AbstractRenderer implements IRenderer { + + protected Resource resource; + + public AbstractRenderer(ReadGraph graph, Resource resource) { + this.resource = resource; + } + + @Override + public void dispose() { + } + + @Override + public Resource getResource() { + return resource; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/BarRenderer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/BarRenderer.java new file mode 100644 index 00000000..30430d3b --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/BarRenderer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.labels.StandardCategoryToolTipGenerator; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + + +/** + * Normal bar renderer + * @author Teemu Lempinen + * + */ +public class BarRenderer extends AbstractRenderer { + + public BarRenderer(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + private org.jfree.chart.renderer.category.BarRenderer renderer; + + @Override + public org.jfree.chart.renderer.AbstractRenderer getRenderer() { + if(renderer == null) { + renderer = new org.jfree.chart.renderer.category.BarRenderer(); + renderer.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator()); + } + return renderer; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryAxis.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryAxis.java new file mode 100644 index 00000000..65731618 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryAxis.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.axis.Axis; +import org.jfree.chart.axis.CategoryLabelPositions; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +/** + * Class representing a JFreeChart.CategoryAxis + * + * @author Teemu Lempinen + * + */ +public class CategoryAxis extends AbstractAxis { + + public CategoryAxis(ReadGraph graph, Resource axisResource) { + super(graph, axisResource); + } + + @Override + public Axis getAxis() { + axis = new org.jfree.chart.axis.CategoryAxis(); + + if(rotate != null && rotate > 0) { + ((org.jfree.chart.axis.CategoryAxis)axis).setCategoryLabelPositions( + CategoryLabelPositions.createUpRotationLabelPositions(Math.toRadians(rotate))); + } + + return super.getAxis(); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryDataset.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryDataset.java new file mode 100644 index 00000000..8b67400b --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryDataset.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + + +/** + * Class representing a JFreeChart.CategoryDataset + * + * @author Teemu Lempinen + * + */ +public interface CategoryDataset extends IDataset { + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryPlot.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryPlot.java new file mode 100644 index 00000000..51ab9408 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/CategoryPlot.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.axis.CategoryAxis; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.Plot; +import org.jfree.chart.renderer.category.CategoryItemRenderer; +import org.jfree.ui.RectangleInsets; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class representing a CategoryPlot for JFreeChart + * @author Teemu Lempinen + * + */ +public class CategoryPlot extends AbstractPlot { + + public CategoryPlot(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + @Override + protected Plot newPlot() { + return new org.jfree.chart.plot.CategoryPlot(null, null, null, null); + } + + @Override + protected void setPlotProperties(PlotProperties properties) { + if(!(plot instanceof org.jfree.chart.plot.CategoryPlot)) + return; + + org.jfree.chart.plot.CategoryPlot cplot = (org.jfree.chart.plot.CategoryPlot) plot; + /* Support using multiple axis, but prefer using only one domain and + * one range axis + */ + for(int i = 0; i < properties.ranges.size(); i++) { + cplot.setRangeAxis(i, (ValueAxis)properties.ranges.get(i).getAxis()); + } + + for(int i = 0; i < properties.domains.size(); i++) { + cplot.setDomainAxis(i, (CategoryAxis)properties.domains.get(i).getAxis()); + } + + IAxis axis; + for(int i = 0; i < properties.datasets.size(); i++) { + IDataset dataset = properties.datasets.get(i); + org.jfree.data.category.CategoryDataset ds = (org.jfree.data.category.CategoryDataset)dataset.getDataset(); + cplot.setDataset(i, ds); +// System.out.println("setting dataset " + i + ": " + ds); + cplot.setRenderer(i, (CategoryItemRenderer)dataset.getRenderer()); + axis = properties.rangeMappings.get(dataset); + if(axis != null && properties.ranges.contains(axis)) + cplot.mapDatasetToRangeAxis(i, properties.ranges.indexOf(axis)); + axis = properties.domainMappings.get(dataset); + if(axis != null && properties.ranges.contains(axis)) + cplot.mapDatasetToDomainAxis(i, properties.domains.indexOf(axis)); + } + + Boolean visibleGrid = (Boolean)properties.otherProperties.get("visibleGrid"); + if(visibleGrid != null) { + cplot.setRangeGridlinesVisible(visibleGrid); + cplot.setDomainGridlinesVisible(false); + } + + // Cleaner look: no outline borders + cplot.setInsets(new RectangleInsets(2,5,2,2), false); + cplot.setOutlineVisible(false); + } + + @Override + protected void getOtherProperties(ReadGraph graph, PlotProperties properties) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Boolean visibleGrid = graph.getPossibleRelatedValue(resource, jfree.Plot_visibleGrid); + properties.otherProperties.put("visibleGrid", visibleGrid); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ChartComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ChartComposite.java new file mode 100644 index 00000000..fa6bb32b --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ChartComposite.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import java.awt.Frame; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.awt.SWT_AWT; +import org.eclipse.swt.widgets.Composite; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.simantics.Simantics; +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.AsyncListener; +import org.simantics.db.request.Read; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.RunnableWithObject; + +/** + * Composite containing a single chart defined by a JFreeChart.Chart + * + * @author Teemu Lempinen + * + */ +public class ChartComposite extends Composite { + + private Frame frame; + private ChartPanel panel; + private Composite composite; + private IJFreeChart chart; + + /** + * A new ChartComposite with a definition in chartResourceURI + * @param parent Composite + * @param chartResourceURI URI for a JFreeChart.Chart definition + * @param style SWT style + */ + public ChartComposite(Composite parent, final String chartResourceURI, int style) { + super(parent, style | SWT.NO_BACKGROUND | SWT.EMBEDDED); + + try { + Resource chartResource = SimanticsUI.getSession().syncRequest(new Read() { + + @Override + public Resource perform(ReadGraph graph) throws DatabaseException { + return graph.getPossibleResource(chartResourceURI); + } + + }); + if(chartResource != null) + CreateContent(chartResource); + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + + /** + * A new ChartComposite with a chartResource definition + * @param parent Composite + * @param chartResource JFreeChart.Chart resource + * @param style SWT style + */ + public ChartComposite(Composite parent, final Resource chartResource, int style) { + super(parent, style | SWT.NO_BACKGROUND | SWT.EMBEDDED); + CreateContent(chartResource); + } + + /** + * Creates and displays the chart defined in chartResource + * @param chartResource + */ + private void CreateContent(final Resource chartResource) { + composite = this; + + GridLayoutFactory.fillDefaults().applyTo(composite); + GridDataFactory.fillDefaults().grab(true, true).applyTo(composite); + frame = SWT_AWT.new_Frame(composite); + + // Add a listener displaying the contents of the chart. Chart is re-drawn if the definition changes + Simantics.getSession().asyncRequest(new Read() { + + @Override + public IJFreeChart perform(ReadGraph graph) throws DatabaseException { + // Adapt chartResource to a chart (XY, pie, bar, ...) + if(graph.isInstanceOf(chartResource, JFreeChartResource.getInstance(graph).Chart)) { + if(chart != null) + chart.dispose(); + chart = graph.adapt(chartResource, IJFreeChart.class); + return chart; + } else { + return null; + } + } + + } , new AsyncListener() { + + @Override + public boolean isDisposed() { + return composite.isDisposed(); + } + + @Override + public void execute(AsyncReadGraph graph, IJFreeChart chart) { + if(chart == null || composite.isDisposed()) + return; + + JFreeChart jfreeChart = chart.getChart(); + // Display the result chart + composite.getDisplay().asyncExec(new RunnableWithObject(jfreeChart) { + + @Override + public void run() { + if(composite.isDisposed()) + return; + if(panel != null) + frame.remove(panel); + composite.layout(); + JFreeChart chart = (JFreeChart)getObject(); + panel = new ChartPanel(chart, false, true, true, true, true); + frame.add(panel); + frame.repaint(); + frame.validate(); + } + }); + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + throwable.printStackTrace(); + + } + }); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ChartUtils.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ChartUtils.java new file mode 100644 index 00000000..150c6a26 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ChartUtils.java @@ -0,0 +1,150 @@ +package org.simantics.jfreechart.chart; + +import java.util.ArrayList; +import java.util.UUID; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PossibleActiveExperiment; +import org.simantics.db.layer0.request.PossibleModel; +import org.simantics.layer0.Layer0; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.operation.Layer0X; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Utilities for handling charts + * + * @author Teemu Lempinen + * + */ +public class ChartUtils { + + /** + * Creates a new range axis of type jfree.NumberAxis to a plot + * + * @param graph WriteGraph + * @param plot Plot resource + * @return Created number axis, null if not successful + * @throws DatabaseException + */ + public static Resource createNumberRangeAxis(WriteGraph graph, Resource plot) throws DatabaseException { + Resource axis = null; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + if(plot != null) { + // Create range axis + axis = GraphUtils.create2(graph, jfree.NumberAxis, + l0.HasName, "NumberAxis" + UUID.randomUUID().toString(), + l0.HasLabel, NameUtils.findFreshLabel(graph, "Y-axis", plot), + jfree.Plot_rangeAxis_Inverse, plot, + l0.PartOf, plot); + + // Add range axis to the plot's range axis list + Resource axisList = graph.getPossibleObject(plot, jfree.Plot_rangeAxisList); + ArrayList list = new ArrayList(); + list.add(axis); + if(axisList == null) { + axisList = ListUtils.create(graph, list); + graph.claim(plot, jfree.Plot_rangeAxisList, axisList); + } else { + ListUtils.insertBack(graph, axisList, list); + } + } + + return axis; + + } + + /** + * Create a XYDataset and map it to axis + * @param graph WriteGraph + * @param plot Plot resource containing the dataset + * @param domainAxis Mapped domain axis for the dataset + * @param rangeAxis Mapped range axis for the dataset + * @return created dataset or null if not successful + * @throws DatabaseException + */ + public static Resource createXYDataset(WriteGraph graph, Resource plot, Resource domainAxis, Resource rangeAxis) throws DatabaseException { + if(plot == null || domainAxis == null || rangeAxis == null) + return null; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + + // Create a dataset for the axis + Resource dataset = GraphUtils.create2(graph, jfree.XYDataset, + l0.HasName, "XYDataset" + UUID.randomUUID().toString(), + jfree.Dataset_mapToDomainAxis, domainAxis, + jfree.Dataset_mapToRangeAxis, rangeAxis, + jfree.Dataset_renderer, GraphUtils.create2(graph, jfree.XYLineRenderer), + l0.PartOf, plot); + + return dataset; + } + + /** + * Creates a new series to a dataset + * @param graph WriteGraph + * @param dataset Dataset for the new series + * @return created series or null if unsuccessful + * @throws DatabaseException + */ + public static Resource createSeries(WriteGraph graph, Resource dataset, String rvi) throws DatabaseException { + if(dataset == null) return null; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + // Create series + Resource series = GraphUtils.create2(graph, jfree.Series, + l0.HasName, "Series" + UUID.randomUUID().toString(), + jfree.variableRVI, rvi == null ? " " : rvi, + l0.PartOf, dataset); + + // Add series to the dataset's series list + Resource seriesList = graph.getPossibleObject(dataset, jfree.Dataset_seriesList); + ArrayList list = new ArrayList(); + list.add(series); + if(seriesList == null) { + seriesList = ListUtils.create(graph, list); + graph.claim(dataset, jfree.Dataset_seriesList, seriesList); + } else { + ListUtils.insertBack(graph, seriesList, list); + } + + return series; + } + + /** + * Find the current realization uri + * + * @param graph ReadGraph + * @param chartComponent A resource from a chart (consistsOf relation in a chart) + * @return current realization uri + * @throws DatabaseException + */ + public static String getCurrentRealizationURI(ReadGraph graph, Resource chartComponent) throws DatabaseException { + // Find the model where the chart is located + Resource model = graph.syncRequest(new PossibleModel(chartComponent)); + if(model == null) + return null; + + // Find the variable realization of the current experiment + String realizationURI = null; + Resource realization = graph.syncRequest(new PossibleActiveExperiment(model)); + if (realization == null) { + Layer0X L0X = Layer0X.getInstance(graph); + realization = graph.getPossibleObject(model, L0X.HasBaseRealization); + } + if (realization != null) + realizationURI = graph.getURI(realization); + + return realizationURI; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ExtendedNumberAxis.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ExtendedNumberAxis.java new file mode 100644 index 00000000..0587a58b --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ExtendedNumberAxis.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.data.Range; + +/** + * NumberAxis that supports adding only one bound, lower or upper. + * The standard NumberAxis disables auto adjusting if even one of the bounds is set + * + * @author Teemu Lempinen + * + */ +public class ExtendedNumberAxis extends org.jfree.chart.axis.NumberAxis { + private static final long serialVersionUID = 3066266986472919998L; + + private Double lower = null; + private Double upper = null; + /** + * Use own lower and upper bounds to support using only one of them + */ + protected void autoAdjustRange() { + super.autoAdjustRange(); + Range range = getRange(); + Double lower = this.lower == null ? range.getLowerBound() : this.lower; + Double upper = this.upper == null ? range.getUpperBound() : this.upper; + if(lower > upper) + upper = lower + 1; + if(upper - lower < getAutoRangeMinimumSize()) + upper = lower + getAutoRangeMinimumSize(); + + setRange(new Range(lower, upper), false, false); + + } + + public void setLower(Double lower) { + this.lower = lower; + } + + public void setUpper(Double upper) { + this.upper = upper; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IAxis.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IAxis.java new file mode 100644 index 00000000..c92f2438 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IAxis.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.axis.Axis; +import org.simantics.db.exception.DatabaseException; + +/** + * Interface for JFreeChart.Axis type resource + * + * @author Teemu Lempinen + * + */ +public interface IAxis extends IJFreeChartComponent { + + /** + * Returns the axis + * + * @return + * @throws DatabaseException + */ + public Axis getAxis(); + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IDataset.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IDataset.java new file mode 100644 index 00000000..6af906eb --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IDataset.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.renderer.AbstractRenderer; +import org.jfree.data.general.Dataset; +import org.simantics.db.Resource; + +/** + * Interface for JFreeChart.Dataset type resource + * @author Teemu Lempinen + * + */ +public interface IDataset extends IJFreeChartComponent { + + /** + * Returns the JFreeChart dataset represented by the associated resource + * + * @return JFreeChart dataset + */ + public Dataset getDataset(); + + + /** + * Returns the renderer for this dataset + * + * @return JFreeChart renderer + */ + public AbstractRenderer getRenderer(); + + /** + * Returns the resource of this dataset + * + * @return + */ + public Resource getResource(); +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IJFreeChart.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IJFreeChart.java new file mode 100644 index 00000000..f03d7b45 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IJFreeChart.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.JFreeChart; +import org.simantics.db.exception.DatabaseException; +/** + * Interface for JFreeChart.Chart type resource + * + * @author Teemu Lempinen + * + */ +public interface IJFreeChart extends IJFreeChartComponent { + + /** + * Returns the chart + * + * @return + * @throws DatabaseException + */ + public JFreeChart getChart(); + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IJFreeChartComponent.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IJFreeChartComponent.java new file mode 100644 index 00000000..27e1d4cc --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IJFreeChartComponent.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +/** + * Interface for all components that are used to create JFreeCharts based on org.simantics.jfreechart ontology + * @author Teemu Lempinen + * + */ +public interface IJFreeChartComponent { + + /** + * Dispose this component. Disposing a component may be useful + * if the component contains listeners that need to be disposed. + */ + public void dispose(); + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IPlot.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IPlot.java new file mode 100644 index 00000000..2fb7d1eb --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IPlot.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.plot.Plot; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; + +/** + * Interface for JFreeChart.Plot type resource + * + * @author Teemu Lempinen + * + */ +public interface IPlot extends IJFreeChartComponent { + + /** + * Returns the plot + * + * @return Title + * @throws DatabaseException + */ + public Plot getPlot(); + + /** + * Returns the resource of this plot + * + * @return + */ + public Resource getResource(); + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IRenderer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IRenderer.java new file mode 100644 index 00000000..7f68e8f1 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/IRenderer.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.renderer.AbstractRenderer; +import org.simantics.db.Resource; + +/** + * Interface for JFreeChart.Renderer type resource + * @author Teemu Lempinen + * + */ +public interface IRenderer extends IJFreeChartComponent { + + /** + * Returns the JFreeChart AbstractRenderer represented by the associated resource + * + * @return JFreeChart renderer + */ + public AbstractRenderer getRenderer(); + + /** + * Returns the resource of this renderer + * @return + */ + public Resource getResource(); + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ITitle.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ITitle.java new file mode 100644 index 00000000..aa50612f --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ITitle.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.title.Title; +import org.simantics.db.exception.DatabaseException; + +/** + * Interface for JFreeChart.Title type resource + * + * @author Teemu Lempinen + * + */ +public interface ITitle extends IJFreeChartComponent { + + /** + * Returns the title + * + * @return Title + * @throws DatabaseException + */ + public Title getTitle(); + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/JFreeChart.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/JFreeChart.java new file mode 100644 index 00000000..ea8df3d6 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/JFreeChart.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import java.awt.Color; +import java.awt.Font; +import java.util.Collection; + +import javax.swing.SwingUtilities; + +import org.jfree.chart.title.LegendTitle; +import org.jfree.chart.title.TextTitle; +import org.jfree.ui.RectangleInsets; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.Read; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.datastructures.Pair; + +/** + * Class representing a complete JFreeChart.Chart + * + * This class supports all types of charts. The details of the chart are + * defined in plots and other adapted classes. + * + * @author Teemu Lempinen + * + */ +public class JFreeChart implements IJFreeChart { + + private org.jfree.chart.JFreeChart jfreechart; + private IPlot plot; + private ITitle title; + private Resource chartResource; + + /** + * + * @param graph ReadGraph + * @param chartResource Resource of type JFreeChart.Chart + */ + public JFreeChart(ReadGraph graph, Resource chartResource) { + this.chartResource = chartResource; + + try { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + Collection plotsCollection = graph.syncRequest(new ObjectsWithType(chartResource, l0.ConsistsOf, jfree.Plot)); + for(Resource plotResource : plotsCollection) { + this.plot = graph.adapt(plotResource, IPlot.class); + } + + } catch(DatabaseException e) { + e.printStackTrace(); + } + } + + + JFreeChartListener listener; + + /** + * Returns a new chart using the information collected in the constructor + */ + @Override + public org.jfree.chart.JFreeChart getChart() { + if(plot == null) + return null; + + if(jfreechart == null) + jfreechart = new org.jfree.chart.JFreeChart(plot.getPlot()); + + if(listener == null) { + listener = new JFreeChartListener(); + SimanticsUI.getSession().asyncRequest(new Read>() { + + @Override + public Pair perform(ReadGraph graph) throws DatabaseException { + if(chartResource == null || !graph.hasStatement(chartResource)) + return null; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + Resource titleResource = graph.syncRequest(new PossibleObjectWithType(chartResource, l0.ConsistsOf, jfree.Title)); + title = graph.adapt(titleResource, ITitle.class); + Boolean legendVisible = graph.getPossibleRelatedValue(chartResource, jfree.Chart_visibleLegend, Bindings.BOOLEAN); + return new Pair(title, legendVisible); + } + }, listener); + } + + return jfreechart; + } + + @Override + public void dispose() { + // Call dispose to title and plots to disable their possible listeners + if(title != null) + title.dispose(); + if(listener != null) + listener.dispose(); + if(plot != null) + plot.dispose(); + } + + + private class JFreeChartListener implements Listener> { + + private boolean disposed = false; + private LegendTitle legend; + + public void dispose() { + disposed = true; + } + + @Override + public void execute(final Pair result) { + if(result == null) + return; + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if(jfreechart == null) + return; + + jfreechart.setBackgroundPaint(Color.WHITE); + + if(jfreechart.getLegend() != null && !jfreechart.getLegend().equals(legend)) { + legend = jfreechart.getLegend(); + legend.setBorder(0, 0, 0, 0); + int size = legend.getItemFont().getSize(); + legend.setItemFont(new Font("helvetica", Font.PLAIN, size)); + } + + if(Boolean.FALSE.equals(result.second)) { + jfreechart.removeLegend(); + } else if (jfreechart.getLegend() == null && legend != null){ + jfreechart.addLegend(legend); + } + + TextTitle t = (org.jfree.chart.title.TextTitle)result.first.getTitle(); + if(t.isVisible()) { + t.setFont(new Font("georgia", Font.BOLD, 13)); + t.setPadding(new RectangleInsets(4, 0, 0, 0)); + jfreechart.setTitle(t); + } else { + jfreechart.setTitle((TextTitle)null); + } + } + }); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return disposed; + } + + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/NumberAxis.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/NumberAxis.java new file mode 100644 index 00000000..4f070631 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/NumberAxis.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.axis.Axis; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +/** + * Class representing a JFreeChart.NumberAxis + * + * @author Teemu Lempinen + * + */ +public class NumberAxis extends AbstractAxis { + + /** + * + * @param graph ReadGraph + * @param axisResource resource of type JFreeChart.NumberAxis + */ + public NumberAxis(ReadGraph graph, Resource axisResource) { + super(graph, axisResource); + } + + + @Override + public Axis getAxis() { + axis = new ExtendedNumberAxis(); + ((ExtendedNumberAxis)axis).setLower(min); + ((ExtendedNumberAxis)axis).setUpper(max); + return super.getAxis(); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/PieDataset.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/PieDataset.java new file mode 100644 index 00000000..de176a4c --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/PieDataset.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import java.awt.Color; +import java.util.HashMap; + +/** + * Class representing a PieDataset in JFreeChart ontology + * @author Teemu Lempinen + * + */ +public interface PieDataset extends IDataset { + + + /** + * Map of colors for different slices in a pie chart. Name + * indicates the key of the value. + * @return Map of colors for different slices in a pie chart + */ + public HashMap getColorMap(); + + + /** + * Map of exploded statuses for slices in a pie chart. Name + * indicates the key of the slice. + * @return + */ + public HashMap getExplodedMap(); + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/PiePlot.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/PiePlot.java new file mode 100644 index 00000000..925816a8 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/PiePlot.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import java.awt.Color; +import java.awt.Font; +import java.util.HashMap; + +import org.jfree.chart.labels.StandardPieSectionLabelGenerator; +import org.jfree.chart.labels.StandardPieToolTipGenerator; +import org.jfree.chart.plot.DefaultDrawingSupplier; +import org.jfree.chart.plot.Plot; +import org.jfree.data.general.Dataset; +import org.jfree.data.general.DatasetChangeEvent; +import org.jfree.data.general.DatasetChangeListener; +import org.jfree.ui.RectangleInsets; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class representing a PiePlot in JFreeChart ontology + * + * @author Teemu Lempinen + * + */ +public class PiePlot extends AbstractPlot { + + private org.jfree.data.general.PieDataset pieDataset; + private DatasetChangeListener listener; + + public PiePlot(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + /** + * Pie plot class with a stricter equals condition + * @author Teemu Lempinen + * + */ + private class MyPiePlot extends org.jfree.chart.plot.PiePlot { + + private static final long serialVersionUID = -5917620061541212934L; + + @Override + public boolean equals(Object obj) { + boolean result = super.equals(obj); + if(result == true) { + org.jfree.chart.plot.PiePlot that = (org.jfree.chart.plot.PiePlot) obj; + if (this.getDataset() != that.getDataset()) { + return false; // Normally plot does not check this. We need this to properly update the charts + } + } + + return result; + } + + } + + @Override + protected Plot newPlot() { + MyPiePlot plot = new MyPiePlot(); + plot.setToolTipGenerator(new StandardPieToolTipGenerator()); + return plot; + } + + @Override + protected void getOtherProperties(ReadGraph graph, PlotProperties properties) throws DatabaseException { + Boolean labelsVisible = graph.getPossibleRelatedValue(resource, JFreeChartResource.getInstance(graph).Plot_visibleLabels, Bindings.BOOLEAN); + properties.otherProperties.put("labelsVisible", labelsVisible); + } + + @Override + protected void setPlotProperties(PlotProperties properties) { + if(!(plot instanceof MyPiePlot)) + return; + + final MyPiePlot piePlot = (MyPiePlot)plot; + + if(!properties.datasets.isEmpty()) { + // We assume that a pie plot has only one dataset + final IDataset ds = properties.datasets.get(0); + Dataset dataset = ((PieDataset)ds).getDataset(); + + if(dataset == null) + return; + + if(pieDataset != null && listener != null) { + pieDataset.removeChangeListener(listener); + } + + pieDataset = (org.jfree.data.general.PieDataset)dataset; + piePlot.setDataset(pieDataset); + + Boolean labelsVisible = (Boolean)properties.otherProperties.get("labelsVisible"); + if(Boolean.FALSE.equals(labelsVisible)) + piePlot.setLabelGenerator(null); + else if(piePlot.getLabelGenerator() == null) + piePlot.setLabelGenerator(new StandardPieSectionLabelGenerator()); + + listener = new DatasetChangeListener() { + + @Override + public void datasetChanged(DatasetChangeEvent event) { + HashMap colorMap = ((PieDataset)ds).getColorMap(); + HashMap explodedMap = ((PieDataset)ds).getExplodedMap(); + + for(Object o : piePlot.getDataset().getKeys()) { + if(o instanceof Comparable) { + Comparable key = (Comparable)o; + if(explodedMap.containsKey(key) && explodedMap.get(key)) { + piePlot.setExplodePercent(key, 0.3); + + } else { + piePlot.setExplodePercent(key, 0); + } + } + } + + for(String name : explodedMap.keySet()) { + Boolean exploded = explodedMap.get(name); + if(Boolean.TRUE.equals(exploded)) + piePlot.setExplodePercent(name, 0.3); + } + piePlot.clearSectionPaints(false); + piePlot.setDrawingSupplier(new DefaultDrawingSupplier()); + for(String name : colorMap.keySet()) + piePlot.setSectionPaint(name, colorMap.get(name)); + } + }; + + pieDataset.addChangeListener(listener); + } + + // Cleaner look: no outline borders + piePlot.setInsets(new RectangleInsets(0,0,0,0), false); + piePlot.setOutlineVisible(false); + piePlot.setLabelBackgroundPaint(Color.WHITE); + piePlot.setLabelFont(new Font("helvetica", Font.PLAIN, 11)); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/StackedBarRenderer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/StackedBarRenderer.java new file mode 100644 index 00000000..a7da60cc --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/StackedBarRenderer.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.labels.StandardCategoryToolTipGenerator; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +/** + * Stacked bar renderer + * @author Teemu Lempinen + * + */ +public class StackedBarRenderer extends AbstractRenderer { + + public StackedBarRenderer(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + private org.jfree.chart.renderer.category.StackedBarRenderer renderer; + + @Override + public org.jfree.chart.renderer.AbstractRenderer getRenderer() { + if(renderer == null) { + renderer = new org.jfree.chart.renderer.category.StackedBarRenderer(); + renderer.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator()); + } + return renderer; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/TextTitle.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/TextTitle.java new file mode 100644 index 00000000..bdb73de1 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/TextTitle.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.title.Title; +import org.jfree.ui.RectangleEdge; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class representing a JFreeChart.TextTitle + * @author Teemu Lempinen + * + */ +public class TextTitle implements ITitle { + + private org.jfree.chart.title.TextTitle textTitle; + private RectangleEdge position; + private String text; + private Boolean visible; + + public TextTitle(ReadGraph graph, Resource titleResource) { + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + try { + text = graph.getPossibleRelatedValue(titleResource, l0.HasLabel, Bindings.STRING); + Resource pos = graph.getPossibleObject(titleResource, jfree.Title_position); + position = getRectangleEdgePosition(graph, pos); + visible = graph.getPossibleRelatedValue(titleResource, jfree.visible, Bindings.BOOLEAN); + + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + + /** + * Get the RectangleEdge representation for Resource position (JFreeChart.Position) + * @param graph ReadGraph + * @param position Resource of type JFreeChart.Position + * @return RectangleEdge representation for Resource position + */ + private RectangleEdge getRectangleEdgePosition(ReadGraph graph, Resource position) { + if(position == null) + return null; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + if(position.equals(jfree.Top)) + return RectangleEdge.TOP; + else if(position.equals(jfree.Bottom)) + return RectangleEdge.BOTTOM; + else if(position.equals(jfree.Left)) + return RectangleEdge.LEFT; + else if(position.equals(jfree.Right)) + return RectangleEdge.RIGHT; + else + return null; + + } + + @Override + public Title getTitle() { + textTitle = new org.jfree.chart.title.TextTitle(text); + if(position != null) + textTitle.setPosition(position); + if(visible != null) + textTitle.setVisible(visible); + return textTitle; + } + + @Override + public void dispose() { + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYAreaRenderer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYAreaRenderer.java new file mode 100644 index 00000000..6c680348 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYAreaRenderer.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +/** + * Renderer representing jfree chart renderer for xy areas + * @author Teemu Lempinen + * + */ +public class XYAreaRenderer extends AbstractRenderer { + + private org.jfree.chart.renderer.xy.XYAreaRenderer renderer; + + public XYAreaRenderer(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + @Override + public org.jfree.chart.renderer.AbstractRenderer getRenderer() { + if(renderer == null) { + renderer = new org.jfree.chart.renderer.xy.XYAreaRenderer(); + renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator()); + } + return renderer; + } + +} \ No newline at end of file diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYDataset.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYDataset.java new file mode 100644 index 00000000..d7433d64 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYDataset.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + + +/** + * Class representing a JFreeChart.XYDataset + * + * @author Teemu Lempinen + * + */ +public interface XYDataset extends IDataset { + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYLineRenderer.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYLineRenderer.java new file mode 100644 index 00000000..7d5abb22 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYLineRenderer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +/** + * Renderer representing jfree chart renderer for xy lines + * @author Teemu Lempinen + * + */ +public class XYLineRenderer extends AbstractRenderer { + + XYLineAndShapeRenderer renderer; + + public XYLineRenderer(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + @Override + public org.jfree.chart.renderer.AbstractRenderer getRenderer() { + if(renderer == null) { + renderer = new XYLineAndShapeRenderer(true, false); + renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator()); + } + return renderer; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYPlot.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYPlot.java new file mode 100644 index 00000000..5b09f694 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/XYPlot.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart; + +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.Plot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.data.xy.XYDataset; +import org.jfree.ui.RectangleInsets; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class representing a JFreeChart.XYPlot + * + * @author Teemu Lempinen + * + */ +public class XYPlot extends AbstractPlot { + + public XYPlot(ReadGraph graph, Resource plotResource) { + super(graph, plotResource); + } + + @Override + protected Plot newPlot() { + return new org.jfree.chart.plot.XYPlot(null, null, null, null); + } + + @Override + protected void getOtherProperties(ReadGraph graph, PlotProperties properties) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Boolean visibleGrid = graph.getPossibleRelatedValue(resource, jfree.Plot_visibleGrid); + properties.otherProperties.put("visibleGrid", visibleGrid); + if(!properties.datasets.isEmpty()) { + IDataset idataset = properties.datasets.get(0); + Resource renderer = graph.getPossibleObject(idataset.getResource(), jfree.Dataset_renderer); + if(renderer != null) { + properties.otherProperties.put("renderer", graph.adapt(renderer, IRenderer.class)); + } + } + } + + @Override + protected void setPlotProperties(PlotProperties properties) { + if(!(plot instanceof org.jfree.chart.plot.XYPlot)) + return; + + org.jfree.chart.plot.XYPlot xyplot = (org.jfree.chart.plot.XYPlot)plot; + xyplot.clearDomainAxes(); + xyplot.clearRangeAxes(); + + for(int i = 0; i < properties.ranges.size(); i++) { + xyplot.setRangeAxis(i, (ValueAxis)properties.ranges.get(i).getAxis()); + } + + for(int i = 0; i < properties.domains.size(); i++) { + xyplot.setDomainAxis(i, (ValueAxis)properties.domains.get(i).getAxis()); + } + + IAxis axis; + for(int i = 0; i < properties.datasets.size(); i++) { + IDataset dataset = properties.datasets.get(i); + xyplot.setDataset(i, (XYDataset)dataset.getDataset()); + xyplot.setRenderer(i, (XYItemRenderer)dataset.getRenderer()); + axis = properties.rangeMappings.get(dataset); + if(axis != null && properties.ranges.contains(axis)) + xyplot.mapDatasetToRangeAxis(i, properties.ranges.indexOf(axis)); + axis = properties.domainMappings.get(dataset); + if(axis != null && properties.ranges.contains(axis)) + xyplot.mapDatasetToDomainAxis(i, properties.domains.indexOf(axis)); + } + + Boolean visibleGrid = (Boolean)properties.otherProperties.get("visibleGrid"); + if(visibleGrid == null) + visibleGrid = true; + + xyplot.setRangeGridlinesVisible(visibleGrid); + xyplot.setDomainGridlinesVisible(visibleGrid); + + // Cleaner look: no outline borders + xyplot.setInsets(new RectangleInsets(2,5,2,10), false); + xyplot.setOutlineVisible(false); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartBoundsOutline.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartBoundsOutline.java new file mode 100644 index 00000000..990ff4f1 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartBoundsOutline.java @@ -0,0 +1,37 @@ +package org.simantics.jfreechart.chart.element; + +import java.awt.geom.Rectangle2D; + +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.LifeCycle; +import org.simantics.g2d.element.handler.impl.BoundsOutline; + +/** + * Outline with default bounds. Needed to avoid crashing when trying to rotate chart elements. + * @author Teemu Lempinen + * + */ +public class ChartBoundsOutline extends BoundsOutline implements LifeCycle { + private static final long serialVersionUID = -3819495313008722843L; + + Rectangle2D defaultBounds; + + public ChartBoundsOutline(Rectangle2D defaultBounds) { + this.defaultBounds = defaultBounds; + } + + @Override + public void onElementCreated(IElement e) { + e.setHint(ElementHints.KEY_BOUNDS, defaultBounds); + } + + @Override + public void onElementDestroyed(IElement e) {} + @Override + public void onElementActivated(IDiagram d, IElement e) {} + @Override + public void onElementDeactivated(IDiagram d, IElement e) {} + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartElementFactory.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartElementFactory.java new file mode 100644 index 00000000..4ee1d2e9 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartElementFactory.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.element; + +import java.awt.BasicStroke; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; +import java.awt.geom.QuadCurve2D; +import java.awt.geom.Rectangle2D; + +import org.jfree.chart.JFreeChart; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.adapter.ElementFactory; +import org.simantics.diagram.adapter.ElementFactoryUtil; +import org.simantics.diagram.adapter.SyncElementFactory; +import org.simantics.diagram.elements.ElementPropertySetter; +import org.simantics.diagram.synchronization.CompositeHintSynchronizer; +import org.simantics.diagram.synchronization.IHintSynchronizer; +import org.simantics.diagram.synchronization.ISynchronizationContext; +import org.simantics.diagram.synchronization.SynchronizationHints; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.diagram.synchronization.graph.RemoveElement; +import org.simantics.diagram.synchronization.graph.TransformSynchronizer; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementClass; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.LifeCycle; +import org.simantics.g2d.element.handler.impl.DefaultTransform; +import org.simantics.g2d.element.handler.impl.StaticObjectAdapter; +import org.simantics.g2d.element.handler.impl.StaticSymbolImageInitializer; +import org.simantics.g2d.element.handler.impl.StaticSymbolImpl; +import org.simantics.g2d.image.Image; +import org.simantics.g2d.image.impl.ShapeImage; +import org.simantics.jfreechart.chart.IJFreeChart; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; + +/** + * Element factory for creating chart elements to diagrams + * + * @author Teemu Lempinen + * + */ +public class ChartElementFactory extends SyncElementFactory { + + private static final String CLASS_ID = "Chart"; + public static final ElementFactory INSTANCE = new ChartElementFactory(); + public static final Image STATIC_IMAGE = new ShapeImage(getChartShape(), null, new BasicStroke(1f), true); + public static final double SYMBOL_CHART_SIZE = 10.0; + public static final Key KEY_CHART_COMPONENT = new KeyOf(Resource.class, "CHART_COMPONENT"); + public static final Key KEY_CHART = new KeyOf(JFreeChart.class, "CHART"); + + static Shape getChartShape() { + + Path2D path = new Path2D.Double(); + // First create the axis for a chart symbol + path.moveTo(-SYMBOL_CHART_SIZE, -SYMBOL_CHART_SIZE); + path.lineTo(-SYMBOL_CHART_SIZE, SYMBOL_CHART_SIZE); + path.lineTo( SYMBOL_CHART_SIZE, SYMBOL_CHART_SIZE); + + // Then a curve to the chart + QuadCurve2D curve = new QuadCurve2D.Double( + -SYMBOL_CHART_SIZE + 1, SYMBOL_CHART_SIZE - 1, + SYMBOL_CHART_SIZE - 5, SYMBOL_CHART_SIZE - 5, + SYMBOL_CHART_SIZE - 1, -SYMBOL_CHART_SIZE + 3); + + // Connect shapes + path.append(curve, false); + return path; + } + + // Hint synchronizer for synchronizing transform and bounds + private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer( + TransformSynchronizer.INSTANCE); + + public static ElementClass create(ReadGraph graph, Resource chart) throws DatabaseException { + return ElementClass.compile( + new ChartSceneGraph(), + new Initializer(chart), + new StaticObjectAdapter(JFreeChartResource.getInstance(graph).ChartElement), + DefaultTransform.INSTANCE, + StaticSymbolImageInitializer.INSTANCE, + new StaticSymbolImpl(STATIC_IMAGE), + new ChartBoundsOutline(new Rectangle2D.Double(-20, -20, 60, 40)), + new ElementPropertySetter(ChartSceneGraph.KEY_SG_NODE) + ).setId(CLASS_ID); + } + + public ElementClass create(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType) throws DatabaseException { + return create(graph, null); + } + + @Override + public void load(ReadGraph g, ICanvasContext canvas, final IDiagram diagram, Resource element, final IElement e) throws DatabaseException { + + Resource chartResource; + ElementPropertySetter ps = e.getElementClass().getSingleItem(ElementPropertySetter.class); + ps.loadProperties(e, element, g); + + AffineTransform at = DiagramGraphUtil.getAffineTransform(g, element); + // Hack for disabling all rotations in chart elements + double x = at.getTranslateX(); + double y = at.getTranslateY(); + at.setToRotation(0); + at.setToTranslation(x, y); + ElementUtils.setTransform(e, at); // Set hint transform without rotations + ps.overrideProperty(e, "Transform", at); // Set property Transform without rotations + + e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER); + + + Object o = e.getHint(KEY_CHART_COMPONENT); + if(o == null || !(o instanceof Resource)) { + chartResource = g.getPossibleObject(element, JFreeChartResource.getInstance(g).ChartElement_component); + } else { + chartResource = (Resource)o; + } + + if(chartResource == null || !g.hasStatement(chartResource)) { + // Remove element if there is no chart resource for it + final ISynchronizationContext syncContext = ElementFactoryUtil.getContextChecked(diagram); + g.asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + new RemoveElement(syncContext, diagram, e).perform(graph); + } + }); + return; + } + + IJFreeChart ichart = g.adapt(chartResource, IJFreeChart.class); + + if(ichart != null) { + JFreeChart chart = ichart.getChart(); + e.setHint(KEY_CHART, chart); + } + + } + + + /** + * Initializer for setting a chart component for element + * @author Teemu Lempinen + * + */ + static class Initializer implements LifeCycle { + private static final long serialVersionUID = -5822080013184271204L; + Object component; + + Initializer(Object component) { + this.component = component; + } + + @Override + public void onElementCreated(IElement e) { + if(component != null) e.setHint(KEY_CHART_COMPONENT, component); + } + + @Override + public void onElementActivated(IDiagram d, IElement e) {} + @Override + public void onElementDeactivated(IDiagram d, IElement e) {} + @Override + public void onElementDestroyed(IElement e) {} + }; +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartElementWriter.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartElementWriter.java new file mode 100644 index 00000000..2fe7fc13 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartElementWriter.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.element; + +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.synchronization.graph.ElementWriter; +import org.simantics.g2d.element.IElement; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Element writer for chart elements. ChartElementWriter stores + * the reference to a chart definition into the element resource + * @author Teemu Lempinen + * + */ +public class ChartElementWriter implements ElementWriter { + + @Override + public void addToGraph(WriteGraph graph, IElement element, Resource elementResource) throws DatabaseException { + Resource chartComponent = element.getHint(ChartElementFactory.KEY_CHART_COMPONENT); + if (chartComponent == null) + throw new IllegalArgumentException("KEY_CHART_COMPONENT hint not set"); + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + graph.claim(elementResource, jfree.ChartElement_component, chartComponent); + } + + @Override + public void removeFromGraph(WriteGraph graph, Resource elementResource) throws DatabaseException { + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartNode.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartNode.java new file mode 100644 index 00000000..00715038 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartNode.java @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2007, 2012 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.jfreechart.chart.element; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import javax.swing.JPanel; + +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.simantics.scenegraph.ISelectionPainterNode; +import org.simantics.scenegraph.g2d.events.EventTypes; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; +import org.simantics.scenegraph.swing.ComponentNode; +import org.simantics.scenegraph.utils.GeometryUtils; +import org.simantics.scenegraph.utils.NodeUtil; + +/** + * Chart node for displaying jfreechart charts in diagrams + * @author Teemu Lempinen + * + */ +public class ChartNode extends ComponentNode implements ISelectionPainterNode { + + private static final long serialVersionUID = 5013911689968911010L; + private boolean hover = false; + private boolean dragging = false; + + private ResizeListener resizeListener; + + protected transient JFreeChart chart = null; + + public boolean dragging() { + return dragging; + } + + public void setChart(JFreeChart chart) { + this.chart = chart; + } + + public void setResizeListener(ResizeListener listener) { + this.resizeListener = listener; + } + + @SyncField({"hover"}) + public void setHover(boolean hover) { + this.hover = hover; + repaint(); + } + + @Override + public void cleanup() { + removeEventHandler(this); + super.cleanup(); + } + + @Override + public void init() { + super.init(); + } + + public static void expand(Rectangle2D rectangle, double scaleX, double scaleY) { + GeometryUtils.expandRectangle(rectangle, + 5 * scaleY > 5 ? 5 * scaleY : 5, + 3 * scaleY > 3 ? 3 * scaleY : 3, + 3 * scaleX > 3 ? 3 * scaleX : 3, + 3 * scaleX > 3 ? 3 * scaleX : 3); + } + + @Override + public void render(Graphics2D g2d) { + if (component == null && chart != null) { + // Need the chart, so this cannot be done during initialization + component = new ChartPanel(chart, false); + ((ChartPanel)component).setRefreshBuffer(false); + component.setIgnoreRepaint(true); + component.setDoubleBuffered(false); + if(bounds != null) { + component.setBounds(0, 0, 0, 0); + } + super.init(); + addEventHandler(this); + } + + if (component != null) { + AffineTransform ot = g2d.getTransform(); + g2d.transform(transform); + double scaleX = g2d.getTransform().getScaleX(); + double scaleY = g2d.getTransform().getScaleY(); + + AffineTransform at = new AffineTransform(transform); + synchronized(transform) { + at.setToTranslation(bounds.getMinX(), bounds.getMinY()); + at.scale(1/scaleX, 1/scaleY); + } + g2d.transform(at); + int width = (int)(bounds.getWidth() * scaleX); + int height = (int)(bounds.getHeight() * scaleY); + + if(hover || dragging) { + // Borders + Color orig = g2d.getColor(); + BasicStroke oldStroke = (BasicStroke) g2d.getStroke(); + g2d.setColor(Color.LIGHT_GRAY); + Rectangle2D b = new Rectangle2D.Double(0, 0, width, height); + Rectangle2D r = b.getBounds2D(); + expand(r, 1 * scaleX, 1 * scaleY); + g2d.fill(r); + + // Lower right corner for dragging + double x = r.getMaxX() - (0.33 * scaleX); + double y = r.getMaxY() - (0.33 * scaleY); + + if(r.getMaxX() - x > 0.4) { + // if there is enough space, use decorated corner + BasicStroke hilightStroke = new BasicStroke(oldStroke.getLineWidth() * 3); + for(int i = 1; i < 4; i++) { + Line2D line = new Line2D.Double( + x - (i * scaleX), + y, + x, + y - (i * scaleY)); + + g2d.setStroke(hilightStroke); + g2d.setColor(Color.GRAY); + g2d.draw(line); + + g2d.setStroke(oldStroke); + g2d.setColor(Color.BLACK); + g2d.draw(line); + } + + + } else { + // not enough space, use a non-decorated corner + float f = 3; + Rectangle2D corner = new Rectangle2D.Double(r.getMaxX() - f, r.getMaxY() - f, f, f); + g2d.setColor(Color.DARK_GRAY); + g2d.fill(corner); + } + + g2d.setStroke(oldStroke); + g2d.setColor(orig); + } + + boolean selected = NodeUtil.isSelected(this, 1); + if (selected) { + Color orig = g2d.getColor(); + Stroke origStroke = g2d.getStroke(); + + g2d.setColor(Color.RED); + double s = GeometryUtils.getScale(g2d.getTransform()); + g2d.setStroke(new BasicStroke(1f * s < 1f ? 1f : 1f * (float)s)); + + Rectangle2D b = new Rectangle2D.Double(0, 0, width, height); + Rectangle2D r = b.getBounds2D(); + expand(r, scaleX, scaleY); + g2d.draw(r); + + g2d.setColor(orig); + g2d.setStroke(origStroke); + } + + synchronized(component) { + component.setLocation((int)g2d.getTransform().getTranslateX(), (int)g2d.getTransform().getTranslateY()); + if(component.getSize().getWidth() != width || component.getSize().getHeight() != height) { + component.setSize(width, height); + } + component.paint(g2d); + } + + g2d.setTransform(ot); + } else { + /* + * Component == null + * + * The related chart definition ha been removed. + */ + System.out.println("TÄÄLLÄ, TÄÄLLÄ"); + } + } + + @Override + protected boolean mouseButtonPressed(MouseButtonPressedEvent event) { + Point2D local = controlToLocal( event.controlPosition ); + local = parentToLocal(local); + Rectangle2D bounds = getBoundsInLocal().getBounds2D(); + expand(bounds, 1, 1); + double control = 3.0; + Rectangle2D corner = new Rectangle2D.Double(bounds.getMaxX() - control, bounds.getMaxY() - control, control, control); + if (hover && corner.contains(local)) { + dragging = true; + return true; + } + return super.mouseButtonPressed(event); + } + + + @Override + protected boolean mouseMoved(MouseMovedEvent e) { + if(dragging) { + Point2D local = controlToLocal( e.controlPosition ); + local = parentToLocal(local); + + Rectangle2D bounds = getBoundsInLocal().getBounds2D(); + + if(Math.abs(bounds.getMaxX() - local.getX()) > 3 || + Math.abs(bounds.getMaxY() - local.getY()) > 3) { + resize(local); + } + return true; + } + return false; + } + + public boolean hitCorner(Point2D point) { + Rectangle2D bounds = getBoundsInLocal().getBounds2D(); + expand(bounds, 1, 1); + double control = 3.0; + Rectangle2D corner = new Rectangle2D.Double(bounds.getMaxX() - control, bounds.getMaxY() - control, control, control); + return corner.contains(point); + } + + private void resize(Point2D local) { + Rectangle2D bounds = getBoundsInLocal().getBounds2D(); + double x = bounds.getX(); + double y = bounds.getY(); + double dx = local.getX() - bounds.getMaxX(); + double dy = local.getY() - bounds.getMaxY(); + double w = bounds.getWidth() + dx; + double h = bounds.getHeight() + dy; + bounds.setRect( + x, + y, + w > 20 ? w : 20, + h > 20 ? h : 20 + ); + setBounds(bounds); + } + + @Override + protected boolean mouseDragged(MouseDragBegin e) { + if(dragging) { + return true; // Eat event for faster resize + } else { + return false; + } + } + + @Override + protected boolean mouseButtonReleased(MouseButtonReleasedEvent e) { + if(dragging) { + Point2D local = controlToLocal( e.controlPosition ); + local = parentToLocal(local); + if(Math.abs(bounds.getMaxX() - local.getX()) > 3 || + Math.abs(bounds.getMaxY() - local.getY()) > 3) { + resize(local); + } + dragging = false; + if(resizeListener != null) + resizeListener.elementResized(bounds); + } + return false; + } + + @Override + public int getEventMask() { + return EventTypes.MouseButtonPressedMask + | EventTypes.MouseMovedMask + | EventTypes.MouseButtonReleasedMask + ; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartSceneGraph.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartSceneGraph.java new file mode 100644 index 00000000..7ca96929 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ChartSceneGraph.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.element; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.jfree.chart.JFreeChart; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.diagram.DiagramUtils; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.SceneGraphNodeKey; +import org.simantics.g2d.element.handler.HandleMouseEvent; +import org.simantics.g2d.element.handler.InternalSize; +import org.simantics.g2d.element.handler.PropertySetter; +import org.simantics.g2d.element.handler.SceneGraph; +import org.simantics.scenegraph.Node; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.IG2DNode; +import org.simantics.scenegraph.g2d.events.MouseEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintListener; +import org.simantics.utils.datastructures.hints.IHintObservable; + +/** + * Chart scenegraph for chart elements in diagrams + * @author Teemu Lempinen + * + */ +public class ChartSceneGraph implements SceneGraph, HandleMouseEvent, InternalSize { + private static final long serialVersionUID = 1875762898776996989L; + + public static final Key KEY_SG_NODE = new SceneGraphNodeKey(Node.class, "CHART_SG_NODE"); + public static final Key KEY_SG_SELECTION_NODE = new SceneGraphNodeKey(Node.class, "CHART_SG_SELECTION_NODE"); + + protected IHintListener hoverHintListener; + + public ChartSceneGraph() { + } + + /** + * Expands bounds a little to allow selecting and grabbing a chart element + * from outside the chart graphics + */ + @Override + public Rectangle2D getBounds(IElement e, Rectangle2D s) { + if (s==null) s = new Rectangle2D.Double(); + + IG2DNode node = (IG2DNode)e.getHint(KEY_SG_NODE); + AffineTransform at = (AffineTransform)e.getHint(ElementHints.KEY_TRANSFORM); + if(at != null && node != null && node.getBoundsInLocal() != null) { + Shape shape = node.getBoundsInLocal(); + Rectangle2D r = shape.getBounds2D(); + double scaleX = at.getScaleX(); + double scaleY = at.getScaleY(); + ChartNode.expand(r, 1 * scaleX, 1 * scaleY); + shape = r; + s.setFrame(shape.getBounds2D()); + } else { + s.setFrame((Rectangle2D)e.getHint(ElementHints.KEY_BOUNDS)); + } + return s; + } + + @Override + public void cleanup(IElement e) { + if(hoverHintListener != null) + e.removeHintListener(hoverHintListener); + + Node node = e.removeHint(KEY_SG_NODE); + if (node != null) + node.remove(); + } + + @Override + public void init(final IElement e, G2DParentNode parent) { + ChartNode node = e.getHint(KEY_SG_NODE); + if(node == null) { + // Create a new chart node + node = parent.getOrCreateNode("chart_"+e.hashCode(), ChartNode.class); + + Rectangle2D bounds = (Rectangle2D)e.getHint(ElementHints.KEY_BOUNDS); + if(bounds == null) { + bounds = new Rectangle2D.Double(-40, -40, 80, 80); + e.setHint(ElementHints.KEY_BOUNDS, bounds); + } + node.setBounds(bounds); + + JFreeChart chart = e.getHint(ChartElementFactory.KEY_CHART); + if(chart != null) + node.setChart(chart); + + // Add a resize listener for updating bounds information to graph after resizing + node.setResizeListener(new ResizeListener() { + + @Override + public void elementResized(Rectangle2D newBounds) { + e.setHint(ElementHints.KEY_BOUNDS, newBounds); + IDiagram diagram = ElementUtils.getDiagram(e); + DiagramUtils.synchronizeHintsToBackend(diagram, e); + } + }); + + e.setHint(KEY_SG_NODE, node); + } + + // Hover listening + hoverHintListener = new IHintListener() { + @Override + public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { + + } + + @Override + public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { + if(key == ElementHints.KEY_HOVER) { + IElement e = (IElement)sender; + ChartNode name = (ChartNode) e.getHint(KEY_SG_NODE); + if (name != null) + name.setHover(Boolean.TRUE.equals(e.getHint(ElementHints.KEY_HOVER))); + } + } + }; + e.addHintListener(hoverHintListener); + + update(e); + } + + public void update(IElement e) { + PropertySetter setter = e.getElementClass().getSingleItem(PropertySetter.class); + setter.syncPropertiesToNode(e); + } + + + @Override + public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) { + if (me instanceof MouseEnterEvent) { + e.setHint(ElementHints.KEY_HOVER, true); + } else if (me instanceof MouseExitEvent) { + e.setHint(ElementHints.KEY_HOVER, false); + } + return false; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/PopulateChartDropParticipant.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/PopulateChartDropParticipant.java new file mode 100644 index 00000000..6b8d9f69 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/PopulateChartDropParticipant.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.element; + +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.geom.AffineTransform; +import java.io.IOException; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.adapter.GraphToDiagramSynchronizer; +import org.simantics.g2d.dnd.DnDHints; +import org.simantics.g2d.dnd.ElementClassDragItem; +import org.simantics.g2d.dnd.IDnDContext; +import org.simantics.g2d.dnd.IDropTargetParticipant; +import org.simantics.g2d.element.ElementHints; +import org.simantics.modeling.ui.diagramEditor.PopulateElementDropParticipant; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.dnd.LocalObjectTransfer; +import org.simantics.ui.dnd.LocalObjectTransferable; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Drop participant for dropping chart definitions into diagrams + * @author Teemu Lempinen + * + */ +public class PopulateChartDropParticipant extends PopulateElementDropParticipant implements IDropTargetParticipant { + + public PopulateChartDropParticipant(GraphToDiagramSynchronizer synchronizer) { + super(synchronizer); + } + + @Override + public void dragEnter(DropTargetDragEvent dtde, final IDnDContext dp) { + Transferable tr = dtde.getTransferable(); + if (tr.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) { + + Session session = synchronizer.getSession(); + + Object obj = null; + + try { + obj = tr.getTransferData(LocalObjectTransferable.FLAVOR); + + // Create a structural selection from transfer data + if (!(obj instanceof IStructuredSelection)) { + obj = LocalObjectTransfer.getTransfer().getObject(); + } + + if (obj instanceof IStructuredSelection) { + + IStructuredSelection sel = (IStructuredSelection) obj; + + // Can drop only one chart at the time + if (sel.size() == 1) { + + // Get the chart definition + Resource chart = AdaptionUtils.adaptToSingle(sel, Resource.class); + if (chart == null) + return; + + ElementClassDragItem item = session.syncRequest(new UnaryRead(chart) { + + @Override + public ElementClassDragItem perform(ReadGraph graph) throws DatabaseException { + if(graph.isInstanceOf(parameter, JFreeChartResource.getInstance(graph).Chart)) { + ElementClassDragItem item = new ElementClassDragItem(ChartElementFactory.create(graph, parameter)); + AffineTransform initialTr = AffineTransform.getScaleInstance(1, 1); + item.getHintContext().setHint(ElementHints.KEY_TRANSFORM, initialTr); + return item; + } else { + return null; + } + + } + }); + + if(item != null) { + dp.add(item); + dp.getHints().setHint(DnDHints.KEY_DND_GRID_COLUMNS, Integer.valueOf(1)); + } + + } + + } + + } catch (UnsupportedFlavorException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (DatabaseException e) { + e.printStackTrace(); + } + + } + + dtde.acceptDrag(DnDConstants.ACTION_COPY); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ResizeListener.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ResizeListener.java new file mode 100644 index 00000000..4c31a6be --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/element/ResizeListener.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.element; + +import java.awt.geom.Rectangle2D; + +/** + * Interface for listeners listening resize events in chart nodes + * @author Teemu Lempinen + * + */ +public interface ResizeListener { + + /** + * Triggered when a node has been resized + * @param newBounds new bounds for the node + */ + public void elementResized(Rectangle2D newBounds); +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisChildRule.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisChildRule.java new file mode 100644 index 00000000..af8071fb --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisChildRule.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.browsing.ui.model.children.ChildRule; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * ChildRule for finding the axis of a JFreeChart + * + * @author Teemu Lempinen + * + */ +public class AxisChildRule implements ChildRule { + + @Override + public boolean isCompatible(Class contentType) { + return contentType.equals(Resource.class); + } + + @Override + public Collection getChildren(ReadGraph graph, Object parent) throws DatabaseException { + ArrayList result = new ArrayList(); + if(!(parent instanceof Resource)) + return result; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + /* + * 1. chart may have multiple plots + * 2. plot may have multiple axis + */ + for(Resource plot : graph.syncRequest(new ObjectsWithType((Resource)parent, l0.ConsistsOf, jfree.Plot))) { + Resource rangeAxisList = graph.getPossibleObject(plot, jfree.Plot_rangeAxisList); + if(rangeAxisList != null) + for(Resource axis : ListUtils.toList(graph, rangeAxisList)) { + result.add(axis); + } + } + return result; + + + } + + @Override + public Collection getParents(ReadGraph graph, Object child) throws DatabaseException { + return new ArrayList(); + } + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisDropAction.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisDropAction.java new file mode 100644 index 00000000..41be71cc --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisDropAction.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.List; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.DropActionFactory; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.jfreechart.chart.properties.xyline.AxisAndVariablesExplorerComposite; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Action for dropping axis on top of other axis or series in {@link AxisAndVariablesExplorerComposite} + * @author Teemu Lempinen + * + */ +public class AxisDropAction implements DropActionFactory { + + @Override + public Runnable create(ReadGraph g, Object target, Object source) throws DatabaseException { + // Make sure that both target and source are resources + Resource t = AdaptionUtils.adaptToSingle(target, Resource.class); + Resource s = AdaptionUtils.adaptToSingle(source, Resource.class); + + if(t == null || s == null) + return null; + + // Make sure that source and target are of correct type + JFreeChartResource jfree = JFreeChartResource.getInstance(g); + if(!g.isInstanceOf(s, jfree.Axis)) + return null; + if(!g.isInstanceOf(t, jfree.Series) && !g.isInstanceOf(t, jfree.Axis)) + return null; + + return getRunnable(t, s); + } + + /** + * Get the runnable for doing the drop action + * + * @param t target resource + * @param s source resource + * @return Runnable + */ + private Runnable getRunnable(final Resource t, final Resource s) { + Runnable runnable = new Runnable() { + + @Override + public void run() { + SimanticsUI.getSession().asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + if(t == null || s == null) return; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource target = t; + Resource source = s; + + // Dragged axis always exists in the same list with target axis, so it is safe to get the target index + Resource plot = graph.getPossibleObject(source, l0.PartOf); + Resource axisListResource = graph.getPossibleObject(plot, jfree.Plot_rangeAxisList); + List axisList = ListUtils.toList(graph, axisListResource); + if(graph.isInstanceOf(target, jfree.Series)) { + // Dropped a axis over a series -> get the axis of the series + Resource dataset = graph.getPossibleObject(target, l0.PartOf); + target = graph.getPossibleObject(dataset, jfree.Dataset_mapToRangeAxis); + } + + // move axis to target position + int targetIndex = axisList.indexOf(target); + axisList.remove(source); + axisList.add(targetIndex, source); + + // Update the range axis list + graph.deny(plot, jfree.Plot_rangeAxisList); + axisListResource = ListUtils.create(graph, axisList); + graph.claim(plot, jfree.Plot_rangeAxisList, axisListResource); + } + + }); + } + }; + return runnable; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisLabelRule.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisLabelRule.java new file mode 100644 index 00000000..d501c6b5 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/AxisLabelRule.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.simantics.browsing.ui.common.ColumnKeys; +import org.simantics.browsing.ui.model.labels.LabelRule; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Label rule for range axis label + * @author Teemu Lempinen + * + */ +public class AxisLabelRule implements LabelRule { + + @Override + public boolean isCompatible(Class contentType) { + return contentType.equals(Resource.class); + } + + /** + * Range axis label + * + * Options: + * 1. Label + * 2. Default + */ + @Override + public Map getLabel(ReadGraph graph, Object content) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource resource = (Resource)content; + String label = graph.getPossibleRelatedValue(resource, l0.HasLabel, Bindings.STRING); + if(label == null || label.isEmpty()) { + label = "Range"; + Resource plot = graph.getPossibleObject(resource, l0.PartOf); + if(plot != null) { + Resource axisListResource = graph.getPossibleObject(plot, jfree.Plot_rangeAxisList); + if(axisListResource != null) { + List axisList = ListUtils.toList(graph, axisListResource); + if(axisList.contains(resource)) + label = label + " " + (axisList.indexOf(resource) + 1); + } + } + } + return Collections.singletonMap(ColumnKeys.SINGLE, label); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesChildRule.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesChildRule.java new file mode 100644 index 00000000..3e058fbc --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesChildRule.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.browsing.ui.model.children.ChildRule; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Child rule for obtaining series in a chart. + * Assumes that the chart has only one plot and that plot has only one dataset + * @author Teemu Lempinen + * + */ +public class SeriesChildRule implements ChildRule { + + @Override + public boolean isCompatible(Class contentType) { + return contentType.equals(Resource.class); + } + + @Override + public Collection getChildren(ReadGraph graph, Object parent) throws DatabaseException { + ArrayList result = new ArrayList(); + if(!(parent instanceof Resource)) + return result; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + /* + * 1. we assume that there is only one plot + * 2. we assume that the only plot has only one dataset + */ + Resource plot = graph.syncRequest(new PossibleObjectWithType((Resource)parent, l0.ConsistsOf, jfree.Plot)); + + Resource dataset = graph.syncRequest(new PossibleObjectWithType(plot, l0.ConsistsOf, jfree.Dataset)); + + Resource seriesList = graph.getPossibleObject(dataset, jfree.Dataset_seriesList); + if(seriesList != null) + for(Resource series : ListUtils.toList(graph, seriesList)) { + result.add(series); + } + return result; + } + + @Override + public Collection getParents(ReadGraph graph, Object child) throws DatabaseException { + return new ArrayList(); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesDropAction.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesDropAction.java new file mode 100644 index 00000000..4ad8d3ea --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesDropAction.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.Collections; +import java.util.List; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.DropActionFactory; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.jfreechart.chart.properties.xyline.XYLineAxisAndVariablesTab; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Drop action for explorer in {@link XYLineAxisAndVariablesTab}. This action is used for dropping + * both series on axis or another sries + * + * @author Teemu Lempinen + * + */ +public class SeriesDropAction implements DropActionFactory { + + @Override + public Runnable create(ReadGraph g, Object target, Object source) throws DatabaseException { + // Make sure that both target and source are resources + Resource t = AdaptionUtils.adaptToSingle(target, Resource.class); + Resource s = AdaptionUtils.adaptToSingle(source, Resource.class); + + if(t == null || s == null) + return null; + + // Make sure that source and target are of correct type + JFreeChartResource jfree = JFreeChartResource.getInstance(g); + if(!g.isInstanceOf(s, jfree.Series)) + return null; + if(!g.isInstanceOf(t, jfree.Series) && !g.isInstanceOf(t, jfree.Axis)) + return null; + + return getRunnable(t, s); + } + + /** + * Get the runnable for doing the drop action + * + * @param t target resource + * @param s source resource + * @return Runnable + */ + private Runnable getRunnable(final Resource t, final Resource s) { + Runnable runnable = new Runnable() { + + @Override + public void run() { + SimanticsUI.getSession().asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + if(t == null || s == null) return; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource target = t; + Resource source = s; + Resource droppedOnSeries = null; + + // Dropped a series over a series -> get target dataset + if(graph.isInstanceOf(target, jfree.Series)) { + droppedOnSeries = target; + Resource dataset = graph.getPossibleObject(target, l0.PartOf); + if(dataset != null) + target = dataset; + } + + // Dropped a series over an axis -> get target dataset + if(graph.isInstanceOf(target, jfree.Axis)) { + Resource dataset = graph.syncRequest(new PossibleObjectWithType(target, jfree.Dataset_mapToRangeAxis_Inverse, jfree.Dataset)); + if(dataset != null) + target = dataset; + } + + // Move series to a dataset + if(graph.isInstanceOf(target, jfree.Dataset)) { + // Remove from old dataset if it was different than the new one + Resource sourceDataset = graph.getPossibleObject(source, l0.PartOf); + if(sourceDataset != null && !sourceDataset.equals(target)) { + Resource sourceSeriesList = graph.getPossibleObject(sourceDataset, jfree.Dataset_seriesList); + if(sourceSeriesList != null) + ListUtils.removeElement(graph, sourceSeriesList, source); + } + graph.deny(source, l0.PartOf); + + // Add to new dataset + Resource targetSeriesList = graph.getPossibleObject(target, jfree.Dataset_seriesList); + if(targetSeriesList == null) { + targetSeriesList = ListUtils.create(graph, Collections.emptyList()); + graph.claim(target, jfree.Dataset_seriesList, targetSeriesList); + } + + + // Series was dropped on another series. Move the dropped series to that place and recreate the list + if(droppedOnSeries != null) { + List list = ListUtils.toList(graph, targetSeriesList); + int targetIndex = list.indexOf(droppedOnSeries); + if(list.contains(source)) + list.remove(source); + list.add(targetIndex, source); + graph.deny(target, jfree.Dataset_seriesList); + targetSeriesList = ListUtils.create(graph, list); + graph.claim(target, jfree.Dataset_seriesList, targetSeriesList); + } else { + ListUtils.insertFront(graph, targetSeriesList, Collections.singleton(source)); + } + + graph.claim(target, l0.ConsistsOf, source); + } + } + }); + } + }; + return runnable; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesLabelDecorationRule.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesLabelDecorationRule.java new file mode 100644 index 00000000..be94644a --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesLabelDecorationRule.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import org.eclipse.jface.resource.FontDescriptor; +import org.simantics.browsing.ui.content.LabelDecorator; +import org.simantics.browsing.ui.model.labeldecorators.LabelDecorationRule; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.utils.AdaptionUtils; + +public class SeriesLabelDecorationRule implements LabelDecorationRule { + + @Override + public boolean isCompatible(Class contentType) { + return contentType.equals(Resource.class); + } + + @Override + public LabelDecorator getLabelDecorator(ReadGraph graph, Object content) throws DatabaseException { + Resource resource = AdaptionUtils.adaptToSingle(content, Resource.class); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + + if (resource != null && graph.isInstanceOf(resource, jfree.Series)) { + final String[] filter = graph.getPossibleRelatedValue(resource, jfree.variableFilter, Bindings.STRING_ARRAY); + if(filter != null) { + return new LabelDecorator.Stub() { + @Override + public String decorateLabel(String label, String column, int itemIndex) { + label += " ["; + for(int i = 0; i < filter.length; i++) { + label += filter[i]; + if(i < filter.length - 1) + label += ", "; + } + label += "]"; + return label; + } + + @SuppressWarnings("unchecked") + @Override + public F decorateFont(F font, String column, int itemIndex) { + return (F) ((FontDescriptor) font); + } + }; + } + } + return null; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesLabelRule.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesLabelRule.java new file mode 100644 index 00000000..f3db811e --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/SeriesLabelRule.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.Collections; +import java.util.Map; + +import org.simantics.browsing.ui.common.ColumnKeys; +import org.simantics.browsing.ui.model.labels.LabelRule; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Label rule for dataset series + * @author Teemu Lempinen + * + */ +public class SeriesLabelRule implements LabelRule { + + @Override + public boolean isCompatible(Class contentType) { + return contentType.equals(Resource.class); + } + + /** + * Options: + * 1. Label + * 2. Variable rvi + * 3. Default + */ + @Override + public Map getLabel(ReadGraph graph, Object content) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource resource = (Resource)content; + String label = graph.getPossibleRelatedValue(resource, l0.HasLabel, Bindings.STRING); + if(label == null || label.isEmpty()) { + label = graph.getPossibleRelatedValue(resource, jfree.variableRVI); + if(label != null && !label.isEmpty() && label.length() > 1) + label = label.substring(1).replace('/', '.'); + else + label = "Set variable"; + } + return Collections.singletonMap(ColumnKeys.SINGLE, label); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/VariableChildRule.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/VariableChildRule.java new file mode 100644 index 00000000..afe693dc --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/ge/VariableChildRule.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.ge; + +import java.util.ArrayList; +import java.util.Collection; + +import org.simantics.browsing.ui.model.children.ChildRule; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * ChildRule for finding the series of an axis + * + * @author Teemu Lempinen + * + */ +public class VariableChildRule implements ChildRule { + + @Override + public boolean isCompatible(Class contentType) { + return contentType.equals(Resource.class); + } + + @Override + public Collection getChildren(ReadGraph graph, Object parent) throws DatabaseException { + ArrayList result = new ArrayList(); + if(!(parent instanceof Resource)) + return result; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource axis = (Resource)parent; + /* + * 1. Axis belongs to a plot + * 2. Plot may have multiple datasets + * 3. Dataset is mapped to a single range axis + * 3. Dataset may have multiple seires + */ + Resource plot = graph.getPossibleObject(axis, jfree.Plot_rangeAxis_Inverse); + if(plot == null) + return result; + + for(Resource dataset : graph.syncRequest(new ObjectsWithType(plot, l0.ConsistsOf, jfree.Dataset))) { + if(graph.hasStatement(dataset, jfree.Dataset_mapToRangeAxis, axis)) { + Resource seriesList = graph.getPossibleObject(dataset, jfree.Dataset_seriesList); + if(seriesList != null) + for(Resource series : ListUtils.toList(graph, seriesList)) { + result.add(series); + } + } + } + return result; + } + + @Override + public Collection getParents(ReadGraph graph, Object child) throws DatabaseException { + return new ArrayList(); + } + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/AllVariablesOfModel.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/AllVariablesOfModel.java new file mode 100644 index 00000000..251bdfe1 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/AllVariablesOfModel.java @@ -0,0 +1,22 @@ +package org.simantics.jfreechart.chart.properties; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; + +public class AllVariablesOfModel implements Read { + + public Resource res; + + public AllVariablesOfModel(Resource res) { + this.res = res; + } + + @Override + public String[] perform(ReadGraph graph) throws DatabaseException { + IAllVariablesOfModel query = graph.adapt(res, IAllVariablesOfModel.class); + return graph.syncRequest(query); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/AxisHidePropertyComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/AxisHidePropertyComposite.java new file mode 100644 index 00000000..02960a88 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/AxisHidePropertyComposite.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.management.ISessionContext; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class containing properties for hiding pars of an axis + * + * @author Teemu Lempinen + * + */ +public class AxisHidePropertyComposite extends Composite { + + public AxisHidePropertyComposite(Composite parent, ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + + GridLayoutFactory.fillDefaults().applyTo(this); + + Group hideGroup = new Group(this, SWT.NONE); + hideGroup.setText("Hide"); + GridDataFactory.fillDefaults().applyTo(hideGroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(hideGroup); + + Button label = new Button(hideGroup, support, SWT.CHECK); + label.setText("Label"); + label.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Axis_visibleLabel, true)); + label.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Axis_visibleLabel)); + GridDataFactory.fillDefaults().applyTo(label.getWidget()); + + Button tmarks = new Button(hideGroup, support, SWT.CHECK); + tmarks.setText("Tick marks"); + tmarks.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Axis_visibleTickMarks, true)); + tmarks.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Axis_visibleTickMarks)); + GridDataFactory.fillDefaults().applyTo(tmarks.getWidget()); + + Button axisLine = new Button(hideGroup, support, SWT.CHECK); + axisLine.setText("Axis line"); + axisLine.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Axis_visibleAxisLine, true)); + axisLine.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Axis_visibleAxisLine)); + GridDataFactory.fillDefaults().applyTo(axisLine.getWidget()); + + Button tlabels = new Button(hideGroup, support, SWT.CHECK); + tlabels.setText("Tick labels"); + tlabels.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Axis_visibleTickLabels, true)); + tlabels.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Axis_visibleTickLabels)); + GridDataFactory.fillDefaults().applyTo(tlabels.getWidget()); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/BooleanPropertyFactory.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/BooleanPropertyFactory.java new file mode 100644 index 00000000..751a1344 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/BooleanPropertyFactory.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.utils.datastructures.Quad; + +/** + * PropertyFactory for finding a boolean property. Supports also finding the + * property from a first occurrence of resource ConsistsOf type HasProperty + * + * @author Teemu Lempinen + * + */ +public class BooleanPropertyFactory extends ReadFactoryImpl { + + final private String propertyURI; + final private String typeURI; + final private Boolean inverse; + final private Boolean defaultValue; + + /** + * PropertyFactory for finding a boolean property with propertyURI + * + * @param propertyURI URI for the boolean property + */ + public BooleanPropertyFactory(String propertyURI) { + this(null, propertyURI, false); + } + + /** + * PropertyFactory for finding a boolean property with propertyURI. + * + * Supports inverting the result (e.g. if required information is IsHidden, but database contains IsVisible) + * + * @param propertyURI URI for the boolean property + * @param inverse Invert the result? + */ + public BooleanPropertyFactory(String propertyURI, boolean inverse) { + this(null, propertyURI, inverse); + } + + /** + * PropertyFactory for finding a boolean property with propertyURI. + * + * Finds the property for first ObjectWithType(resource, L0.ConsistsOf, type) + * + * Supports inverting the result (e.g. if required information is IsHidden, but database contains IsVisible) + * + * @param typeURI URI for a resource (resource ConsistsOf type) (null allowed) + * @param propertyURI URI for the boolean property + * @param inverse Invert the result? + */ + public BooleanPropertyFactory(String typeURI, String propertyURI, boolean inverse) { + this(typeURI, propertyURI, inverse, false); + } + + /** + * PropertyFactory for finding a boolean property with propertyURI. + * + * Finds the property for first ObjectWithType(resource, L0.ConsistsOf, type) + * + * Supports inverting the result (e.g. if required information is IsHidden, but database contains IsVisible) + * + * @param typeURI URI for a resource (resource ConsistsOf type) (null allowed -> not used) + * @param propertyURI URI for the boolean property + * @param inverse Invert the result? + * @param defaultValue default value + */ + public BooleanPropertyFactory(String typeURI, String propertyURI, boolean inverse, boolean defaultValue) { + this.propertyURI = propertyURI; + this.inverse = inverse; + this.typeURI = typeURI; + this.defaultValue = defaultValue; + } + + @Override + public Object getIdentity(Object inputContents) { + return new Quad((Resource) inputContents, propertyURI, getClass(), defaultValue); + } + + @Override + public Boolean perform(ReadGraph graph, Resource r) throws DatabaseException { + if(typeURI == null) { + // if no typeUri, use the default resource r + return getValue(graph, r); + } else { + // typeURI was defined, find the property for the first occurence of ConsistsOf type + Resource type = graph.getResource(typeURI); + for(Resource o : graph.syncRequest(new ObjectsWithType(r, Layer0.getInstance(graph).ConsistsOf, type))) { + // Returns the value for the first occurrence + return getValue(graph, o); + } + } + // if nothing was found with typeURI + return false; + } + + /** + * Return the value for a Boolean literal possibly inverted (or default if resource != Boolean literal) + * + * @param graph ReadGraph + * @param resource Literal Boolean resource + * @return value of the parameter (or default or inverted) + * @throws DatabaseException + */ + private Boolean getValue(ReadGraph graph, Resource resource) throws DatabaseException { + Boolean value = graph.getPossibleRelatedValue(resource, graph.getResource(propertyURI), Bindings.BOOLEAN); + if(value != null) { + return !inverse.equals(value); + } else { + return defaultValue; + } + } +} \ No newline at end of file diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/BooleanSelectionListener.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/BooleanSelectionListener.java new file mode 100644 index 00000000..8364b82c --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/BooleanSelectionListener.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.simantics.browsing.ui.swt.widgets.impl.SelectionListenerImpl; +import org.simantics.databoard.Bindings; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.layer0.Layer0; + +/** + * Class for setting a boolean value when a selection occurs. (check box buttons) + * + * @author Teemu Lempinen + * + */ +public class BooleanSelectionListener extends SelectionListenerImpl { + + final private String propertyURI; + final private String typeUri; + + /** + * Boolean selection listener for property with propertyURI + * + * @param context ISessionContext + * @param propertyURI uri of the boolean property + */ + public BooleanSelectionListener(ISessionContext context, String propertyURI) { + this(context, null, propertyURI); + } + + /** + * Boolean selection listener for property with propertyURI + * Sets the property for all ObjectWithType(resource, L0.ConsistsOf, type) + * + * @param context ISessionContext + * @param typeUri URI for a resource (resource ConsistsOf type) (null allowed -> not used) + * @param propertyURI uri of the boolean property + */ + public BooleanSelectionListener(ISessionContext context, String typeUri, String propertyURI) { + super(context); + this.propertyURI = propertyURI; + this.typeUri = typeUri; + } + + @Override + public void apply(WriteGraph graph, Resource chart) throws DatabaseException { + if(typeUri == null) { + setValue(graph, chart); + } else { + Resource type = graph.getResource(typeUri); + for(Resource object : graph.syncRequest(new ObjectsWithType(chart, Layer0.getInstance(graph).ConsistsOf, type))) { + setValue(graph, object); + } + } + + } + + /** + * Set boolean value for Boolean literal resource (inverts the current value). + * @param graph ReadGraph + * @param resource Boolean literal resource + * @throws DatabaseException + */ + private void setValue(WriteGraph graph, Resource resource) throws DatabaseException { + Resource property = graph.getResource(propertyURI); + Boolean value = graph.getPossibleRelatedValue(resource, property, Bindings.BOOLEAN); + graph.claimLiteral(resource, property, Boolean.FALSE.equals(value)); + } +} \ No newline at end of file diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ChartTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ChartTab.java new file mode 100644 index 00000000..d6f62591 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ChartTab.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.ChartComposite; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Tab for displaying a chart + * @author Teemu Lempinen + * + */ +public class ChartTab extends LabelPropertyTabContributor implements Widget { + + private Composite parent; + + @Override + public void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support) { + support.register(this); + this.parent = body; + } + + @Override + public void setInput(ISessionContext context, final Object input) { + Resource chart = AdaptionUtils.adaptToSingle(input, Resource.class); + new ChartComposite(parent, chart, SWT.BORDER); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java new file mode 100644 index 00000000..2901c270 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java @@ -0,0 +1,375 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Device; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.browsing.ui.swt.widgets.impl.SelectionListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.Read; +import org.simantics.diagram.stubs.G2DResource; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.RunnableWithObject; +import org.simantics.utils.datastructures.Triple; + +/** + * Composite for selecting a color for a chart component + * + * @author Teemu Lempinen + * + */ +public class ColorPicker extends Composite implements Widget { + + Button defaultColor, customColor, color; + + /** + * Create a composite containing radio buttons for default or custom color. Color chooser button is active + * when the custom radio button is selected. Color chooser uses {@link ColorDialog} to select a color + * + * @param parent Composite + * @param context ISessionContext + * @param support WidgetSupport + * @param style SWT style + */ + public ColorPicker(Composite parent, ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + support.register(this); + + GridLayoutFactory.fillDefaults().numColumns(4).applyTo(this); + + defaultColor = new Button(this, support, SWT.RADIO); + defaultColor.setText("default"); + defaultColor.setSelectionFactory(new DefaultColorSelectionFactory(false)); + defaultColor.addSelectionListener(new DefaultColorSelectionListener(context)); + GridDataFactory.fillDefaults().applyTo(defaultColor.getWidget()); + + customColor = new Button(this, support, SWT.RADIO); + customColor.setText("custom"); + customColor.setSelectionFactory(new DefaultColorSelectionFactory(true)); + customColor.addSelectionListener(new DefaultColorSelectionListener(context)); + + GridDataFactory.fillDefaults().applyTo(customColor.getWidget()); + + color = new Button(this, support, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(color.getWidget()); + color.setImageFactory(new ColorImageFactoryFactory(color)); + color.addSelectionListener(new ColorSelectionListener(context)); + color.getWidget().setEnabled(false); + } + + /** + * Method for finding the resource for which the color is selected. + * + * @param graph ReadGraph + * @param input input from WidgetSupport + * @return + * @throws DatabaseException + */ + protected Resource getResource(ReadGraph graph, Resource input) throws DatabaseException { + return input; + } + + /** + * Method for getting the relation with which the g2d.Color is related to a resource + * + * @param graph ReadGraph + * @return Color relation + * @throws DatabaseException + */ + protected Resource getColorRelation(ReadGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + return jfree.color; + } + + + @Override + public void setInput(ISessionContext context, Object input) { + final Resource resource = AdaptionUtils.adaptToSingle(input, Resource.class); + + // Create a listener to define the enabled state of the color chooser button + context.getSession().asyncRequest(new Read() { + + @Override + public Boolean perform(ReadGraph graph) throws DatabaseException { + // if there is a color definition, the color chooser is active + Boolean result = graph.hasStatement(getResource(graph, resource), getColorRelation(graph)); + return result; + } + + }, new Listener() { + + @Override + public void execute(Boolean result) { + if(!color.getWidget().isDisposed()) { + color.getWidget().getDisplay().asyncExec(new RunnableWithObject(result) { + @Override + public void run() { + if(!color.getWidget().isDisposed()) + color.getWidget().setEnabled((Boolean)getObject()); + } + }); + } + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return color.getWidget().isDisposed(); + } + }); + } + + /** + * Get a colored image to be displayed in the color chooser button + * + * @param device SWT Device + * @param red Red 0-255 + * @param green Green 0-255 + * @param blue Blue 0-255 + * @return + */ + private Image getColorPickerImage(Device device, int red, int green, int blue) { + Image image = new Image(device, 20, 20); + GC gc = new GC (image); + gc.setBackground (new Color(device, red, green, blue)); + gc.fillRectangle (image.getBounds ()); + gc.dispose (); + return image; + } + + /** + * ImageFactory returning an image for color button + * @author Teemu Lempinen + * + */ + private class ColorImageFactoryFactory extends ReadFactoryImpl { + + Button button; + + public ColorImageFactoryFactory(Button button) { + super(); + this.button = button; + } + + public Object getIdentity(Object inputContents) { + return new Triple, Button>(inputContents, getClass(), button); + } + + @Override + public Image perform(ReadGraph graph, Resource input) throws DatabaseException { + if(button.getWidget().isDisposed()) + return null; + Display device = button.getWidget().getDisplay(); + if(device == null) + return null; + RGB rgb = getColor(graph, getResource(graph, input)); + return getColorPickerImage(device, rgb.red, rgb.green, rgb.blue); + } + + } + + /** + * Get RGB from a color literal resource. If resource is not a color resource, return blue (RGB 0, 0, 255) + * @param graph ReadGraph + * @param input Color literal resource (float[4]) + * @return RGB color + * @throws DatabaseException + */ + private RGB getColor(ReadGraph graph, Resource input) throws DatabaseException{ + float[] colorComponents = graph.getPossibleRelatedValue(input, getColorRelation(graph)); + RGB rgb; + if(colorComponents == null) + rgb = new RGB(0, 0, 255); + else + rgb = new RGB((int)(colorComponents[0] * 255.0f), + (int)(colorComponents[1] * 255.0f), + (int)(colorComponents[2] * 255.0f)); + return rgb; + } + + + /** + * SelectionListener for color button. + * + * @author Teemu Lempinen + * + */ + private class ColorSelectionListener extends SelectionListenerImpl { + + private SelectionEvent e; + private RGB rgb; + + /** + * + * @param context ISessionContext + */ + public ColorSelectionListener(ISessionContext context) { + super(context); + } + + @Override + public void widgetSelected(SelectionEvent e) { + if(color.getWidget().isDisposed()) + return; + // Save the event for coordinates + this.e = e; + super.widgetSelected(e); + } + + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + if(color.getWidget().isDisposed()) + return; + + final Resource resource = getResource(graph, input); + final Display display = color.getWidget().getDisplay(); + final RGB oldRGB = getColor(graph, resource); + + display.asyncExec(new RunnableWithObject(oldRGB) { + public void run() { + // Use color dialog to select a color + Shell shell = new Shell(display); + ColorDialog cd = new ColorDialog(shell); + Point point = color.getWidget().toDisplay(e.x - 150, e.y - 150); + cd.getParent().setLocation(point.x, point.y); + cd.setText("Select color"); + cd.setRGB((RGB)getObject()); + rgb = cd.open(); + if(rgb == null) + return; + + SimanticsUI.getSession().asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + G2DResource g2d = G2DResource.getInstance(graph); + float[] components = new float[] {(float)rgb.red / 255.0f, (float)rgb.green / 255.0f, (float)rgb.blue / 255.0f, 1.0f}; + graph.claimLiteral(resource, getColorRelation(graph), g2d.Color, components); + } + }); + + } + }); + + + + } + + } + + /** + * SelectionFactory for default and custom color radio buttons + * @author Teemu Lempinen + * + */ + private class DefaultColorSelectionFactory extends ReadFactoryImpl { + + private Boolean isCustom; + + /** + * + * @param isCustom Is this custom button? + */ + public DefaultColorSelectionFactory(Boolean isCustom) { + super(); + this.isCustom = isCustom; + } + + @Override + public Object getIdentity(Object inputContents) { + return new Triple((Resource) inputContents, getClass(), isCustom); + } + + @Override + public Boolean perform(ReadGraph graph, Resource input) throws DatabaseException { + Resource r = graph.getPossibleObject(getResource(graph, input), getColorRelation(graph)); + boolean result = false; // Default == not selected + if(r == null && !isCustom) { + // No color definition and default-button -> selected + result = true; + } else if(r != null && isCustom) { + // color definition and custom button -> selected + result = true; + } + return result; + } + + } + + /** + * SelectionListener for default and custom radio buttons + * + * @author Teemu Lempinen + * + */ + private class DefaultColorSelectionListener extends SelectionListenerImpl { + + private SelectionEvent e; + + public DefaultColorSelectionListener(ISessionContext context) { + super(context); + } + + @Override + public void widgetSelected(SelectionEvent e) { + this.e = e; + super.widgetSelected(e); + } + + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + Resource resource = getResource(graph, input); + if(customColor.getWidget().equals(e.widget)) { + // Custom selected. If there is no color already, create a default Blue color + G2DResource g2d = G2DResource.getInstance(graph); + if(graph.getPossibleObject(resource, getColorRelation(graph)) == null) { + float[] components = java.awt.Color.BLUE.getColorComponents(new float[4]); + components[3] = 1.0f; + graph.claimLiteral(resource, getColorRelation(graph), g2d.Color, components); + } + } else { + // Default selected, remove color definition + graph.deny(resource, getColorRelation(graph)); + } + } + } + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/DoubleValidator.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/DoubleValidator.java new file mode 100644 index 00000000..e41c9b0a --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/DoubleValidator.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.jface.dialogs.IInputValidator; + +/** + * Validator for validating that an input is double. + * + * Can allow empty strings. + * + * @author Teemu Lempinen + * + */ +public class DoubleValidator implements IInputValidator { + + boolean allowEmpty; + + /** + * New double validator. Does not allow empty strings + */ + public DoubleValidator() { + this(false); + } + + /** + * New double validator. + * @param allowEmpty Are empty strings allowed + */ + public DoubleValidator(boolean allowEmpty) { + this.allowEmpty = allowEmpty; + } + + @Override + public String isValid(String newText) { + if (allowEmpty && newText.trim().isEmpty()) + return null; + try { + Double.parseDouble(newText); + return null; + } catch (NumberFormatException e) { + return e.getMessage(); + } + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/IAllVariablesOfModel.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/IAllVariablesOfModel.java new file mode 100644 index 00000000..c46c4938 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/IAllVariablesOfModel.java @@ -0,0 +1,7 @@ +package org.simantics.jfreechart.chart.properties; + +import org.simantics.db.request.Read; + +public interface IAllVariablesOfModel extends Read{ + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/JFreeChartPropertyColorProvider.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/JFreeChartPropertyColorProvider.java new file mode 100644 index 00000000..ab4c4327 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/JFreeChartPropertyColorProvider.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.jface.resource.ColorDescriptor; +import org.eclipse.jface.resource.ResourceManager; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.simantics.browsing.ui.swt.widgets.impl.ITrackedColorProvider; + +/** + * ColorProvider providing coloring scheme for chart tab text widgets + * + * @author Teemu Lempinen + * + */ +public class JFreeChartPropertyColorProvider implements ITrackedColorProvider { + + private final ResourceManager resourceManager; + + private final ColorDescriptor highlightColor = ColorDescriptor.createFrom(new RGB(254, 255, 197)); + private final ColorDescriptor inactiveColor = ColorDescriptor.createFrom(new RGB(255, 255, 255)); + private final ColorDescriptor invalidInputColor = ColorDescriptor.createFrom(new RGB(255, 128, 128)); + + public JFreeChartPropertyColorProvider(ResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + + @Override + public Color getEditingBackground() { + return null; + } + + @Override + public Color getHoverBackground() { + return resourceManager.createColor(highlightColor); + } + + @Override + public Color getInactiveBackground() { + return resourceManager.createColor(inactiveColor); + } + + @Override + public Color getInvalidBackground() { + return resourceManager.createColor(invalidInputColor); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/LabelPropertyTabContributor.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/LabelPropertyTabContributor.java new file mode 100644 index 00000000..5d6e3e56 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/LabelPropertyTabContributor.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2007, 2012 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.jfreechart.chart.properties; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.procedure.AsyncListener; +import org.simantics.db.request.Read; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.selectionview.PropertyTabContributorImpl; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.datastructures.Callback; + +public abstract class LabelPropertyTabContributor extends PropertyTabContributorImpl { + + private boolean isDisposed = false; + + + public void createControl(Composite parent, final IWorkbenchSite site, final ISessionContext context, final WidgetSupportImpl support) { + super.createControl(parent, site, context, support); + + // Add dispose listener to make sure name listening receives the correct isDisposed -value + parent.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + LabelPropertyTabContributor.this.dispose(); + } + }); + } + + @Override + public void updatePartName(ISelection forSelection, final Callback updateCallback) { + final Variable variable = AdaptionUtils.adaptToSingle(forSelection, Variable.class); + final Resource resource = AdaptionUtils.adaptToSingle(forSelection, Resource.class); + if(resource == null && variable == null) { + updateCallback.run("Selection properties"); + return; + } + + SimanticsUI.getSession().asyncRequest(new Read() { + + @Override + public String perform(ReadGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + ModelingResources mr = ModelingResources.getInstance(graph); + + Resource r; + if(variable != null) { + r = (Resource)variable.getRepresents(graph); + } else { + r = resource; + } + + if(graph.hasStatement(r, mr.ElementToComponent)) { + r = graph.getSingleObject(r, mr.ElementToComponent); + } + String label = graph.getPossibleRelatedValue(r, l0.HasLabel); + if(label != null) + return label; + label = graph.getPossibleRelatedValue(r, l0.HasName); + if(label != null) + return label; + return "No name for selection"; + } + }, new AsyncListener() { + + @Override + public void execute(AsyncReadGraph graph, String result) { + updateCallback.run(result); + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + + } + + @Override + public boolean isDisposed() { + return isDisposed; + } + }); + } + + @Override + protected void dispose() { + this.isDisposed = true; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RVIFactory.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RVIFactory.java new file mode 100644 index 00000000..52a9a632 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RVIFactory.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class for providing RVI content to a text field with all '/' characters changed to '.' + * @author Teemu Lempinen + * + */ +public class RVIFactory extends ReadFactoryImpl { + + @Override + public String perform(ReadGraph graph, Resource input) throws DatabaseException { + String value = graph.getPossibleRelatedValue(input, JFreeChartResource.getInstance(graph).variableRVI); + return value != null ? value = value.substring(1).replace('/', '.') : ""; + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RVIModifier.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RVIModifier.java new file mode 100644 index 00000000..6a036607 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RVIModifier.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.jface.bindings.keys.KeyStroke; +import org.eclipse.jface.bindings.keys.ParseException; +import org.eclipse.jface.fieldassist.ContentProposalAdapter; +import org.eclipse.jface.fieldassist.IContentProposal; +import org.eclipse.jface.fieldassist.IContentProposalListener; +import org.eclipse.jface.fieldassist.IContentProposalListener2; +import org.eclipse.jface.fieldassist.SimpleContentProposalProvider; +import org.eclipse.jface.fieldassist.TextContentAdapter; +import org.eclipse.swt.widgets.Control; +import org.simantics.browsing.ui.swt.widgets.impl.TextModifyListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.TrackedModifyEvent; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.databoard.Bindings; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Class for modifying variable name to rvi and saving it to database. + * + * Modifier also adds content proposal support to the control it is added to. + * @author Teemu Lempinen + * + */ +public class RVIModifier extends TextModifyListenerImpl { + + private boolean active; + private Control control; + + private char[] alphaNumericCharacters = { + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','å','ä','ö', + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','Å','Ä','Ö', + '1','2','3','4','5','6','7','8','9','0','.','_'}; + + /** + * Create a new RVIModifier and attach a content proposal support to control + * @param control + * @param support + */ + public RVIModifier(Control control, WidgetSupport support) { + this.control = control; + this.active = true; + + KeyStroke keyStroke = null; + try { + keyStroke = KeyStroke.getInstance("Ctrl+Space"); + } catch (ParseException e1) { + e1.printStackTrace(); + } + + SimpleContentProposalProvider scpp = new VariableProposalProvider(control, support); + scpp.setFiltering(true); + + ContentProposalAdapter adapter = new ContentProposalAdapter( + control, new TextContentAdapter(), scpp, keyStroke, alphaNumericCharacters); + adapter.setAutoActivationDelay(0); + adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); + adapter.addContentProposalListener(new IContentProposalListener2() { + + @Override + public void proposalPopupOpened(ContentProposalAdapter adapter) { + if(RVIModifier.this != null) + RVIModifier.this.deactivate(); + } + + @Override + public void proposalPopupClosed(ContentProposalAdapter adapter) { + if(RVIModifier.this != null) + RVIModifier.this.activate(); + } + }); + + adapter.addContentProposalListener(new IContentProposalListener() { + + @Override + public void proposalAccepted(IContentProposal proposal) { + if(RVIModifier.this.control != null && !RVIModifier.this.control.isDisposed()) + RVIModifier.this.modifyText(new TrackedModifyEvent(RVIModifier.this.control, proposal.getContent())); + } + }); + + + } + + + @Override + public void applyText(WriteGraph graph, Resource resource, String text) throws DatabaseException { + if(active) { + text = "/" + text.replace('.', '/'); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + graph.claimLiteral(resource, jfree.variableRVI, text, Bindings.STRING); + graph.deny(resource, jfree.variableFilter); + } + } + + public void deactivate() { + active = false; + } + + public void activate() { + active = true; + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RangeComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RangeComposite.java new file mode 100644 index 00000000..cbb2f51a --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RangeComposite.java @@ -0,0 +1,257 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import java.util.Iterator; +import java.util.LinkedHashMap; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.simantics.browsing.ui.swt.widgets.TrackedCombo; +import org.simantics.browsing.ui.swt.widgets.impl.ComboModifyListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.Read; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.utils.RunnableWithObject; +import org.simantics.utils.datastructures.Triple; +import org.simantics.utils.ui.AdaptionUtils; +import org.simantics.utils.ui.ExceptionUtils; + +/** + * Composite for range controls in chart series properties + * @author Teemu Lempinen + * + */ +public class RangeComposite extends Composite implements Widget { + + private Composite composite; + + public RangeComposite(Composite parent, ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + support.register(this); + GridLayoutFactory.fillDefaults().spacing(3, 0).margins(3, 3).applyTo(this); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this); + composite = this; + } + + @Override + public void setInput(final ISessionContext context, final Object input) { + if(composite == null || composite.isDisposed()) + return; + + final Resource series = AdaptionUtils.adaptToSingle(input, Resource.class); + + RangeHandlerFactory f; + try { + f = context.getSession().syncRequest(new Read() { + @Override + public RangeHandlerFactory perform(ReadGraph graph) + throws DatabaseException { + return graph.adapt(series, RangeHandlerFactory.class); + } + }); + + } catch (DatabaseException e) { + //ExceptionUtils.logAndShowError("Insert something intelligent here.", e); + return; + } + + final RangeHandlerFactory factory = f; + + /* + * Listen to the enumerations assigned to the variable in this series. + * Listener is needed because the user can change the variableRVI for the series + * and that changes the options for range + */ + context.getSession().asyncRequest(factory.getRequest(series), new Listener>() { + + @Override + public void execute(LinkedHashMap result) { + if(isDisposed()) + return; + + // Always modify the composite, even with null result + composite.getDisplay().asyncExec(new RunnableWithObject(result) { + @Override + public void run() { + if(composite == null || composite.isDisposed()) + return; + + // Remove all content (even with null result) + for(Control child : composite.getChildren()) + child.dispose(); + + if(getObject() == null) + return; + + // New widgetSupport for the combos + WidgetSupportImpl support = new WidgetSupportImpl(); + + Label label; + TrackedCombo combo; + LinkedHashMap result = (LinkedHashMap)getObject(); + Iterator iterator = result.keySet().iterator(); + + // For each array index (enumeration), create a label and a combo + int index = 0; + while(iterator.hasNext()) { + Object key = iterator.next(); + Composite c = new Composite(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(c); + GridLayoutFactory.fillDefaults().applyTo(c); + + label = new Label(c, SWT.NONE); + label.setText((String)key); + GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.END).applyTo(label); + + combo = new TrackedCombo(c, support, SWT.READ_ONLY); + combo.setItemFactory(factory.getRangeItemFactory(index, (Resource)result.get(key))); + combo.setSelectionFactory(new RangeSelectionFactory(index)); + combo.addModifyListener(new RangeModifyListener(index, result.size())); + GridDataFactory.fillDefaults().applyTo(combo.getWidget()); + index++; + } + + // Set the width of the combo + GridLayout gl = (GridLayout)composite.getLayout(); + gl.numColumns = index; + + // Set input for the combos + support.fireInput(context, input); + + /* + * Find out if this composite is located in a scrolled composite. + * If it is, resize the scrolled composite + */ + Composite previousParent = composite.getParent(); + for(int i = 0; i < 5; i++) { + if(previousParent.getParent() instanceof ScrolledComposite) { + previousParent.layout(); + ScrolledComposite sc = (ScrolledComposite) previousParent.getParent(); + Point size = previousParent.computeSize(SWT.DEFAULT, SWT.DEFAULT); + sc.setMinSize(size); + break; + } + previousParent = previousParent.getParent(); + } + } + }); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return composite == null || composite.isDisposed(); + } + }); + } + + /** + * + * @author Teemu Lempinen + * + */ + private class RangeSelectionFactory extends ReadFactoryImpl { + + int index; + + /** + * + * @param index Index of the enumeration in the variable + */ + public RangeSelectionFactory(int index) { + this.index = index; + } + + public Object getIdentity(Object inputContents) { + return new Triple>(inputContents, index, getClass()); + } + + @Override + public String perform(ReadGraph graph, Resource series) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + String[] filter = graph.getPossibleRelatedValue(series, jfree.variableFilter, Bindings.STRING_ARRAY); + + /* + * If no filter was found or the index is not applicable, return "All" + */ + if(filter == null) + return "All"; + else if(filter.length < index) + return "All"; + else + return filter[index]; + } + + } + + + + /** + * RangeModifyListener for modifying a range filter in chart series + * @author Teemu Lempinen + * + */ + private class RangeModifyListener extends ComboModifyListenerImpl { + + private int index, size; + + /** + * + * @param index Index of the modified range filter + * @param size Size of the whole filter (for situations where there is no filter) + */ + public RangeModifyListener(int index, int size) { + this.index = index; + this.size = size; + } + + @Override + public void applyText(WriteGraph graph, Resource series, String text) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + String[] filter = graph.getPossibleRelatedValue(series, jfree.variableFilter, Bindings.STRING_ARRAY); + + // If there is no filter, create a default filter with all indexes "All" + if(filter == null) { + filter = new String[size]; + for(int i = 0; i < filter.length; i++) { + filter[i] = "All"; + } + } + + // Modify the filter index + filter[index] = text; + graph.claimLiteral(series, jfree.variableFilter, filter, Bindings.STRING_ARRAY); + } + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RangeHandlerFactory.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RangeHandlerFactory.java new file mode 100644 index 00000000..f015878c --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/RangeHandlerFactory.java @@ -0,0 +1,15 @@ +package org.simantics.jfreechart.chart.properties; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.db.Resource; +import org.simantics.db.request.Read; + +public interface RangeHandlerFactory { + + public Read> getRequest(final Resource series); + + public ReadFactoryImpl> getRangeItemFactory(int index, Resource res); +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TitleFactory.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TitleFactory.java new file mode 100644 index 00000000..c02b3a58 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TitleFactory.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * TextFactory for chart title + * @author Teemu Lempinen + * + */ +public class TitleFactory extends ReadFactoryImpl { + @Override + public String perform(ReadGraph graph, Resource chart) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Resource title = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.TextTitle)); + if(title == null) + return ""; + else { + String label = graph.getPossibleRelatedValue(title, l0.HasLabel, Bindings.STRING); + return label == null ? "" : label; + } + } +} \ No newline at end of file diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TitleModifier.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TitleModifier.java new file mode 100644 index 00000000..543d173b --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TitleModifier.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.simantics.browsing.ui.swt.widgets.impl.TextModifyListenerImpl; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * TitleModifier for chart title + * @author Teemu Lempinen + * + */ +public class TitleModifier extends TextModifyListenerImpl { + + @Override + public void applyText(WriteGraph graph, Resource chart, String text) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Resource title = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.TextTitle)); + if(title == null) { + title = GraphUtils.create2(graph, jfree.TextTitle, + jfree.Title_position, jfree.Top); + } + graph.claimLiteral(title, l0.HasLabel, text); + } + +} \ No newline at end of file diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TrackedSpinner.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TrackedSpinner.java new file mode 100644 index 00000000..74673a03 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/TrackedSpinner.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Spinner; +import org.simantics.browsing.ui.common.ErrorLogger; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactory; +import org.simantics.browsing.ui.swt.widgets.impl.TextModifyListener; +import org.simantics.browsing.ui.swt.widgets.impl.TrackedModifyEvent; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.procedure.Listener; +import org.simantics.utils.ui.SWTUtils; + +/** + * Class for implementing Widget behavior for SWT Spinner in Simantics. + * + * @author Teemu Lempinen + * + */ +public class TrackedSpinner implements Widget { + + private Spinner spinner; + private ListenerList modifyListeners; + private ReadFactory selectionFactory; + + + public TrackedSpinner(Composite parent, WidgetSupport support, int style) { + spinner = new Spinner(parent, style); + support.register(this); + + // Add a ModifyListener that uses all listeners in modifyListeners -list + spinner.addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + if (modifyListeners != null) { + TrackedModifyEvent event = new TrackedModifyEvent(spinner, spinner.getText()); + for (Object o : modifyListeners.getListeners()) { + ((TextModifyListener) o).modifyText(event); + } + } + } + }); + } + + @Override + public void setInput(ISessionContext context, Object input) { + + // Update all modifyListeners + if (modifyListeners != null) { + for (Object o : modifyListeners.getListeners()) { + if(o instanceof Widget) { + ((Widget) o).setInput(context, input); + } + } + } + + if (selectionFactory != null) { + // Get a value for the spinner + selectionFactory.listen(context, input, new Listener() { + @Override + public void exception(Throwable t) { + ErrorLogger.defaultLogError(t); + } + @Override + public void execute(final Integer selection) { + SWTUtils.asyncExec(spinner, new Runnable() { + @Override + public void run() { + if(isDisposed()) return; + spinner.setSelection(selection); + } + }); + } + @Override + public boolean isDisposed() { + return spinner.isDisposed(); + } + }); + } + + } + + /** + * Set a selection factory for the spinner + * + * @param selectionFactory ReadFactory SelectionFactory + */ + public void setSelectionFactory(ReadFactory selectionFactory) { + this.selectionFactory = selectionFactory; + } + + /** + * Add a modifyListener for the spinner + * @param listener TextModifyListener + */ + public synchronized void addModifyListener(TextModifyListener listener) { + if (modifyListeners == null) { + modifyListeners = new ListenerList(ListenerList.IDENTITY); + } + modifyListeners.add(listener); + } + + /** + * Remove modifyListener from the spinner + * + * @param listener TextModifyListener + */ + public synchronized void removeModifyListener(TextModifyListener listener) { + if (modifyListeners == null) + return; + modifyListeners.remove(listener); + } + + /** + * Get the SWT Spinner of this TrackedSpinner widget + * @return + */ + public Spinner getWidget() { + return spinner; + } + + /** + * Set minimum value + * @param value int minimum value + */ + public void setMinimum(int value) { + spinner.setMinimum(value); + } + + /** + * Set maximum value + * @param value int maximum value + */ + public void setMaximum(int value) { + spinner.setMaximum(value); + } + + /** + * Sets the receiver's selection, minimum value, maximum value, digits, increment and page increment all at once. + * + * @param selection the new selection value + * @param minimum the new minimum value + * @param maximum the new maximum value + * @param digits the new digits value + * @param increment the new increment value + * @param pageIncrement the new pageIncrement value + */ + public void setValues(int selection, int minimum, int maximum, int digits, int increment, int pageIncrement) { + spinner.setValues(selection, minimum, maximum, digits, increment, pageIncrement); + } + + /** + * Sets the selection, which is the receiver's position, to the argument. + * If the argument is not within the range specified by minimum and maximum, + * it will be adjusted to fall within this range. + * + * @param value + */ + public void setSelection(int value) { + spinner.setSelection(value); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/VariableExistsValidator.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/VariableExistsValidator.java new file mode 100644 index 00000000..08815bc8 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/VariableExistsValidator.java @@ -0,0 +1,132 @@ +package org.simantics.jfreechart.chart.properties; + +import org.eclipse.jface.dialogs.IInputValidator; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.Read; +import org.simantics.layer0.Layer0; +import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Variable exists validator for tracked text widgets. + * + * @author Teemu Lempinen + * + */ +public class VariableExistsValidator implements IInputValidator, Widget { + + private String[] names; + private TrackedText text; + private boolean allowEmpty; + + /** + * Validate against all variables + * + * Do not allow empty input + * @param support WidgetSupport + * @param text Text widget + */ + public VariableExistsValidator(WidgetSupport support, TrackedText text) { + this(support, text, false); + } + + /** + * Validate against all variables + * + * @param support WidgetSupport + * @param text Text widget + * @param allowEmpty Allow empty input text + */ + public VariableExistsValidator(WidgetSupport support, TrackedText text, boolean allowEmpty) { + support.register(this); + names = new String[] {"time"}; + this.text = text; + this.allowEmpty = allowEmpty; + } + + /** + * Returns null if there is a variable named newText in the model + */ + @Override + public String isValid(String newText) { + if(newText == null || newText.isEmpty()) { + if(allowEmpty) + return null; + else + return "Empty name not allowed"; + } + + synchronized (names) { + for(String s : names) { + if(newText.equals(s)) + return null; + } + } + + return "Not a valid variable name"; + } + + @Override + public void setInput(ISessionContext context, Object input) { + final Resource resource = AdaptionUtils.adaptToSingle(input, Resource.class); + + if(resource == null) { + names = new String[] {"time"}; + return; + } + + Resource model = null; + try { + /* Find the model resource. It can be found with PartOf + relations from series resource in a chart */ + model = context.getSession().syncRequest(new Read() { + + @Override + public Resource perform(ReadGraph graph) throws DatabaseException { + Resource r = resource; + while((r = graph.getPossibleObject(r, Layer0.getInstance(graph).PartOf)) != null) { + if(graph.isInstanceOf(r, SimulationResource.getInstance(graph).Model)) + return r; + } + return null; + } + + }); + + if(model != null) { + // Find all variables and set them as the reference for isValid(String) + SimanticsUI.getSession().asyncRequest( + new AllVariablesOfModel(model) + , new Listener() { + + @Override + public void execute(String[] result) { + names = result; + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return text.isDisposed(); + } + + }); + } + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/VariableProposalProvider.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/VariableProposalProvider.java new file mode 100644 index 00000000..d6962cfa --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/VariableProposalProvider.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties; + +import org.eclipse.jface.fieldassist.SimpleContentProposalProvider; +import org.eclipse.swt.widgets.Control; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.Resource; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.procedure.Listener; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Provides all variables a model contains + * + * @author Teemu Lempinen + * + */ +public class VariableProposalProvider extends SimpleContentProposalProvider implements Widget { + + /** + * Provides all variables a model contains. Given resource needs to be + * part of a model (i.e. using PartOf leads eventually to a SysdynModel). + * + * @param control Control that is using this provider + * @param resource A resource that is part of a model + */ + public VariableProposalProvider(final Control control, WidgetSupport support) { + super(new String [] {}); + support.register(this); + this.control = control; + } + + private Resource resource; + private Control control; + + @Override + public void setInput(ISessionContext context, Object input) { + + final Resource resource = AdaptionUtils.adaptToSingle(input, Resource.class); + if(resource == null) + return; + this.resource = resource; + + SimanticsUI.getSession().asyncRequest( + new AllVariablesOfModel(resource) + , new Listener() { + + @Override + public void execute(String[] result) { + setProposals(result); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + @Override + public boolean isDisposed() { + return control == null || + control.isDisposed() || + !resource.equals(VariableProposalProvider.this.resource); + } + + }); + + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarAxisTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarAxisTab.java new file mode 100644 index 00000000..acd39555 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarAxisTab.java @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.bar; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Spinner; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.browsing.ui.swt.widgets.impl.TextModifyListener; +import org.simantics.browsing.ui.swt.widgets.impl.TrackedModifyEvent; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.AxisHidePropertyComposite; +import org.simantics.jfreechart.chart.properties.ColorPicker; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.jfreechart.chart.properties.TrackedSpinner; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Tab for bar chart axis properties + * @author Teemu Lempinen + * + */ +public class BarAxisTab extends LabelPropertyTabContributor implements Widget { + + private TrackedSpinner angle; + private Integer angleInt = null; + private WidgetSupportImpl domainAxisSupport = new WidgetSupportImpl(); + private WidgetSupportImpl rangeAxisSupport = new WidgetSupportImpl(); + private TrackedText rangelabel, rangemin, rangemax; + private ScrolledComposite sc; + private Composite composite; + + + @Override + public void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support) { + support.register(this); + + // Scrolled composite containing all of the properties in this tab + sc = new ScrolledComposite(body, SWT.NONE | SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().grab(true, true).applyTo(sc); + GridLayoutFactory.fillDefaults().margins(3, 3).applyTo(sc); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + composite = new Composite(sc, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // Domain Axis properties + Group domainGroup = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(domainGroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(3).applyTo(domainGroup); + domainGroup.setText("Domain axis"); + + // Label for x-axis + Label label = new Label(domainGroup, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Label:"); + + rangelabel = new TrackedText(domainGroup, domainAxisSupport, SWT.BORDER); + rangelabel.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); + rangelabel.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + rangelabel.setColorProvider(new JFreeChartPropertyColorProvider(rangelabel.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(rangelabel.getWidget()); + + Composite axisHide = new AxisHidePropertyComposite(domainGroup, context, domainAxisSupport, SWT.NONE); + GridDataFactory.fillDefaults().span(1, 3).applyTo(axisHide); + + Label angleLabel = new Label(domainGroup, SWT.NONE); + angleLabel.setText("Label angle:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(angleLabel); + + Composite angleComposite = new Composite(domainGroup, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(angleComposite); + GridLayoutFactory.fillDefaults().applyTo(angleComposite); + angle = new TrackedSpinner(angleComposite, domainAxisSupport, SWT.BORDER); + angle.setSelectionFactory(new AngleSelectionFactory()); + angle.addModifyListener(new AngleModifyListener()); + angle.setMinimum(0); + angle.setMaximum(90); + angle.getWidget().setIncrement(5); + GridDataFactory.fillDefaults().applyTo(angle.getWidget()); + + // Domain Color + label = new Label(domainGroup, SWT.NONE); + label.setText("Color:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + Composite colorPicker = new ColorPicker(domainGroup, context, domainAxisSupport, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(colorPicker); + + domainGroup.layout(); + + // Range Axis properties + Group rangeGroup = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(rangeGroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(3).applyTo(rangeGroup); + rangeGroup.setText("Range axis"); + + // Label for range axis + label = new Label(rangeGroup, SWT.NONE); + label.setText("Label:"); + label.setAlignment(SWT.RIGHT); + GridDataFactory.fillDefaults().hint(angleLabel.getBounds().width, SWT.DEFAULT).align(SWT.END, SWT.CENTER).applyTo(label); + + rangelabel = new TrackedText(rangeGroup, rangeAxisSupport, SWT.BORDER); + rangelabel.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); + rangelabel.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + rangelabel.setColorProvider(new JFreeChartPropertyColorProvider(rangelabel.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(rangelabel.getWidget()); + + axisHide = new AxisHidePropertyComposite(rangeGroup, context, rangeAxisSupport, SWT.NONE); + GridDataFactory.fillDefaults().span(1, 4).applyTo(axisHide); + + // Min and max values for range axis + label = new Label(rangeGroup, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Min:"); + + Composite minmax = new Composite(rangeGroup, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(minmax); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(minmax); + rangemin = new TrackedText(minmax, rangeAxisSupport, SWT.BORDER); + rangemin.setColorProvider(new JFreeChartPropertyColorProvider(rangemin.getResourceManager())); + rangemin.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Axis_min)); + rangemin.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Axis_min)); + rangemin.setInputValidator(new DoubleValidator(true)); + + label = new Label(minmax, SWT.NONE); + label.setText("Max:"); + rangemax = new TrackedText(minmax, rangeAxisSupport, SWT.BORDER); + rangemax.setColorProvider(new JFreeChartPropertyColorProvider(rangemax.getResourceManager())); + rangemax.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Axis_max)); + rangemax.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Axis_max)); + rangemax.setInputValidator(new DoubleValidator(true)); + + // Range Color + label = new Label(rangeGroup, SWT.NONE); + label.setText("Color:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + colorPicker = new ColorPicker(rangeGroup, context, rangeAxisSupport, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(colorPicker); + + // Resize scrolled composite + sc.setContent(composite); + Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); + sc.setMinSize(size); + } + + /** + * ModifyListener for the angle {@link TrackedSpinner} + * + * @author Teemu Lempinen + * + */ + private class AngleModifyListener implements TextModifyListener, Widget { + + private ISessionContext context; + private Object lastInput = null; + + @Override + public void modifyText(TrackedModifyEvent e) { + if(context == null) + return; + + // Get the text value from spinner and associated resource (input) + Spinner spinner = (Spinner)e.getWidget(); + final String textValue = spinner.getText(); + final Object input = lastInput; + + try { + context.getSession().syncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Resource domainAxis = AdaptionUtils.adaptToSingle(input, Resource.class); + try { + // usually reliable, since the spinner does all the checks + Double value = Double.parseDouble(textValue); + Double oldValue = graph.getPossibleRelatedValue(domainAxis, jfree.Axis_rotateLabelDegrees, Bindings.DOUBLE); + if(oldValue == null || !oldValue.equals(value)) { + graph.claimLiteral(domainAxis, jfree.Axis_rotateLabelDegrees, value, Bindings.DOUBLE); + angleInt = value.intValue(); + } + } catch (NumberFormatException e) { + graph.claimLiteral(domainAxis, jfree.Axis_rotateLabelDegrees, 0.0, Bindings.DOUBLE); + angleInt = 0; + } + } + + }); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + } + + @Override + public void setInput(ISessionContext context, Object parameter) { + this.context = context; + lastInput = parameter; + } + + } + + /** + * Class for setting the value for angle {@link TrackedSpinner} + * @author Teemu Lempinen + * + */ + private class AngleSelectionFactory extends ReadFactoryImpl { + + @Override + public Integer perform(ReadGraph graph, Resource domainAxis) throws DatabaseException { + if(angleInt == null) { + Double angle = 0.0; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + if(domainAxis != null) { + Double value = graph.getPossibleRelatedValue(domainAxis, jfree.Axis_rotateLabelDegrees); + if(value != null) + angle = value; + } + return angle.intValue(); + } else { + return angleInt; + } + } + + } + + @Override + public void setInput(final ISessionContext context, Object input) { + final Resource chart = AdaptionUtils.adaptToSingle(input, Resource.class); + if(chart == null) + return; + + context.getSession().asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.Plot)); + if(plot == null) return; + Resource rangeAxis = graph.getPossibleObject(plot, jfree.Plot_rangeAxis); + if(rangeAxis == null) return; + rangeAxisSupport.fireInput(context, new StructuredSelection(rangeAxis)); + + Resource domainAxis = graph.getPossibleObject(plot, jfree.Plot_domainAxis); + if(domainAxis == null) return; + domainAxisSupport.fireInput(context, new StructuredSelection(domainAxis)); + } + }); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarGeneralPropertiesTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarGeneralPropertiesTab.java new file mode 100644 index 00000000..91d604ff --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarGeneralPropertiesTab.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.bar; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.layout.LayoutConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedCombo; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.ComboModifyListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.BooleanPropertyFactory; +import org.simantics.jfreechart.chart.properties.BooleanSelectionListener; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.jfreechart.chart.properties.TitleFactory; +import org.simantics.jfreechart.chart.properties.TitleModifier; +import org.simantics.layer0.Layer0; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; + + +/** + * General properties of a bar chart + * @author Teemu Lempinen + * + */ +public class BarGeneralPropertiesTab extends LabelPropertyTabContributor { + + private ScrolledComposite sc; + private Composite composite; + private Button hgrid, htitle, hlegend; + private TrackedText name, title, time; + private TrackedCombo type; + + + @Override + public void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support) { + // Scrolled composite containing all of the properties in this tab + sc = new ScrolledComposite(body, SWT.NONE | SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().grab(true, true).applyTo(sc); + GridLayoutFactory.fillDefaults().applyTo(sc); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + composite = new Composite(sc, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // General properties + Group general = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(general); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(4).applyTo(general); + general.setText("General"); + + // first column: labels + Composite labelColumn1 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(labelColumn1); + GridLayoutFactory.fillDefaults().applyTo(labelColumn1); + + // second column: name and title + Composite propertyColumn1 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(propertyColumn1); + GridLayoutFactory.fillDefaults().spacing(0, LayoutConstants.getSpacing().y).applyTo(propertyColumn1); + + // third column: labels + Composite labelColumn2 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(labelColumn2); + GridLayoutFactory.fillDefaults().spacing(0, LayoutConstants.getSpacing().y).applyTo(labelColumn2); + + // fourth column: type and time + Composite propertyColumn2 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(propertyColumn2); + GridLayoutFactory.fillDefaults().applyTo(propertyColumn2); + + // Name + Label label = new Label(labelColumn1, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Name:"); + + name = new org.simantics.browsing.ui.swt.widgets.TrackedText(propertyColumn1, support, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(name.getWidget()); + name.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel)); + name.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + name.setColorProvider(new JFreeChartPropertyColorProvider(name.getResourceManager())); + + // Type + label = new Label(labelColumn2, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Type:"); + + type = new TrackedCombo(propertyColumn2, support, SWT.BORDER | SWT.READ_ONLY); + type.addModifyListener(new TypeModifyListener()); + type.setItemFactory(new TypeItemFactory()); + type.setSelectionFactory(new TypeSelectionFactory()); + GridDataFactory.fillDefaults().applyTo(type.getWidget()); + + // Title (Which is different than name) + label = new Label(labelColumn1, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Title:"); + + title = new org.simantics.browsing.ui.swt.widgets.TrackedText(propertyColumn1, support, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(title.getWidget()); + title.setTextFactory(new TitleFactory()); + title.addModifyListener(new TitleModifier()); + title.setColorProvider(new JFreeChartPropertyColorProvider(name.getResourceManager())); + + // Time + label = new Label(labelColumn2, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Time:"); + + time = new org.simantics.browsing.ui.swt.widgets.TrackedText(propertyColumn2, support, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(time.getWidget()); + time.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Chart_time)); + time.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Chart_time)); + time.setInputValidator(new DoubleValidator(true)); + time.setColorProvider(new JFreeChartPropertyColorProvider(time.getResourceManager())); + + // Group for hide options + Group hideGroup = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(hideGroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(hideGroup); + hideGroup.setText("Hide"); + + hgrid = new Button(hideGroup, support, SWT.CHECK); + hgrid.setText("Grid"); + hgrid.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.Plot, JFreeChartResource.URIs.Plot_visibleGrid, true)); + hgrid.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Plot, JFreeChartResource.URIs.Plot_visibleGrid)); + htitle = new Button(hideGroup, support, SWT.CHECK); + htitle.setText("Title"); + htitle.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.TextTitle, JFreeChartResource.URIs.visible, true)); + htitle.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.TextTitle, JFreeChartResource.URIs.visible)); + hlegend = new Button(hideGroup, support, SWT.CHECK); + hlegend.setText("Legend"); + hlegend.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Chart_visibleLegend, true)); + hlegend.addSelectionListener(new BooleanSelectionListener(context, null, JFreeChartResource.URIs.Chart_visibleLegend)); + + + + // Resize scrolled composite + sc.setContent(composite); + Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); + sc.setMinSize(size); + } + + /** + * + * @author Teemu Lempinen + * + */ + private class TypeSelectionFactory extends ReadFactoryImpl { + @Override + public String perform(ReadGraph graph, Resource chart) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.CategoryPlot)); + if(plot != null) { + Resource dataset = graph.syncRequest(new PossibleObjectWithType(plot, l0.ConsistsOf, jfree.CategoryDataset)); + + if(dataset != null) { + Resource renderer = graph.syncRequest(new PossibleObjectWithType(dataset, jfree.Dataset_renderer, jfree.Renderer)); + + if(renderer != null && graph.isInstanceOf(renderer, jfree.StackedBarRenderer)) + return "Stacked"; + } + } + return "Normal"; + } + } + + /** + * RangeItemFactory finds all inexes of a given enumeration + * and adds "Sum" and "All" to the returned indexes + * @author Teemu Lempinen + * + */ + private class TypeItemFactory extends ReadFactoryImpl> { + @Override + public Map perform(ReadGraph graph, Resource series) throws DatabaseException { + LinkedHashMap result = new LinkedHashMap(); + result.put("Normal", "Normal"); + result.put("Stacked", "Stacked"); + return result; + } + } + + /** + * TypeModifyListener for modifying the type of a bar chart + * @author Teemu Lempinen + * + */ + private class TypeModifyListener extends ComboModifyListenerImpl { + @Override + public void applyText(WriteGraph graph, Resource chart, String text) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.CategoryPlot)); + if(plot == null) + return; + + Resource dataset = graph.syncRequest(new PossibleObjectWithType(plot, l0.ConsistsOf, jfree.CategoryDataset)); + if(dataset == null) + return; + + graph.deny(dataset, jfree.Dataset_renderer); + + Resource renderer; + if(text.equals("Stacked")) + renderer = GraphUtils.create2(graph, jfree.StackedBarRenderer); + else + renderer = GraphUtils.create2(graph, jfree.BarRenderer); + + graph.claim(dataset, jfree.Dataset_renderer, renderer); + } + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarSeriesPropertyComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarSeriesPropertyComposite.java new file mode 100644 index 00000000..94b15ee5 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarSeriesPropertyComposite.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.bar; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.RVIFactory; +import org.simantics.jfreechart.chart.properties.RVIModifier; +import org.simantics.jfreechart.chart.properties.RangeComposite; +import org.simantics.jfreechart.chart.properties.VariableExistsValidator; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Composite for modifying properties of a series in a bar chart + * @author Teemu Lempinen + * + */ +public class BarSeriesPropertyComposite extends Composite { + + private TrackedText variable, label, time; + + public BarSeriesPropertyComposite(Composite parent, final ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(this); + + // Variable for the series + Label label = new Label(this, SWT.NONE); + label.setText("Variable:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + variable = new TrackedText(this, support, SWT.BORDER); + variable.setTextFactory(new RVIFactory()); + variable.addModifyListener(new RVIModifier(variable.getWidget(), support)); + variable.setInputValidator(new VariableExistsValidator(support, variable)); + variable.setColorProvider(new JFreeChartPropertyColorProvider(this.variable.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this.variable.getWidget()); + + // Range + label = new Label(this, SWT.NONE); + label.setText("Range:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + RangeComposite rangeComposite = new RangeComposite(this, context, support, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(rangeComposite); + + + // Label to be displayed in chart for this series + label = new Label(this, SWT.NONE); + label.setText("Label:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + this.label = new TrackedText(this, support, SWT.BORDER); + this.label.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); + this.label.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + this.label.setColorProvider(new JFreeChartPropertyColorProvider(this.label.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this.label.getWidget()); + + // Time + label = new Label(this, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + label.setText("Time:"); + + Composite composite = new Composite(this, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(composite); + GridLayoutFactory.fillDefaults().applyTo(composite); + + time = new org.simantics.browsing.ui.swt.widgets.TrackedText(composite, support, SWT.BORDER); + time.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Series_time)); + time.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Series_time)); + time.setInputValidator(new DoubleValidator(true)); + time.setColorProvider(new JFreeChartPropertyColorProvider(time.getResourceManager())); + GridDataFactory.fillDefaults().applyTo(time.getWidget()); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarSeriesTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarSeriesTab.java new file mode 100644 index 00000000..459d0b32 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/bar/BarSeriesTab.java @@ -0,0 +1,212 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.bar; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.SingleSelectionInputSource; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite; +import org.simantics.browsing.ui.swt.widgets.impl.SelectionListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.RemoverUtil; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.ChartUtils; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.jfreechart.chart.properties.xyline.AxisAndVariablesExplorerComposite; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.datastructures.ArrayMap; + +/** + * Tab containing the series of a bar chart + * @author Teemu Lempinen + * + */ +public class BarSeriesTab extends LabelPropertyTabContributor implements Widget { + + private GraphExplorerComposite explorer; + private ScrolledComposite propertyContainer; + private WidgetSupportImpl additionalSupport; + private Button add, remove; + private Resource chartResource; + private BarSeriesPropertyComposite spc; + + + public BarSeriesTab() { + additionalSupport = new WidgetSupportImpl(); + } + + @Override + public void createControls(Composite body, IWorkbenchSite site, final ISessionContext context, WidgetSupport support) { + support.register(this); + Composite composite = new Composite(body, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(composite); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // (Ontology-based) GraphExplorer displaying variables in a bar chart + explorer = new AxisAndVariablesExplorerComposite(ArrayMap.keys( + "displaySelectors", "displayFilter").values(false, false), site, composite, support, SWT.FULL_SELECTION | SWT.BORDER | SWT.SINGLE); + explorer.setBrowseContexts(JFreeChartResource.URIs.BarSeriesBrowseContext); + explorer.setInputSource(new SingleSelectionInputSource( + Resource.class)); + explorer.getExplorer().setAutoExpandLevel(2); // Expand everything in the beginning + explorer.finish(); + + ((Tree)explorer.getExplorerControl()).addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + updateSelection(context); + } + }); + GridDataFactory.fillDefaults().hint(250, SWT.DEFAULT).grab(false, true).applyTo(explorer); + + // Scrolled composite for displaying properties of a selection in explorer + propertyContainer = new ScrolledComposite(composite, SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().span(1, 2).grab(true, true).applyTo(propertyContainer); + GridLayoutFactory.fillDefaults().applyTo(propertyContainer); + propertyContainer.setExpandHorizontal(true); + propertyContainer.setExpandVertical(true); + + // Buttons for adding and removing variables from a pie plot + Composite buttonComposite = new Composite(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(buttonComposite); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite); + + add = new Button(buttonComposite, additionalSupport, SWT.NONE); + add.setText("Add"); + add.addSelectionListener(new NewVariableListener(context)); + + remove = new Button(buttonComposite, additionalSupport, SWT.NONE); + remove.setText("Remove"); + remove.addSelectionListener(new RemoveListener(context)); + } + + /** + * Updates the content of propertyContainer + * @param context + */ + private void updateSelection(ISessionContext context) { + ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class); + IStructuredSelection selection = (IStructuredSelection)selectionProvider.getSelection(); + final Resource resource = AdaptionUtils.adaptToSingle(selection, Resource.class); + if(resource == null) + return; + + for(Control child : propertyContainer.getChildren()) { + child.dispose(); + } + spc = new BarSeriesPropertyComposite(propertyContainer, context, additionalSupport, SWT.NONE); + + additionalSupport.fireInput(context, selection); + + propertyContainer.setContent(spc); + Point size = spc.computeSize(SWT.DEFAULT, SWT.DEFAULT); + propertyContainer.setMinSize(size); + } + + /** + * SelectionListener for adding a new variable to a plot + * @author Teemu Lempinen + * + */ + private class NewVariableListener extends SelectionListenerImpl { + + public NewVariableListener(ISessionContext context) { + super(context); + } + + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + Resource dataset = null; + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + if(input == null) { + if(chartResource != null) { + Resource plot = graph.syncRequest(new PossibleObjectWithType(chartResource, l0.ConsistsOf, jfree.Plot)); + if(plot != null) + dataset = graph.syncRequest(new PossibleObjectWithType(plot, l0.ConsistsOf, jfree.Dataset)); + } + } else { + if(graph.isInstanceOf(input, jfree.Series)) { + dataset = graph.getPossibleObject(input, l0.PartOf); + } + } + + if(dataset != null) { + // Create series with no rvi + ChartUtils.createSeries(graph, dataset, null); + } + } + } + + /** + * SelectionListener for remove button + * @author Teemu Lempinen + * + */ + private class RemoveListener extends SelectionListenerImpl { + + public RemoveListener(ISessionContext context) { + super(context); + } + + /** + * Removes selected resource from explorer + */ + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + if(input == null) + return; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource list = null; + if(graph.isInstanceOf(input, jfree.Series)) { + // Remove series from dataset and seriesList + Resource dataset = graph.getPossibleObject(input, l0.PartOf); + if(dataset != null) + list = graph.getPossibleObject(dataset, jfree.Dataset_seriesList); + + if(list != null) + ListUtils.removeElement(graph, list, input); + RemoverUtil.remove(graph, input); + } + } + } + + @Override + public void setInput(ISessionContext context, Object input) { + chartResource = AdaptionUtils.adaptToSingle(input, Resource.class); + } + + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieGeneralPropertiesTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieGeneralPropertiesTab.java new file mode 100644 index 00000000..cb721a58 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieGeneralPropertiesTab.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.pie; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.layout.LayoutConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.BooleanPropertyFactory; +import org.simantics.jfreechart.chart.properties.BooleanSelectionListener; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.jfreechart.chart.properties.TitleFactory; +import org.simantics.jfreechart.chart.properties.TitleModifier; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * General properties of a pie chart + * @author Teemu Lempinen + * + */ +public class PieGeneralPropertiesTab extends LabelPropertyTabContributor { + + private ScrolledComposite sc; + private Composite composite; + private Button htitle, hlegend, hlabels; + private TrackedText name, title, time; + + @Override + public void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support) { + // Scrolled composite containing all of the properties in this tab + sc = new ScrolledComposite(body, SWT.NONE | SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().grab(true, true).applyTo(sc); + GridLayoutFactory.fillDefaults().applyTo(sc); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + composite = new Composite(sc, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // General properties + Group general = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(general); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(4).applyTo(general); + general.setText("General"); + + // first column: labels + Composite labelColumn1 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(labelColumn1); + GridLayoutFactory.fillDefaults().applyTo(labelColumn1); + + // first column: name and title + Composite propertyColumn1 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(propertyColumn1); + GridLayoutFactory.fillDefaults().spacing(0, LayoutConstants.getSpacing().y).applyTo(propertyColumn1); + + // first column: labels + Composite labelColumn2 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(labelColumn2); + GridLayoutFactory.fillDefaults().spacing(0, LayoutConstants.getSpacing().y).applyTo(labelColumn2); + + // first column: type and time + Composite propertyColumn2 = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(propertyColumn2); + GridLayoutFactory.fillDefaults().applyTo(propertyColumn2); + + // Name + Label label = new Label(labelColumn1, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Name:"); + + name = new org.simantics.browsing.ui.swt.widgets.TrackedText(propertyColumn1, support, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(name.getWidget()); + name.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel)); + name.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + name.setColorProvider(new JFreeChartPropertyColorProvider(name.getResourceManager())); + + // Dummy data for now. Waiting for different pie chart types + label = new Label(labelColumn2, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(label); + label.setText(""); + + label = new Label(propertyColumn2, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).applyTo(label); + label.setText(""); + + // Title (Which is different than name) + label = new Label(labelColumn1, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Title:"); + + title = new org.simantics.browsing.ui.swt.widgets.TrackedText(propertyColumn1, support, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(title.getWidget()); + title.setTextFactory(new TitleFactory()); + title.addModifyListener(new TitleModifier()); + title.setColorProvider(new JFreeChartPropertyColorProvider(name.getResourceManager())); + + // Time + label = new Label(labelColumn2, SWT.NONE); + GridDataFactory.fillDefaults().grab(false, true).align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Time:"); + + time = new org.simantics.browsing.ui.swt.widgets.TrackedText(propertyColumn2, support, SWT.BORDER); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).applyTo(time.getWidget()); + time.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Chart_time)); + time.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Chart_time)); + time.setInputValidator(new DoubleValidator(true)); + time.setColorProvider(new JFreeChartPropertyColorProvider(time.getResourceManager())); + + // Group for hide options + Group hideGroup = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(hideGroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(hideGroup); + hideGroup.setText("Hide"); + + htitle = new Button(hideGroup, support, SWT.CHECK); + htitle.setText("Title"); + htitle.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.TextTitle, JFreeChartResource.URIs.visible, true)); + htitle.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.TextTitle, JFreeChartResource.URIs.visible)); + hlegend = new Button(hideGroup, support, SWT.CHECK); + hlegend.setText("Legend"); + hlegend.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Chart_visibleLegend, true)); + hlegend.addSelectionListener(new BooleanSelectionListener(context, null, JFreeChartResource.URIs.Chart_visibleLegend)); + hlabels = new Button(hideGroup, support, SWT.CHECK); + hlabels.setText("Section labels"); + hlabels.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.Plot, JFreeChartResource.URIs.Plot_visibleLabels, true)); + hlabels.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Plot, JFreeChartResource.URIs.Plot_visibleLabels)); + + sc.setContent(composite); + Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); + sc.setMinSize(size); + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieSeriesPropertyComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieSeriesPropertyComposite.java new file mode 100644 index 00000000..d2b149b0 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieSeriesPropertyComposite.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.pie; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.BooleanPropertyFactory; +import org.simantics.jfreechart.chart.properties.BooleanSelectionListener; +import org.simantics.jfreechart.chart.properties.ColorPicker; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.RVIFactory; +import org.simantics.jfreechart.chart.properties.RVIModifier; +import org.simantics.jfreechart.chart.properties.RangeComposite; +import org.simantics.jfreechart.chart.properties.VariableExistsValidator; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Composite containing the properties of a series + * @author Teemu Lempinen + * + */ +public class PieSeriesPropertyComposite extends Composite { + + private TrackedText variable, label, time; + + public PieSeriesPropertyComposite(Composite parent, ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(this); + + // Variable for the series + Label label = new Label(this, SWT.NONE); + label.setText("Variable:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + variable = new TrackedText(this, support, SWT.BORDER); + variable.setTextFactory(new RVIFactory()); + variable.addModifyListener(new RVIModifier(variable.getWidget(), support)); + variable.setInputValidator(new VariableExistsValidator(support, variable)); + variable.setColorProvider(new JFreeChartPropertyColorProvider(this.variable.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this.variable.getWidget()); + + // Range + label = new Label(this, SWT.NONE); + label.setText("Range:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + RangeComposite rangeComposite = new RangeComposite(this, context, support, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(rangeComposite); + + + // Label to be displayed in chart for this series + label = new Label(this, SWT.NONE); + label.setText("Label:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + this.label = new TrackedText(this, support, SWT.BORDER); + this.label.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); + this.label.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + this.label.setColorProvider(new JFreeChartPropertyColorProvider(this.label.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this.label.getWidget()); + + // Color + label = new Label(this, SWT.NONE); + label.setText("Color:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + Composite colorPicker = new ColorPicker(this, context, support, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(colorPicker); + + // Time + label = new Label(this, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + label.setText("Time:"); + + Composite composite = new Composite(this, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(composite); + GridLayoutFactory.fillDefaults().applyTo(composite); + + time = new org.simantics.browsing.ui.swt.widgets.TrackedText(composite, support, SWT.BORDER); + time.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Series_time)); + time.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Series_time)); + time.setInputValidator(new DoubleValidator(true)); + time.setColorProvider(new JFreeChartPropertyColorProvider(time.getResourceManager())); + GridDataFactory.fillDefaults().applyTo(time.getWidget()); + + // Exploded + label = new Label(this, SWT.NONE); + label.setText(""); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + Button exploded = new Button(this, support, SWT.CHECK); + exploded.setText("Exploded"); + exploded.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Series_exploded)); + exploded.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.Series_exploded)); + GridDataFactory.fillDefaults().applyTo(exploded.getWidget()); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieSeriesTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieSeriesTab.java new file mode 100644 index 00000000..34a09b34 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/pie/PieSeriesTab.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.pie; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.SingleSelectionInputSource; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite; +import org.simantics.browsing.ui.swt.widgets.impl.SelectionListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.RemoverUtil; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.ChartUtils; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.jfreechart.chart.properties.xyline.AxisAndVariablesExplorerComposite; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.datastructures.ArrayMap; + +/** + * Tab for modifying series in a pie chart configuration + * @author Teemu Lempinen + * + */ +public class PieSeriesTab extends LabelPropertyTabContributor implements Widget { + + private GraphExplorerComposite explorer; + private ScrolledComposite propertyContainer; + private WidgetSupportImpl additionalSupport; + private Button add, remove; + private Resource chartResource; + + public PieSeriesTab() { + additionalSupport = new WidgetSupportImpl(); + } + + @Override + public void createControls(Composite body, IWorkbenchSite site, final ISessionContext context, WidgetSupport support) { + support.register(this); + Composite composite = new Composite(body, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(composite); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // (Ontology-based) GraphExplorer displaying variables of a pie chart + explorer = new AxisAndVariablesExplorerComposite(ArrayMap.keys( + "displaySelectors", "displayFilter").values(false, false), site, composite, support, SWT.FULL_SELECTION | SWT.BORDER | SWT.SINGLE); + explorer.setBrowseContexts(JFreeChartResource.URIs.PieSeriesBrowseContext); + explorer.setInputSource(new SingleSelectionInputSource( + Resource.class)); + explorer.getExplorer().setAutoExpandLevel(2); // Expand everything in the beginning + explorer.finish(); + + ((Tree)explorer.getExplorerControl()).addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + updateSelection(context); + } + }); + GridDataFactory.fillDefaults().hint(250, SWT.DEFAULT).grab(false, true).applyTo(explorer); + + // Scrolled composite for displaying properties of a selection in explorer + propertyContainer = new ScrolledComposite(composite, SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().span(1, 2).grab(true, true).applyTo(propertyContainer); + GridLayoutFactory.fillDefaults().applyTo(propertyContainer); + propertyContainer.setExpandHorizontal(true); + propertyContainer.setExpandVertical(true); + + + // Buttons for adding and removing variables from a pie plot + Composite buttonComposite = new Composite(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(buttonComposite); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite); + + add = new Button(buttonComposite, additionalSupport, SWT.NONE); + add.setText("Add"); + add.addSelectionListener(new NewVariableListener(context)); + + remove = new Button(buttonComposite, additionalSupport, SWT.NONE); + remove.setText("Remove"); + remove.addSelectionListener(new RemoveListener(context)); + } + + /** + * Updates the content of propertyContainer + * @param context + */ + private void updateSelection(ISessionContext context) { + ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class); + IStructuredSelection selection = (IStructuredSelection)selectionProvider.getSelection(); + final Resource resource = AdaptionUtils.adaptToSingle(selection, Resource.class); + if(resource == null) + return; + + for(Control child : propertyContainer.getChildren()) { + child.dispose(); + } + + PieSeriesPropertyComposite spc = new PieSeriesPropertyComposite(propertyContainer, context, additionalSupport, SWT.NONE); + propertyContainer.setContent(spc); + Point size = spc.computeSize(SWT.DEFAULT, SWT.DEFAULT); + propertyContainer.setMinSize(size); + + additionalSupport.fireInput(context, selection); + } + + + /** + * SelectionListener for adding a new variable to a plot + * @author Teemu Lempinen + * + */ + private class NewVariableListener extends SelectionListenerImpl { + + public NewVariableListener(ISessionContext context) { + super(context); + } + + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource dataset = null; + if(input == null) { + if(chartResource != null) { + Resource plot = graph.syncRequest(new PossibleObjectWithType(chartResource, l0.ConsistsOf, jfree.Plot)); + if(plot != null) + dataset = graph.syncRequest(new PossibleObjectWithType(plot, l0.ConsistsOf, jfree.Dataset)); + } + } else { + if(graph.isInstanceOf(input, jfree.Series)) { + dataset = graph.getPossibleObject(input, l0.PartOf); + } + } + if(dataset != null) { + // Create series with no rvi + Resource series = ChartUtils.createSeries(graph, dataset, null); + graph.claimLiteral(series, jfree.Series_exploded, false); + } + } + } + + /** + * SelectionListener for remove button + * @author Teemu Lempinen + * + */ + private class RemoveListener extends SelectionListenerImpl { + + public RemoveListener(ISessionContext context) { + super(context); + } + + /** + * Removes selected resource from explorer + */ + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + if(input == null) + return; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource list = null; + if(graph.isInstanceOf(input, jfree.Series)) { + // Remove series from dataset and seriesList + Resource dataset = graph.getPossibleObject(input, l0.PartOf); + if(dataset != null) + list = graph.getPossibleObject(dataset, jfree.Dataset_seriesList); + + if(list != null) + ListUtils.removeElement(graph, list, input); + RemoverUtil.remove(graph, input); + } + } + } + + @Override + public void setInput(ISessionContext context, Object input) { + chartResource = AdaptionUtils.adaptToSingle(input, Resource.class); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/AxisAndVariablesExplorerComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/AxisAndVariablesExplorerComposite.java new file mode 100644 index 00000000..04b02097 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/AxisAndVariablesExplorerComposite.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.xyline; + +import java.util.ArrayList; +import java.util.Map; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.NodeContext; +import org.simantics.browsing.ui.common.ErrorLogger; +import org.simantics.browsing.ui.model.InvalidContribution; +import org.simantics.browsing.ui.model.dnd.DndBrowseContext; +import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.procedure.Procedure; +import org.simantics.db.request.Read; +import org.simantics.ui.SimanticsUI; + +/** + * ExplorerComposite allowing ontology-based DnD definitions. DnD Copied from {@link ModelBrowser2} + * + * @author Teemu Lempinen + * + */ +public class AxisAndVariablesExplorerComposite extends GraphExplorerComposite { + + volatile DndBrowseContext dndBrowseContext; + + public AxisAndVariablesExplorerComposite(Map args, IWorkbenchSite site, Composite parent, + WidgetSupport support, int style) { + super(args, site, parent, support, style); + + SimanticsUI.getSession().asyncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + ArrayList browseContexts = new ArrayList(); + for (String uri : getBrowseContexts()) { + Resource browseContext = graph.getPossibleResource(uri); + if (browseContext != null) + browseContexts.add(browseContext); + } + try { + dndBrowseContext = DndBrowseContext.create(graph, browseContexts); + } catch (InvalidContribution e) { + ErrorLogger.defaultLogError(e); + } + } + }); + } + + @Override + protected void handleDrop(final Object data, final NodeContext target) { + if (target == null) + return; + + SimanticsUI.getSession().asyncRequest(new Read() { + @Override + public Runnable perform(ReadGraph graph) throws DatabaseException { + if (dndBrowseContext == null) + return null; + return dndBrowseContext.getAction(graph, target, data); + } + }, new Procedure() { + @Override + public void execute(Runnable result) { + if (result != null) + result.run(); + } + + @Override + public void exception(Throwable t) { + ErrorLogger.defaultLogError(t); + } + }); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/AxisPropertyComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/AxisPropertyComposite.java new file mode 100644 index 00000000..14bdb4d4 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/AxisPropertyComposite.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.xyline; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.AxisHidePropertyComposite; +import org.simantics.jfreechart.chart.properties.ColorPicker; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; + +/** + * Composite for displaying axis properties in {@link XYLineAxisAndVariablesTab} + * + * @author Teemu Lempinen + * + */ +public class AxisPropertyComposite extends Composite { + + TrackedText name, units, min, max; + Button tlabels, tmarks; + + public AxisPropertyComposite(Composite parent, ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(this); + + // Label (units) + Label label = new Label(this, SWT.NONE); + label.setText("Label: "); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + units = new TrackedText(this, support, SWT.BORDER); + units.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); // FIXME: Units + units.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); // FIXME: Units + units.setColorProvider(new JFreeChartPropertyColorProvider(units.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(units.getWidget()); + + + // Minimum and maximum values + label = new Label(this, SWT.NONE); + label.setText("Min:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + Composite minmax = new Composite(this, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(minmax); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(minmax); + min = new TrackedText(minmax, support, SWT.BORDER); + min.setColorProvider(new JFreeChartPropertyColorProvider(min.getResourceManager())); + min.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Axis_min)); + min.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Axis_min)); + min.setInputValidator(new DoubleValidator(true)); + + label = new Label(minmax, SWT.NONE); + label.setText("Max:"); + max = new TrackedText(minmax, support, SWT.BORDER); + max.setColorProvider(new JFreeChartPropertyColorProvider(max.getResourceManager())); + max.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Axis_max)); + max.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Axis_max)); + max.setInputValidator(new DoubleValidator(true)); + + + // Color + label = new Label(this, SWT.NONE); + label.setText("Color:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + Composite colorPicker = new ColorPicker(this, context, support, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(colorPicker); + + // Tick and label visibility + Composite c = new Composite(this, SWT.NONE); + GridDataFactory.fillDefaults().span(2, 1).applyTo(c); + GridLayoutFactory.fillDefaults().applyTo(c); + Composite axisHide = new AxisHidePropertyComposite(c, context, support, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(axisHide); + } + +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/SeriesPropertyComposite.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/SeriesPropertyComposite.java new file mode 100644 index 00000000..f3dc7848 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/SeriesPropertyComposite.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.xyline; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Spinner; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.browsing.ui.swt.widgets.impl.TextModifyListener; +import org.simantics.browsing.ui.swt.widgets.impl.TrackedModifyEvent; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.ColorPicker; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.RVIFactory; +import org.simantics.jfreechart.chart.properties.RVIModifier; +import org.simantics.jfreechart.chart.properties.RangeComposite; +import org.simantics.jfreechart.chart.properties.TrackedSpinner; +import org.simantics.jfreechart.chart.properties.VariableExistsValidator; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * Composite for displaying series properties in {@link XYLineAxisAndVariablesTab} + * + * @author Teemu Lempinen + * + */ +public class SeriesPropertyComposite extends Composite { + + private TrackedText variable, label; + private TrackedSpinner width; + + public SeriesPropertyComposite(Composite parent, ISessionContext context, WidgetSupport support, int style) { + super(parent, style); + + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(this); + + // Variable for the series + Label label = new Label(this, SWT.NONE); + label.setText("Variable:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + variable = new TrackedText(this, support, SWT.BORDER); + variable.setTextFactory(new RVIFactory()); + variable.addModifyListener(new RVIModifier(variable.getWidget(), support)); + variable.setColorProvider(new JFreeChartPropertyColorProvider(this.variable.getResourceManager())); + variable.setInputValidator(new VariableExistsValidator(support, variable)); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this.variable.getWidget()); + + // Range + label = new Label(this, SWT.NONE); + label.setText("Range:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + RangeComposite rangeComposite = new RangeComposite(this, context, support, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(rangeComposite); + + // Label to be displayed in chart for this series + label = new Label(this, SWT.NONE); + label.setText("Label:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + this.label = new TrackedText(this, support, SWT.BORDER); + this.label.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); + this.label.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + this.label.setColorProvider(new JFreeChartPropertyColorProvider(this.label.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(this.label.getWidget()); + + // Color + label = new Label(this, SWT.NONE); + label.setText("Color:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + + Composite colorPicker = new ColorPicker(this, context, support, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(colorPicker); + + // Line width + label = new Label(this, SWT.NONE); + label.setText("Line width:"); + GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).applyTo(label); + + width = new TrackedSpinner(this, support, SWT.BORDER); + width.setSelectionFactory(new WidthSelectionFactory()); + width.addModifyListener(new WidthModifyListener()); + width.setMinimum(1); + width.setMaximum(10); + + } + + + /** + * ModifyListener for the width {@link TrackedSpinner} + * + * @author Teemu Lempinen + * + */ + private class WidthModifyListener implements TextModifyListener, Widget { + + private ISessionContext context; + private Object lastInput = null; + + @Override + public void modifyText(TrackedModifyEvent e) { + if(context == null) + return; + + // Get the text value from spinner and associated resource (input) + Spinner spinner = (Spinner)e.getWidget(); + final String textValue = spinner.getText(); + final Object input = lastInput; + + try { + context.getSession().syncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + // Apply with (textValue) to the series (input) + Resource series = AdaptionUtils.adaptToSingle(input, Resource.class); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + try { + // usually reliable, since the spinner does all the checks + Integer value = Integer.parseInt(textValue); + graph.claimLiteral(series, jfree.Series_lineWidth, value, Bindings.INTEGER); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + + }); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + } + + @Override + public void setInput(ISessionContext context, Object parameter) { + this.context = context; + lastInput = parameter; + } + + } + + /** + * Class for setting the value for width {@link TrackedSpinner} + * @author Teemu Lempinen + * + */ + private class WidthSelectionFactory extends ReadFactoryImpl { + + @Override + public Integer perform(ReadGraph graph, Resource axis) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Integer width = graph.getPossibleRelatedValue(axis, jfree.Series_lineWidth); + if(width == null) + // Default width == 1 + width = 1; + return width; + } + + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/XYLineAxisAndVariablesTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/XYLineAxisAndVariablesTab.java new file mode 100644 index 00000000..d091202c --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/XYLineAxisAndVariablesTab.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.xyline; + +import java.util.List; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.NodeContext; +import org.simantics.browsing.ui.swt.SingleSelectionInputSource; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite; +import org.simantics.browsing.ui.swt.widgets.impl.SelectionListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.utils.ListUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.RemoverUtil; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.request.Read; +import org.simantics.jfreechart.chart.ChartUtils; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.layer0.Layer0; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.SimanticsUI; +import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.datastructures.ArrayMap; + +/** + * PropertyTab displaying properties of axis and variables of a chart + * + * @author Teemu Lempinen + * + */ +public class XYLineAxisAndVariablesTab extends LabelPropertyTabContributor { + + private GraphExplorerComposite explorer; + private ScrolledComposite propertyContainer; + private Button addAxis, addVariable, remove; + private WidgetSupportImpl additionalSupport; + + public XYLineAxisAndVariablesTab() { + additionalSupport = new WidgetSupportImpl(); + } + + @Override + public void createControls(Composite body, IWorkbenchSite site, final ISessionContext context, WidgetSupport support) { + Composite composite = new Composite(body, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(composite); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // (Ontology-based) GraphExplorer displaying range axis and variables mapped to those axis + explorer = new AxisAndVariablesExplorerComposite(ArrayMap.keys( + "displaySelectors", "displayFilter").values(false, false), site, composite, support, SWT.FULL_SELECTION | SWT.BORDER | SWT.SINGLE); + explorer.setBrowseContexts(JFreeChartResource.URIs.ChartAxisAndVariablesBrowseContext); + explorer.setInputSource(new SingleSelectionInputSource( + Resource.class)); + explorer.getExplorer().setAutoExpandLevel(2); // Expand everything in the beginning + explorer.finish(); + + ((Tree)explorer.getExplorerControl()).addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + updateSelection(context); + } + }); + GridDataFactory.fillDefaults().hint(250, SWT.DEFAULT).grab(false, true).applyTo(explorer); + + // Scrolled composite for displaying properties of a selection in explorer + propertyContainer = new ScrolledComposite(composite, SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().span(1, 2).grab(true, true).applyTo(propertyContainer); + GridLayoutFactory.fillDefaults().applyTo(propertyContainer); + propertyContainer.setExpandHorizontal(true); + propertyContainer.setExpandVertical(true); + + // Buttons for adding axis and variables and removing selected items from explorer + Composite buttonComposite = new Composite(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(buttonComposite); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite); + + addAxis = new Button(buttonComposite, support, SWT.NONE); + addAxis.setText("Add axis"); + addAxis.addSelectionListener(new NewAxisListener(context)); + + addVariable = new Button(buttonComposite, additionalSupport, SWT.NONE); + addVariable.setText("Add variable"); + addVariable.addSelectionListener(new NewVariableListener(context)); + + remove = new Button(buttonComposite, additionalSupport, SWT.NONE); + remove.setText("Remove"); + remove.addSelectionListener(new RemoveListener(context)); + } + + /** + * Updates the content of propertyContainer + * @param context + */ + private void updateSelection(ISessionContext context) { + ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class); + IStructuredSelection selection = (IStructuredSelection)selectionProvider.getSelection(); + final Resource resource = AdaptionUtils.adaptToSingle(selection, Resource.class); + if(resource == null) + return; + + // Get the type of the selected node (axis or series) + String typeUri = null; + try { + typeUri = SimanticsUI.getSession().syncRequest(new Read() { + + @Override + public String perform(ReadGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + if(graph.isInstanceOf(resource, jfree.Axis)) + return graph.getURI(jfree.Axis); + else if (graph.isInstanceOf(resource, jfree.Series)) + return graph.getURI(jfree.Series); + return null; + } + + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } + + // Create a PropertyComposite for the selected node + if(typeUri != null) { + + for(Control child : propertyContainer.getChildren()) { + child.dispose(); + } + + if(typeUri.equals(JFreeChartResource.URIs.Axis)) { + AxisPropertyComposite apc = new AxisPropertyComposite(propertyContainer, context, additionalSupport, SWT.NONE); + propertyContainer.setContent(apc); + Point size = apc.computeSize(SWT.DEFAULT, SWT.DEFAULT); + propertyContainer.setMinSize(size); + } else if(typeUri.equals(JFreeChartResource.URIs.Series)) { + SeriesPropertyComposite spc = new SeriesPropertyComposite(propertyContainer, context, additionalSupport, SWT.NONE); + propertyContainer.setContent(spc); + Point size = spc.computeSize(SWT.DEFAULT, SWT.DEFAULT); + propertyContainer.setMinSize(size); + } + } + + additionalSupport.fireInput(context, selection); + } + + /** + * SelectionListener for adding a new range axis to a plot + * @author Teemu Lempinen + * + */ + private class NewAxisListener extends SelectionListenerImpl { + + public NewAxisListener(ISessionContext context) { + super(context); + } + + @Override + public void apply(WriteGraph graph, Resource chart) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.Plot)); + if(plot != null) { + Resource rangeAxis = ChartUtils.createNumberRangeAxis(graph, plot); + if(rangeAxis != null) { + Resource domainAxis = graph.getPossibleObject(plot, jfree.Plot_domainAxis); + ChartUtils.createXYDataset(graph, plot, domainAxis, rangeAxis); + } + } + } + } + + + /** + * SelectionListener for adding a new variable to a plot + * @author Teemu Lempinen + * + */ + private class NewVariableListener extends SelectionListenerImpl { + + public NewVariableListener(ISessionContext context) { + super(context); + } + + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + NodeContext nc = explorer.getExplorer().getRoot(); + if(nc == null) + return; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + if(input == null) { + Resource chart = AdaptionUtils.adaptToSingle(nc, Resource.class); + if(chart == null) return; + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.Plot)); + if(plot == null) return; + Resource rangelist = graph.getPossibleObject(plot, jfree.Plot_rangeAxisList); + if(rangelist == null) return; + List list = ListUtils.toList(graph, rangelist); + if(list == null || list.isEmpty()) return; + input = list.get(0); + } + + Resource dataset; + if(graph.isInstanceOf(input, jfree.Series)) { + // Selected resource is series. Add to same dataset + dataset = graph.getPossibleObject(input, l0.PartOf); + } else { + // Selected resource is axis. Find the dataset it is mapped to or create dataset if not created already + dataset = graph.getPossibleObject(input, jfree.Dataset_mapToRangeAxis_Inverse); + if(dataset == null) { + Resource plot = graph.getPossibleObject(input, l0.PartOf); + if(plot == null) return; + Resource domainAxis = graph.getPossibleObject(plot, jfree.Plot_domainAxis); + if(domainAxis == null) return; + ChartUtils.createXYDataset(graph, plot, domainAxis, input); + } + } + + if(dataset != null) { + // Create series with no rvi + ChartUtils.createSeries(graph, dataset, null); + } + } + } + + + /** + * SelectionListener for remove button + * @author Teemu Lempinen + * + */ + private class RemoveListener extends SelectionListenerImpl { + + public RemoveListener(ISessionContext context) { + super(context); + } + + /** + * Removes selected resource from explorer + */ + @Override + public void apply(WriteGraph graph, Resource input) throws DatabaseException { + if(input == null) + return; + + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + Resource list = null; + if(graph.isInstanceOf(input, jfree.Series)) { + // Remove series from dataset and seriesList + Resource dataset = graph.getPossibleObject(input, l0.PartOf); + if(dataset != null) + list = graph.getPossibleObject(dataset, jfree.Dataset_seriesList); + } else { + // Remove associated dataset + Resource dataset = graph.getPossibleObject(input, jfree.Dataset_mapToRangeAxis_Inverse); + if(dataset != null) { + graph.deny(dataset, jfree.Dataset_mapToDomainAxis); + graph.deny(dataset, jfree.Dataset_mapToRangeAxis); + RemoverUtil.remove(graph, dataset); + } + + // Remove axis from plot and rangeAxisList + Resource plot = graph.getPossibleObject(input, l0.PartOf); + if(plot != null) + list = graph.getPossibleObject(plot, jfree.Plot_rangeAxisList); + } + if(list != null) + ListUtils.removeElement(graph, list, input); + RemoverUtil.remove(graph, input); + } + } +} diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/XYLineGeneralPropertiesTab.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/XYLineGeneralPropertiesTab.java new file mode 100644 index 00000000..6adf26f2 --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/xyline/XYLineGeneralPropertiesTab.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 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.jfreechart.chart.properties.xyline; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IWorkbenchSite; +import org.simantics.browsing.ui.swt.widgets.Button; +import org.simantics.browsing.ui.swt.widgets.StringPropertyFactory; +import org.simantics.browsing.ui.swt.widgets.StringPropertyModifier; +import org.simantics.browsing.ui.swt.widgets.TrackedCombo; +import org.simantics.browsing.ui.swt.widgets.TrackedText; +import org.simantics.browsing.ui.swt.widgets.impl.ComboModifyListenerImpl; +import org.simantics.browsing.ui.swt.widgets.impl.ReadFactoryImpl; +import org.simantics.browsing.ui.swt.widgets.impl.Widget; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.PossibleObjectWithType; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.management.ISessionContext; +import org.simantics.jfreechart.chart.properties.AxisHidePropertyComposite; +import org.simantics.jfreechart.chart.properties.BooleanPropertyFactory; +import org.simantics.jfreechart.chart.properties.BooleanSelectionListener; +import org.simantics.jfreechart.chart.properties.DoubleValidator; +import org.simantics.jfreechart.chart.properties.JFreeChartPropertyColorProvider; +import org.simantics.jfreechart.chart.properties.LabelPropertyTabContributor; +import org.simantics.jfreechart.chart.properties.RVIFactory; +import org.simantics.jfreechart.chart.properties.RVIModifier; +import org.simantics.jfreechart.chart.properties.TitleFactory; +import org.simantics.jfreechart.chart.properties.TitleModifier; +import org.simantics.jfreechart.chart.properties.VariableExistsValidator; +import org.simantics.layer0.Layer0; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.modeling.ui.chart.property.DoublePropertyFactory; +import org.simantics.modeling.ui.chart.property.DoublePropertyModifier; +import org.simantics.sysdyn.JFreeChartResource; +import org.simantics.ui.utils.AdaptionUtils; + +/** + * PropertyTab displaying general properties and x-axis properties of a chart + * + * @author Teemu Lempinen + * + */ +public class XYLineGeneralPropertiesTab extends LabelPropertyTabContributor implements Widget { + + private ScrolledComposite sc; + private Composite composite; + private TrackedText name, title, xlabel, xvariable, xmin, xmax; + private TrackedCombo type; + private Button hgrid, htitle, hlegend; + private WidgetSupportImpl domainAxisSupport = new WidgetSupportImpl(); + + @Override + public void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support) { + support.register(this); + + // Scrolled composite containing all of the properties in this tab + sc = new ScrolledComposite(body, SWT.NONE | SWT.H_SCROLL | SWT.V_SCROLL); + GridDataFactory.fillDefaults().grab(true, true).applyTo(sc); + GridLayoutFactory.fillDefaults().applyTo(sc); + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + composite = new Composite(sc, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(2).margins(3, 3).applyTo(composite); + + // General properties + Group general = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(general); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(general); + general.setText("General"); + + // Name + Label nameLabel = new Label(general, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(nameLabel); + nameLabel.setText("Name:"); + nameLabel.setAlignment(SWT.RIGHT); + + Composite c = new Composite(general, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(c); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(c); + + name = new org.simantics.browsing.ui.swt.widgets.TrackedText(c, support, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(name.getWidget()); + name.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel)); + name.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + name.setColorProvider(new JFreeChartPropertyColorProvider(name.getResourceManager())); + + // Type + Label label = new Label(c, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Type:"); + + type = new TrackedCombo(c, support, SWT.BORDER | SWT.READ_ONLY); + type.addModifyListener(new TypeModifyListener()); + type.setItemFactory(new TypeItemFactory()); + type.setSelectionFactory(new TypeSelectionFactory()); + GridDataFactory.fillDefaults().applyTo(type.getWidget()); + + // Title (Which is different than name) + label = new Label(general, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Title:"); + + title = new org.simantics.browsing.ui.swt.widgets.TrackedText(general, support, SWT.BORDER); + GridDataFactory.fillDefaults().grab(true, false).applyTo(title.getWidget()); + title.setTextFactory(new TitleFactory()); + title.addModifyListener(new TitleModifier()); + title.setColorProvider(new JFreeChartPropertyColorProvider(name.getResourceManager())); + + // Group for hide options + Group hideGroup = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(hideGroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(2).applyTo(hideGroup); + hideGroup.setText("Hide"); + + hgrid = new Button(hideGroup, support, SWT.CHECK); + hgrid.setText("Grid"); + hgrid.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.Plot, JFreeChartResource.URIs.Plot_visibleGrid, true)); + hgrid.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.Plot, JFreeChartResource.URIs.Plot_visibleGrid)); + htitle = new Button(hideGroup, support, SWT.CHECK); + htitle.setText("Title"); + htitle.setSelectionFactory(new BooleanPropertyFactory(JFreeChartResource.URIs.TextTitle, JFreeChartResource.URIs.visible, true)); + htitle.addSelectionListener(new BooleanSelectionListener(context, JFreeChartResource.URIs.TextTitle, JFreeChartResource.URIs.visible)); + hlegend = new Button(hideGroup, support, SWT.CHECK); + hlegend.setText("Legend"); + hlegend.setSelectionFactory(new BooleanPropertyFactory(null, JFreeChartResource.URIs.Chart_visibleLegend, true)); + hlegend.addSelectionListener(new BooleanSelectionListener(context, null, JFreeChartResource.URIs.Chart_visibleLegend)); + + + // X-Axis properties + Group xgroup = new Group(composite, SWT.NONE); + GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(xgroup); + GridLayoutFactory.fillDefaults().margins(3, 3).numColumns(3).applyTo(xgroup); + xgroup.setText("X-axis"); + + // Variable for x-axis (default: empty == time) + Label xVariableLabel = new Label(xgroup, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(xVariableLabel); + xVariableLabel.setText("Variable:"); + + xvariable = new TrackedText(xgroup, domainAxisSupport, SWT.BORDER); + xvariable.setTextFactory(new RVIFactory()); + xvariable.addModifyListener(new RVIModifier(xvariable.getWidget(), domainAxisSupport)); + xvariable.setColorProvider(new JFreeChartPropertyColorProvider(xvariable.getResourceManager())); + xvariable.setInputValidator(new VariableExistsValidator(support, xvariable, true)); + GridDataFactory.fillDefaults().grab(true, false).applyTo(xvariable.getWidget()); + + Composite axisHide = new AxisHidePropertyComposite(xgroup, context, domainAxisSupport, SWT.NONE); + GridDataFactory.fillDefaults().span(1, 3).applyTo(axisHide); + + // Label for x-axis + label = new Label(xgroup, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Label:"); + + xlabel = new TrackedText(xgroup, domainAxisSupport, SWT.BORDER); + xlabel.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasLabel, "")); + xlabel.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasLabel)); + xlabel.setColorProvider(new JFreeChartPropertyColorProvider(xlabel.getResourceManager())); + GridDataFactory.fillDefaults().grab(true, false).applyTo(xlabel.getWidget()); + + // Min and max values for x-axis + label = new Label(xgroup, SWT.NONE); + GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(label); + label.setText("Min:"); + + Composite minmax = new Composite(xgroup, SWT.NONE); + GridDataFactory.fillDefaults().applyTo(minmax); + GridLayoutFactory.fillDefaults().numColumns(3).applyTo(minmax); + xmin = new TrackedText(minmax, domainAxisSupport, SWT.BORDER); + xmin.setColorProvider(new JFreeChartPropertyColorProvider(xmin.getResourceManager())); + xmin.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Axis_min)); + xmin.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Axis_min)); + xmin.setInputValidator(new DoubleValidator(true)); + + label = new Label(minmax, SWT.NONE); + label.setText("Max:"); + xmax = new TrackedText(minmax, domainAxisSupport, SWT.BORDER); + xmax.setColorProvider(new JFreeChartPropertyColorProvider(xmax.getResourceManager())); + xmax.setTextFactory(new DoublePropertyFactory(JFreeChartResource.URIs.Axis_max)); + xmax.addModifyListener(new DoublePropertyModifier(context, JFreeChartResource.URIs.Axis_max)); + xmax.setInputValidator(new DoubleValidator(true)); + + // Set the same width to both label rows + composite.layout(); + GridDataFactory.fillDefaults().hint(xVariableLabel.getBounds().width, SWT.DEFAULT).align(SWT.END, SWT.CENTER).applyTo(nameLabel); + + sc.setContent(composite); + Point size = composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); + sc.setMinSize(size); + } + + @Override + public void setInput(final ISessionContext context, Object input) { + final Resource chart = AdaptionUtils.adaptToSingle(input, Resource.class); + if(chart == null) + return; + + context.getSession().asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.Plot)); + if(plot == null) return; + Resource domainAxis = graph.getPossibleObject(plot, jfree.Plot_domainAxis); + if(domainAxis == null) return; + domainAxisSupport.fireInput(context, new StructuredSelection(domainAxis)); + } + }); + } + + /** + * + * @author Teemu Lempinen + * + */ + private class TypeSelectionFactory extends ReadFactoryImpl { + @Override + public String perform(ReadGraph graph, Resource chart) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.XYPlot)); + if(plot != null) { + Collection datasets = graph.syncRequest(new ObjectsWithType(plot, l0.ConsistsOf, jfree.XYDataset)); + if(!datasets.isEmpty()) { + Resource dataset = datasets.iterator().next(); + if(dataset != null) { + Resource renderer = graph.syncRequest(new PossibleObjectWithType(dataset, jfree.Dataset_renderer, jfree.Renderer)); + if(renderer != null && graph.isInstanceOf(renderer, jfree.XYAreaRenderer)) + return "Area"; + } + } + } + return "Line"; + } + } + + /** + * RangeItemFactory finds all inexes of a given enumeration + * and adds "Sum" and "All" to the returned indexes + * @author Teemu Lempinen + * + */ + private class TypeItemFactory extends ReadFactoryImpl> { + @Override + public Map perform(ReadGraph graph, Resource series) throws DatabaseException { + LinkedHashMap result = new LinkedHashMap(); + result.put("Line", "Line"); + result.put("Area", "Area"); +// result.put("Stacked Area", "Stacked Area"); + return result; + } + } + + /** + * TypeModifyListener for modifying the type of a bar chart + * @author Teemu Lempinen + * + */ + private class TypeModifyListener extends ComboModifyListenerImpl { + @Override + public void applyText(WriteGraph graph, Resource chart, String text) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + Layer0 l0 = Layer0.getInstance(graph); + + Resource plot = graph.syncRequest(new PossibleObjectWithType(chart, l0.ConsistsOf, jfree.XYPlot)); + if(plot == null) + return; + + Collection datasets = graph.syncRequest(new ObjectsWithType(plot, l0.ConsistsOf, jfree.XYDataset)); + if(datasets == null || datasets.isEmpty()) + return; + + for(Resource dataset : datasets) { + graph.deny(dataset, jfree.Dataset_renderer); + + Resource renderer; + if(text.equals("Area")) + renderer = GraphUtils.create2(graph, jfree.XYAreaRenderer); + else + renderer = GraphUtils.create2(graph, jfree.XYLineRenderer); + + graph.claim(dataset, jfree.Dataset_renderer, renderer); + } + } + } + +} \ No newline at end of file diff --git a/org.simantics.jfreechart/src/org/simantics/jfreechart/internal/Activator.java b/org.simantics.jfreechart/src/org/simantics/jfreechart/internal/Activator.java new file mode 100644 index 00000000..97597b7e --- /dev/null +++ b/org.simantics.jfreechart/src/org/simantics/jfreechart/internal/Activator.java @@ -0,0 +1,50 @@ +package org.simantics.jfreechart.internal; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.simantics.jfreechart"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +}