All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.impl.javase.BuildHintEditor Maven / Gradle / Ivy

package com.codename1.impl.javase;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URI;
import java.util.*;
import java.util.List;

/**
 * A GUI editor for editing build hints.  This includes support for cn1libs to tie into it at runtime.
 *
 */
public class BuildHintEditor {
    private final JavaSEPort javaSEPort;
    private JFrame frame;
    private boolean modified;
    private final Map> propertyChangeListeners = new HashMap>();

    private final LinkedHashMap buildHintModels = new LinkedHashMap();
    private final LinkedHashMap buildHintGroupModels = new LinkedHashMap();

    private final Map projectBuildHints = new HashMap();

    public BuildHintEditor(JavaSEPort javaSEPort) {
        this.javaSEPort = javaSEPort;
    }

    private enum BuildHintValueType {
        TextField,
        TextArea,
        Checkbox,
        Select
    }

    private class BuildHintModel {
        private String name="", label="", description="", hint="";
        private BuildHintValueType type = BuildHintValueType.TextField;
        private boolean required;
        private String[] values;
        private String group;
        private String linkUrl, linkLabel;
    }

    private class BuildHintGroupModel {
        private String name = "", label = "", description = "";
        private LinkedHashMap hints = new LinkedHashMap();
    }

    private class BuildHintFields {
        private JTextField value;
        private JLabel label, description;
    }



    private void onPropertyChange(String hintName, Runnable r) {
        ArrayList listeners = propertyChangeListeners.get(hintName);
        if (listeners == null) {
            listeners = new ArrayList();
            propertyChangeListeners.put(hintName, listeners);
        }
        listeners.add(r);
    }

    private void loadBuildHintModels() {
        clearModified();

        buildHintModels.clear();
        buildHintGroupModels.clear();
        projectBuildHints.clear();
        projectBuildHints.putAll(javaSEPort.getProjectBuildHints());
        Properties props = System.getProperties();

        for (String propName : props.stringPropertyNames()) {
            if (propName.startsWith("codename1.arg.{{") && propName.contains("}}.")) {
                String hintName = propName.substring(propName.indexOf("{{")+2, propName.indexOf("}}.")).trim();


                String hintPropertyName = propName.substring(propName.indexOf("}}.")+3).trim();
                String propertyValue = props.getProperty(propName);

                if (hintName.startsWith("@")) {
                    // This is a group property
                    BuildHintGroupModel groupModel = buildHintGroupModels.get(hintName.substring(1));
                    if (groupModel == null) {
                        groupModel = new BuildHintGroupModel();
                        groupModel.name = hintName.substring(1);
                        groupModel.label = groupModel.name;
                        buildHintGroupModels.put(groupModel.name, groupModel);

                    }
                    if ("label".equals(hintPropertyName)) {
                        groupModel.label = propertyValue;
                    } else if ("description".equals(hintPropertyName)) {
                        groupModel.description = propertyValue;
                    }
                    continue;

                }
                BuildHintModel model;
                if (hintName.startsWith("#") && hintName.substring(1).contains("#")) {
                    String groupName = hintName.substring(1, hintName.indexOf("#", 1));
                    hintName = hintName.substring(hintName.indexOf("#", 1)+1);
                    BuildHintGroupModel groupModel = buildHintGroupModels.get(groupName);
                    if (groupModel == null) {
                        groupModel = new BuildHintGroupModel();
                        groupModel.name = groupName;
                        groupModel.label = groupModel.name;
                        buildHintGroupModels.put(groupModel.name, groupModel);
                    }

                    model = groupModel.hints.get(hintName);
                    if (model == null) {
                        model = new BuildHintModel();
                        model.name = hintName;
                        model.label = hintName;
                        groupModel.hints.put(hintName, model);
                    }
                } else {
                    model = buildHintModels.get(hintName);
                    if (model == null) {
                        model = new BuildHintModel();
                        model.name = hintName;
                        model.label = hintName;

                        buildHintModels.put(hintName, model);
                    }
                }

                if ("description".equals(hintPropertyName)) {
                    model.description = propertyValue;
                } else if ("label".equals(hintPropertyName)) {
                    model.label = propertyValue;
                } else if ("link".equals(hintPropertyName)) {
                    model.linkUrl = propertyValue;
                    model.linkLabel = "Learn more";
                    if (propertyValue.contains(" ")) {
                        model.linkUrl = propertyValue.substring(0, propertyValue.indexOf(" "));
                        model.linkLabel = propertyValue.substring(propertyValue.indexOf(" ")+1);

                    }
                } else if ("hint".equals(hintPropertyName)) {
                    model.hint = propertyValue;
                } else if ("required".equals(hintPropertyName)) {
                    model.required = "true".equalsIgnoreCase(propertyValue);
                } else if ("type".equals(hintPropertyName)) {
                    if ("textfield".equalsIgnoreCase(propertyValue)) {
                        model.type = BuildHintValueType.TextField;
                    } else if ("textarea".equalsIgnoreCase(propertyValue)) {
                        model.type = BuildHintValueType.TextArea;
                    } else if ("checkbox".equalsIgnoreCase(propertyValue)) {
                        model.type = BuildHintValueType.Checkbox;
                    } else if ("select".equalsIgnoreCase(propertyValue)) {
                        model.type = BuildHintValueType.Select;
                        String valuesString = System.getProperty("codename1.arg.{{ "+model.name+" }}.values");
                        if (valuesString != null) {
                            String separator = ""+valuesString.charAt(valuesString.length()-1);
                            ArrayList values = new ArrayList();
                            values.add("");
                            for (String value : valuesString.split(separator)) {
                                if (!value.trim().isEmpty()) {
                                    values.add(value);
                                }
                            }

                            model.values = values.toArray(new String[values.size()]);
                        }
                    }
                } else if ("group".equals(hintPropertyName)) {
                    BuildHintGroupModel groupModel = buildHintGroupModels.get(propertyValue);
                    model.group = hintPropertyName;
                    if (groupModel == null) {
                        groupModel = new BuildHintGroupModel();
                        groupModel.name = propertyValue;
                        groupModel.label = propertyValue;
                        buildHintGroupModels.put(groupModel.name, groupModel);
                    }
                    groupModel.hints.put(model.name, model);

                }

            }
        }

        for (String hint : projectBuildHints.keySet()) {
            BuildHintModel model = buildHintModels.get(hint);
            if (model == null) {
                model = new BuildHintModel();
                model.name = hint;
                model.label = hint;
                buildHintModels.put(hint, model);
            }
        }

    }

