diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f36e81 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/dist/ +/nbproject/private/ +/build/ \ No newline at end of file diff --git a/build.xml b/build.xml index b8fe200..e815013 100644 --- a/build.xml +++ b/build.xml @@ -1,311 +1,99 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + Builds, tests, and runs the project Prefuse. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - \ No newline at end of file diff --git a/demos/prefuse/demos/GraphView.java b/demos/prefuse/demos/GraphView.java index ff77553..dade0a0 100644 --- a/demos/prefuse/demos/GraphView.java +++ b/demos/prefuse/demos/GraphView.java @@ -170,9 +170,9 @@ public void tupleSetChanged(TupleSet ts, Tuple[] add, Tuple[] rem) display.addControlListener(new NeighborHighlightControl()); // overview display -// Display overview = new Display(vis); -// overview.setSize(290,290); -// overview.addItemBoundsListener(new FitOverviewListener()); + Display overview = new Display(m_vis); + overview.setSize(290,290); + overview.addItemBoundsListener(new FitOverviewListener()); display.setForeground(Color.GRAY); display.setBackground(Color.WHITE); @@ -184,10 +184,10 @@ public void tupleSetChanged(TupleSet ts, Tuple[] add, Tuple[] rem) ForceSimulator fsim = ((ForceDirectedLayout)animate.get(0)).getForceSimulator(); JForcePanel fpanel = new JForcePanel(fsim); -// JPanel opanel = new JPanel(); -// opanel.setBorder(BorderFactory.createTitledBorder("Overview")); -// opanel.setBackground(Color.WHITE); -// opanel.add(overview); + JPanel opanel = new JPanel(); + opanel.setBorder(BorderFactory.createTitledBorder("Overview")); + opanel.setBackground(Color.WHITE); + opanel.add(overview); final JValueSlider slider = new JValueSlider("Distance", 0, hops, hops); slider.addChangeListener(new ChangeListener() { @@ -205,7 +205,7 @@ public void stateChanged(ChangeEvent e) { cf.setBorder(BorderFactory.createTitledBorder("Connectivity Filter")); fpanel.add(cf); - //fpanel.add(opanel); + fpanel.add(opanel); fpanel.add(Box.createVerticalGlue()); diff --git a/lib/junit_4/junit-4.10-javadoc.jar b/lib/junit_4/junit-4.10-javadoc.jar new file mode 100644 index 0000000..d9184c4 Binary files /dev/null and b/lib/junit_4/junit-4.10-javadoc.jar differ diff --git a/lib/junit_4/junit-4.10-sources.jar b/lib/junit_4/junit-4.10-sources.jar new file mode 100644 index 0000000..75cdd86 Binary files /dev/null and b/lib/junit_4/junit-4.10-sources.jar differ diff --git a/lib/junit_4/junit-4.10.jar b/lib/junit_4/junit-4.10.jar new file mode 100644 index 0000000..954851e Binary files /dev/null and b/lib/junit_4/junit-4.10.jar differ diff --git a/lib/nblibraries.properties b/lib/nblibraries.properties new file mode 100644 index 0000000..6d17b00 --- /dev/null +++ b/lib/nblibraries.properties @@ -0,0 +1,8 @@ +libs.junit_4.classpath=\ + ${base}/junit_4/junit-4.10.jar +libs.junit_4.displayName=JUnit 4.10 +libs.junit_4.javadoc=\ + ${base}/junit_4/junit-4.10-javadoc.jar +libs.junit_4.prop-maven-dependencies=junit:junit:4.10:jar +libs.junit_4.src=\ + ${base}/junit_4/junit-4.10-sources.jar diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..6d736f3 --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,1441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.demos.dir + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..3bcdcf6 --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=c9bc544e +build.xml.script.CRC32=8f7dbb3b +build.xml.stylesheet.CRC32=28e38971@1.56.1.46 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=07a3f84f +nbproject/build-impl.xml.script.CRC32=1f61b2c3 +nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46 diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..9d6d077 --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,77 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=Prefuse +application.vendor=Sascha +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/Prefuse.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +file.reference.lucene-1.4.3.jar=lib\\lucene-1.4.3.jar +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.lucene-1.4.3.jar}:\ + ${libs.junit_4.classpath} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.7 +javac.target=1.7 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class= +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.demos.dir=demos +src.dir=src +test.src.dir=test diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..882072c --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,19 @@ + + + org.netbeans.modules.java.j2seproject + + + Prefuse + + + + + + + + + + .\lib\nblibraries.properties + + + diff --git a/build.bat b/old build tools/build.bat similarity index 100% rename from build.bat rename to old build tools/build.bat diff --git a/build.sh b/old build tools/build.sh similarity index 100% rename from build.sh rename to old build tools/build.sh diff --git a/old build tools/build.xml b/old build tools/build.xml new file mode 100644 index 0000000..b8fe200 --- /dev/null +++ b/old build tools/build.xml @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/prefuse/controls/FocusControl.java b/src/prefuse/controls/FocusControl.java index 1794c91..a2f992e 100644 --- a/src/prefuse/controls/FocusControl.java +++ b/src/prefuse/controls/FocusControl.java @@ -12,19 +12,18 @@ import prefuse.util.ui.UILib; import prefuse.visual.VisualItem; - /** *

Updates the contents of a TupleSet of focus items in response to mouse - * actions. For example, clicking a node or double-clicking a node could - * update its focus status. This Control supports monitoring a specified - * number of clicks to executing a focus change. By default a click pattern - * will cause a VisualItem to become the sole member of the focus group. - * Hold down the control key while clicking to add an item to a group - * without removing the current members.

- * - *

Updating a focus group does not necessarily cause - * the display to change. For this functionality, either register an action - * with this control, or register a TupleSetListener with the focus group. + * actions. For example, clicking a node or double-clicking a node could update + * its focus status. This Control supports monitoring a specified number of + * clicks to executing a focus change. By default a click pattern will cause a + * VisualItem to become the sole member of the focus group. Hold down the + * control key while clicking to add an item to a group without removing the + * current members.

+ * + *

Updating a focus group does not necessarily cause the display to change. + * For this functionality, either register an action with this control, or + * register a TupleSetListener with the focus group. *

