Initial commit
[debian/openrocket] / src / net / sf / openrocket / gui / adaptors / MotorConfigurationModel.java
1 package net.sf.openrocket.gui.adaptors;
2
3
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.MouseAdapter;
7 import java.awt.event.MouseEvent;
8 import java.util.ArrayList;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.Map;
12
13 import javax.swing.ComboBoxModel;
14 import javax.swing.JButton;
15 import javax.swing.JDialog;
16 import javax.swing.JFrame;
17 import javax.swing.JLabel;
18 import javax.swing.JPanel;
19 import javax.swing.JScrollPane;
20 import javax.swing.JTable;
21 import javax.swing.JTextField;
22 import javax.swing.ListSelectionModel;
23 import javax.swing.SwingUtilities;
24 import javax.swing.event.ChangeEvent;
25 import javax.swing.event.ChangeListener;
26 import javax.swing.event.EventListenerList;
27 import javax.swing.event.ListDataEvent;
28 import javax.swing.event.ListDataListener;
29 import javax.swing.event.ListSelectionEvent;
30 import javax.swing.event.ListSelectionListener;
31
32 import net.miginfocom.swing.MigLayout;
33 import net.sf.openrocket.gui.ResizeLabel;
34 import net.sf.openrocket.gui.TextFieldListener;
35 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
36 import net.sf.openrocket.rocketcomponent.Configuration;
37 import net.sf.openrocket.rocketcomponent.Motor;
38 import net.sf.openrocket.rocketcomponent.MotorMount;
39 import net.sf.openrocket.rocketcomponent.Rocket;
40 import net.sf.openrocket.rocketcomponent.RocketComponent;
41 import net.sf.openrocket.util.GUIUtil;
42
43 public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
44
45         private static final String EDIT = "Edit configurations";
46         
47         
48         private EventListenerList listenerList = new EventListenerList();
49         
50         private final Configuration config;
51         private final Rocket rocket;
52         
53         private Map<String, ID> map = new HashMap<String, ID>();
54         
55
56         public MotorConfigurationModel(Configuration config) {
57                 this.config = config;
58                 this.rocket = config.getRocket();
59                 config.addChangeListener(this);
60         }
61         
62         
63         
64         @Override
65         public Object getElementAt(int index) {
66                 String[] ids = rocket.getMotorConfigurationIDs();
67                 if (index < 0  ||  index > ids.length)
68                         return null;
69                 
70                 if (index == ids.length)
71                         return EDIT;
72                 
73                 return get(ids[index]);
74         }
75
76         @Override
77         public int getSize() {
78                 return rocket.getMotorConfigurationIDs().length + 1;
79         }
80
81         @Override
82         public Object getSelectedItem() {
83                 return get(config.getMotorConfigurationID());
84         }
85
86         @Override
87         public void setSelectedItem(Object item) {
88                 if (item == EDIT) {
89                         
90                         // Open edit dialog in the future, after combo box has closed
91                         SwingUtilities.invokeLater(new Runnable() {
92                                 @Override
93                                 public void run() {
94                                         EditConfigurationDialog dialog = new EditConfigurationDialog();
95                                         dialog.setVisible(true);
96                                         
97                                         if (dialog.isRowSelected()) {
98                                                 rocket.getDefaultConfiguration().setMotorConfigurationID(
99                                                                 dialog.getSelectedID());
100                                         }
101                                 }
102                         });
103
104                         return;
105                 }
106                 if (!(item instanceof ID))
107                         return;
108                 
109                 ID idObject = (ID) item;
110                 config.setMotorConfigurationID(idObject.getID());
111         }
112
113
114         
115         ////////////////  Event/listener handling  ////////////////
116         
117         
118         @Override
119         public void addListDataListener(ListDataListener l) {
120                 listenerList.add(ListDataListener.class, l);
121         }
122
123         @Override
124         public void removeListDataListener(ListDataListener l) {
125                 listenerList.remove(ListDataListener.class, l);
126         }
127
128         protected void fireListDataEvent() {
129                 Object[] listeners = listenerList.getListenerList();
130                 ListDataEvent e = null;
131
132                 for (int i = listeners.length-2; i>=0; i-=2) {
133                         if (listeners[i] == ListDataListener.class) {
134                                 if (e == null)
135                                         e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize());
136                                 ((ListDataListener) listeners[i+1]).contentsChanged(e);
137                         }
138                 }
139         }
140          
141         
142         @Override
143         public void stateChanged(ChangeEvent e) {
144                 if (e instanceof ComponentChangeEvent) {
145                         // Ignore unnecessary changes
146                         if (!((ComponentChangeEvent)e).isMotorChange())
147                                 return;
148                 }
149                 fireListDataEvent();
150         }
151         
152         
153         
154         /*
155          * The ID class is an adapter, that contains the actual configuration ID,
156          * but gives the configuration description as its String representation.
157          * The get(id) method retrieves ID objects and caches them for reuse.
158          */
159         
160         private ID get(String id) {
161                 ID idObject = map.get(id);
162                 if (idObject != null)
163                         return idObject;
164                 
165                 idObject = new ID(id);
166                 map.put(id, idObject);
167                 return idObject;
168         }
169         
170         
171         private class ID {
172                 private final String id;
173                 
174                 public ID(String id) {
175                         this.id = id;
176                 }
177                 
178                 public String getID() {
179                         return id;
180                 }
181                 
182                 @Override
183                 public String toString() {
184                         return rocket.getMotorConfigurationDescription(id);
185                 }
186         }
187         
188         
189         private class EditConfigurationDialog extends JDialog {
190                 private final ColumnTableModel tableModel;
191                 private String[] ids;
192                 int selection = -1;
193                 
194                 private final JButton addButton;
195                 private final JButton removeButton;
196                 private final JTextField nameField;
197                 
198                 private final JTable table;
199                 
200                 
201                 public boolean isRowSelected() {
202                         return selection >= 0;
203                 }
204                 
205                 public String getSelectedID() {
206                         if (selection >= 0)
207                                 return ids[selection];
208                         return null;
209                 }
210                 
211                 
212                 public EditConfigurationDialog() {
213                         super((JFrame)null, "Edit configurations", true);
214
215                         ids = rocket.getMotorConfigurationIDs();
216                         
217                         // Create columns
218                         ArrayList<Column> columnList = new ArrayList<Column>();
219                         columnList.add(new Column("Name") {
220                                 @Override
221                                 public Object getValueAt(int row) {
222                                         return rocket.getMotorConfigurationDescription(ids[row]);
223                                 }
224                         });
225                         
226                         // Create columns from the motor mounts
227                         Iterator<RocketComponent> iterator = rocket.deepIterator();
228                         while (iterator.hasNext()) {
229                                 RocketComponent c = iterator.next();
230                                 if (!(c instanceof MotorMount))
231                                         continue;
232                                 
233                                 final MotorMount mount = (MotorMount)c;
234                                 if (!mount.isMotorMount())
235                                         continue;
236                                 
237                                 Column col = new Column(c.getName()) {
238                                         @Override
239                                         public Object getValueAt(int row) {
240                                                 Motor motor = mount.getMotor(ids[row]);
241                                                 if (motor == null)
242                                                         return "";
243                                                 return motor.getDesignation(mount.getMotorDelay(ids[row]));
244                                         }
245                                 };
246                                 columnList.add(col);
247                         }
248                         tableModel = new ColumnTableModel(columnList.toArray(new Column[0])) {
249                                 @Override
250                                 public int getRowCount() {
251                                         return ids.length;
252                                 }
253                         };
254
255                         
256                         
257                         // Create the panel
258                         JPanel panel = new JPanel(new MigLayout("fill","[shrink][grow]"));
259                         
260                         
261                         panel.add(new JLabel("Configuration name:"), "gapright para");
262                         nameField = new JTextField();
263                         new TextFieldListener() {
264                                 @Override
265                                 public void setText(String text) {
266                                         if (selection < 0 || ids[selection] == null)
267                                                 return;
268                                         rocket.setMotorConfigurationName(ids[selection], text);
269                                         fireChange();
270                                 }
271                         }.listenTo(nameField);
272                         panel.add(nameField, "growx, wrap");
273                         
274                         panel.add(new ResizeLabel("Leave empty for default description", -2), 
275                                         "skip, growx, wrap para");
276                         
277                         
278                         table = new JTable(tableModel);
279                         table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
280                         table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
281                                 @Override
282                                 public void valueChanged(ListSelectionEvent e) {
283                                         updateSelection();
284                                 }
285                         });
286
287                         // Mouse listener to act on double-clicks
288                         table.addMouseListener(new MouseAdapter() {
289                                 @Override
290                                 public void mouseClicked(MouseEvent e) {
291                                         if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
292                                                 EditConfigurationDialog.this.dispose();
293                                         }
294                                 }
295                         });
296                          
297                         
298                         
299                         JScrollPane scrollpane = new JScrollPane(table);
300                         panel.add(scrollpane, "spanx, height 150lp, width 400lp, grow, wrap");
301                         
302                         
303                         addButton = new JButton("New");
304                         addButton.addActionListener(new ActionListener() {
305                                 @Override
306                                 public void actionPerformed(ActionEvent e) {
307                                         String id = rocket.newMotorConfigurationID();
308                                         ids = rocket.getMotorConfigurationIDs();
309                                         tableModel.fireTableDataChanged();
310                                         int sel;
311                                         for (sel=0; sel < ids.length; sel++) {
312                                                 if (id.equals(ids[sel]))
313                                                         break;
314                                         }
315                                         table.getSelectionModel().addSelectionInterval(sel, sel);
316                                 }
317                         });
318                         panel.add(addButton, "growx, spanx, split 2");
319                         
320                         removeButton = new JButton("Remove");
321                         removeButton.addActionListener(new ActionListener() {
322                                 @Override
323                                 public void actionPerformed(ActionEvent e) {
324                                         int sel = table.getSelectedRow();
325                                         if (sel < 0 || sel >= ids.length || ids[sel] == null)
326                                                 return;
327                                         rocket.removeMotorConfigurationID(ids[sel]);
328                                         ids = rocket.getMotorConfigurationIDs();
329                                         tableModel.fireTableDataChanged();
330                                         if (sel >= ids.length)
331                                                 sel--;
332                                         table.getSelectionModel().addSelectionInterval(sel, sel);
333                                 }
334                         });
335                         panel.add(removeButton, "growx, wrap para");
336                         
337                         
338                         JButton close = new JButton("Close");
339                         close.addActionListener(new ActionListener() {
340                                 @Override
341                                 public void actionPerformed(ActionEvent e) {
342                                         EditConfigurationDialog.this.dispose();
343                                 }
344                         });
345                         panel.add(close, "spanx, alignx 100%");
346                         
347                         this.getRootPane().setDefaultButton(close);
348                         
349                         
350                         this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
351                         GUIUtil.installEscapeCloseOperation(this);
352                         this.setLocationByPlatform(true);
353                         
354                         updateSelection();
355                         
356                         this.add(panel);
357                         this.validate();
358                         this.pack();
359                 }
360                 
361                 private void fireChange() {
362                         int sel = table.getSelectedRow();
363                         tableModel.fireTableDataChanged();
364                         table.getSelectionModel().addSelectionInterval(sel, sel);
365                 }
366                 
367                 private void updateSelection() {
368                         selection = table.getSelectedRow();
369                         if (selection < 0  ||  ids[selection] == null) {
370                                 removeButton.setEnabled(false);
371                                 nameField.setEnabled(false);
372                                 nameField.setText("");
373                         } else {
374                                 removeButton.setEnabled(true);
375                                 nameField.setEnabled(true);
376                                 nameField.setText(rocket.getMotorConfigurationName(ids[selection]));
377                         }
378                 }
379         }
380         
381 }
382