major optimization updates
[debian/openrocket] / src / net / sf / openrocket / gui / dialogs / ComponentAnalysisDialog.java
1 package net.sf.openrocket.gui.dialogs;
2
3 import static net.sf.openrocket.unit.Unit.NOUNIT2;
4 import static net.sf.openrocket.util.Chars.ALPHA;
5
6 import java.awt.Color;
7 import java.awt.Component;
8 import java.awt.Dimension;
9 import java.awt.Font;
10 import java.awt.event.ActionEvent;
11 import java.awt.event.ActionListener;
12 import java.awt.event.WindowAdapter;
13 import java.awt.event.WindowEvent;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Vector;
18
19 import javax.swing.BorderFactory;
20 import javax.swing.JButton;
21 import javax.swing.JComboBox;
22 import javax.swing.JDialog;
23 import javax.swing.JFrame;
24 import javax.swing.JLabel;
25 import javax.swing.JList;
26 import javax.swing.JPanel;
27 import javax.swing.JScrollPane;
28 import javax.swing.JTabbedPane;
29 import javax.swing.JTable;
30 import javax.swing.JToggleButton;
31 import javax.swing.ListSelectionModel;
32 import javax.swing.SwingConstants;
33 import javax.swing.SwingUtilities;
34 import javax.swing.event.ChangeEvent;
35 import javax.swing.event.ChangeListener;
36 import javax.swing.table.TableCellRenderer;
37
38 import net.miginfocom.swing.MigLayout;
39 import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
40 import net.sf.openrocket.aerodynamics.AerodynamicForces;
41 import net.sf.openrocket.aerodynamics.FlightConditions;
42 import net.sf.openrocket.aerodynamics.Warning;
43 import net.sf.openrocket.aerodynamics.WarningSet;
44 import net.sf.openrocket.gui.adaptors.Column;
45 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
46 import net.sf.openrocket.gui.adaptors.DoubleModel;
47 import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
48 import net.sf.openrocket.gui.components.BasicSlider;
49 import net.sf.openrocket.gui.components.StageSelector;
50 import net.sf.openrocket.gui.components.StyledLabel;
51 import net.sf.openrocket.gui.components.UnitSelector;
52 import net.sf.openrocket.gui.scalefigure.RocketPanel;
53 import net.sf.openrocket.l10n.Translator;
54 import net.sf.openrocket.masscalc.BasicMassCalculator;
55 import net.sf.openrocket.masscalc.MassCalculator;
56 import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
57 import net.sf.openrocket.rocketcomponent.Configuration;
58 import net.sf.openrocket.rocketcomponent.FinSet;
59 import net.sf.openrocket.rocketcomponent.Rocket;
60 import net.sf.openrocket.rocketcomponent.RocketComponent;
61 import net.sf.openrocket.startup.Application;
62 import net.sf.openrocket.unit.Unit;
63 import net.sf.openrocket.unit.UnitGroup;
64 import net.sf.openrocket.util.Coordinate;
65 import net.sf.openrocket.util.GUIUtil;
66 import net.sf.openrocket.util.MathUtil;
67 import net.sf.openrocket.util.Prefs;
68
69 public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
70         
71         private static ComponentAnalysisDialog singletonDialog = null;
72         private static final Translator trans = Application.getTranslator();
73
74
75         private final FlightConditions conditions;
76         private final Configuration configuration;
77         private final DoubleModel theta, aoa, mach, roll;
78         private final JToggleButton worstToggle;
79         private boolean fakeChange = false;
80         private AerodynamicCalculator aerodynamicCalculator;
81         private final MassCalculator massCalculator = new BasicMassCalculator();
82         
83         private final ColumnTableModel cpTableModel;
84         private final ColumnTableModel dragTableModel;
85         private final ColumnTableModel rollTableModel;
86         
87         private final JList warningList;
88         
89
90         private final List<AerodynamicForces> cpData = new ArrayList<AerodynamicForces>();
91         private final List<Coordinate> cgData = new ArrayList<Coordinate>();
92         private final List<AerodynamicForces> dragData = new ArrayList<AerodynamicForces>();
93         private double totalCD = 0;
94         private final List<AerodynamicForces> rollData = new ArrayList<AerodynamicForces>();
95         
96         
97         public ComponentAnalysisDialog(final RocketPanel rocketPanel) {
98                 ////Component analysis
99                 super(SwingUtilities.getWindowAncestor(rocketPanel), 
100                                 trans.get("componentanalysisdlg.componentanalysis"));
101                 
102                 JTable table;
103                 
104                 JPanel panel = new JPanel(new MigLayout("fill", "[][35lp::][fill][fill]"));
105                 add(panel);
106                 
107                 this.configuration = rocketPanel.getConfiguration();
108                 this.aerodynamicCalculator = rocketPanel.getAerodynamicCalculator().newInstance();
109                 
110
111                 conditions = new FlightConditions(configuration);
112                 
113                 rocketPanel.setCPAOA(0);
114                 aoa = new DoubleModel(rocketPanel, "CPAOA", UnitGroup.UNITS_ANGLE, 0, Math.PI);
115                 rocketPanel.setCPMach(Prefs.getDefaultMach());
116                 mach = new DoubleModel(rocketPanel, "CPMach", UnitGroup.UNITS_COEFFICIENT, 0);
117                 rocketPanel.setCPTheta(rocketPanel.getFigure().getRotation());
118                 theta = new DoubleModel(rocketPanel, "CPTheta", UnitGroup.UNITS_ANGLE, 0, 2 * Math.PI);
119                 rocketPanel.setCPRoll(0);
120                 roll = new DoubleModel(rocketPanel, "CPRoll", UnitGroup.UNITS_ROLL);
121                 
122                 //// Wind direction:
123                 panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.winddir")), "width 100lp!");
124                 panel.add(new UnitSelector(theta, true), "width 50lp!");
125                 BasicSlider slider = new BasicSlider(theta.getSliderModel(0, 2 * Math.PI));
126                 panel.add(slider, "growx, split 2");
127                 //// Worst button
128                 worstToggle = new JToggleButton(trans.get("componentanalysisdlg.ToggleBut.worst"));
129                 worstToggle.setSelected(true);
130                 worstToggle.addActionListener(new ActionListener() {
131                         @Override
132                         public void actionPerformed(ActionEvent e) {
133                                 stateChanged(null);
134                         }
135                 });
136                 slider.addChangeListener(new ChangeListener() {
137                         @Override
138                         public void stateChanged(ChangeEvent e) {
139                                 if (!fakeChange)
140                                         worstToggle.setSelected(false);
141                         }
142                 });
143                 panel.add(worstToggle, "");
144                 
145
146                 warningList = new JList();
147                 JScrollPane scrollPane = new JScrollPane(warningList);
148                 ////Warnings:
149                 scrollPane.setBorder(BorderFactory.createTitledBorder(trans.get("componentanalysisdlg.TitledBorder.warnings")));
150                 panel.add(scrollPane, "gap paragraph, spany 4, width 300lp!, growy 1, height :100lp:, wrap");
151                 
152                 ////Angle of attack:
153                 panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.angleofattack")), "width 100lp!");
154                 panel.add(new UnitSelector(aoa, true), "width 50lp!");
155                 panel.add(new BasicSlider(aoa.getSliderModel(0, Math.PI)), "growx, wrap");
156                 
157                 //// Mach number:
158                 panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.machnumber")), "width 100lp!");
159                 panel.add(new UnitSelector(mach, true), "width 50lp!");
160                 panel.add(new BasicSlider(mach.getSliderModel(0, 3)), "growx, wrap");
161                 
162                 //// Roll rate:
163                 panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.rollrate")), "width 100lp!");
164                 panel.add(new UnitSelector(roll, true), "width 50lp!");
165                 panel.add(new BasicSlider(roll.getSliderModel(-20 * 2 * Math.PI, 20 * 2 * Math.PI)),
166                                 "growx, wrap paragraph");
167                 
168
169                 // Stage and motor selection:
170                 //// Active stages:
171                 panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.activestages")), "spanx, split, gapafter rel");
172                 panel.add(new StageSelector(configuration), "gapafter paragraph");
173                 
174                 //// Motor configuration:
175                 JLabel label = new JLabel(trans.get("componentanalysisdlg.lbl.motorconf"));
176                 label.setHorizontalAlignment(JLabel.RIGHT);
177                 panel.add(label, "growx, right");
178                 panel.add(new JComboBox(new MotorConfigurationModel(configuration)), "wrap");
179                 
180
181
182                 // Tabbed pane
183                 
184                 JTabbedPane tabbedPane = new JTabbedPane();
185                 panel.add(tabbedPane, "spanx, growx, growy");
186                 
187
188                 // Create the CP data table
189                 cpTableModel = new ColumnTableModel(
190
191                 //// Component
192                 new Column(trans.get("componentanalysisdlg.TabStability.Col.Component")) {
193                         @Override
194                         public Object getValueAt(int row) {
195                                 RocketComponent c = cpData.get(row).getComponent();
196                                 if (c instanceof Rocket) {
197                                         return "Total";
198                                 }
199                                 return c.toString();
200                         }
201                         
202                         @Override
203                         public int getDefaultWidth() {
204                                 return 200;
205                         }
206                 },
207                                 new Column("CG / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
208                                         private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
209                                         
210                                         @Override
211                                         public Object getValueAt(int row) {
212                                                 return unit.toString(cgData.get(row).x);
213                                         }
214                                 },
215                                 new Column("Mass / " + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit()) {
216                                         private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
217                                         
218                                         @Override
219                                         public Object getValueAt(int row) {
220                                                 return unit.toString(cgData.get(row).weight);
221                                         }
222                                 },
223                                 new Column("CP / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
224                                         private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
225                                         
226                                         @Override
227                                         public Object getValueAt(int row) {
228                                                 return unit.toString(cpData.get(row).getCP().x);
229                                         }
230                                 },
231                                 new Column("<html>C<sub>N<sub>" + ALPHA + "</sub></sub>") {
232                                         @Override
233                                         public Object getValueAt(int row) {
234                                                 return NOUNIT2.toString(cpData.get(row).getCP().weight);
235                                         }
236                                 }
237
238                 ) {
239                         @Override
240                         public int getRowCount() {
241                                 return cpData.size();
242                         }
243                 };
244                 
245                 table = new JTable(cpTableModel);
246                 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
247                 table.setSelectionBackground(Color.LIGHT_GRAY);
248                 table.setSelectionForeground(Color.BLACK);
249                 cpTableModel.setColumnWidths(table.getColumnModel());
250                 
251                 table.setDefaultRenderer(Object.class, new CustomCellRenderer());
252                 //              table.setShowHorizontalLines(false);
253                 //              table.setShowVerticalLines(true);
254                 
255                 JScrollPane scrollpane = new JScrollPane(table);
256                 scrollpane.setPreferredSize(new Dimension(600, 200));
257                 
258                 //// Stability and Stability information
259                 tabbedPane.addTab(trans.get("componentanalysisdlg.TabStability"), 
260                                 null, scrollpane, trans.get("componentanalysisdlg.TabStability.ttip"));
261                 
262
263
264                 // Create the drag data table
265                 dragTableModel = new ColumnTableModel(
266                                 //// Component
267                                 new Column(trans.get("componentanalysisdlg.dragTableModel.Col.Component")) {
268                                         @Override
269                                         public Object getValueAt(int row) {
270                                                 RocketComponent c = dragData.get(row).getComponent();
271                                                 if (c instanceof Rocket) {
272                                                         return "Total";
273                                                 }
274                                                 return c.toString();
275                                         }
276                                         
277                                         @Override
278                                         public int getDefaultWidth() {
279                                                 return 200;
280                                         }
281                                 },
282                                 //// <html>Pressure C<sub>D</sub>
283                                 new Column(trans.get("componentanalysisdlg.dragTableModel.Col.Pressure")) {
284                                         @Override
285                                         public Object getValueAt(int row) {
286                                                 return dragData.get(row).getPressureCD();
287                                         }
288                                 },
289                                 //// <html>Base C<sub>D</sub>
290                                 new Column(trans.get("componentanalysisdlg.dragTableModel.Col.Base")) {
291                                         @Override
292                                         public Object getValueAt(int row) {
293                                                 return dragData.get(row).getBaseCD();
294                                         }
295                                 },
296                                 //// <html>Friction C<sub>D</sub>
297                                 new Column(trans.get("componentanalysisdlg.dragTableModel.Col.friction")) {
298                                         @Override
299                                         public Object getValueAt(int row) {
300                                                 return dragData.get(row).getFrictionCD();
301                                         }
302                                 },
303                                 //// <html>Total C<sub>D</sub>
304                                 new Column(trans.get("componentanalysisdlg.dragTableModel.Col.total")) {
305                                         @Override
306                                         public Object getValueAt(int row) {
307                                                 return dragData.get(row).getCD();
308                                         }
309                                 }
310                                 ) {
311                                         @Override
312                                         public int getRowCount() {
313                                                 return dragData.size();
314                                         }
315                                 };
316                 
317
318                 table = new JTable(dragTableModel);
319                 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
320                 table.setSelectionBackground(Color.LIGHT_GRAY);
321                 table.setSelectionForeground(Color.BLACK);
322                 dragTableModel.setColumnWidths(table.getColumnModel());
323                 
324                 table.setDefaultRenderer(Object.class, new DragCellRenderer(new Color(0.5f, 1.0f, 0.5f)));
325                 //              table.setShowHorizontalLines(false);
326                 //              table.setShowVerticalLines(true);
327                 
328                 scrollpane = new JScrollPane(table);
329                 scrollpane.setPreferredSize(new Dimension(600, 200));
330                 
331                 //// Drag characteristics and Drag characteristics tooltip
332                 tabbedPane.addTab(trans.get("componentanalysisdlg.dragTabchar"), null, scrollpane,
333                                 trans.get("componentanalysisdlg.dragTabchar.ttip"));
334                 
335
336
337
338                 // Create the roll data table
339                 rollTableModel = new ColumnTableModel(
340                                 //// Component
341                                 new Column(trans.get("componentanalysisdlg.rollTableModel.Col.component")) {
342                                         @Override
343                                         public Object getValueAt(int row) {
344                                                 RocketComponent c = rollData.get(row).getComponent();
345                                                 if (c instanceof Rocket) {
346                                                         return "Total";
347                                                 }
348                                                 return c.toString();
349                                         }
350                                 },
351                                 //// Roll forcing coefficient
352                                 new Column(trans.get("componentanalysisdlg.rollTableModel.Col.rollforc")) {
353                                         @Override
354                                         public Object getValueAt(int row) {
355                                                 return rollData.get(row).getCrollForce();
356                                         }
357                                 },
358                                 //// Roll damping coefficient
359                                 new Column(trans.get("componentanalysisdlg.rollTableModel.Col.rolldamp")) {
360                                         @Override
361                                         public Object getValueAt(int row) {
362                                                 return rollData.get(row).getCrollDamp();
363                                         }
364                                 },
365                                 //// <html>Total C<sub>l</sub>
366                                 new Column(trans.get("componentanalysisdlg.rollTableModel.Col.total")) {
367                                         @Override
368                                         public Object getValueAt(int row) {
369                                                 return rollData.get(row).getCroll();
370                                         }
371                                 }
372                                 ) {
373                                         @Override
374                                         public int getRowCount() {
375                                                 return rollData.size();
376                                         }
377                                 };
378                 
379
380                 table = new JTable(rollTableModel);
381                 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
382                 table.setSelectionBackground(Color.LIGHT_GRAY);
383                 table.setSelectionForeground(Color.BLACK);
384                 rollTableModel.setColumnWidths(table.getColumnModel());
385                 
386                 scrollpane = new JScrollPane(table);
387                 scrollpane.setPreferredSize(new Dimension(600, 200));
388                 
389                 //// Roll dynamics and Roll dynamics tooltip
390                 tabbedPane.addTab(trans.get("componentanalysisdlg.rollTableModel"), null, scrollpane, 
391                                 trans.get("componentanalysisdlg.rollTableModel.ttip"));
392                 
393
394
395
396
397                 // Add the data updater to listen to changes in aoa and theta
398                 mach.addChangeListener(this);
399                 theta.addChangeListener(this);
400                 aoa.addChangeListener(this);
401                 roll.addChangeListener(this);
402                 configuration.addChangeListener(this);
403                 this.stateChanged(null);
404                 
405
406
407                 // Remove listeners when closing window
408                 this.addWindowListener(new WindowAdapter() {
409                         @Override
410                         public void windowClosed(WindowEvent e) {
411                                 System.out.println("Closing method called: " + this);
412                                 theta.removeChangeListener(ComponentAnalysisDialog.this);
413                                 aoa.removeChangeListener(ComponentAnalysisDialog.this);
414                                 mach.removeChangeListener(ComponentAnalysisDialog.this);
415                                 roll.removeChangeListener(ComponentAnalysisDialog.this);
416                                 configuration.removeChangeListener(ComponentAnalysisDialog.this);
417                                 System.out.println("SETTING NAN VALUES");
418                                 rocketPanel.setCPAOA(Double.NaN);
419                                 rocketPanel.setCPTheta(Double.NaN);
420                                 rocketPanel.setCPMach(Double.NaN);
421                                 rocketPanel.setCPRoll(Double.NaN);
422                                 singletonDialog = null;
423                         }
424                 });
425                 
426                 //// Reference length:
427                 panel.add(new StyledLabel(trans.get("componentanalysisdlg.lbl.reflenght"), -1),
428                                 "span, split, gapleft para, gapright rel");
429                 DoubleModel dm = new DoubleModel(conditions, "RefLength", UnitGroup.UNITS_LENGTH);
430                 UnitSelector sel = new UnitSelector(dm, true);
431                 sel.resizeFont(-1);
432                 panel.add(sel, "gapright para");
433                 
434                 //// Reference area: 
435                 panel.add(new StyledLabel(trans.get("componentanalysisdlg.lbl.refarea"), -1), "gapright rel");
436                 dm = new DoubleModel(conditions, "RefArea", UnitGroup.UNITS_AREA);
437                 sel = new UnitSelector(dm, true);
438                 sel.resizeFont(-1);
439                 panel.add(sel, "wrap");
440                 
441
442
443                 // Buttons
444                 JButton button;
445                 
446                 // TODO: LOW: printing
447                 //              button = new JButton("Print");
448                 //              button.addActionListener(new ActionListener() {
449                 //                      public void actionPerformed(ActionEvent e) {
450                 //                              try {
451                 //                                      table.print();
452                 //                              } catch (PrinterException e1) {
453                 //                                      JOptionPane.showMessageDialog(ComponentAnalysisDialog.this, 
454                 //                                                      "An error occurred while printing.", "Print error",
455                 //                                                      JOptionPane.ERROR_MESSAGE);
456                 //                              }
457                 //                      }
458                 //              });
459                 //              panel.add(button,"tag ok");
460                 
461                 //button = new JButton("Close");
462                 //Close button
463                 button = new JButton(trans.get("dlg.but.close"));
464                 button.addActionListener(new ActionListener() {
465                         public void actionPerformed(ActionEvent e) {
466                                 ComponentAnalysisDialog.this.dispose();
467                         }
468                 });
469                 panel.add(button, "span, split, tag cancel");
470                 
471
472                 this.setLocationByPlatform(true);
473                 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
474                 pack();
475                 
476                 GUIUtil.setDisposableDialogOptions(this, null);
477         }
478         
479         
480
481         /**
482          * Updates the data in the table and fires a table data change event.
483          */
484         @Override
485         public void stateChanged(ChangeEvent e) {
486                 AerodynamicForces forces;
487                 WarningSet set = new WarningSet();
488                 conditions.setAOA(aoa.getValue());
489                 conditions.setTheta(theta.getValue());
490                 conditions.setMach(mach.getValue());
491                 conditions.setRollRate(roll.getValue());
492                 conditions.setReference(configuration);
493                 
494                 if (worstToggle.isSelected()) {
495                         aerodynamicCalculator.getWorstCP(configuration, conditions, null);
496                         if (!MathUtil.equals(conditions.getTheta(), theta.getValue())) {
497                                 fakeChange = true;
498                                 theta.setValue(conditions.getTheta()); // Fires a stateChanged event
499                                 fakeChange = false;
500                                 return;
501                         }
502                 }
503                 
504                 Map<RocketComponent, AerodynamicForces> aeroData =
505                                 aerodynamicCalculator.getForceAnalysis(configuration, conditions, set);
506                 Map<RocketComponent, Coordinate> massData =
507                                 massCalculator.getCGAnalysis(configuration, MassCalcType.LAUNCH_MASS);
508                 
509
510                 cpData.clear();
511                 cgData.clear();
512                 dragData.clear();
513                 rollData.clear();
514                 for (RocketComponent c : configuration) {
515                         forces = aeroData.get(c);
516                         Coordinate cg = massData.get(c);
517                         
518                         if (forces == null)
519                                 continue;
520                         if (forces.getCP() != null) {
521                                 cpData.add(forces);
522                                 cgData.add(cg);
523                         }
524                         if (!Double.isNaN(forces.getCD())) {
525                                 dragData.add(forces);
526                         }
527                         if (c instanceof FinSet) {
528                                 rollData.add(forces);
529                         }
530                 }
531                 forces = aeroData.get(configuration.getRocket());
532                 if (forces != null) {
533                         cpData.add(forces);
534                         cgData.add(massData.get(configuration.getRocket()));
535                         dragData.add(forces);
536                         rollData.add(forces);
537                         totalCD = forces.getCD();
538                 } else {
539                         totalCD = 0;
540                 }
541                 
542                 // Set warnings
543                 if (set.isEmpty()) {
544                         warningList.setListData(new String[] {
545                                         "<html><i><font color=\"gray\">No warnings.</font></i>"
546                         });
547                 } else {
548                         warningList.setListData(new Vector<Warning>(set));
549                 }
550                 
551                 cpTableModel.fireTableDataChanged();
552                 dragTableModel.fireTableDataChanged();
553                 rollTableModel.fireTableDataChanged();
554         }
555         
556         
557         private class CustomCellRenderer extends JLabel implements TableCellRenderer {
558                 private final Font normalFont;
559                 private final Font boldFont;
560                 
561                 public CustomCellRenderer() {
562                         super();
563                         normalFont = getFont();
564                         boldFont = normalFont.deriveFont(Font.BOLD);
565                 }
566                 
567                 @Override
568                 public Component getTableCellRendererComponent(JTable table, Object value,
569                                 boolean isSelected, boolean hasFocus, int row, int column) {
570                         
571                         this.setText(value.toString());
572                         
573                         if ((row < 0) || (row >= cpData.size()))
574                                 return this;
575                         
576                         if (cpData.get(row).getComponent() instanceof Rocket) {
577                                 this.setFont(boldFont);
578                         } else {
579                                 this.setFont(normalFont);
580                         }
581                         return this;
582                 }
583         }
584         
585         
586
587         private class DragCellRenderer extends JLabel implements TableCellRenderer {
588                 private final Font normalFont;
589                 private final Font boldFont;
590                 
591                 
592                 public DragCellRenderer(Color baseColor) {
593                         super();
594                         normalFont = getFont();
595                         boldFont = normalFont.deriveFont(Font.BOLD);
596                 }
597                 
598                 @Override
599                 public Component getTableCellRendererComponent(JTable table, Object value,
600                                 boolean isSelected, boolean hasFocus, int row, int column) {
601                         
602                         if (value instanceof Double) {
603                                 
604                                 // A drag coefficient
605                                 double cd = (Double) value;
606                                 this.setText(String.format("%.2f (%.0f%%)", cd, 100 * cd / totalCD));
607                                 
608                                 float r = (float) (cd / 1.5);
609                                 
610                                 float hue = MathUtil.clamp(0.3333f * (1 - 2.0f * r), 0, 0.3333f);
611                                 float sat = MathUtil.clamp(0.8f * r + 0.1f * (1 - r), 0, 1);
612                                 float val = 1.0f;
613                                 
614                                 this.setBackground(Color.getHSBColor(hue, sat, val));
615                                 this.setOpaque(true);
616                                 this.setHorizontalAlignment(SwingConstants.CENTER);
617                                 
618                         } else {
619                                 
620                                 // Other
621                                 this.setText(value.toString());
622                                 this.setOpaque(false);
623                                 this.setHorizontalAlignment(SwingConstants.LEFT);
624                                 
625                         }
626                         
627                         if ((row < 0) || (row >= dragData.size()))
628                                 return this;
629                         
630                         if ((dragData.get(row).getComponent() instanceof Rocket) || (column == 4)) {
631                                 this.setFont(boldFont);
632                         } else {
633                                 this.setFont(normalFont);
634                         }
635                         return this;
636                 }
637         }
638         
639         
640         /////////  Singleton implementation
641         
642         public static void showDialog(RocketPanel rocketpanel) {
643                 if (singletonDialog != null)
644                         singletonDialog.dispose();
645                 singletonDialog = new ComponentAnalysisDialog(rocketpanel);
646                 singletonDialog.setVisible(true);
647         }
648         
649         public static void hideDialog() {
650                 if (singletonDialog != null)
651                         singletonDialog.dispose();
652         }
653         
654 }