UI locking fixes for GraphExplorer implementations 69/2369/4
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Sat, 27 Oct 2018 17:35:14 +0000 (20:35 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Sat, 27 Oct 2018 21:15:41 +0000 (00:15 +0300)
GraphExplorer implementations contained ExplorerState restore code that
was ran synchronously in the UI thread. It will possibly require DB read
transactions which locks the UI up. Persisted explorer state loading has
now been moved into a Job from GraphExplorer implementations and
GraphExplorerComposite.

Also contains fixes for doSetColumns of all graph explorer
implementations which was using a Map with the wrong keys.

gitlab #160

Change-Id: I879fe4a099db70d5d8bbba185b4dc9d745c80911

12 files changed:
bundles/org.simantics.browsing.ui.common/META-INF/MANIFEST.MF
bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/ExplorerStates.java [new file with mode: 0644]
bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/GraphExplorerStateBean.java [moved from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerStateBean.java with 95% similarity]
bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/GraphExplorerStateNodeBean.java [moved from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerStateNodeBean.java with 94% similarity]
bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/IdentifiedStatePersistor.java [moved from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/IdentifiedStatePersistor.java with 89% similarity]
bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/StringArrayBean.java [moved from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/StringArrayBean.java with 94% similarity]
bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/StringBean.java [moved from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/StringBean.java with 94% similarity]
bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableGraphExplorer.java
bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerImpl.java
bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerImpl2.java
bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/widgets/GraphExplorerComposite.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/function/StandardPersistor.java

index 4da99a1260a8210d2b1681de5f13b5186a1ef8fb..b33d37df42e03f5c4d706c3cfc5a89d4379a60e9 100644 (file)
@@ -24,6 +24,7 @@ Export-Package: org.simantics.browsing.ui.common,
  org.simantics.browsing.ui.common.node,
  org.simantics.browsing.ui.common.processors,
  org.simantics.browsing.ui.common.property,
+ org.simantics.browsing.ui.common.state,
  org.simantics.browsing.ui.common.viewpoints,
  org.simantics.browsing.ui.common.views
 Bundle-Vendor: VTT Technical Research Center of Finland
diff --git a/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/ExplorerStates.java b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/ExplorerStates.java
new file mode 100644 (file)
index 0000000..380968b
--- /dev/null
@@ -0,0 +1,60 @@
+package org.simantics.browsing.ui.common.state;
+
+import java.io.File;
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.simantics.DatabaseJob;
+import org.simantics.browsing.ui.ExplorerState;
+import org.simantics.browsing.ui.NodeContext;
+import org.simantics.browsing.ui.StatePersistor;
+import org.simantics.browsing.ui.common.Activator;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.36.0
+ */
+public class ExplorerStates {
+
+    public static File explorerStateLocation() {
+        return Platform.getStateLocation(Activator.getDefault().getBundle()).toFile();
+    }
+
+    public static CompletableFuture<ExplorerState> scheduleRead(NodeContext root, StatePersistor persistor) {
+        CompletableFuture<ExplorerState> result = new CompletableFuture<>();
+        new ReaderJob(root, persistor, result).schedule();
+        return result;
+    }
+
+    private static class ReaderJob extends DatabaseJob {
+
+        private NodeContext root;
+        private StatePersistor persistor;
+        private CompletableFuture<ExplorerState> consumer;
+
+        public ReaderJob(NodeContext root, StatePersistor persistor, CompletableFuture<ExplorerState> consumer) {
+            super("Reading previous graph explorer state");
+            this.root = root;
+            this.persistor = persistor;
+            this.consumer = consumer;
+        }
+
+        @Override
+        protected IStatus run(IProgressMonitor monitor) {
+            try {
+                monitor.beginTask("Loading persisted data", 1);
+                ExplorerState state = persistor.deserialize(explorerStateLocation(), root);
+                monitor.worked(1);
+                consumer.complete(state);
+                return Status.OK_STATUS;
+            } finally {
+                monitor.done();
+            }
+        }
+
+    }
+
+}
similarity index 95%
rename from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerStateBean.java
rename to bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/GraphExplorerStateBean.java
index c9bf211dd9028f94c63b6a316567a60dff8a83c2..7b4d7877e6d608d6953737c16ee0ac82f6fe578c 100644 (file)
@@ -9,7 +9,7 @@
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
  *******************************************************************************/
-package org.simantics.browsing.ui.swt;
+package org.simantics.browsing.ui.common.state;
 
 import java.util.Map;
 
similarity index 94%
rename from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerStateNodeBean.java
rename to bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/GraphExplorerStateNodeBean.java
index 49831e28c0b44ae0288fbfd807e73a5725abc126..67c5c9d7a54a0833bea422443b191759825c356d 100644 (file)
@@ -9,7 +9,7 @@
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
  *******************************************************************************/
-package org.simantics.browsing.ui.swt;
+package org.simantics.browsing.ui.common.state;
 
 import java.util.TreeMap;
 
similarity index 89%
rename from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/IdentifiedStatePersistor.java
rename to bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/IdentifiedStatePersistor.java
index 5a3bb75b225af675b90ca05a2bbb021343ba8965..0a417bd389c32ca8b2368888c3fb3ebef06fe2dc 100644 (file)
@@ -1,4 +1,4 @@
-package org.simantics.browsing.ui.swt;
+package org.simantics.browsing.ui.common.state;
 
 import java.io.File;
 import java.nio.file.Files;
@@ -11,13 +11,16 @@ 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.simantics.db.common.utils.Logger;
+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) {
@@ -40,7 +43,7 @@ public class IdentifiedStatePersistor implements StatePersistor {
                        if (bean != null && memento != null)
                                Files.write(memento, bean.serialize());
                } catch (Throwable t) {
-                       Logger.defaultLogError(t);
+                       LOGGER.error("Failed to serialize ExplorerState " + state, t);
                }
        }
 