* * @author jeffrey heer @@ -37,173 +36,207 @@ public class FocusControl extends ControlAdapter { protected int ccount; protected int button = Control.LEFT_MOUSE_BUTTON; protected Predicate filter = null; - + private boolean focusOnEnter = false; + private boolean wasInFocusGroup = false; + private boolean itemFixedByClick = false; + /** - * Creates a new FocusControl that changes the focus to another item - * when that item is clicked once. + * Creates a new FocusControl that changes the focus to another item when + * that item is clicked once. */ public FocusControl() { this(1); } - + /** - * Creates a new FocusControl that changes the focus to another item - * when that item is clicked once. + * Creates a new FocusControl that changes the focus to another item when + * that item is clicked once. + * * @param focusGroup the name of the focus group to use */ public FocusControl(String focusGroup) { this(1); group = focusGroup; } - + /** - * Creates a new FocusControl that changes the focus when an item is - * clicked the specified number of times. A click value of zero indicates - * that the focus should be changed in response to mouse-over events. + * Creates a new FocusControl that changes the focus when an item is clicked + * the specified number of times. A click value of zero indicates that the + * focus should be changed in response to mouse-over events. + * * @param clicks the number of clicks needed to switch the focus. */ public FocusControl(int clicks) { ccount = clicks; } - + /** - * Creates a new FocusControl that changes the focus when an item is - * clicked the specified number of times. A click value of zero indicates - * that the focus should be changed in response to mouse-over events. - * @param focusGroup the name of the focus group to use + * Creates a new FocusControl that changes the focus when an item is clicked + * the specified number of times. A click value of zero indicates that the + * focus should be changed in response to mouse-over events. + * + * @param focusGroup the name of the focus group to use * @param clicks the number of clicks needed to switch the focus. */ public FocusControl(String focusGroup, int clicks) { ccount = clicks; group = focusGroup; } - + /** - * Creates a new FocusControl that changes the focus when an item is - * clicked the specified number of times. A click value of zero indicates - * that the focus should be changed in response to mouse-over events. + * Creates a new FocusControl that changes the focus when an item is clicked + * the specified number of times. A click value of zero indicates that the + * focus should be changed in response to mouse-over events. + * * @param clicks the number of clicks needed to switch the focus. - * @param act an action run to upon focus change + * @param act an action run to upon focus change */ public FocusControl(int clicks, String act) { ccount = clicks; activity = act; } - + /** - * Creates a new FocusControl that changes the focus when an item is - * clicked the specified number of times. A click value of zero indicates - * that the focus should be changed in response to mouse-over events. + * Creates a new FocusControl that changes the focus when an item is clicked + * the specified number of times. A click value of zero indicates that the + * focus should be changed in response to mouse-over events. + * * @param focusGroup the name of the focus group to use * @param clicks the number of clicks needed to switch the focus. - * @param act an action run to upon focus change + * @param act an action run to upon focus change */ public FocusControl(String focusGroup, int clicks, String act) { ccount = clicks; activity = act; this.group = focusGroup; } - + // ------------------------------------------------------------------------ - /** * Set a filter for processing items by this focus control. Only items for - * which the predicate returns true (or doesn't throw an exception) will - * be considered by this control. A null value indicates that no filtering + * which the predicate returns true (or doesn't throw an exception) will be + * considered by this control. A null value indicates that no filtering * should be applied. That is, all items will be considered. + * * @param p the filtering predicate to apply */ public void setFilter(Predicate p) { this.filter = p; } - + /** - * Get the filter for processing items by this focus control. Only items - * for which the predicate returns true (or doesn't throw an exception) - * are considered by this control. A null value indicates that no - * filtering is applied. + * Get the filter for processing items by this focus control. Only items for + * which the predicate returns true (or doesn't throw an exception) are + * considered by this control. A null value indicates that no filtering is + * applied. + * * @return the filtering predicate */ public Predicate getFilter() { return filter; } - + /** * Perform a filtering check on the input item. + * * @param item the item to check against the filter * @return true if the item should be considered, false otherwise */ protected boolean filterCheck(VisualItem item) { - if ( filter == null ) + if (filter == null) { return true; - + } + try { return filter.getBoolean(item); - } catch ( Exception e ) { + } catch (Exception e) { Logger.getLogger(getClass().getName()).warning( - e.getMessage() + "\n" + StringLib.getStackTrace(e)); + e.getMessage() + "\n" + StringLib.getStackTrace(e)); return false; } } - + // ------------------------------------------------------------------------ - /** - * @see prefuse.controls.Control#itemEntered(prefuse.visual.VisualItem, java.awt.event.MouseEvent) + * @see prefuse.controls.Control#itemEntered(prefuse.visual.VisualItem, + * java.awt.event.MouseEvent) */ public void itemEntered(VisualItem item, MouseEvent e) { - if ( !filterCheck(item) ) return; - Display d = (Display)e.getSource(); + if (!filterCheck(item)) { + return; + } + Display d = (Display) e.getSource(); d.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - if ( ccount == 0 ) { + if (ccount == 0 || focusOnEnter) { Visualization vis = item.getVisualization(); TupleSet ts = vis.getFocusGroup(group); - ts.setTuple(item); - curFocus = item; + if (ccount == 0) { + ts.setTuple(item); + } else { + wasInFocusGroup = ts.containsTuple(item); + if (!wasInFocusGroup) { + ts.addTuple(item); + } + } + if (!focusOnEnter) { + curFocus = item; + } runActivity(vis); } } - + /** - * @see prefuse.controls.Control#itemExited(prefuse.visual.VisualItem, java.awt.event.MouseEvent) + * @see prefuse.controls.Control#itemExited(prefuse.visual.VisualItem, + * java.awt.event.MouseEvent) */ public void itemExited(VisualItem item, MouseEvent e) { - if ( !filterCheck(item) ) return; - Display d = (Display)e.getSource(); + if (!filterCheck(item)) { + return; + } + Display d = (Display) e.getSource(); d.setCursor(Cursor.getDefaultCursor()); - if ( ccount == 0 ) { + if (ccount == 0 || focusOnEnter) { curFocus = null; Visualization vis = item.getVisualization(); TupleSet ts = vis.getFocusGroup(group); - ts.removeTuple(item); + if (!wasInFocusGroup && !itemFixedByClick) { + ts.removeTuple(item); + } runActivity(vis); } + wasInFocusGroup = false; + itemFixedByClick = false; } - + /** - * @see prefuse.controls.Control#itemClicked(prefuse.visual.VisualItem, java.awt.event.MouseEvent) + * @see prefuse.controls.Control#itemClicked(prefuse.visual.VisualItem, + * java.awt.event.MouseEvent) */ public void itemClicked(VisualItem item, MouseEvent e) { - if ( !filterCheck(item) ) return; - if ( UILib.isButtonPressed(e, button) && - e.getClickCount() == ccount ) - { - if ( item != curFocus ) { + if (!filterCheck(item)) { + return; + } + itemFixedByClick = false; + if (UILib.isButtonPressed(e, button) + && e.getClickCount() == ccount) { + if (item != curFocus) { Visualization vis = item.getVisualization(); TupleSet ts = vis.getFocusGroup(group); - + boolean ctrl = e.isControlDown(); - if ( !ctrl ) { + if (!ctrl) { curFocus = item; ts.setTuple(item); - } else if ( ts.containsTuple(item) ) { + itemFixedByClick = true; + } else if (ts.containsTuple(item) && wasInFocusGroup) { ts.removeTuple(item); } else { ts.addTuple(item); + itemFixedByClick = true; } runActivity(vis); - - } else if ( e.isControlDown() ) { + + } else if (e.isControlDown()) { Visualization vis = item.getVisualization(); TupleSet ts = vis.getFocusGroup(group); ts.removeTuple(item); @@ -212,11 +245,24 @@ public void itemClicked(VisualItem item, MouseEvent e) { } } } - + private void runActivity(Visualization vis) { - if ( activity != null ) { + if (activity != null) { vis.run(activity); } } - + + /** + * @return the focusOnEnter + */ + public boolean isFocusOnEnter() { + return focusOnEnter; + } + + /** + * @param focusOnEnter the focusOnEnter to set + */ + public void setFocusOnEnter(boolean focusOnEnter) { + this.focusOnEnter = focusOnEnter; + } } // end of class FocusControl diff --git a/src/prefuse/data/CascadedTable.java b/src/prefuse/data/CascadedTable.java index 6fbd315..d542c60 100644 --- a/src/prefuse/data/CascadedTable.java +++ b/src/prefuse/data/CascadedTable.java @@ -336,6 +336,10 @@ public int getChildRow(int prow) { return ((CascadedRowManager)m_rows).getChildRow(prow); } + public void dispose(){ + m_parent.removeTableListener(m_listener); + } + // ------------------------------------------------------------------------ // Row Operations diff --git a/src/prefuse/data/column/AbstractColumn.java b/src/prefuse/data/column/AbstractColumn.java index ac29a9b..d233321 100644 --- a/src/prefuse/data/column/AbstractColumn.java +++ b/src/prefuse/data/column/AbstractColumn.java @@ -272,6 +272,7 @@ public boolean canGet(Class type) { * @param type the Class of the data type to check * @return true if the type is supported by this column, false otherwise */ + @Override public boolean canSet(Class type) { if ( type == null ) return false; diff --git a/src/prefuse/data/column/BooleanColumn.java b/src/prefuse/data/column/BooleanColumn.java index 103b371..f0851f1 100644 --- a/src/prefuse/data/column/BooleanColumn.java +++ b/src/prefuse/data/column/BooleanColumn.java @@ -4,27 +4,29 @@ import prefuse.data.DataReadOnlyException; import prefuse.data.DataTypeException; +import prefuse.util.TypeLib; /** * Column implementation storing boolean values. Uses a BitSet representation * for space efficient storage. - * + * * @author jeffrey heer */ public class BooleanColumn extends AbstractColumn { - private BitSet m_bits; - private int m_size; - + private BitSet m_bits; + private int m_size; + /** * Create an empty BooleanColumn. */ public BooleanColumn() { this(0, 10, false); } - + /** - * Create a new BooleanColumn. + * Create a new BooleanColumn. + * * @param nrows the initial size of the column */ public BooleanColumn(int nrows) { @@ -32,46 +34,45 @@ public BooleanColumn(int nrows) { } /** - * Create a new BooleanColumn. + * Create a new BooleanColumn. + * * @param nrows the initial size of the column * @param capacity the initial capacity of the column * @param defaultValue the default value for the column */ public BooleanColumn(int nrows, int capacity, boolean defaultValue) { super(boolean.class, new Boolean(defaultValue)); - if ( capacity < nrows ) { + if (capacity < nrows) { throw new IllegalArgumentException( - "Capacity value can not be less than the row count."); + "Capacity value can not be less than the row count."); } m_bits = new BitSet(capacity); m_bits.set(0, capacity, defaultValue); m_size = nrows; } - + // ------------------------------------------------------------------------ // Column Metadata - /** * @see prefuse.data.column.Column#getRowCount() */ public int getRowCount() { return m_size; } - + /** * @see prefuse.data.column.Column#setMaximumRow(int) */ public void setMaximumRow(int nrows) { - if ( nrows > m_size ) { - m_bits.set(m_size, nrows, - ((Boolean)m_defaultValue).booleanValue()); + if (nrows > m_size) { + m_bits.set(m_size, nrows, + ((Boolean) m_defaultValue).booleanValue()); } m_size = nrows; } // ------------------------------------------------------------------------ // Data Access Methods - /** * @see prefuse.data.column.Column#get(int) */ @@ -83,13 +84,13 @@ public Object get(int row) { * @see prefuse.data.column.Column#set(java.lang.Object, int) */ public void set(Object val, int row) throws DataTypeException { - if ( m_readOnly ) { + if (m_readOnly) { throw new DataReadOnlyException(); - } else if ( val != null ) { - if ( val instanceof Boolean ) { - setBoolean(((Boolean)val).booleanValue(), row); - } else if ( val instanceof String ) { - setString((String)val, row); + } else if (val != null) { + if (val instanceof Boolean) { + setBoolean(((Boolean) val).booleanValue(), row); + } else if (val instanceof String) { + setString((String) val, row); } else { throw new DataTypeException(val.getClass()); } @@ -100,13 +101,12 @@ public void set(Object val, int row) throws DataTypeException { // ------------------------------------------------------------------------ // Data Type Convenience Methods - /** * @see prefuse.data.column.AbstractColumn#getBoolean(int) */ public boolean getBoolean(int row) throws DataTypeException { - if ( row < 0 || row > m_size ) { - throw new IllegalArgumentException("Row index out of bounds: "+row); + if (row < 0 || row > m_size) { + throw new IllegalArgumentException("Row index out of bounds: " + row); } return m_bits.get(row); } @@ -115,24 +115,50 @@ public boolean getBoolean(int row) throws DataTypeException { * @see prefuse.data.column.AbstractColumn#setBoolean(boolean, int) */ public void setBoolean(boolean val, int row) throws DataTypeException { - if ( m_readOnly ) { + if (m_readOnly) { throw new DataReadOnlyException(); - } else if ( row < 0 || row >= m_size ) { - throw new IllegalArgumentException("Row index out of bounds: "+row); + } else if (row < 0 || row >= m_size) { + throw new IllegalArgumentException("Row index out of bounds: " + row); } // get the previous value boolean prev = m_bits.get(row); - + // exit early if no change - if ( prev == val ) return; - + if (prev == val) { + return; + } + // set the new value m_bits.set(row, val); - + + // fire a change event + fireColumnEvent(row, prev); + } + + @Override + public void setInt(int val, int row) throws DataTypeException { + if (m_readOnly) { + throw new DataReadOnlyException(); + } else if (row < 0 || row >= m_size) { + throw new IllegalArgumentException("Row index out of bounds: " + row); + } + // get the previous value + boolean prev = m_bits.get(row); + + boolean boolVal = val >= 1 ? true : false; + + // exit early if no change + if (prev == boolVal) { + return; + } + + // set the new value + m_bits.set(row, boolVal); + // fire a change event fireColumnEvent(row, prev); } - + // /** // * @see prefuse.data.column.AbstractColumn#getString(int) // */ @@ -155,5 +181,13 @@ public void setBoolean(boolean val, int row) throws DataTypeException { // } // setBoolean(b, row); // } - + @Override + public boolean canSet(Class type) { + Class wrapperType = TypeLib.getWrapperType(type); + if (wrapperType != null && wrapperType == Integer.class) { + return true; + } else { + return super.canSet(type); + } + } } // end of class BooleanColumn diff --git a/src/prefuse/data/io/CSVTableReader.java b/src/prefuse/data/io/CSVTableReader.java index 179e4af..499e9d2 100644 --- a/src/prefuse/data/io/CSVTableReader.java +++ b/src/prefuse/data/io/CSVTableReader.java @@ -9,116 +9,110 @@ import prefuse.data.parser.ParserFactory; /** - * TableReader for Comma Separated Value (CSV) files. CSV files list - * each row of a table on a line, separating each data column by a line. - * Typically the first line of the file is a header row indicating the - * names of each data column. - * + * TableReader for Comma Separated Value (CSV) files. CSV files list each row of + * a table on a line, separating each data column by a line. Typically the first + * line of the file is a header row indicating the names of each data column. + * * For a more in-depth description of the CSV format, please see this * - * CSV reference web page. - * + * CSV reference web page. + * * @author jeffrey heer */ public class CSVTableReader extends AbstractTextTableReader { + private char delimiter; + /** * Create a new CSVTableReader. */ public CSVTableReader() { super(); + delimiter = ','; + } + + public CSVTableReader(char delimiter) { + this.delimiter = delimiter; } - + /** * Create a new CSVTableReader. + * * @param parserFactory the ParserFactory to use for parsing text strings * into table values. */ public CSVTableReader(ParserFactory parserFactory) { super(parserFactory); + delimiter = ','; } - + + public CSVTableReader(char delimiter, ParserFactory parserFactory) { + super(parserFactory); + this.delimiter = delimiter; + } + /** - * @see prefuse.data.io.AbstractTextTableReader#read(java.io.InputStream, prefuse.data.io.TableReadListener) + * @see prefuse.data.io.AbstractTextTableReader#read(java.io.InputStream, + * prefuse.data.io.TableReadListener) */ public void read(InputStream is, TableReadListener trl) - throws IOException, DataParseException - { + throws IOException, DataParseException { String line; StringBuffer sbuf = new StringBuffer(); - + boolean inRecord = false; - int inQuote = 0; - int lineno = 0; - int col = 0; - + int inQuote = 0; + int lineno = 0; + int col = 0; + BufferedReader br = new BufferedReader(new InputStreamReader(is)); - while ( (line=br.readLine()) != null ) { + while ((line = br.readLine()) != null) { // increment the line number ++lineno; - + // extract the character array for quicker processing char[] c = line.toCharArray(); - int last = c.length-1; - + int last = c.length - 1; + // iterate through current line - for ( int i=0; i<=last; ++i ) { - if ( !inRecord ) { + for (int i = 0; i <= last; ++i) { + if (!inRecord) { // not currently processing a record - if ( Character.isWhitespace(c[i]) ) - { + if (Character.isWhitespace(c[i])) { continue; - } - else if ( c[i] == '\"' ) - { + } else if (c[i] == '\"') { inRecord = true; - inQuote = 1; - } - else if ( c[i] == ',' ) - { + inQuote = 1; + } else if (c[i] == delimiter) { String s = sbuf.toString().trim(); trl.readValue(lineno, ++col, s); sbuf.delete(0, sbuf.length()); - } - else - { + } else { inRecord = true; sbuf.append(c[i]); } } else { // in the midst of a record - if ( inQuote == 1 ) { - if ( c[i]=='\"' && (i==last || c[i+1] != '\"') ) - { + if (inQuote == 1) { + if (c[i] == '\"' && (i == last || c[i + 1] != '\"')) { // end of quotation inQuote = 2; - } - else if ( c[i]=='\"' ) - { + } else if (c[i] == '\"') { // double quote so skip one ahead sbuf.append(c[i++]); - } - else - { + } else { sbuf.append(c[i]); } } else { - if ( Character.isWhitespace(c[i]) ) - { + if (Character.isWhitespace(c[i])) { sbuf.append(c[i]); - } - else if ( c[i] != ',' && inQuote == 2 ) - { + } else if (c[i] != delimiter && inQuote == 2) { throw new IllegalStateException( - "Invalid data format. " + - "Error at line " + lineno + ", col " + i); - } - else if ( c[i] != ',' ) - { + "Invalid data format. " + + "Error at line " + lineno + ", col " + i); + } else if (c[i] != delimiter) { sbuf.append(c[i]); - } - else - { + } else { String s = sbuf.toString().trim(); trl.readValue(lineno, ++col, s); sbuf.delete(0, sbuf.length()); @@ -128,17 +122,16 @@ else if ( c[i] != ',' ) } } } - if ( inQuote != 1 ) { + if (inQuote != 1) { String s = sbuf.toString().trim(); trl.readValue(lineno, ++col, s); sbuf.delete(0, sbuf.length()); inQuote = 0; inRecord = false; } - if ( !inRecord && col > 0 ) { + if (!inRecord && col > 0) { col = 0; } } } - } // end of class CSVTableReader diff --git a/src/prefuse/data/io/CSVTableWriter.java b/src/prefuse/data/io/CSVTableWriter.java index 26a7b95..f25b11b 100644 --- a/src/prefuse/data/io/CSVTableWriter.java +++ b/src/prefuse/data/io/CSVTableWriter.java @@ -17,12 +17,13 @@ public class CSVTableWriter extends AbstractTableWriter { private boolean m_printHeader; + private char delimiter = ','; /** * Create a new CSVTableWriter that writes comma separated values files. */ public CSVTableWriter() { - this(true); + this(true, ','); } /** @@ -30,7 +31,12 @@ public CSVTableWriter() { * @param printHeader indicates if a header row should be printed */ public CSVTableWriter(boolean printHeader) { + this(printHeader, ','); + } + + public CSVTableWriter(boolean printHeader, char delimiter){ m_printHeader = printHeader; + this.delimiter = delimiter; } // ------------------------------------------------------------------------ @@ -64,7 +70,7 @@ public void writeTable(Table table, OutputStream os) throws DataIOException { // write out header row if ( m_printHeader ) { for ( int i=0; i0 ) out.print(','); + if ( i>0 ) out.print(delimiter); out.print(makeCSVSafe(table.getColumnName(i))); } out.println(); @@ -74,7 +80,7 @@ public void writeTable(Table table, OutputStream os) throws DataIOException { for ( IntIterator rows = table.rows(); rows.hasNext(); ) { int row = rows.nextInt(); for ( int i=0; i0 ) out.print(','); + if ( i>0 ) out.print(delimiter); String str = table.getString(row, table.getColumnName(i)); out.print(makeCSVSafe(str)); } diff --git a/src/prefuse/data/io/sql/DatabaseDataSource.java b/src/prefuse/data/io/sql/DatabaseDataSource.java index a8d22f6..d01c482 100644 --- a/src/prefuse/data/io/sql/DatabaseDataSource.java +++ b/src/prefuse/data/io/sql/DatabaseDataSource.java @@ -2,15 +2,12 @@ import java.sql.Connection; import java.sql.ResultSet; -import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Logger; -import prefuse.data.Schema; import prefuse.data.Table; import prefuse.data.io.DataIOException; -import prefuse.data.util.Index; /** * Sends queries to a relational database and processes the results, storing @@ -28,7 +25,7 @@ public class DatabaseDataSource { protected Connection m_conn; protected Statement m_stmt; - protected SQLDataHandler m_handler; + DatabaseResultSetProcessor m_resultSetProcessor; // ------------------------------------------------------------------------ @@ -41,7 +38,7 @@ public class DatabaseDataSource { */ DatabaseDataSource(Connection conn, SQLDataHandler handler) { m_conn = conn; - m_handler = handler; + m_resultSetProcessor = new DatabaseResultSetProcessor(handler); } // ------------------------------------------------------------------------ @@ -127,7 +124,7 @@ public synchronized Table getData(Table t, String query, } catch ( SQLException e ) { throw new DataIOException(e); } - return process(t, rs, keyField, lock); + return m_resultSetProcessor.process(t, rs, keyField, lock, false); } // ------------------------------------------------------------------------ @@ -235,138 +232,4 @@ private ResultSet executeQuery(String query) throws SQLException { return rset; } - - // ------------------------------------------------------------------------ - - /** - * Process the results of a SQL query, putting retrieved data into a - * Table instance. If a null table is provided, a new table with the - * appropriate schema will be created. - * @param t the Table to store results in - * @param rset the SQL query result set - * @return a Table containing the query results - */ - protected Table process(Table t, ResultSet rset, String key, Object lock) - throws DataIOException - { - // clock in - int count = 0; - long timein = System.currentTimeMillis(); - - try { - ResultSetMetaData metadata = rset.getMetaData(); - int ncols = metadata.getColumnCount(); - - // create a new table if necessary - if ( t == null ) { - t = getSchema(metadata, m_handler).instantiate(); - if ( key != null ) { - try { - t.index(key); - s_logger.info("Indexed field: "+key); - } catch ( Exception e ) { - s_logger.warning("Error indexing field: "+key); - } - } - } - - // set the lock, lock on the table itself if nothing else provided - lock = (lock==null ? t : lock); - - // process the returned rows - while ( rset.next() ) - { - synchronized ( lock ) { - // determine the table row index to use - int row = getExistingRow(t, rset, key); - if ( row < 0 ) { - row = t.addRow(); - } - - //process each value in the current row - for ( int i=1; i<=ncols; ++i ) { - m_handler.process(t, row, rset, i); - } - } - - // increment row count - ++count; - } - } catch ( SQLException e ) { - throw new DataIOException(e); - } - - // clock out - long time = System.currentTimeMillis()-timein; - s_logger.info("Internal query processing completed: "+count+" rows, " - + (time/1000) + "." + (time%1000) + " seconds."); - - return t; - } - - /** - * See if a retrieved database row is already represented in the given - * Table. - * @param t the prefuse Table to check for an existing row - * @param rset the ResultSet, set to a particular row, which may or - * may not have a matching row in the prefuse Table - * @param keyField the key field to look up to check for an existing row - * @return the index of the existing row, or -1 if no match is found - * @throws SQLException - */ - protected int getExistingRow(Table t, ResultSet rset, String keyField) - throws SQLException - { - // check if we have a keyField, bail if not - if ( keyField == null ) - return -1; - - // retrieve the column data type, bail if column is not found - Class type = t.getColumnType(keyField); - if ( type == null ) - return -1; - - // get the index and perform the lookup - Index index = t.index(keyField); - if ( type == int.class ) { - return index.get(rset.getInt(keyField)); - } else if ( type == long.class ) { - return index.get(rset.getLong(keyField)); - } else if ( type == float.class ) { - return index.get(rset.getFloat(keyField)); - } else if ( type == double.class ) { - return index.get(rset.getDouble(keyField)); - } else if ( !type.isPrimitive() ) { - return index.get(rset.getObject(keyField)); - } else { - return -1; - } - } - - /** - * Given the metadata for a SQL result set and a data value handler for that - * result set, returns a corresponding schema for a prefuse table. - * @param metadata the SQL result set metadata - * @param handler the data value handler - * @return the schema determined by the metadata and handler - * @throws SQLException if an error occurs accessing the metadata - */ - public Schema getSchema(ResultSetMetaData metadata, SQLDataHandler handler) - throws SQLException - { - int ncols = metadata.getColumnCount(); - Schema schema = new Schema(ncols); - - // determine the table schema - for ( int i=1; i<=ncols; ++i ) { - String name = metadata.getColumnName(i); - int sqlType = metadata.getColumnType(i); - Class type = handler.getDataType(name, sqlType); - if ( type != null ) - schema.addColumn(name, type); - } - - return schema; - } - } // end of class DatabaseDataSource diff --git a/src/prefuse/data/io/sql/DatabaseResultSetProcessor.java b/src/prefuse/data/io/sql/DatabaseResultSetProcessor.java new file mode 100644 index 0000000..4d82dfd --- /dev/null +++ b/src/prefuse/data/io/sql/DatabaseResultSetProcessor.java @@ -0,0 +1,201 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package prefuse.data.io.sql; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.logging.Logger; +import prefuse.data.Schema; +import prefuse.data.Table; +import prefuse.data.Tuple; +import prefuse.data.io.DataIOException; +import prefuse.data.util.Index; +import prefuse.data.util.TableIterator; + +/** + * Is responible fpr processing a ResultSet and transfering it into a + * Prefuse-Table. + * + * Is just a refactoring of the DatabaseDataSource. + * + * @author Sascha Thielemann + */ +public class DatabaseResultSetProcessor { + + private static final Logger s_logger = Logger.getLogger(DatabaseResultSetProcessor.class.getName()); + protected SQLDataHandler m_handler; + + /** + * Creates a new DatabaseResultSetProcessor for reading data from a SQL + * relational database. + */ + public DatabaseResultSetProcessor(SQLDataHandler handler) { + m_handler = handler; + } + + /** + * Process the results of a SQL query, putting retrieved data into a Table + * instance. If a null table is provided, a new table with the appropriate + * schema will be created. + * + * @param t the Table to store results in + * @param rset the SQL query result set + * @param remove decides of rows which have no counterpart in the ResultSet + * should get removed + * @param lock object used for syncronization + * @return a Table containing the query results + */ + public Table process(Table t, ResultSet rset, String key, Object lock, boolean remove) + throws DataIOException { + // clock in + int count = 0; + long timein = System.currentTimeMillis(); + + boolean tableIsNew = false; + HashSet rowsToRemove = new HashSet<>(); + + if (t != null) { + TableIterator iterator = t.iterator(); + while (iterator.hasNext()) { + Integer row = iterator.nextInt(); + rowsToRemove.add(t.getTuple(row)); + } + } + + try { + ResultSetMetaData metadata = rset.getMetaData(); + int ncols = metadata.getColumnCount(); + + // create a new table if necessary + if (t == null) { + t = getSchema(metadata, m_handler).instantiate(); + tableIsNew = true; + if (key != null) { + try { + t.index(key); + s_logger.info("Indexed field: " + key); + } catch (Exception e) { + s_logger.warning("Error indexing field: " + key); + } + } + } + + // set the lock, lock on the table itself if nothing else provided + lock = (lock == null ? t : lock); + + // process the returned rows + while (rset.next()) { + synchronized (lock) { + // determine the table row index to use + + int row = getExistingRow(t, rset, key); + if (row < 0) { + row = t.addRow(); + } + rowsToRemove.remove(row); + //process each value in the current row + for (int i = 1; i <= ncols; ++i) { + if (0 <= t.getColumnNumber(rset.getMetaData().getCatalogName(i))) { + m_handler.process(t, row, rset, i); + } + } + } + + // increment row count + ++count; + } + + if (!tableIsNew && remove) { + // remove all no longer relevant columns + Iterator iterator = rowsToRemove.iterator(); + while (iterator.hasNext()) { + Tuple tuple = iterator.next(); + boolean removeRow = t.removeTuple(tuple); + assert removeRow : "maybe some syncronization problems"; + } + } + } catch (SQLException e) { + throw new DataIOException(e); + } + + // clock out + long time = System.currentTimeMillis() - timein; + s_logger.info("Internal query processing completed: " + count + " rows, " + + (time / 1000) + "." + (time % 1000) + " seconds."); + + return t; + } + + /** + * See if a retrieved database row is already represented in the given + * Table. + * + * @param t the prefuse Table to check for an existing row + * @param rset the ResultSet, set to a particular row, which may or may not + * have a matching row in the prefuse Table + * @param keyField the key field to look up to check for an existing row + * @return the index of the existing row, or -1 if no match is found + * @throws SQLException + */ + protected int getExistingRow(Table t, ResultSet rset, String keyField) + throws SQLException { + // check if we have a keyField, bail if not + if (keyField == null) { + return -1; + } + + // retrieve the column data type, bail if column is not found + Class type = t.getColumnType(keyField); + if (type == null) { + return -1; + } + + // get the index and perform the lookup + Index index = t.index(keyField); + if (type == int.class) { + return index.get(rset.getInt(keyField)); + } else if (type == long.class) { + return index.get(rset.getLong(keyField)); + } else if (type == float.class) { + return index.get(rset.getFloat(keyField)); + } else if (type == double.class) { + return index.get(rset.getDouble(keyField)); + } else if (!type.isPrimitive()) { + return index.get(rset.getObject(keyField)); + } else { + return -1; + } + } + + /** + * Given the metadata for a SQL result set and a data value handler for that + * result set, returns a corresponding schema for a prefuse table. + * + * @param metadata the SQL result set metadata + * @param handler the data value handler + * @return the schema determined by the metadata and handler + * @throws SQLException if an error occurs accessing the metadata + */ + public Schema getSchema(ResultSetMetaData metadata, SQLDataHandler handler) + throws SQLException { + int ncols = metadata.getColumnCount(); + Schema schema = new Schema(ncols); + + // determine the table schema + for (int i = 1; i <= ncols; ++i) { + String name = metadata.getColumnName(i); + int sqlType = metadata.getColumnType(i); + Class type = handler.getDataType(name, sqlType); + if (type != null) { + schema.addColumn(name, type); + } + } + + return schema; + } +} diff --git a/src/prefuse/data/parser/DateParser.java b/src/prefuse/data/parser/DateParser.java index 14bcfea..a43e626 100644 --- a/src/prefuse/data/parser/DateParser.java +++ b/src/prefuse/data/parser/DateParser.java @@ -3,54 +3,62 @@ import java.sql.Date; import java.text.DateFormat; import java.text.ParsePosition; +import java.text.SimpleDateFormat; /** * DataParser instance that parses Date values as java.sql.Time instances, - * representing a particular date (but not a specific time on that day). - * This class uses a backing {@link java.text.DateFormat} instance to - * perform parsing. The DateFormat instance to use can be passed in to the - * constructor, or by default the DateFormat returned by - * {@link java.text.DateFormat#getDateInstance(int)} with an - * argument of {@link java.text.DateFormat#SHORT} is used. - * + * representing a particular date (but not a specific time on that day). This + * class uses a backing {@link java.text.DateFormat} instance to perform + * parsing. The DateFormat instance to use can be passed in to the constructor, + * or by default the DateFormat returned by + * {@link java.text.DateFormat#getDateInstance(int)} with an argument of + * {@link java.text.DateFormat#SHORT} is used. + * * @author jeffrey heer */ public class DateParser implements DataParser { - - protected DateFormat m_dfmt; + + protected DateFormat[] m_dfmt; protected ParsePosition m_pos; - + /** * Create a new DateParser. */ public DateParser() { - this(DateFormat.getDateInstance(DateFormat.SHORT)); + this( + new DateFormat[]{ + new SimpleDateFormat("dd.MM.yyyy"), + new SimpleDateFormat("dd.MM.yy"), + new SimpleDateFormat("MM/dd/yyyy") + }); } - + /** * Create a new DateParser. + * * @param dateFormat the DateFormat instance to use for parsing */ - public DateParser(DateFormat dateFormat) { - m_dfmt = dateFormat; + public DateParser(DateFormat[] dateFormats) { + m_dfmt = dateFormats; m_pos = new ParsePosition(0); } - + /** * Returns java.sql.Date. + * * @see prefuse.data.parser.DataParser#getType() */ public Class getType() { return Date.class; } - + /** * @see prefuse.data.parser.DataParser#format(java.lang.Object) */ public String format(Object value) { - return value==null ? null : m_dfmt.format(value); + return value == null ? null : m_dfmt[0].format(value); } - + /** * @see prefuse.data.parser.DataParser#canParse(java.lang.String) */ @@ -58,20 +66,21 @@ public boolean canParse(String text) { try { parseDate(text); return true; - } catch ( DataParseException e ) { + } catch (DataParseException e) { return false; } } - + /** * @see prefuse.data.parser.DataParser#parse(java.lang.String) */ public Object parse(String text) throws DataParseException { return parseDate(text); } - + /** * Parse a Date value from a text string. + * * @param text the text string to parse * @return the parsed Date value * @throws DataParseException if an error occurs during parsing @@ -79,29 +88,33 @@ public Object parse(String text) throws DataParseException { public Date parseDate(String text) throws DataParseException { m_pos.setErrorIndex(0); m_pos.setIndex(0); - + // parse the data value, convert to the wrapper type Date d = null; try { d = Date.valueOf(text); m_pos.setIndex(text.length()); - } catch ( IllegalArgumentException e ) { + } catch (IllegalArgumentException e) { d = null; } - if ( d == null ) { - java.util.Date d1 = m_dfmt.parse(text, m_pos); - if ( d1 != null ) { - d = new Date(d1.getTime()); + if (d == null) { + // interate through all known formats and try to parse + for (int i = 0; i < m_dfmt.length; i++) { + DateFormat dateFormat = m_dfmt[i]; + java.util.Date d1 = dateFormat.parse(text, m_pos); + if (d1 != null) { + d = new Date(d1.getTime()); + break; + } } } - + // date format will parse substrings successfully, so we need // to check the position to make sure the whole value was used - if ( d == null || m_pos.getIndex() < text.length() ) { - throw new DataParseException("Could not parse Date: "+text); + if (d == null || m_pos.getIndex() < text.length()) { + throw new DataParseException("Could not parse Date: " + text); } else { return d; } } - } // end of class DateParser diff --git a/src/prefuse/data/parser/DateTimeParser.java b/src/prefuse/data/parser/DateTimeParser.java index ac688a6..b50396c 100644 --- a/src/prefuse/data/parser/DateTimeParser.java +++ b/src/prefuse/data/parser/DateTimeParser.java @@ -4,31 +4,31 @@ /** * DataParser instance that parses Date values as java.util.Date instances, - * representing a particular date and time. - * This class uses a backing {@link java.text.DateFormat} instance to - * perform parsing. The DateFormat instance to use can be passed in to the - * constructor, or by default the DateFormat returned by + * representing a particular date and time. This class uses a backing + * {@link java.text.DateFormat} instance to perform parsing. The DateFormat + * instance to use can be passed in to the constructor, or by default the + * DateFormat returned by * {@link java.text.DateFormat#getDateTimeInstance(int, int)} with both * arguments being {@link java.text.DateFormat#SHORT} is used. * * @author jeffrey heer */ public class DateTimeParser extends DateParser { - + /** * Create a new DateTimeParser. */ public DateTimeParser() { - this(DateFormat.getDateTimeInstance( - DateFormat.SHORT, DateFormat.SHORT)); + this(new DateFormat[]{DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.SHORT)}); } - + /** * Create a new DateTimeParser. + * * @param dateFormat the DateFormat instance to use for parsing */ - public DateTimeParser(DateFormat dateFormat) { - super(dateFormat); + public DateTimeParser(DateFormat[] dateFormats) { + super(dateFormats); } - } // end of class DateTimeParser diff --git a/src/prefuse/data/parser/TimeParser.java b/src/prefuse/data/parser/TimeParser.java index 78dc1b1..a81cb3a 100644 --- a/src/prefuse/data/parser/TimeParser.java +++ b/src/prefuse/data/parser/TimeParser.java @@ -2,15 +2,15 @@ import java.sql.Time; import java.text.DateFormat; +import java.text.SimpleDateFormat; /** * DataParser instance that parses Date values as java.util.Time instances, - * representing a particular time (but no specific date). - * This class uses a backing {@link java.text.DateFormat} instance to - * perform parsing. The DateFormat instance to use can be passed in to the - * constructor, or by default the DateFormat returned by - * {@link java.text.DateFormat#getTimeInstance(int)} with an - * argument of {@link java.text.DateFormat#SHORT} is used. + * representing a particular time (but no specific date). This class uses a + * backing {@link java.text.DateFormat} instance to perform parsing. The + * DateFormat instance to use can be passed in to the constructor, or by default + * the DateFormat returned by {@link java.text.DateFormat#getTimeInstance(int)} + * with an argument of {@link java.text.DateFormat#SHORT} is used. * * @author jeffrey heer */ @@ -20,25 +20,30 @@ public class TimeParser extends DateParser { * Create a new TimeParser. */ public TimeParser() { - this(DateFormat.getTimeInstance(DateFormat.SHORT)); + this(new DateFormat[]{ + new SimpleDateFormat("KK:mm a"), + new SimpleDateFormat("HH:mm") + }); } - + /** * Create a new TimeParser. + * * @param dateFormat the DateFormat instance to use for parsing */ - public TimeParser(DateFormat dateFormat) { - super(dateFormat); + public TimeParser(DateFormat[] dateFormats) { + super(dateFormats); } - + /** * Returns java.sql.Time.class. + * * @see prefuse.data.parser.DataParser#getType() */ public Class getType() { return Time.class; } - + /** * @see prefuse.data.parser.DataParser#canParse(java.lang.String) */ @@ -46,20 +51,21 @@ public boolean canParse(String val) { try { parseTime(val); return true; - } catch ( DataParseException e ) { + } catch (DataParseException e) { return false; } } - + /** * @see prefuse.data.parser.DataParser#parse(java.lang.String) */ public Object parse(String val) throws DataParseException { return parseTime(val); } - + /** * Parse a Time value from a text string. + * * @param text the text string to parse * @return the parsed Time value * @throws DataParseException if an error occurs during parsing @@ -67,29 +73,33 @@ public Object parse(String val) throws DataParseException { public Time parseTime(String text) throws DataParseException { m_pos.setErrorIndex(0); m_pos.setIndex(0); - + // parse the data value, convert to the wrapper type Time t = null; try { t = Time.valueOf(text); m_pos.setIndex(text.length()); - } catch ( IllegalArgumentException e ) { + } catch (IllegalArgumentException e) { t = null; } - if ( t == null ) { - java.util.Date d1 = m_dfmt.parse(text, m_pos); - if ( d1 != null ) { - t = new Time(d1.getTime()); + if (t == null) { + // interate through all known time formats and try to parse + for (int i = 0; i < m_dfmt.length; i++) { + DateFormat dateFormat = m_dfmt[i]; + java.util.Date d1 = dateFormat.parse(text, m_pos); + if (d1 != null) { + t = new Time(d1.getTime()); + break; + } } } - + // date format will parse substrings successfully, so we need // to check the position to make sure the whole value was used - if ( t == null || m_pos.getIndex() < text.length() ) { - throw new DataParseException("Could not parse Date: "+text); + if (t == null || m_pos.getIndex() < text.length()) { + throw new DataParseException("Could not parse Date: " + text); } else { return t; } } - } // end of class TimeParser diff --git a/src/prefuse/render/EdgeRenderer.java b/src/prefuse/render/EdgeRenderer.java index 5d087ad..dfde32b 100644 --- a/src/prefuse/render/EdgeRenderer.java +++ b/src/prefuse/render/EdgeRenderer.java @@ -15,65 +15,65 @@ import prefuse.util.GraphicsLib; import prefuse.util.StrokeLib; import prefuse.visual.EdgeItem; +import prefuse.visual.NodeItem; +import prefuse.visual.VisualGraph; import prefuse.visual.VisualItem; - /** - *

Renderer that draws edges as lines connecting nodes. Both - * straight and curved lines are supported. Curved lines are drawn using - * cubic Bezier curves. Subclasses can override the + *

Renderer that draws edges as lines connecting nodes. Both straight and + * curved lines are supported. Curved lines are drawn using cubic Bezier curves. + * Subclasses can override the * {@link #getCurveControlPoints(EdgeItem, Point2D[], double, double, double, double)} * method to provide custom control point assignment for such curves.

- * + * *

This class also supports arrows for directed edges. See the * {@link #setArrowType(int)} method for more.

- * + * * @version 1.0 * @author jeffrey heer */ public class EdgeRenderer extends AbstractShapeRenderer { - + public static final String EDGE_TYPE = "edgeType"; - protected static final double HALF_PI = Math.PI / 2; - - protected Line2D m_line = new Line2D.Float(); + protected Line2D m_line = new Line2D.Float(); protected CubicCurve2D m_cubic = new CubicCurve2D.Float(); - - protected int m_edgeType = Constants.EDGE_TYPE_LINE; - protected int m_xAlign1 = Constants.CENTER; - protected int m_yAlign1 = Constants.CENTER; - protected int m_xAlign2 = Constants.CENTER; - protected int m_yAlign2 = Constants.CENTER; - protected double m_width = 1; - protected float m_curWidth = 1; - protected Point2D m_tmpPoints[] = new Point2D[2]; + protected int m_edgeType = Constants.EDGE_TYPE_LINE; + protected MixedGraphEdgeType mixedEdgeType = MixedGraphEdgeType.Default; + final double offsetStrength = 1d / 4d; + protected int m_xAlign1 = Constants.CENTER; + protected int m_yAlign1 = Constants.CENTER; + protected int m_xAlign2 = Constants.CENTER; + protected int m_yAlign2 = Constants.CENTER; + protected double m_width = 1; + protected float m_curWidth = 1; + protected Point2D m_tmpPoints[] = new Point2D[2]; protected Point2D m_ctrlPoints[] = new Point2D[2]; protected Point2D m_isctPoints[] = new Point2D[2]; - // arrow head handling - protected int m_edgeArrow = Constants.EDGE_ARROW_FORWARD; - protected int m_arrowWidth = 8; - protected int m_arrowHeight = 12; - protected Polygon m_arrowHead = updateArrowHead( - m_arrowWidth, m_arrowHeight); + protected int m_edgeArrow = Constants.EDGE_ARROW_FORWARD; + protected int m_arrowWidth = 8; + protected int m_arrowHeight = 12; + protected Polygon m_arrowHead = updateArrowHead( + m_arrowWidth, m_arrowHeight); protected AffineTransform m_arrowTrans = new AffineTransform(); - protected Shape m_curArrow; + protected Shape m_curArrow; /** * Create a new EdgeRenderer. */ public EdgeRenderer() { - m_tmpPoints[0] = new Point2D.Float(); - m_tmpPoints[1] = new Point2D.Float(); + m_tmpPoints[0] = new Point2D.Float(); + m_tmpPoints[1] = new Point2D.Float(); m_ctrlPoints[0] = new Point2D.Float(); - m_ctrlPoints[1] = new Point2D.Float(); + m_ctrlPoints[1] = new Point2D.Float(); m_isctPoints[0] = new Point2D.Float(); - m_isctPoints[1] = new Point2D.Float(); + m_isctPoints[1] = new Point2D.Float(); } /** * Create a new EdgeRenderer with the given edge type. + * * @param edgeType the edge type, one of * {@link prefuse.Constants#EDGE_TYPE_LINE} or * {@link prefuse.Constants#EDGE_TYPE_CURVE}. @@ -81,14 +81,14 @@ public EdgeRenderer() { public EdgeRenderer(int edgeType) { this(edgeType, Constants.EDGE_ARROW_FORWARD); } - + /** * Create a new EdgeRenderer with the given edge and arrow types. + * * @param edgeType the edge type, one of * {@link prefuse.Constants#EDGE_TYPE_LINE} or * {@link prefuse.Constants#EDGE_TYPE_CURVE}. - * @param arrowType the arrow type, one of - * {@link prefuse.Constants#EDGE_ARROW_FORWARD}, + * @param arrowType the arrow type, one of null {@link prefuse.Constants#EDGE_ARROW_FORWARD}, * {@link prefuse.Constants#EDGE_ARROW_REVERSE}, or * {@link prefuse.Constants#EDGE_ARROW_NONE}. * @see #setArrowType(int) @@ -98,225 +98,291 @@ public EdgeRenderer(int edgeType, int arrowType) { setEdgeType(edgeType); setArrowType(arrowType); } - + + public EdgeRenderer(int edgeType, int arrowType, MixedGraphEdgeType mixedEdgeType) { + this(); + setEdgeType(edgeType); + setArrowType(arrowType); + this.mixedEdgeType = mixedEdgeType; + } + /** - * @see prefuse.render.AbstractShapeRenderer#getRenderType(prefuse.visual.VisualItem) + * @see + * prefuse.render.AbstractShapeRenderer#getRenderType(prefuse.visual.VisualItem) */ public int getRenderType(VisualItem item) { return RENDER_TYPE_DRAW; } - + /** - * @see prefuse.render.AbstractShapeRenderer#getRawShape(prefuse.visual.VisualItem) + * @see + * prefuse.render.AbstractShapeRenderer#getRawShape(prefuse.visual.VisualItem) */ protected Shape getRawShape(VisualItem item) { - EdgeItem edge = (EdgeItem)item; + EdgeItem edge = (EdgeItem) item; VisualItem item1 = edge.getSourceItem(); VisualItem item2 = edge.getTargetItem(); - + int type = m_edgeType; - + getAlignedPoint(m_tmpPoints[0], item1.getBounds(), - m_xAlign1, m_yAlign1); + m_xAlign1, m_yAlign1); getAlignedPoint(m_tmpPoints[1], item2.getBounds(), - m_xAlign2, m_yAlign2); - m_curWidth = (float)(m_width * getLineWidth(item)); - + m_xAlign2, m_yAlign2); + m_curWidth = (float) (m_width * getLineWidth(item)); + // create the arrow head, if needed - EdgeItem e = (EdgeItem)item; - if ( e.isDirected() && m_edgeArrow != Constants.EDGE_ARROW_NONE ) { + EdgeItem e = (EdgeItem) item; + if (e.isDirected() && m_edgeArrow != Constants.EDGE_ARROW_NONE) { // get starting and ending edge endpoints boolean forward = (m_edgeArrow == Constants.EDGE_ARROW_FORWARD); Point2D start = null, end = null; - start = m_tmpPoints[forward?0:1]; - end = m_tmpPoints[forward?1:0]; - + start = m_tmpPoints[forward ? 0 : 1]; + end = m_tmpPoints[forward ? 1 : 0]; + + changeByMixedEdgeType(edge, start, end); + // compute the intersection with the target bounding box VisualItem dest = forward ? e.getTargetItem() : e.getSourceItem(); int i = GraphicsLib.intersectLineRectangle(start, end, dest.getBounds(), m_isctPoints); - if ( i > 0 ) end = m_isctPoints[0]; - + if (i > 0) { + end = m_isctPoints[0]; + } + // create the arrow head shape AffineTransform at = getArrowTrans(start, end, m_curWidth); m_curArrow = at.createTransformedShape(m_arrowHead); - + // update the endpoints for the edge shape // need to bias this by arrow head size - Point2D lineEnd = m_tmpPoints[forward?1:0]; + Point2D lineEnd = m_tmpPoints[forward ? 1 : 0]; lineEnd.setLocation(0, -m_arrowHeight); at.transform(lineEnd, lineEnd); } else { m_curArrow = null; } - + // create the edge shape Shape shape = null; double n1x = m_tmpPoints[0].getX(); double n1y = m_tmpPoints[0].getY(); double n2x = m_tmpPoints[1].getX(); double n2y = m_tmpPoints[1].getY(); - switch ( type ) { - case Constants.EDGE_TYPE_LINE: + switch (type) { + case Constants.EDGE_TYPE_LINE: m_line.setLine(n1x, n1y, n2x, n2y); shape = m_line; break; case Constants.EDGE_TYPE_CURVE: - getCurveControlPoints(edge, m_ctrlPoints,n1x,n1y,n2x,n2y); + getCurveControlPoints(edge, m_ctrlPoints, n1x, n1y, n2x, n2y); m_cubic.setCurve(n1x, n1y, - m_ctrlPoints[0].getX(), m_ctrlPoints[0].getY(), - m_ctrlPoints[1].getX(), m_ctrlPoints[1].getY(), - n2x, n2y); + m_ctrlPoints[0].getX(), m_ctrlPoints[0].getY(), + m_ctrlPoints[1].getX(), m_ctrlPoints[1].getY(), + n2x, n2y); shape = m_cubic; break; default: throw new IllegalStateException("Unknown edge type"); } - + // return the edge shape return shape; } + private void changeByMixedEdgeType(EdgeItem edge, Point2D start, Point2D end) { + + NodeItem sourceItem = edge.getSourceItem(); + NodeItem targetItem = edge.getTargetItem(); + VisualGraph graph = (VisualGraph) edge.getGraph(); + EdgeItem opposingEdge = (EdgeItem) graph.getEdge(targetItem, sourceItem); + + if (opposingEdge != null) { + if(!opposingEdge.isVisible()) + return; + + if (mixedEdgeType == MixedGraphEdgeType.Two_Edges) { + Rectangle2D sourceNodeBounds = sourceItem.getBounds(); + Rectangle2D targetNodeBounds = targetItem.getBounds(); + double sourceX = sourceNodeBounds.getCenterX(); + double sourceY = sourceNodeBounds.getCenterY(); + double targetX = targetNodeBounds.getCenterX(); + double targetY = targetNodeBounds.getCenterY(); + + double directionX = targetX - sourceX; + double directionY = targetY - sourceY; + + double length = Math.sqrt(Math.pow(directionX, 2) + Math.pow(directionY, 2)); + + double nX = -directionY / length; + double nY = directionX / length; + + if (length == 0) { + nX = 0; + nY = 0; + } + start.setLocation( + start.getX() + nX * (sourceNodeBounds.getWidth() / 2) * offsetStrength, + start.getY() + nY * (sourceNodeBounds.getHeight() / 2) * offsetStrength); + end.setLocation(end.getX() + nX * (targetNodeBounds.getWidth() / 2) * offsetStrength, + end.getY() + +nY * (sourceNodeBounds.getHeight() / 2) * offsetStrength); + } else if (mixedEdgeType == MixedGraphEdgeType.Half_Edges) { + float directionX = (float) (end.getX() - start.getX()); + float directionY = (float) (end.getY() - start.getY()); + end.setLocation(start.getX() + (directionX / 2), start.getY() + (directionY / 2)); + } + } + } + /** - * @see prefuse.render.Renderer#render(java.awt.Graphics2D, prefuse.visual.VisualItem) + * @see prefuse.render.Renderer#render(java.awt.Graphics2D, + * prefuse.visual.VisualItem) */ public void render(Graphics2D g, VisualItem item) { // render the edge line super.render(g, item); // render the edge arrow head, if appropriate - if ( m_curArrow != null ) { + if (m_curArrow != null) { g.setPaint(ColorLib.getColor(item.getFillColor())); g.fill(m_curArrow); } } /** - * Returns an affine transformation that maps the arrowhead shape - * to the position and orientation specified by the provided - * line segment end points. + * Returns an affine transformation that maps the arrowhead shape to the + * position and orientation specified by the provided line segment end + * points. */ - protected AffineTransform getArrowTrans(Point2D p1, Point2D p2, - double width) - { + protected AffineTransform getArrowTrans(Point2D p1, Point2D p2, + double width) { m_arrowTrans.setToTranslation(p2.getX(), p2.getY()); - m_arrowTrans.rotate(-HALF_PI + - Math.atan2(p2.getY()-p1.getY(), p2.getX()-p1.getX())); - if ( width > 1 ) { - double scalar = width/4; + m_arrowTrans.rotate(-HALF_PI + + Math.atan2(p2.getY() - p1.getY(), p2.getX() - p1.getX())); + if (width > 1) { + double scalar = width / 4; m_arrowTrans.scale(scalar, scalar); } return m_arrowTrans; } - + /** - * Update the dimensions of the arrow head, creating a new - * arrow head if necessary. The return value is also set - * as the member variable m_arrowHead + * Update the dimensions of the arrow head, creating a new arrow head if + * necessary. The return value is also set as the member variable + * m_arrowHead + * * @param w the width of the untransformed arrow head base, in pixels * @param h the height of the untransformed arrow head, in pixels * @return the untransformed arrow head shape */ protected Polygon updateArrowHead(int w, int h) { - if ( m_arrowHead == null ) { + if (m_arrowHead == null) { m_arrowHead = new Polygon(); } else { m_arrowHead.reset(); } m_arrowHead.addPoint(0, 0); - m_arrowHead.addPoint(-w/2, -h); - m_arrowHead.addPoint( w/2, -h); + m_arrowHead.addPoint(-w / 2, -h); + m_arrowHead.addPoint(w / 2, -h); m_arrowHead.addPoint(0, 0); return m_arrowHead; } - - /** - * @see prefuse.render.AbstractShapeRenderer#getTransform(prefuse.visual.VisualItem) + * @see + * prefuse.render.AbstractShapeRenderer#getTransform(prefuse.visual.VisualItem) */ protected AffineTransform getTransform(VisualItem item) { return null; } - + /** - * @see prefuse.render.Renderer#locatePoint(java.awt.geom.Point2D, prefuse.visual.VisualItem) + * @see prefuse.render.Renderer#locatePoint(java.awt.geom.Point2D, + * prefuse.visual.VisualItem) */ public boolean locatePoint(Point2D p, VisualItem item) { Shape s = getShape(item); - if ( s == null ) { + if (s == null) { return false; } else { double width = Math.max(2, getLineWidth(item)); - double halfWidth = width/2.0; - return s.intersects(p.getX()-halfWidth, - p.getY()-halfWidth, - width,width); + double halfWidth = width / 2.0; + return s.intersects(p.getX() - halfWidth, + p.getY() - halfWidth, + width, width); } } - + /** * @see prefuse.render.Renderer#setBounds(prefuse.visual.VisualItem) */ public void setBounds(VisualItem item) { - if ( !m_manageBounds ) return; + if (!m_manageBounds) { + return; + } Shape shape = getShape(item); - if ( shape == null ) { + if (shape == null) { item.setBounds(item.getX(), item.getY(), 0, 0); return; } GraphicsLib.setBounds(item, shape, getStroke(item)); - if ( m_curArrow != null ) { - Rectangle2D bbox = (Rectangle2D)item.get(VisualItem.BOUNDS); + if (m_curArrow != null) { + Rectangle2D bbox = (Rectangle2D) item.get(VisualItem.BOUNDS); Rectangle2D.union(bbox, m_curArrow.getBounds2D(), bbox); } } /** * Returns the line width to be used for this VisualItem. By default, - * returns the base width value set using the {@link #setDefaultLineWidth(double)} - * method, scaled by the item size returned by - * {@link VisualItem#getSize()}. Subclasses can override this method to - * perform custom line width determination, however, the preferred + * returns the base width value set using the + * {@link #setDefaultLineWidth(double)} method, scaled by the item size + * returned by {@link VisualItem#getSize()}. Subclasses can override this + * method to perform custom line width determination, however, the preferred * method is to change the item size value itself. + * * @param item the VisualItem for which to determine the line width * @return the desired line width, in pixels */ protected double getLineWidth(VisualItem item) { return item.getSize(); } - + /** * Returns the stroke value returned by {@link VisualItem#getStroke()}, - * scaled by the current line width - * determined by the {@link #getLineWidth(VisualItem)} method. Subclasses - * may override this method to perform custom stroke assignment, but should - * respect the line width paremeter stored in the {@link #m_curWidth} - * member variable, which caches the result of getLineWidth. - * @see prefuse.render.AbstractShapeRenderer#getStroke(prefuse.visual.VisualItem) + * scaled by the current line width determined by the + * {@link #getLineWidth(VisualItem)} method. Subclasses may override this + * method to perform custom stroke assignment, but should respect the line + * width paremeter stored in the {@link #m_curWidth} member variable, which + * caches the result of + * getLineWidth. + * + * @see + * prefuse.render.AbstractShapeRenderer#getStroke(prefuse.visual.VisualItem) */ protected BasicStroke getStroke(VisualItem item) { return StrokeLib.getDerivedStroke(item.getStroke(), m_curWidth); } /** - * Determines the control points to use for cubic (Bezier) curve edges. - * Override this method to provide custom curve specifications. - * To reduce object initialization, the entries of the Point2D array are - * already initialized, so use the Point2D.setLocation() method rather than - * new Point2D.Double() to more efficiently set custom control points. + * Determines the control points to use for cubic (Bezier) curve edges. + * Override this method to provide custom curve specifications. To reduce + * object initialization, the entries of the Point2D array are already + * initialized, so use the Point2D.setLocation() method rather than + * new Point2D.Double() to more efficiently set custom control + * points. + * * @param eitem the EdgeItem we are determining the control points for - * @param cp array of Point2D's (length >= 2) in which to return the control points + * @param cp array of Point2D's (length >= 2) in which to return the control + * points * @param x1 the x co-ordinate of the first node this edge connects to * @param y1 the y co-ordinate of the first node this edge connects to * @param x2 the x co-ordinate of the second node this edge connects to * @param y2 the y co-ordinate of the second node this edge connects to */ - protected void getCurveControlPoints(EdgeItem eitem, Point2D[] cp, - double x1, double y1, double x2, double y2) - { - double dx = x2-x1, dy = y2-y1; - cp[0].setLocation(x1+2*dx/3,y1); - cp[1].setLocation(x2-dx/8,y2-dy/8); + protected void getCurveControlPoints(EdgeItem eitem, Point2D[] cp, + double x1, double y1, double x2, double y2) { + double dx = x2 - x1, dy = y2 - y1; + cp[0].setLocation(x1 + 2 * dx / 3, y1); + cp[1].setLocation(x2 - dx / 8, y2 - dy / 8); } /** @@ -325,73 +391,79 @@ protected void getCurveControlPoints(EdgeItem eitem, Point2D[] cp, */ protected static void getAlignedPoint(Point2D p, Rectangle2D r, int xAlign, int yAlign) { double x = r.getX(), y = r.getY(), w = r.getWidth(), h = r.getHeight(); - if ( xAlign == Constants.CENTER ) { - x = x+(w/2); - } else if ( xAlign == Constants.RIGHT ) { - x = x+w; + if (xAlign == Constants.CENTER) { + x = x + (w / 2); + } else if (xAlign == Constants.RIGHT) { + x = x + w; } - if ( yAlign == Constants.CENTER ) { - y = y+(h/2); - } else if ( yAlign == Constants.BOTTOM ) { - y = y+h; + if (yAlign == Constants.CENTER) { + y = y + (h / 2); + } else if (yAlign == Constants.BOTTOM) { + y = y + h; } - p.setLocation(x,y); + + p.setLocation(x, y); } /** * Returns the type of the drawn edge. This is one of * {@link prefuse.Constants#EDGE_TYPE_LINE} or * {@link prefuse.Constants#EDGE_TYPE_CURVE}. + * * @return the edge type */ public int getEdgeType() { return m_edgeType; } - + /** * Sets the type of the drawn edge. This must be one of - * {@link prefuse.Constants#EDGE_TYPE_LINE} or - * {@link prefuse.Constants#EDGE_TYPE_CURVE}. + * {@link prefuse.Constants#EDGE_TYPE_LINE} or + * {@link prefuse.Constants#EDGE_TYPE_CURVE}. + * * @param type the new edge type */ public void setEdgeType(int type) { - if ( type < 0 || type >= Constants.EDGE_TYPE_COUNT ) + if (type < 0 || type >= Constants.EDGE_TYPE_COUNT) { throw new IllegalArgumentException( - "Unrecognized edge curve type: "+type); + "Unrecognized edge curve type: " + type); + } m_edgeType = type; } - + /** - * Returns the type of the drawn edge. This is one of - * {@link prefuse.Constants#EDGE_ARROW_FORWARD}, + * Returns the type of the drawn edge. This is one of null {@link prefuse.Constants#EDGE_ARROW_FORWARD}, * {@link prefuse.Constants#EDGE_ARROW_REVERSE}, or * {@link prefuse.Constants#EDGE_ARROW_NONE}. + * * @return the edge type */ public int getArrowType() { return m_edgeArrow; } - + /** * Sets the type of the drawn edge. This is either * {@link prefuse.Constants#EDGE_ARROW_NONE} for no edge arrows, * {@link prefuse.Constants#EDGE_ARROW_FORWARD} for arrows from source to - * target on directed edges, or - * {@link prefuse.Constants#EDGE_ARROW_REVERSE} for arrows from target to - * source on directed edges. + * target on directed edges, or {@link prefuse.Constants#EDGE_ARROW_REVERSE} + * for arrows from target to source on directed edges. + * * @param type the new arrow type */ public void setArrowType(int type) { - if ( type < 0 || type >= Constants.EDGE_ARROW_COUNT ) + if (type < 0 || type >= Constants.EDGE_ARROW_COUNT) { throw new IllegalArgumentException( - "Unrecognized edge arrow type: "+type); + "Unrecognized edge arrow type: " + type); + } m_edgeArrow = type; } - + /** * Sets the dimensions of an arrow head for a directed edge. This specifies - * the pixel dimensions when both the zoom level and the size factor - * (a combination of item size value and default stroke width) are 1.0. + * the pixel dimensions when both the zoom level and the size factor (a + * combination of item size value and default stroke width) are 1.0. + * * @param width the untransformed arrow head width, in pixels. This * specifies the span of the base of the arrow head. * @param height the untransformed arrow head height, in pixels. This @@ -402,10 +474,11 @@ public void setArrowHeadSize(int width, int height) { m_arrowHeight = height; m_arrowHead = updateArrowHead(width, height); } - + /** - * Get the height of the untransformed arrow head. This is the distance, - * in pixels, from the tip of the arrow to its base. + * Get the height of the untransformed arrow head. This is the distance, in + * pixels, from the tip of the arrow to its base. + * * @return the default arrow head height */ public int getArrowHeadHeight() { @@ -413,25 +486,28 @@ public int getArrowHeadHeight() { } /** - * Get the width of the untransformed arrow head. This is the length, - * in pixels, of the base of the arrow head. + * Get the width of the untransformed arrow head. This is the length, in + * pixels, of the base of the arrow head. + * * @return the default arrow head width */ public int getArrowHeadWidth() { return m_arrowWidth; } - + /** * Get the horizontal aligment of the edge mount point with the first node. + * * @return the horizontal alignment, one of {@link prefuse.Constants#LEFT}, * {@link prefuse.Constants#RIGHT}, or {@link prefuse.Constants#CENTER}. */ public int getHorizontalAlignment1() { return m_xAlign1; } - + /** * Get the vertical aligment of the edge mount point with the first node. + * * @return the vertical alignment, one of {@link prefuse.Constants#TOP}, * {@link prefuse.Constants#BOTTOM}, or {@link prefuse.Constants#CENTER}. */ @@ -440,36 +516,39 @@ public int getVerticalAlignment1() { } /** - * Get the horizontal aligment of the edge mount point with the second - * node. + * Get the horizontal aligment of the edge mount point with the second node. + * * @return the horizontal alignment, one of {@link prefuse.Constants#LEFT}, * {@link prefuse.Constants#RIGHT}, or {@link prefuse.Constants#CENTER}. */ public int getHorizontalAlignment2() { return m_xAlign2; } - + /** * Get the vertical aligment of the edge mount point with the second node. + * * @return the vertical alignment, one of {@link prefuse.Constants#TOP}, * {@link prefuse.Constants#BOTTOM}, or {@link prefuse.Constants#CENTER}. */ public int getVerticalAlignment2() { return m_yAlign2; } - + /** * Set the horizontal aligment of the edge mount point with the first node. - * @param align the horizontal alignment, one of + * + * @param align the horizontal alignment, one of * {@link prefuse.Constants#LEFT}, {@link prefuse.Constants#RIGHT}, or * {@link prefuse.Constants#CENTER}. */ public void setHorizontalAlignment1(int align) { m_xAlign1 = align; } - + /** * Set the vertical aligment of the edge mount point with the first node. + * * @param align the vertical alignment, one of * {@link prefuse.Constants#TOP}, {@link prefuse.Constants#BOTTOM}, or * {@link prefuse.Constants#CENTER}. @@ -479,8 +558,8 @@ public void setVerticalAlignment1(int align) { } /** - * Set the horizontal aligment of the edge mount point with the second - * node. + * Set the horizontal aligment of the edge mount point with the second node. + * * @param align the horizontal alignment, one of * {@link prefuse.Constants#LEFT}, {@link prefuse.Constants#RIGHT}, or * {@link prefuse.Constants#CENTER}. @@ -488,9 +567,10 @@ public void setVerticalAlignment1(int align) { public void setHorizontalAlignment2(int align) { m_xAlign2 = align; } - + /** * Set the vertical aligment of the edge mount point with the second node. + * * @param align the vertical alignment, one of * {@link prefuse.Constants#TOP}, {@link prefuse.Constants#BOTTOM}, or * {@link prefuse.Constants#CENTER}. @@ -498,25 +578,31 @@ public void setHorizontalAlignment2(int align) { public void setVerticalAlignment2(int align) { m_yAlign2 = align; } - + /** - * Sets the default width of lines. This width value will - * be scaled by the value of an item's size data field. The default - * base width is 1. + * Sets the default width of lines. This width value will be scaled by the + * value of an item's size data field. The default base width is 1. + * * @param w the desired default line width, in pixels */ public void setDefaultLineWidth(double w) { m_width = w; } - + /** - * Gets the default width of lines. This width value that will - * be scaled by the value of an item's size data field. The default - * base width is 1. + * Gets the default width of lines. This width value that will be scaled by + * the value of an item's size data field. The default base width is 1. + * * @return the default line width, in pixels */ public double getDefaultLineWidth() { return m_width; } + public enum MixedGraphEdgeType { + + Default, + Two_Edges, + Half_Edges + } } // end of class EdgeRenderer