Class BaseMDIApplication

All Implemented Interfaces:
ImageObserver, MenuContainer, Serializable, Accessible, RootPaneContainer, WindowConstants
Direct Known Subclasses:
DemoApp, HelloMDI

public class BaseMDIApplication extends JFrame
Base class for all MDI applications.

BaseMDIApplication is the top-level JFrame that hosts:

  • The Desktop (MDI workspace)
  • A standard application JMenuBar
  • Framework menus (File, View, etc.)

Singleton Application Model

The MDI framework is designed around a single top-level application frame per JVM. This class enforces that constraint using an atomic set-once singleton reference.

Thread safety: construction uses an atomic compare-and-set to avoid race conditions in unusual scenarios (tests, tooling, or hosts that may instantiate from multiple threads).

Shutdown Policy

This framework class does not call System.exit(...) by default. Closing the main frame — by any means, including the platform's native close button — triggers prepareForShutdown(), disposes every open Window, then disposes the frame itself. Whether the JVM should then actually terminate is a separate question this class leaves to exitOnClose() (default false), because it is genuinely application-specific: some embedders host MDI inside a larger application and must not have it call System.exit; some want the process to keep running with no windows open, the conventional behavior for many native macOS applications (reactivated via the Dock).

With the default policy, disposing every window does not by itself guarantee the JVM exits — AWT's own internal event-dispatch and shutdown-management threads are not daemon threads, and are not required to notice that no windows remain. A single-window "tool" style application that wants the native close button and a "Quit" menu item to behave identically should override exitOnClose() to return true.

Virtual Desktop Support

The class provides an opt-in "virtual desktop" lifecycle (one-shot "ready" callback and debounced relayout callback) via prepareForVirtualDesktop().

Author:
heddle
See Also:
  • Field Details

    • _properties

      protected final Properties _properties
      Parsed application properties created from constructor key-value pairs.
  • Constructor Details

    • BaseMDIApplication

      protected BaseMDIApplication(Object... keyVals)
      Protected constructor.

      Applications subclass BaseMDIApplication. The constructor accepts a variable-length list of property key-value pairs used to configure frame size, title, background, etc. Properties are parsed via PropertyUtils.fromKeyValues(Object...).

      Singleton enforcement: If a second instance is constructed, this constructor throws IllegalStateException. Framework code must not terminate the JVM; it should fail fast and let the caller decide what to do.

      Parameters:
      keyVals - property key-value pairs
      Throws:
      IllegalStateException - if a second BaseMDIApplication is constructed
  • Method Details

    • addInitialViews

      protected void addInitialViews()
      Create and register the initial set of views shown in the application.

      The default implementation does not add any views. Subclasses should override to create and register their initial set of views.

    • prepareForShutdown

      protected void prepareForShutdown()
      Performs framework-level shutdown work prior to disposing the application frame.

      This method is called when the user attempts to close the main application window (see the WindowListener installed by this class). The default implementation delegates to the Desktop so that open views can be notified and given a chance to release resources and persist state.

      Subclassing: Applications may override to add custom shutdown behavior (stopping background workers, saving preferences, flushing logs, etc.). When overriding, call super.prepareForShutdown() as part of your implementation so the framework can notify views.

      No JVM termination: This framework method intentionally does not call System.exit(...). See exitOnClose() for the supported way to opt into JVM termination after shutdown.

    • exitOnClose

      protected boolean exitOnClose()
      Whether the JVM should terminate once the main frame has actually been disposed — that is, after prepareForShutdown() has run and every open Window (including this one) has been disposed — regardless of whether that happened via the platform's native close button, a "Quit" menu item, or any other window-closing gesture.

      The default is false: disposing every window does not by itself call System.exit(...), matching this class's documented "Shutdown Policy." That default is correct for an MDI frame embedded inside a larger application, or for an application that intends to keep running with no windows open. A single-window "tool" style application — where the native close button and any "Quit" action should behave identically — should override this to return true.

      Returns:
      true to call System.exit(int) once the frame is disposed; false (the default) to leave JVM termination to something else (a "Quit" menu item, a shutdown hook, or simply letting the process keep running)
    • getVirtualDesktopColumns

      protected int getVirtualDesktopColumns()
      Override to opt in to a virtual desktop with the given column count. Return 0 to disable.
    • getApplicationId

      protected String getApplicationId()
      Returns a stable application identifier used for persistence (window placement, saved desktop configuration, etc.).

      The default implementation returns getClass().getSimpleName(), which is the simple name of the class that contains the main program. Subclasses may override to provide a shorter or more user-friendly identifier, but it should remain stable over time to avoid breaking persisted settings.

      Returns:
      a stable, non-null application identifier
    • getApplication

      public static BaseMDIApplication getApplication()
      Returns the singleton BaseMDIApplication instance for this JVM.

      The instance is established during construction using an atomic set-once operation. If this method is called before the application is constructed, it returns null.

      Returns:
      the singleton application instance, or null if not yet constructed
    • standardVirtualDesktopReady

      protected void standardVirtualDesktopReady(VirtualView vv, Runnable defaultLayout, boolean applySavedLayout)
    • hasSavedLayout

      protected boolean hasSavedLayout(BaseView view)
      Returns true if the desktop has a saved layout entry for the given view (i.e. it was present in the configuration file).

      Use this in defaultViewLayout() to skip views whose positions have already been restored from saved config:

         if (!hasSavedLayout(myView)) vv.moveTo(myView, col, constraint);
       
      Parameters:
      view - the view to check
      Returns:
      true if a saved position exists for this view
    • virtualViewMove

      protected void virtualViewMove(BaseView view, int col, int delh, int delv, int constraint)
      Moves the given view to the specified virtual desktop column and position.
      Parameters:
      view - the view to move
      col - the target virtual desktop column
      delh - horizontal delta from constraint position (positive = right, negative = left)
      delv - vertical delta from constraint position (positive = down, negative = up)
      constraint - position constraint (e.g., VirtualView.UPPERLEFT, CENTER)
    • virtualViewMove

      protected void virtualViewMove(BaseView view, int col, int constraint)
    • standardVirtualDesktopRelayout

      protected void standardVirtualDesktopRelayout(VirtualView vv)
    • prepareForVirtualDesktop

      protected void prepareForVirtualDesktop()
      Enable virtual desktop support using a sensible default debounce delay.
    • onVirtualDesktopReady

      protected void onVirtualDesktopReady()
      Called once, after the application frame is first shown and Swing layout has stabilized.

      Typical uses:

      • Reconfigure a VirtualView
      • Place default view locations
      • Load and apply persisted desktop configuration

      Default implementation does nothing.

    • onVirtualDesktopRelayout

      protected void onVirtualDesktopRelayout()
      Called after the application frame is resized or moved (debounced).

      Intended for lightweight geometry updates such as:

       virtualView.reconfigure();
       

      Default implementation does nothing.

    • defaultViewLayout

      protected void defaultViewLayout()
      Override to define the default view placement.
    • getFrameworkVersion

      public static String getFrameworkVersion()
      Attempt to determine the framework version from the manifest or pom.properties.

      This is used in the "About" dialog and elsewhere. If the version cannot be determined, returns "(development build)".

      Returns:
      framework version string
    • launch

      public static void launch(Supplier<? extends BaseMDIApplication> factory)
      Launch the application on the EDT using the provided factory.

      This helper ensures Swing construction and visibility occur on the Event Dispatch Thread (EDT).

      Parameters:
      factory - supplier that creates the application instance