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