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