@@ -52,7 +55,7 @@ public class IdentifiedStatePersistor implements StatePersistor {
                        stateBean.deserialize( Files.readAllBytes(path) );
                        return toState(stateBean);
                } catch (Throwable t) {
-                       Logger.defaultLogError(t);
+                       LOGGER.error("Failed to deserialize ExplorerState from " + path, t);
                        return ExplorerState.EMPTY;
                }
        }
similarity index 94%
rename from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/StringArrayBean.java
rename to bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/StringArrayBean.java
index 219db8364e5c322d27e9775d662a4358f36ffb54..90ff79a142929d52c9017deeb9d523b9b14ea887 100644 (file)
@@ -9,7 +9,7 @@
  * Contributors:
  *     Semantum Oy - initial API and implementation
  *******************************************************************************/
-package org.simantics.browsing.ui.swt;
+package org.simantics.browsing.ui.common.state;
 
 import org.simantics.databoard.annotations.Optional;
 import org.simantics.databoard.util.Bean;
similarity index 94%
rename from bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/StringBean.java
rename to bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/state/StringBean.java
index c584da059eb55970d0168e0518296acc6ba21425..c2b435648fe17051f72c34ed89fca950178cb6ec 100644 (file)
@@ -9,7 +9,7 @@
  * Contributors:
  *     Semantum Oy - initial API and implementation
  *******************************************************************************/
-package org.simantics.browsing.ui.swt;
+package org.simantics.browsing.ui.common.state;
 
 import org.simantics.databoard.annotations.Optional;
 import org.simantics.databoard.util.Bean;
index be6a73a0c05dbff44a460e4b5de85bd9000947fb..37eafd4eb5e965e1e1811fc418576e8a37535b21 100644 (file)
@@ -26,7 +26,6 @@ import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.resource.ColorDescriptor;
@@ -172,6 +171,7 @@ import org.simantics.browsing.ui.common.processors.DefaultViewpointProcessor;
 import org.simantics.browsing.ui.common.processors.IsExpandedProcessor;
 import org.simantics.browsing.ui.common.processors.NoSelectionRequestProcessor;
 import org.simantics.browsing.ui.common.processors.ProcessorLifecycle;
+import org.simantics.browsing.ui.common.state.ExplorerStates;
 import org.simantics.browsing.ui.content.Labeler;
 import org.simantics.browsing.ui.content.Labeler.CustomModifier;
 import org.simantics.browsing.ui.content.Labeler.DialogModifier;
@@ -198,6 +198,7 @@ import org.simantics.utils.threads.SWTThread;
 import org.simantics.utils.threads.ThreadUtils;
 import org.simantics.utils.ui.AdaptionUtils;
 import org.simantics.utils.ui.ISelectionUtils;
