The EntityEditPanel manages the input components (text fields, combo boxes and such) for editing an entity instance.

When extending an EntityEditPanel you must implement the initializeUI() method, which initializes the edit panel UI. The EntityEditPanel class exposes methods for creating input components and binding them with the underlying EntityEditModel instance.

public class CustomerEditPanel extends EntityEditPanel {

  public CustomerEditPanel(SwingEntityEditModel editModel) {
    super(editModel);
  }

  @Override
  protected void initializeUI() {
    //the firstName field should receive the focus whenever the panel is initialized
    focus().initial().set(Customer.FIRST_NAME);

    createTextField(Customer.FIRST_NAME);
    createTextField(Customer.LAST_NAME);
    createTextField(Customer.EMAIL);
    createCheckBox(Customer.ACTIVE);

    setLayout(new GridLayout(4, 1));
    //the addInputPanel method creates and adds a panel containing the
    //component associated with the attribute as well as a JLabel with the
    //property caption as defined in the domain model
    addInputPanel(Customer.FIRST_NAME);
    addInputPanel(Customer.LAST_NAME);
    addInputPanel(Customer.EMAIL);
    addInputPanel(Customer.ACTIVE);
  }
}
public class AddressEditPanel extends EntityEditPanel {

  public AddressEditPanel(SwingEntityEditModel editModel) {
    super(editModel);
  }

  @Override
  protected void initializeUI() {
    focus().initial().set(Address.STREET);

    createTextField(Address.STREET).columns(25);
    createTextField(Address.CITY).columns(25);
    createCheckBox(Address.VALID);

    setLayout(new GridLayout(3, 1, 5, 5));
    addInputPanel(Address.STREET);
    addInputPanel(Address.CITY);
    addInputPanel(Address.VALID);
  }
}
public class CustomerAddressEditPanel extends EntityEditPanel {

  public CustomerAddressEditPanel(SwingEntityEditModel editModel) {
    super(editModel);
  }

  @Override
  protected void initializeUI() {
    focus().initial().set(CustomerAddress.ADDRESS_FK);

    createComboBoxPanel(CustomerAddress.ADDRESS_FK, this::createAddressEditPanel)
            .preferredWidth(280)
            .includeAddButton(true);

    setLayout(borderLayout());

    addInputPanel(CustomerAddress.ADDRESS_FK);
  }

  private AddressEditPanel createAddressEditPanel() {
    return new AddressEditPanel(new SwingEntityEditModel(Address.TYPE, editModel().connectionProvider()));
  }
}

1. Detailed example

Here’s how a text field is created and added to the edit panel.

createTextField(Customer.FIRST_NAME)
        .columns(12);

setLayout(gridLayout(1, 1));
addInputPanel(Customer.FIRST_NAME);

And here’s the equivilent code, showing what’s going on behind the scenes.

ColumnDefinition<String> firstNameDefinition =
        editModel().entityDefinition().columns().definition(Customer.FIRST_NAME);

//create the text field
JTextField firstNameField = new JTextField();
firstNameField.setColumns(12);
firstNameDefinition.description()
        .ifPresent(firstNameField::setToolTipText);
//associate the text field with the first name attribute
component(Customer.FIRST_NAME).set(firstNameField);

//wrap the text field in a ComponentValue
ComponentValue<String, JTextField> firstNameFieldValue =
        new AbstractTextComponentValue<String, JTextField>(firstNameField) {
          @Override
          protected String getComponentValue() {
            return component().getText();
          }

          @Override
          protected void setComponentValue(String text) {
            component().setText(text);
          }
        };

//link the component value to the attribute value in the editor
firstNameFieldValue.link(editModel().editor().value(Customer.FIRST_NAME));

//create the first name label
JLabel firstNameLabel = new JLabel(firstNameDefinition.caption());
//associate the label with the text field
firstNameLabel.setLabelFor(firstNameField);

