SpreadsheetCells with Circular References support iterations.
[simantics/platform.git] / bundles / org.simantics.spreadsheet.ui / src / org / simantics / spreadsheet / ui / SpreadsheetModel.java
1 package org.simantics.spreadsheet.ui;\r
2 \r
3 import java.awt.BorderLayout;\r
4 import java.awt.Color;\r
5 import java.awt.Font;\r
6 import java.awt.Frame;\r
7 import java.awt.GridBagConstraints;\r
8 import java.awt.GridBagLayout;\r
9 import java.awt.Image;\r
10 import java.awt.Rectangle;\r
11 import java.awt.datatransfer.Clipboard;\r
12 import java.awt.datatransfer.Transferable;\r
13 import java.awt.datatransfer.UnsupportedFlavorException;\r
14 import java.awt.dnd.DnDConstants;\r
15 import java.awt.dnd.DropTarget;\r
16 import java.awt.dnd.DropTargetDragEvent;\r
17 import java.awt.dnd.DropTargetDropEvent;\r
18 import java.awt.dnd.DropTargetEvent;\r
19 import java.awt.dnd.DropTargetListener;\r
20 import java.awt.event.ActionEvent;\r
21 import java.awt.event.ActionListener;\r
22 import java.awt.event.ItemEvent;\r
23 import java.awt.event.ItemListener;\r
24 import java.awt.event.KeyEvent;\r
25 import java.io.IOException;\r
26 import java.util.Arrays;\r
27 import java.util.HashMap;\r
28 import java.util.Iterator;\r
29 import java.util.List;\r
30 import java.util.Map;\r
31 import java.util.Properties;\r
32 \r
33 import javax.imageio.ImageIO;\r
34 import javax.swing.AbstractAction;\r
35 import javax.swing.Action;\r
36 import javax.swing.DefaultListModel;\r
37 import javax.swing.ImageIcon;\r
38 import javax.swing.InputMap;\r
39 import javax.swing.JButton;\r
40 import javax.swing.JCheckBox;\r
41 import javax.swing.JColorChooser;\r
42 import javax.swing.JComboBox;\r
43 import javax.swing.JComponent;\r
44 import javax.swing.JList;\r
45 import javax.swing.JOptionPane;\r
46 import javax.swing.JPanel;\r
47 import javax.swing.JTable;\r
48 import javax.swing.JTextField;\r
49 import javax.swing.JToggleButton;\r
50 import javax.swing.KeyStroke;\r
51 import javax.swing.SwingUtilities;\r
52 import javax.swing.UIManager;\r
53 import javax.swing.event.ChangeEvent;\r
54 import javax.swing.event.ListSelectionEvent;\r
55 import javax.swing.event.TableColumnModelEvent;\r
56 import javax.swing.event.TableColumnModelListener;\r
57 import javax.swing.event.TableModelEvent;\r
58 import javax.swing.event.TableModelListener;\r
59 import javax.swing.table.TableColumn;\r
60 \r
61 import org.eclipse.core.runtime.Platform;\r
62 import org.eclipse.swt.widgets.Display;\r
63 import org.simantics.databoard.Bindings;\r
64 import org.simantics.databoard.binding.Binding;\r
65 import org.simantics.datatypes.literal.RGB;\r
66 import org.simantics.scenegraph.INode;\r
67 import org.simantics.scenegraph.swing.JScrollPaneSG;\r
68 import org.simantics.spreadsheet.Adaptable;\r
69 import org.simantics.spreadsheet.CellEditor;\r
70 import org.simantics.spreadsheet.CellEditor.Transaction;\r
71 import org.simantics.spreadsheet.ClientModel;\r
72 import org.simantics.spreadsheet.ClientModel.OperationMode;\r
73 import org.simantics.spreadsheet.SheetCommands;\r
74 import org.simantics.spreadsheet.common.cell.Parsers;\r
75 import org.simantics.spreadsheet.common.cell.StringCellParser;\r
76 import org.simantics.spreadsheet.event.model.RemoveCellHandler;\r
77 import org.simantics.spreadsheet.util.SpreadsheetUtils;\r
78 import org.simantics.ui.colors.Colors;\r
79 import org.simantics.ui.dnd.LocalObjectTransfer;\r
80 import org.simantics.ui.dnd.LocalObjectTransferable;\r
81 import org.simantics.ui.fonts.Fonts;\r
82 import org.simantics.utils.ui.dialogs.ShowMessage;\r
83 import org.simantics.utils.ui.jface.ActiveSelectionProvider;\r
84 \r
85 @SuppressWarnings({ "rawtypes", "unchecked" })\r
86 public class SpreadsheetModel {\r
87 \r
88         final private Adaptable serverInterface;\r
89         final private ClientModel clientModel;\r
90         final private ActiveSelectionProvider selectionProvider;\r
91         protected Clipboard system;\r
92         protected StringCellParser[] parsers =  new StringCellParser[] { Parsers.COMMAND_PARSER, Parsers.EXPRESSION_PARSER, Parsers.TEXT_PARSER };\r
93 \r
94         public SpreadsheetModel(Adaptable serverInterface, ActiveSelectionProvider selectionProvider) {\r
95 \r
96                 this.serverInterface = serverInterface;\r
97                 this.clientModel = new ClientModelImpl();\r
98                 this.selectionProvider = selectionProvider;\r
99 \r
100         }\r
101 \r
102         public ClientModel getClientModel() {\r
103                 return clientModel;\r
104         }\r
105 \r
106         public SpreadsheetTable getTable() {\r
107                 return table;\r
108         }\r
109 \r
110         private JTextField expression;\r
111         private JButton foreground;\r
112         private JButton background;\r
113         private JButton font;\r
114         private JButton align_left;\r
115         private JButton align_hcenter;\r
116         private JButton align_right;\r
117         private JButton align_top;\r
118         private JButton align_vcenter;\r
119         private JButton align_bottom;\r
120         private JComboBox borders;\r
121         public JComboBox inputSource;\r
122         public JComboBox sheets;\r
123         private JButton lock;\r
124         private JButton unlock;\r
125         private JButton merge;\r
126         private JButton unmerge;\r
127         private ExpressionTextListener etl;\r
128         private SpreadsheetTable table;\r
129         @SuppressWarnings("unused")\r
130         private ExcelAdapter excel;\r
131         @SuppressWarnings("unused")\r
132         private boolean columnMarginsDirty = false;\r
133         \r
134         private ItemListener itemListener = null;\r
135         private ItemListener sheetsListener = null;\r
136         private ItemListener initialConditionsListener = null;\r
137         \r
138         private JComboBox initialConditions;\r
139     private JButton saveIc;\r
140     private JButton context;\r
141     private JToggleButton operationMode;\r
142     \r
143     private JCheckBox iterationEnabled;\r
144     private JTextField iterationLimit;\r
145 \r
146         public JComponent createComponent(final INode node) {\r
147 \r
148                 Properties props = serverInterface.getAdapter(Properties.class);\r
149                 \r
150                 boolean addExpressionField = props == null || "true".equalsIgnoreCase(props.getProperty(SpreadsheetModelProperties.SHEET_EXPRESSION_VISIBLE, "true"));\r
151 \r
152                 final JPanel panel = new JPanel(new BorderLayout());\r
153                 \r
154                 final DefaultListModel lm = new DefaultListModel() {\r
155 \r
156                         private static final long serialVersionUID = 5246691801867533053L;\r
157 \r
158                         public Object getElementAt(int index) {\r
159                                 Object result = super.getElementAt(index);\r
160                                 if(result instanceof String) return result; \r
161                                 else return "" + (index + 1);\r
162                         }\r
163 \r
164                 };\r
165 \r
166                 if (addExpressionField) {\r
167                         \r
168                         foreground = new JButton();\r
169                         foreground.setToolTipText("Assign foreground color to selection");\r
170                         \r
171                         try {\r
172                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/paintbrush.png"));\r
173                                 foreground.setIcon(new ImageIcon(img));\r
174                         } catch (IOException ex) {\r
175                         }\r
176                         foreground.addActionListener(new ActionListener() {\r
177                                 @Override\r
178                                 public void actionPerformed(ActionEvent e) {\r
179                                         \r
180                                         Color c = JColorChooser.showDialog(foreground, "asd", Colors.awt(Colors.rgb(0, 0, 0)));\r
181                                         if (c == null)\r
182                                             return;\r
183                                         RGB.Integer color = Colors.integerRGB(c);\r
184 \r
185                                         editSelection(ClientModel.FOREGROUND, color, RGB.Integer.BINDING);\r
186                                 }\r
187                         });\r
188 \r
189                         background = new JButton();\r
190                         background.setToolTipText("Assign background color to selection");\r
191                         \r
192                         try {\r
193                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/paintcan.png"));\r
194                                 background.setIcon(new ImageIcon(img));\r
195                         } catch (IOException ex) {\r
196                         }\r
197                         \r
198                         background.addActionListener(new ActionListener() {\r
199                                 @Override\r
200                                 public void actionPerformed(ActionEvent e) {\r
201                                         \r
202                                         Color c = JColorChooser.showDialog(background, "asd", Colors.awt(Colors.rgb(0, 0, 0)));\r
203                                         if (c == null)\r
204                                             return;\r
205 \r
206                                         RGB.Integer color = Colors.integerRGB(c);\r
207 \r
208                                         editSelection(ClientModel.BACKGROUND, color, RGB.Integer.BINDING);\r
209                                 }\r
210                         });\r
211                         \r
212                         String[] availableInitialConditions = clientModel.getPossiblePropertyAt(ClientModel.STATES, ClientModel.STATES_AVAILABLE);\r
213                         String currentInitialCondition = clientModel.getPossiblePropertyAt(ClientModel.STATES, ClientModel.STATES_CURRENT);\r
214                         \r
215                         initialConditions = new JComboBox<>();\r
216                         for(String sheet : availableInitialConditions)\r
217                             initialConditions.addItem(sheet);\r
218                         \r
219                         initialConditions.setSelectedItem(currentInitialCondition);\r
220                         \r
221                         initialConditionsListener = new ItemListener() {\r
222                             @Override\r
223                 public void itemStateChanged(ItemEvent arg0) {\r
224                         \r
225                     CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
226                     if(editor != null) {\r
227                         if(arg0.getStateChange() == ItemEvent.SELECTED)\r
228                             editor.edit(null, ClientModel.STATES, ClientModel.STATES_CURRENT, arg0.getItem(), null, null);\r
229                     }\r
230                 }\r
231             };\r
232             \r
233             initialConditions.addItemListener(initialConditionsListener);\r
234 \r
235                         saveIc = new JButton();\r
236                         saveIc.setText("Save IC");\r
237                         saveIc.setToolTipText("Save current Initial Condition");\r
238                         saveIc.addActionListener(new ActionListener() {\r
239                 \r
240                 @Override\r
241                 public void actionPerformed(ActionEvent e) {\r
242                     \r
243                     SheetCommands commands = serverInterface.getAdapter(SheetCommands.class);\r
244                     commands.saveState();\r
245                 }\r
246             });\r
247                         \r
248                         font = new JButton();\r
249                         font.setToolTipText("Assign font to selection");\r
250                         \r
251                         font.addActionListener(new ActionListener() {\r
252                                 @Override\r
253                                 public void actionPerformed(ActionEvent e) {\r
254                                         JFontChooser fontChooser = new JFontChooser();\r
255                                         int result = fontChooser.showDialog(font);\r
256                                         if (result == JFontChooser.OK_OPTION) {\r
257                                                 \r
258                                                 Font font = fontChooser.getSelectedFont(); \r
259                                                 System.out.println("Selected Font : " + font);\r
260 \r
261                                                 org.simantics.datatypes.literal.Font f = Fonts.fromAWT(font);\r
262 \r
263                                                 editSelection(ClientModel.FONT, f, org.simantics.datatypes.literal.Font.BINDING);\r
264                                         }\r
265                                 }\r
266                         });\r
267                         \r
268                         try {\r
269                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/font.png"));\r
270                                 font.setIcon(new ImageIcon(img));\r
271                         } catch (IOException ex) {\r
272                         }\r
273 \r
274                         align_left = new JButton();\r
275                         align_left.setToolTipText("Align selection to left");\r
276                         \r
277                         try {\r
278                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/shape_align_left.png"));\r
279                                 align_left.setIcon(new ImageIcon(img));\r
280                         } catch (IOException ex) {\r
281                         }\r
282 \r
283                         align_left.addActionListener(new ActionListener() {\r
284                                 @Override\r
285                                 public void actionPerformed(ActionEvent e) {\r
286                                         editSelectionAlignment(0, null);\r
287                                 }\r
288                         });\r
289                         \r
290                         align_hcenter = new JButton();\r
291                         align_hcenter.setToolTipText("Align selection horizontally to center");\r
292                         \r
293                         try {\r
294                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/shape_align_center.png"));\r
295                                 align_hcenter.setIcon(new ImageIcon(img));\r
296                         } catch (IOException ex) {\r
297                         }\r
298 \r
299                         align_hcenter.addActionListener(new ActionListener() {\r
300                                 @Override\r
301                                 public void actionPerformed(ActionEvent e) {\r
302                                         editSelectionAlignment(1, null);\r
303                                 }\r
304                         });             \r
305                         \r
306                         align_right = new JButton();\r
307                         align_right.setToolTipText("Align selection to right");\r
308                         \r
309                         try {\r
310                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/shape_align_right.png"));\r
311                                 align_right.setIcon(new ImageIcon(img));\r
312                         } catch (IOException ex) {\r
313                         }\r
314 \r
315                         align_right.addActionListener(new ActionListener() {\r
316                                 @Override\r
317                                 public void actionPerformed(ActionEvent e) {\r
318                                         editSelectionAlignment(2, null);\r
319                                 }\r
320                         });             \r
321                         \r
322                         align_top = new JButton();\r
323                         align_top.setToolTipText("Align selection to top");\r
324                         \r
325                         try {\r
326                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/shape_align_top.png"));\r
327                                 align_top.setIcon(new ImageIcon(img));\r
328                         } catch (IOException ex) {\r
329                         }\r
330 \r
331                         align_top.addActionListener(new ActionListener() {\r
332                                 @Override\r
333                                 public void actionPerformed(ActionEvent e) {\r
334                                         editSelectionAlignment(null, 0);\r
335                                 }\r
336                         });             \r
337                         \r
338                         align_vcenter = new JButton();\r
339                         align_vcenter.setToolTipText("Align selection vertically to center");\r
340                         \r
341                         try {\r
342                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/shape_align_middle.png"));\r
343                                 align_vcenter.setIcon(new ImageIcon(img));\r
344                         } catch (IOException ex) {\r
345                         }\r
346 \r
347                         align_vcenter.addActionListener(new ActionListener() {\r
348                                 @Override\r
349                                 public void actionPerformed(ActionEvent e) {\r
350                                         editSelectionAlignment(null, 1);\r
351                                 }\r
352                         });             \r
353                         \r
354                         align_bottom = new JButton();\r
355                         align_bottom.setToolTipText("Align selection to bottom");\r
356                         \r
357                         try {\r
358                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/shape_align_bottom.png"));\r
359                                 align_bottom.setIcon(new ImageIcon(img));\r
360                         } catch (IOException ex) {\r
361                         }\r
362 \r
363                         align_bottom.addActionListener(new ActionListener() {\r
364                                 @Override\r
365                                 public void actionPerformed(ActionEvent e) {\r
366                                         editSelectionAlignment(null, 2);\r
367                                 }\r
368                         });             \r
369                         \r
370                         borders = new JComboBox();\r
371                         borders.addItem("No borders");\r
372                         borders.addItem("Bottom border");\r
373                         borders.addItem("Top border");\r
374                         borders.addItem("Left border");\r
375                         borders.addItem("Right border");\r
376                         borders.addActionListener(new ActionListener() {\r
377 \r
378                                 Map<String,Integer> work = new HashMap<String,Integer>();\r
379                                 \r
380                                 int getCurrent(String location, int row, int column) {\r
381                                         CellValue value = (CellValue)table.getValueAt(row, column);\r
382                                         int border = value != null ? value.border : 0;\r
383                                         work.put(location, border);\r
384                                         return border;\r
385                                 }\r
386                                 \r
387                                 void setCurrent(String location, int border) {\r
388                                         work.put(location, border);\r
389                                 }\r
390                                 \r
391                                 @Override\r
392                                 public void actionPerformed(ActionEvent e) {\r
393                                         \r
394                                         work.clear();\r
395                                         \r
396                                         int index = borders.getSelectedIndex();\r
397                                         \r
398                                         final int[] selectedColumns = table.getSelectedColumns();\r
399                                         final int[] selectedRows = table.getSelectedRows();\r
400 \r
401                                         CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
402                                         if(editor == null) return;\r
403                                         \r
404                                         for(int col : selectedColumns) {\r
405                                                 for(int row : selectedRows) {\r
406                                                         \r
407                                                         String location = SpreadsheetUtils.cellName(row, col);\r
408                                                         \r
409                                                         // No\r
410                                                         if(index == 0) {\r
411                                                                 if(col > 0) {\r
412                                                                         String left = SpreadsheetUtils.cellName(row, col-1);\r
413                                                                         setCurrent(left, getCurrent(left, row, col-1) & 2);\r
414                                                                 }\r
415                                                                 if(row > 0) {\r
416                                                                         String up = SpreadsheetUtils.cellName(row-1, col);\r
417                                                                         setCurrent(up, getCurrent(up, row-1, col) & 1);\r
418                                                                 }\r
419                                                                 setCurrent(location, 0);\r
420                                                         }\r
421                                                         // Bottom\r
422                                                         else if(index == 1) {\r
423                                                                 setCurrent(location, getCurrent(location, row, col) | 2);\r
424                                                         }\r
425                                                         // Top\r
426                                                         else if(index == 2) {\r
427                                                                 if(row > 0) {\r
428                                                                         String up = SpreadsheetUtils.cellName(row-1, col);\r
429                                                                         setCurrent(up, getCurrent(up, row-1, col) | 2);\r
430                                                                 }\r
431                                                         }\r
432                                                         // Left\r
433                                                         else if(index == 3) {\r
434                                                                 if(col > 0) {\r
435                                                                         String left = SpreadsheetUtils.cellName(row, col-1);\r
436                                                                         setCurrent(left, getCurrent(left, row, col-1) | 1);\r
437                                                                 }\r
438                                                         }\r
439                                                         // Right\r
440                                                         else if(index == 4) {\r
441                                                                 setCurrent(location, getCurrent(location, row, col) | 1);\r
442                                                         }\r
443                                                         \r
444                                                 }\r
445                                                 \r
446                                         }\r
447                                         OperationMode mode = clientModel.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
448                                         Transaction transaction = editor.startTransaction(mode);\r
449                                         for(Map.Entry<String, Integer> entry : work.entrySet()) {\r
450                                                 String location = entry.getKey();\r
451                                                 Integer border = entry.getValue();\r
452                                                 editor.edit(transaction, location, ClientModel.BORDER, border, Bindings.INTEGER, null);\r
453                                         }\r
454                                         transaction.commit();\r
455                                         \r
456                                 }\r
457                         });\r
458                         \r
459                         \r
460                         lock = new JButton();\r
461                         lock.setToolTipText("Lock selection");\r
462                         \r
463                         try {\r
464                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/lock.png"));\r
465                                 lock.setIcon(new ImageIcon(img));\r
466                         } catch (IOException ex) {\r
467                         }\r
468                         \r
469                         lock.addActionListener(new ActionListener() {\r
470                                 @Override\r
471                                 public void actionPerformed(ActionEvent e) {\r
472                                         editSelection(ClientModel.LOCKED, true, Bindings.BOOLEAN);\r
473                                 }\r
474                         });\r
475 \r
476                         unlock = new JButton();\r
477                         unlock.setToolTipText("Unlock selection");\r
478                         \r
479                         try {\r
480                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/lock_open.png"));\r
481                                 unlock.setIcon(new ImageIcon(img));\r
482                         } catch (IOException ex) {\r
483                         }\r
484                         \r
485                         unlock.addActionListener(new ActionListener() {\r
486                                 @Override\r
487                                 public void actionPerformed(ActionEvent e) {\r
488                                         editSelection(ClientModel.LOCKED, false, Bindings.BOOLEAN);\r
489                                 }\r
490                         });\r
491                         \r
492                         merge = new JButton();\r
493                         merge.setToolTipText("Merge cells");\r
494                         \r
495                         try {\r
496                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/link.png"));\r
497                                 merge.setIcon(new ImageIcon(img));\r
498                         } catch (IOException ex) {\r
499                         }\r
500                         \r
501                         merge.addActionListener(new ActionListener() {\r
502                                 @Override\r
503                                 public void actionPerformed(ActionEvent e) {\r
504                                         \r
505                                         final int[] selectedColumns = table.getSelectedColumns();\r
506                                         final int[] selectedRows = table.getSelectedRows();\r
507 \r
508                                         if (isRectangularSelection(table)) {\r
509                                         \r
510                                                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
511                                                 if(editor == null) return;\r
512                                                 \r
513                                                 OperationMode mode = clientModel.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
514                                                 Transaction transaction = editor.startTransaction(mode);\r
515                                                 \r
516                                                 Rectangle selection = new Rectangle(selectedColumns[0], selectedRows[0], selectedColumns.length, selectedRows.length);\r
517                                                 List<Rectangle> spans = clientModel.getSpans();\r
518                                                 \r
519                                                 boolean found = true;\r
520                                                 while (found) {\r
521                                                         found = false;\r
522                                                         Iterator<Rectangle> iter = spans.iterator();\r
523                                                         while (iter.hasNext()) {\r
524                                                                 Rectangle span = iter.next();\r
525                                                                 if (selection.intersects(span)) {\r
526                                                                         selection = selection.union(span);\r
527                                                                         found = true;\r
528                                                                         String location = SpreadsheetUtils.cellName(span.y, span.x);\r
529                                                                         editor.edit(transaction, location, ClientModel.ROW_SPAN, 1, Bindings.INTEGER, null);\r
530                                                                         editor.edit(transaction, location, ClientModel.COLUMN_SPAN, 1, Bindings.INTEGER, null);\r
531                                                                         iter.remove();\r
532                                                                 }\r
533                                                         }\r
534                                                 }\r
535                                                 \r
536                                                 String location = SpreadsheetUtils.cellName(selection.y, selection.x);\r
537                                                 if (selection.height > 1) {\r
538                                                         editor.edit(transaction, location, ClientModel.ROW_SPAN, selection.height, Bindings.INTEGER, null);\r
539                                                 }\r
540                                                 if (selection.width > 1) {\r
541                                                         editor.edit(transaction, location, ClientModel.COLUMN_SPAN, selection.width, Bindings.INTEGER, null);\r
542                                                 }\r
543                                                 transaction.commit();\r
544                                                 \r
545                                         } else {\r
546                                                 //ShowMessage.showError(, message);\r
547                                                 Display.getDefault().asyncExec(new Runnable() {\r
548                                                         public void run() {\r
549                                                                 ShowMessage.showWarning("Merging cells failed", "Selected range is not rectangular.");\r
550                                                         }\r
551                                                 });\r
552                                         }\r
553                                 }\r
554                         });\r
555                         \r
556                         unmerge = new JButton();\r
557                         unmerge.setToolTipText("Unmerge cells");\r
558                         \r
559                         try {\r
560                                 Image img = ImageIO.read(Platform.getBundle("com.famfamfam.silk").getResource("icons/link_break.png"));\r
561                                 unmerge.setIcon(new ImageIcon(img));\r
562                         } catch (IOException ex) {\r
563                         }\r
564                         \r
565                         unmerge.addActionListener(new ActionListener() {\r
566                                 @Override\r
567                                 public void actionPerformed(ActionEvent e) {\r
568                                         \r
569                                         CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
570                                         if(editor == null) return;\r
571                                         \r
572                                         OperationMode mode = clientModel.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
573                                         Transaction transaction = editor.startTransaction(mode);\r
574                                         editSelection(editor, transaction, ClientModel.ROW_SPAN, 1, Bindings.INTEGER);\r
575                                         editSelection(editor, transaction, ClientModel.COLUMN_SPAN, 1, Bindings.INTEGER);\r
576                                         transaction.commit();\r
577                                 }\r
578                         });\r
579                         \r
580                         String[] availableSources = clientModel.getPossiblePropertyAt(ClientModel.SOURCES, ClientModel.SOURCES_AVAILABLE);\r
581                         String[] availableSheets = clientModel.getPossiblePropertyAt(ClientModel.SHEETS, ClientModel.SHEETS_AVAILABLE);\r
582                         String currentSheet = clientModel.getPossiblePropertyAt(ClientModel.SHEETS, ClientModel.SHEETS_CURRENT);\r
583                         @SuppressWarnings("unused")\r
584                         String currentSource = clientModel.getPossiblePropertyAt(ClientModel.SOURCES, ClientModel.SOURCES_CURRENT);\r
585                         \r
586                         inputSource = new JComboBox();\r
587                         for(String source : availableSources)\r
588                                 inputSource.addItem(source);\r
589 \r
590                         sheets = new JComboBox();\r
591                         for(String sheet : availableSheets)\r
592                                 sheets.addItem(sheet);\r
593                         \r
594             sheets.setSelectedItem(currentSheet);\r
595 \r
596             sheetsListener = new ItemListener() {\r
597 \r
598                 @Override\r
599                 public void itemStateChanged(ItemEvent arg0) {\r
600 \r
601                     CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
602                     if (editor != null) {\r
603                         if (arg0.getStateChange() == ItemEvent.SELECTED)\r
604                             editor.edit(null, ClientModel.SHEETS, ClientModel.SHEETS_CURRENT, arg0.getItem(), null,\r
605                                     null);\r
606                     }\r
607                 }\r
608             };\r
609 \r
610                         itemListener = new ItemListener() {\r
611                                 \r
612                                 @Override\r
613                                 public void itemStateChanged(ItemEvent arg0) {\r
614                                         \r
615                                         CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
616                                         if(editor != null) {\r
617                                                 if(arg0.getStateChange() == ItemEvent.SELECTED)\r
618                                                         editor.edit(null, ClientModel.SOURCES, ClientModel.SOURCES_CURRENT, arg0.getItem(), null, null);\r
619                                         }\r
620 \r
621                                 }\r
622                                 \r
623                         };\r
624                         \r
625                         inputSource.addItemListener(itemListener);\r
626                         \r
627                         new DropTarget(inputSource,DnDConstants.ACTION_COPY_OR_MOVE,new DropTargetListener() {\r
628                                 \r
629                                 @Override\r
630                                 public void dropActionChanged(DropTargetDragEvent arg0) {\r
631                                         // TODO Auto-generated method stub\r
632                                         \r
633                                 }\r
634                                 \r
635                                 @Override\r
636                                 public void drop(DropTargetDropEvent dtde) {\r
637                                         \r
638                         try {\r
639                             Transferable transferable = dtde.getTransferable();\r
640                             \r
641                             if( transferable.isDataFlavorSupported( \r
642                                     LocalObjectTransferable.FLAVOR ) ) {\r
643                                 \r
644                                 dtde.acceptDrop( DnDConstants.ACTION_MOVE );\r
645                                 \r
646                                 transferable.getTransferData(LocalObjectTransferable.FLAVOR );\r
647                                 Object obj = LocalObjectTransfer.getTransfer().getObject();\r
648                                 \r
649                                                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
650                                                 if(editor != null) {\r
651                                                         editor.edit(null, ClientModel.SOURCES, ClientModel.SOURCES_CURRENT, obj, null, null);\r
652                                                 }\r
653                                 \r
654                                 dtde.getDropTargetContext().dropComplete( true );\r
655                                 \r
656                             }\r
657                             else {\r
658                                 dtde.rejectDrop();\r
659                             }\r
660                         } catch( IOException exception ) {\r
661                             exception.printStackTrace();\r
662                             dtde.rejectDrop();\r
663                         } catch( UnsupportedFlavorException ufException ) {\r
664                             ufException.printStackTrace();\r
665                             dtde.rejectDrop();\r
666                         }\r
667                                         \r
668                                 }\r
669                                 \r
670                                 @Override\r
671                                 public void dragOver(DropTargetDragEvent arg0) {\r
672                                         // TODO Auto-generated method stub\r
673                                         \r
674                                 }\r
675                                 \r
676                                 @Override\r
677                                 public void dragExit(DropTargetEvent arg0) {\r
678                                         // TODO Auto-generated method stub\r
679                                         \r
680                                 }\r
681                                 \r
682                                 @Override\r
683                                 public void dragEnter(DropTargetDragEvent arg0) {\r
684                                         // TODO Auto-generated method stub\r
685                                         \r
686                                 }\r
687                                 \r
688                         });\r
689                         \r
690                         expression = new JTextField();\r
691                         etl = new ExpressionTextListener(expression, serverInterface.getAdapter(CellEditor.class));\r
692                         expression.addFocusListener(etl);\r
693                         expression.addKeyListener(etl);\r
694                         \r
695                      sheets.addItemListener(sheetsListener);\r
696 \r
697                         \r
698                         context = new JButton("Change context");\r
699                         \r
700                         context.addActionListener(new ActionListener() {\r
701                             \r
702                             @Override\r
703                             public void actionPerformed(ActionEvent e) {\r
704                                 \r
705                                 Frame frame = (Frame) SwingUtilities.getRoot(context);\r
706                                 String result = JOptionPane.showInputDialog(frame, "Context URI");\r
707                                 if (result != null && !result.isEmpty()) {\r
708                                     CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
709                                     if(editor != null) {\r
710                                         editor.edit(null, ClientModel.CONTEXT, ClientModel.CONTEXT_CURRENT, result, null, null);\r
711                                     }\r
712                                 }\r
713                             }\r
714                         });\r
715                         \r
716                         OperationMode currentMode = clientModel.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
717                         String text;\r
718                         if (currentMode.equals(OperationMode.OPERATION))\r
719                             text = "Operation Mode";\r
720                         else\r
721                             text = "Edit Mode";\r
722                         operationMode = new JToggleButton(text);\r
723                         operationMode.addActionListener(new ActionListener() {\r
724                             \r
725                             @Override\r
726                             public void actionPerformed(ActionEvent e) {\r
727                                 \r
728                                 OperationMode currentMode = clientModel.getPropertyAt(ClientModel.MODE, ClientModel.MODE_CURRENT);\r
729                                 OperationMode newMode;\r
730                                 String newText;\r
731                                 if (currentMode.equals(OperationMode.OPERATION)) {\r
732                                     System.err.println("Current mode is operation");\r
733                                     newMode = OperationMode.EDIT_MODE;\r
734                                     newText = "Edit Mode";\r
735                                 } else {\r
736                                     System.err.println("Current mode is read-only");\r
737                                     newMode = OperationMode.OPERATION;\r
738                                     newText = "Operation Mode";\r
739                                 }\r
740                                 System.err.println("Setting new text " + newText + " to replace old " + operationMode.getText());\r
741                                 operationMode.setText(newText);\r
742                                 \r
743                                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
744                                 if(editor != null) {\r
745                                     editor.edit(null, ClientModel.MODE, ClientModel.MODE_CURRENT, newMode, null, null);\r
746                                 }\r
747                             }\r
748                         });\r
749                         \r
750                         iterationEnabled = new JCheckBox("Iteration Enabled");\r
751                         iterationEnabled.addActionListener(new ActionListener() {\r
752                             \r
753                             @Override\r
754                             public void actionPerformed(ActionEvent e) {\r
755                                 System.out.println("state is " + iterationEnabled.isSelected());\r
756                                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
757                                 if(editor != null) {\r
758                                     editor.edit(null, ClientModel.ITERATION_ENABLED, ClientModel.ITERATION_ENABLED, iterationEnabled.isSelected(), null, null);\r
759                                 }\r
760                             }\r
761                         });\r
762                         \r
763                         iterationLimit = new JTextField("100");\r
764                         iterationLimit.setEnabled(false);\r
765                         iterationLimit.addActionListener(new ActionListener() {\r
766                             \r
767                             @Override\r
768                             public void actionPerformed(ActionEvent e) {\r
769                                 \r
770                             }\r
771                         });\r
772 \r
773                 }\r
774                 \r
775                 Font font = new Font("Courier", Font.PLAIN, 14);\r
776 \r
777                 UIManager.put(SpreadsheetTable.uiClassID, SpreadsheetTableUI.class.getCanonicalName());\r
778                 final JList rowHeader = new JList(lm);\r
779                 table = new SpreadsheetTable(node, (CellEditor)serverInterface.getAdapter(CellEditor.class), clientModel, lm, rowHeader) {\r
780                         \r
781                         private static final long serialVersionUID = 4553572254034185984L;\r
782 \r
783                         @Override\r
784                         protected void mouseDragFinished() {\r
785                                 \r
786                                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
787                                 if(editor == null) return;\r
788 \r
789                                 TableColumn column = table.getTableHeader().getResizingColumn();\r
790                                 if(column == null) return;\r
791 \r
792                                 int[] current = clientModel.getColumnWidths();\r
793                                 if(column.getModelIndex() >= current.length) {\r
794                                         current = Arrays.copyOf(current, column.getModelIndex()+1);\r
795                                 }\r
796 \r
797                                 current[column.getModelIndex()] = column.getWidth();\r
798 \r
799                                 editor.edit(null, ClientModel.HEADERS, ClientModel.HEADERS_COL_WIDTHS, current, Bindings.INT_ARRAY, null);\r
800                                 \r
801                         }\r
802                         \r
803                 };\r
804 \r
805                 ((ClientTableModel)table.getModel()).setModel(this);\r
806 \r
807                 InputMap im = table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);\r
808                 Action deleteAction = new AbstractAction() {\r
809                         private static final long serialVersionUID = 428343700053346645L;\r
810 \r
811                         @SuppressWarnings("unused")\r
812                         public void actionPerformed(ActionEvent ae) {\r
813                                 System.out.println("deleteaction");\r
814                                 RemoveCellHandler removeHandler = serverInterface.getAdapter(RemoveCellHandler.class);\r
815                                 int[] rowSelection = table.getSelectedRows();\r
816                                 int[] columnSelection = table.getSelectedColumns();\r
817                                 for (int i = 0; i < columnSelection.length; i++) {\r
818                                         for (int j = 0; j < rowSelection.length; j++) {\r
819                                                 int row = rowSelection[j];\r
820                                                 int column = columnSelection[i];\r
821                                                 System.out.println("deleteaction " + row + " " + column);\r
822                                                 Object cell = table.getValueAt(row, column);\r
823                                                 //                                  RemoveHandler remove = cell.getAdapter(RemoveHandler.class);\r
824                                                 //                                  remove.handle();\r
825                                         }\r
826                                 }\r
827                         }\r
828                 };\r
829                 KeyStroke delete = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);\r
830                 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), delete);\r
831                 table.getActionMap().put(im.get(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)), deleteAction);\r
832 \r
833                 table.setFont(font);\r
834 \r
835                 @SuppressWarnings("unused")\r
836                 DropTarget dropTarget = new DropTarget(table,\r
837                                 new TableDropTargetListener(table, serverInterface, clientModel));\r
838 \r
839                 if(serverInterface != null)\r
840                         excel = new ExcelAdapter(table, clientModel, serverInterface, parsers);\r
841 \r
842                 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);\r
843 \r
844                 table.setColumnSelectionAllowed(true);\r
845                 \r
846                 rowHeader.setFixedCellWidth(40);\r
847 \r
848                 rowHeader.setCellRenderer(new RowHeaderRenderer(table));\r
849                 rowHeader.setBackground(DefaultLookup.GRAY);\r
850 \r
851                 table.getModel().addTableModelListener(new TableModelListener() {\r
852 \r
853                         @Override\r
854                         public void tableChanged(TableModelEvent e) {\r
855                                 int currentRows = rowHeader.getModel().getSize();\r
856                                 int tableRows = table.getModel().getRowCount();\r
857                                 if(currentRows != tableRows) {\r
858                                         lm.setSize(tableRows);\r
859                                 }\r
860                         }\r
861                 });\r
862 \r
863                 JScrollPaneSG scroll = new JScrollPaneSG(table, node);\r
864 \r
865                 scroll.setRowHeaderView(rowHeader);\r
866 \r
867                 table.getParent().setBackground(DefaultLookup.GRAY);\r
868                 table.getTableHeader().setBackground(DefaultLookup.GRAY);\r
869                 rowHeader.getParent().setBackground(DefaultLookup.GRAY);\r
870                 scroll.getViewport().setBackground(DefaultLookup.GRAY);\r
871 \r
872                 table.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer());\r
873 \r
874                 scroll.setBackground(DefaultLookup.GRAY);\r
875 \r
876                 if(selectionProvider != null) {\r
877 \r
878                         SelectionListener listener = new SelectionListener(table, expression, etl, selectionProvider, serverInterface, clientModel);\r
879                         table.getSelectionModel().addListSelectionListener(listener);\r
880                         table.getColumnModel().getSelectionModel()\r
881                         .addListSelectionListener(listener);\r
882 \r
883                 }\r
884                 \r
885                 table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {\r
886 \r
887                         @Override\r
888                         public void columnSelectionChanged(ListSelectionEvent e) {\r
889                                 //                    System.out.println("columnSelectionChanged " + e);\r
890                         }\r
891 \r
892                         @Override\r
893                         public void columnRemoved(TableColumnModelEvent e) {\r
894                                 //                    System.out.println("columnRemoved " + e);\r
895                         }\r
896 \r
897                         @Override\r
898                         public void columnMoved(TableColumnModelEvent e) {\r
899                                 //                    System.out.println("columnMoved " + e);\r
900                         }\r
901 \r
902                         @Override\r
903                         public void columnMarginChanged(ChangeEvent e) {\r
904                                 columnMarginsDirty = true;\r
905                         }\r
906 \r
907                         @Override\r
908                         public void columnAdded(TableColumnModelEvent e) {\r
909                                 //                    System.out.println("columnAdded " + e);\r
910                         }\r
911 \r
912                 });\r
913                 \r
914                 new TableRowResizer(table) {\r
915                         \r
916                         @Override\r
917                         public void onResize(int row, int height) {\r
918                                 \r
919                                 if(row < 0) return;\r
920                                 \r
921                                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
922                                 if(editor == null) return;\r
923 \r
924                                 int[] current = clientModel.getRowHeights();\r
925                                 if(row >= current.length) {\r
926                                         current = Arrays.copyOf(current, row+1);\r
927                                 }\r
928 \r
929                                 current[row] = height;\r
930 \r
931                                 editor.edit(null, ClientModel.HEADERS, ClientModel.HEADERS_ROW_HEIGHTS, current, Bindings.INT_ARRAY, null);\r
932                                 \r
933                                 rowHeader.setCellRenderer(new RowHeaderRenderer(table));\r
934                                 \r
935                         }\r
936                         \r
937                 };\r
938                 \r
939                 if (addExpressionField) {\r
940                         \r
941                         JPanel tools = new JPanel(new GridBagLayout());\r
942                         panel.add(tools, BorderLayout.PAGE_START);\r
943 \r
944                         GridBagConstraints c = new GridBagConstraints();                        \r
945 \r
946                         c.gridx = 0;\r
947                 c.anchor = GridBagConstraints.WEST;\r
948                         tools.add(this.font, c);\r
949 \r
950                         c.gridx = 1;\r
951                         tools.add(foreground, c);\r
952 \r
953                         c.gridx = 2;\r
954                         tools.add(background, c);\r
955 \r
956                         c.gridx = 3;\r
957                         tools.add(align_left, c);\r
958                         c.gridx = 4;\r
959                         tools.add(align_hcenter, c);\r
960                         c.gridx = 5;\r
961                         tools.add(align_right, c);\r
962 \r
963                         c.gridx = 6;\r
964                         tools.add(align_top, c);\r
965                         c.gridx = 7;\r
966                         tools.add(align_vcenter, c);\r
967                         c.gridx = 8;\r
968                         tools.add(align_bottom, c);\r
969 \r
970                         c.gridx = 9;\r
971                         tools.add(borders, c);\r
972 \r
973                         c.gridx = 10;\r
974                         tools.add(lock, c);\r
975                         c.gridx = 11;\r
976                         tools.add(unlock, c);\r
977 \r
978                         c.gridx = 12;\r
979                         tools.add(merge, c);\r
980                         c.gridx = 13;\r
981                         tools.add(unmerge, c);\r
982                         \r
983                         c.gridx = 14;\r
984                         tools.add(inputSource, c);\r
985 \r
986                         c.gridx = 15;\r
987                         tools.add(sheets, c);\r
988 \r
989                         c.gridx = 16;\r
990                         tools.add(initialConditions, c);\r
991                         \r
992                         c.gridx = 17;\r
993                         tools.add(saveIc, c);\r
994                         \r
995                         c.gridx = 18;\r
996                         tools.add(context, c);\r
997                         \r
998                         c.gridx = 19;\r
999                         tools.add(operationMode, c);\r
1000                         \r
1001                         c.gridx = 20;\r
1002                         tools.add(iterationEnabled, c);\r
1003                         \r
1004                         c.gridx = 21;\r
1005                         tools.add(iterationLimit, c);\r
1006 \r
1007                         c.gridx = 0;\r
1008                         c.gridy = 1;\r
1009                         c.gridwidth = 22;\r
1010                 c.gridheight = 1;\r
1011                 c.weighty = 0.0;\r
1012                 c.weightx = 1.0;\r
1013                 c.fill = GridBagConstraints.HORIZONTAL;\r
1014 \r
1015                         tools.add(expression,c);\r
1016                         \r
1017                 }\r
1018                 panel.add(scroll, BorderLayout.CENTER);\r
1019 \r
1020                 return panel;\r
1021 \r
1022         }\r
1023 \r
1024         private boolean isRectangularSelection(SpreadsheetTable table) {\r
1025                 int[] selectedColumns = table.getSelectedColumns();\r
1026                 int[] selectedRows = table.getSelectedRows();\r
1027 \r
1028                 if ((selectedColumns.length == 0) || (selectedRows.length == 0)) {\r
1029                         return false;\r
1030                 }\r
1031                 \r
1032                 for (int row = 0; row < selectedRows.length - 1; row++) {\r
1033                         if (selectedRows[row + 1] != selectedRows[row] + 1) {\r
1034                                 return false;\r
1035                         }\r
1036                 }\r
1037                 \r
1038                 for (int column = 0; column < selectedColumns.length - 1; column++) {\r
1039                         if (selectedColumns[column + 1] != selectedColumns[column] + 1) {\r
1040                                 return false;\r
1041                         }\r
1042                 }\r
1043                 \r
1044                 return true;\r
1045         }\r
1046         \r
1047         private void editSelection(String property, Object value, Binding binding) { \r
1048                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
1049                 if(editor == null) return;\r
1050                 \r
1051 //              Transaction transaction = editor.startTransaction();\r
1052                 editSelection(editor, null, property, value, binding);\r
1053 //              transaction.commit();\r
1054         }\r
1055 \r
1056         private void editSelection(CellEditor editor, Transaction transaction, String property, Object value, Binding binding) { \r
1057                 for(int col : table.getSelectedColumns()) {\r
1058                         for(int row : table.getSelectedRows()) {\r
1059                                 String location = SpreadsheetUtils.cellName(row, col);\r
1060                                 editor.edit(transaction, location, property, value, binding, null);\r
1061                         }\r
1062                 }\r
1063         }\r
1064         \r
1065         \r
1066         private void editSelectionAlignment(Integer horizontal, Integer vertical) {\r
1067                 final int[] selectedColumns = table.getSelectedColumns();\r
1068                 final int[] selectedRows = table.getSelectedRows();\r
1069         \r
1070                 CellEditor editor = serverInterface.getAdapter(CellEditor.class);\r
1071                 if(editor == null) return;\r
1072         \r
1073 //              Transaction transaction = editor.startTransaction(); \r
1074                 for(int col : selectedColumns) {\r
1075                         for(int row : selectedRows) {\r
1076                                 String location = SpreadsheetUtils.cellName(row, col);\r
1077                                 \r
1078                                 CellValue value = (CellValue)table.getValueAt(row, col);\r
1079                                 int align = value != null ? value.align : 0;\r
1080                                 \r
1081                                 if (horizontal != null) {\r
1082                                         align = (align & 12) + horizontal;\r
1083                                 }\r
1084                                 if (vertical != null) {\r
1085                                         align = (align & 3) + (vertical << 2);\r
1086                                 }\r
1087 \r
1088 //                              editor.edit(transaction, location, ClientModel.ALIGN, align, Bindings.INTEGER);\r
1089                                 editor.edit(null, location, ClientModel.ALIGN, align, Bindings.INTEGER, null);\r
1090                                 \r
1091                         }\r
1092                 }\r
1093 //              transaction.commit();\r
1094         }\r
1095         \r
1096         public ClientModel getClientInterface() {\r
1097 \r
1098                 return clientModel;\r
1099 \r
1100         }\r
1101 \r
1102         public void setSources() {\r
1103                 // If expression fields are not visible, do nothing.\r
1104                 if (inputSource == null)\r
1105                         return;\r
1106 \r
1107                 String[] available = (String[])getClientModel().getPossiblePropertyAt(ClientModel.SOURCES, ClientModel.SOURCES_AVAILABLE);\r
1108                 String current = (String)getClientModel().getPossiblePropertyAt(ClientModel.SOURCES, ClientModel.SOURCES_CURRENT);\r
1109                 \r
1110                 inputSource.removeItemListener(itemListener);\r
1111                 inputSource.removeAllItems();\r
1112                 for(String a : available)\r
1113                         inputSource.addItem(a);\r
1114                 inputSource.setSelectedItem(current);\r
1115                 inputSource.addItemListener(itemListener);\r
1116                 \r
1117         }\r
1118 \r
1119 \r
1120 }