]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/ClientModelImpl.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.spreadsheet.ui / src / org / simantics / spreadsheet / ui / ClientModelImpl.java
1 /*******************************************************************************\r
2  * in Industry THTH ry.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package org.simantics.spreadsheet.ui;\r
12 \r
13 import gnu.trove.map.hash.THashMap;\r
14 \r
15 import java.awt.Rectangle;\r
16 import java.util.ArrayList;\r
17 import java.util.Collection;\r
18 import java.util.HashMap;\r
19 import java.util.HashSet;\r
20 import java.util.List;\r
21 import java.util.Map;\r
22 import java.util.Set;\r
23 import java.util.concurrent.CopyOnWriteArrayList;\r
24 \r
25 import org.simantics.spreadsheet.ClientModel;\r
26 import org.simantics.spreadsheet.util.SpreadsheetUtils;\r
27 import org.simantics.utils.datastructures.Pair;\r
28 import org.simantics.utils.datastructures.collections.CollectionUtils;\r
29 \r
30 public class ClientModelImpl implements ClientModel {\r
31         \r
32         final private Map<String, Map<String, Object>> properties = new THashMap<String, Map<String, Object>>();\r
33         final private Map<String, Map<String, Object>> cells = new THashMap<String, Map<String, Object>>();\r
34         \r
35         private int maxRow = 0;\r
36         private int maxColumn = 0;\r
37         \r
38         private Set<String> clears = new HashSet<String>();\r
39 //      private ArrayList<Triple<String, String, Object>> modifications = new ArrayList<Triple<String, String, Object>>();\r
40         \r
41         private ArrayList<String> modLocation = new ArrayList<String>();\r
42         private ArrayList<String> modProperty = new ArrayList<String>();\r
43         private ArrayList<Object> modValue = new ArrayList<Object>();\r
44         private Map<Long, Rectangle> spanMap = new HashMap<Long, Rectangle>();\r
45         \r
46     public ClientModelImpl() {\r
47 \r
48                 if(Spreadsheet.DEBUG) System.out.println("SimpleContainerTableModel.init");\r
49 \r
50         Map<String, Object> sheetDimensions = new THashMap<String, Object>();\r
51         Map<String, Object> headers = new THashMap<String, Object>();\r
52         Map<String, Object> excel = new THashMap<String, Object>();\r
53         Map<String, Object> sources = new THashMap<String, Object>();\r
54         Map<String, Object> sheets = new THashMap<String, Object>();\r
55         Map<String, Object> context = new THashMap<String, Object>();\r
56         Map<String, Object> mode = new THashMap<String, Object>();\r
57         Map<String, Object> states = new THashMap<String, Object>();\r
58         \r
59         sheetDimensions.put(DIMENSIONS_FIT_ROWS, false);\r
60         sheetDimensions.put(DIMENSIONS_FIT_COLS, false);\r
61         sheetDimensions.put(DIMENSIONS_COL_COUNT, 0);\r
62         sheetDimensions.put(DIMENSIONS_ROW_COUNT, 0);\r
63 \r
64         excel.put(EXCEL_VISIBLE, false);\r
65 \r
66         headers.put(HEADERS_COL_WIDTHS, new int[] {  });\r
67         headers.put(HEADERS_ROW_HEIGHTS, new int[] {  });\r
68         headers.put(HEADERS_COL_LABELS, new String[] {  });\r
69         headers.put(HEADERS_ROW_LABELS, new String[] {  });\r
70         \r
71         sources.put(SOURCES_AVAILABLE, new String[] { });\r
72         sources.put(SOURCES_CURRENT, "");\r
73         \r
74         properties.put(DIMENSIONS, sheetDimensions);\r
75         properties.put(HEADERS, headers);\r
76         properties.put(EXCEL, excel);\r
77         properties.put(SOURCES, sources);\r
78         properties.put(SHEETS, sheets);\r
79         properties.put(CONTEXT, context);\r
80         properties.put(MODE, mode);\r
81         properties.put(STATES, states);\r
82         \r
83         setProperty(EXCEL, EXCEL_VISIBLE, false);\r
84 \r
85     }\r
86 \r
87     CopyOnWriteArrayList<ClientModelListener> listeners = new CopyOnWriteArrayList<ClientModelListener>();\r
88     \r
89     @Override\r
90     public void addListener(ClientModelListener listener) {\r
91         listeners.add(listener);\r
92         listener.rows(getRows());\r
93         listener.columns(getColumns());\r
94         listener.rowLabels((String[])getPropertyAt(HEADERS, HEADERS_ROW_LABELS));\r
95         listener.columnWidths((int[])getPropertyAt(HEADERS, HEADERS_COL_WIDTHS));\r
96         listener.sources((String[])getPropertyAt(SOURCES, SOURCES_AVAILABLE), (String)getPropertyAt(SOURCES, SOURCES_CURRENT));\r
97     }\r
98 \r
99     @Override\r
100     public void removeListener(ClientModelListener listener) {\r
101         listeners.remove(listener);\r
102     }\r
103     \r
104     private void fireFlush() {\r
105         for(ClientModelListener listener : listeners)\r
106                 listener.flush();\r
107     }\r
108 \r
109     private void fireRows() {\r
110         for(ClientModelListener listener : listeners)\r
111                 listener.rows(getRows());\r
112     }\r
113 \r
114     private void fireColumns() {\r
115         for(ClientModelListener listener : listeners)\r
116                 listener.columns(getColumns());\r
117     }\r
118     \r
119     private void fireColumnWidths() {\r
120         for(ClientModelListener listener : listeners)\r
121                 listener.columnWidths((int[])getPropertyAt(HEADERS, HEADERS_COL_WIDTHS));\r
122     }\r
123     \r
124     private void fireSources() {\r
125         for(ClientModelListener listener : listeners)\r
126                 listener.sources((String[])getPropertyAt(SOURCES, SOURCES_AVAILABLE), (String)getPropertyAt(SOURCES, SOURCES_CURRENT));\r
127     }\r
128 \r
129     private void fireProperty(String location, String property, Object value) {\r
130         for(ClientModelListener listener : listeners)\r
131                 listener.propertyChange(location, property, value);\r
132     }\r
133 \r
134     private void fireCleared(String location) {\r
135         for(ClientModelListener listener : listeners)\r
136                 listener.cleared(location);\r
137     }\r
138     \r
139     @Override\r
140     public <T> T getPossiblePropertyAt(String location, String property) {\r
141         try {\r
142                 T t = getPropertyAt(location, property);\r
143                 return t; \r
144         } catch (Throwable e) {\r
145                 return null;\r
146         }\r
147     }\r
148     \r
149     @SuppressWarnings("unchecked")\r
150     public synchronized <T> T getPropertyAt(String location, String property) {\r
151 \r
152                 if(Spreadsheet.DEBUG) System.out.println("SimpleContainerTableModel.getPropertyAt " + location + " " + property);\r
153         \r
154         Map<String, Object> props = properties.get(location);\r
155         if(props != null) {\r
156                 return (T)props.get(property);\r
157         } else {\r
158                 Map<String, Object> cls = cells.get(location);\r
159                 if(cls != null) {\r
160                         return (T)cls.get(property);\r
161                 } else {\r
162                         return null;\r
163                 }\r
164         }\r
165 \r
166     }\r
167         \r
168     private final Set<String> sizing = CollectionUtils.toSet(\r
169                 DIMENSIONS_COL_COUNT,\r
170                 DIMENSIONS_ROW_COUNT,\r
171                 DIMENSIONS_FIT_COLS,\r
172                 DIMENSIONS_FIT_ROWS);\r
173     \r
174     private boolean sizingProperty(String property) {\r
175         return sizing.contains(property);\r
176     }\r
177     \r
178     private boolean checkMaxRow(int row) {\r
179                 if((row+1) > maxRow) {\r
180                         maxRow = row+1;\r
181                         return true;\r
182                 } else {\r
183                         return false;\r
184                 }\r
185     }\r
186 \r
187     private boolean checkMaxColumn(int column) {\r
188                 if((column+1) > maxColumn) {\r
189                         maxColumn = column+1;\r
190                         return true;\r
191                 } else {\r
192                         return false;\r
193                 }\r
194     }\r
195 \r
196         @Override\r
197         public synchronized void setProperty(final String location, final String property, final Object value) {\r
198 \r
199                 assert(location != null);\r
200                 assert(property != null);\r
201 \r
202                 modLocation.add(location);\r
203                 modProperty.add(property);\r
204                 modValue.add(value);\r
205                 \r
206         }\r
207         \r
208         @Override\r
209     public void clearAll() {\r
210         clears.addAll(cells.keySet());\r
211     }\r
212 \r
213         @Override\r
214         public synchronized void clear(String location) {\r
215             if (location.startsWith("Style"))\r
216                 // Nothing to do for now..\r
217                 return;\r
218                 clears.add(location);\r
219         }\r
220         \r
221         @Override\r
222         public synchronized void flush() {\r
223                 \r
224                 for(String location : clears) {\r
225                         \r
226                         Map<String, Object> cls = cells.remove(location);\r
227                         if(cls == null) return;\r
228                         \r
229                         long l = SpreadsheetUtils.decodeCellCoded(location);\r
230                         int row = (int)(l & 0xffffffff) - 1;\r
231                         int column = (int)((l>>32) & 0xffffffff);\r
232                         \r
233                         if(checkMaxRow(row)) fireRows();\r
234                         if(checkMaxColumn(column)) fireColumns();\r
235 \r
236                         removeSpan(row, column);\r
237                         \r
238                         fireCleared(location);\r
239                         \r
240                 }\r
241 \r
242                 for(int i=0;i<modLocation.size();i++) {\r
243                         \r
244                         String location = modLocation.get(i);\r
245                         String property = modProperty.get(i);\r
246                         Object value = modValue.get(i);\r
247 \r
248                         if(Spreadsheet.DEBUG) System.out.println("ClientModelImpl.setProperty " + location + " " + property + " " + value);\r
249 \r
250                         Map<String, Object> props = properties.get(location);\r
251                         if(props != null || location.startsWith("Style")) {\r
252                             if (location.startsWith("Style") && props == null) {\r
253                                 props = new HashMap<>();\r
254                                 properties.put(location, props);\r
255                             }\r
256 \r
257                                 if(sizingProperty(property)) {\r
258 \r
259                                         int currentRows = getRows();\r
260                                         int currentCols = getColumns();\r
261                                         props.put(property, value);\r
262                                         if(getRows() != currentRows) fireRows();\r
263                                         if(getColumns() != currentCols) fireColumns();\r
264 \r
265                                 } else {\r
266 \r
267                                         props.put(property, value);\r
268                                         if(property.equals(HEADERS_COL_WIDTHS)) fireColumnWidths();\r
269                                         if(property.equals(SOURCES_AVAILABLE) ||  property.equals(SOURCES_CURRENT)) fireSources();\r
270 \r
271                                 }\r
272 \r
273                         } else {\r
274 \r
275                                 Map<String, Object> cls = cells.get(location);\r
276                                 if(cls == null) {\r
277                                         cls = new HashMap<String, Object>();\r
278                                         cells.put(location, cls);\r
279                                 }\r
280 \r
281                                 cls.put(property, value);\r
282 \r
283                                 long l = SpreadsheetUtils.decodeCellCoded(location);\r
284                                 int row = (int)(l & 0xffffffff) - 1;\r
285                                 int column = (int)((l>>32) & 0xffffffff);\r
286 \r
287                                 if(checkMaxRow(row)) fireRows();\r
288                                 if(checkMaxColumn(column)) fireColumns();\r
289 \r
290                                 boolean rowSpanProperty = property.equals(ROW_SPAN);\r
291                                 boolean columnSpanProperty = property.equals(COLUMN_SPAN);\r
292                                 if (rowSpanProperty || columnSpanProperty) {\r
293                                         Rectangle span = getRootSpan(row, column);\r
294                                         int size = (Integer)value;\r
295                                         \r
296                                         if (span == null) {\r
297                                                 if (size > 1) {\r
298                                                         if (rowSpanProperty) {\r
299                                                                 span = createSpan(row, column, size, 1);\r
300                                                         } else {\r
301                                                                 span = createSpan(row, column, 1, size);\r
302                                                         }\r
303                                                 }\r
304                                         } else {\r
305                                                 if (rowSpanProperty) {\r
306                                                         span.height = size;\r
307                                                 } else {\r
308                                                         span.width = size;\r
309                                                 }\r
310                                                 if ((span.width == 1) && (span.height == 1)) {\r
311                                                         removeSpan(row, column);\r
312                                                 }\r
313                                         }\r
314                                 }\r
315                         }\r
316 \r
317                         fireProperty(location, property, value);\r
318                 \r
319                 }\r
320                 \r
321                 clears.clear();\r
322                 modLocation.clear();\r
323                 modProperty.clear();\r
324                 modValue.clear(); \r
325                 \r
326                 fireFlush();\r
327                 \r
328         }\r
329         \r
330         @Override\r
331         public int getRows() {\r
332                 boolean fitRows = getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_FIT_ROWS);\r
333                 if(fitRows) return maxRow;\r
334                 else return getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_ROW_COUNT);\r
335         }\r
336 \r
337         @Override\r
338         public int getColumns() {\r
339                 boolean fitCols = getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_FIT_COLS);\r
340                 if(fitCols) {\r
341                         return maxColumn;\r
342                 }\r
343                 else return getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_COL_COUNT);\r
344         }\r
345         \r
346         @Override\r
347         public int[] getColumnWidths() {\r
348                 int[] data = getPropertyAt(HEADERS, HEADERS_COL_WIDTHS);\r
349                 return data.clone();\r
350         }\r
351 \r
352         @Override\r
353         public int[] getRowHeights() {\r
354                 int[] data = getPropertyAt(HEADERS, HEADERS_ROW_HEIGHTS);\r
355                 return data.clone();\r
356         }\r
357 \r
358         @Override\r
359         public synchronized Collection<Pair<String, Object>> listAll(String property) {\r
360 \r
361                 ArrayList<Pair<String, Object>> result = new ArrayList<Pair<String, Object>>(); \r
362                 \r
363                 for(Map.Entry<String, Map<String, Object>> entry : properties.entrySet()) {\r
364                         Object value = entry.getValue().get(property);\r
365                         if(value != null) result.add(Pair.make(entry.getKey(), value));\r
366                 }\r
367                 for(Map.Entry<String, Map<String, Object>> entry : cells.entrySet()) {\r
368                         Object value = entry.getValue().get(property);\r
369                         if(value != null) result.add(Pair.make(entry.getKey(), value));\r
370                 }\r
371                 \r
372                 return result;\r
373                 \r
374         }\r
375         \r
376         private long spanKey(int row, int column) {\r
377                 return (row & 0xffffffff) | (((long)(column & 0xffffffff)) << 32);\r
378         }\r
379 \r
380         @Override\r
381         public synchronized Rectangle getSpan(int row, int column) {\r
382                 for (Rectangle span : spanMap.values()) {\r
383                         if (span.contains(column, row)) {\r
384                                 return new Rectangle(span);\r
385                         }\r
386                 }\r
387                 return null;\r
388         }\r
389         \r
390         @Override\r
391         public synchronized List<Rectangle> getSpans() {\r
392                 List<Rectangle> spans = new ArrayList<Rectangle>(spanMap.size());\r
393                 for (Rectangle span : spanMap.values()) {\r
394                         spans.add(new Rectangle(span));\r
395                 }\r
396                 return spans;                   \r
397         }\r
398 \r
399         private Rectangle getRootSpan(int row, int column) {\r
400                 return spanMap.get(spanKey(row, column));\r
401         }\r
402         \r
403         private Rectangle createSpan(int row, int column, int rowSpan, int columnSpan) {\r
404                 Rectangle span = new Rectangle(column, row, columnSpan, rowSpan);\r
405                 spanMap.put(spanKey(row, column), span);\r
406                 return span;\r
407         }\r
408         \r
409         private void removeSpan(int row, int column) {\r
410                 spanMap.remove(spanKey(row, column));\r
411         }\r
412         \r
413 }\r