//create an input panel, with the label and text field
JPanel firstNamePanel = new JPanel(borderLayout());
firstNamePanel.add(firstNameLabel, BorderLayout.NORTH);
firstNamePanel.add(firstNameField, BorderLayout.CENTER);

setLayout(gridLayout(1, 1));
add(firstNamePanel);

2. Input controls

2.1. Boolean

JCheckBox checkBox =
        createCheckBox(Demo.BOOLEAN)
                .build();

NullableCheckBox nullableCheckBox =
        (NullableCheckBox) createCheckBox(Demo.BOOLEAN)
                .nullable(true)
                .build();

JComboBox<Item<Boolean>> comboBox =
        createBooleanComboBox(Demo.BOOLEAN)
                .build();

2.2. Foreign key

EntityComboBox comboBox =
        createComboBox(Demo.FOREIGN_KEY)
                .build();

EntitySearchField searchField =
        createSearchField(Demo.FOREIGN_KEY)
                .build();

//readOnly
JTextField textField =
        createTextField(Demo.FOREIGN_KEY)
                .build();

2.3. Temporal

TemporalField<LocalDateTime> textField =
        (TemporalField<LocalDateTime>) createTextField(Demo.LOCAL_DATE)
                .build();

TemporalField<LocalDate> localDateField =
        createTemporalField(Demo.LOCAL_DATE)
                .build();

TemporalFieldPanel<LocalDate> temporalPanel =
        createTemporalFieldPanel(Demo.LOCAL_DATE)
                .build();

2.4. Numerical

NumberField<Integer> integerField =
        (NumberField<Integer>) createTextField(Demo.INTEGER)
                .build();

integerField =
        createIntegerField(Demo.INTEGER)
                .build();

NumberField<Long> longField =
        (NumberField<Long>) createTextField(Demo.LONG)
                .build();

longField =
        createLongField(Demo.LONG)
                .build();

NumberField<Double> doubleField =
        (NumberField<Double>) createTextField(Demo.DOUBLE)
                .build();

doubleField =
        createDoubleField(Demo.DOUBLE)
                .build();

NumberField<BigDecimal> bigDecimalField =
        (NumberField<BigDecimal>) createTextField(Demo.BIG_DECIMAL)
                .build();

bigDecimalField =
        createBigDecimalField(Demo.BIG_DECIMAL)
                .build();

2.5. Text

JTextField textField =
        createTextField(Demo.TEXT)
                .build();

JFormattedTextField maskedField =
        createMaskedTextField(Demo.FORMATTED_TEXT)
                .mask("###:###")
                .valueContainsLiteralCharacters(true)
                .build();

JTextArea textArea =
        createTextArea(Demo.LONG_TEXT)
                .rowsColumns(5, 20)
                .build();

TextFieldPanel inputPanel =
        createTextFieldPanel(Demo.LONG_TEXT)
                .build();

2.6. Selection

DefaultComboBoxModel<String> comboBoxModel =
        new DefaultComboBoxModel<>(new String[] {"One", "Two"});

JComboBox<String> comboBox =
        createComboBox(Demo.TEXT, comboBoxModel)
                .editable(true)
                .build();

2.7. Items

JComboBox<Item<String>> comboBox =
        createItemComboBox(Demo.ITEM_LIST)
                .build();

3. Panels & labels

JLabel label = createLabel(Demo.TEXT)
        .build();

JPanel inputPanel = createInputPanel(Demo.TEXT)
        .label(new JLabel("Label"))
        .build();

4. Advanced Patterns

4.1. Configuration Options

EntityEditPanel supports configuration via a lambda in the constructor:

    class InvoiceEditPanel extends EntityEditPanel {
      public InvoiceEditPanel(SwingEntityEditModel editModel) {
        super(editModel, config ->
                // Keep displaying newly inserted invoice since we'll continue
                // working with it by adding invoice lines
                config.clearAfterInsert(false));
      }

      @Override
      protected void initializeUI() {
        // UI setup
      }
    }

