updates for 0.9.4
[debian/openrocket] / src / net / sf / openrocket / gui / configdialog / FreeformFinSetConfig.java
1 package net.sf.openrocket.gui.configdialog;
2
3
4 import java.awt.Point;
5 import java.awt.event.MouseEvent;
6 import java.awt.geom.Point2D;
7
8 import javax.swing.JComboBox;
9 import javax.swing.JLabel;
10 import javax.swing.JPanel;
11 import javax.swing.JScrollPane;
12 import javax.swing.JSeparator;
13 import javax.swing.JSpinner;
14 import javax.swing.JTable;
15 import javax.swing.ListSelectionModel;
16 import javax.swing.SwingConstants;
17 import javax.swing.table.AbstractTableModel;
18
19 import net.miginfocom.swing.MigLayout;
20 import net.sf.openrocket.gui.SpinnerEditor;
21 import net.sf.openrocket.gui.adaptors.DoubleModel;
22 import net.sf.openrocket.gui.adaptors.EnumModel;
23 import net.sf.openrocket.gui.adaptors.IntegerModel;
24 import net.sf.openrocket.gui.components.BasicSlider;
25 import net.sf.openrocket.gui.components.StyledLabel;
26 import net.sf.openrocket.gui.components.UnitSelector;
27 import net.sf.openrocket.gui.scalefigure.FinPointFigure;
28 import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
29 import net.sf.openrocket.gui.scalefigure.ScaleSelector;
30 import net.sf.openrocket.material.Material;
31 import net.sf.openrocket.rocketcomponent.FinSet;
32 import net.sf.openrocket.rocketcomponent.FreeformFinSet;
33 import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
34 import net.sf.openrocket.rocketcomponent.RocketComponent;
35 import net.sf.openrocket.unit.UnitGroup;
36 import net.sf.openrocket.util.Coordinate;
37
38 public class FreeformFinSetConfig extends FinSetConfig {
39
40         private final FreeformFinSet finset;
41         private JTable table = null;
42         private FinPointTableModel tableModel = null;
43         
44         private FinPointFigure figure = null;
45         
46         
47         public FreeformFinSetConfig(RocketComponent component) {
48                 super(component);
49                 this.finset = (FreeformFinSet)component;
50
51
52                 tabbedPane.insertTab("General", null, generalPane(), "General properties", 0);
53                 tabbedPane.insertTab("Shape", null, shapePane(), "Fin shape", 1);
54                 tabbedPane.setSelectedIndex(0);
55                 
56                 addFinSetButtons();
57         }
58         
59         
60         
61         private JPanel generalPane() {
62
63                 DoubleModel m;
64                 JSpinner spin;
65                 JComboBox combo;
66                 
67                 JPanel mainPanel = new JPanel(new MigLayout("fill"));
68                 
69                 JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel","[][65lp::][30lp::]",""));
70                 
71                 
72                 
73                 ////  Number of fins
74                 panel.add(new JLabel("Number of fins:"));
75                 
76                 IntegerModel im = new IntegerModel(component,"FinCount",1,8);
77                 
78                 spin = new JSpinner(im.getSpinnerModel());
79                 spin.setEditor(new SpinnerEditor(spin));
80                 panel.add(spin,"growx, wrap");
81                 
82                 
83                 ////  Base rotation
84                 panel.add(new JLabel("Fin rotation:"));
85                 
86                 m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE,-Math.PI,Math.PI);
87                 
88                 spin = new JSpinner(m.getSpinnerModel());
89                 spin.setEditor(new SpinnerEditor(spin));
90                 panel.add(spin,"growx");
91                 
92                 panel.add(new UnitSelector(m),"growx");
93                 panel.add(new BasicSlider(m.getSliderModel(-Math.PI,Math.PI)),"w 100lp, wrap");
94                 
95                 
96
97                 ////  Fin cant
98                 JLabel label = new JLabel("Fin cant:");
99                 label.setToolTipText("The angle that the fins are canted with respect to the rocket " +
100                                 "body.");
101                 panel.add(label);
102                 
103                 m = new DoubleModel(component, "CantAngle", UnitGroup.UNITS_ANGLE,
104                                 -FinSet.MAX_CANT,FinSet.MAX_CANT);
105                 
106                 spin = new JSpinner(m.getSpinnerModel());
107                 spin.setEditor(new SpinnerEditor(spin));
108                 panel.add(spin,"growx");
109                 
110                 panel.add(new UnitSelector(m),"growx");
111                 panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT,FinSet.MAX_CANT)),
112                                 "w 100lp, wrap 40lp");
113                 
114                 
115                 
116                 ////  Position
117                 panel.add(new JLabel("Position relative to:"));
118
119                 combo = new JComboBox(
120                                 new EnumModel<RocketComponent.Position>(component, "RelativePosition",
121                                                 new RocketComponent.Position[] {
122                                                 RocketComponent.Position.TOP,
123                                                 RocketComponent.Position.MIDDLE,
124                                                 RocketComponent.Position.BOTTOM,
125                                                 RocketComponent.Position.ABSOLUTE
126                                 }));
127                 panel.add(combo,"spanx 3, growx, wrap");
128                                 
129                 panel.add(new JLabel("plus"),"right");
130
131                 m = new DoubleModel(component,"PositionValue",UnitGroup.UNITS_LENGTH);
132                 spin = new JSpinner(m.getSpinnerModel());
133                 spin.setEditor(new SpinnerEditor(spin));
134                 panel.add(spin,"growx");
135                 
136                 panel.add(new UnitSelector(m),"growx");
137                 panel.add(new BasicSlider(m.getSliderModel(
138                                 new DoubleModel(component.getParent(), "Length", -1.0, UnitGroup.UNITS_NONE),
139                                 new DoubleModel(component.getParent(), "Length"))),
140                                 "w 100lp, wrap");
141
142                 
143                 
144                 
145
146                 mainPanel.add(panel, "aligny 20%");
147                 mainPanel.add(new JSeparator(SwingConstants.VERTICAL), "growy, height 150lp");
148                 
149                 
150                 panel = new JPanel(new MigLayout("gap rel unrel","[][65lp::][30lp::]",""));
151                 
152                 
153                 
154                 
155                 ////  Cross section
156                 panel.add(new JLabel("Fin cross section:"),"span, split");
157                 combo = new JComboBox(
158                                 new EnumModel<FinSet.CrossSection>(component,"CrossSection"));
159                 panel.add(combo,"growx, wrap unrel");
160                 
161
162                 ////  Thickness
163                 panel.add(new JLabel("Thickness:"));
164                 
165                 m = new DoubleModel(component,"Thickness",UnitGroup.UNITS_LENGTH,0);
166                 
167                 spin = new JSpinner(m.getSpinnerModel());
168                 spin.setEditor(new SpinnerEditor(spin));
169                 panel.add(spin,"growx");
170                 
171                 panel.add(new UnitSelector(m),"growx");
172                 panel.add(new BasicSlider(m.getSliderModel(0,0.01)),"w 100lp, wrap 30lp");
173                 
174
175                 //// Material
176                 materialPanel(panel, Material.Type.BULK);
177                 
178                 
179                 
180                 mainPanel.add(panel, "aligny 20%");
181                 
182                 return mainPanel;
183         }
184         
185         
186         
187         private JPanel shapePane() {
188                 JPanel panel = new JPanel(new MigLayout("fill"));
189                 
190                 
191                 // Create the figure
192                 figure = new FinPointFigure(finset);
193                 ScaleScrollPane figurePane = new FinPointScrollPane();
194                 figurePane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
195                 figurePane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
196
197                 // Create the table
198                 tableModel = new FinPointTableModel();
199                 table = new JTable(tableModel);
200                 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
201                 for (int i=0; i < Columns.values().length; i++) {
202                         table.getColumnModel().getColumn(i).
203                                 setPreferredWidth(Columns.values()[i].getWidth());
204                 }
205                 JScrollPane tablePane = new JScrollPane(table);
206                 
207                 
208 //              panel.add(new JLabel("Coordinates:"), "aligny bottom, alignx 50%");
209 //              panel.add(new JLabel("    View:"), "wrap, aligny bottom");
210                 
211                 
212                 panel.add(tablePane,"growy, width 100lp:100lp:, height 100lp:250lp:");
213                 panel.add(figurePane,"gap unrel, spanx, growx, growy 1000, height 100lp:250lp:, wrap");
214                 
215                 panel.add(new StyledLabel("Double-click", -2), "alignx 50%");
216                 
217                 panel.add(new ScaleSelector(figurePane),"spany 2");
218                 panel.add(new StyledLabel("Click+drag: Add and move points   " +
219                                 "Ctrl+click: Remove point", -2), "spany 2, right, wrap");
220                 
221                 
222                 panel.add(new StyledLabel("to edit", -2), "alignx 50%");
223                 
224                 return panel;
225         }
226         
227         
228         
229         
230         
231         @Override
232         public void updateFields() {
233                 super.updateFields();
234                 
235                 if (tableModel != null) {
236                         tableModel.fireTableDataChanged();
237                 }
238                 if (figure != null) {
239                         figure.updateFigure();
240                 }
241         }
242         
243         
244         
245         
246         private class FinPointScrollPane extends ScaleScrollPane {
247                 private static final int ANY_MASK = 
248                         (MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK | 
249                                         MouseEvent.META_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK | 
250                                         MouseEvent.SHIFT_DOWN_MASK);
251                 
252                 private int dragIndex = -1;
253                 
254                 public FinPointScrollPane() {
255                         super(figure, false);   // Disallow fitting as it's buggy
256                 }
257
258                 @Override
259                 public void mousePressed(MouseEvent event) {
260                         int mods = event.getModifiersEx();
261                         
262                         if (event.getButton() != MouseEvent.BUTTON1 ||
263                                         (mods & ANY_MASK) != 0) {
264                                 super.mousePressed(event);
265                                 return;
266                         }
267                         
268                         int index = getPoint(event);
269                         if (index >= 0) {
270                                 dragIndex = index;
271                                 return;
272                         }
273                         index = getSegment(event);
274                         if (index >= 0) {
275                                 Point2D.Double point = getCoordinates(event);
276                                 finset.addPoint(index);
277                                 try {
278                                         finset.setPoint(index, point.x, point.y);
279                                 } catch (IllegalFinPointException ignore) { }
280                                 dragIndex = index;
281                                 
282                                 return;
283                         }
284                         
285                         super.mousePressed(event);
286                         return;
287                 }
288
289                 
290                 @Override
291                 public void mouseDragged(MouseEvent event) {
292                         int mods = event.getModifiersEx();
293                         if (dragIndex < 0 ||
294                                         (mods & (ANY_MASK | MouseEvent.BUTTON1_DOWN_MASK)) != 
295                                                 MouseEvent.BUTTON1_DOWN_MASK) {
296                                 super.mouseDragged(event);
297                                 return;
298                         }
299                         Point2D.Double point = getCoordinates(event);
300                         
301                         try {
302                                 finset.setPoint(dragIndex, point.x, point.y);
303                         } catch (IllegalFinPointException ignore) {
304                                 System.out.println("IAE:"+ignore);
305                         }
306                 }
307                 
308                 
309                 @Override
310                 public void mouseReleased(MouseEvent event) {
311                         dragIndex = -1;
312                         super.mouseReleased(event);
313                 }
314                 
315                 @Override
316                 public void mouseClicked(MouseEvent event) {
317                         int mods = event.getModifiersEx();
318                         if (event.getButton() != MouseEvent.BUTTON1 ||
319                                         (mods & ANY_MASK) != MouseEvent.CTRL_DOWN_MASK) {
320                                 super.mouseClicked(event);
321                                 return;
322                         }
323                         
324                         int index = getPoint(event);
325                         if (index < 0) {
326                                 super.mouseClicked(event);
327                                 return;
328                         }
329
330                         try {
331                                 finset.removePoint(index);
332                         } catch (IllegalFinPointException ignore) {
333                         }
334                 }
335                 
336                 
337                 private int getPoint(MouseEvent event) {
338                         Point p0 = event.getPoint();
339                         Point p1 = this.getViewport().getViewPosition();
340                         int x = p0.x + p1.x;
341                         int y = p0.y + p1.y;
342                         
343                         return figure.getIndexByPoint(x, y);
344                 }
345                 
346                 private int getSegment(MouseEvent event) {
347                         Point p0 = event.getPoint();
348                         Point p1 = this.getViewport().getViewPosition();
349                         int x = p0.x + p1.x;
350                         int y = p0.y + p1.y;
351                         
352                         return figure.getSegmentByPoint(x, y);
353                 }
354                 
355                 private Point2D.Double getCoordinates(MouseEvent event) {
356                         Point p0 = event.getPoint();
357                         Point p1 = this.getViewport().getViewPosition();
358                         int x = p0.x + p1.x;
359                         int y = p0.y + p1.y;
360                         
361                         return figure.convertPoint(x, y);
362                 }
363                 
364                 
365         }
366         
367         
368
369         
370         
371         private enum Columns {
372 //              NUMBER {
373 //                      @Override
374 //                      public String toString() {
375 //                              return "#";
376 //                      }
377 //                      @Override
378 //                      public String getValue(FreeformFinSet finset, int row) {
379 //                              return "" + (row+1) + ".";
380 //                      }
381 //                      @Override
382 //                      public int getWidth() {
383 //                              return 10;
384 //                      }
385 //              }, 
386                 X {
387                         @Override
388                         public String toString() {
389                                 return "X / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().toString();
390                         }
391                         @Override
392                         public String getValue(FreeformFinSet finset, int row) {
393                                 return UnitGroup.UNITS_LENGTH.getDefaultUnit()
394                                         .toString(finset.getFinPoints()[row].x);
395                         }
396                 }, 
397                 Y {
398                         @Override
399                         public String toString() {
400                                 return "Y / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().toString();
401                         }
402                         @Override
403                         public String getValue(FreeformFinSet finset, int row) {
404                                 return UnitGroup.UNITS_LENGTH.getDefaultUnit()
405                                         .toString(finset.getFinPoints()[row].y);
406                         }
407                 };
408                 
409                 public abstract String getValue(FreeformFinSet finset, int row);
410                 @Override
411                 public abstract String toString();
412                 public int getWidth() {
413                         return 20;
414                 }
415         }
416         
417         private class FinPointTableModel extends AbstractTableModel {
418                 
419                 @Override
420                 public int getColumnCount() {
421                         return Columns.values().length;
422                 }
423
424                 @Override
425                 public int getRowCount() {
426                         return finset.getPointCount();
427                 }
428
429                 @Override
430                 public Object getValueAt(int rowIndex, int columnIndex) {
431                         return Columns.values()[columnIndex].getValue(finset, rowIndex);
432                 }
433                 
434                 @Override
435                 public String getColumnName(int columnIndex) {
436                         return Columns.values()[columnIndex].toString();
437                 }
438                 
439                 @Override
440                 public boolean isCellEditable(int rowIndex, int columnIndex) {
441                         if (rowIndex == 0 || rowIndex == getRowCount()-1) {
442                                 return (columnIndex == Columns.X.ordinal());
443                         }
444                         
445                         return (columnIndex == Columns.X.ordinal() || columnIndex == Columns.Y.ordinal());
446                 }
447                 
448                 @Override
449                 public void setValueAt(Object o, int rowIndex, int columnIndex) {
450                         if (!(o instanceof String))
451                                 return;
452                         
453                         String str = (String)o;
454                         try {
455                                 
456                                 double value = UnitGroup.UNITS_LENGTH.fromString(str);
457                                 Coordinate c = finset.getFinPoints()[rowIndex];
458                                 if (columnIndex == Columns.X.ordinal())
459                                         c = c.setX(value);
460                                 else
461                                         c = c.setY(value);
462                                 
463                                 finset.setPoint(rowIndex, c.x, c.y);
464                         
465                         } catch (NumberFormatException ignore) {
466                         } catch (IllegalFinPointException ignore) {
467                         }
468                 }
469                 
470                 
471         }
472 }