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