Numerous bug fixes and updates
[debian/openrocket] / src / net / sf / openrocket / gui / dialogs / EditMotorConfigurationDialog.java
1 package net.sf.openrocket.gui.dialogs;
2
3 import java.awt.Window;
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.awt.event.WindowAdapter;
9 import java.awt.event.WindowEvent;
10 import java.util.ArrayList;
11 import java.util.Iterator;
12
13 import javax.swing.JButton;
14 import javax.swing.JDialog;
15 import javax.swing.JLabel;
16 import javax.swing.JPanel;
17 import javax.swing.JScrollPane;
18 import javax.swing.JTable;
19 import javax.swing.JTextField;
20 import javax.swing.ListSelectionModel;
21 import javax.swing.event.DocumentEvent;
22 import javax.swing.event.DocumentListener;
23 import javax.swing.table.AbstractTableModel;
24 import javax.swing.table.TableColumn;
25 import javax.swing.table.TableColumnModel;
26
27 import net.miginfocom.swing.MigLayout;
28 import net.sf.openrocket.document.OpenRocketDocument;
29 import net.sf.openrocket.gui.main.BasicFrame;
30 import net.sf.openrocket.gui.main.MotorChooserDialog;
31 import net.sf.openrocket.rocketcomponent.Motor;
32 import net.sf.openrocket.rocketcomponent.MotorMount;
33 import net.sf.openrocket.rocketcomponent.Rocket;
34 import net.sf.openrocket.rocketcomponent.RocketComponent;
35 import net.sf.openrocket.util.GUIUtil;
36
37 public class EditMotorConfigurationDialog extends JDialog {
38         
39         private final Rocket rocket;
40         
41         private final MotorMount[] mounts;
42
43         private final JTable configurationTable;
44         private final MotorConfigurationTableModel configurationTableModel;
45
46         
47         private final JButton newConfButton, removeConfButton;
48         private final JButton selectMotorButton, removeMotorButton;
49         private final JTextField configurationNameField;
50         
51         
52         private String currentID = null;
53         private MotorMount currentMount = null;
54         
55         // Positive when user is modifying configuration name
56         private int configurationNameModification = 0;
57         
58         public EditMotorConfigurationDialog(final Rocket rocket, Window parent) {
59                 super(parent, "Edit motor configurations");
60                 
61                 if (parent != null)
62                         this.setModalityType(ModalityType.DOCUMENT_MODAL);
63                 else
64                         this.setModalityType(ModalityType.APPLICATION_MODAL);
65                 
66                 this.rocket = rocket;
67                 
68                 ArrayList<MotorMount> mountList = new ArrayList<MotorMount>();
69                 Iterator<RocketComponent> iterator = rocket.deepIterator();
70                 while (iterator.hasNext()) {
71                         RocketComponent c = iterator.next();
72                         if (c instanceof MotorMount) {
73                                 mountList.add((MotorMount)c);
74                         }
75                 }
76                 mounts = mountList.toArray(new MotorMount[0]);
77                 
78                 
79                 
80                 JPanel panel = new JPanel(new MigLayout("fill, flowy"));
81                 
82                 
83                 ////  Motor mount selection
84                 
85                 JLabel label = new JLabel("<html><b>Motor mounts:</b>");
86                 panel.add(label, "gapbottom para");
87                 
88                 label = new JLabel("<html>Select which components function as motor mounts:");
89                 panel.add(label,"ay 100%, w 1px, growx");
90                 
91                 
92                 JTable table = new JTable(new MotorMountTableModel());
93                 table.setTableHeader(null);
94                 table.setShowVerticalLines(false);
95                 table.setRowSelectionAllowed(false);
96                 table.setColumnSelectionAllowed(false);
97                 
98                 TableColumnModel columnModel = table.getColumnModel();
99                 TableColumn col0 = columnModel.getColumn(0);
100                 int w = table.getRowHeight() + 2;
101                 col0.setMinWidth(w);
102                 col0.setPreferredWidth(w);
103                 col0.setMaxWidth(w);
104                 
105                 JScrollPane scroll = new JScrollPane(table);
106                 panel.add(scroll, "w 200lp, h 150lp, grow, wrap 20lp");
107                 
108
109                 
110                 
111                 
112                 //// Motor selection
113                 
114                 label = new JLabel("<html><b>Motor configurations:</b>");
115                 panel.add(label, "spanx, gapbottom para");
116                 
117                 
118                 label = new JLabel("Configuration name:");
119                 String tip = "Leave name empty for default.";
120                 label.setToolTipText(tip);
121                 panel.add(label, "");
122                 
123                 configurationNameField = new JTextField(10);
124                 configurationNameField.setToolTipText(tip);
125                 configurationNameField.getDocument().addDocumentListener(new DocumentListener() {
126                         @Override
127                         public void changedUpdate(DocumentEvent e) {
128                                 update();
129                         }
130                         @Override
131                         public void insertUpdate(DocumentEvent e) {
132                                 update();
133                         }
134                         @Override
135                         public void removeUpdate(DocumentEvent e) {
136                                 update();
137                         }
138                         private void update() {
139                                 if (configurationNameModification != 0)
140                                         return;
141
142                                 String text = configurationNameField.getText();
143                                 if (currentID != null) {
144                                         configurationNameModification++;
145                                         rocket.setMotorConfigurationName(currentID, text);
146                                         int row = configurationTable.getSelectedRow();
147                                         configurationTableModel.fireTableCellUpdated(row, 0);
148                                         updateEnabled();
149                                         configurationNameModification--;
150                                 }
151                         }
152                 });
153                 panel.add(configurationNameField, "cell 2 1, gapright para");
154                 
155                 newConfButton = new JButton("New configuration");
156                 newConfButton.addActionListener(new ActionListener() {
157                         @Override
158                         public void actionPerformed(ActionEvent e) {
159                                 String id = rocket.newMotorConfigurationID();
160                                 rocket.getDefaultConfiguration().setMotorConfigurationID(id);
161                                 configurationTableModel.fireTableDataChanged();
162                                 updateEnabled();
163                         }
164                 });
165                 panel.add(newConfButton, "cell 3 1");
166                 
167                 removeConfButton = new JButton("Remove configuration");
168                 removeConfButton.addActionListener(new ActionListener() {
169                         @Override
170                         public void actionPerformed(ActionEvent e) {
171                                 if (currentID == null)
172                                         return;
173                                 rocket.removeMotorConfigurationID(currentID);
174                                 rocket.getDefaultConfiguration().setMotorConfigurationID(null);
175                                 configurationTableModel.fireTableDataChanged();
176                                 updateEnabled();
177                         }
178                 });
179                 panel.add(removeConfButton, "cell 4 1");
180                 
181                 
182
183                 
184                 configurationTableModel = new MotorConfigurationTableModel();
185                 configurationTable = new JTable(configurationTableModel);
186                 configurationTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
187                 configurationTable.setCellSelectionEnabled(true);
188                 
189                 configurationTable.addMouseListener(new MouseAdapter() {
190                         @Override
191                         public void mouseClicked(MouseEvent e) {
192                                 
193                                 if (e.getClickCount() == 1) {
194                                         
195                                         // Single click updates selection
196                                         updateEnabled();
197                                         
198                                 } else if (e.getClickCount() == 2) {
199                                         
200                                         // Double-click edits motor
201                                         selectMotor();
202                                         
203                                 }
204                                 
205                         }
206                 });
207                 
208
209                 scroll = new JScrollPane(configurationTable);
210                 panel.add(scroll, "cell 1 2, spanx, w 500lp, h 150lp, grow");
211                 
212                 
213                 selectMotorButton = new JButton("Select motor");
214                 selectMotorButton.addActionListener(new ActionListener() {
215                         @Override
216                         public void actionPerformed(ActionEvent e) {
217                                 selectMotor();
218                         }
219                 });
220                 panel.add(selectMotorButton, "spanx, flowx, split 2, ax 50%");
221                 
222                 
223                 removeMotorButton = new JButton("Remove motor");
224                 removeMotorButton.addActionListener(new ActionListener() {
225                         @Override
226                         public void actionPerformed(ActionEvent e) {
227                                 removeMotor();
228                         }
229                 });
230                 panel.add(removeMotorButton, "ax 50%");
231                 
232                 
233                 
234                 //// Close button
235                 
236                 JButton close = new JButton("Close");
237                 close.addActionListener(new ActionListener() {
238                         @Override
239                         public void actionPerformed(ActionEvent e) {
240                                 EditMotorConfigurationDialog.this.dispose();
241                         }
242                 });
243                 panel.add(close, "spanx, right");
244                 
245                 this.add(panel);
246                 this.validate();
247                 this.pack();
248                 
249                 updateEnabled();
250                 
251                 GUIUtil.installEscapeCloseOperation(this);
252                 GUIUtil.setDefaultButton(close);
253                 
254                 // Undo description
255                 final OpenRocketDocument document = BasicFrame.findDocument(rocket);
256                 if (document != null) {
257                         document.startUndo("Edit motor configurations");
258                         this.addWindowListener(new WindowAdapter() {
259                                 @Override
260                                 public void windowClosed(WindowEvent e) {
261                                         document.stopUndo();
262                                 }
263                         });
264                 }
265         }
266
267         
268         
269         
270         private void updateEnabled() {
271                 int column = configurationTable.getSelectedColumn();
272                 int row = configurationTable.getSelectedRow();
273                 
274                 if (column < 0 || row < 0) {
275                         currentID = null;
276                         currentMount = null;
277                 } else {
278                         
279                         currentID = findID(row);
280                         if (column == 0) {
281                                 currentMount = null;
282                         } else {
283                                 currentMount = findMount(column);
284                         }
285                         rocket.getDefaultConfiguration().setMotorConfigurationID(currentID);
286                         
287                 }
288
289                 if (configurationNameModification == 0) {
290                         // Don't update name field when user is modifying it
291                         configurationNameModification++;
292                         
293                         configurationNameField.setEnabled(currentID != null);
294                         if (currentID == null) {
295                                 configurationNameField.setText("");
296                         } else {
297                                 configurationNameField.setText(rocket.getMotorConfigurationName(currentID));
298                         }
299                         
300                         configurationNameModification--;
301                 }
302                 removeConfButton.setEnabled(currentID != null);
303                 selectMotorButton.setEnabled(currentMount != null && currentID != null);
304                 removeMotorButton.setEnabled(currentMount != null && currentID != null);
305         }
306         
307
308         
309         
310         private void selectMotor() {
311                 if (currentID == null || currentMount == null)
312                         return;
313                 
314                 MotorChooserDialog dialog = new MotorChooserDialog(currentMount.getMotor(currentID),
315                                 currentMount.getMotorDelay(currentID), currentMount.getMotorMountDiameter());
316                 dialog.setVisible(true);
317                 Motor m = dialog.getSelectedMotor();
318                 double d = dialog.getSelectedDelay();
319                 
320                 if (m != null) {
321                         currentMount.setMotor(currentID, m);
322                         currentMount.setMotorDelay(currentID, d);
323                 }
324
325                 int row = configurationTable.getSelectedRow();
326                 configurationTableModel.fireTableRowsUpdated(row, row);
327                 updateEnabled();
328         }
329         
330         
331         private void removeMotor() {
332                 if (currentID == null || currentMount == null)
333                         return;
334                 
335                 currentMount.setMotor(currentID, null);
336                 
337                 int row = configurationTable.getSelectedRow();
338                 configurationTableModel.fireTableRowsUpdated(row, row);
339                 updateEnabled();
340         }
341         
342         
343         private String findID(int row) {
344                 return rocket.getMotorConfigurationIDs()[row+1];
345         }
346
347         
348         private MotorMount findMount(int column) {
349                 MotorMount mount = null;
350
351                 int count = column;
352                 for (MotorMount m: mounts) {
353                         if (m.isMotorMount())
354                                 count--;
355                         if (count <= 0) {
356                                 mount = m;
357                                 break;
358                         }
359                 }
360                 
361                 if (mount == null) {
362                         throw new IndexOutOfBoundsException("motor mount not found, column="+column);
363                 }
364                 return mount;
365         }
366
367         
368         /**
369          * The table model for selecting whether components are motor mounts or not.
370          */
371         private class MotorMountTableModel extends AbstractTableModel {
372
373                 @Override
374                 public int getColumnCount() {
375                         return 2;
376                 }
377
378                 @Override
379                 public int getRowCount() {
380                         return mounts.length;
381                 }
382                 
383                 @Override
384                 public Class<?> getColumnClass(int column) {
385                         switch (column) {
386                         case 0:
387                                 return Boolean.class;
388                                 
389                         case 1:
390                                 return String.class;
391                                 
392                         default:
393                                 throw new IndexOutOfBoundsException("column="+column);
394                         }
395                 }
396
397                 @Override
398                 public Object getValueAt(int row, int column) {
399                         switch (column) {
400                         case 0:
401                                 return new Boolean(mounts[row].isMotorMount());
402                                 
403                         case 1:
404                                 return mounts[row].toString();
405                                 
406                         default:
407                                 throw new IndexOutOfBoundsException("column="+column);
408                         }
409                 }
410                 
411                 @Override
412                 public boolean isCellEditable(int row, int column) {
413                         return column == 0;
414                 }
415                 
416                 @Override
417                 public void setValueAt(Object value, int row, int column) {
418                         if (column != 0 || !(value instanceof Boolean)) {
419                                 throw new IllegalArgumentException("column="+column+", value="+value);
420                         }
421                         
422                         mounts[row].setMotorMount((Boolean)value);
423                         configurationTableModel.fireTableStructureChanged();
424                         updateEnabled();
425                 }
426         }
427         
428         
429         
430         /**
431          * The table model for selecting and editing the motor configurations.
432          */
433         private class MotorConfigurationTableModel extends AbstractTableModel {
434                 
435                 @Override
436                 public int getColumnCount() {
437                         int count = 1;
438                         for (MotorMount m: mounts) {
439                                 if (m.isMotorMount())
440                                         count++;
441                         }
442                         return count;
443                 }
444
445                 @Override
446                 public int getRowCount() {
447                         return rocket.getMotorConfigurationIDs().length-1;
448                 }
449
450                 @Override
451                 public Object getValueAt(int row, int column) {
452                         
453                         String id = findID(row);
454
455                         if (column == 0) {
456                                 return rocket.getMotorConfigurationNameOrDescription(id);
457                         }
458                         
459                         MotorMount mount = findMount(column);
460                         Motor motor = mount.getMotor(id);
461                         if (motor == null)
462                                 return "None";
463                         
464                         String str = motor.getDesignation(mount.getMotorDelay(id)); 
465                         int count = mount.getMotorCount();
466                         if (count > 1) {
467                                 str = "" + count + "\u00d7 " + str;
468                         }
469                         return str;
470                 }
471
472
473                 @Override
474                 public String getColumnName(int column) {
475                         if (column == 0) {
476                                 return "Configuration name";
477                         }
478                         
479                         MotorMount mount = findMount(column);
480                         String name = mount.toString();
481                         int count = mount.getMotorCount();
482                         if (count > 1) {
483                                 name = name + " (\u00d7" + count + ")";
484                         }
485                         return name;
486                 }
487                 
488                 
489         }
490
491         
492         
493         
494 }