]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.spreadsheet.ui/src/org/simantics/spreadsheet/ui/ClientModelImpl.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.spreadsheet.ui / src / org / simantics / spreadsheet / ui / ClientModelImpl.java
index 93bd742b5d591468b471b30213482fcc35600282..86fda3d5a7634933efff640a2690ba99de19773b 100644 (file)
-/*******************************************************************************\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.spreadsheet.ui;\r
-\r
-import gnu.trove.map.hash.THashMap;\r
-\r
-import java.awt.Rectangle;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.concurrent.CopyOnWriteArrayList;\r
-\r
-import org.simantics.spreadsheet.ClientModel;\r
-import org.simantics.spreadsheet.util.SpreadsheetUtils;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.datastructures.collections.CollectionUtils;\r
-\r
-public class ClientModelImpl implements ClientModel {\r
-       \r
-       final private Map<String, Map<String, Object>> properties = new THashMap<String, Map<String, Object>>();\r
-       final private Map<String, Map<String, Object>> cells = new THashMap<String, Map<String, Object>>();\r
-       \r
-       private int maxRow = 0;\r
-       private int maxColumn = 0;\r
-       \r
-       private Set<String> clears = new HashSet<String>();\r
-//     private ArrayList<Triple<String, String, Object>> modifications = new ArrayList<Triple<String, String, Object>>();\r
-       \r
-       private ArrayList<String> modLocation = new ArrayList<String>();\r
-       private ArrayList<String> modProperty = new ArrayList<String>();\r
-       private ArrayList<Object> modValue = new ArrayList<Object>();\r
-       private Map<Long, Rectangle> spanMap = new HashMap<Long, Rectangle>();\r
-       \r
-    public ClientModelImpl() {\r
-\r
-               if(Spreadsheet.DEBUG) System.out.println("SimpleContainerTableModel.init");\r
-\r
-        Map<String, Object> sheetDimensions = new THashMap<String, Object>();\r
-        Map<String, Object> headers = new THashMap<String, Object>();\r
-        Map<String, Object> excel = new THashMap<String, Object>();\r
-        Map<String, Object> sources = new THashMap<String, Object>();\r
-        Map<String, Object> sheets = new THashMap<String, Object>();\r
-        Map<String, Object> context = new THashMap<String, Object>();\r
-        Map<String, Object> mode = new THashMap<String, Object>();\r
-        Map<String, Object> states = new THashMap<String, Object>();\r
-        \r
-        sheetDimensions.put(DIMENSIONS_FIT_ROWS, false);\r
-        sheetDimensions.put(DIMENSIONS_FIT_COLS, false);\r
-        sheetDimensions.put(DIMENSIONS_COL_COUNT, 0);\r
-        sheetDimensions.put(DIMENSIONS_ROW_COUNT, 0);\r
-\r
-        excel.put(EXCEL_VISIBLE, false);\r
-\r
-        headers.put(HEADERS_COL_WIDTHS, new int[] {  });\r
-        headers.put(HEADERS_ROW_HEIGHTS, new int[] {  });\r
-        headers.put(HEADERS_COL_LABELS, new String[] {  });\r
-        headers.put(HEADERS_ROW_LABELS, new String[] {  });\r
-        \r
-        sources.put(SOURCES_AVAILABLE, new String[] { });\r
-        sources.put(SOURCES_CURRENT, "");\r
-        \r
-        properties.put(DIMENSIONS, sheetDimensions);\r
-        properties.put(HEADERS, headers);\r
-        properties.put(EXCEL, excel);\r
-        properties.put(SOURCES, sources);\r
-        properties.put(SHEETS, sheets);\r
-        properties.put(CONTEXT, context);\r
-        properties.put(MODE, mode);\r
-        properties.put(STATES, states);\r
-        \r
-        setProperty(EXCEL, EXCEL_VISIBLE, false);\r
-\r
-    }\r
-\r
-    CopyOnWriteArrayList<ClientModelListener> listeners = new CopyOnWriteArrayList<ClientModelListener>();\r
-    \r
-    @Override\r
-    public void addListener(ClientModelListener listener) {\r
-       listeners.add(listener);\r
-       listener.rows(getRows());\r
-       listener.columns(getColumns());\r
-       listener.rowLabels((String[])getPropertyAt(HEADERS, HEADERS_ROW_LABELS));\r
-       listener.columnWidths((int[])getPropertyAt(HEADERS, HEADERS_COL_WIDTHS));\r
-       listener.sources((String[])getPropertyAt(SOURCES, SOURCES_AVAILABLE), (String)getPropertyAt(SOURCES, SOURCES_CURRENT));\r
-    }\r
-\r
-    @Override\r
-    public void removeListener(ClientModelListener listener) {\r
-       listeners.remove(listener);\r
-    }\r
-    \r
-    private void fireFlush() {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.flush();\r
-    }\r
-\r
-    private void fireRows() {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.rows(getRows());\r
-    }\r
-\r
-    private void fireColumns() {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.columns(getColumns());\r
-    }\r
-    \r
-    private void fireColumnWidths() {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.columnWidths((int[])getPropertyAt(HEADERS, HEADERS_COL_WIDTHS));\r
-    }\r
-    \r
-    private void fireSources() {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.sources((String[])getPropertyAt(SOURCES, SOURCES_AVAILABLE), (String)getPropertyAt(SOURCES, SOURCES_CURRENT));\r
-    }\r
-\r
-    private void fireProperty(String location, String property, Object value) {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.propertyChange(location, property, value);\r
-    }\r
-\r
-    private void fireCleared(String location) {\r
-       for(ClientModelListener listener : listeners)\r
-               listener.cleared(location);\r
-    }\r
-    \r
-    @Override\r
-    public <T> T getPossiblePropertyAt(String location, String property) {\r
-       try {\r
-               T t = getPropertyAt(location, property);\r
-               return t; \r
-       } catch (Throwable e) {\r
-               return null;\r
-       }\r
-    }\r
-    \r
-    @SuppressWarnings("unchecked")\r
-    public synchronized <T> T getPropertyAt(String location, String property) {\r
-\r
-               if(Spreadsheet.DEBUG) System.out.println("SimpleContainerTableModel.getPropertyAt " + location + " " + property);\r
-       \r
-       Map<String, Object> props = properties.get(location);\r
-       if(props != null) {\r
-               return (T)props.get(property);\r
-       } else {\r
-               Map<String, Object> cls = cells.get(location);\r
-               if(cls != null) {\r
-                       return (T)cls.get(property);\r
-               } else {\r
-                       return null;\r
-               }\r
-       }\r
-\r
-    }\r
-       \r
-    private final Set<String> sizing = CollectionUtils.toSet(\r
-               DIMENSIONS_COL_COUNT,\r
-               DIMENSIONS_ROW_COUNT,\r
-               DIMENSIONS_FIT_COLS,\r
-               DIMENSIONS_FIT_ROWS);\r
-    \r
-    private boolean sizingProperty(String property) {\r
-       return sizing.contains(property);\r
-    }\r
-    \r
-    private boolean checkMaxRow(int row) {\r
-               if((row+1) > maxRow) {\r
-                       maxRow = row+1;\r
-                       return true;\r
-               } else {\r
-                       return false;\r
-               }\r
-    }\r
-\r
-    private boolean checkMaxColumn(int column) {\r
-               if((column+1) > maxColumn) {\r
-                       maxColumn = column+1;\r
-                       return true;\r
-               } else {\r
-                       return false;\r
-               }\r
-    }\r
-\r
-       @Override\r
-       public synchronized void setProperty(final String location, final String property, final Object value) {\r
-\r
-               assert(location != null);\r
-               assert(property != null);\r
-\r
-               modLocation.add(location);\r
-               modProperty.add(property);\r
-               modValue.add(value);\r
-               \r
-       }\r
-       \r
-       @Override\r
-    public void clearAll() {\r
-       clears.addAll(cells.keySet());\r
-    }\r
-\r
-       @Override\r
-       public synchronized void clear(String location) {\r
-           if (location.startsWith("Style"))\r
-               // Nothing to do for now..\r
-               return;\r
-               clears.add(location);\r
-       }\r
-       \r
-       @Override\r
-       public synchronized void flush() {\r
-               \r
-               for(String location : clears) {\r
-                       \r
-                       Map<String, Object> cls = cells.remove(location);\r
-                       if(cls == null) return;\r
-                       \r
-                       long l = SpreadsheetUtils.decodeCellCoded(location);\r
-                       int row = (int)(l & 0xffffffff) - 1;\r
-                       int column = (int)((l>>32) & 0xffffffff);\r
-                       \r
-                       if(checkMaxRow(row)) fireRows();\r
-                       if(checkMaxColumn(column)) fireColumns();\r
-\r
-                       removeSpan(row, column);\r
-                       \r
-                       fireCleared(location);\r
-                       \r
-               }\r
-\r
-               for(int i=0;i<modLocation.size();i++) {\r
-                       \r
-                       String location = modLocation.get(i);\r
-                       String property = modProperty.get(i);\r
-                       Object value = modValue.get(i);\r
-\r
-                       if(Spreadsheet.DEBUG) System.out.println("ClientModelImpl.setProperty " + location + " " + property + " " + value);\r
-\r
-                       Map<String, Object> props = properties.get(location);\r
-                       if(props != null || location.startsWith("Style")) {\r
-                           if (location.startsWith("Style") && props == null) {\r
-                               props = new HashMap<>();\r
-                               properties.put(location, props);\r
-                           }\r
-\r
-                               if(sizingProperty(property)) {\r
-\r
-                                       int currentRows = getRows();\r
-                                       int currentCols = getColumns();\r
-                                       props.put(property, value);\r
-                                       if(getRows() != currentRows) fireRows();\r
-                                       if(getColumns() != currentCols) fireColumns();\r
-\r
-                               } else {\r
-\r
-                                       props.put(property, value);\r
-                                       if(property.equals(HEADERS_COL_WIDTHS)) fireColumnWidths();\r
-                                       if(property.equals(SOURCES_AVAILABLE) ||  property.equals(SOURCES_CURRENT)) fireSources();\r
-\r
-                               }\r
-\r
-                       } else {\r
-\r
-                               Map<String, Object> cls = cells.get(location);\r
-                               if(cls == null) {\r
-                                       cls = new HashMap<String, Object>();\r
-                                       cells.put(location, cls);\r
-                               }\r
-\r
-                               cls.put(property, value);\r
-\r
-                               long l = SpreadsheetUtils.decodeCellCoded(location);\r
-                               int row = (int)(l & 0xffffffff) - 1;\r
-                               int column = (int)((l>>32) & 0xffffffff);\r
-\r
-                               if(checkMaxRow(row)) fireRows();\r
-                               if(checkMaxColumn(column)) fireColumns();\r
-\r
-                               boolean rowSpanProperty = property.equals(ROW_SPAN);\r
-                               boolean columnSpanProperty = property.equals(COLUMN_SPAN);\r
-                               if (rowSpanProperty || columnSpanProperty) {\r
-                                       Rectangle span = getRootSpan(row, column);\r
-                                       int size = (Integer)value;\r
-                                       \r
-                                       if (span == null) {\r
-                                               if (size > 1) {\r
-                                                       if (rowSpanProperty) {\r
-                                                               span = createSpan(row, column, size, 1);\r
-                                                       } else {\r
-                                                               span = createSpan(row, column, 1, size);\r
-                                                       }\r
-                                               }\r
-                                       } else {\r
-                                               if (rowSpanProperty) {\r
-                                                       span.height = size;\r
-                                               } else {\r
-                                                       span.width = size;\r
-                                               }\r
-                                               if ((span.width == 1) && (span.height == 1)) {\r
-                                                       removeSpan(row, column);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       fireProperty(location, property, value);\r
-               \r
-               }\r
-               \r
-               clears.clear();\r
-               modLocation.clear();\r
-               modProperty.clear();\r
-               modValue.clear(); \r
-               \r
-               fireFlush();\r
-               \r
-       }\r
-       \r
-       @Override\r
-       public int getRows() {\r
-               boolean fitRows = getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_FIT_ROWS);\r
-               if(fitRows) return maxRow;\r
-               else return getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_ROW_COUNT);\r
-       }\r
-\r
-       @Override\r
-       public int getColumns() {\r
-               boolean fitCols = getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_FIT_COLS);\r
-               if(fitCols) {\r
-                       return maxColumn;\r
-               }\r
-               else return getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_COL_COUNT);\r
-       }\r
-       \r
-       @Override\r
-       public int[] getColumnWidths() {\r
-               int[] data = getPropertyAt(HEADERS, HEADERS_COL_WIDTHS);\r
-               return data.clone();\r
-       }\r
-\r
-       @Override\r
-       public int[] getRowHeights() {\r
-               int[] data = getPropertyAt(HEADERS, HEADERS_ROW_HEIGHTS);\r
-               return data.clone();\r
-       }\r
-\r
-       @Override\r
-       public synchronized Collection<Pair<String, Object>> listAll(String property) {\r
-\r
-               ArrayList<Pair<String, Object>> result = new ArrayList<Pair<String, Object>>(); \r
-               \r
-               for(Map.Entry<String, Map<String, Object>> entry : properties.entrySet()) {\r
-                       Object value = entry.getValue().get(property);\r
-                       if(value != null) result.add(Pair.make(entry.getKey(), value));\r
-               }\r
-               for(Map.Entry<String, Map<String, Object>> entry : cells.entrySet()) {\r
-                       Object value = entry.getValue().get(property);\r
-                       if(value != null) result.add(Pair.make(entry.getKey(), value));\r
-               }\r
-               \r
-               return result;\r
-               \r
-       }\r
-       \r
-       private long spanKey(int row, int column) {\r
-               return (row & 0xffffffff) | (((long)(column & 0xffffffff)) << 32);\r
-       }\r
-\r
-       @Override\r
-       public synchronized Rectangle getSpan(int row, int column) {\r
-               for (Rectangle span : spanMap.values()) {\r
-                       if (span.contains(column, row)) {\r
-                               return new Rectangle(span);\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
-       \r
-       @Override\r
-       public synchronized List<Rectangle> getSpans() {\r
-               List<Rectangle> spans = new ArrayList<Rectangle>(spanMap.size());\r
-               for (Rectangle span : spanMap.values()) {\r
-                       spans.add(new Rectangle(span));\r
-               }\r
-               return spans;                   \r
-       }\r
-\r
-       private Rectangle getRootSpan(int row, int column) {\r
-               return spanMap.get(spanKey(row, column));\r
-       }\r
-       \r
-       private Rectangle createSpan(int row, int column, int rowSpan, int columnSpan) {\r
-               Rectangle span = new Rectangle(column, row, columnSpan, rowSpan);\r
-               spanMap.put(spanKey(row, column), span);\r
-               return span;\r
-       }\r
-       \r
-       private void removeSpan(int row, int column) {\r
-               spanMap.remove(spanKey(row, column));\r
-       }\r
-       \r
-}\r
+/*******************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.spreadsheet.ui;
+
+import gnu.trove.map.hash.THashMap;
+
+import java.awt.Rectangle;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.simantics.spreadsheet.ClientModel;
+import org.simantics.spreadsheet.util.SpreadsheetUtils;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.datastructures.collections.CollectionUtils;
+
+public class ClientModelImpl implements ClientModel {
+       
+       final private Map<String, Map<String, Object>> properties = new THashMap<String, Map<String, Object>>();
+       final private Map<String, Map<String, Object>> cells = new THashMap<String, Map<String, Object>>();
+       
+       private int maxRow = 0;
+       private int maxColumn = 0;
+       
+       private Set<String> clears = new HashSet<String>();
+//     private ArrayList<Triple<String, String, Object>> modifications = new ArrayList<Triple<String, String, Object>>();
+       
+       private ArrayList<String> modLocation = new ArrayList<String>();
+       private ArrayList<String> modProperty = new ArrayList<String>();
+       private ArrayList<Object> modValue = new ArrayList<Object>();
+       private Map<Long, Rectangle> spanMap = new HashMap<Long, Rectangle>();
+       
+    public ClientModelImpl() {
+
+               if(Spreadsheet.DEBUG) System.out.println("SimpleContainerTableModel.init");
+
+        Map<String, Object> sheetDimensions = new THashMap<String, Object>();
+        Map<String, Object> headers = new THashMap<String, Object>();
+        Map<String, Object> excel = new THashMap<String, Object>();
+        Map<String, Object> sources = new THashMap<String, Object>();
+        Map<String, Object> sheets = new THashMap<String, Object>();
+        Map<String, Object> context = new THashMap<String, Object>();
+        Map<String, Object> mode = new THashMap<String, Object>();
+        Map<String, Object> states = new THashMap<String, Object>();
+        
+        sheetDimensions.put(DIMENSIONS_FIT_ROWS, false);
+        sheetDimensions.put(DIMENSIONS_FIT_COLS, false);
+        sheetDimensions.put(DIMENSIONS_COL_COUNT, 0);
+        sheetDimensions.put(DIMENSIONS_ROW_COUNT, 0);
+
+        excel.put(EXCEL_VISIBLE, false);
+
+        headers.put(HEADERS_COL_WIDTHS, new int[] {  });
+        headers.put(HEADERS_ROW_HEIGHTS, new int[] {  });
+        headers.put(HEADERS_COL_LABELS, new String[] {  });
+        headers.put(HEADERS_ROW_LABELS, new String[] {  });
+        
+        sources.put(SOURCES_AVAILABLE, new String[] { });
+        sources.put(SOURCES_CURRENT, "");
+        
+        properties.put(DIMENSIONS, sheetDimensions);
+        properties.put(HEADERS, headers);
+        properties.put(EXCEL, excel);
+        properties.put(SOURCES, sources);
+        properties.put(SHEETS, sheets);
+        properties.put(CONTEXT, context);
+        properties.put(MODE, mode);
+        properties.put(STATES, states);
+        
+        setProperty(EXCEL, EXCEL_VISIBLE, false);
+
+    }
+
+    CopyOnWriteArrayList<ClientModelListener> listeners = new CopyOnWriteArrayList<ClientModelListener>();
+    
+    @Override
+    public void addListener(ClientModelListener listener) {
+       listeners.add(listener);
+       listener.rows(getRows());
+       listener.columns(getColumns());
+       listener.rowLabels((String[])getPropertyAt(HEADERS, HEADERS_ROW_LABELS));
+       listener.columnWidths((int[])getPropertyAt(HEADERS, HEADERS_COL_WIDTHS));
+       listener.sources((String[])getPropertyAt(SOURCES, SOURCES_AVAILABLE), (String)getPropertyAt(SOURCES, SOURCES_CURRENT));
+    }
+
+    @Override
+    public void removeListener(ClientModelListener listener) {
+       listeners.remove(listener);
+    }
+    
+    private void fireFlush() {
+       for(ClientModelListener listener : listeners)
+               listener.flush();
+    }
+
+    private void fireRows() {
+       for(ClientModelListener listener : listeners)
+               listener.rows(getRows());
+    }
+
+    private void fireColumns() {
+       for(ClientModelListener listener : listeners)
+               listener.columns(getColumns());
+    }
+    
+    private void fireColumnWidths() {
+       for(ClientModelListener listener : listeners)
+               listener.columnWidths((int[])getPropertyAt(HEADERS, HEADERS_COL_WIDTHS));
+    }
+    
+    private void fireSources() {
+       for(ClientModelListener listener : listeners)
+               listener.sources((String[])getPropertyAt(SOURCES, SOURCES_AVAILABLE), (String)getPropertyAt(SOURCES, SOURCES_CURRENT));
+    }
+
+    private void fireProperty(String location, String property, Object value) {
+       for(ClientModelListener listener : listeners)
+               listener.propertyChange(location, property, value);
+    }
+
+    private void fireCleared(String location) {
+       for(ClientModelListener listener : listeners)
+               listener.cleared(location);
+    }
+    
+    @Override
+    public <T> T getPossiblePropertyAt(String location, String property) {
+       try {
+               T t = getPropertyAt(location, property);
+               return t; 
+       } catch (Throwable e) {
+               return null;
+       }
+    }
+    
+    @SuppressWarnings("unchecked")
+    public synchronized <T> T getPropertyAt(String location, String property) {
+
+               if(Spreadsheet.DEBUG) System.out.println("SimpleContainerTableModel.getPropertyAt " + location + " " + property);
+       
+       Map<String, Object> props = properties.get(location);
+       if(props != null) {
+               return (T)props.get(property);
+       } else {
+               Map<String, Object> cls = cells.get(location);
+               if(cls != null) {
+                       return (T)cls.get(property);
+               } else {
+                       return null;
+               }
+       }
+
+    }
+       
+    private final Set<String> sizing = CollectionUtils.toSet(
+               DIMENSIONS_COL_COUNT,
+               DIMENSIONS_ROW_COUNT,
+               DIMENSIONS_FIT_COLS,
+               DIMENSIONS_FIT_ROWS);
+    
+    private boolean sizingProperty(String property) {
+       return sizing.contains(property);
+    }
+    
+    private boolean checkMaxRow(int row) {
+               if((row+1) > maxRow) {
+                       maxRow = row+1;
+                       return true;
+               } else {
+                       return false;
+               }
+    }
+
+    private boolean checkMaxColumn(int column) {
+               if((column+1) > maxColumn) {
+                       maxColumn = column+1;
+                       return true;
+               } else {
+                       return false;
+               }
+    }
+
+       @Override
+       public synchronized void setProperty(final String location, final String property, final Object value) {
+
+               assert(location != null);
+               assert(property != null);
+
+               modLocation.add(location);
+               modProperty.add(property);
+               modValue.add(value);
+               
+       }
+       
+       @Override
+    public void clearAll() {
+       clears.addAll(cells.keySet());
+    }
+
+       @Override
+       public synchronized void clear(String location) {
+           if (location.startsWith("Style"))
+               // Nothing to do for now..
+               return;
+               clears.add(location);
+       }
+       
+       @Override
+       public synchronized void flush() {
+               
+               for(String location : clears) {
+                       
+                       Map<String, Object> cls = cells.remove(location);
+                       if(cls == null) return;
+                       
+                       long l = SpreadsheetUtils.decodeCellCoded(location);
+                       int row = (int)(l & 0xffffffff) - 1;
+                       int column = (int)((l>>32) & 0xffffffff);
+                       
+                       if(checkMaxRow(row)) fireRows();
+                       if(checkMaxColumn(column)) fireColumns();
+
+                       removeSpan(row, column);
+                       
+                       fireCleared(location);
+                       
+               }
+
+               for(int i=0;i<modLocation.size();i++) {
+                       
+                       String location = modLocation.get(i);
+                       String property = modProperty.get(i);
+                       Object value = modValue.get(i);
+
+                       if(Spreadsheet.DEBUG) System.out.println("ClientModelImpl.setProperty " + location + " " + property + " " + value);
+
+                       Map<String, Object> props = properties.get(location);
+                       if(props != null || location.startsWith("Style")) {
+                           if (location.startsWith("Style") && props == null) {
+                               props = new HashMap<>();
+                               properties.put(location, props);
+                           }
+
+                               if(sizingProperty(property)) {
+
+                                       int currentRows = getRows();
+                                       int currentCols = getColumns();
+                                       props.put(property, value);
+                                       if(getRows() != currentRows) fireRows();
+                                       if(getColumns() != currentCols) fireColumns();
+
+                               } else {
+
+                                       props.put(property, value);
+                                       if(property.equals(HEADERS_COL_WIDTHS)) fireColumnWidths();
+                                       if(property.equals(SOURCES_AVAILABLE) ||  property.equals(SOURCES_CURRENT)) fireSources();
+
+                               }
+
+                       } else {
+
+                               Map<String, Object> cls = cells.get(location);
+                               if(cls == null) {
+                                       cls = new HashMap<String, Object>();
+                                       cells.put(location, cls);
+                               }
+
+                               cls.put(property, value);
+
+                               long l = SpreadsheetUtils.decodeCellCoded(location);
+                               int row = (int)(l & 0xffffffff) - 1;
+                               int column = (int)((l>>32) & 0xffffffff);
+
+                               if(checkMaxRow(row)) fireRows();
+                               if(checkMaxColumn(column)) fireColumns();
+
+                               boolean rowSpanProperty = property.equals(ROW_SPAN);
+                               boolean columnSpanProperty = property.equals(COLUMN_SPAN);
+                               if (rowSpanProperty || columnSpanProperty) {
+                                       Rectangle span = getRootSpan(row, column);
+                                       int size = (Integer)value;
+                                       
+                                       if (span == null) {
+                                               if (size > 1) {
+                                                       if (rowSpanProperty) {
+                                                               span = createSpan(row, column, size, 1);
+                                                       } else {
+                                                               span = createSpan(row, column, 1, size);
+                                                       }
+                                               }
+                                       } else {
+                                               if (rowSpanProperty) {
+                                                       span.height = size;
+                                               } else {
+                                                       span.width = size;
+                                               }
+                                               if ((span.width == 1) && (span.height == 1)) {
+                                                       removeSpan(row, column);
+                                               }
+                                       }
+                               }
+                       }
+
+                       fireProperty(location, property, value);
+               
+               }
+               
+               clears.clear();
+               modLocation.clear();
+               modProperty.clear();
+               modValue.clear(); 
+               
+               fireFlush();
+               
+       }
+       
+       @Override
+       public int getRows() {
+               boolean fitRows = getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_FIT_ROWS);
+               if(fitRows) return maxRow;
+               else return getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_ROW_COUNT);
+       }
+
+       @Override
+       public int getColumns() {
+               boolean fitCols = getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_FIT_COLS);
+               if(fitCols) {
+                       return maxColumn;
+               }
+               else return getPropertyAt(ClientModel.DIMENSIONS, ClientModel.DIMENSIONS_COL_COUNT);
+       }
+       
+       @Override
+       public int[] getColumnWidths() {
+               int[] data = getPropertyAt(HEADERS, HEADERS_COL_WIDTHS);
+               return data.clone();
+       }
+
+       @Override
+       public int[] getRowHeights() {
+               int[] data = getPropertyAt(HEADERS, HEADERS_ROW_HEIGHTS);
+               return data.clone();
+       }
+
+       @Override
+       public synchronized Collection<Pair<String, Object>> listAll(String property) {
+
+               ArrayList<Pair<String, Object>> result = new ArrayList<Pair<String, Object>>(); 
+               
+               for(Map.Entry<String, Map<String, Object>> entry : properties.entrySet()) {
+                       Object value = entry.getValue().get(property);
+                       if(value != null) result.add(Pair.make(entry.getKey(), value));
+               }
+               for(Map.Entry<String, Map<String, Object>> entry : cells.entrySet()) {
+                       Object value = entry.getValue().get(property);
+                       if(value != null) result.add(Pair.make(entry.getKey(), value));
+               }
+               
+               return result;
+               
+       }
+       
+       private long spanKey(int row, int column) {
+               return (row & 0xffffffff) | (((long)(column & 0xffffffff)) << 32);
+       }
+
+       @Override
+       public synchronized Rectangle getSpan(int row, int column) {
+               for (Rectangle span : spanMap.values()) {
+                       if (span.contains(column, row)) {
+                               return new Rectangle(span);
+                       }
+               }
+               return null;
+       }
+       
+       @Override
+       public synchronized List<Rectangle> getSpans() {
+               List<Rectangle> spans = new ArrayList<Rectangle>(spanMap.size());
+               for (Rectangle span : spanMap.values()) {
+                       spans.add(new Rectangle(span));
+               }
+               return spans;                   
+       }
+
+       private Rectangle getRootSpan(int row, int column) {
+               return spanMap.get(spanKey(row, column));
+       }
+       
+       private Rectangle createSpan(int row, int column, int rowSpan, int columnSpan) {
+               Rectangle span = new Rectangle(column, row, columnSpan, rowSpan);
+               spanMap.put(spanKey(row, column), span);
+               return span;
+       }
+       
+       private void removeSpan(int row, int column) {
+               spanMap.remove(spanKey(row, column));
+       }
+       
+}