+import org.simantics.utils.ui.SWTUtils;
 import org.simantics.utils.ui.jface.BasePostSelectionProvider;
 
 import gnu.trove.map.hash.THashMap;
@@ -580,17 +581,16 @@ public class NatTableGraphExplorer extends GraphExplorerImplBase implements Grap
     private void initializeState() {
         if (persistor == null)
             return;
+        ExplorerStates.scheduleRead(getRoot(), persistor)
+        .thenAccept(state -> SWTUtils.asyncExec(natTable, () -> restoreState(state)));
+    }
 
-        ExplorerState state = persistor.deserialize(
-                Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
-                getRoot());
-
-
+    private void restoreState(ExplorerState state) {
         Object processor = getPrimitiveProcessor(BuiltinKeys.IS_EXPANDED);
         if (processor instanceof DefaultIsExpandedProcessor) {
             DefaultIsExpandedProcessor isExpandedProcessor = (DefaultIsExpandedProcessor)processor;
             for(NodeContext expanded : state.expandedNodes) {
-                isExpandedProcessor.setExpanded(expanded, true);
+                isExpandedProcessor.replaceExpanded(expanded, true);
             }
         }
     }
index 3cf5f7478cd7af3dc23ff412db75eac0628f87c1..df736c1e6dc2603315bea23f47b46a2170a52f55 100644 (file)
@@ -39,7 +39,6 @@ import org.eclipse.core.runtime.AssertionFailedException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.action.IStatusLineManager;
@@ -145,6 +144,7 @@ import org.simantics.browsing.ui.common.processors.DefaultViewpointProcessor;
 import org.simantics.browsing.ui.common.processors.IsExpandedProcessor;
 import org.simantics.browsing.ui.common.processors.NoSelectionRequestProcessor;
 import org.simantics.browsing.ui.common.processors.ProcessorLifecycle;
+import org.simantics.browsing.ui.common.state.ExplorerStates;
 import org.simantics.browsing.ui.content.ImageDecorator;
 import org.simantics.browsing.ui.content.Imager;
 import org.simantics.browsing.ui.content.LabelDecorator;
@@ -169,6 +169,7 @@ import org.simantics.utils.threads.IThreadWorkQueue;
 import org.simantics.utils.threads.SWTThread;
 import org.simantics.utils.threads.ThreadUtils;
 import org.simantics.utils.ui.ISelectionUtils;
+import org.simantics.utils.ui.SWTUtils;
 import org.simantics.utils.ui.jface.BasePostSelectionProvider;
 import org.simantics.utils.ui.widgets.VetoingEventHandler;
 import org.simantics.utils.ui.workbench.WorkbenchUtils;
@@ -1883,15 +1884,15 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
             });
         }
     }
-    
+
     private void initializeState() {
         if (persistor == null)
             return;
+        ExplorerStates.scheduleRead(getRoot(), persistor)
+        .thenAccept(state -> SWTUtils.asyncExec(tree, () -> restoreState(state)));
+    }
 
-        ExplorerState state = persistor.deserialize(
-                Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
-                getRoot());
-
+    private void restoreState(ExplorerState state) {
         // topNodeToSet will be processed by #setData when it encounters a
         // NodeContext that matches this one.
 //        topNodePath = state.topNodePath;
@@ -1902,7 +1903,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         if (processor instanceof DefaultIsExpandedProcessor) {
             DefaultIsExpandedProcessor isExpandedProcessor = (DefaultIsExpandedProcessor)processor;
             for(NodeContext expanded : state.expandedNodes) {
-                isExpandedProcessor.setExpanded(expanded, true);
+                isExpandedProcessor.replaceExpanded(expanded, true);
             }
         }
     }
@@ -1947,7 +1948,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         }
                    
         persistor.serialize(
-                Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
+                ExplorerStates.explorerStateLocation(),
                 getRoot(),
                 new ExplorerState(topNodePath, topNodePathChildIndex, expandedNodes, columnWidths));
     }
