101b8099e666ad856e8a172f0bbba08abd2dc466
[debian/openrocket] / src / net / sf / openrocket / gui / configdialog / RocketComponentConfig.java
1 package net.sf.openrocket.gui.configdialog;
2
3
4 import java.awt.Color;
5 import java.awt.Component;
6 import java.awt.Graphics;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.FocusEvent;
10 import java.awt.event.FocusListener;
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.List;
14
15 import javax.swing.BorderFactory;
16 import javax.swing.Icon;
17 import javax.swing.JButton;
18 import javax.swing.JCheckBox;
19 import javax.swing.JColorChooser;
20 import javax.swing.JComboBox;
21 import javax.swing.JLabel;
22 import javax.swing.JPanel;
23 import javax.swing.JScrollPane;
24 import javax.swing.JSpinner;
25 import javax.swing.JTabbedPane;
26 import javax.swing.JTextArea;
27 import javax.swing.JTextField;
28
29 import net.miginfocom.swing.MigLayout;
30 import net.sf.openrocket.gui.SpinnerEditor;
31 import net.sf.openrocket.gui.adaptors.BooleanModel;
32 import net.sf.openrocket.gui.adaptors.DoubleModel;
33 import net.sf.openrocket.gui.adaptors.EnumModel;
34 import net.sf.openrocket.gui.adaptors.MaterialModel;
35 import net.sf.openrocket.gui.components.BasicSlider;
36 import net.sf.openrocket.gui.components.StyledLabel;
37 import net.sf.openrocket.gui.components.StyledLabel.Style;
38 import net.sf.openrocket.gui.components.UnitSelector;
39 import net.sf.openrocket.l10n.Translator;
40 import net.sf.openrocket.material.Material;
41 import net.sf.openrocket.rocketcomponent.ComponentAssembly;
42 import net.sf.openrocket.rocketcomponent.ExternalComponent;
43 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
44 import net.sf.openrocket.rocketcomponent.NoseCone;
45 import net.sf.openrocket.rocketcomponent.Rocket;
46 import net.sf.openrocket.rocketcomponent.RocketComponent;
47 import net.sf.openrocket.startup.Application;
48 import net.sf.openrocket.unit.UnitGroup;
49 import net.sf.openrocket.util.GUIUtil;
50 import net.sf.openrocket.util.Invalidatable;
51 import net.sf.openrocket.util.LineStyle;
52 import net.sf.openrocket.util.Prefs;
53
54 public class RocketComponentConfig extends JPanel {
55         
56         private static final Translator trans = Application.getTranslator();
57         
58         protected final RocketComponent component;
59         protected final JTabbedPane tabbedPane;
60         
61         private final List<Invalidatable> invalidatables = new ArrayList<Invalidatable>();
62         
63
64         protected final JTextField componentNameField;
65         protected JTextArea commentTextArea;
66         private final TextFieldListener textFieldListener;
67         private JButton colorButton;
68         private JCheckBox colorDefault;
69         private JPanel buttonPanel;
70         
71         private JLabel massLabel;
72         
73         
74         public RocketComponentConfig(RocketComponent component) {
75                 setLayout(new MigLayout("fill", "[grow, fill]"));
76                 this.component = component;
77                 
78                 //// Component name:
79                 JLabel label = new JLabel(trans.get("RocketCompCfg.lbl.Componentname"));
80                 //// The component name.
81                 label.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
82                 this.add(label, "split, gapright 10");
83                 
84                 componentNameField = new JTextField(15);
85                 textFieldListener = new TextFieldListener();
86                 componentNameField.addActionListener(textFieldListener);
87                 componentNameField.addFocusListener(textFieldListener);
88                 //// The component name.
89                 componentNameField.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
90                 this.add(componentNameField, "growx, growy 0, wrap");
91                 
92
93                 tabbedPane = new JTabbedPane();
94                 this.add(tabbedPane, "growx, growy 1, wrap");
95                 
96                 //// Override and Mass and CG override options
97                 tabbedPane.addTab(trans.get("RocketCompCfg.tab.Override"), null, overrideTab(), 
98                                 trans.get("RocketCompCfg.tab.MassandCGoverride"));
99                 if (component.isMassive())
100                         //// Figure and Figure style options
101                         tabbedPane.addTab(trans.get("RocketCompCfg.tab.Figure"), null, figureTab(), 
102                                         trans.get("RocketCompCfg.tab.Figstyleopt"));
103                 //// Comment and Specify a comment for the component
104                 tabbedPane.addTab(trans.get("RocketCompCfg.tab.Comment"), null, commentTab(), 
105                                 trans.get("RocketCompCfg.tab.Specifyacomment"));
106                 
107                 addButtons();
108                 
109                 updateFields();
110         }
111         
112         
113         protected void addButtons(JButton... buttons) {
114                 if (buttonPanel != null) {
115                         this.remove(buttonPanel);
116                 }
117                 
118                 buttonPanel = new JPanel(new MigLayout("fill, ins 0"));
119                 
120                 //// Mass:
121                 massLabel = new StyledLabel(trans.get("RocketCompCfg.lbl.Mass") + " ", -1);
122                 buttonPanel.add(massLabel, "growx");
123                 
124                 for (JButton b : buttons) {
125                         buttonPanel.add(b, "right, gap para");
126                 }
127                 
128                 //// Close button
129                 JButton closeButton = new JButton(trans.get("dlg.but.close"));
130                 closeButton.addActionListener(new ActionListener() {
131                         @Override
132                         public void actionPerformed(ActionEvent arg0) {
133                                 ComponentConfigDialog.hideDialog();
134                         }
135                 });
136                 buttonPanel.add(closeButton, "right, gap 30lp");
137                 
138                 updateFields();
139                 
140                 this.add(buttonPanel, "spanx, growx");
141         }
142         
143         
144         /**
145          * Called when a change occurs, so that the fields can be updated if necessary.
146          * When overriding this method, the supermethod must always be called.
147          */
148         public void updateFields() {
149                 // Component name
150                 componentNameField.setText(component.getName());
151                 
152                 // Component color and "Use default color" checkbox
153                 if (colorButton != null && colorDefault != null) {
154                         colorButton.setIcon(new ColorIcon(component.getColor()));
155                         
156                         if ((component.getColor() == null) != colorDefault.isSelected())
157                                 colorDefault.setSelected(component.getColor() == null);
158                 }
159                 
160                 // Mass label
161                 if (component.isMassive()) {
162                         //// Component mass:
163                         String text = trans.get("RocketCompCfg.lbl.Componentmass") + " ";
164                         text += UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
165                                         component.getComponentMass());
166                         
167                         String overridetext = null;
168                         if (component.isMassOverridden()) {
169                                 //// (overridden to 
170                                 overridetext = trans.get("RocketCompCfg.lbl.overriddento")+" " + UnitGroup.UNITS_MASS.getDefaultUnit().
171                                                 toStringUnit(component.getOverrideMass()) + ")";
172                         }
173                         
174                         for (RocketComponent c = component.getParent(); c != null; c = c.getParent()) {
175                                 if (c.isMassOverridden() && c.getOverrideSubcomponents()) {
176                                         ///// (overridden by
177                                         overridetext = trans.get("RocketCompCfg.lbl.overriddenby")+" " + c.getName() + ")";
178                                 }
179                         }
180                         
181                         if (overridetext != null)
182                                 text = text + " " + overridetext;
183                         
184                         massLabel.setText(text);
185                 } else {
186                         massLabel.setText("");
187                 }
188         }
189         
190         
191         protected JPanel materialPanel(JPanel panel, Material.Type type) {
192                 ////Component material: and Component finish:
193                 return materialPanel(panel, type, trans.get("RocketCompCfg.lbl.Componentmaterial"),
194                                 trans.get("RocketCompCfg.lbl.Componentfinish"));
195         }
196         
197         protected JPanel materialPanel(JPanel panel, Material.Type type,
198                         String materialString, String finishString) {
199                 JLabel label = new JLabel(materialString);
200                 //// The component material affects the weight of the component.
201                 label.setToolTipText(trans.get("RocketCompCfg.lbl.ttip.componentmaterialaffects"));
202                 panel.add(label, "spanx 4, wrap rel");
203                 
204                 JComboBox combo = new JComboBox(new MaterialModel(panel, component, type));
205                 //// The component material affects the weight of the component.
206                 combo.setToolTipText(trans.get("RocketCompCfg.combo.ttip.componentmaterialaffects"));
207                 panel.add(combo, "spanx 4, growx, wrap paragraph");
208                 
209
210                 if (component instanceof ExternalComponent) {
211                         label = new JLabel(finishString);
212                         ////<html>The component finish affects the aerodynamic drag of the component.<br>
213                         String tip = trans.get("RocketCompCfg.lbl.longA1")
214                                         //// The value indicated is the average roughness height of the surface.
215                                         + trans.get("RocketCompCfg.lbl.longA2");
216                         label.setToolTipText(tip);
217                         panel.add(label, "spanx 4, wmin 220lp, wrap rel");
218                         
219                         combo = new JComboBox(new EnumModel<ExternalComponent.Finish>(component, "Finish"));
220                         combo.setToolTipText(tip);
221                         panel.add(combo, "spanx 4, growx, split");
222                         
223                         //// Set for all
224                         JButton button = new JButton(trans.get("RocketCompCfg.but.Setforall"));
225                         //// Set this finish for all components of the rocket.
226                         button.setToolTipText(trans.get("RocketCompCfg.but.ttip.Setforall"));
227                         button.addActionListener(new ActionListener() {
228                                 @Override
229                                 public void actionPerformed(ActionEvent e) {
230                                         Finish f = ((ExternalComponent) component).getFinish();
231                                         Rocket rocket = component.getRocket();
232                                         try {
233                                                 rocket.freeze();
234                                                 // Store previous undo description
235                                                 String desc = ComponentConfigDialog.getUndoDescription();
236                                                 ComponentConfigDialog.addUndoPosition("Set rocket finish");
237                                                 // Do changes
238                                                 Iterator<RocketComponent> iter = rocket.iterator();
239                                                 while (iter.hasNext()) {
240                                                         RocketComponent c = iter.next();
241                                                         if (c instanceof ExternalComponent) {
242                                                                 ((ExternalComponent) c).setFinish(f);
243                                                         }
244                                                 }
245                                                 // Restore undo description
246                                                 ComponentConfigDialog.addUndoPosition(desc);
247                                         } finally {
248                                                 rocket.thaw();
249                                         }
250                                 }
251                         });
252                         panel.add(button, "wrap paragraph");
253                 }
254                 
255                 return panel;
256         }
257         
258         
259         private JPanel overrideTab() {
260                 JPanel panel = new JPanel(new MigLayout("align 50% 20%, fillx, gap rel unrel",
261                                 "[][65lp::][30lp::][]", ""));
262                 //// Override the mass or center of gravity of the
263                 panel.add(new StyledLabel(trans.get("RocketCompCfg.lbl.Overridemassorcenter") + " " +
264                                 component.getComponentName() + ":", Style.BOLD), "spanx, wrap 20lp");
265                 
266                 JCheckBox check;
267                 BooleanModel bm;
268                 UnitSelector us;
269                 BasicSlider bs;
270                 
271                 ////  Mass
272                 bm = new BooleanModel(component, "MassOverridden");
273                 check = new JCheckBox(bm);
274                 //// Override mass:
275                 check.setText(trans.get("RocketCompCfg.checkbox.Overridemass"));
276                 panel.add(check, "growx 1, gapright 20lp");
277                 
278                 DoubleModel m = new DoubleModel(component, "OverrideMass", UnitGroup.UNITS_MASS, 0);
279                 
280                 JSpinner spin = new JSpinner(m.getSpinnerModel());
281                 spin.setEditor(new SpinnerEditor(spin));
282                 bm.addEnableComponent(spin, true);
283                 panel.add(spin, "growx 1");
284                 
285                 us = new UnitSelector(m);
286                 bm.addEnableComponent(us, true);
287                 panel.add(us, "growx 1");
288                 
289                 bs = new BasicSlider(m.getSliderModel(0, 0.03, 1.0));
290                 bm.addEnableComponent(bs);
291                 panel.add(bs, "growx 5, w 100lp, wrap");
292                 
293
294                 ////  CG override
295                 bm = new BooleanModel(component, "CGOverridden");
296                 check = new JCheckBox(bm);
297                 //// Override center of gravity:"
298                 check.setText(trans.get("RocketCompCfg.checkbox.Overridecenterofgrav"));
299                 panel.add(check, "growx 1, gapright 20lp");
300                 
301                 m = new DoubleModel(component, "OverrideCGX", UnitGroup.UNITS_LENGTH, 0);
302                 // Calculate suitable length for slider
303                 DoubleModel length;
304                 if (component instanceof ComponentAssembly) {
305                         double l = 0;
306                         
307                         Iterator<RocketComponent> iterator = component.iterator(false);
308                         while (iterator.hasNext()) {
309                                 RocketComponent c = iterator.next();
310                                 if (c.getRelativePosition() == RocketComponent.Position.AFTER)
311                                         l += c.getLength();
312                         }
313                         length = new DoubleModel(l);
314                 } else {
315                         length = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0);
316                 }
317                 
318                 spin = new JSpinner(m.getSpinnerModel());
319                 spin.setEditor(new SpinnerEditor(spin));
320                 bm.addEnableComponent(spin, true);
321                 panel.add(spin, "growx 1");
322                 
323                 us = new UnitSelector(m);
324                 bm.addEnableComponent(us, true);
325                 panel.add(us, "growx 1");
326                 
327                 bs = new BasicSlider(m.getSliderModel(new DoubleModel(0), length));
328                 bm.addEnableComponent(bs);
329                 panel.add(bs, "growx 5, w 100lp, wrap 35lp");
330                 
331
332                 // Override subcomponents checkbox
333                 bm = new BooleanModel(component, "OverrideSubcomponents");
334                 check = new JCheckBox(bm);
335                 //// Override mass and CG of all subcomponents
336                 check.setText(trans.get("RocketCompCfg.checkbox.OverridemassandCG"));
337                 panel.add(check, "gap para, spanx, wrap para");
338                 
339                 //// <html>The overridden mass does not include motors.<br>
340                 panel.add(new StyledLabel(trans.get("RocketCompCfg.lbl.longB1") +
341                                 //// The center of gravity is measured from the front end of the
342                                 trans.get("RocketCompCfg.lbl.longB2") +" " +
343                                 component.getComponentName().toLowerCase() + ".", -1),
344                                 "spanx, wrap, gap para, height 0::30lp");
345                 
346                 return panel;
347         }
348         
349         
350         private JPanel commentTab() {
351                 JPanel panel = new JPanel(new MigLayout("fill"));
352                 
353                 //// Comments on the
354                 panel.add(new StyledLabel(trans.get("RocketCompCfg.lbl.Commentsonthe") +" " + component.getComponentName() + ":",
355                                 Style.BOLD), "wrap");
356                 
357                 // TODO: LOW:  Changes in comment from other sources not reflected in component
358                 commentTextArea = new JTextArea(component.getComment());
359                 commentTextArea.setLineWrap(true);
360                 commentTextArea.setWrapStyleWord(true);
361                 commentTextArea.setEditable(true);
362                 GUIUtil.setTabToFocusing(commentTextArea);
363                 commentTextArea.addFocusListener(textFieldListener);
364                 
365                 panel.add(new JScrollPane(commentTextArea), "width 10px, height 10px, growx, growy");
366                 
367                 return panel;
368         }
369         
370         
371
372         private JPanel figureTab() {
373                 JPanel panel = new JPanel(new MigLayout("align 20% 20%"));
374                 
375                 //// Figure style:
376                 panel.add(new StyledLabel(trans.get("RocketCompCfg.lbl.Figurestyle"), Style.BOLD), "wrap para");
377                 
378                 //// Component color:
379                 panel.add(new JLabel(trans.get("RocketCompCfg.lbl.Componentcolor")), "gapleft para, gapright 10lp");
380                 
381                 colorButton = new JButton(new ColorIcon(component.getColor()));
382                 colorButton.addActionListener(new ActionListener() {
383                         @Override
384                         public void actionPerformed(ActionEvent e) {
385                                 Color c = component.getColor();
386                                 if (c == null) {
387                                         c = Prefs.getDefaultColor(component.getClass());
388                                 }
389                                 
390                                 //// Choose color
391                                 c = JColorChooser.showDialog(tabbedPane, trans.get("RocketCompCfg.lbl.Choosecolor"), c);
392                                 if (c != null) {
393                                         component.setColor(c);
394                                 }
395                         }
396                 });
397                 panel.add(colorButton, "gapright 10lp");
398                 
399                 //// Use default color
400                 colorDefault = new JCheckBox(trans.get("RocketCompCfg.checkbox.Usedefaultcolor"));
401                 if (component.getColor() == null)
402                         colorDefault.setSelected(true);
403                 colorDefault.addActionListener(new ActionListener() {
404                         @Override
405                         public void actionPerformed(ActionEvent e) {
406                                 if (colorDefault.isSelected())
407                                         component.setColor(null);
408                                 else
409                                         component.setColor(Prefs.getDefaultColor(component.getClass()));
410                         }
411                 });
412                 panel.add(colorDefault, "wrap para");
413                 
414                 //// Component line style:
415                 panel.add(new JLabel(trans.get("RocketCompCfg.lbl.Complinestyle")), "gapleft para, gapright 10lp");
416                 
417                 LineStyle[] list = new LineStyle[LineStyle.values().length + 1];
418                 System.arraycopy(LineStyle.values(), 0, list, 1, LineStyle.values().length);
419                 
420                 JComboBox combo = new JComboBox(new EnumModel<LineStyle>(component, "LineStyle",
421                                 list, "Default style"));
422                 panel.add(combo, "spanx 2, growx, wrap 50lp");
423                 
424                 //// Save as default style
425                 JButton button = new JButton(trans.get("RocketCompCfg.but.Saveasdefstyle"));
426                 button.addActionListener(new ActionListener() {
427                         @Override
428                         public void actionPerformed(ActionEvent e) {
429                                 if (component.getColor() != null) {
430                                         Prefs.setDefaultColor(component.getClass(), component.getColor());
431                                         component.setColor(null);
432                                 }
433                                 if (component.getLineStyle() != null) {
434                                         Prefs.setDefaultLineStyle(component.getClass(), component.getLineStyle());
435                                         component.setLineStyle(null);
436                                 }
437                         }
438                 });
439                 panel.add(button, "gapleft para, spanx 3, growx, wrap");
440                 
441                 return panel;
442         }
443         
444         
445
446
447         protected JPanel shoulderTab() {
448                 JPanel panel = new JPanel(new MigLayout("fill"));
449                 JPanel sub;
450                 DoubleModel m, m2;
451                 DoubleModel m0 = new DoubleModel(0);
452                 BooleanModel bm;
453                 JCheckBox check;
454                 JSpinner spin;
455                 
456
457                 ////  Fore shoulder, not for NoseCone
458                 
459                 if (!(component instanceof NoseCone)) {
460                         sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
461                         
462                         //// Fore shoulder
463                         sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.border.Foreshoulder")));
464                         
465
466                         ////  Radius
467                         //// Diameter:
468                         sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Diameter")));
469                         
470                         m = new DoubleModel(component, "ForeShoulderRadius", 2, UnitGroup.UNITS_LENGTH, 0);
471                         m2 = new DoubleModel(component, "ForeRadius", 2, UnitGroup.UNITS_LENGTH);
472                         
473                         spin = new JSpinner(m.getSpinnerModel());
474                         spin.setEditor(new SpinnerEditor(spin));
475                         sub.add(spin, "growx");
476                         
477                         sub.add(new UnitSelector(m), "growx");
478                         sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
479                         
480
481                         ////  Length:
482                         sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Length")));
483                         
484                         m = new DoubleModel(component, "ForeShoulderLength", UnitGroup.UNITS_LENGTH, 0);
485                         
486                         spin = new JSpinner(m.getSpinnerModel());
487                         spin.setEditor(new SpinnerEditor(spin));
488                         sub.add(spin, "growx");
489                         
490                         sub.add(new UnitSelector(m), "growx");
491                         sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)), "w 100lp, wrap");
492                         
493
494                         ////  Thickness:
495                         sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Thickness")));
496                         
497                         m = new DoubleModel(component, "ForeShoulderThickness", UnitGroup.UNITS_LENGTH, 0);
498                         m2 = new DoubleModel(component, "ForeShoulderRadius", UnitGroup.UNITS_LENGTH);
499                         
500                         spin = new JSpinner(m.getSpinnerModel());
501                         spin.setEditor(new SpinnerEditor(spin));
502                         sub.add(spin, "growx");
503                         
504                         sub.add(new UnitSelector(m), "growx");
505                         sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
506                         
507
508                         ////  Capped
509                         bm = new BooleanModel(component, "ForeShoulderCapped");
510                         check = new JCheckBox(bm);
511                         //// End capped
512                         check.setText(trans.get("RocketCompCfg.checkbox.Endcapped"));
513                         //// Whether the end of the shoulder is capped.
514                         check.setToolTipText(trans.get("RocketCompCfg.ttip.Endcapped"));
515                         sub.add(check, "spanx");
516                         
517
518                         panel.add(sub);
519                 }
520                 
521
522                 ////  Aft shoulder
523                 sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
524                 
525                 if (component instanceof NoseCone)
526                         //// Nose cone shoulder
527                         sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Noseconeshoulder")));
528                 else
529                         //// Aft shoulder
530                         sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Aftshoulder")));
531                 
532
533                 ////  Radius
534                 //// Diameter:
535                 sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Diameter")));
536                 
537                 m = new DoubleModel(component, "AftShoulderRadius", 2, UnitGroup.UNITS_LENGTH, 0);
538                 m2 = new DoubleModel(component, "AftRadius", 2, UnitGroup.UNITS_LENGTH);
539                 
540                 spin = new JSpinner(m.getSpinnerModel());
541                 spin.setEditor(new SpinnerEditor(spin));
542                 sub.add(spin, "growx");
543                 
544                 sub.add(new UnitSelector(m), "growx");
545                 sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
546                 
547
548                 ////  Length:
549                 sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Length")));
550                 
551                 m = new DoubleModel(component, "AftShoulderLength", UnitGroup.UNITS_LENGTH, 0);
552                 
553                 spin = new JSpinner(m.getSpinnerModel());
554                 spin.setEditor(new SpinnerEditor(spin));
555                 sub.add(spin, "growx");
556                 
557                 sub.add(new UnitSelector(m), "growx");
558                 sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)), "w 100lp, wrap");
559                 
560
561                 ////  Thickness:
562                 sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Thickness")));
563                 
564                 m = new DoubleModel(component, "AftShoulderThickness", UnitGroup.UNITS_LENGTH, 0);
565                 m2 = new DoubleModel(component, "AftShoulderRadius", UnitGroup.UNITS_LENGTH);
566                 
567                 spin = new JSpinner(m.getSpinnerModel());
568                 spin.setEditor(new SpinnerEditor(spin));
569                 sub.add(spin, "growx");
570                 
571                 sub.add(new UnitSelector(m), "growx");
572                 sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
573                 
574
575                 ////  Capped
576                 bm = new BooleanModel(component, "AftShoulderCapped");
577                 check = new JCheckBox(bm);
578                 //// End capped
579                 check.setText(trans.get("RocketCompCfg.checkbox.Endcapped"));
580                 //// Whether the end of the shoulder is capped.
581                 check.setToolTipText(trans.get("RocketCompCfg.ttip.Endcapped"));
582                 sub.add(check, "spanx");
583                 
584
585                 panel.add(sub);
586                 
587
588                 return panel;
589         }
590         
591         
592
593
594         /*
595          * Private inner class to handle events in componentNameField.
596          */
597         private class TextFieldListener implements ActionListener, FocusListener {
598                 @Override
599                 public void actionPerformed(ActionEvent e) {
600                         setName();
601                 }
602                 
603                 @Override
604                 public void focusGained(FocusEvent e) {
605                 }
606                 
607                 @Override
608                 public void focusLost(FocusEvent e) {
609                         setName();
610                 }
611                 
612                 private void setName() {
613                         if (!component.getName().equals(componentNameField.getText())) {
614                                 component.setName(componentNameField.getText());
615                         }
616                         if (!component.getComment().equals(commentTextArea.getText())) {
617                                 component.setComment(commentTextArea.getText());
618                         }
619                 }
620         }
621         
622         
623         private class ColorIcon implements Icon {
624                 private final Color color;
625                 
626                 public ColorIcon(Color c) {
627                         this.color = c;
628                 }
629                 
630                 @Override
631                 public int getIconHeight() {
632                         return 15;
633                 }
634                 
635                 @Override
636                 public int getIconWidth() {
637                         return 25;
638                 }
639                 
640                 @Override
641                 public void paintIcon(Component c, Graphics g, int x, int y) {
642                         if (color == null) {
643                                 g.setColor(Prefs.getDefaultColor(component.getClass()));
644                         } else {
645                                 g.setColor(color);
646                         }
647                         g.fill3DRect(x, y, getIconWidth(), getIconHeight(), false);
648                 }
649                 
650         }
651         
652         protected void register(Invalidatable model) {
653                 this.invalidatables.add(model);
654         }
655         
656         public void invalidateModels() {
657                 for (Invalidatable i : invalidatables) {
658                         i.invalidate();
659                 }
660         }
661         
662 }