diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c1ceb3..28957f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,13 +8,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Maven Central Repository - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: - java-version: '11' + java-version: '17' distribution: 'temurin' - server-id: ossrh + server-id: central server-username: OSSRH_USER server-password: OSSRH_PASS gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index c856f3d..dd051cf 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -8,16 +8,16 @@ jobs: strategy: matrix: os: [ubuntu-latest] - java: ['11', '17'] + java: ['17'] distribution: ['temurin'] fail-fast: false name: ${{ matrix.os }} JDK ${{ matrix.distribution }} ${{ matrix.java }} steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Set up JDK id: setupjdk - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: ${{ matrix.distribution }} java-version: ${{ matrix.java }} diff --git a/README.md b/README.md index 46bf72a..6dd3c0e 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,14 @@ Best way to start is through examples on [Toolkit Demos](https://github.com/geph org.gephi gephi-toolkit - 0.10.1 + 0.11.2 ``` #### From a Gradle project ``` -compile 'org.gephi:gephi-toolkit:0.10.1' +compile 'org.gephi:gephi-toolkit:0.11.2' ``` #### From a Scala SBT Project @@ -39,57 +39,7 @@ resolvers ++= Seq( "gephi-thirdparty" at "https://raw.github.com/gephi/gephi/mvn-thirdparty-repo/" ) -libraryDependencies += "org.gephi" % "gephi-toolkit" % "0.10.1" classifier "all" -``` - -## Latest releases - -### Stable - -- Latest stable release on [gephi.org](http://gephi.org/toolkit). - -### Development Build - -- [gephi-toolkit-0.10.2-SNAPSHOT-all.jar](https://oss.sonatype.org/service/local/artifact/maven/content?r=snapshots&g=org.gephi&a=gephi-toolkit&v=0.10-2-SNAPSHOT&c=all) - -### Development Build (Maven) - -If you use Maven you can directly depend on the latest development version of the toolkit (i.e the -SNAPSHOT version). - -- Add the Gephi repository - -```xml - -... - - - oss-sonatype - oss-sonatype - https://oss.sonatype.org/content/repositories/snapshots/ - - true - - - -... - -``` - -- Add the dependency - -```xml - -... - - - org.gephi - gephi-toolkit - 0.10.2-SNAPSHOT - - ... - -... - +libraryDependencies += "org.gephi" % "gephi-toolkit" % "0.11.2" classifier "all" ``` ## Build @@ -100,7 +50,7 @@ It sources its Gephi dependencies from [Maven Central](https://central.sonatype. ### Requirements -- Java JDK 11. +- Java JDK 17. - [Apache Maven](http://maven.apache.org/) version 3.6.3 or later @@ -116,8 +66,8 @@ It sources its Gephi dependencies from [Maven Central](https://central.sonatype. ### Can the Toolkit use plugins? -Yes that is possible if the plug-in doesn’t depend on something not included in the Toolkit, for instance the UI. If that happens, it is likely that the plug-in has been divided in several modules, and in that case one need only the core and can exclude the UI. -Consult this [HowTo](https://github.com/gephi/gephi/wiki/How-to-use-plug-ins-with-the-Toolkit) page to know how to extract the plugin JARs from the NBM file. Once you have the JARs, include them in your project’s classpath, in addition of the Gephi Toolkit. +Yes, that is possible if the plug-in doesn’t depend on something not included in the Toolkit, for instance the UI. If that happens, it is likely that the plug-in has been divided in several modules, and in that case one need only the core and can exclude the UI. +We recommend pulling JAR dependencies directly from Maven Central. ### Can it depends on a development version of Gephi? diff --git a/pom.xml b/pom.xml index 983a0e5..e5a453f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.gephi gephi-toolkit - 0.10.2-SNAPSHOT + 0.11.2 jar gephi-toolkit @@ -60,13 +60,13 @@ ${netbeans.run.params.ide} - RELEASE160 + RELEASE290 ${project.version} - 11 + 17 -Xlint:all true true @@ -75,11 +75,7 @@ 768M ${project.build.directory}/surefire-reports/plain - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - + git @@ -88,23 +84,23 @@ - 3.3.0 + 3.7.1 - 3.10.0 + 3.13.0 3.0.1 - 3.4.1 + 3.7.0 - 2.22.2 + 3.2.5 - 3.11.0 - - 1.6.12 + 3.12.1 4.1 - 3.2.1 + 3.5.0 + + 0.10.0 @@ -117,22 +113,17 @@ - oss-sonatype - oss-sonatype - https://oss.sonatype.org/content/repositories/snapshots/ + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + true - - - - - ${gephi.ossrh.repository.id} - ${gephi.ossrh.repository.url} - - @@ -362,6 +353,12 @@ maven-enforcer-plugin ${gephi.maven-enforcer-plugin.version} + + org.sonatype.central + central-publishing-maven-plugin + ${gephi.central-publishing-maven-plugin.version} + true + @@ -416,7 +413,7 @@ true false none - 11 + 17 Gephi Toolkit ${project.version} API Index @@ -453,16 +450,15 @@ - - + + - org.sonatype.plugins - nexus-staging-maven-plugin + org.sonatype.central + central-publishing-maven-plugin true - ossrh - https://oss.sonatype.org/ - true + central + true diff --git a/src/test/java/org/gephi/toolkit/FilteringTest.java b/src/test/java/org/gephi/toolkit/FilteringTest.java index d77cd7b..41e4d0b 100644 --- a/src/test/java/org/gephi/toolkit/FilteringTest.java +++ b/src/test/java/org/gephi/toolkit/FilteringTest.java @@ -36,6 +36,8 @@ */ package org.gephi.toolkit; +import java.io.IOException; +import java.io.StringWriter; import org.gephi.appearance.api.AppearanceModel; import org.gephi.filters.api.Query; import org.gephi.filters.api.Range; @@ -47,6 +49,9 @@ import org.gephi.graph.api.Graph; import org.gephi.graph.api.GraphView; import org.gephi.graph.api.Node; +import org.gephi.io.exporter.plugin.ExporterGraphML; +import org.gephi.io.exporter.spi.CharacterExporter; +import org.gephi.io.exporter.spi.Exporter; import org.gephi.project.api.Project; import org.gephi.project.api.Workspace; import org.junit.Assert; @@ -111,6 +116,39 @@ public void testPartitionFilter() { Assert.assertTrue(filteredGraph.contains(graph.getNode(GraphGenerator.SECOND_NODE))); } + @Test + public void testExportToLabelVisible() { + // Reproduces gephi/gephi-toolkit-demos#5: filterController.exportToLabelVisible(query) + // should set label visibility to true for nodes matching the query and false for the rest. + Project project = projectController.newProject(); + Workspace workspace = project.getCurrentWorkspace(); + + Graph graph = GraphGenerator.build(workspace).generateTinyGraph().getGraph(); + + // Add one extra isolated node — degree filter will exclude it + Node isolated = graph.getModel().factory().newNode("isolated"); + graph.addNode(isolated); + + // Ensure all labels start visible + for (Node n : graph.getNodes()) { + n.getTextProperties().setVisible(true); + } + + DegreeRangeBuilder.DegreeRangeFilter degreeFilter = new DegreeRangeBuilder.DegreeRangeFilter(); + degreeFilter.init(graph); + degreeFilter.setRange(new Range(1, Integer.MAX_VALUE)); + Query query = filterController.createQuery(degreeFilter); + + filterController.exportToLabelVisible(query); + + Assert.assertFalse("Isolated node's label should be hidden after exportToLabelVisible", + isolated.getTextProperties().isVisible()); + Assert.assertTrue("Connected node's label should remain visible", + graph.getNode(GraphGenerator.FIRST_NODE).getTextProperties().isVisible()); + Assert.assertTrue("Connected node's label should remain visible", + graph.getNode(GraphGenerator.SECOND_NODE).getTextProperties().isVisible()); + } + @Test public void testAndOperator() { Project project = projectController.newProject(); diff --git a/src/test/java/org/gephi/toolkit/GeneratorTest.java b/src/test/java/org/gephi/toolkit/GeneratorTest.java index 022be5c..c0d9cd4 100644 --- a/src/test/java/org/gephi/toolkit/GeneratorTest.java +++ b/src/test/java/org/gephi/toolkit/GeneratorTest.java @@ -36,6 +36,7 @@ */ package org.gephi.toolkit; +import org.gephi.graph.api.GraphModel; import org.gephi.io.generator.plugin.DynamicGraph; import org.gephi.io.generator.plugin.RandomGraph; import org.gephi.io.importer.api.Container; @@ -50,8 +51,6 @@ public class GeneratorTest extends ToolkitTest { @Test public void testGenerate() { - Workspace workspace = Utils.newWorkspace(); - //Generate a new random graph into a container Container container = Lookup.getDefault().lookup(Container.Factory.class).newContainer(); RandomGraph randomGraph = new RandomGraph(); @@ -60,7 +59,7 @@ public void testGenerate() { randomGraph.generate(container.getLoader()); //Append container to graph structure - importController.process(container, new DefaultProcessor(), workspace); + Workspace workspace = importController.process(container); Assert.assertEquals(randomGraph.getNumberOfNodes(), graphController.getGraphModel(workspace).getGraph().getNodeCount()); @@ -68,15 +67,14 @@ public void testGenerate() { @Test public void testGenerateDynamicGraph() { - Workspace workspace = Utils.newWorkspace(); - //Generate dynamic graph into workspace Container container = Lookup.getDefault().lookup(Container.Factory.class).newContainer(); DynamicGraph dynamicGraph = new DynamicGraph(); dynamicGraph.generate(container.getLoader()); - importController.process(container, new DefaultProcessor(), workspace); + Workspace workspace = importController.process(container); - Assert.assertTrue(graphController.getGraphModel(workspace).isDynamic()); + GraphModel graphModel = graphController.getGraphModel(workspace); + Assert.assertTrue(graphModel.isDynamic()); } } diff --git a/src/test/java/org/gephi/toolkit/ImportTest.java b/src/test/java/org/gephi/toolkit/ImportTest.java index c3d64b0..ed2d3ae 100644 --- a/src/test/java/org/gephi/toolkit/ImportTest.java +++ b/src/test/java/org/gephi/toolkit/ImportTest.java @@ -45,6 +45,7 @@ import org.gephi.io.processor.plugin.DefaultProcessor; import org.gephi.io.processor.plugin.MergeProcessor; import org.gephi.project.api.Project; +import org.gephi.project.api.Workspace; import org.junit.Assert; import org.junit.Test; @@ -52,8 +53,6 @@ public class ImportTest extends ToolkitTest { @Test public void testImport() throws IOException, URISyntaxException { - Project project = projectController.newProject(); - //Import file File file = new File(getClass().getResource("/org/gephi/toolkit/lesmiserables.gml").toURI()); Container container = importController.importFile(file); @@ -61,18 +60,47 @@ public void testImport() throws IOException, URISyntaxException { container.getLoader().setAllowAutoNode(false); //Don't create missing nodes //Append imported data to GraphAPI - importController.process(container, new DefaultProcessor(), project.getCurrentWorkspace()); + Workspace workspace = importController.process(container); //Assert - GraphModel graphModel = graphController.getGraphModel(project.getCurrentWorkspace()); + GraphModel graphModel = graphController.getGraphModel(workspace); Assert.assertEquals(77, graphModel.getGraph().getNodeCount()); Assert.assertEquals(254, graphModel.getGraph().getEdgeCount()); } @Test - public void testImportSlices() throws IOException, URISyntaxException { - Project project = projectController.newProject(); + public void testImportGexf() throws IOException, URISyntaxException { + //Import file + File file = new File(getClass().getResource("/org/gephi/toolkit/LesMiserables.gexf").toURI()); + Container container = importController.importFile(file); + container.getLoader().setEdgeDefault(EdgeDirectionDefault.DIRECTED); //Force DIRECTED + container.getLoader().setAllowAutoNode(false); //Don't create missing nodes + //Append imported data to GraphAPI + Workspace workspace = importController.process(container); + + //Assert + GraphModel graphModel = graphController.getGraphModel(workspace); + Assert.assertEquals(77, graphModel.getGraph().getNodeCount()); + Assert.assertEquals(254, graphModel.getGraph().getEdgeCount()); + } + + @Test + public void testImportGraphMLSingleIsolatedNode() throws IOException, URISyntaxException { + // Reproduces gephi/gephi-toolkit-demos#8: a GraphML file with a single isolated node + // was reported to import as 0 nodes. + File file = new File(getClass().getResource("/org/gephi/toolkit/singleNode.graphml").toURI()); + Container container = importController.importFile(file); + + Workspace workspace = importController.process(container); + + GraphModel graphModel = graphController.getGraphModel(workspace); + Assert.assertEquals(1, graphModel.getGraph().getNodeCount()); + Assert.assertEquals(0, graphModel.getGraph().getEdgeCount()); + } + + @Test + public void testImportSlices() throws IOException, URISyntaxException { Container[] containers = new Container[3]; for (int i = 0; i < 3; i++) { File file = new File(getClass().getResource("/org/gephi/toolkit/timeframe" + (i + 1) + ".gexf").toURI()); @@ -80,10 +108,10 @@ public void testImportSlices() throws IOException, URISyntaxException { } // Process the container using the MergeProcessor - importController.process(containers, new MergeProcessor(), project.getCurrentWorkspace()); + Workspace workspace = importController.process(containers, new MergeProcessor(), null)[0]; // Assert proper merging - GraphModel graphModel = graphController.getGraphModel(project.getCurrentWorkspace()); + GraphModel graphModel = graphController.getGraphModel(workspace); Assert.assertEquals(4, graphModel.getGraph().getNodeCount()); Assert.assertEquals(4, graphModel.getGraph().getEdgeCount()); diff --git a/src/test/java/org/gephi/toolkit/ProjectIOTest.java b/src/test/java/org/gephi/toolkit/ProjectIOTest.java index 64240c7..f83dcf0 100644 --- a/src/test/java/org/gephi/toolkit/ProjectIOTest.java +++ b/src/test/java/org/gephi/toolkit/ProjectIOTest.java @@ -39,11 +39,15 @@ import java.io.File; import java.io.IOException; import org.gephi.graph.GraphGenerator; +import org.gephi.preview.api.PreviewController; +import org.gephi.preview.api.PreviewModel; +import org.gephi.preview.api.PreviewProperty; import org.gephi.project.api.Project; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.openide.util.Lookup; public class ProjectIOTest extends ToolkitTest { @@ -70,6 +74,31 @@ public void testSave() throws IOException { assertTinyGraph(fileNotExisting); } + @Test + public void testSavePreviewModel() throws IOException { + Project project = projectController.newProject(); + + // Generate tiny graph + GraphGenerator.build(project.getCurrentWorkspace()).generateTinyGraph(); + + // Set a preview property + PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class); + PreviewModel previewModel = previewController.getModel(); + Assert.assertFalse(previewModel.getProperties().getBooleanValue(PreviewProperty.SHOW_NODE_LABELS)); + previewModel.getProperties().putValue(PreviewProperty.SHOW_NODE_LABELS, Boolean.TRUE); + + // Save + File file = new File(tempFolder.getRoot(), "testpreview.gephi"); + projectController.saveProject(project, file); + projectController.closeCurrentProject(); + + projectController.openProject(file); + PreviewModel readPreviewModel = previewController.getModel(); + Assert.assertNotSame(previewModel, readPreviewModel); + Assert.assertTrue(readPreviewModel.getProperties().getBooleanValue(PreviewProperty.SHOW_NODE_LABELS)); + projectController.closeCurrentProject(); + } + private void assertTinyGraph(File file) { projectController.closeCurrentProject(); Project project = projectController.openProject(file); diff --git a/src/test/resources/org/gephi/toolkit/singleNode.graphml b/src/test/resources/org/gephi/toolkit/singleNode.graphml new file mode 100644 index 0000000..ec7499c --- /dev/null +++ b/src/test/resources/org/gephi/toolkit/singleNode.graphml @@ -0,0 +1,6 @@ + + + + + +