@@ -3251,13 +3252,16 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
      */
     private void doSetColumns(Column[] cols, Consumer<Map<Column, Object>> callback) {
         // Attempt to keep previous column widths.
-        Map<String, Integer> prevWidths = new HashMap<String, Integer>();
+        Map<String, Integer> prevWidths = new HashMap<>();
         for (TreeColumn column : tree.getColumns()) {
-            prevWidths.put(column.getText(), column.getWidth());
-            column.dispose();
+            Column c = (Column) column.getData();
+            if (c != null) {
+                prevWidths.put(c.getKey(), column.getWidth());
+                column.dispose();
+            }
         }
 
-        HashMap<String, Integer> keyToIndex = new HashMap<String, Integer>();
+        HashMap<String, Integer> keyToIndex = new HashMap<>();
         for (int i = 0; i < cols.length; ++i) {
             keyToIndex.put(cols[i].getKey(), i);
         }
@@ -3268,7 +3272,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         this.columnImageArray = new Image[cols.length];
         this.columnDescOrImageArray = new Object[cols.length];
 
-        Map<Column, Object> map = new HashMap<Column, Object>();
+        Map<Column, Object> map = new HashMap<>();
 
         tree.setHeaderVisible(columnsAreVisible);
         for (Column column : columns) {
@@ -3281,7 +3285,7 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
             int cw = column.getWidth();
 
             // Try to keep previous widths
-            Integer w = prevWidths.get(column);
+            Integer w = prevWidths.get(column.getKey());
             if (w != null)
                 c.setWidth(w);
             else if (cw != Column.DEFAULT_CONTROL_WIDTH)
@@ -3306,13 +3310,9 @@ class GraphExplorerImpl extends GraphExplorerImplBase implements Listener, Graph
         if(callback != null) callback.accept(map);
 
         // Make sure the explorer fits the columns properly after initialization.
-        tree.getDisplay().asyncExec(new Runnable() {
-            @Override
-            public void run() {
-                if (tree.isDisposed())
-                    return;
+        SWTUtils.asyncExec(tree, () -> {
+            if (!tree.isDisposed())
                 refreshColumnSizes();
-            }
         });
     }
 
index af0fa25a355019468aecd5a89f6a6f950e69833e..c21158e31a65785d8a9dd5d7df728871af63a785 100644 (file)
@@ -38,7 +38,6 @@ import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.layout.GridDataFactory;
@@ -154,6 +153,7 @@ import org.simantics.browsing.ui.common.processors.DefaultViewpointProcessor;
 import org.simantics.browsing.ui.common.processors.IsExpandedProcessor;
 import org.simantics.browsing.ui.common.processors.NoSelectionRequestProcessor;
 import org.simantics.browsing.ui.common.processors.ProcessorLifecycle;
+import org.simantics.browsing.ui.common.state.ExplorerStates;
 import org.simantics.browsing.ui.content.ImageDecorator;
 import org.simantics.browsing.ui.content.Imager;
 import org.simantics.browsing.ui.content.LabelDecorator;
@@ -174,6 +174,7 @@ import org.simantics.utils.threads.SWTThread;
 import org.simantics.utils.threads.ThreadUtils;
 import org.simantics.utils.ui.AdaptionUtils;
 import org.simantics.utils.ui.ISelectionUtils;
+import org.simantics.utils.ui.SWTUtils;
 import org.simantics.utils.ui.jface.BasePostSelectionProvider;
 
 import gnu.trove.map.hash.THashMap;
@@ -574,17 +575,16 @@ public class GraphExplorerImpl2 extends GraphExplorerImplBase implements GraphEx
     private void initializeState() {
         if (persistor == null)
             return;
+        ExplorerStates.scheduleRead(getRoot(), persistor)
+        .thenAccept(state -> SWTUtils.asyncExec(viewer.getTree(), () -> restoreState(state)));
+    }
 
-        ExplorerState state = persistor.deserialize(
-                Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
-                getRoot());
-
-
+    private void restoreState(ExplorerState state) {
         Object processor = getPrimitiveProcessor(BuiltinKeys.IS_EXPANDED);
         if (processor instanceof DefaultIsExpandedProcessor) {
             DefaultIsExpandedProcessor isExpandedProcessor = (DefaultIsExpandedProcessor)processor;
             for(NodeContext expanded : state.expandedNodes) {
-                isExpandedProcessor.setExpanded(expanded, true);
+                isExpandedProcessor.replaceExpanded(expanded, true);
             }
         }
     }
@@ -717,13 +717,14 @@ public class GraphExplorerImpl2 extends GraphExplorerImplBase implements GraphEx
     
     private void doSetColumns(Column[] cols, Consumer<Map<Column, Object>> callback) {
         // Attempt to keep previous column widths.
-        Map<String, Integer> prevWidths = new HashMap<String, Integer>();
-        
+        Map<String, Integer> prevWidths = new HashMap<>();
         for (TreeViewerColumn c : treeViewerColumns) {
-               prevWidths.put(c.getColumn().getText(), c.getColumn().getWidth());
-               c.getColumn().dispose();
+            Column col = (Column) (c.getColumn().getData());
+            if (col != null)
+                prevWidths.put(col.getKey(), c.getColumn().getWidth());
+            c.getColumn().dispose();
         }
-       
+
         treeViewerColumns.clear();
         
         HashMap<String, Integer> keyToIndex = new HashMap<String, Integer>();
@@ -765,7 +766,7 @@ public class GraphExplorerImpl2 extends GraphExplorerImplBase implements GraphEx
             int cw = column.getWidth();
 
             // Try to keep previous widths
-            Integer w = prevWidths.get(column);
+            Integer w = prevWidths.get(column.getKey());
             if (w != null)
                 c.setWidth(w);
             else if (cw != Column.DEFAULT_CONTROL_WIDTH)
@@ -2487,11 +2488,11 @@ public class GraphExplorerImpl2 extends GraphExplorerImplBase implements GraphEx
                        return context == null;
                }
                
-               @SuppressWarnings("rawtypes")
+               @SuppressWarnings("unchecked")
                @Override
-               public Object getAdapter(Class adapter) {
+               public <T> T getAdapter(Class<T> adapter) {
                        if (adapter == NodeContext.class)
-                               return context;
+                               return (T) context;
                        return context.getAdapter(adapter);
                }
                
@@ -2712,9 +2713,8 @@ public class GraphExplorerImpl2 extends GraphExplorerImplBase implements GraphEx
             * store the key, this is not used.
             */
            NodeContext getNC = new NodeContext() {
-               @SuppressWarnings("rawtypes")
-                       @Override
-               public Object getAdapter(Class adapter) {
+               @Override
+               public <T> T getAdapter(Class<T> adapter) {
                        return null;
                }
                
index 42ee2bdf812fe788e20b040139ac9ae9df4fdce6..2f52153a1192b45e2a6c33e42afd2da58a86e1a1 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management
  * in Industry THTH ry.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -17,10 +17,8 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.BiFunction;
-import java.util.function.Consumer;
 
 import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.layout.GridDataFactory;
 import org.eclipse.jface.layout.GridLayoutFactory;
@@ -45,7 +43,6 @@ import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
 import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.ui.ISelectionListener;
 import org.eclipse.ui.IWorkbenchSite;
@@ -72,6 +69,7 @@ import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
+import org.simantics.browsing.ui.common.state.ExplorerStates;
 import org.simantics.browsing.ui.common.views.FilterAreaSource;
 import org.simantics.browsing.ui.common.views.IFilterArea;
 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
@@ -83,7 +81,6 @@ import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor;
 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
 import org.simantics.browsing.ui.model.nodetypes.NodeType;
-import org.simantics.browsing.ui.swt.Activator;
 import org.simantics.browsing.ui.swt.ComparatorSelector;
 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
 import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener;
@@ -135,6 +132,7 @@ import org.simantics.utils.datastructures.hints.IHintContext.Key;
 import org.simantics.utils.datastructures.hints.IHintListener;
 import org.simantics.utils.datastructures.hints.IHintObservable;
 import org.simantics.utils.datastructures.hints.IHintTracker;
+import org.simantics.utils.ui.SWTUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -1194,52 +1192,48 @@ public class GraphExplorerComposite extends Composite implements Widget, IAdapta
     }
 
     private int getColumnWidth(Column column, ExplorerState state) {
-       // Get saved width from the persistor if there is one.
+        // Get saved width from the persistor if there is one.
         if (state != null && state.columnWidths != null) {
-               Integer width = state.columnWidths.get(column.getLabel());
-               if (width != null)
-                       return width;
+            Integer width = state.columnWidths.get(column.getLabel());
+            if (width != null)
+                return width;
         }
         return column.getWidth();
     }
-    
-    public void setColumns(Column[] columns) {
-
-        explorer.setColumns(columns, new Consumer<Map<Column, Object>>() {
-
-            @Override
-            public void accept(Map<Column, Object> objects) {
-               ExplorerState state = null;
-               if (persistor != null) {
-                       state = persistor.deserialize(
-                               Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
-                               explorer.getRoot());
-               }
-
-                for(Map.Entry<Column, Object> entry : objects.entrySet()) {
-                    Column column = entry.getKey();
-                    TreeColumn treeColumn = (TreeColumn)entry.getValue();
-
-                    if (column.getWidth() < 0) {
-                        throw new IllegalArgumentException("Column minimum width cannot be < 0, got " + column.getWidth());
-                    }
-
-                    int width = getColumnWidth(column, state);
-                    if(column.hasGrab()) {
-                       
-                        ad.setColumnData(treeColumn, new ColumnWeightData(column.getWeight(), width));
-
-                    } else {
-
-                        ad.setColumnData(treeColumn, new ColumnWeightData(0, width));
 
-                    }
-
-                }
-            }
+    protected void restoreColumnSizes(Map<Column, Object> columns) {
+        if (persistor != null) {
+            setColumnData(columns, null);
+            ExplorerStates.scheduleRead(explorer.getRoot(), persistor).thenAccept(state -> {
+                SWTUtils.asyncExec(GraphExplorerComposite.this, () -> {
+                    if (explorerComposite.isDisposed())
+                        setColumnData(columns, state);
+                });
+            });
+        } else {
+            setColumnData(columns, null);
+        }
+    }
 
+    protected void setColumnData(Map<Column, Object> columns, ExplorerState state) {
+        columns.forEach((column, widget) -> {
+            org.eclipse.swt.widgets.Widget columnWidget = (org.eclipse.swt.widgets.Widget) widget;
+            ad.setColumnData(columnWidget,
+                    new ColumnWeightData(
+                            column.hasGrab() ? column.getWeight() : 0,
+                            getColumnWidth(column, state)));
         });
+    }
 
+    public void setColumns(Column[] columns) {
+        // ColumnWeightData does not support column weight/width < 0
+        for (Column column : columns) {
+            if (column.getWeight() < 0)
+                throw new IllegalArgumentException("Column weight must be >= 0, got " + column.getWeight() + " for " + column);
+            if (column.getWidth() < 0)
+                throw new IllegalArgumentException("Column minimum width must be >= 0, got " + column.getWidth() + " for " + column);
+        }
+        explorer.setColumns(columns, this::restoreColumnSizes);
     }
 
     @Override
index c8bf80cd8520b8152e994f93f48ae6b69650da57..21126cccca89eebcac44a0f3cae4df133922a77e 100644 (file)
@@ -24,18 +24,18 @@ import org.simantics.browsing.ui.NodeContext;
 import org.simantics.browsing.ui.NodeContext.ConstantKey;
 import org.simantics.browsing.ui.common.NodeContextBuilder;
 import org.simantics.browsing.ui.common.NodeContextBuilder.MapNodeContext;
+import org.simantics.browsing.ui.common.state.GraphExplorerStateBean;
+import org.simantics.browsing.ui.common.state.GraphExplorerStateNodeBean;
+import org.simantics.browsing.ui.common.state.IdentifiedStatePersistor;
+import org.simantics.browsing.ui.common.state.StringArrayBean;
+import org.simantics.browsing.ui.common.state.StringBean;
 import org.simantics.browsing.ui.model.actions.ActionBrowseContext;
 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
 import org.simantics.browsing.ui.model.browsecontexts.BrowseContexts;
 import org.simantics.browsing.ui.model.nodetypes.EntityNodeType;
 import org.simantics.browsing.ui.model.nodetypes.NodeType;
 import org.simantics.browsing.ui.model.nodetypes.SpecialNodeType;
-import org.simantics.browsing.ui.swt.GraphExplorerStateBean;
-import org.simantics.browsing.ui.swt.GraphExplorerStateNodeBean;
-import org.simantics.browsing.ui.swt.IdentifiedStatePersistor;
 import org.simantics.browsing.ui.swt.NodeContextValueBean;
-import org.simantics.browsing.ui.swt.StringArrayBean;
-import org.simantics.browsing.ui.swt.StringBean;
 import org.simantics.databoard.Bindings;
 import org.simantics.databoard.binding.impl.ArrayListBinding;
 import org.simantics.databoard.util.Bean;