Search in sources :

Example 51 with Mirror

use of org.concord.energy3d.model.Mirror in project energy3d by concord-consortium.

the class PopupMenuForHeliostat method getPopupMenu.

static JPopupMenu getPopupMenu() {
    if (popupMenuForHeliostat == null) {
        final JCheckBoxMenuItem cbmiDisableEditPoint = new JCheckBoxMenuItem("Disable Edit Point");
        cbmiDisableEditPoint.addItemListener(new ItemListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void itemStateChanged(final ItemEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final boolean disabled = cbmiDisableEditPoint.isSelected();
                final Mirror m = (Mirror) selectedPart;
                final String partInfo = m.toString().substring(0, m.toString().indexOf(')') + 1);
                final JPanel gui = new JPanel(new BorderLayout(0, 20));
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.SOUTH);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final String title = "<html>" + (disabled ? "Disable" : "Enable") + " edit point for " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>Disable the edit point of a heliostat prevents it from<br>being unintentionally moved.<hr></html>";
                final Object[] options = new Object[] { "OK", "Cancel" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[0]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), (disabled ? "Disable" : "Enable") + " Edit Point");
                dialog.setVisible(true);
                if (optionPane.getValue() == options[0]) {
                    if (rb1.isSelected()) {
                        final LockEditPointsCommand c = new LockEditPointsCommand(m);
                        m.setLockEdit(disabled);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                        selectedScopeIndex = 0;
                    } else if (rb2.isSelected()) {
                        final Foundation foundation = m.getTopContainer();
                        final LockEditPointsOnFoundationCommand c = new LockEditPointsOnFoundationCommand(foundation, m.getClass());
                        foundation.setLockEditForClass(disabled, m.getClass());
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                        selectedScopeIndex = 1;
                    } else if (rb3.isSelected()) {
                        final LockEditPointsForClassCommand c = new LockEditPointsForClassCommand(m);
                        Scene.getInstance().setLockEditForClass(disabled, m.getClass());
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                        selectedScopeIndex = 2;
                    }
                    SceneManager.getInstance().refresh();
                    Scene.getInstance().setEdited(true);
                }
            }
        });
        final JCheckBoxMenuItem cbmiDrawSunBeam = new JCheckBoxMenuItem("Draw Sun Beam");
        cbmiDrawSunBeam.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final Mirror m = (Mirror) selectedPart;
                final ShowSunBeamCommand c = new ShowSunBeamCommand(m);
                m.setSunBeamVisible(cbmiDrawSunBeam.isSelected());
                m.draw();
                SceneManager.getInstance().refresh();
                SceneManager.getInstance().getUndoManager().addEdit(c);
                Scene.getInstance().setEdited(true);
            }
        });
        final JMenuItem miSetHeliostat = new JMenuItem("Set Target Tower...");
        miSetHeliostat.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final Mirror m = (Mirror) selectedPart;
                final String partInfo = m.toString().substring(0, m.toString().indexOf(')') + 1);
                final JPanel gui = new JPanel(new BorderLayout(0, 20));
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.SOUTH);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final List<Foundation> foundations = Scene.getInstance().getAllFoundations();
                final JComboBox<String> comboBox = new JComboBox<String>();
                comboBox.addItemListener(new ItemListener() {

                    @Override
                    public void itemStateChanged(final ItemEvent e) {
                    }
                });
                comboBox.addItem("None");
                for (final Foundation x : foundations) {
                    if (!x.getChildren().isEmpty()) {
                        comboBox.addItem(x.getId() + "");
                    }
                }
                if (m.getReceiver() != null) {
                    comboBox.setSelectedItem(m.getReceiver().getId() + "");
                }
                gui.add(comboBox, BorderLayout.CENTER);
                final String title = "<html>Select the ID of the foundation<br>of the target tower for " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>The sunlight reflected by the mirror(s) of this heliostat will<br>focus on the top of the target tower.<hr></html>";
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Heliostat Target");
                while (true) {
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        Foundation target = null;
                        if (comboBox.getSelectedIndex() > 0) {
                            boolean ok = true;
                            int id = -1;
                            try {
                                id = Integer.parseInt((String) comboBox.getSelectedItem());
                            } catch (final NumberFormatException exception) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), comboBox.getSelectedItem() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                                ok = false;
                            }
                            if (ok) {
                                final HousePart p = Scene.getInstance().getPart(id);
                                if (p instanceof Foundation) {
                                    target = (Foundation) p;
                                } else {
                                    JOptionPane.showMessageDialog(MainFrame.getInstance(), "ID must be that of a foundation.", "ID Error", JOptionPane.ERROR_MESSAGE);
                                }
                            }
                        }
                        boolean changed = target != m.getReceiver();
                        if (rb1.isSelected()) {
                            if (changed) {
                                final Foundation oldTarget = m.getReceiver();
                                final ChangeHeliostatTargetCommand c = new ChangeHeliostatTargetCommand(m);
                                m.setReceiver(target);
                                m.draw();
                                if (oldTarget != null) {
                                    oldTarget.drawSolarReceiver();
                                }
                                SceneManager.getInstance().refresh();
                                SceneManager.getInstance().getUndoManager().addEdit(c);
                            }
                            selectedScopeIndex = 0;
                        } else if (rb2.isSelected()) {
                            final Foundation foundation = m.getTopContainer();
                            if (!changed) {
                                for (final Mirror x : foundation.getHeliostats()) {
                                    if (target != x.getReceiver()) {
                                        changed = true;
                                        break;
                                    }
                                }
                            }
                            if (changed) {
                                final ChangeFoundationHeliostatTargetCommand c = new ChangeFoundationHeliostatTargetCommand(foundation);
                                foundation.setTargetForHeliostats(target);
                                SceneManager.getInstance().getUndoManager().addEdit(c);
                            }
                            selectedScopeIndex = 1;
                        } else if (rb3.isSelected()) {
                            if (!changed) {
                                for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                    if (target != x.getReceiver()) {
                                        changed = true;
                                        break;
                                    }
                                }
                            }
                            if (changed) {
                                final ChangeTargetForAllHeliostatsCommand c = new ChangeTargetForAllHeliostatsCommand();
                                Scene.getInstance().setTargetForAllHeliostats(target);
                                SceneManager.getInstance().getUndoManager().addEdit(c);
                            }
                            selectedScopeIndex = 2;
                        }
                        if (changed) {
                            if (target != null) {
                                target.drawSolarReceiver();
                            }
                            updateAfterEdit();
                        }
                        if (choice == options[0]) {
                            break;
                        }
                    }
                }
            }
        });
        final JMenuItem miZenith = new JMenuItem("Tilt Angle...");
        miZenith.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final Mirror m = (Mirror) selectedPart;
                final String partInfo = m.toString().substring(0, m.toString().indexOf(')') + 1);
                final String title = "<html>Tilt Angle of " + partInfo + " (&deg;)</html>";
                final String footnote = "<html><hr><font size=2>The tilt angle of the mirror of a heliostat is the angle between its surface and the base surface.<br>The tilt angle must be between -90&deg; and 90&deg;.<hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(m.getTiltAngle()));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Heliostat Mirror Tilt Angle");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (val < -90 || val > 90) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "The tilt angle must be between -90 and 90 degrees.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                if (Util.isZero(val - 90)) {
                                    val = 89.999;
                                } else if (Util.isZero(val + 90)) {
                                    val = -89.999;
                                }
                                boolean changed = Math.abs(val - m.getTiltAngle()) > 0.000001;
                                if (rb1.isSelected()) {
                                    if (changed) {
                                        final ChangeTiltAngleCommand c = new ChangeTiltAngleCommand(m);
                                        m.setTiltAngle(val);
                                        m.draw();
                                        SceneManager.getInstance().refresh();
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 0;
                                } else if (rb2.isSelected()) {
                                    final Foundation foundation = m.getTopContainer();
                                    if (!changed) {
                                        for (final Mirror x : foundation.getHeliostats()) {
                                            if (Math.abs(val - x.getTiltAngle()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeFoundationHeliostatTiltAngleCommand c = new ChangeFoundationHeliostatTiltAngleCommand(foundation);
                                        foundation.setTiltAngleForHeliostats(val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 1;
                                } else if (rb3.isSelected()) {
                                    if (!changed) {
                                        for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                            if (Math.abs(val - x.getTiltAngle()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeTiltAngleForAllHeliostatsCommand c = new ChangeTiltAngleForAllHeliostatsCommand();
                                        Scene.getInstance().setTiltAngleForAllHeliostats(val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 2;
                                }
                                if (changed) {
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        final JMenuItem miAzimuth = new JMenuItem("Azimuth...");
        miAzimuth.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Mirror mirror = (Mirror) selectedPart;
                final Foundation foundation = mirror.getTopContainer();
                final String title = "<html>Azimuth Angle (&deg;) of " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>The azimuth angle is measured clockwise from the true north.<hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                double a = mirror.getRelativeAzimuth() + foundation.getAzimuth();
                if (a > 360) {
                    a -= 360;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(a));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Heliostat Azimuth");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            a = val - foundation.getAzimuth();
                            if (a < 0) {
                                a += 360;
                            }
                            boolean changed = Math.abs(a - mirror.getRelativeAzimuth()) > 0.000001;
                            if (rb1.isSelected()) {
                                if (changed) {
                                    final ChangeAzimuthCommand c = new ChangeAzimuthCommand(mirror);
                                    mirror.setRelativeAzimuth(a);
                                    mirror.draw();
                                    SceneManager.getInstance().refresh();
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                                selectedScopeIndex = 0;
                            } else if (rb2.isSelected()) {
                                if (!changed) {
                                    for (final Mirror x : foundation.getHeliostats()) {
                                        if (Math.abs(a - x.getRelativeAzimuth()) > 0.000001) {
                                            changed = true;
                                            break;
                                        }
                                    }
                                }
                                if (changed) {
                                    final ChangeFoundationHeliostatAzimuthCommand c = new ChangeFoundationHeliostatAzimuthCommand(foundation);
                                    foundation.setAzimuthForHeliostats(a);
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                                selectedScopeIndex = 1;
                            } else if (rb3.isSelected()) {
                                if (!changed) {
                                    for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                        if (Math.abs(a - x.getRelativeAzimuth()) > 0.000001) {
                                            changed = true;
                                            break;
                                        }
                                    }
                                }
                                if (changed) {
                                    final ChangeAzimuthForAllHeliostatsCommand c = new ChangeAzimuthForAllHeliostatsCommand();
                                    Scene.getInstance().setAzimuthForAllHeliostats(a);
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                                selectedScopeIndex = 2;
                            }
                            if (changed) {
                                updateAfterEdit();
                            }
                            if (choice == options[0]) {
                                break;
                            }
                        }
                    }
                }
            }
        });
        final JMenuItem miSize = new JMenuItem("Size...");
        miSize.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final Mirror m = (Mirror) selectedPart;
                final Foundation foundation = m.getTopContainer();
                final String partInfo = m.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel inputPanel = new JPanel(new GridLayout(2, 2, 5, 5));
                gui.add(inputPanel, BorderLayout.CENTER);
                inputPanel.add(new JLabel("Width: "));
                final JTextField widthField = new JTextField(threeDecimalsFormat.format(m.getMirrorWidth()));
                inputPanel.add(widthField);
                inputPanel.add(new JLabel("Length: "));
                final JTextField heightField = new JTextField(threeDecimalsFormat.format(m.getMirrorHeight()));
                inputPanel.add(heightField);
                inputPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
                final JPanel scopePanel = new JPanel();
                scopePanel.setLayout(new BoxLayout(scopePanel, BoxLayout.Y_AXIS));
                scopePanel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                scopePanel.add(rb1);
                scopePanel.add(rb2);
                scopePanel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                gui.add(scopePanel, BorderLayout.NORTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { "Set size for " + partInfo, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Heliostat Size");
                while (true) {
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double w = 0, h = 0;
                        boolean ok = true;
                        try {
                            w = Double.parseDouble(widthField.getText());
                            h = Double.parseDouble(heightField.getText());
                        } catch (final NumberFormatException x) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), "Invalid input!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (w < 1 || w > 50) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "Width must be between 1 and 50 m.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else if (h < 1 || h > 50) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "Height must be between 1 and 50 m.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                boolean changed = Math.abs(w - m.getMirrorWidth()) > 0.000001 || Math.abs(h - m.getMirrorHeight()) > 0.000001;
                                if (rb1.isSelected()) {
                                    if (changed) {
                                        final SetPartSizeCommand c = new SetPartSizeCommand(m);
                                        m.setMirrorWidth(w);
                                        m.setMirrorHeight(h);
                                        m.draw();
                                        SceneManager.getInstance().refresh();
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 0;
                                } else if (rb2.isSelected()) {
                                    if (!changed) {
                                        for (final Mirror x : foundation.getHeliostats()) {
                                            if (Math.abs(w - x.getMirrorWidth()) > 0.000001 || Math.abs(h - x.getMirrorHeight()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final SetSizeForHeliostatsOnFoundationCommand c = new SetSizeForHeliostatsOnFoundationCommand(foundation);
                                        foundation.setSizeForHeliostats(w, h);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 1;
                                } else if (rb3.isSelected()) {
                                    if (!changed) {
                                        for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                            if (Math.abs(w - x.getMirrorWidth()) > 0.000001 || Math.abs(h - x.getMirrorHeight()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final SetSizeForAllHeliostatsCommand c = new SetSizeForAllHeliostatsCommand();
                                        Scene.getInstance().setSizeForAllHeliostats(w, h);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 2;
                                }
                                if (changed) {
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        final JMenuItem miBaseHeight = new JMenuItem("Base Height...");
        miBaseHeight.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Mirror m = (Mirror) selectedPart;
                final Foundation foundation = m.getTopContainer();
                final String title = "<html>Base Height (m) of " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(m.getBaseHeight() * Scene.getInstance().getAnnotationScale()));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Heliostat Base Height");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText()) / Scene.getInstance().getAnnotationScale();
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            boolean changed = Math.abs(val - m.getBaseHeight()) > 0.000001;
                            if (rb1.isSelected()) {
                                if (changed) {
                                    final ChangeBaseHeightCommand c = new ChangeBaseHeightCommand(m);
                                    m.setBaseHeight(val);
                                    m.draw();
                                    SceneManager.getInstance().refresh();
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                                selectedScopeIndex = 0;
                            } else if (rb2.isSelected()) {
                                if (!changed) {
                                    for (final Mirror x : foundation.getHeliostats()) {
                                        if (Math.abs(val - x.getBaseHeight()) > 0.000001) {
                                            changed = true;
                                            break;
                                        }
                                    }
                                }
                                if (changed) {
                                    final ChangeFoundationSolarCollectorBaseHeightCommand c = new ChangeFoundationSolarCollectorBaseHeightCommand(foundation, m.getClass());
                                    foundation.setBaseHeightForHeliostats(val);
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                                selectedScopeIndex = 1;
                            } else if (rb3.isSelected()) {
                                if (!changed) {
                                    for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                        if (Math.abs(val - x.getBaseHeight()) > 0.000001) {
                                            changed = true;
                                            break;
                                        }
                                    }
                                }
                                if (changed) {
                                    final ChangeBaseHeightForAllSolarCollectorsCommand c = new ChangeBaseHeightForAllSolarCollectorsCommand(m.getClass());
                                    Scene.getInstance().setBaseHeightForAllHeliostats(val);
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                                selectedScopeIndex = 2;
                            }
                            if (changed) {
                                updateAfterEdit();
                            }
                            if (choice == options[0]) {
                                break;
                            }
                        }
                    }
                }
            }
        });
        final JMenu labelMenu = new JMenu("Label");
        final JCheckBoxMenuItem miLabelNone = new JCheckBoxMenuItem("None", true);
        miLabelNone.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                if (miLabelNone.isSelected()) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Mirror) {
                        final Mirror m = (Mirror) selectedPart;
                        final SetHeliostatLabelCommand c = new SetHeliostatLabelCommand(m);
                        m.clearLabels();
                        m.draw();
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().refresh();
                    }
                }
            }
        });
        labelMenu.add(miLabelNone);
        final JCheckBoxMenuItem miLabelCustom = new JCheckBoxMenuItem("Custom");
        miLabelCustom.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Mirror) {
                    final Mirror m = (Mirror) selectedPart;
                    final SetHeliostatLabelCommand c = new SetHeliostatLabelCommand(m);
                    m.setLabelCustom(miLabelCustom.isSelected());
                    if (m.getLabelCustom()) {
                        m.setLabelCustomText(JOptionPane.showInputDialog(MainFrame.getInstance(), "Custom Text", m.getLabelCustomText()));
                    }
                    m.draw();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                    Scene.getInstance().setEdited(true);
                    SceneManager.getInstance().refresh();
                }
            }
        });
        labelMenu.add(miLabelCustom);
        final JCheckBoxMenuItem miLabelId = new JCheckBoxMenuItem("ID");
        miLabelId.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Mirror) {
                    final Mirror m = (Mirror) selectedPart;
                    final SetHeliostatLabelCommand c = new SetHeliostatLabelCommand(m);
                    m.setLabelId(miLabelId.isSelected());
                    m.draw();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                    Scene.getInstance().setEdited(true);
                    SceneManager.getInstance().refresh();
                }
            }
        });
        labelMenu.add(miLabelId);
        final JCheckBoxMenuItem miLabelEnergyOutput = new JCheckBoxMenuItem("Energy Output");
        miLabelEnergyOutput.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Mirror) {
                    final Mirror m = (Mirror) selectedPart;
                    final SetHeliostatLabelCommand c = new SetHeliostatLabelCommand(m);
                    m.setLabelEnergyOutput(miLabelEnergyOutput.isSelected());
                    m.draw();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                    Scene.getInstance().setEdited(true);
                    SceneManager.getInstance().refresh();
                }
            }
        });
        labelMenu.add(miLabelEnergyOutput);
        final JMenu textureMenu = new JMenu("Texture");
        final ButtonGroup textureButtonGroup = new ButtonGroup();
        final JRadioButtonMenuItem texture1MenuItem = new JRadioButtonMenuItem("Whole Mirror");
        texture1MenuItem.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final ChangeHeliostatTextureCommand c = new ChangeHeliostatTextureCommand();
                    Scene.getInstance().setHeliostatTextureType(Mirror.TEXTURE_ONE_MIRROR);
                    Scene.getInstance().setEdited(true);
                    if (MainPanel.getInstance().getEnergyButton().isSelected()) {
                        MainPanel.getInstance().getEnergyButton().setSelected(false);
                    }
                    Scene.getInstance().redrawAll();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                }
            }
        });
        textureButtonGroup.add(texture1MenuItem);
        textureMenu.add(texture1MenuItem);
        final JRadioButtonMenuItem texture2MenuItem = new JRadioButtonMenuItem("2 \u00D7 1 Mirrors");
        texture2MenuItem.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final ChangeHeliostatTextureCommand c = new ChangeHeliostatTextureCommand();
                    Scene.getInstance().setHeliostatTextureType(Mirror.TEXTURE_2X1_MIRRORS);
                    Scene.getInstance().setEdited(true);
                    if (MainPanel.getInstance().getEnergyButton().isSelected()) {
                        MainPanel.getInstance().getEnergyButton().setSelected(false);
                    }
                    Scene.getInstance().redrawAll();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                }
            }
        });
        textureButtonGroup.add(texture2MenuItem);
        textureMenu.add(texture2MenuItem);
        final JRadioButtonMenuItem texture3MenuItem = new JRadioButtonMenuItem("1 \u00D7 2 Mirrors");
        texture3MenuItem.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final ChangeHeliostatTextureCommand c = new ChangeHeliostatTextureCommand();
                    Scene.getInstance().setHeliostatTextureType(Mirror.TEXTURE_1X2_MIRRORS);
                    Scene.getInstance().setEdited(true);
                    if (MainPanel.getInstance().getEnergyButton().isSelected()) {
                        MainPanel.getInstance().getEnergyButton().setSelected(false);
                    }
                    Scene.getInstance().redrawAll();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                }
            }
        });
        textureButtonGroup.add(texture3MenuItem);
        textureMenu.add(texture3MenuItem);
        final JRadioButtonMenuItem texture4MenuItem = new JRadioButtonMenuItem("7 \u00D7 5 Mirrors");
        texture4MenuItem.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final ChangeHeliostatTextureCommand c = new ChangeHeliostatTextureCommand();
                    Scene.getInstance().setHeliostatTextureType(Mirror.TEXTURE_7X5_MIRRORS);
                    Scene.getInstance().setEdited(true);
                    if (MainPanel.getInstance().getEnergyButton().isSelected()) {
                        MainPanel.getInstance().getEnergyButton().setSelected(false);
                    }
                    Scene.getInstance().redrawAll();
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                }
            }
        });
        textureButtonGroup.add(texture4MenuItem);
        textureMenu.add(texture4MenuItem);
        textureMenu.addMenuListener(new MenuListener() {

            @Override
            public void menuCanceled(final MenuEvent e) {
            }

            @Override
            public void menuDeselected(final MenuEvent e) {
                SceneManager.getInstance().refresh();
            }

            @Override
            public void menuSelected(final MenuEvent e) {
                switch(Scene.getInstance().getHeliostatTextureType()) {
                    default:
                        Util.selectSilently(texture1MenuItem, true);
                        break;
                    case Mirror.TEXTURE_2X1_MIRRORS:
                        Util.selectSilently(texture2MenuItem, true);
                        break;
                    case Mirror.TEXTURE_1X2_MIRRORS:
                        Util.selectSilently(texture3MenuItem, true);
                        break;
                    case Mirror.TEXTURE_7X5_MIRRORS:
                        Util.selectSilently(texture4MenuItem, true);
                        break;
                }
            }
        });
        popupMenuForHeliostat = createPopupMenu(true, true, new Runnable() {

            @Override
            public void run() {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final Mirror m = (Mirror) selectedPart;
                if (m.getReceiver() == null) {
                    miZenith.setEnabled(true);
                    miAzimuth.setEnabled(true);
                } else {
                    miZenith.setEnabled(false);
                    miAzimuth.setEnabled(false);
                }
                Util.selectSilently(cbmiDisableEditPoint, m.getLockEdit());
                Util.selectSilently(cbmiDrawSunBeam, m.isSunBeamVisible());
                Util.selectSilently(miLabelNone, !m.isLabelVisible());
                Util.selectSilently(miLabelCustom, m.getLabelCustom());
                Util.selectSilently(miLabelId, m.getLabelId());
                Util.selectSilently(miLabelEnergyOutput, m.getLabelEnergyOutput());
            }
        });
        final JMenuItem miReflectance = new JMenuItem("Reflectance...");
        miReflectance.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Mirror m = (Mirror) selectedPart;
                final String title = "<html>Reflectance (%) of " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>Reflectance can be affected by pollen and dust.<hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(m.getReflectance() * 100));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Heliostat Mirror Reflectance");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (val < 50 || val > 99) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "Heliostat mirror reflectance must be between 50% and 99%.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                boolean changed = Math.abs(val * 0.01 - m.getReflectance()) > 0.000001;
                                if (rb1.isSelected()) {
                                    if (changed) {
                                        final ChangeSolarReflectorReflectanceCommand c = new ChangeSolarReflectorReflectanceCommand(m);
                                        m.setReflectance(val * 0.01);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 0;
                                } else if (rb2.isSelected()) {
                                    final Foundation foundation = m.getTopContainer();
                                    if (!changed) {
                                        for (final Mirror x : foundation.getHeliostats()) {
                                            if (Math.abs(val * 0.01 - x.getReflectance()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeFoundationSolarReflectorReflectanceCommand c = new ChangeFoundationSolarReflectorReflectanceCommand(foundation, m.getClass());
                                        foundation.setReflectanceForHeliostatMirrors(val * 0.01);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 1;
                                } else if (rb3.isSelected()) {
                                    if (!changed) {
                                        for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                            if (Math.abs(val * 0.01 - x.getReflectance()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeReflectanceForAllSolarReflectorsCommand c = new ChangeReflectanceForAllSolarReflectorsCommand(m.getClass());
                                        Scene.getInstance().setReflectanceForAllSolarReflectors(val * 0.01, m.getClass());
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 2;
                                }
                                if (changed) {
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        final JMenuItem miApertureRatio = new JMenuItem("Aperture Ratio...");
        miApertureRatio.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Mirror m = (Mirror) selectedPart;
                final String title = "<html>Aperture percentage of " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>The percentage of the effective area for reflection<br>after deducting the area of gaps, frames, etc.<hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Heliostat", true);
                final JRadioButton rb2 = new JRadioButton("All Heliostats on this Foundation");
                final JRadioButton rb3 = new JRadioButton("All Heliostats");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(m.getOpticalEfficiency() * 100));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Aperture Percentage of Heliostat Surface");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (val < 70 || val > 100) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "Heliostat aperature percentage must be between 70% and 100%.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                boolean changed = Math.abs(val * 0.01 - m.getOpticalEfficiency()) > 0.000001;
                                if (rb1.isSelected()) {
                                    if (changed) {
                                        final ChangeSolarReflectorOpticalEfficiencyCommand c = new ChangeSolarReflectorOpticalEfficiencyCommand(m);
                                        m.setOpticalEfficiency(val * 0.01);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 0;
                                } else if (rb2.isSelected()) {
                                    final Foundation foundation = m.getTopContainer();
                                    if (!changed) {
                                        for (final Mirror x : foundation.getHeliostats()) {
                                            if (Math.abs(val * 0.01 - x.getOpticalEfficiency()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeFoundationSolarReflectorOpticalEfficiencyCommand c = new ChangeFoundationSolarReflectorOpticalEfficiencyCommand(foundation, m.getClass());
                                        foundation.setOpticalEfficiencyForSolarReflectors(val * 0.01, m.getClass());
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 1;
                                } else if (rb3.isSelected()) {
                                    if (!changed) {
                                        for (final Mirror x : Scene.getInstance().getAllHeliostats()) {
                                            if (Math.abs(val * 0.01 - x.getOpticalEfficiency()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeOpticalEfficiencyForAllSolarReflectorsCommand c = new ChangeOpticalEfficiencyForAllSolarReflectorsCommand(m.getClass());
                                        Scene.getInstance().setOpticalEfficiencyForAllSolarReflectors(val * 0.01, m.getClass());
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 2;
                                }
                                if (changed) {
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        final JMenuItem miConversionEfficiency = new JMenuItem("Central Receiver Conversion Efficiency...");
        miConversionEfficiency.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Mirror)) {
                    return;
                }
                final Mirror m = (Mirror) selectedPart;
                final Foundation receiver = m.getReceiver();
                if (receiver == null) {
                    JOptionPane.showMessageDialog(MainFrame.getInstance(), "This heliostat does not link to a receiver.", "No Receiver", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final String title = "<html>Light-electricity conversion efficiency (%) of " + partInfo + "'s central receiver</html>";
                final String footnote = "<html><hr><font size=2><hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(receiver.getSolarReceiverEfficiency() * 100));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Receiver Conversion Efficiency");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (val < 5 || val > 50) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "Light-electricity conversion efficiency must be between 5% and 50%.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                final boolean changed = Math.abs(val * 0.01 - receiver.getSolarReceiverEfficiency()) > 0.000001;
                                if (changed) {
                                    final ChangeSolarReceiverEfficiencyCommand c = new ChangeSolarReceiverEfficiencyCommand(receiver);
                                    receiver.setSolarReceiverEfficiency(val * 0.01);
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        popupMenuForHeliostat.addSeparator();
        popupMenuForHeliostat.add(miSetHeliostat);
        popupMenuForHeliostat.add(miZenith);
        popupMenuForHeliostat.add(miAzimuth);
        popupMenuForHeliostat.add(miSize);
        popupMenuForHeliostat.add(miBaseHeight);
        popupMenuForHeliostat.addSeparator();
        popupMenuForHeliostat.add(miReflectance);
        popupMenuForHeliostat.add(miApertureRatio);
        popupMenuForHeliostat.add(miConversionEfficiency);
        popupMenuForHeliostat.addSeparator();
        popupMenuForHeliostat.add(cbmiDisableEditPoint);
        popupMenuForHeliostat.add(cbmiDrawSunBeam);
        popupMenuForHeliostat.add(labelMenu);
        popupMenuForHeliostat.add(textureMenu);
        popupMenuForHeliostat.addSeparator();
        JMenuItem mi = new JMenuItem("Daily Yield Analysis...");
        mi.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                if (EnergyPanel.getInstance().adjustCellSize()) {
                    return;
                }
                if (SceneManager.getInstance().getSelectedPart() instanceof Mirror) {
                    new HeliostatDailyAnalysis().show();
                }
            }
        });
        popupMenuForHeliostat.add(mi);
        mi = new JMenuItem("Annual Yield Analysis...");
        mi.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                if (EnergyPanel.getInstance().adjustCellSize()) {
                    return;
                }
                if (SceneManager.getInstance().getSelectedPart() instanceof Mirror) {
                    new HeliostatAnnualAnalysis().show();
                }
            }
        });
        popupMenuForHeliostat.add(mi);
    }
    return popupMenuForHeliostat;
}
Also used : JPanel(javax.swing.JPanel) ChangeFoundationHeliostatTiltAngleCommand(org.concord.energy3d.undo.ChangeFoundationHeliostatTiltAngleCommand) ActionEvent(java.awt.event.ActionEvent) SetPartSizeCommand(org.concord.energy3d.undo.SetPartSizeCommand) ChangeFoundationHeliostatAzimuthCommand(org.concord.energy3d.undo.ChangeFoundationHeliostatAzimuthCommand) ChangeSolarReflectorOpticalEfficiencyCommand(org.concord.energy3d.undo.ChangeSolarReflectorOpticalEfficiencyCommand) ChangeBaseHeightForAllSolarCollectorsCommand(org.concord.energy3d.undo.ChangeBaseHeightForAllSolarCollectorsCommand) BorderLayout(java.awt.BorderLayout) ChangeTargetForAllHeliostatsCommand(org.concord.energy3d.undo.ChangeTargetForAllHeliostatsCommand) Foundation(org.concord.energy3d.model.Foundation) LockEditPointsOnFoundationCommand(org.concord.energy3d.undo.LockEditPointsOnFoundationCommand) List(java.util.List) ChangeReflectanceForAllSolarReflectorsCommand(org.concord.energy3d.undo.ChangeReflectanceForAllSolarReflectorsCommand) HousePart(org.concord.energy3d.model.HousePart) HeliostatDailyAnalysis(org.concord.energy3d.simulation.HeliostatDailyAnalysis) JRadioButtonMenuItem(javax.swing.JRadioButtonMenuItem) JOptionPane(javax.swing.JOptionPane) ChangeAzimuthCommand(org.concord.energy3d.undo.ChangeAzimuthCommand) JCheckBoxMenuItem(javax.swing.JCheckBoxMenuItem) ChangeHeliostatTextureCommand(org.concord.energy3d.undo.ChangeHeliostatTextureCommand) ActionListener(java.awt.event.ActionListener) ChangeFoundationSolarCollectorBaseHeightCommand(org.concord.energy3d.undo.ChangeFoundationSolarCollectorBaseHeightCommand) Mirror(org.concord.energy3d.model.Mirror) JDialog(javax.swing.JDialog) ItemEvent(java.awt.event.ItemEvent) HeliostatAnnualAnalysis(org.concord.energy3d.simulation.HeliostatAnnualAnalysis) JRadioButton(javax.swing.JRadioButton) ChangeSolarReflectorReflectanceCommand(org.concord.energy3d.undo.ChangeSolarReflectorReflectanceCommand) MenuListener(javax.swing.event.MenuListener) BoxLayout(javax.swing.BoxLayout) JTextField(javax.swing.JTextField) SetSizeForHeliostatsOnFoundationCommand(org.concord.energy3d.undo.SetSizeForHeliostatsOnFoundationCommand) ChangeHeliostatTargetCommand(org.concord.energy3d.undo.ChangeHeliostatTargetCommand) GridLayout(java.awt.GridLayout) JMenuItem(javax.swing.JMenuItem) SetHeliostatLabelCommand(org.concord.energy3d.undo.SetHeliostatLabelCommand) MenuEvent(javax.swing.event.MenuEvent) LockEditPointsCommand(org.concord.energy3d.undo.LockEditPointsCommand) JComboBox(javax.swing.JComboBox) JLabel(javax.swing.JLabel) ShowSunBeamCommand(org.concord.energy3d.undo.ShowSunBeamCommand) ChangeTiltAngleCommand(org.concord.energy3d.undo.ChangeTiltAngleCommand) ChangeBaseHeightCommand(org.concord.energy3d.undo.ChangeBaseHeightCommand) ChangeOpticalEfficiencyForAllSolarReflectorsCommand(org.concord.energy3d.undo.ChangeOpticalEfficiencyForAllSolarReflectorsCommand) ChangeSolarReceiverEfficiencyCommand(org.concord.energy3d.undo.ChangeSolarReceiverEfficiencyCommand) SetSizeForAllHeliostatsCommand(org.concord.energy3d.undo.SetSizeForAllHeliostatsCommand) LockEditPointsForClassCommand(org.concord.energy3d.undo.LockEditPointsForClassCommand) ChangeFoundationSolarReflectorReflectanceCommand(org.concord.energy3d.undo.ChangeFoundationSolarReflectorReflectanceCommand) ChangeFoundationSolarReflectorOpticalEfficiencyCommand(org.concord.energy3d.undo.ChangeFoundationSolarReflectorOpticalEfficiencyCommand) ButtonGroup(javax.swing.ButtonGroup) ChangeAzimuthForAllHeliostatsCommand(org.concord.energy3d.undo.ChangeAzimuthForAllHeliostatsCommand) ChangeFoundationHeliostatTargetCommand(org.concord.energy3d.undo.ChangeFoundationHeliostatTargetCommand) ItemListener(java.awt.event.ItemListener) JMenu(javax.swing.JMenu) ChangeTiltAngleForAllHeliostatsCommand(org.concord.energy3d.undo.ChangeTiltAngleForAllHeliostatsCommand)

Example 52 with Mirror

use of org.concord.energy3d.model.Mirror in project energy3d by concord-consortium.

the class MainPanel method getRotateButton.

public JButton getRotateButton() {
    if (rotateButton == null) {
        rotateButton = new JButton();
        if (Config.isMac()) {
            // for some reason, the newer version of Mac draws border for JButton (but not JToggleButton)
            rotateButton.setBorderPainted(false);
        }
        rotateButton.addMouseListener(refreshUponMouseExit);
        rotateButton.setIcon(new ImageIcon(getClass().getResource("icons/rotate_cw.png")));
        rotateButton.setToolTipText("<html>Rotate in the clockwise direction (change azimuth).<br>Hold down the Ctrl key and press this button for counter-clockwise rotation.<br>Hold down the Shift key while pressing this button to rotate more slowly.<br>If a component is selected, rotate around its center. Otherwise rotate everything around the origin.</html>");
        rotateButton.setFocusable(false);
        addMouseOverEffect(rotateButton);
        rotateButton.addMouseListener(new MouseAdapter() {

            private volatile boolean mousePressed = false;

            @Override
            public void mousePressed(final MouseEvent e) {
                energyButton.setSelected(false);
                mousePressed = true;
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart == null || selectedPart instanceof Tree || selectedPart instanceof Human) {
                    int count = 0;
                    HousePart hp = null;
                    for (final HousePart x : Scene.getInstance().getParts()) {
                        if (x instanceof Foundation) {
                            count++;
                            hp = x;
                        }
                    }
                    if (count == 1) {
                        // if there is only one building, automatically select it to ensure that we always rotate around its center
                        SceneManager.getInstance().setSelectedPart(hp);
                        SceneManager.getInstance().refresh();
                        EnergyPanel.getInstance().updateProperties();
                    }
                }
                new Thread("Energy3D Continuous Rotation") {

                    private int count;

                    private ChangeAzimuthCommand c;

                    @Override
                    public void run() {
                        final HousePart part = SceneManager.getInstance().getSelectedPart();
                        if (part != null) {
                            c = new ChangeAzimuthCommand(part);
                        }
                        while (mousePressed) {
                            SceneManager.getTaskManager().update(new Callable<Object>() {

                                @Override
                                public Object call() throws Exception {
                                    if (part == null) {
                                        SceneManager.getInstance().rotateAllFoundations(rotationAngle);
                                    } else {
                                        if (part instanceof Foundation) {
                                            SceneManager.getInstance().rotateFoundation(rotationAngle, true);
                                        } else if (part instanceof SolarPanel) {
                                            final SolarPanel solarPanel = (SolarPanel) part;
                                            solarPanel.setRelativeAzimuth(solarPanel.getRelativeAzimuth() + Math.toDegrees(rotationAngle));
                                            solarPanel.draw();
                                        } else if (part instanceof Rack) {
                                            final Rack rack = (Rack) part;
                                            rack.setRelativeAzimuth(rack.getRelativeAzimuth() + Math.toDegrees(rotationAngle));
                                            rack.draw();
                                        } else if (part instanceof Mirror) {
                                            final Mirror mirror = (Mirror) part;
                                            mirror.setRelativeAzimuth(mirror.getRelativeAzimuth() + Math.toDegrees(rotationAngle));
                                            mirror.draw();
                                        }
                                    }
                                    count++;
                                    Scene.getInstance().setEdited(true);
                                    EventQueue.invokeLater(new Runnable() {

                                        @Override
                                        public void run() {
                                            EnergyPanel.getInstance().updateProperties();
                                        }
                                    });
                                    return null;
                                }
                            });
                            final int partCount = Scene.getInstance().getParts().size();
                            try {
                                // give it enough time for the above call to complete (the more parts it has, the more time it needs)
                                Thread.sleep(200 + partCount * 5);
                            } catch (final InterruptedException e) {
                            }
                        }
                        // undo only after the thread ends
                        if (part == null) {
                            SceneManager.getInstance().getUndoManager().addEdit(new RotateBuildingCommand(null, rotationAngle * count));
                        } else {
                            if (part instanceof Foundation) {
                                SceneManager.getInstance().getUndoManager().addEdit(new RotateBuildingCommand((Foundation) part, rotationAngle * count));
                            } else if (part instanceof SolarPanel || part instanceof Rack || part instanceof Mirror) {
                                if (c != null) {
                                    SceneManager.getInstance().getUndoManager().addEdit(c);
                                }
                            }
                        }
                    }
                }.start();
            }

            @Override
            public void mouseReleased(final MouseEvent e) {
                mousePressed = false;
            }
        });
    }
    return rotateButton;
}
Also used : Human(org.concord.energy3d.model.Human) ImageIcon(javax.swing.ImageIcon) RotateBuildingCommand(org.concord.energy3d.undo.RotateBuildingCommand) MouseEvent(java.awt.event.MouseEvent) JButton(javax.swing.JButton) MouseAdapter(java.awt.event.MouseAdapter) ChangeAzimuthCommand(org.concord.energy3d.undo.ChangeAzimuthCommand) BadLocationException(javax.swing.text.BadLocationException) Rack(org.concord.energy3d.model.Rack) SolarPanel(org.concord.energy3d.model.SolarPanel) Tree(org.concord.energy3d.model.Tree) Foundation(org.concord.energy3d.model.Foundation) Mirror(org.concord.energy3d.model.Mirror) HousePart(org.concord.energy3d.model.HousePart)

Example 53 with Mirror

use of org.concord.energy3d.model.Mirror in project energy3d by concord-consortium.

the class CspProjectInfoPanel method update.

void update(final Foundation foundation) {
    final List<ParabolicTrough> troughs = foundation.getParabolicTroughs();
    if (!troughs.isEmpty()) {
        countBar.setValue(troughs.size());
        int totalModules = 0;
        for (final ParabolicTrough t : troughs) {
            totalModules += t.getNumberOfModules();
        }
        moduleCountBar.setValue(totalModules);
        countPanel.setBorder(EnergyPanel.createTitledBorder("Number of parabolic troughs", true));
        double cost = 0;
        double reflectingArea = 0;
        double troughArea = 0;
        final CspCustomPrice price = Scene.getInstance().getCspCustomPrice();
        for (final ParabolicTrough t : troughs) {
            troughArea = t.getTroughLength() * t.getApertureWidth();
            cost += price.getParabolicTroughUnitPrice() * troughArea;
            reflectingArea += troughArea;
        }
        cost += foundation.getArea() * price.getLandUnitPrice() * price.getLifespan();
        costBar.setValue(Math.round(cost));
        final CspDesignSpecs specs = Scene.getInstance().getCspDesignSpecs();
        String t = "Total cost over " + price.getLifespan() + " years";
        if (specs.isBudgetEnabled()) {
            t += " (" + "<$" + specs.getMaximumBudget() + ")";
        }
        costPanel.setBorder(EnergyPanel.createTitledBorder(t, true));
        packingDensityBar.setValue((float) (reflectingArea / foundation.getArea()));
    } else {
        final List<ParabolicDish> dishes = foundation.getParabolicDishes();
        if (!dishes.isEmpty()) {
            countBar.setValue(dishes.size());
            moduleCountBar.setValue(dishes.size());
            countPanel.setBorder(EnergyPanel.createTitledBorder("Number of parabolic dishes", true));
            double cost = 0;
            double reflectingArea = 0;
            double rimArea = 0;
            final CspCustomPrice price = Scene.getInstance().getCspCustomPrice();
            for (final ParabolicDish d : dishes) {
                rimArea = d.getRimRadius() * d.getRimRadius() * Math.PI;
                cost += price.getHeliostatUnitPrice() * rimArea;
                reflectingArea += rimArea;
            }
            cost += foundation.getArea() * price.getLandUnitPrice() * price.getLifespan();
            costBar.setValue(Math.round(cost));
            final CspDesignSpecs specs = Scene.getInstance().getCspDesignSpecs();
            String t = "Total cost over " + price.getLifespan() + " years";
            if (specs.isBudgetEnabled()) {
                t += " (" + "<$" + specs.getMaximumBudget() + ")";
            }
            costPanel.setBorder(EnergyPanel.createTitledBorder(t, true));
            packingDensityBar.setValue((float) (reflectingArea / foundation.getArea()));
        } else {
            final List<FresnelReflector> fresnels = foundation.getFresnelReflectors();
            if (fresnels.isEmpty()) {
                final List<Mirror> mirrors = foundation.getHeliostats();
                countBar.setValue(mirrors.size());
                moduleCountBar.setValue(mirrors.size());
                countPanel.setBorder(EnergyPanel.createTitledBorder("Number of heliostats", true));
                double cost = 0;
                double reflectingArea = 0;
                double mirrorArea = 0;
                final CspCustomPrice price = Scene.getInstance().getCspCustomPrice();
                final ArrayList<Foundation> towers = new ArrayList<Foundation>();
                for (final Mirror m : mirrors) {
                    mirrorArea = m.getMirrorWidth() * m.getMirrorHeight();
                    cost += price.getHeliostatUnitPrice() * mirrorArea;
                    reflectingArea += mirrorArea;
                    if (m.getReceiver() != null) {
                        if (!towers.contains(m.getReceiver())) {
                            towers.add(m.getReceiver());
                        }
                    }
                }
                if (!mirrors.isEmpty()) {
                    cost += foundation.getArea() * price.getLandUnitPrice() * price.getLifespan();
                    if (!towers.isEmpty()) {
                        for (final Foundation tower : towers) {
                            cost += price.getTowerUnitPrice() * tower.getSolarReceiverHeight(0) * Scene.getInstance().getAnnotationScale();
                        }
                    }
                } else {
                    if (foundation.hasSolarReceiver()) {
                        cost += price.getTowerUnitPrice() * foundation.getSolarReceiverHeight(0) * Scene.getInstance().getAnnotationScale();
                    }
                }
                costBar.setValue(Math.round(cost));
                final CspDesignSpecs specs = Scene.getInstance().getCspDesignSpecs();
                String t = "Total cost over " + price.getLifespan() + " years";
                if (specs.isBudgetEnabled()) {
                    t += " (" + "<$" + specs.getMaximumBudget() + ")";
                }
                costPanel.setBorder(EnergyPanel.createTitledBorder(t, true));
                packingDensityBar.setValue((float) (reflectingArea / foundation.getArea()));
            } else {
                countBar.setValue(fresnels.size());
                int totalModules = 0;
                for (final FresnelReflector r : fresnels) {
                    totalModules += r.getNumberOfModules();
                }
                moduleCountBar.setValue(totalModules);
                countPanel.setBorder(EnergyPanel.createTitledBorder("Number of Fresnel reflectors", true));
                double cost = 0;
                double reflectingArea = 0;
                double unitArea = 0;
                final CspCustomPrice price = Scene.getInstance().getCspCustomPrice();
                for (final FresnelReflector r : fresnels) {
                    unitArea = r.getLength() * r.getModuleWidth();
                    cost += price.getFresnelReflectorUnitPrice() * unitArea;
                    reflectingArea += unitArea;
                }
                cost += foundation.getArea() * price.getLandUnitPrice() * price.getLifespan();
                costBar.setValue(Math.round(cost));
                final CspDesignSpecs specs = Scene.getInstance().getCspDesignSpecs();
                String t = "Total cost over " + price.getLifespan() + " years";
                if (specs.isBudgetEnabled()) {
                    t += " (" + "<$" + specs.getMaximumBudget() + ")";
                }
                costPanel.setBorder(EnergyPanel.createTitledBorder(t, true));
                packingDensityBar.setValue((float) (reflectingArea / foundation.getArea()));
            }
        }
    }
}
Also used : ParabolicTrough(org.concord.energy3d.model.ParabolicTrough) FresnelReflector(org.concord.energy3d.model.FresnelReflector) ArrayList(java.util.ArrayList) ParabolicDish(org.concord.energy3d.model.ParabolicDish) CspDesignSpecs(org.concord.energy3d.simulation.CspDesignSpecs) CspCustomPrice(org.concord.energy3d.simulation.CspCustomPrice) Foundation(org.concord.energy3d.model.Foundation) Mirror(org.concord.energy3d.model.Mirror)

Example 54 with Mirror

use of org.concord.energy3d.model.Mirror in project energy3d by concord-consortium.

the class EnergyPanel method updateProperties.

// As this method may be called from a non-Event-Queue thread, updating GUI must be done through invokeLater.
public void updateProperties() {
    // update part properties
    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
    final boolean energyViewShown = MainPanel.getInstance().getEnergyButton().isSelected();
    final double meterToFoot;
    final String lengthUnit;
    switch(Scene.getInstance().getUnit()) {
        case USCustomaryUnits:
            meterToFoot = 3.28084;
            lengthUnit = "ft";
            break;
        default:
            meterToFoot = 1;
            lengthUnit = "m";
    }
    final double scale = Scene.getInstance().getAnnotationScale() * meterToFoot;
    final TitledBorder partPanelBorder = (TitledBorder) partPanel.getBorder();
    if (selectedPart != null) {
        final ReadOnlyVector3 v = selectedPart.getAbsPoint(0);
        if (selectedPart instanceof Tree) {
            final Tree tree = (Tree) selectedPart;
            if (tree.isDrawable()) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Tree (" + tree.getId() + "): " + tree.getTreeName());
                        partProperty1Label.setText("  Spread & Height:");
                        partProperty2Label.setText("  Type:");
                        partProperty3Label.setText("  Position:");
                        final double l = v.length();
                        double a = 90 + Math.toDegrees(Math.asin(-v.getY() / l));
                        if (v.getX() < 0) {
                            a = 360 - a;
                        }
                        if (Util.isZero(a - 360)) {
                            a = 0;
                        }
                        partProperty1TextField.setText(ONE_DECIMAL.format(tree.getWidth() * scale) + lengthUnit + ", " + ONE_DECIMAL.format(tree.getHeight() * scale) + lengthUnit);
                        partProperty2TextField.setText(tree.getTreeName() + " (" + (tree.getTreeType() == Tree.PINE ? "Evergreen" : "Deciduous") + ")");
                        partProperty3TextField.setText("(" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ")" + lengthUnit + " or (" + ONE_DECIMAL.format(l * scale) + lengthUnit + ", " + ONE_DECIMAL.format(a) + "\u00B0)");
                        partProperty1TextField.putClientProperty("tooltip", "The spread and height of the tree");
                        partProperty2TextField.putClientProperty("tooltip", "The type of the tree");
                        partProperty3TextField.putClientProperty("tooltip", "The (x, y) or polar coordinates on the land");
                    }
                });
            }
        } else if (selectedPart instanceof Human) {
            final Human human = (Human) selectedPart;
            if (human.isDrawable()) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Human (" + human.getId() + "): " + human.getHumanName());
                        partProperty1Label.setText("  X:");
                        partProperty2Label.setText("  Y:");
                        partProperty3Label.setText("  Z:");
                        partProperty1TextField.setText(ONE_DECIMAL.format(v.getX() * scale) + lengthUnit);
                        partProperty2TextField.setText(ONE_DECIMAL.format(v.getY() * scale) + lengthUnit);
                        partProperty3TextField.setText(ONE_DECIMAL.format(v.getZ() * scale) + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "X coordinate");
                        partProperty2TextField.putClientProperty("tooltip", "Y coordinate");
                        partProperty3TextField.putClientProperty("tooltip", "Z coordinate");
                    }
                });
            }
        } else if (selectedPart instanceof SolarPanel) {
            final SolarPanel sp = (SolarPanel) selectedPart;
            if (sp.isDrawable()) {
                final Foundation f = sp.getTopContainer();
                if (f != null) {
                    double a = sp.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    final boolean flat = (sp.getContainer() instanceof Roof && Util.isZero(sp.getContainer().getHeight())) || (sp.getContainer() instanceof Foundation);
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            String title = "Solar Panel (" + sp.getId() + "), " + (sp.getModelName() == null ? "" : "Model: " + sp.getModelName());
                            final String trackerName = sp.getTrackerName();
                            if (trackerName != null) {
                                title += ", Tracker: " + trackerName;
                            }
                            partPanelBorder.setTitle(title);
                            partProperty1Label.setText("  Size & Position:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(sp.getPanelWidth() * meterToFoot) + "\u00d7" + TWO_DECIMALS.format(sp.getPanelHeight() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "The length, width, and center coordinates of the solar panel");
                            partProperty2Label.setText("  Angles:");
                            partProperty2TextField.setText(flat ? "tilt: " + ONE_DECIMAL.format(Util.isZero(sp.getTiltAngle()) ? Math.toDegrees(Math.asin(sp.getNormal().getY())) : sp.getTiltAngle()) + "\u00B0, azimuth: " + ONE_DECIMAL.format(az) + "\u00B0" : " --- ");
                            partProperty2TextField.putClientProperty("tooltip", "The angles of the solar panel");
                            final String eff = ONE_DECIMAL.format(sp.getCellEfficiency() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Efficiency & Yield:");
                                partProperty3TextField.setText(eff + ", " + TWO_DECIMALS.format(sp.getSolarPotentialToday()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The solar cell efficiency and daily yield of the solar panel");
                            } else {
                                partProperty3Label.setText("  Efficiency:");
                                partProperty3TextField.setText(eff);
                                partProperty3TextField.putClientProperty("tooltip", "The solar cell efficiency of the solar panel");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof Rack) {
            final Rack rack = (Rack) selectedPart;
            if (rack.isDrawable()) {
                final Foundation f = rack.getTopContainer();
                if (f != null) {
                    double a = rack.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    final int n = rack.isMonolithic() ? rack.getNumberOfSolarPanels() : rack.getChildren().size();
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            String title = "Rack (" + rack.getId() + ")";
                            final SolarPanel s = rack.getSolarPanel();
                            if (s.getModelName() != null) {
                                title += ", Model: " + s.getModelName();
                            }
                            final String trackerName = rack.getTrackerName();
                            if (trackerName != null) {
                                title += ", Tracker: " + trackerName;
                            }
                            partPanelBorder.setTitle(title);
                            partProperty1Label.setText("  Size & Center:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(rack.getRackWidth() * meterToFoot) + "\u00d7" + TWO_DECIMALS.format(rack.getRackHeight() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "The length, width, and center coordinates of the rack");
                            partProperty2Label.setText("  Angles:");
                            partProperty2TextField.setText("tilt: " + ONE_DECIMAL.format(Util.isZero(rack.getTiltAngle()) ? Math.toDegrees(Math.asin(rack.getNormal().getY())) : rack.getTiltAngle()) + "\u00B0, azimuth: " + ONE_DECIMAL.format(az) + "\u00B0");
                            partProperty2TextField.putClientProperty("tooltip", "The angles of the rack");
                            partProperty3Label.setText("  Solar Panels:");
                            final SolarPanel sp = rack.getSolarPanel();
                            final String eff = ONE_DECIMAL.format(sp.getCellEfficiency() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Efficiency & Yield:");
                                partProperty3TextField.setText(eff + ", " + TWO_DECIMALS.format(rack.getSolarPotentialToday()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The solar cell efficiency and daily yield of the solar panel array on the rack");
                            } else {
                                if (rack.isMonolithic()) {
                                    final int[] rnc = rack.getSolarPanelRowAndColumnNumbers();
                                    partProperty3TextField.setText("" + n + " (" + rnc[0] + "\u00D7" + rnc[1] + "), " + s.getPanelWidth() + "\u00D7" + s.getPanelHeight() + lengthUnit + ", " + eff);
                                } else {
                                    partProperty3TextField.setText("" + n);
                                }
                                partProperty3TextField.putClientProperty("tooltip", "Number and type of solar panels on this rack");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof Mirror) {
            final Mirror m = (Mirror) selectedPart;
            if (m.isDrawable()) {
                final Foundation f = m.getTopContainer();
                if (f != null) {
                    double a = m.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    final boolean flat = m.getContainer() instanceof Foundation;
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Heliostat (" + m.getId() + ")");
                            partProperty1Label.setText("  Size & Center:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(m.getMirrorWidth() * meterToFoot) + "\u00d7" + TWO_DECIMALS.format(m.getMirrorHeight() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "The length, width, and center coordinates of the heliostat");
                            partProperty2Label.setText("  Angles:");
                            partProperty2TextField.setText(flat ? "tilt: " + ONE_DECIMAL.format(m.getTiltAngle()) + "\u00B0, azimuth: " + ONE_DECIMAL.format(az) + "\u00B0" : " --- ");
                            partProperty2TextField.putClientProperty("tooltip", "The angles of the heliostat");
                            final Foundation receiver = m.getReceiver();
                            final String s = "R=" + ONE_DECIMAL.format(m.getReflectance() * 100) + "%" + (receiver == null ? "" : ", \u03B7=" + ONE_DECIMAL.format(receiver.getSolarReceiverEfficiency() * 100) + "%");
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(s + ", " + ONE_DECIMAL.format(m.getSolarPotentialToday() * m.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The physical properties and electric yield of this heliostat");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(s);
                                partProperty3TextField.putClientProperty("tooltip", "The physical properties of this heliostat");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof ParabolicTrough) {
            final ParabolicTrough t = (ParabolicTrough) selectedPart;
            if (t.isDrawable()) {
                final Foundation f = t.getTopContainer();
                if (f != null) {
                    double a = t.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    // http://www.powerfromthesun.net/Book/chapter08/chapter08.html
                    final double focalLength = t.getSemilatusRectum() * 0.5;
                    final double d = t.getApertureWidth();
                    final double h = d * d / (16 * focalLength);
                    final double rimAngle = Math.toDegrees(Math.atan(1.0 / (d / (8 * h) - (2 * h) / d)));
                    final double b = 4 * h / d;
                    final double c = Math.sqrt(b * b + 1);
                    final double s = 0.5 * d * c + 2 * focalLength * Math.log(b + c);
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Parabolic Trough (" + t.getId() + ")");
                            partProperty1Label.setText("  Length & Center:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(t.getTroughLength() * meterToFoot) + lengthUnit + ", module:" + TWO_DECIMALS.format(t.getModuleLength() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit + ", azimuth:" + ONE_DECIMAL.format(az) + "\u00B0");
                            partProperty1TextField.putClientProperty("tooltip", "Assembly length, module length, center coordinates, and azimith of the parabolic trough");
                            partProperty2Label.setText("  Parabola Shape:");
                            partProperty2TextField.setText("f=" + ONE_DECIMAL.format(focalLength * meterToFoot) + lengthUnit + ", d=" + ONE_DECIMAL.format(t.getApertureWidth() * meterToFoot) + lengthUnit + ", h=" + ONE_DECIMAL.format(h * meterToFoot) + lengthUnit + ", \u03C6=" + ONE_DECIMAL.format(rimAngle >= 0 ? rimAngle : 180 + rimAngle) + "\u00B0");
                            partProperty2TextField.putClientProperty("tooltip", "Parameters of the parabolic shape");
                            final String str = "R=" + ONE_DECIMAL.format(t.getReflectance() * 100) + "%, s=" + ONE_DECIMAL.format(s * t.getTroughLength() * meterToFoot * meterToFoot) + lengthUnit + "\u00B2, a=" + ONE_DECIMAL.format(d * t.getTroughLength() * meterToFoot * meterToFoot) + lengthUnit + "\u00B2, \u03B1=" + ONE_DECIMAL.format(t.getAbsorptance() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(str + ", " + ONE_DECIMAL.format(t.getSolarPotentialToday() * t.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The properties and yield of this parabolic trough");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(str);
                                partProperty3TextField.putClientProperty("tooltip", "The properties of this parabolic trough");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof ParabolicDish) {
            final ParabolicDish d = (ParabolicDish) selectedPart;
            if (d.isDrawable()) {
                final Foundation f = d.getTopContainer();
                if (f != null) {
                    double a = d.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double focalLength = d.getFocalLength();
                    final double rimRadius = d.getRimRadius();
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Parabolic Dish (" + d.getId() + ")");
                            partProperty1Label.setText("  Size & Center:");
                            partProperty1TextField.setText("Rim radius=" + TWO_DECIMALS.format(rimRadius * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "Rim radius and center coordinates of the parabolic dish");
                            partProperty2Label.setText("  Parabola Shape:");
                            partProperty2TextField.setText("Focal length=" + ONE_DECIMAL.format(focalLength * meterToFoot) + lengthUnit);
                            partProperty2TextField.putClientProperty("tooltip", "Parameters of the parabolic shape");
                            final String str = "R=" + ONE_DECIMAL.format(d.getReflectance() * 100) + "%, \u03B1=" + ONE_DECIMAL.format(d.getAbsorptance() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(str + ", " + ONE_DECIMAL.format(d.getSolarPotentialToday() * d.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The properties and yield of this parabolic dish");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(str);
                                partProperty3TextField.putClientProperty("tooltip", "The properties of this parabolic dish");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof FresnelReflector) {
            final FresnelReflector r = (FresnelReflector) selectedPart;
            if (r.isDrawable()) {
                final Foundation f = r.getTopContainer();
                if (f != null) {
                    double a = r.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Fresnel Reflector (" + r.getId() + ")");
                            partProperty1Label.setText("  Center & Azimuth:");
                            partProperty1TextField.setText("(" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit + ", azimuth:" + ONE_DECIMAL.format(az) + "\u00B0");
                            partProperty1TextField.putClientProperty("tooltip", "Center coordinates and azimuth of the Fresnel reflector");
                            partProperty2Label.setText("  Length & Width:");
                            partProperty2TextField.setText(TWO_DECIMALS.format(r.getLength() * meterToFoot) + lengthUnit + ", module:" + TWO_DECIMALS.format(r.getModuleLength() * meterToFoot) + lengthUnit + ", " + ONE_DECIMAL.format(r.getModuleWidth() * meterToFoot) + lengthUnit);
                            partProperty2TextField.putClientProperty("tooltip", "Assembly length, module length, and width of the Fresnel reflector");
                            final Foundation receiver = r.getReceiver();
                            final String str = "R=" + ONE_DECIMAL.format(r.getReflectance() * 100) + "%, a=" + ONE_DECIMAL.format(r.getModuleWidth() * r.getLength() * meterToFoot * meterToFoot) + lengthUnit + "\u00B2" + (receiver == null ? "" : ", \u03B7=" + ONE_DECIMAL.format(receiver.getSolarReceiverEfficiency() * 100) + "%");
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(str + ", " + ONE_DECIMAL.format(r.getSolarPotentialToday() * r.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The properties and yield of this Fresnel reflector");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(str);
                                partProperty3TextField.putClientProperty("tooltip", "The properties of this Fresnel reflector");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof Sensor) {
            final Sensor sensor = (Sensor) selectedPart;
            if (sensor.isDrawable()) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Sensor (" + sensor.getId() + ")");
                        partProperty1Label.setText("  Position:");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Light:");
                        partProperty1TextField.setText("(" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                        partProperty2TextField.setText(TWO_DECIMALS.format(-sensor.getTotalHeatLoss() / sensor.getArea()) + " kWh/day/m\u00B2");
                        partProperty3TextField.setText(TWO_DECIMALS.format(sensor.getSolarPotentialToday() / sensor.getArea()) + " kWh/day/m\u00B2");
                        partProperty1TextField.putClientProperty("tooltip", "The (x, y, z) coordinates of the sensor");
                        partProperty2TextField.putClientProperty("tooltip", "The heat flux measured by the sensor");
                        partProperty3TextField.putClientProperty("tooltip", "The light intensity measured by the sensor");
                    }
                });
            }
        } else if (selectedPart instanceof Foundation) {
            final Foundation foundation = (Foundation) selectedPart;
            if (foundation.isDrawable()) {
                final Vector3 v1 = foundation.getAbsPoint(1);
                final Vector3 v2 = foundation.getAbsPoint(2);
                final Vector3 v3 = foundation.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double lx = v.distance(v2);
                final double ly = v.distance(v1);
                final double lz = foundation.getHeight();
                final double az = foundation.getAzimuth();
                final String landArea;
                final FoundationPolygon polygon = foundation.getPolygon();
                if (polygon != null && polygon.isVisible()) {
                    landArea = " (inset:" + ONE_DECIMAL.format(polygon.getArea()) + ")";
                } else {
                    landArea = "";
                }
                final Mesh selectedMesh;
                final Node selectedNode;
                final OrientedBoundingBox nodeBox, meshBox;
                final List<Node> nodes = foundation.getImportedNodes();
                if (nodes != null) {
                    selectedMesh = foundation.getSelectedMesh();
                    if (selectedMesh != null) {
                        selectedNode = selectedMesh.getParent();
                        nodeBox = Util.getOrientedBoundingBox(selectedNode);
                        meshBox = Util.getOrientedBoundingBox(selectedMesh);
                    } else {
                        selectedNode = null;
                        nodeBox = null;
                        meshBox = null;
                    }
                } else {
                    selectedMesh = null;
                    selectedNode = null;
                    nodeBox = null;
                    meshBox = null;
                }
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        if (selectedNode != null) {
                            final double xNodeBox = 2 * nodeBox.getExtent().getX() * scale;
                            final double yNodeBox = 2 * nodeBox.getExtent().getY() * scale;
                            final double zNodeBox = 2 * nodeBox.getExtent().getZ() * scale;
                            final double xMeshBox = 2 * meshBox.getExtent().getX() * scale;
                            final double yMeshBox = 2 * meshBox.getExtent().getY() * scale;
                            final double zMeshBox = 2 * meshBox.getExtent().getZ() * scale;
                            final ReadOnlyVector3 meshBoxCenter = meshBox.getCenter();
                            final NodeState ns = foundation.getNodeState(selectedNode);
                            final Vector3 position = ns.getRelativePosition().add(foundation.getAbsCenter(), null);
                            Vector3 meshNormal = null;
                            int meshIndex = -1;
                            if (selectedMesh.getUserData() instanceof UserData) {
                                final UserData ud = (UserData) selectedMesh.getUserData();
                                meshIndex = ud.getMeshIndex();
                                meshNormal = (Vector3) ud.getNormal();
                                if (!Util.isZero(az)) {
                                    selectedNode.getRotation().applyPost(meshNormal, meshNormal);
                                }
                            }
                            // System.out.println(">>>" + Util.computeFirstNormal(selectedMesh) + ", " + Util.getFirstNormalFromBuffer(selectedMesh));
                            final String meshBoxString = TWO_DECIMALS.format(xMeshBox) + "\u00d7" + (TWO_DECIMALS.format(yMeshBox)) + "\u00d7" + (TWO_DECIMALS.format(zMeshBox)) + lengthUnit;
                            final String meshCenterString = "(" + ONE_DECIMAL.format(meshBoxCenter.getX() * scale) + ", " + ONE_DECIMAL.format(meshBoxCenter.getY() * scale) + ", " + ONE_DECIMAL.format(meshBoxCenter.getZ() * scale) + ")" + lengthUnit;
                            final String meshNormalString = meshNormal != null ? "(" + TWO_DECIMALS.format(meshNormal.getX()) + ", " + TWO_DECIMALS.format(meshNormal.getY()) + ", " + TWO_DECIMALS.format(meshNormal.getZ()) + ")" : "";
                            partPanelBorder.setTitle("Node #" + foundation.getImportedNodes().indexOf(selectedNode) + " (" + Util.getFileName(ns.getSourceURL().getPath()).replace("%20", " ") + "), Mesh #" + meshIndex + ", Base #" + foundation.getId());
                            partProperty1Label.setText("  Node:");
                            partProperty2Label.setText("  Mesh:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(xNodeBox) + "\u00d7" + (TWO_DECIMALS.format(yNodeBox)) + "\u00d7" + (TWO_DECIMALS.format(zNodeBox)) + lengthUnit + ", (" + TWO_DECIMALS.format(position.getX() * scale) + ", " + TWO_DECIMALS.format(position.getY() * scale) + ")" + lengthUnit);
                            partProperty2TextField.setText(meshBoxString + ", " + meshCenterString);
                            partProperty1TextField.putClientProperty("tooltip", "Dimension and location of the bounding box of the selected node<br>File:" + ns.getSourceURL().getFile());
                            partProperty2TextField.putClientProperty("tooltip", "Dimension and location of the bounding box of the selected mesh");
                            if (energyViewShown) {
                                double dailyMeshSolarPotential = 0;
                                final double[] meshSolarPotential = SolarRadiation.getInstance().getSolarPotential(selectedMesh);
                                for (final double x : meshSolarPotential) {
                                    dailyMeshSolarPotential += x;
                                }
                                partProperty3Label.setText("  Solar:");
                                partProperty3TextField.setText("\u2191" + meshNormalString + ", " + TWO_DECIMALS.format(dailyMeshSolarPotential) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "Normal vector and solar potential of the selected mesh");
                            } else {
                                partProperty3Label.setText("  Normal:");
                                partProperty3TextField.setText("\u2191" + meshNormalString + ", " + selectedMesh.getMeshData().getVertexCount() + " vertices");
                                partProperty3TextField.putClientProperty("tooltip", "Normal vector and vertex count of the selected mesh");
                            }
                        } else {
                            partPanelBorder.setTitle("Foundation (" + foundation.getId() + ")");
                            partProperty1Label.setText("  Size:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(lx * scale) + "\u00d7" + (TWO_DECIMALS.format(ly * scale)) + "\u00d7" + (TWO_DECIMALS.format(lz * scale)) + lengthUnit + ", Area\u2248" + ONE_DECIMAL.format(lx * ly * scale * scale) + landArea + lengthUnit + "\u00B2");
                            partProperty1TextField.putClientProperty("tooltip", "The length and width of the foundation");
                            partProperty2Label.setText("  Position:");
                            partProperty2TextField.setText("(" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ")" + lengthUnit);
                            partProperty2TextField.putClientProperty("tooltip", "The (x, y) coordinate of the center of the foundation");
                            partProperty3Label.setText("  Azimuth:");
                            partProperty3TextField.setText(TWO_DECIMALS.format(az) + "\u00B0");
                            partProperty3TextField.putClientProperty("tooltip", "The azimuth of the reference edge");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Roof) {
            final Roof roof = (Roof) selectedPart;
            if (roof.isDrawable()) {
                final double area = roof.getArea();
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Roof (" + roof.getId() + ")");
                        partProperty1Label.setText("  Area & Rise:");
                        partProperty1TextField.setText("Area = " + TWO_DECIMALS.format(area) + lengthUnit + "\u00B2, Rise = " + TWO_DECIMALS.format(roof.getHeight() * scale) + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The total area and the rise of the roof<br>(The rise is the highest point of the roof to the top of the walls.)");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String rval = ONE_DECIMAL.format(Util.toUsRValue(roof.getUValue()));
                        final boolean isBuildingProject = Scene.getInstance().getProjectType() == Foundation.TYPE_BUILDING;
                        final float absorptance = 1 - roof.getAlbedo();
                        if (energyViewShown) {
                            partProperty2TextField.setText("R-value = " + rval + ", Gain = " + TWO_DECIMALS.format(-roof.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value and daily thermal gain of the roof");
                            if (isBuildingProject) {
                                partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance) + ", Absorption = " + TWO_DECIMALS.format(roof.getSolarPotentialToday() * absorptance) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The absorptance and daily solar heat gain of the roof surface");
                            } else {
                                partProperty3TextField.setText("Radiation energy = " + TWO_DECIMALS.format(roof.getSolarPotentialToday()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The solar radiation energy onto this roof surface");
                            }
                        } else {
                            partProperty2TextField.setText("R-value = " + rval + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value of the roof");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance));
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance of the roof surface");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Window) {
            final Window window = (Window) selectedPart;
            if (window.isDrawable()) {
                final double lx = window.getWindowWidth();
                final double ly = window.getWindowHeight();
                final Vector3 v1 = window.getAbsPoint(1);
                final Vector3 v2 = window.getAbsPoint(2);
                final Vector3 v3 = window.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double cz = 0.25 * (v.getZ() + v1.getZ() + v2.getZ() + v3.getZ());
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Window (" + window.getId() + ")");
                        partProperty1Label.setText("  Size & Center:");
                        partProperty1TextField.setText(TWO_DECIMALS.format(lx) + "\u00d7" + (TWO_DECIMALS.format(ly)) + lengthUnit + " \u2248 " + TWO_DECIMALS.format(lx * ly) + lengthUnit + "\u00B2, (" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ", " + TWO_DECIMALS.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The width, height, and center of the window");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String shgc = TWO_DECIMALS.format(window.getSolarHeatGainCoefficient());
                        if (energyViewShown) {
                            partProperty2TextField.setText("U-Value = " + TWO_DECIMALS.format(Util.toUsUValue(window.getUValue())) + ", Gain = " + TWO_DECIMALS.format(-window.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The U-value and daily thermal gain of the window");
                            partProperty3TextField.setText("SHGC = " + shgc + ", Gain = " + TWO_DECIMALS.format(window.getSolarPotentialToday() * window.getSolarHeatGainCoefficient()) + " kWh");
                            partProperty3TextField.putClientProperty("tooltip", "The SHGC value and daily solar gain of the window");
                        } else {
                            partProperty2TextField.setText("U-Value = " + TWO_DECIMALS.format(Util.toUsUValue(window.getUValue())) + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The U-value of the window");
                            partProperty3TextField.setText("SHGC = " + shgc);
                            partProperty3TextField.putClientProperty("tooltip", "The solar heat gain coefficient (SHGC) of the window");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Wall) {
            final Wall wall = (Wall) selectedPart;
            if (wall.isDrawable()) {
                final Vector3 v1 = wall.getAbsPoint(1);
                final Vector3 v2 = wall.getAbsPoint(2);
                final Vector3 v3 = wall.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double cz = 0.25 * (v.getZ() + v1.getZ() + v2.getZ() + v3.getZ());
                final double lx = v.distance(v2);
                final double ly = v.distance(v1);
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Wall (" + wall.getId() + ")");
                        partProperty1Label.setText("  Size & Center:");
                        partProperty1TextField.setText(TWO_DECIMALS.format(lx * scale) + "\u00d7" + (TWO_DECIMALS.format(ly * scale)) + lengthUnit + " \u2248 " + TWO_DECIMALS.format(lx * ly * scale * scale) + lengthUnit + " \u00B2, " + "(" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ", " + TWO_DECIMALS.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The width, height, and center of the wall");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String rval = ONE_DECIMAL.format(Util.toUsRValue(wall.getUValue()));
                        final float absorptance = 1 - wall.getAlbedo();
                        if (energyViewShown) {
                            partProperty2TextField.setText("R-Value = " + rval + ", Gain = " + TWO_DECIMALS.format(-wall.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value and daily thermal gain of the wall");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance) + ", Absorption = " + TWO_DECIMALS.format(wall.getSolarPotentialToday() * absorptance) + " kWh");
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance and daily solar heat gain of the wall surface");
                        } else {
                            partProperty2TextField.setText("R-Value = " + rval + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value of the wall");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance));
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance of the wall surface");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Door) {
            final Door door = (Door) selectedPart;
            if (door.isDrawable()) {
                final Vector3 v1 = door.getAbsPoint(1);
                final Vector3 v2 = door.getAbsPoint(2);
                final Vector3 v3 = door.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double cz = 0.25 * (v.getZ() + v1.getZ() + v2.getZ() + v3.getZ());
                final double lx = v.distance(v2);
                final double ly = v.distance(v1);
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Door (" + door.getId() + ")");
                        partProperty1Label.setText("  Size & Center:");
                        partProperty1TextField.setText(TWO_DECIMALS.format(lx * scale) + "\u00d7" + (TWO_DECIMALS.format(ly * scale)) + lengthUnit + " \u2248 " + TWO_DECIMALS.format(lx * ly * scale * scale) + lengthUnit + "\u00B2, (" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ", " + TWO_DECIMALS.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The width, height, and center of the door");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String uval = TWO_DECIMALS.format(Util.toUsUValue(door.getUValue()));
                        final float absorptance = 1 - door.getAlbedo();
                        if (energyViewShown) {
                            partProperty2TextField.setText("U-Value = " + uval + ", Gain = " + TWO_DECIMALS.format(-door.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value and daily thermal gain of the door");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance) + ", Absorption = " + TWO_DECIMALS.format(door.getSolarPotentialToday() * absorptance) + " kWh");
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance and daily solar heat gain of the door surface");
                        } else {
                            partProperty2TextField.setText("U-Value = " + uval + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The U-value of the door");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance));
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance of the door surface");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Floor) {
            final Floor floor = (Floor) selectedPart;
            if (floor.isDrawable()) {
                final double cx, cy;
                final double cz = v.getZ();
                if (floor.getPoints().size() > 1) {
                    final Vector3 v1 = floor.getAbsPoint(1);
                    final Vector3 v2 = floor.getAbsPoint(2);
                    final Vector3 v3 = floor.getAbsPoint(3);
                    cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                    cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                } else {
                    cx = v.getX();
                    cy = v.getY();
                }
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Floor (" + floor.getId() + ")");
                        partProperty1Label.setText("  Area & Center");
                        partProperty1TextField.setText(ONE_DECIMAL.format(floor.getArea()) + lengthUnit + "\u00B2, (" + ONE_DECIMAL.format(cx * scale) + ", " + ONE_DECIMAL.format(cy * scale) + ", " + ONE_DECIMAL.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The area and center of the floor");
                        partProperty2Label.setText("  Thermal:");
                        partProperty2TextField.setText("N.A.");
                        partProperty2TextField.putClientProperty("tooltip", "Not applicable to thermal analysis");
                        partProperty3Label.setText("  Solar:");
                        partProperty3TextField.setText("N.A.");
                        partProperty3TextField.putClientProperty("tooltip", "Not applicable to solar analysis");
                    }
                });
            }
        }
    } else {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                final int numberOfSolarPanels = Scene.getInstance().countSolarPanels();
                if (numberOfSolarPanels > 0) {
                    partPanelBorder.setTitle("Solar Panels");
                    partProperty1Label.setText("  Total Number:");
                    partProperty1TextField.setText("" + numberOfSolarPanels);
                    partProperty1TextField.putClientProperty("tooltip", "Total number of solar panels");
                    partProperty2Label.setText("  Total Cost:");
                    partProperty2TextField.setText("$" + TWO_DECIMALS.format(PvProjectCost.getInstance().getTotalCost()));
                    partProperty2TextField.putClientProperty("tooltip", "Total cost of solar panels");
                    partProperty3Label.setText("  -");
                    partProperty3TextField.setText("");
                    partProperty3TextField.putClientProperty("tooltip", null);
                } else {
                    final int numberOfHeliostats = Scene.getInstance().countParts(Mirror.class);
                    if (numberOfHeliostats > 0) {
                        partPanelBorder.setTitle("Heliostats");
                        partProperty1Label.setText("  Total Number:");
                        partProperty1TextField.setText("" + numberOfHeliostats);
                        partProperty1TextField.putClientProperty("tooltip", "Total number of heliostats");
                        partProperty2Label.setText("  Total Cost:");
                        partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                        partProperty2TextField.putClientProperty("tooltip", "Total cost of heliostats");
                        partProperty3Label.setText("  -");
                        partProperty3TextField.setText("");
                        partProperty3TextField.putClientProperty("tooltip", null);
                    } else {
                        final int numberOfParabolicTroughs = Scene.getInstance().countParts(ParabolicTrough.class);
                        if (numberOfParabolicTroughs > 0) {
                            partPanelBorder.setTitle("Parabolic Troughs");
                            partProperty1Label.setText("  Total Number:");
                            partProperty1TextField.setText("" + numberOfParabolicTroughs);
                            partProperty1TextField.putClientProperty("tooltip", "Total number of parabolic troughs");
                            partProperty2Label.setText("  Total Cost:");
                            partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                            partProperty2TextField.putClientProperty("tooltip", "Total cost of parabolic troughs");
                            partProperty3Label.setText("  -");
                            partProperty3TextField.setText("");
                            partProperty3TextField.putClientProperty("tooltip", null);
                        } else {
                            final int numberOfParabolicDishes = Scene.getInstance().countParts(ParabolicDish.class);
                            if (numberOfParabolicDishes > 0) {
                                partPanelBorder.setTitle("Parabolic Dishes");
                                partProperty1Label.setText("  Total Number:");
                                partProperty1TextField.setText("" + numberOfParabolicDishes);
                                partProperty1TextField.putClientProperty("tooltip", "Total number of parabolic dishes");
                                partProperty2Label.setText("  Total Cost:");
                                partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                                partProperty2TextField.putClientProperty("tooltip", "Total cost of parabolic dishes");
                                partProperty3Label.setText("  -");
                                partProperty3TextField.setText("");
                                partProperty3TextField.putClientProperty("tooltip", null);
                            } else {
                                final int numberOfFresnelReflectors = Scene.getInstance().countParts(FresnelReflector.class);
                                if (numberOfFresnelReflectors > 0) {
                                    partPanelBorder.setTitle("Fresnel Reflectors");
                                    partProperty1Label.setText("  Total Number:");
                                    partProperty1TextField.setText("" + numberOfFresnelReflectors);
                                    partProperty1TextField.putClientProperty("tooltip", "Total number of Fresnel reflectors");
                                    partProperty2Label.setText("  Total Cost:");
                                    partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                                    partProperty2TextField.putClientProperty("tooltip", "Total cost of Fresnel reflectors");
                                    partProperty3Label.setText("  -");
                                    partProperty3TextField.setText("");
                                    partProperty3TextField.putClientProperty("tooltip", null);
                                } else {
                                    final int numberOfNodes = Scene.getInstance().countNodes();
                                    if (numberOfNodes > 0) {
                                        partPanelBorder.setTitle("Structures");
                                        partProperty1Label.setText("  Total Nodes:");
                                        partProperty1TextField.setText("" + numberOfNodes);
                                        partProperty1TextField.putClientProperty("tooltip", "Total number of structure nodes");
                                        partProperty2Label.setText("  Total Meshes:");
                                        partProperty2TextField.setText("" + Scene.getInstance().countMeshes());
                                        partProperty2TextField.putClientProperty("tooltip", "Total number of structure meshes");
                                        partProperty3Label.setText("  -");
                                        partProperty3TextField.setText("");
                                        partProperty3TextField.putClientProperty("tooltip", null);
                                    } else {
                                        partPanelBorder.setTitle(" -");
                                        partProperty1Label.setText("  -");
                                        partProperty1TextField.setText("");
                                        partProperty1TextField.putClientProperty("tooltip", null);
                                        partProperty2Label.setText("  -");
                                        partProperty2TextField.setText("");
                                        partProperty2TextField.putClientProperty("tooltip", null);
                                        partProperty3Label.setText("  -");
                                        partProperty3TextField.setText("");
                                        partProperty3TextField.putClientProperty("tooltip", null);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });
    }
    partPanel.repaint();
    // update building properties
    final Foundation selectedFoundation;
    if (selectedPart == null) {
        selectedFoundation = null;
    } else if (selectedPart instanceof Foundation) {
        selectedFoundation = (Foundation) selectedPart;
    } else {
        selectedFoundation = selectedPart.getTopContainer();
    }
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            if (selectedFoundation != null) {
                switch(selectedFoundation.getProjectType()) {
                    case Foundation.TYPE_BUILDING:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(pvProjectPanel);
                        dataPanel.remove(cspProjectPanel);
                        dataPanel.add(buildingPanel, 2);
                        final Calendar c = Heliodon.getInstance().getCalendar();
                        final int temp = selectedFoundation.getThermostat().getTemperature(c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY, c.get(Calendar.HOUR_OF_DAY));
                        switch(Scene.getInstance().getUnit()) {
                            case InternationalSystemOfUnits:
                                thermostatTemperatureField.setText(temp + " \u00B0C");
                                break;
                            case USCustomaryUnits:
                                thermostatTemperatureField.setText(Math.round(32.0 + 9.0 * temp / 5.0) + " \u00B0F");
                                break;
                        }
                        thermostatPanel.add(adjustThermostatButton, BorderLayout.EAST);
                        String s2 = selectedFoundation.toString();
                        s2 = s2.substring(0, s2.indexOf(')') + 1);
                        final int i1 = s2.indexOf('(');
                        final int i2 = s2.indexOf(')');
                        ((TitledBorder) buildingPanel.getBorder()).setTitle("Building #" + s2.substring(i1 + 1, i2));
                        buildingInfoPanel.update(selectedFoundation);
                        break;
                    case Foundation.TYPE_PV_PROJECT:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(buildingPanel);
                        dataPanel.remove(cspProjectPanel);
                        dataPanel.add(pvProjectPanel, 2);
                        pvProjectInfoPanel.update(selectedFoundation);
                        break;
                    case Foundation.TYPE_CSP_PROJECT:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(buildingPanel);
                        dataPanel.remove(pvProjectPanel);
                        dataPanel.add(cspProjectPanel, 2);
                        cspProjectInfoPanel.update(selectedFoundation);
                        break;
                    case -1:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(buildingPanel);
                        dataPanel.remove(pvProjectPanel);
                        dataPanel.remove(cspProjectPanel);
                        break;
                }
            } else {
                dataPanel.remove(buildingPanel);
                dataPanel.remove(pvProjectPanel);
                dataPanel.remove(cspProjectPanel);
                dataPanel.add(instructionPanel, 2);
                for (int i = 0; i < instructionSheets.length; i++) {
                    final String contentType = Scene.getInstance().getInstructionSheetTextType(i);
                    instructionSheets[i].setContentType(contentType == null ? "text/plain" : contentType);
                    if (!instructionSheets[i].getText().equals(Scene.getInstance().getInstructionSheetText(i))) {
                        instructionSheets[i].setText(Scene.getInstance().getInstructionSheetText(i));
                    }
                }
            }
            dataPanel.validate();
            dataPanel.repaint();
        }
    });
}
Also used : ParabolicTrough(org.concord.energy3d.model.ParabolicTrough) NodeState(org.concord.energy3d.model.NodeState) Wall(org.concord.energy3d.model.Wall) UserData(org.concord.energy3d.model.UserData) Node(com.ardor3d.scenegraph.Node) TitledBorder(javax.swing.border.TitledBorder) Rack(org.concord.energy3d.model.Rack) Roof(org.concord.energy3d.model.Roof) Tree(org.concord.energy3d.model.Tree) Foundation(org.concord.energy3d.model.Foundation) List(java.util.List) HousePart(org.concord.energy3d.model.HousePart) FoundationPolygon(org.concord.energy3d.model.FoundationPolygon) Human(org.concord.energy3d.model.Human) Window(org.concord.energy3d.model.Window) Floor(org.concord.energy3d.model.Floor) FresnelReflector(org.concord.energy3d.model.FresnelReflector) GregorianCalendar(java.util.GregorianCalendar) Calendar(java.util.Calendar) Mesh(com.ardor3d.scenegraph.Mesh) ReadOnlyVector3(com.ardor3d.math.type.ReadOnlyVector3) Vector3(com.ardor3d.math.Vector3) Door(org.concord.energy3d.model.Door) ParabolicDish(org.concord.energy3d.model.ParabolicDish) ReadOnlyVector3(com.ardor3d.math.type.ReadOnlyVector3) OrientedBoundingBox(com.ardor3d.bounding.OrientedBoundingBox) SolarPanel(org.concord.energy3d.model.SolarPanel) Mirror(org.concord.energy3d.model.Mirror) Sensor(org.concord.energy3d.model.Sensor)

Example 55 with Mirror

use of org.concord.energy3d.model.Mirror in project energy3d by concord-consortium.

the class PopupMenuForWall method getPopupMenuForWall.

static JPopupMenu getPopupMenuForWall() {
    if (popupMenuForWall == null) {
        final JMenuItem miPaste = new JMenuItem("Paste");
        miPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Config.isMac() ? KeyEvent.META_MASK : InputEvent.CTRL_MASK));
        miPaste.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                SceneManager.getTaskManager().update(new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        Scene.getInstance().pasteToPickedLocationOnWall();
                        Scene.getInstance().setEdited(true);
                        return null;
                    }
                });
            }
        });
        final JMenuItem miClear = new JMenuItem("Clear");
        miClear.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                SceneManager.getTaskManager().update(new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        Scene.getInstance().removeAllChildren(SceneManager.getInstance().getSelectedPart());
                        EventQueue.invokeLater(new Runnable() {

                            @Override
                            public void run() {
                                MainPanel.getInstance().getEnergyButton().setSelected(false);
                                Scene.getInstance().setEdited(true);
                            }
                        });
                        return null;
                    }
                });
            }
        });
        final JMenuItem miDeleteAllConnectedWalls = new JMenuItem("Delete All Connected Walls");
        miDeleteAllConnectedWalls.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Wall) {
                    Scene.getInstance().deleteAllConnectedWalls((Wall) selectedPart);
                }
            }
        });
        final JMenuItem miThickness = new JMenuItem("Thickness...");
        miThickness.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Wall)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Wall w = (Wall) selectedPart;
                final String title = "<html>Thickness of " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>Thickness of wall is in meters.<hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Wall", true);
                final JRadioButton rb2 = new JRadioButton("All Walls on This Foundation");
                final JRadioButton rb3 = new JRadioButton("All Walls");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(w.getThickness() * Scene.getInstance().getAnnotationScale()));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Wall Thickness");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        double val = 0;
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (val < 0.1 || val > 10) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "The thickness of a wall must be between 0.1 and 10 meters.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                val /= Scene.getInstance().getAnnotationScale();
                                Wall.setDefaultThickess(val);
                                boolean changed = Math.abs(val - w.getThickness()) > 0.000001;
                                if (rb1.isSelected()) {
                                    if (changed) {
                                        final ChangeWallThicknessCommand c = new ChangeWallThicknessCommand(w);
                                        w.setThickness(val);
                                        w.draw();
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 0;
                                } else if (rb2.isSelected()) {
                                    final Foundation foundation = w.getTopContainer();
                                    if (!changed) {
                                        for (final Wall x : foundation.getWalls()) {
                                            if (Math.abs(val - x.getThickness()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeFoundationWallThicknessCommand c = new ChangeFoundationWallThicknessCommand(foundation);
                                        foundation.setThicknessOfWalls(val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 1;
                                } else if (rb3.isSelected()) {
                                    if (!changed) {
                                        for (final Wall x : Scene.getInstance().getAllWalls()) {
                                            if (Math.abs(val - x.getThickness()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeThicknessForAllWallsCommand c = new ChangeThicknessForAllWallsCommand(w);
                                        Scene.getInstance().setThicknessForAllWalls(val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 2;
                                }
                                if (changed) {
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        final JMenuItem miHeight = new JMenuItem("Height...");
        miHeight.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            private boolean changed;

            private double val;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Wall)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Wall w = (Wall) selectedPart;
                final String title = "<html>Height of " + partInfo + "</html>";
                final String footnote = "<html><hr><font size=2>Height of wall is in meters.<hr></html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Wall", true);
                final JRadioButton rb2 = new JRadioButton("All Walls Connected to This One (Direct and Indirect)");
                final JRadioButton rb3 = new JRadioButton("All Walls on This Foundation");
                final JRadioButton rb4 = new JRadioButton("All Walls");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                panel.add(rb4);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                bg.add(rb4);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                    case 3:
                        rb4.setSelected(true);
                        break;
                }
                final JTextField inputField = new JTextField(EnergyPanel.TWO_DECIMALS.format(w.getHeight() * Scene.getInstance().getAnnotationScale()));
                gui.add(inputField, BorderLayout.SOUTH);
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Wall Height");
                while (true) {
                    inputField.selectAll();
                    inputField.requestFocusInWindow();
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        boolean ok = true;
                        try {
                            val = Double.parseDouble(inputField.getText());
                        } catch (final NumberFormatException exception) {
                            JOptionPane.showMessageDialog(MainFrame.getInstance(), inputField.getText() + " is an invalid value!", "Error", JOptionPane.ERROR_MESSAGE);
                            ok = false;
                        }
                        if (ok) {
                            if (val < 1 || val > 1000) {
                                JOptionPane.showMessageDialog(MainFrame.getInstance(), "The height of a wall must be between 1 and 1000 meters.", "Range Error", JOptionPane.ERROR_MESSAGE);
                            } else {
                                val /= Scene.getInstance().getAnnotationScale();
                                changed = Math.abs(val - w.getHeight()) > 0.000001;
                                if (rb1.isSelected()) {
                                    if (changed) {
                                        final ChangeWallHeightCommand c = new ChangeWallHeightCommand(w);
                                        w.setHeight(val, true);
                                        Scene.getInstance().redrawAllWallsNow();
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                        final Foundation foundation = w.getTopContainer();
                                        if (foundation.hasSolarReceiver()) {
                                            foundation.drawSolarReceiver();
                                            for (final HousePart x : Scene.getInstance().getParts()) {
                                                if (x instanceof FresnelReflector) {
                                                    final FresnelReflector reflector = (FresnelReflector) x;
                                                    if (foundation == reflector.getReceiver() && reflector.isSunBeamVisible()) {
                                                        reflector.drawSunBeam();
                                                    }
                                                } else if (x instanceof Mirror) {
                                                    final Mirror heliostat = (Mirror) x;
                                                    if (foundation == heliostat.getReceiver() && heliostat.isSunBeamVisible()) {
                                                        heliostat.drawSunBeam();
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    selectedScopeIndex = 0;
                                } else if (rb2.isSelected()) {
                                    if (!changed) {
                                        w.visitNeighbors(new WallVisitor() {

                                            @Override
                                            public void visit(final Wall currentWall, final Snap prev, final Snap next) {
                                                if (Math.abs(val - currentWall.getHeight()) > 0.000001) {
                                                    changed = true;
                                                }
                                            }
                                        });
                                    }
                                    if (changed) {
                                        final ChangeHeightForConnectedWallsCommand c = new ChangeHeightForConnectedWallsCommand(w);
                                        Scene.getInstance().setHeightOfConnectedWalls(w, val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 1;
                                } else if (rb3.isSelected()) {
                                    final Foundation foundation = w.getTopContainer();
                                    if (!changed) {
                                        for (final Wall x : foundation.getWalls()) {
                                            if (Math.abs(val - x.getHeight()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeFoundationWallHeightCommand c = new ChangeFoundationWallHeightCommand(foundation);
                                        foundation.setHeightOfWalls(val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 2;
                                } else if (rb4.isSelected()) {
                                    if (!changed) {
                                        for (final Wall x : Scene.getInstance().getAllWalls()) {
                                            if (Math.abs(val - x.getHeight()) > 0.000001) {
                                                changed = true;
                                                break;
                                            }
                                        }
                                    }
                                    if (changed) {
                                        final ChangeHeightForAllWallsCommand c = new ChangeHeightForAllWallsCommand(w);
                                        Scene.getInstance().setHeightForAllWalls(val);
                                        SceneManager.getInstance().getUndoManager().addEdit(c);
                                    }
                                    selectedScopeIndex = 3;
                                }
                                if (changed) {
                                    updateAfterEdit();
                                }
                                if (choice == options[0]) {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        });
        final JCheckBoxMenuItem miOutline = new JCheckBoxMenuItem("Outline...", true);
        miOutline.addActionListener(new ActionListener() {

            // remember the scope selection as the next action will likely be applied to the same scope
            private int selectedScopeIndex = 0;

            @Override
            public void actionPerformed(final ActionEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (!(selectedPart instanceof Wall)) {
                    return;
                }
                final String partInfo = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
                final Wall w = (Wall) selectedPart;
                final String title = "<html>Outline of " + partInfo + "</html>";
                final String footnote = "<html>Hiding outline may create a continuous effect of a polygon<br>formed by many walls.</html>";
                final JPanel gui = new JPanel(new BorderLayout());
                final JPanel panel = new JPanel();
                gui.add(panel, BorderLayout.CENTER);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                panel.setBorder(BorderFactory.createTitledBorder("Apply to:"));
                final JRadioButton rb1 = new JRadioButton("Only this Wall", true);
                final JRadioButton rb2 = new JRadioButton("All Walls Connected to This One (Direct and Indirect)");
                final JRadioButton rb3 = new JRadioButton("All Walls on This Foundation");
                final JRadioButton rb4 = new JRadioButton("All Walls");
                panel.add(rb1);
                panel.add(rb2);
                panel.add(rb3);
                panel.add(rb4);
                final ButtonGroup bg = new ButtonGroup();
                bg.add(rb1);
                bg.add(rb2);
                bg.add(rb3);
                bg.add(rb4);
                switch(selectedScopeIndex) {
                    case 0:
                        rb1.setSelected(true);
                        break;
                    case 1:
                        rb2.setSelected(true);
                        break;
                    case 2:
                        rb3.setSelected(true);
                        break;
                    case 3:
                        rb4.setSelected(true);
                        break;
                }
                final Object[] options = new Object[] { "OK", "Cancel", "Apply" };
                final JOptionPane optionPane = new JOptionPane(new Object[] { title, footnote, gui }, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION, null, options, options[2]);
                final JDialog dialog = optionPane.createDialog(MainFrame.getInstance(), "Wall Outline");
                while (true) {
                    dialog.setVisible(true);
                    final Object choice = optionPane.getValue();
                    if (choice == options[1] || choice == null) {
                        break;
                    } else {
                        if (rb1.isSelected()) {
                            // final ChangeWallHeightCommand c = new ChangeWallHeightCommand(w);
                            w.showOutline(miOutline.isSelected());
                            w.draw();
                            // SceneManager.getInstance().getUndoManager().addEdit(c);
                            selectedScopeIndex = 0;
                        } else if (rb2.isSelected()) {
                            // final ChangeHeightForConnectedWallsCommand c = new ChangeHeightForConnectedWallsCommand(w);
                            Scene.getInstance().showOutlineOfConnectedWalls(w, miOutline.isSelected());
                            // SceneManager.getInstance().getUndoManager().addEdit(c);
                            selectedScopeIndex = 1;
                        } else if (rb3.isSelected()) {
                            final Foundation foundation = w.getTopContainer();
                            // final ChangeFoundationWallHeightCommand c = new ChangeFoundationWallHeightCommand(foundation);
                            foundation.showOutlineOfWalls(miOutline.isSelected());
                            // SceneManager.getInstance().getUndoManager().addEdit(c);
                            selectedScopeIndex = 2;
                        } else if (rb4.isSelected()) {
                            // final ChangeHeightForAllWallsCommand c = new ChangeHeightForAllWallsCommand(w);
                            Scene.getInstance().showOutlineForAllWalls(miOutline.isSelected());
                            // SceneManager.getInstance().getUndoManager().addEdit(c);
                            selectedScopeIndex = 3;
                        }
                        updateAfterEdit();
                        if (choice == options[0]) {
                            break;
                        }
                    }
                }
            }
        });
        popupMenuForWall = createPopupMenu(false, false, new Runnable() {

            @Override
            public void run() {
                final HousePart copyBuffer = Scene.getInstance().getCopyBuffer();
                miPaste.setEnabled(copyBuffer instanceof Window || copyBuffer instanceof SolarPanel || copyBuffer instanceof Rack);
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Wall) {
                    final Wall w = (Wall) selectedPart;
                    Util.selectSilently(miOutline, w.outlineShown());
                }
            }
        });
        popupMenuForWall.add(miPaste);
        popupMenuForWall.add(miDeleteAllConnectedWalls);
        popupMenuForWall.add(miClear);
        popupMenuForWall.addSeparator();
        popupMenuForWall.add(colorAction);
        popupMenuForWall.add(miOutline);
        popupMenuForWall.add(miThickness);
        popupMenuForWall.add(miHeight);
        popupMenuForWall.add(createInsulationMenuItem(false));
        popupMenuForWall.add(createVolumetricHeatCapacityMenuItem());
        popupMenuForWall.addSeparator();
        final JMenu textureMenu = new JMenu("Texture");
        popupMenuForWall.add(textureMenu);
        final ButtonGroup textureGroup = new ButtonGroup();
        final JRadioButtonMenuItem rbmiTextureNone = new JRadioButtonMenuItem("No Texture");
        rbmiTextureNone.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final ChangeBuildingTextureCommand c = new ChangeBuildingTextureCommand();
                    Scene.getInstance().setTextureMode(TextureMode.None);
                    Scene.getInstance().setEdited(true);
                    if (MainPanel.getInstance().getEnergyButton().isSelected()) {
                        MainPanel.getInstance().getEnergyButton().setSelected(false);
                    }
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                }
            }
        });
        textureGroup.add(rbmiTextureNone);
        textureMenu.add(rbmiTextureNone);
        final JRadioButtonMenuItem rbmiTextureOutline = new JRadioButtonMenuItem("Outline Texture");
        rbmiTextureOutline.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final ChangeBuildingTextureCommand c = new ChangeBuildingTextureCommand();
                    Scene.getInstance().setTextureMode(TextureMode.Simple);
                    Scene.getInstance().setEdited(true);
                    if (MainPanel.getInstance().getEnergyButton().isSelected()) {
                        MainPanel.getInstance().getEnergyButton().setSelected(false);
                    }
                    SceneManager.getInstance().getUndoManager().addEdit(c);
                }
            }
        });
        textureGroup.add(rbmiTextureOutline);
        textureMenu.add(rbmiTextureOutline);
        textureMenu.addSeparator();
        final JRadioButtonMenuItem rbmiTexture01 = MainFrame.getInstance().createWallTextureMenuItem(Wall.TEXTURE_01, "icons/wall_01.png");
        final JRadioButtonMenuItem rbmiTexture02 = MainFrame.getInstance().createWallTextureMenuItem(Wall.TEXTURE_02, "icons/wall_02.png");
        final JRadioButtonMenuItem rbmiTexture03 = MainFrame.getInstance().createWallTextureMenuItem(Wall.TEXTURE_03, "icons/wall_03.png");
        final JRadioButtonMenuItem rbmiTexture04 = MainFrame.getInstance().createWallTextureMenuItem(Wall.TEXTURE_04, "icons/wall_04.png");
        final JRadioButtonMenuItem rbmiTexture05 = MainFrame.getInstance().createWallTextureMenuItem(Wall.TEXTURE_05, "icons/wall_05.png");
        final JRadioButtonMenuItem rbmiTexture06 = MainFrame.getInstance().createWallTextureMenuItem(Wall.TEXTURE_06, "icons/wall_06.png");
        textureGroup.add(rbmiTexture01);
        textureGroup.add(rbmiTexture02);
        textureGroup.add(rbmiTexture03);
        textureGroup.add(rbmiTexture04);
        textureGroup.add(rbmiTexture05);
        textureGroup.add(rbmiTexture06);
        textureMenu.add(rbmiTexture01);
        textureMenu.add(rbmiTexture02);
        textureMenu.add(rbmiTexture03);
        textureMenu.add(rbmiTexture04);
        textureMenu.add(rbmiTexture05);
        textureMenu.add(rbmiTexture06);
        textureMenu.addMenuListener(new MenuListener() {

            @Override
            public void menuSelected(final MenuEvent e) {
                if (Scene.getInstance().getTextureMode() == TextureMode.None) {
                    Util.selectSilently(rbmiTextureNone, true);
                    return;
                }
                if (Scene.getInstance().getTextureMode() == TextureMode.Simple) {
                    Util.selectSilently(rbmiTextureOutline, true);
                    return;
                }
                switch(Scene.getInstance().getWallTextureType()) {
                    case Wall.TEXTURE_01:
                        Util.selectSilently(rbmiTexture01, true);
                        break;
                    case Wall.TEXTURE_02:
                        Util.selectSilently(rbmiTexture02, true);
                        break;
                    case Wall.TEXTURE_03:
                        Util.selectSilently(rbmiTexture03, true);
                        break;
                    case Wall.TEXTURE_04:
                        Util.selectSilently(rbmiTexture04, true);
                        break;
                    case Wall.TEXTURE_05:
                        Util.selectSilently(rbmiTexture05, true);
                        break;
                    case Wall.TEXTURE_06:
                        Util.selectSilently(rbmiTexture06, true);
                        break;
                }
            }

            @Override
            public void menuDeselected(final MenuEvent e) {
                textureMenu.setEnabled(true);
            }

            @Override
            public void menuCanceled(final MenuEvent e) {
                textureMenu.setEnabled(true);
            }
        });
        final JMenu typeMenu = new JMenu("Type");
        popupMenuForWall.add(typeMenu);
        popupMenuForWall.addSeparator();
        final ButtonGroup typeGroup = new ButtonGroup();
        final JRadioButtonMenuItem rbmiSolidWall = new JRadioButtonMenuItem("Solid Wall");
        rbmiSolidWall.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.SOLID_WALL);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiSolidWall);
        typeGroup.add(rbmiSolidWall);
        final JRadioButtonMenuItem rbmiEmpty = new JRadioButtonMenuItem("Empty");
        rbmiEmpty.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.EMPTY);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiEmpty);
        typeGroup.add(rbmiEmpty);
        final JRadioButtonMenuItem rbmiEdges = new JRadioButtonMenuItem("Vertical Edges");
        rbmiEdges.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.VERTICAL_EDGES_ONLY);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiEdges);
        typeGroup.add(rbmiEdges);
        final JRadioButtonMenuItem rbmiColumns = new JRadioButtonMenuItem("Columns");
        rbmiColumns.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.COLUMNS_ONLY);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiColumns);
        typeGroup.add(rbmiColumns);
        final JRadioButtonMenuItem rbmiRails = new JRadioButtonMenuItem("Rails");
        rbmiRails.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.RAILS_ONLY);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiRails);
        typeGroup.add(rbmiRails);
        final JRadioButtonMenuItem rbmiColumnsAndRailings = new JRadioButtonMenuItem("Columns & Railings");
        rbmiColumnsAndRailings.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.COLUMNS_RAILS);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiColumnsAndRailings);
        typeGroup.add(rbmiColumnsAndRailings);
        final JRadioButtonMenuItem rbmiFence = new JRadioButtonMenuItem("Fence");
        rbmiFence.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.FENCE);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiFence);
        typeGroup.add(rbmiFence);
        final JRadioButtonMenuItem rbmiSteelFrame = new JRadioButtonMenuItem("Steel Frame");
        rbmiSteelFrame.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Wall) {
                        final Wall wall = (Wall) selectedPart;
                        final ChangeWallTypeCommand c = new ChangeWallTypeCommand(wall);
                        wall.setType(Wall.STEEL_FRAME);
                        wall.draw();
                        Scene.getInstance().setEdited(true);
                        SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiSteelFrame);
        typeGroup.add(rbmiSteelFrame);
        typeMenu.addMenuListener(new MenuListener() {

            @Override
            public void menuSelected(final MenuEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Wall) {
                    final Wall wall = (Wall) selectedPart;
                    switch(wall.getType()) {
                        case Wall.SOLID_WALL:
                            Util.selectSilently(rbmiSolidWall, true);
                            break;
                        case Wall.EMPTY:
                            Util.selectSilently(rbmiEmpty, true);
                            break;
                        case Wall.VERTICAL_EDGES_ONLY:
                            Util.selectSilently(rbmiEdges, true);
                            break;
                        case Wall.COLUMNS_ONLY:
                            Util.selectSilently(rbmiColumns, true);
                            break;
                        case Wall.RAILS_ONLY:
                            Util.selectSilently(rbmiRails, true);
                            break;
                        case Wall.COLUMNS_RAILS:
                            Util.selectSilently(rbmiColumnsAndRailings, true);
                            break;
                        case Wall.STEEL_FRAME:
                            Util.selectSilently(rbmiSteelFrame, true);
                            break;
                    }
                }
            }

            @Override
            public void menuDeselected(final MenuEvent e) {
                typeMenu.setEnabled(true);
            }

            @Override
            public void menuCanceled(final MenuEvent e) {
                typeMenu.setEnabled(true);
            }
        });
        JMenuItem mi = new JMenuItem("Daily Energy Analysis...");
        mi.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                if (EnergyPanel.getInstance().adjustCellSize()) {
                    return;
                }
                if (SceneManager.getInstance().getSelectedPart() instanceof Wall) {
                    new EnergyDailyAnalysis().show("Daily Energy for Wall");
                }
            }
        });
        popupMenuForWall.add(mi);
        mi = new JMenuItem("Annual Energy Analysis...");
        mi.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                if (EnergyPanel.getInstance().adjustCellSize()) {
                    return;
                }
                if (SceneManager.getInstance().getSelectedPart() instanceof Wall) {
                    new EnergyAnnualAnalysis().show("Annual Energy for Wall");
                }
            }
        });
        popupMenuForWall.add(mi);
    }
    return popupMenuForWall;
}
Also used : JPanel(javax.swing.JPanel) EnergyAnnualAnalysis(org.concord.energy3d.simulation.EnergyAnnualAnalysis) ChangeWallHeightCommand(org.concord.energy3d.undo.ChangeWallHeightCommand) ItemEvent(java.awt.event.ItemEvent) Wall(org.concord.energy3d.model.Wall) JRadioButton(javax.swing.JRadioButton) ActionEvent(java.awt.event.ActionEvent) MenuListener(javax.swing.event.MenuListener) BoxLayout(javax.swing.BoxLayout) JTextField(javax.swing.JTextField) Snap(org.concord.energy3d.model.Snap) Callable(java.util.concurrent.Callable) ChangeHeightForConnectedWallsCommand(org.concord.energy3d.undo.ChangeHeightForConnectedWallsCommand) ChangeFoundationWallThicknessCommand(org.concord.energy3d.undo.ChangeFoundationWallThicknessCommand) WallVisitor(org.concord.energy3d.util.WallVisitor) Rack(org.concord.energy3d.model.Rack) BorderLayout(java.awt.BorderLayout) Foundation(org.concord.energy3d.model.Foundation) JMenuItem(javax.swing.JMenuItem) HousePart(org.concord.energy3d.model.HousePart) MenuEvent(javax.swing.event.MenuEvent) Window(org.concord.energy3d.model.Window) FresnelReflector(org.concord.energy3d.model.FresnelReflector) ChangeThicknessForAllWallsCommand(org.concord.energy3d.undo.ChangeThicknessForAllWallsCommand) ChangeWallThicknessCommand(org.concord.energy3d.undo.ChangeWallThicknessCommand) JRadioButtonMenuItem(javax.swing.JRadioButtonMenuItem) ChangeHeightForAllWallsCommand(org.concord.energy3d.undo.ChangeHeightForAllWallsCommand) JOptionPane(javax.swing.JOptionPane) JCheckBoxMenuItem(javax.swing.JCheckBoxMenuItem) ChangeWallTypeCommand(org.concord.energy3d.undo.ChangeWallTypeCommand) ActionListener(java.awt.event.ActionListener) ButtonGroup(javax.swing.ButtonGroup) ChangeFoundationWallHeightCommand(org.concord.energy3d.undo.ChangeFoundationWallHeightCommand) SolarPanel(org.concord.energy3d.model.SolarPanel) EnergyDailyAnalysis(org.concord.energy3d.simulation.EnergyDailyAnalysis) ItemListener(java.awt.event.ItemListener) ChangeBuildingTextureCommand(org.concord.energy3d.undo.ChangeBuildingTextureCommand) Mirror(org.concord.energy3d.model.Mirror) JDialog(javax.swing.JDialog) JMenu(javax.swing.JMenu)

Aggregations

Mirror (org.concord.energy3d.model.Mirror)55 HousePart (org.concord.energy3d.model.HousePart)35 Foundation (org.concord.energy3d.model.Foundation)29 FresnelReflector (org.concord.energy3d.model.FresnelReflector)21 Rack (org.concord.energy3d.model.Rack)21 SolarPanel (org.concord.energy3d.model.SolarPanel)19 ParabolicDish (org.concord.energy3d.model.ParabolicDish)17 ParabolicTrough (org.concord.energy3d.model.ParabolicTrough)17 Window (org.concord.energy3d.model.Window)16 Wall (org.concord.energy3d.model.Wall)14 Door (org.concord.energy3d.model.Door)11 Roof (org.concord.energy3d.model.Roof)11 ArrayList (java.util.ArrayList)10 Calendar (java.util.Calendar)5 List (java.util.List)5 JDialog (javax.swing.JDialog)5 Human (org.concord.energy3d.model.Human)5 Tree (org.concord.energy3d.model.Tree)5 ActionEvent (java.awt.event.ActionEvent)4 ActionListener (java.awt.event.ActionListener)4