    private void setModified(String hint) {
        modified = true;
        ArrayList listeners = propertyChangeListeners.get(hint);
        if (listeners != null && !listeners.isEmpty()) {
            for (Runnable r : listeners) {
                r.run();
            }
        }
    }

    private void clearModified() {
        modified = false;
    }

    private List getGrouplessBuildHints() {
        ArrayList out = new ArrayList();
        for (BuildHintModel buildHintModel : buildHintModels.values()) {
            if (buildHintModel.group == null || buildHintModel.group.isEmpty()) {
                out.add(buildHintModel);
            }
        }
        return out;
    }

    private JComponent left(Component... cmps) {
        JPanel p = new JPanel();
        decorateContainer(p);
        p.setLayout(new FlowLayout(FlowLayout.LEFT));
        for (Component cmp : cmps) {
            p.add(cmp);
        }
        return p;
    }

    private JComponent leftNoGrow(Component... cmps) {
        JPanel p = new JPanel() {
            @Override
            public Dimension getMaximumSize() {
                return new Dimension(Integer.MAX_VALUE, getPreferredSize().height);
            }
        };
        decorateContainer(p);
        p.setLayout(new FlowLayout(FlowLayout.LEFT));
        for (Component cmp : cmps) {
            p.add(cmp);
        }

        return p;
    }

    private JComponent wrapRigid(Component cmp) {
        JPanel p = new JPanel() {
            @Override
            public Dimension getMaximumSize() {
                return new Dimension(Integer.MAX_VALUE, getPreferredSize().height);
            }
        };
        decorateContainer(p);
        p.setLayout(new BorderLayout());
        p.add(cmp, BorderLayout.CENTER);

        return p;
    }