4.2. Focus Management

Configure the focus behaviour:

    class CustomerEditPanel extends EntityEditPanel {
      public CustomerEditPanel(SwingEntityEditModel editModel) {
        super(editModel);
      }

      @Override
      protected void initializeUI() {
        focus().initial().set(Customer.FIRSTNAME);
        focus().afterInsert().set(Customer.ADDRESS);

        // Create your input components...
      }
    }

4.3. Inline Edit Panels with ComboBoxPanel

Create combo boxes with inline add/edit capabilities:

    class TrackEditPanel extends EntityEditPanel {
      public TrackEditPanel(SwingEntityEditModel editModel) {
        super(editModel);
      }

      @Override
      protected void initializeUI() {
        createComboBoxPanel(Track.MEDIATYPE_FK, this::createMediaTypeEditPanel)
                .preferredWidth(160)
                .includeAddButton(true)
                .includeEditButton(true);

        createSearchFieldPanel(Track.MEDIATYPE_FK, this::createMediaTypeEditPanel)
                .preferredWidth(160)
                .includeAddButton(true)
                .includeEditButton(true);
      }

      private EntityEditPanel createMediaTypeEditPanel() {
        return new MediaTypeEditPanel(new SwingEntityEditModel(Chinook.MediaType.TYPE, editModel().connectionProvider()));
      }
    }

4.4. Custom Component Integration

Replace default components with custom ones:

    class TrackEditPanel extends EntityEditPanel {
      public TrackEditPanel(SwingEntityEditModel editModel) {
        super(editModel);
      }

      @Override
      protected void initializeUI() {
        // Create a custom component
        DurationComponentValue durationValue = createDurationComponent();

        // Link it to the attribute value
        editModel().editor().value(Track.MILLISECONDS).link(durationValue);
        // And set the component it as the attribute component
        component(Track.MILLISECONDS).set(durationValue.component());
      }

      private DurationComponentValue createDurationComponent() {
        // Custom implementation
        return new DurationComponentValue();
      }
    }

4.5. Keyboard Shortcuts and Actions

Add custom keyboard shortcuts for enhanced productivity:

    class CustomerEditPanel extends EntityEditPanel {
      public CustomerEditPanel(SwingEntityEditModel editModel) {
        super(editModel);
      }

      @Override
      protected void initializeUI() {
        createTextField(Customer.STATE)
                .keyEvent(KeyEvents.builder()
                        .keyCode(VK_SPACE)
                        .modifiers(CTRL_DOWN_MASK)
                        .action(Control.action(this::selectStateFromExistingValues)));
      }

      private void selectStateFromExistingValues(ActionEvent event) {
        JTextField stateField = (JTextField) event.getSource();

        Dialogs.select()
                .list(editModel().connection().select(Customer.STATE))
                .owner(stateField)
                .select()
                .single()
                .ifPresent(stateField::setText);
      }
    }

4.6. Detail Panel Integration

EntityEditPanel can include detail panels for master-detail relationships:

    class InvoiceEditPanel extends EntityEditPanel {
      private final EntityPanel invoiceLinePanel;

      public InvoiceEditPanel(SwingEntityEditModel editModel, SwingEntityModel invoiceLineModel) {
        super(editModel, config -> config.clearAfterInsert(false));
        this.invoiceLinePanel = createInvoiceLinePanel(invoiceLineModel);
      }

      @Override
      protected void initializeUI() {
        // Initialize main edit controls...

        // Add detail panel
        add(invoiceLinePanel, BorderLayout.SOUTH);
      }

      private EntityPanel createInvoiceLinePanel(SwingEntityModel invoiceLineModel) {
        // Create and return invoice line panel
        return new EntityPanel(invoiceLineModel);
      }
    }

5. Custom actions

The action mechanism used throughout the Codion framework is based on the Control class and its subclasses and the Controls class which represents a collection of controls.