protected void initComponents(
        AirspaceBuilderModel model, final AirspaceBuilderController controller) {
      final JCheckBox resizeNewShapesCheckBox;
      final JCheckBox enableEditCheckBox;

      JPanel newShapePanel = new JPanel();
      {
        JButton newShapeButton = new JButton("New shape");
        newShapeButton.setActionCommand(NEW_AIRSPACE);
        newShapeButton.addActionListener(controller);
        newShapeButton.setToolTipText("Create a new shape centered in the viewport");

        this.factoryComboBox = new JComboBox(defaultAirspaceFactories);
        this.factoryComboBox.setEditable(false);
        this.factoryComboBox.setToolTipText("Choose shape type to create");

        resizeNewShapesCheckBox = new JCheckBox("Fit new shapes to viewport");
        resizeNewShapesCheckBox.setActionCommand(SIZE_NEW_SHAPES_TO_VIEWPORT);
        resizeNewShapesCheckBox.addActionListener(controller);
        resizeNewShapesCheckBox.setSelected(controller.isResizeNewShapesToViewport());
        resizeNewShapesCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
        resizeNewShapesCheckBox.setToolTipText(
            "New shapes are sized to fit the geographic viewport");

        enableEditCheckBox = new JCheckBox("Enable shape editing");
        enableEditCheckBox.setActionCommand(ENABLE_EDIT);
        enableEditCheckBox.addActionListener(controller);
        enableEditCheckBox.setSelected(controller.isEnableEdit());
        enableEditCheckBox.setAlignmentX(Component.LEFT_ALIGNMENT);
        enableEditCheckBox.setToolTipText("Allow modifications to shapes");

        Box newShapeBox = Box.createHorizontalBox();
        newShapeBox.add(newShapeButton);
        newShapeBox.add(Box.createHorizontalStrut(5));
        newShapeBox.add(this.factoryComboBox);
        newShapeBox.setAlignmentX(Component.LEFT_ALIGNMENT);

        JPanel gridPanel = new JPanel(new GridLayout(0, 1, 0, 5)); // rows, cols, hgap, vgap
        gridPanel.add(newShapeBox);
        gridPanel.add(resizeNewShapesCheckBox);
        gridPanel.add(enableEditCheckBox);

        newShapePanel.setLayout(new BorderLayout());
        newShapePanel.add(gridPanel, BorderLayout.NORTH);
      }

      JPanel entryPanel = new JPanel();
      {
        this.entryTable = new JTable(model);
        this.entryTable.setColumnSelectionAllowed(false);
        this.entryTable.setRowSelectionAllowed(true);
        this.entryTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        this.entryTable
            .getSelectionModel()
            .addListSelectionListener(
                new ListSelectionListener() {
                  public void valueChanged(ListSelectionEvent e) {
                    if (!ignoreSelectEvents) {
                      controller.actionPerformed(
                          new ActionEvent(e.getSource(), -1, SELECTION_CHANGED));
                    }
                  }
                });
        this.entryTable.setToolTipText("<html>Click to select<br>Double-Click to rename</html>");

        JScrollPane tablePane = new JScrollPane(this.entryTable);
        tablePane.setPreferredSize(new Dimension(200, 100));

        entryPanel.setLayout(new BorderLayout(0, 0)); // hgap, vgap
        entryPanel.add(tablePane, BorderLayout.CENTER);
      }

      JPanel selectionPanel = new JPanel();
      {
        JButton delselectButton = new JButton("Deselect");
        delselectButton.setActionCommand(CLEAR_SELECTION);
        delselectButton.addActionListener(controller);
        delselectButton.setToolTipText("Clear the selection");

        JButton deleteButton = new JButton("Delete Selected");
        deleteButton.setActionCommand(REMOVE_SELECTED);
        deleteButton.addActionListener(controller);
        deleteButton.setToolTipText("Delete selected shapes");

        JPanel gridPanel = new JPanel(new GridLayout(0, 1, 0, 5)); // rows, cols, hgap, vgap
        gridPanel.add(delselectButton);
        gridPanel.add(deleteButton);

        selectionPanel.setLayout(new BorderLayout());
        selectionPanel.add(gridPanel, BorderLayout.NORTH);
      }

      this.setLayout(new BorderLayout(30, 0)); // hgap, vgap
      this.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); // top, left, bottom, right
      this.add(newShapePanel, BorderLayout.WEST);
      this.add(entryPanel, BorderLayout.CENTER);
      this.add(selectionPanel, BorderLayout.EAST);

      controller.addPropertyChangeListener(
          new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
              if (SIZE_NEW_SHAPES_TO_VIEWPORT.equals(e.getPropertyName())) {
                resizeNewShapesCheckBox.setSelected(controller.isResizeNewShapesToViewport());
              } else if (ENABLE_EDIT.equals(e.getPropertyName())) {
                enableEditCheckBox.setSelected(controller.isEnableEdit());
              }
            }
          });
    }
  public SketchProperties(Editor e, Sketch s) {
    super();

    editor = e;
    sketch = s;

    fields = new HashMap<String, JComponent>();

    this.setPreferredSize(new Dimension(500, 400));
    this.setMinimumSize(new Dimension(500, 400));
    this.setMaximumSize(new Dimension(500, 400));
    this.setSize(new Dimension(500, 400));
    Point eLoc = editor.getLocation();
    int x = eLoc.x;
    int y = eLoc.y;

    Dimension eSize = editor.getSize();
    int w = eSize.width;
    int h = eSize.height;

    int cx = x + (w / 2);
    int cy = y + (h / 2);

    this.setLocation(new Point(cx - 250, cy - 200));
    this.setModal(true);

    outer = new JPanel(new BorderLayout());
    outer.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    this.add(outer);

    win = new JPanel();
    win.setLayout(new BorderLayout());
    outer.add(win, BorderLayout.CENTER);

    buttonBar = new JPanel(new FlowLayout(FlowLayout.RIGHT));

    saveButton = new JButton("OK");
    saveButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            save();
            SketchProperties.this.dispose();
          }
        });

    cancelButton = new JButton("Cancel");
    cancelButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            SketchProperties.this.dispose();
          }
        });

    buttonBar.add(saveButton);
    buttonBar.add(cancelButton);

    win.add(buttonBar, BorderLayout.SOUTH);

    tabs = new JTabbedPane();

    overviewPane = new JPanel();
    overviewPane.setLayout(new BoxLayout(overviewPane, BoxLayout.PAGE_AXIS));
    overviewPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    addTextField(overviewPane, "author", "Sketch author:");
    addTextArea(overviewPane, "summary", "Summary:");
    addTextArea(overviewPane, "license", "Copyright / License:");
    tabs.add("Overview", overviewPane);

    objectsPane = new JPanel();
    objectsPane.setLayout(new BoxLayout(objectsPane, BoxLayout.PAGE_AXIS));
    objectsPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    addTextField(objectsPane, "board", "Board:");
    addTextField(objectsPane, "core", "Core:");
    addTextField(objectsPane, "compiler", "Compiler:");
    addTextField(objectsPane, "port", "Serial port:");
    addTextField(objectsPane, "programmer", "Programmer:");
    JButton setDef = new JButton("Set to current IDE values");
    setDef.setMaximumSize(setDef.getPreferredSize());
    setDef.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            setObjectValues();
          }
        });
    objectsPane.add(Box.createVerticalGlue());
    objectsPane.add(setDef);

    tabs.add("Objects", objectsPane);

    win.add(tabs, BorderLayout.CENTER);

    this.setTitle("Sketch Properties");

    this.pack();
    this.setVisible(true);
  }