    private static void addChangeListenerTo(JTextComponent textField, final Runnable r) {
        textField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                r.run();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                r.run();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                r.run();
            }
        });
    }

    private JComponent createHintView(final BuildHintModel model) {
        JPanel cnt = new JPanel();
        cnt.setLayout(new BorderLayout());
        JLabel label = new JLabel(model.label);
        Font labelFont = label.getFont();
        labelFont = labelFont.deriveFont(Font.BOLD);
        label.setFont(labelFont);
        cnt.add(label, BorderLayout.NORTH);
        JTextArea description = null;
        if (!model.description.isEmpty()) {
            //description = new JLabel("

"+model.description+"

"); description = new JTextArea(model.description); description.setOpaque(false); description.setEditable(false); description.setBorder(null); description.setLineWrap(true); description.setWrapStyleWord(true); description.setFont(UIManager.getFont("Label.font")); Font descriptionFont = description.getFont(); descriptionFont = descriptionFont.deriveFont(descriptionFont.getSize2D() * 0.75f); description.setFont(descriptionFont); description.setForeground(Color.darkGray); description.setBackground(UIManager.getColor("Label.background")); description.setAlignmentX(Component.LEFT_ALIGNMENT); description.setPreferredSize(new Dimension(400, 30)); description.setMaximumSize(new Dimension(400, 200)); //description.setPreferredSize(new Dimension(480, description.getPreferredSize().height)); } JPanel examplePanel = new JPanel(); decorateContainer(examplePanel); examplePanel.setLayout(new BorderLayout()); JPanel descriptionPanel = new JPanel(); descriptionPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); decorateContainer(descriptionPanel); examplePanel.add(descriptionPanel, BorderLayout.NORTH); if (description != null) { descriptionPanel.add(description); } if (model.linkLabel != null && model.linkUrl != null && !model.linkLabel.isEmpty() && !model.linkUrl.isEmpty()) { JButton link = new JButton(model.linkLabel); ActionListener l = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { if (Desktop.isDesktopSupported()) { Desktop.getDesktop().browse(new URI(model.linkUrl)); } else { JOptionPane.showMessageDialog(frame, "Opening system web browser not supported on this platform."); } } catch (Exception ex) { JOptionPane.showMessageDialog(frame, "Failed to open page. "+ex.getMessage(), "Failed", JOptionPane.ERROR_MESSAGE); } } }; link.addActionListener(l); descriptionPanel.add(link); } if (model.hint != null && !model.hint.isEmpty()) { JPanel innerExamplePanel = new JPanel(); decorateContainer(innerExamplePanel); innerExamplePanel.setLayout(new BorderLayout()); innerExamplePanel.setBorder(new TitledBorder("Example")); final JTextArea example = new JTextArea(model.hint); example.setEditable(false); example.setBorder(new LineBorder(Color.gray)); example.setWrapStyleWord(true); example.setLineWrap(true); example.setForeground(Color.darkGray); example.setBackground(new Color(0xff, 0xff, 0xff, 0xcc)); Font defaultFont = UIManager.getFont("Label.font"); defaultFont = defaultFont.deriveFont(defaultFont.getSize2D() * 0.75f); example.setFont(defaultFont); example.setColumns(30); example.setPreferredSize(new Dimension(400, 30)); example.setMaximumSize(new Dimension(400, 200)); innerExamplePanel.add(left(example), BorderLayout.CENTER); JButton copy = new JButton("Copy"); ActionListener l = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { java.awt.Toolkit.getDefaultToolkit().getSystemClipboard() .setContents(new java.awt.datatransfer.StringSelection(example.getText()), null); } }; copy.addActionListener(l); copy.putClientProperty("JComponent.sizeVariant", "mini"); innerExamplePanel.add(copy, BorderLayout.EAST); examplePanel.add(innerExamplePanel, BorderLayout.CENTER); } cnt.add(examplePanel, BorderLayout.SOUTH); JComponent valueComponent; switch (model.type) { case TextField: { final JTextField textField = new JTextField(); textField.setColumns(30); //textField.setMinimumSize(new Dimension(textField.getPreferredSize().width,30)); textField.setText(""); String currentValue = projectBuildHints.get(model.name); if (currentValue == null) { //textField.setText(model.hint); } else { textField.setText(currentValue); } textField.setPreferredSize(new Dimension(100, 30)); textField.setMaximumSize(new Dimension(200, 30)); Runnable l = new Runnable() { @Override public void run() { projectBuildHints.put(model.name, textField.getText()); setModified(model.name); } }; addChangeListenerTo(textField, l); l = new Runnable() { @Override public void run() { if (!Objects.equals(projectBuildHints.get(model.name), textField.getText())) { textField.setText(projectBuildHints.get(model.name)); } } }; onPropertyChange(model.name, l); valueComponent = textField; break; } case TextArea: { final JTextArea textField = new JTextArea(); String currentValue = projectBuildHints.get(model.name); if (currentValue == null) { //textField.setText(model.hint); } else { textField.setText(currentValue); } textField.setPreferredSize(new Dimension(100, 30)); textField.setMaximumSize(new Dimension(200, 30)); Runnable l = new Runnable() { @Override public void run() { projectBuildHints.put(model.name, textField.getText()); setModified(model.name); } }; addChangeListenerTo(textField, l); l = new Runnable() { @Override public void run() { if (!Objects.equals(projectBuildHints.get(model.name), textField.getText())) { textField.setText(projectBuildHints.get(model.name)); } } }; onPropertyChange(model.name, l); valueComponent = textField; break; } case Checkbox: { final JCheckBox checkBox = new JCheckBox(model.label); if (projectBuildHints.containsKey(model.name) && "true".equals(projectBuildHints.get(model.name))) { checkBox.setSelected(true); } checkBox.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { if (checkBox.isSelected()) { projectBuildHints.put(model.name, "true"); } else { projectBuildHints.put(model.name, "false"); } setModified(model.name); } }); Runnable l = new Runnable() { @Override public void run() { boolean newVal = "true".equals(projectBuildHints.get(model.name)); if (newVal != checkBox.isSelected()) { checkBox.setSelected(newVal); } } }; onPropertyChange(model.name, l); valueComponent = checkBox; break; } case Select: { if (model.values == null) { model.values = new String[]{}; } ArrayList values = new ArrayList(Arrays.asList(model.values)); if (projectBuildHints.containsKey(model.name) && !values.contains(projectBuildHints.get(model.name))) { values.add(projectBuildHints.get(model.name)); } final JComboBox comboBox = new JComboBox(values.toArray(new String[values.size()])); if (projectBuildHints.containsKey(model.name)) { comboBox.setSelectedItem(projectBuildHints.get(model.name)); } ActionListener l = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { projectBuildHints.put(model.name, (String)comboBox.getSelectedItem()); setModified(model.name); } }; comboBox.addActionListener(l); Runnable r = new Runnable() { @Override public void run() { String newVal = projectBuildHints.get(model.name); if (!Objects.equals(newVal, comboBox.getSelectedItem())) { comboBox.setSelectedItem(newVal); } } }; onPropertyChange(model.name, r); valueComponent = comboBox; break; } default: { throw new IllegalStateException("No type set for field "+model.name); } } cnt.add(valueComponent, BorderLayout.CENTER); decorateContainer(cnt); //cnt.setPreferredSize(new Dimension(480, cnt.getPreferredSize().height+20)); //cnt.setMaximumSize(new Dimension(640, cnt.getPreferredSize().height+20)); cnt.setBorder(new EmptyBorder(10, 10, 10,50)); return cnt; } private JComponent decorateContainer(JComponent cmp) { cmp.setOpaque(false); return cmp; } private void buildUI() { propertyChangeListeners.clear(); loadBuildHintModels(); frame = new JFrame("Build Hint Editor"); JTabbedPane tabs = new JTabbedPane(); tabs.setOpaque(false); for (BuildHintGroupModel group : buildHintGroupModels.values()) { final ArrayList views = new ArrayList(); final JPanel groupPanel = new JPanel(); decorateContainer(groupPanel); groupPanel.setLayout(new BoxLayout(groupPanel, BoxLayout.Y_AXIS)); if (group.description != null && !group.description.isEmpty()) { JLabel description = new JLabel("

"+group.description+"

"); groupPanel.add(left(description)); } for (BuildHintModel hintModel : group.hints.values()) { JComponent view = createHintView(hintModel); groupPanel.add(wrapRigid(view)); view.putClientProperty("keywords", hintModel.name+" "+hintModel.label+" "+hintModel.description); views.add(view); } groupPanel.add(decorateContainer((JComponent)Box.createVerticalGlue())); final JTextField filter = new JTextField(); filter.putClientProperty("JTextField.variant", "search"); Runnable l = new Runnable() { @Override public void run() { String[] words = filter.getText().split(" "); boolean noSearch = filter.getText().trim().isEmpty(); for (JComponent view : views) { String keywords = (String)view.getClientProperty("keywords"); if (keywords == null) continue; String lcKeywords = keywords.toLowerCase(); boolean found = noSearch; if (!found) { for (String word : words) { if (word.trim().isEmpty()) continue; if (lcKeywords.contains(word.toLowerCase())) { found = true; break; } } } view.setVisible(found); } groupPanel.revalidate(); } }; addChangeListenerTo(filter, l); JScrollPane groupScroller = new JScrollPane(groupPanel); decorateContainer(groupScroller); decorateContainer(groupScroller.getViewport()); groupScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JPanel groupWrapper = new JPanel(); groupWrapper.setLayout(new BorderLayout()); decorateContainer(groupWrapper); groupWrapper.add(groupScroller, BorderLayout.CENTER); groupWrapper.add(filter, BorderLayout.NORTH); tabs.add(group.label, groupWrapper); } final JPanel grouplessPanel = new JPanel(); decorateContainer(grouplessPanel); grouplessPanel.setLayout(new BoxLayout(grouplessPanel, BoxLayout.Y_AXIS)); final ArrayList grouplessViews = new ArrayList(); for (BuildHintModel hintModel : getGrouplessBuildHints()) { JComponent view = createHintView(hintModel); grouplessPanel.add(wrapRigid(view)); view.putClientProperty("keywords", hintModel.name+ " " + hintModel.label + " " + hintModel.description); grouplessViews.add(view); } grouplessPanel.add(decorateContainer((JComponent)Box.createVerticalGlue())); final JTextField filter = new JTextField(); filter.putClientProperty("JTextField.variant", "search"); Runnable l = new Runnable() { @Override public void run() { String[] words = filter.getText().split(" "); boolean noSearch = filter.getText().trim().isEmpty(); for (JComponent view : grouplessViews) { String keywords = (String)view.getClientProperty("keywords"); if (keywords == null) continue; String lcKeywords = keywords.toLowerCase(); boolean found = noSearch; if (!found) { for (String word : words) { if (word.trim().isEmpty()) continue; if (lcKeywords.contains(word.toLowerCase())) { found = true; break; } } } view.setVisible(found); } grouplessPanel.revalidate(); } }; addChangeListenerTo(filter,l); JScrollPane grouplessScroller = new JScrollPane(grouplessPanel); decorateContainer(grouplessScroller.getViewport()); decorateContainer(grouplessScroller); grouplessScroller.setBorder(new EmptyBorder(0,0,0,0)); String grouplessLabel = buildHintGroupModels.isEmpty() ? "Build Hints" : "Other"; JPanel grouplessWrapper = new JPanel(); grouplessWrapper.setLayout(new BorderLayout()); decorateContainer(grouplessWrapper); grouplessWrapper.add(grouplessScroller, BorderLayout.CENTER); grouplessWrapper.add(filter, BorderLayout.NORTH); tabs.add(grouplessLabel, grouplessWrapper); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(tabs, BorderLayout.CENTER); JButton cancel = new JButton("Cancel"); JButton apply = new JButton("Apply"); ActionListener actionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(); } }; apply.addActionListener(actionListener); actionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { close(); } }; cancel.addActionListener(actionListener); JButton save = new JButton("Save"); actionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(); close(); } }; save.addActionListener(actionListener); JPanel buttons = new JPanel(); buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); buttons.add(cancel); buttons.add(apply); buttons.add(save); frame.getContentPane().add(buttons, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { close(); } }); } private void save() { Map oldHints = javaSEPort.getProjectBuildHints(); for (String hint : projectBuildHints.keySet()) { if (!oldHints.containsKey(hint) || !hint.equals(oldHints.get(hint))) { javaSEPort.setProjectBuildHint(hint, projectBuildHints.get(hint)); } } clearModified(); } private void close() { if (modified) { int result = JOptionPane.showConfirmDialog(frame, "Save changes to build hints before closing?", "Save Changes?", JOptionPane.YES_NO_CANCEL_OPTION); switch (result) { case JOptionPane.CANCEL_OPTION: return; case JOptionPane.NO_OPTION: frame.dispose(); break; case JOptionPane.YES_OPTION: save(); frame.dispose(); break; } } else { frame.dispose(); } } public void show() { buildUI(); frame.getContentPane().setPreferredSize(new Dimension(640, 480)); frame.pack(); frame.setLocationRelativeTo(javaSEPort.canvas); frame.setVisible(true); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy