]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/NodePropertyTester.java
Merge remote-tracking branch 'origin/svn' commit 'ccc1271c9d6657fb9dcf4cf3cb115fa0c8c...
[simantics/platform.git] / bundles / org.simantics.browsing.ui.swt / src / org / simantics / browsing / ui / swt / NodePropertyTester.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2012 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.browsing.ui.swt;\r
13 \r
14 import java.util.List;\r
15 \r
16 import org.eclipse.core.expressions.PropertyTester;\r
17 import org.eclipse.jface.viewers.ISelection;\r
18 import org.simantics.DatabaseJob;\r
19 import org.simantics.Simantics;\r
20 import org.simantics.browsing.ui.BuiltinKeys;\r
21 import org.simantics.browsing.ui.NodeContext;\r
22 import org.simantics.browsing.ui.common.node.IDeletable;\r
23 import org.simantics.browsing.ui.common.node.IModifiable;\r
24 import org.simantics.browsing.ui.common.node.IRefreshable;\r
25 import org.simantics.browsing.ui.model.queries.IsNodeContextModifiable;\r
26 import org.simantics.browsing.ui.model.queries.IsNodeContextRemovable;\r
27 import org.simantics.db.Resource;\r
28 import org.simantics.db.Session;\r
29 import org.simantics.db.common.utils.RequestUtil;\r
30 import org.simantics.db.exception.DatabaseException;\r
31 import org.simantics.db.layer0.SelectionHints;\r
32 import org.simantics.ui.SimanticsUI;\r
33 import org.simantics.utils.ui.ISelectionUtils;\r
34 \r
35 /**\r
36  * A JFace property tester extension for the Eclipse command framework that is\r
37  * meant for working with {@link NodeContext} instances of the Simantics\r
38  * browsing framework.\r
39  * \r
40  * <p>\r
41  * This tester expects to receive IStructuredSelections that contain NodeContext\r
42  * instances.\r
43  * \r
44  * <p>\r
45  * It supports testing of the following properties:\r
46  * <ul>\r
47  * <li>nodeClass - tests if the {@link NodeContext} input (see\r
48  * {@link BuiltinKeys#INPUT}) is an instance of the class specified as an\r
49  * argument. The class must be given as a qualified class name.</li>\r
50  * <li>deletable - for testing whether a NodeContext can be considered\r
51  * generically deletable, see <code>org.eclipse.ui.edit.delete</code> command.\r
52  * No arguments required.</li>\r
53  * <li>modifiable - for testing whether a NodeContext can be considered\r
54  * generically modifiable (either in-line or not), see\r
55  * <code>org.eclipse.ui.edit.rename</code> command. No arguments required.</li>\r
56  * <li>refreshable - for testing whether a NodeContext can be considered\r
57  * generically refreshable, see <code>org.eclipse.ui.file.refresh</code>\r
58  * command. No arguments required.</li>\r
59  * </ul>\r
60  * \r
61  * @author Tuukka Lehtonen\r
62  */\r
63 public class NodePropertyTester extends PropertyTester {\r
64 \r
65     /**\r
66      * Tests if the received object within the model browser tree node is an\r
67      * instance of the class specified as the argument.\r
68      */\r
69     private static final String NODE_CLASS = "nodeClass";\r
70 \r
71     /**\r
72      * Tests if the received object is considered deletable.\r
73      */\r
74     private static final String DELETABLE = "deletable";\r
75 \r
76     /**\r
77      * Tests if the received object is considered modifiable.\r
78      */\r
79     private static final String MODIFIABLE = "modifiable";\r
80 \r
81     /**\r
82      * Tests if the received object is considered refreshable.\r
83      */\r
84     private static final String REFRESHABLE = "refreshable";\r
85 \r
86     ContextTester deletableTester = new DeletableTester();\r
87     ContextTester modifiableTester = new ModifiableTester();\r
88     ContextTester refreshableTester = new RefreshableTester();\r
89 \r
90     @Override\r
91     public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {\r
92 //        System.out.println("TEST: " + receiver + ", " + property + ", " + Arrays.toString(args) + ", " + expectedValue);\r
93         if (!(receiver instanceof ISelection))\r
94             return false;\r
95 \r
96         List<NodeContext> ncs = ISelectionUtils.getPossibleKeys((ISelection) receiver, SelectionHints.KEY_MAIN, NodeContext.class);\r
97         \r
98         if (ncs.isEmpty())\r
99             return false;\r
100 \r
101         if (NODE_CLASS.equals(property)) {\r
102             return testCollection(ncs, new NodeClassTester(args));\r
103         } else if (DELETABLE.equals(property)) {\r
104             return testCollection(ncs, deletableTester);\r
105         } else if (MODIFIABLE.equals(property)) {\r
106             if (ncs.size() == 1)\r
107                 return testCollection(ncs, modifiableTester);\r
108             return false;\r
109         } else if (REFRESHABLE.equals(property)) {\r
110             return testCollection(ncs, refreshableTester);\r
111         }\r
112 \r
113         return false;\r
114     }\r
115 \r
116     static interface ContextTester {\r
117         boolean test(NodeContext c);\r
118     }\r
119 \r
120     public static class NodeClassTester implements ContextTester {\r
121         Object[] args;\r
122         NodeClassTester(Object[] args) {\r
123             this.args = args;\r
124         }\r
125         @Override\r
126         public boolean test(NodeContext nc) {\r
127             try {\r
128                 Object input = nc.getConstant(BuiltinKeys.INPUT);\r
129                 Class<?> inputClass = input.getClass();\r
130 //                System.out.println("input: " + input);\r
131                 boolean assignable = false;\r
132                 for (Object o : args) {\r
133                     Class<?> clazz = Class.forName((String) o, true, input.getClass().getClassLoader());\r
134 //                    System.out.println("  ARG " + o + " CLAZZ: " + clazz);\r
135                     if (clazz.isAssignableFrom(inputClass)) {\r
136 //                        System.out.println("  assignable!");\r
137                         assignable = true;\r
138                         break;\r
139                     }\r
140                 }\r
141                 return assignable;\r
142             } catch (ClassNotFoundException e) {\r
143             }\r
144             return false;\r
145         }\r
146     }\r
147 \r
148     public static class DeletableTester implements ContextTester {\r
149         @Override\r
150         public boolean test(NodeContext nc) {\r
151             Object input = nc.getConstant(BuiltinKeys.INPUT);\r
152             if (input instanceof Resource) {\r
153                 Session session = Simantics.peekSession();\r
154                 try {\r
155                     if (session != null && !DatabaseJob.inProgress())\r
156                         return RequestUtil.trySyncRequest(\r
157                                 session,\r
158                                 SimanticsUI.UI_THREAD_REQUEST_START_TIMEOUT,\r
159                                 SimanticsUI.UI_THREAD_REQUEST_EXECUTION_TIMEOUT,\r
160                                 false,\r
161                                 new IsNodeContextRemovable( nc ) );\r
162                 } catch (DatabaseException | InterruptedException e) {\r
163                 }\r
164                 return false;\r
165             } else if (input instanceof IDeletable) {\r
166                 // OK, this is something that should be considered\r
167                 // deletable, as long as we can find\r
168                 // a method for performing the deletion.\r
169                 return true;\r
170             }\r
171             return false;\r
172         }\r
173     }\r
174 \r
175     public static class ModifiableTester implements ContextTester {\r
176         @Override\r
177         public boolean test(NodeContext nc) {\r
178             Object input = nc.getConstant(BuiltinKeys.INPUT);\r
179             if (input instanceof Resource) {\r
180                 Session session = Simantics.peekSession();\r
181                 try {\r
182                     if (session != null && !DatabaseJob.inProgress())\r
183                         return RequestUtil.trySyncRequest(\r
184                                 session,\r
185                                 SimanticsUI.UI_THREAD_REQUEST_START_TIMEOUT,\r
186                                 SimanticsUI.UI_THREAD_REQUEST_EXECUTION_TIMEOUT,\r
187                                 false,\r
188                                 new IsNodeContextModifiable( nc ) );\r
189                 } catch (DatabaseException | InterruptedException e) {\r
190                 }\r
191                 return false;\r
192             } else if (input instanceof IModifiable) {\r
193                 return true;\r
194             }\r
195             return false;\r
196         }\r
197     }\r
198 \r
199     public static class RefreshableTester implements ContextTester {\r
200         @Override\r
201         public boolean test(NodeContext nc) {\r
202             return nc.getConstant(BuiltinKeys.INPUT) instanceof IRefreshable;\r
203         }\r
204     }\r
205 \r
206     private boolean testCollection(List<NodeContext> receiver, ContextTester tester) {\r
207         if (receiver.isEmpty())\r
208             return false;\r
209 \r
210         int fails = 0;\r
211         for (NodeContext nc : receiver) {\r
212             if (!tester.test(nc))\r
213                 ++fails;\r
214         }\r
215         return fails > 0 ? false : true;\r
216     }\r
217 \r
218 }\r