2bddd6fa3ba07f1dc8a787913c8c7a9ab27e64d2
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / actions / SuperblockMaskCustomizeAction.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
4  * Copyright (C) 2009 - DIGITEO - Clement DAVID
5  * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
6  *
7  * Copyright (C) 2012 - 2016 - Scilab Enterprises
8  *
9  * This file is hereby licensed under the terms of the GNU GPL v2.0,
10  * pursuant to article 5.3.4 of the CeCILL v.2.1.
11  * This file was originally licensed under the terms of the CeCILL v2.1,
12  * and continues to be available under such terms.
13  * For more information, see the COPYING file which you should have received
14  * along with this program.
15  *
16  */
17
18 package org.scilab.modules.xcos.block.actions;
19
20 import java.awt.event.ActionEvent;
21 import java.awt.event.ActionListener;
22 import java.util.Arrays;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.swing.BorderFactory;
31 import javax.swing.DefaultCellEditor;
32 import javax.swing.JComboBox;
33 import javax.swing.JFrame;
34 import javax.swing.WindowConstants;
35 import javax.swing.event.ChangeEvent;
36 import javax.swing.event.ChangeListener;
37 import javax.swing.event.ListSelectionEvent;
38 import javax.swing.event.ListSelectionListener;
39 import javax.swing.event.TableModelEvent;
40 import javax.swing.event.TableModelListener;
41 import javax.swing.table.DefaultTableModel;
42 import javax.swing.table.TableColumn;
43
44 import org.scilab.modules.graph.ScilabComponent;
45 import org.scilab.modules.graph.ScilabGraph;
46 import org.scilab.modules.graph.actions.base.DefaultAction;
47 import org.scilab.modules.gui.menuitem.MenuItem;
48 import org.scilab.modules.types.ScilabDouble;
49 import org.scilab.modules.types.ScilabList;
50 import org.scilab.modules.types.ScilabString;
51 import org.scilab.modules.types.ScilabType;
52 import org.scilab.modules.xcos.JavaController;
53 import org.scilab.modules.xcos.ObjectProperties;
54 import org.scilab.modules.xcos.VectorOfDouble;
55 import org.scilab.modules.xcos.block.SuperBlock;
56 import org.scilab.modules.xcos.graph.XcosDiagram;
57 import org.scilab.modules.xcos.io.ScilabTypeCoder;
58 import org.scilab.modules.xcos.utils.XcosMessages;
59
60 /**
61  * Customize the mask of the {@link SuperBlock}.
62  */
63 @SuppressWarnings(value = { "serial" })
64 public final class SuperblockMaskCustomizeAction extends DefaultAction {
65     /** Name of the action */
66     public static final String NAME = XcosMessages.CUSTOMIZE;
67     /** Icon name of the action */
68     public static final String SMALL_ICON = "";
69     /** Mnemonic key of the action */
70     public static final int MNEMONIC_KEY = 0;
71     /** Accelerator key for the action */
72     public static final int ACCELERATOR_KEY = 0;
73
74     private static final String TERMINATE_EDIT_ON_FOCUS_LOST = "terminateEditOnFocusLost";
75
76     /**
77      * Private constructor
78      *
79      * @param scilabGraph
80      *            the associated graph
81      */
82     public SuperblockMaskCustomizeAction(ScilabGraph scilabGraph) {
83         super(scilabGraph);
84     }
85
86     /**
87      * Create the menu associated with this action
88      *
89      * @param scilabGraph
90      *            the associated graph
91      * @return the newly created menu
92      */
93     public static MenuItem createMenu(ScilabGraph scilabGraph) {
94         return createMenu(scilabGraph, SuperblockMaskCustomizeAction.class);
95     }
96
97     /**
98      * Function to be performed by this action.
99      *
100      * @param e
101      *            The associated event
102      */
103     @Override
104     public void actionPerformed(ActionEvent e) {
105         final XcosDiagram graph = (XcosDiagram) getGraph(e);
106
107         // action disabled when the cell is edited
108         final ScilabComponent comp = ((ScilabComponent) graph.getAsComponent());
109         if (comp.isEditing()) {
110             return;
111         }
112
113         SuperBlock block = (SuperBlock) graph.getSelectionCell();
114
115         CustomizeFrame frame = new CustomizeFrame(graph);
116         CustomizeFrame.CustomizeFrameModel model = frame.getController().getModel();
117         model.setBlock(block);
118         model.importFromBlock();
119         frame.setVisible(true);
120     }
121
122     /**
123      * Frame used to customize fields and variables default values. DAC: this
124      * class is tightly coupled to Swing
125      */
126     // CSOFF: ClassDataAbstractionCoupling
127     @SuppressWarnings(value = { "serial" })
128     private class CustomizeFrame extends JFrame {
129
130         private final CustomizeFrameControler controler;
131
132         private javax.swing.JPanel buttonBlob;
133         private javax.swing.JButton cancelButton;
134         private javax.swing.JPanel customizeMainPanel;
135         private javax.swing.JScrollPane customizeScrollPane;
136         private javax.swing.JTabbedPane tabbedPane;
137         private javax.swing.JTable defaultValueTable;
138         private javax.swing.JPanel defaultValues;
139         private javax.swing.JScrollPane defaultValuesScrollPane;
140         private javax.swing.JButton delete;
141         private javax.swing.JButton insert;
142         private javax.swing.JPanel mainPanel;
143         private javax.swing.JButton moveDown;
144         private javax.swing.JButton moveUp;
145         private javax.swing.JButton okButton;
146         private javax.swing.JLabel rowLabel;
147         private javax.swing.JPanel rowManagement;
148         private javax.swing.JSpinner rowSpinner;
149         private javax.swing.JPanel tableManagement;
150         private javax.swing.JPanel validationPanel;
151         private javax.swing.JTable varCustomizeTable;
152         private javax.swing.JPanel varSettings;
153
154         /**
155          * Constructor
156          *
157          * @param diagram
158          *            the container diagram
159          */
160         public CustomizeFrame(XcosDiagram diagram) {
161             setTitle(XcosMessages.MASK_TITLE);
162             setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
163             controler = new CustomizeFrameControler(diagram);
164             initComponents();
165         }
166
167         /**
168          * @return The associated controller
169          */
170         public CustomizeFrameControler getController() {
171             return controler;
172         }
173
174         /**
175          * Construct the UI and install the listeners.
176          */
177         // CSOFF: JavaNCSS
178         // CSOFF: MagicNumber
179         private void initComponents() {
180
181             /* Construct the components */
182             mainPanel = new javax.swing.JPanel();
183             tabbedPane = new javax.swing.JTabbedPane();
184             varSettings = new javax.swing.JPanel();
185             customizeMainPanel = new javax.swing.JPanel();
186             customizeScrollPane = new javax.swing.JScrollPane();
187             varCustomizeTable = new javax.swing.JTable();
188             tableManagement = new javax.swing.JPanel();
189             insert = new javax.swing.JButton();
190             delete = new javax.swing.JButton();
191             buttonBlob = new javax.swing.JPanel();
192             moveUp = new javax.swing.JButton();
193             moveDown = new javax.swing.JButton();
194             rowManagement = new javax.swing.JPanel();
195             rowLabel = new javax.swing.JLabel();
196             rowSpinner = new javax.swing.JSpinner();
197             defaultValues = new javax.swing.JPanel();
198             defaultValuesScrollPane = new javax.swing.JScrollPane();
199             defaultValueTable = new javax.swing.JTable();
200             validationPanel = new javax.swing.JPanel();
201             okButton = new javax.swing.JButton();
202             cancelButton = new javax.swing.JButton();
203
204             setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
205
206             /* Initialize the components */
207             mainPanel.setLayout(new java.awt.BorderLayout());
208             mainPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
209
210             varSettings.setLayout(new javax.swing.BoxLayout(varSettings, javax.swing.BoxLayout.PAGE_AXIS));
211
212             varCustomizeTable.setModel(controler.getModel().customizeTableModel);
213             varCustomizeTable.putClientProperty(TERMINATE_EDIT_ON_FOCUS_LOST, Boolean.TRUE);
214             customizeScrollPane.setViewportView(varCustomizeTable);
215             // setAutoCreateRowSorter is java 1.6
216             // varCustomizeTable.setAutoCreateRowSorter(true);
217
218             /* Update the default value table */
219             varCustomizeTable.getModel().addTableModelListener(controler.updateValuesTable);
220
221             /*
222              * Activate and deactivate insertion/deletion sensible
223              * buttons/spinner
224              */
225             varCustomizeTable.getModel().addTableModelListener(controler.updateButtonsSensibleForModifications);
226
227             /* Activate and deactivate selection sensible buttons */
228             varCustomizeTable.getSelectionModel().addListSelectionListener(controler.updateButtonsSensibleForSelectionChange);
229
230             customizeMainPanel.add(customizeScrollPane);
231
232             tableManagement.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 2, 2, 2));
233             tableManagement.setLayout(new java.awt.GridLayout(5, 1));
234
235             /* Install the insert action */
236             insert.setMnemonic('n');
237             insert.setText(XcosMessages.MASK_INSERT);
238             tableManagement.add(insert);
239             insert.addActionListener(controler.insertActionListener);
240
241             /* Install the delete action */
242             delete.setMnemonic('l');
243             delete.setText(XcosMessages.MASK_DELETE);
244             tableManagement.add(delete);
245             delete.addActionListener(controler.deleteActionListener);
246
247             /* Install empty area */
248             tableManagement.add(buttonBlob);
249
250             /* Install the move-up action */
251             moveUp.setMnemonic('u');
252             moveUp.setText(XcosMessages.MASK_MOVEUP);
253             tableManagement.add(moveUp);
254             moveUp.addActionListener(controler.moveUpActionListener);
255
256             /* Install the move-down action */
257             moveDown.setMnemonic('w');
258             moveDown.setText(XcosMessages.MASK_MOVEDOWN);
259             tableManagement.add(moveDown);
260             moveDown.addActionListener(controler.moveDownActionListener);
261
262             /* add the table management */
263             customizeMainPanel.add(tableManagement);
264
265             varSettings.add(customizeMainPanel);
266
267             rowLabel.setText(XcosMessages.MASK_ROWS + " :");
268             rowManagement.add(rowLabel);
269
270             rowSpinner.setModel(new javax.swing.SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 1));
271             rowSpinner.setEditor(new javax.swing.JSpinner.NumberEditor(rowSpinner, "######0"));
272             rowSpinner.setValue(varCustomizeTable.getModel().getRowCount());
273             rowManagement.add(rowSpinner);
274             rowSpinner.addChangeListener(controler.rowSpinnerChangeListener);
275
276             varSettings.add(rowManagement);
277
278             tabbedPane.addTab(XcosMessages.MASK_VARSETTINGS, varSettings);
279
280             defaultValueTable.setModel(controler.getModel().valuesTableModel);
281             defaultValueTable.putClientProperty(TERMINATE_EDIT_ON_FOCUS_LOST, Boolean.TRUE);
282             defaultValuesScrollPane.setViewportView(defaultValueTable);
283
284             // setAutoCreateRowSorter is java 1.6
285             // defaultValueTable.setAutoCreateRowSorter(false);
286
287             defaultValues.add(defaultValuesScrollPane);
288
289             tabbedPane.addTab(XcosMessages.MASK_DEFAULTVALUES, defaultValues);
290
291             mainPanel.add(tabbedPane, java.awt.BorderLayout.CENTER);
292
293             okButton.setText(XcosMessages.OK);
294             validationPanel.add(okButton);
295             okButton.addActionListener(controler.okActionListener);
296
297             cancelButton.setText(XcosMessages.CANCEL);
298             validationPanel.add(cancelButton);
299             cancelButton.addActionListener(controler.cancelActionListener);
300
301             mainPanel.add(validationPanel, java.awt.BorderLayout.PAGE_END);
302
303             add(mainPanel);
304
305             pack();
306             cancelButton.requestFocusInWindow();
307
308             /* Evaluate the context and set up the variable name selection */
309             TableColumn vars = varCustomizeTable.getColumnModel().getColumn(0);
310             JComboBox validVars = new JComboBox();
311             final Set<String> keys = controler.context.keySet();
312             for (String key : keys) {
313                 validVars.addItem(key);
314             }
315             vars.setCellEditor(new DefaultCellEditor(validVars));
316
317             insert.setEnabled(validVars.getModel().getSize() != 0);
318         }
319
320         // CSON: JavaNCSS
321         // CSON: MagicNumber
322
323         /**
324          * Implements the models used on the frame.
325          */
326         private class CustomizeFrameModel {
327             private SuperBlock block;
328
329             /**
330              * Model used on the customize table.
331              */
332             private final DefaultTableModel customizeTableModel = new DefaultTableModel(new Object[][] { new Object[] { XcosMessages.MASK_WINTITLEVAR,
333                         XcosMessages.MASK_WINTITLE, false
334                                                                                                                           }
335             }, new String[] { XcosMessages.MASK_VARNAME, XcosMessages.MASK_VARDESC, XcosMessages.MASK_EDITABLE }) {
336                 private final Class<?>[] types = new Class[] { java.lang.String.class, java.lang.String.class, java.lang.Boolean.class };
337                 private final boolean[] canEdit = new boolean[] { true, true, true };
338
339                 @Override
340                 public Class<?> getColumnClass(int columnIndex) {
341                     return types[columnIndex];
342                 }
343
344                 @Override
345                 public boolean isCellEditable(int rowIndex, int columnIndex) {
346                     if (rowIndex != 0) {
347                         return canEdit[columnIndex];
348                     }
349                     return false;
350                 }
351             };
352
353             /**
354              * Model used for the values table
355              */
356             private final DefaultTableModel valuesTableModel = new javax.swing.table.DefaultTableModel(new Object[][] { new Object[] {
357                     XcosMessages.MASK_WINTITLE, ""
358                 }
359             }, new String[] { XcosMessages.MASK_VARDESC, XcosMessages.MASK_VARVALUES }) {
360                 private final Class<?>[] types = new Class[] { java.lang.String.class, java.lang.String.class };
361                 private final boolean[] canEdit = new boolean[] { false, true };
362
363                 @Override
364                 public Class<?> getColumnClass(int columnIndex) {
365                     return types[columnIndex];
366                 }
367
368                 @Override
369                 public boolean isCellEditable(int rowIndex, int columnIndex) {
370                     return canEdit[columnIndex];
371                 }
372             };
373
374             /**
375              * Default constructor
376              */
377             protected CustomizeFrameModel() {
378                 // Does nothing as the fields are final.
379             }
380
381             /**
382              * @param block
383              *            This model associated block.
384              */
385             public void setBlock(SuperBlock block) {
386                 this.block = block;
387             }
388
389             /**
390              * @return This model associated block.
391              */
392             public SuperBlock getBlock() {
393                 return block;
394             }
395
396             /**
397              * Export the table models to the block exprs.
398              */
399             public void exportToBlock() {
400                 /** Data vectors are typed when parsing */
401                 final List<?> customModel = customizeTableModel.getDataVector();
402                 final List<?> valuesModel = valuesTableModel.getDataVector();
403
404                 /* We have one content that is not a variable : Window Title */
405                 final int nbOfVar = valuesModel.size() - 1;
406
407                 final String[][] values = new String[nbOfVar][1];
408                 final String[][] varNames = new String[nbOfVar][1];
409                 final String[][] varDesc = new String[nbOfVar + 1][1];
410                 final ScilabList polFields = new ScilabList();
411
412                 /* Title */
413                 varDesc[0][0] = (String) ((List<?>) valuesModel.get(0)).get(1);
414
415                 /* Other fields */
416                 for (int i = 0; i < nbOfVar; i++) {
417                     values[i][0] = (String) ((List<?>) valuesModel.get(i + 1)).get(1);
418                     varNames[i][0] = (String) ((List<?>) customModel.get(i + 1)).get(0);
419                     varDesc[i + 1][0] = (String) ((List<?>) customModel.get(i + 1)).get(1);
420
421                     /*
422                      * reconstruct pol fields. The default types of the values.
423                      *
424                      * This field indicate the dimension of each entry (-1.0 is
425                      * automatic). TODO: type the data there instead of using
426                      * the generic "pol".
427                      */
428                     polFields.add(new ScilabString("pol"));
429                     polFields.add(new ScilabDouble(-1.0));
430                 }
431
432                 /* Construct fields from data */
433                 final ScilabList exprs;
434                 if (nbOfVar == 0) {
435                     /* Set default values */
436                     exprs = new ScilabList(Arrays.asList(
437                                                new ScilabDouble(),
438                                                new ScilabList(Arrays.asList(new ScilabDouble(), new ScilabString(XcosMessages.MASK_DEFAULTWINDOWNAME),
439                                                        new ScilabList(Arrays.asList(new ScilabDouble()))))));
440                 } else {
441                     /* set the values */
442                     exprs = new ScilabList(Arrays.asList(new ScilabString(values),
443                                                          new ScilabList(Arrays.asList(new ScilabString(varNames), new ScilabString(varDesc), polFields))));
444                 }
445
446                 JavaController controller = new JavaController();
447                 VectorOfDouble vec = new ScilabTypeCoder().var2vec(exprs);
448                 controller.setObjectProperty(block.getUID(), block.getKind(), ObjectProperties.EXPRS, vec);
449
450                 /*
451                  * Trace the exprs update.
452                  */
453                 if (Logger.getLogger(SuperblockMaskCustomizeAction.class.getName()).isLoggable(Level.FINEST)) {
454                     Logger.getLogger(SuperblockMaskCustomizeAction.class.getName()).finest("exprs=" + exprs);
455                 }
456             }
457
458             /**
459              * Import the model exprs to the table models.
460              */
461             public void importFromBlock() {
462                 ScilabString values;
463                 ScilabString varNames;
464                 ScilabString varDesc;
465
466                 JavaController controller = new JavaController();
467                 VectorOfDouble vec = new VectorOfDouble();
468                 controller.getObjectProperty(block.getUID(), block.getKind(), ObjectProperties.EXPRS, vec);
469                 ScilabType rawExprs = new ScilabTypeCoder().vec2var(vec);
470
471                 // Xcos from Scilab 5.2.0 version
472                 // so set default values
473                 if (rawExprs instanceof ScilabDouble) {
474                     rawExprs = new ScilabList(Arrays.asList(
475                                                   new ScilabDouble(),
476                                                   new ScilabList(Arrays.asList(new ScilabDouble(), new ScilabString(XcosMessages.MASK_DEFAULTWINDOWNAME),
477                                                           new ScilabList(Arrays.asList(new ScilabDouble()))))));
478                 }
479                 DefaultTableModel customModel = customizeTableModel;
480                 DefaultTableModel valuesModel = valuesTableModel;
481
482                 /*
483                  * rawExprs have to be typed as
484                  * list([],list([],"Set block parameters",list())) or as
485                  * list([""],list([""],"Set block parameters",list([""])))
486                  */
487                 assert rawExprs instanceof ScilabList;
488                 ScilabList exprs = (ScilabList) rawExprs;
489
490                 assert (exprs.get(0) instanceof ScilabDouble) || (exprs.get(0) instanceof ScilabString);
491                 if (exprs.get(0) instanceof ScilabDouble) {
492                     values = new ScilabString("");
493                 } else { /* exprs.get(0) instanceof ScilabString) */
494                     values = (ScilabString) exprs.get(0);
495                 }
496
497                 assert exprs.get(1) instanceof ScilabList;
498                 ScilabList lvalues = (ScilabList) exprs.get(1);
499
500                 assert (lvalues.get(0) instanceof ScilabDouble) || (lvalues.get(0) instanceof ScilabString);
501                 if (lvalues.get(0) instanceof ScilabDouble) {
502                     varNames = new ScilabString();
503                 } else { /* exprs.get(0) instanceof ScilabString) */
504                     varNames = (ScilabString) lvalues.get(0);
505                 }
506
507                 assert lvalues.get(1) instanceof ScilabString;
508                 varDesc = (ScilabString) lvalues.get(1);
509
510                 /*
511                  * Check if the data are stored as columns or as row.
512                  */
513                 if (varDesc.getHeight() >= varDesc.getWidth()) {
514
515                     /* Title */
516                     valuesModel.setValueAt(varDesc.getData()[0][0], 0, 1);
517
518                     /* Loop all over the data */
519                     for (int i = 1; i < varDesc.getHeight(); i++) {
520                         customModel.addRow(new Object[] { varNames.getData()[i - 1][0], varDesc.getData()[i][0], true });
521                         valuesModel.setValueAt(values.getData()[i - 1][0], i, 1);
522                     }
523                 } else {
524                     /* Title */
525                     valuesModel.setValueAt(varDesc.getData()[0][0], 0, 1);
526
527                     /* Loop all over the data */
528                     for (int i = 1; i < varDesc.getHeight(); i++) {
529                         customModel.addRow(new Object[] { varNames.getData()[0][i - 1], varDesc.getData()[0][i], true });
530                         valuesModel.setValueAt(values.getData()[0][i - 1], i, 1);
531                     }
532                 }
533             }
534         }
535
536         /**
537          * Implement the action listeners for the frame
538          */
539         private class CustomizeFrameControler {
540             private final CustomizeFrameModel model;
541
542             private final ActionListener cancelActionListener = new ActionListener() {
543                 @Override
544                 public void actionPerformed(ActionEvent e) {
545                     dispose();
546                 }
547             };
548
549             private final ActionListener okActionListener = new ActionListener() {
550                 @Override
551                 public void actionPerformed(ActionEvent arg0) {
552                     model.exportToBlock();
553                     dispose();
554                 }
555             };
556
557             private final ChangeListener rowSpinnerChangeListener = new ChangeListener() {
558                 @Override
559                 public void stateChanged(ChangeEvent e) {
560                     int rowCount = varCustomizeTable.getRowCount();
561                     int value = (Integer) rowSpinner.getModel().getValue();
562
563                     for (; rowCount < value; rowCount++) {
564                         insertActionListener.actionPerformed(new ActionEvent(this, -1, ACTION_COMMAND_KEY));
565                     }
566
567                     for (; rowCount > value; rowCount--) {
568                         deleteActionListener.actionPerformed(new ActionEvent(this, -1, ACTION_COMMAND_KEY));
569                     }
570                 }
571             };
572
573             private final ActionListener moveDownActionListener = new ActionListener() {
574                 @Override
575                 public void actionPerformed(ActionEvent arg0) {
576                     int selectedRow = varCustomizeTable.getSelectedRow();
577
578                     swapTableRow(model.customizeTableModel, selectedRow, selectedRow + 1);
579                     swapTableRow(model.valuesTableModel, selectedRow, selectedRow + 1);
580
581                     /* Keep the same row selected */
582                     varCustomizeTable.changeSelection(selectedRow + 1, varCustomizeTable.getSelectedColumn(), false, false);
583                 }
584             };
585
586             private final ActionListener moveUpActionListener = new ActionListener() {
587                 @Override
588                 public void actionPerformed(ActionEvent arg0) {
589                     int selectedRow = varCustomizeTable.getSelectedRow();
590
591                     swapTableRow(model.customizeTableModel, selectedRow, selectedRow - 1);
592                     swapTableRow(model.valuesTableModel, selectedRow, selectedRow - 1);
593
594                     /* Keep the same row selected */
595                     varCustomizeTable.changeSelection(selectedRow - 1, varCustomizeTable.getSelectedColumn(), false, false);
596                 }
597             };
598
599             private final ActionListener deleteActionListener = new ActionListener() {
600                 @Override
601                 public void actionPerformed(ActionEvent e) {
602                     int selected = varCustomizeTable.getSelectedRow();
603                     int nbOfRows = varCustomizeTable.getRowCount();
604
605                     if (selected > 1) {
606                         model.customizeTableModel.removeRow(selected);
607                         varCustomizeTable.changeSelection(selected - 1, 1, false, false);
608                     } else if (nbOfRows > 1) {
609                         model.customizeTableModel.removeRow(nbOfRows - 1);
610                         varCustomizeTable.changeSelection(nbOfRows - 2, 1, false, false);
611                     }
612                 }
613             };
614
615             private final ActionListener insertActionListener = new ActionListener() {
616                 @Override
617                 public void actionPerformed(ActionEvent e) {
618                     final String nextKey;
619                     if (keyIterator.hasNext()) {
620                         nextKey = keyIterator.next();
621                     } else {
622                         // at the end of the iteration loop again
623                         keyIterator = context.keySet().iterator();
624
625                         if (keyIterator.hasNext()) {
626                             nextKey = keyIterator.next();
627                         } else {
628                             nextKey = ""; // no defined vars.
629                         }
630                     }
631
632                     model.customizeTableModel.addRow(new Object[] { nextKey, nextKey, true });
633                     varCustomizeTable.changeSelection(model.customizeTableModel.getRowCount() - 1, 1, false, false);
634                 }
635             };
636
637             /**
638              * Update the buttons on selection change.
639              */
640             private final ListSelectionListener updateButtonsSensibleForSelectionChange = new ListSelectionListener() {
641                 @Override
642                 public void valueChanged(ListSelectionEvent e) {
643                     /* We cannot move up anymore */
644                     final boolean isFirst;
645                     /* We cannot move down anymore */
646                     final boolean isLast;
647                     /* The second row is selected */
648                     final boolean isSecond;
649
650                     int selectedRow = varCustomizeTable.getSelectedRow();
651                     int rowCount = varCustomizeTable.getRowCount();
652
653                     isFirst = selectedRow < 1;
654                     isSecond = selectedRow == 1;
655                     isLast = selectedRow == rowCount - 1;
656
657                     moveUp.setEnabled(!isFirst && !isSecond);
658                     moveDown.setEnabled(!isFirst && !isLast);
659
660                     delete.setEnabled(!isFirst);
661                 }
662             };
663
664             /**
665              * Update the buttons/spinner on modifications
666              */
667             private final TableModelListener updateButtonsSensibleForModifications = new TableModelListener() {
668                 @Override
669                 public void tableChanged(TableModelEvent e) {
670                     int rowCount = model.customizeTableModel.getRowCount();
671                     rowSpinner.setValue(rowCount);
672                 }
673             };
674
675             /**
676              * Update the values table on change on the customize table.
677              */
678             private final TableModelListener updateValuesTable = new TableModelListener() {
679                 @Override
680                 public void tableChanged(TableModelEvent e) {
681                     final DefaultTableModel valuesModel = model.valuesTableModel;
682                     final DefaultTableModel customModel = model.customizeTableModel;
683                     int row = e.getFirstRow();
684                     int column = e.getColumn();
685
686                     switch (e.getType()) {
687                         case TableModelEvent.INSERT:
688                             String key = (String) customModel.getValueAt(row, 0);
689                             String value = context.get(key);
690                             valuesModel.addRow(new Object[] { key, value });
691                             break;
692
693                         case TableModelEvent.DELETE:
694                             valuesModel.removeRow(row);
695                             break;
696
697                         case TableModelEvent.UPDATE:
698                             if (column == 0) {
699                                 // update the description when it was set to a var
700                                 // name and the variable change
701                                 // the description should not change when it is not
702                                 // the default.
703                                 String varName = (String) customModel.getValueAt(row, 0);
704                                 String varDesc = (String) customModel.getValueAt(row, 1);
705                                 if (context.containsKey(varDesc)) {
706                                     customModel.setValueAt(varName, row, 1);
707                                 }
708                             } else if (column == 1) {
709                                 // update the description on the default value table
710                                 valuesModel.setValueAt(customModel.getValueAt(row, 1), row, 0);
711                             }
712                             break;
713
714                         default:
715                             break;
716                     }
717                 }
718             };
719
720             private final Map<String, String> context;
721             private Iterator<String> keyIterator;
722
723             /**
724              * Cstr
725              *
726              * @param diagram
727              *            the calling diagram
728              */
729             public CustomizeFrameControler(XcosDiagram diagram) {
730                 model = new CustomizeFrameModel();
731                 context = diagram.evaluateContext();
732                 keyIterator = context.keySet().iterator();
733             }
734
735             /**
736              * @return the model
737              */
738             public CustomizeFrameModel getModel() {
739                 return model;
740             }
741
742             /**
743              * Swap two table rows
744              *
745              * @param model
746              *            the model
747              * @param row1
748              *            the first row
749              * @param row2
750              *            th second row
751              */
752             private void swapTableRow(DefaultTableModel model, int row1, int row2) {
753                 /*
754                  * doesn't need to be checked as the operation doesn't depend on
755                  * it
756                  */
757                 @SuppressWarnings("unchecked")
758                 final List < List<? >> data = model.getDataVector();
759
760                 /* Inverting data */
761                 List<?> tmp = data.get(row2);
762                 data.set(row2, data.get(row1));
763                 data.set(row1, tmp);
764             }
765         }
766     }
767     // CSON: ClassDataAbstractionCoupling
768 }