The EntityApplicationPanel class serves as the main application UI. When extending this class you must provide a constructor with a single application model parameter, as seen below.

The constructor takes the application’s root entity panels, and optionally a set of lookup panel builders: panels for supporting entities — lookup and reference data — which appear in the application’s View menu and open on demand, in their own windows, rather than occupying a tab.

public class StoreApplicationPanel extends EntityApplicationPanel<StoreApplicationModel> {

  public StoreApplicationPanel(StoreApplicationModel applicationModel) {
    super(applicationModel, createPanels(applicationModel), createLookupPanelBuilders());
  }

  private static List<EntityPanel> createPanels(StoreApplicationModel applicationModel) {
    CustomerModel customerModel = (CustomerModel)
            applicationModel.models().get(Customer.TYPE);
    CustomerAddressModel customerAddressModel = (CustomerAddressModel)
            customerModel.detail().get(CustomerAddress.TYPE);

    EntityPanel customerPanel = new EntityPanel(customerModel,
            new CustomerEditPanel(customerModel.editModel()),
            new CustomerTablePanel(customerModel.tableModel()));
    EntityPanel customerAddressPanel = new EntityPanel(customerAddressModel,
            new CustomerAddressEditPanel(customerAddressModel.editModel()));

    customerPanel.detail().add(customerAddressPanel);

    return List.of(customerPanel);
  }

  private static List<EntityPanel.Builder> createLookupPanelBuilders() {
    EntityPanel.Builder addressPanelBuilder = EntityPanel.builder()
            .entityType(Address.TYPE)
            .panel(connectionProvider -> {
              SwingEntityModel addressModel =
                      new SwingEntityModel(Address.TYPE, connectionProvider);

              return new EntityPanel(addressModel,
                      new AddressEditPanel(addressModel.editModel()));
            });

    return List.of(addressPanelBuilder);
  }

  public static void main(String[] args) {
    Locale.setDefault(new Locale("en", "EN"));
    EntityPanel.Config.TOOLBAR_CONTROLS.set(true);
    ReferentialIntegrityErrorHandling.REFERENTIAL_INTEGRITY_ERROR_HANDLING
            .set(ReferentialIntegrityErrorHandling.DISPLAY_DEPENDENCIES);
    EntityApplication.builder(StoreApplicationModel.class, StoreApplicationPanel.class)
            .domain(Store.DOMAIN)
            .defaultUser(User.parse("scott:tiger"))
            .start();
  }
}

1. Starting the application

An application is assembled and started with the EntityApplication builder, which handles the startup sequence: look and feel, login (unless a user is provided), connection, application model and panel construction, and the main frame. The main method is also the natural place to configure framework defaults — configuration values apply to every panel created after them. The Chinook demo exercises a good portion of the configuration surface:

public static void main(String[] args) throws CancelException {
  String language = UserPreferences.get(LANGUAGE_PREFERENCES_KEY, Locale.getDefault().getLanguage());
  Locale.setDefault(LANGUAGE_IS.equals(language) ? LOCALE_IS : LOCALE_EN);
  UIManager.put("PasswordField.showRevealButton", true);
  FrameworkIcons icons = FrameworkIcons.instance();
  icons.put("plus", ChinookAppPanel.class.getResource("plus.svg"));
  icons.put("minus", ChinookAppPanel.class.getResource("minus.svg"));
  icons.put("graph-pie", ChinookAppPanel.class.getResource("graph-pie.svg"));
  Completion.COMPLETION_MODE.set(Completion.Mode.AUTOCOMPLETE);
  EntityApplicationPanel.CACHE_ENTITY_PANELS.set(true);
  EntityApplicationPanel.SQL_TRACING.set(true);
  EntityPanel.Config.TOOLBAR_CONTROLS.set(true);
  EntityPanel.Config.WINDOW_TYPE.set(WindowType.FRAME);
  EntityEditPanel.Config.MODIFIED_WARNING.set(true);
  EntityEditPanel.Config.INCLUDE_INSPECTOR.set(true);
  // Add a CTRL modifier to the DELETE key shortcut for table panels
  EntityTablePanel.ControlKeys.DELETE.defaultKeystroke().update(keyStroke ->
          keyStroke(keyStroke.getKeyCode(), MENU_SHORTCUT_MASK));
  EntityTablePanel.Config.COLUMN_SELECTION.set(SelectionMode.MENU);
  EntityTablePanel.Config.AUTO_RESIZE_MODE_SELECTION.set(SelectionMode.MENU);
  EntityTablePanel.Config.INCLUDE_FILTERS.set(true);
  EntityTablePanel.Config.INCLUDE_INSPECTOR.set(true);
  EntityTablePanel.Config.INCLUDE_EXPORT.set(true);
  FilterTable.AUTO_RESIZE_MODE.set(JTable.AUTO_RESIZE_ALL_COLUMNS);
  FilterTable.ROWS_FILL_VIEWPORT.set(true);
  FilterTable.STOP_EDIT_ON_FOCUS_LOST.set(false);
  FilterTableCellRenderer.NUMERICAL_HORIZONTAL_ALIGNMENT.set(SwingConstants.CENTER);
  FilterTableCellRenderer.TEMPORAL_HORIZONTAL_ALIGNMENT.set(SwingConstants.CENTER);
  FilterTableHeaderRenderer.FOCUSED_COLUMN_INDICATOR.set(true);
  ValidIndicator.INDICATOR_CLASS.set("is.codion.plugin.flatlaf.indicator.FlatLafValidIndicator");
  CalendarPanel.WEEK_NUMBERS.set(true);
  ReferentialIntegrityErrorHandling.REFERENTIAL_INTEGRITY_ERROR_HANDLING
          .set(ReferentialIntegrityErrorHandling.DISPLAY_DEPENDENCIES);
  EntityApplication.builder(ChinookAppModel.class, ChinookAppPanel.class)
          .domain(Chinook.DOMAIN)
          .version(ChinookAppModel.VERSION)
          .defaultLookAndFeel(MaterialTheme.class)
          .defaultUser(User.parse("scott:tiger"))
          .start();
}

2. Layout

The root entity panels are laid out by an ApplicationLayout — by default a TabbedApplicationLayout, one tab per root panel, initialized lazily as they are first displayed. Supply a custom layout via the EntityApplicationPanel constructor to arrange the root panels differently.

3. SQL Tracing

Note
SQL Tracing is only available when using a local EntityConnection.

Application SQL Tracing can be enabled via the EntityApplicationPanel.SQL_TRACING configuration value.

This configures the underlying EntityConnection to trace its queries and adds a SQL Trace item under HelpLog main menu, with actions to enable tracing and view the trace log.

Disabling SQL Tracing clears the trace log.

EntityApplicationPanel.SQL_TRACING.set(true);

4. Examples