--- /dev/null
+package org.simantics.browsing.ui.common.state;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.simantics.browsing.ui.ExplorerState;
+import org.simantics.browsing.ui.NodeContext;
+import org.simantics.browsing.ui.StatePersistor;
+import org.simantics.databoard.util.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class IdentifiedStatePersistor implements StatePersistor {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(IdentifiedStatePersistor.class);
+
+ protected final String id;
+
+ public IdentifiedStatePersistor(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public ExplorerState deserialize(File stateLocation, NodeContext root) {
+ return stateLocation == null ? ExplorerState.EMPTY
+ : deserialize(getMementoPath(stateLocation, root));
+ }
+
+ @Override
+ public void serialize(File stateLocation, NodeContext root, ExplorerState state) {
+ if (stateLocation == null || root == null)
+ return;
+ try {
+ GraphExplorerStateBean bean = toStateBean(state, root);
+ Path memento = getMementoPath(stateLocation, root);
+ if (bean != null && memento != null)
+ Files.write(memento, bean.serialize());
+ } catch (Throwable t) {
+ LOGGER.error("Failed to serialize ExplorerState " + state, t);
+ }
+ }
+
+ protected ExplorerState deserialize(Path path) {
+ if (path == null || !Files.exists(path))
+ return ExplorerState.EMPTY;
+ try {
+ GraphExplorerStateBean stateBean = new GraphExplorerStateBean();
+ stateBean.deserialize( Files.readAllBytes(path) );
+ return toState(stateBean);
+ } catch (Throwable t) {
+ LOGGER.error("Failed to deserialize ExplorerState from " + path, t);
+ return ExplorerState.EMPTY;
+ }
+ }
+
+ protected NodeContext[] toNodeContexts(GraphExplorerStateNodeBean[] beans) throws Exception {
+ return NodeContext.NONE;
+ }
+
+ protected List<NodeContext> toNodeContextList(GraphExplorerStateNodeBean[] beans) throws Exception {
+ return beans.length == 0 ? Collections.<NodeContext>emptyList()
+ : Arrays.asList(toNodeContexts(beans));
+ }
+
+ protected GraphExplorerStateNodeBean[] toNodeBeans(NodeContext[] contexts) {
+ return GraphExplorerStateNodeBean.NONE;
+ }
+
+ protected ExplorerState toState(GraphExplorerStateBean stateBean) throws Exception {
+ return new ExplorerState(
+ toNodeContexts(stateBean.topNodePath),
+ stateBean.topNodePathChildIndexes,
+ toNodeContextList(stateBean.expandedNodes),
+ stateBean.columnWidths);
+ }
+
+ /**
+ * @param state
+ * the {@link ExplorerState} to transform into a
+ * {@link GraphExplorerStateBean}
+ * @param root
+ * the input root node context that was used to initialize the
+ * explorer state
+ * @return
+ */
+ protected GraphExplorerStateBean toStateBean(ExplorerState state, NodeContext root) {
+ GraphExplorerStateBean ib = new GraphExplorerStateBean();
+ ib.topNodePath = toNodeBeans(state.topNodePath);
+ ib.topNodePathChildIndexes = state.topNodePathChildIndex;
+ ib.expandedNodes = toNodeBeans(state.expandedNodes.toArray(NodeContext.NONE));
+ ib.columnWidths = state.columnWidths;
+ return ib;
+ }
+
+ protected Path getMementoPath(File stateLocation, NodeContext root) {
+ return stateLocation.toPath().resolve(StringUtil.escapeToFileName(id) + ".ge");
+ }
+
+}
\ No newline at end of file