提交 881958ba 编写于 作者: M Mathieu Bastian

Add support for appearance ui persistence

上级 87384ada
......@@ -16,7 +16,7 @@ import org.gephi.project.spi.WorkspacePersistenceProvider;
import org.gephi.project.spi.WorkspaceXMLPersistenceProvider;
import org.openide.util.lookup.ServiceProvider;
@ServiceProvider(service = WorkspacePersistenceProvider.class)
@ServiceProvider(service = WorkspacePersistenceProvider.class, position = 400)
public class AppearanceModelPersistenceProvider implements WorkspaceXMLPersistenceProvider {
......
......@@ -45,7 +45,6 @@ package org.gephi.appearance.plugin;
import java.awt.Color;
import java.io.Serializable;
import java.util.Arrays;
import org.gephi.appearance.api.Interpolator;
import org.gephi.appearance.api.Ranking;
import org.gephi.appearance.spi.RankingTransformer;
import org.gephi.appearance.spi.Transformer;
......@@ -94,6 +93,14 @@ public class RankingElementColorTransformer implements RankingTransformer<Elemen
linearGradient.setColors(colors);
}
public int[] getColorsAsRgba() {
return linearGradient.getColorsAsRgba();
}
public void setColorsAsRgba(int[] colors) {
linearGradient.setColorsAsRgba(colors);
}
public LinearGradient getLinearGradient() {
return linearGradient;
}
......@@ -149,6 +156,14 @@ public class RankingElementColorTransformer implements RankingTransformer<Elemen
this.colors = colors;
}
public int[] getColorsAsRgba() {
return Arrays.stream(colors).mapToInt(c -> (c.getAlpha() << 24) | c.getRGB()).toArray();
}
public void setColorsAsRgba(int[] colors) {
this.colors = Arrays.stream(colors).mapToObj(rgba -> new Color(rgba, true)).toArray(Color[]::new);
}
public float[] getPositions() {
return positions;
}
......
......@@ -44,6 +44,10 @@
<groupId>${project.groupId}</groupId>
<artifactId>ui-utils</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>utils</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>core-library-wrapper</artifactId>
......@@ -84,6 +88,12 @@
<scope>test</scope>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>project-api</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<build>
......
......@@ -60,6 +60,7 @@ import org.gephi.appearance.spi.RankingTransformer;
import org.gephi.appearance.spi.Transformer;
import org.gephi.appearance.spi.TransformerCategory;
import org.gephi.appearance.spi.TransformerUI;
import org.gephi.project.api.Workspace;
import org.gephi.ui.appearance.plugin.category.DefaultCategory;
/**
......@@ -102,7 +103,6 @@ public class AppearanceUIModel {
selectedAutoTransformer.put(elementClass, new HashMap<>());
selectedTransformerUI.put(elementClass, new HashMap<>());
Map<TransformerCategory, TransformerUI> newMap = new HashMap<>();
for (Function func : elementClass.equals(AppearanceUIController.NODE_ELEMENT) ?
appearanceModel.getNodeFunctions() : appearanceModel.getEdgeFunctions()) {
TransformerUI ui = func.getUI();
......@@ -146,11 +146,7 @@ public class AppearanceUIModel {
Function func = getSelectedFunction();
if (func != null) {
Transformer transformer = func.getTransformer();
Map<String, Object> props = savedProperties.get(func);
if (props == null) {
props = new HashMap<>();
savedProperties.put(func, new HashMap<String, Object>());
}
Map<String, Object> props = savedProperties.computeIfAbsent(func, k -> new HashMap<>());
for (Map.Entry<String, Method[]> entry : getProperties(transformer).entrySet()) {
String name = entry.getKey();
......@@ -234,6 +230,14 @@ public class AppearanceUIModel {
return null;
}
public Workspace getWorkspace() {
return appearanceModel.getWorkspace();
}
public AppearanceModel getAppearanceModel() {
return appearanceModel;
}
public Collection<Function> getFunctions() {
List<Function> functions = new ArrayList<>();
for (Function func : selectedElementClass.equalsIgnoreCase(AppearanceUIController.NODE_ELEMENT) ?
......@@ -316,7 +320,7 @@ public class AppearanceUIModel {
return true;
} else if (type.isArray()) {
Class cmp = type.getComponentType();
return cmp.isPrimitive() || cmp.equals(Color.class);
return cmp.isPrimitive();
} else {
return type.equals(Color.class);
}
......
package org.gephi.desktop.appearance;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.events.XMLEvent;
import org.gephi.appearance.api.AppearanceController;
import org.gephi.appearance.api.AppearanceModel;
import org.gephi.appearance.api.Function;
import org.gephi.project.api.Workspace;
import org.gephi.project.spi.WorkspacePersistenceProvider;
import org.gephi.project.spi.WorkspaceXMLPersistenceProvider;
import org.gephi.utils.Serialization;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
@ServiceProvider(service = WorkspacePersistenceProvider.class, position = 450)
public class AppearanceUIModelPersistenceProvider implements WorkspaceXMLPersistenceProvider {
@Override
public void writeXML(XMLStreamWriter writer, Workspace workspace) {
AppearanceUIModel model = workspace.getLookup().lookup(AppearanceUIModel.class);
if (model != null) {
try {
writeXML(writer, model);
} catch (XMLStreamException ex) {
throw new RuntimeException(ex);
}
}
}
@Override
public void readXML(XMLStreamReader reader, Workspace workspace) {
AppearanceUIModel model = workspace.getLookup().lookup(AppearanceUIModel.class);
AppearanceController appearanceController =
Lookup.getDefault().lookup(AppearanceController.class);
if (model == null) {
model = new AppearanceUIModel(appearanceController.getModel(workspace));
workspace.add(model);
}
try {
readXML(reader, model);
} catch (XMLStreamException ex) {
throw new RuntimeException(ex);
}
}
@Override
public String getIdentifier() {
return "appearanceuimodel";
}
protected void writeXML(XMLStreamWriter writer, AppearanceUIModel model)
throws XMLStreamException {
for (Map.Entry<Function, Map<String, Object>> savedProperty : model.savedProperties.entrySet()) {
writer.writeStartElement("savedproperty");
writer.writeAttribute("function", savedProperty.getKey().toString());
writeSavedProperty(writer, savedProperty.getValue());
writer.writeEndElement();
}
}
private void writeSavedProperty(XMLStreamWriter writer, Map<String, Object> savedProperty)
throws XMLStreamException {
for (Map.Entry<String, Object> entry : savedProperty.entrySet()) {
writer.writeStartElement("property");
writer.writeAttribute("key", entry.getKey());
writer.writeAttribute("value", Serialization.getValueAsText(entry.getValue()));
writer.writeAttribute("type", entry.getValue().getClass().getName());
writer.writeEndElement();
}
}
public void readXML(XMLStreamReader reader, AppearanceUIModel model) throws XMLStreamException {
AppearanceModel appearanceModel = model.appearanceModel;
Function[] functions = Stream.concat(Arrays.stream(appearanceModel.getNodeFunctions()),
Arrays.stream(appearanceModel.getEdgeFunctions()))
.toArray(Function[]::new);
Function function = null;
Map<String, Object> properties = null;
boolean end = false;
while (reader.hasNext() && !end) {
Integer eventType = reader.next();
if (eventType.equals(XMLEvent.START_ELEMENT)) {
String name = reader.getLocalName();
if ("savedproperty".equalsIgnoreCase(name)) {
String functionName = reader.getAttributeValue(null, "function");
function = Arrays.stream(functions).filter(f -> f.toString().equals(functionName)).findFirst()
.orElse(null);
properties = new HashMap<>();
} else if ("property".equalsIgnoreCase(name) && function != null) {
readSavedProperty(reader, properties);
}
} else if (eventType.equals(XMLStreamReader.END_ELEMENT)) {
if ("savedproperty".equalsIgnoreCase(reader.getLocalName()) && function != null) {
model.savedProperties.put(function, properties);
function = null;
properties = null;
} else if (getIdentifier().equalsIgnoreCase(reader.getLocalName())) {
end = true;
}
}
}
}
private void readSavedProperty(XMLStreamReader reader, Map<String, Object> map) throws XMLStreamException {
String key = reader.getAttributeValue(null, "key");
String value = reader.getAttributeValue(null, "value");
String type = reader.getAttributeValue(null, "type");
Object val = Serialization.readValueFromText(value, type);
if (val != null) {
map.put(key, val);
}
}
}
package org.gephi.desktop.appearance;
import org.gephi.appearance.api.Function;
import org.gephi.appearance.plugin.RankingElementColorTransformer;
import org.gephi.appearance.plugin.RankingNodeSizeTransformer;
import org.gephi.appearance.plugin.UniqueElementColorTransformer;
import org.gephi.appearance.plugin.UniqueNodeSizeTransformer;
import org.gephi.desktop.appearance.utils.Utils;
import org.gephi.project.api.Workspace;
import org.gephi.project.io.utils.GephiFormat;
import org.junit.Assert;
import org.junit.Test;
public class PersistenceProviderTest {
@Test
public void testEmpty() throws Exception {
AppearanceUIModel model = Utils.newAppearanceUIModel();
GephiFormat
.testXMLPersistenceProvider(new AppearanceUIModelPersistenceProvider(), model.getWorkspace());
}
@Test
public void testUniqueColor() throws Exception {
AppearanceUIModel model = Utils.newAppearanceUIModel();
Function function = Utils.findNodeFunction(model, UniqueElementColorTransformer.class);
model.setSelectedFunction(function);
Assert.assertNotNull(function);
Assert.assertFalse(model.savedProperties.isEmpty());
Workspace workspace = GephiFormat
.testXMLPersistenceProvider(new AppearanceUIModelPersistenceProvider(), model.getWorkspace());
AppearanceUIModel readModel = workspace.getLookup().lookup(AppearanceUIModel.class);
Assert.assertEquals(model.savedProperties, readModel.savedProperties);
}
@Test
public void testUniqueSize() throws Exception {
AppearanceUIModel model = Utils.newAppearanceUIModel();
Function function = Utils.findNodeFunction(model, UniqueNodeSizeTransformer.class);
Assert.assertNotNull(function);
model.setSelectedFunction(function);
model.saveTransformerProperties();
Assert.assertTrue(model.savedProperties.containsKey(function));
Workspace workspace = GephiFormat
.testXMLPersistenceProvider(new AppearanceUIModelPersistenceProvider(), model.getWorkspace());
AppearanceUIModel readModel = workspace.getLookup().lookup(AppearanceUIModel.class);
Assert.assertEquals(model.savedProperties, readModel.savedProperties);
}
@Test
public void testRankingColor() throws Exception {
AppearanceUIModel model = Utils.newAppearanceUIModel();
Function function = Utils.findNodeFunction(model, RankingElementColorTransformer.class);
Assert.assertNotNull(function);
model.setSelectedFunction(function);
model.saveTransformerProperties();
Assert.assertTrue(model.savedProperties.containsKey(function));
Workspace workspace = GephiFormat
.testXMLPersistenceProvider(new AppearanceUIModelPersistenceProvider(), model.getWorkspace());
AppearanceUIModel readModel = workspace.getLookup().lookup(AppearanceUIModel.class);
Assert.assertEquals(model.savedProperties, readModel.savedProperties);
}
@Test
public void testRankingSize() throws Exception {
AppearanceUIModel model = Utils.newAppearanceUIModel();
Function function = Utils.findNodeFunction(model, RankingNodeSizeTransformer.class);
Assert.assertNotNull(function);
model.setSelectedFunction(function);
Assert.assertFalse(model.savedProperties.isEmpty());
Workspace workspace = GephiFormat
.testXMLPersistenceProvider(new AppearanceUIModelPersistenceProvider(), model.getWorkspace());
AppearanceUIModel readModel = workspace.getLookup().lookup(AppearanceUIModel.class);
Assert.assertEquals(model.savedProperties, readModel.savedProperties);
}
}
package org.gephi.desktop.appearance.utils;
import java.util.Arrays;
import java.util.stream.Stream;
import org.gephi.appearance.AppearanceModelImpl;
import org.gephi.appearance.api.Function;
import org.gephi.appearance.spi.Transformer;
import org.gephi.desktop.appearance.AppearanceUIModel;
import org.gephi.graph.GraphGenerator;
import org.gephi.graph.api.Node;
public class Utils {
public static AppearanceUIModel newAppearanceUIModel() {
GraphGenerator generator =
GraphGenerator.build().withWorkspace().generateTinyGraph();
AppearanceModelImpl model = new AppearanceModelImpl(generator.getWorkspace());
model.getWorkspace().add(model);
AppearanceUIModel uiModel = new AppearanceUIModel(model);
model.getWorkspace().add(uiModel);
return uiModel;
}
public static Function findNodeFunction(AppearanceUIModel model, Class<? extends Transformer> transformer) {
Function[] functions = Stream.concat(Arrays.stream(model.getAppearanceModel().getNodeFunctions()),
Arrays.stream(model.getAppearanceModel().getEdgeFunctions()))
.toArray(Function[]::new);
return Arrays.stream(functions).filter(
f -> f.getElementClass().isAssignableFrom(Node.class) && f.getTransformer().getClass().equals(transformer))
.findFirst().orElse(null);
}
}
......@@ -46,6 +46,7 @@ import java.awt.Font;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Method;
import org.gephi.graph.api.AttributeUtils;
import org.gephi.graph.api.GraphModel;
/**
......@@ -177,6 +178,8 @@ public class Serialization {
} else if (isPrimitiveOrPrimitiveWrapper(valueClass) ||
(Number.class.isAssignableFrom(valueClass) && !Number.class.equals(valueClass))) {
return String.valueOf(value);
} else if (valueClass.isArray()) {
return AttributeUtils.printArray(value);
} else {
PropertyEditor editor = PropertyEditorManager.findEditor(valueClass);
if (editor != null) {
......@@ -222,6 +225,8 @@ public class Serialization {
return parsePrimitiveOrWrapper(valueClass, valueStr);
} else if (Number.class.isAssignableFrom(valueClass) && !Number.class.equals(valueClass)) {
return NumberUtils.parseNumber(valueStr, valueClass);
} else if (valueClass.isArray()) {
return AttributeUtils.parse(valueStr, valueClass);
} else {
PropertyEditor editor = PropertyEditorManager.findEditor(valueClass);
if (editor != null) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册