Class BaseMDIApplication
- All Implemented Interfaces:
ImageObserver,MenuContainer,Serializable,Accessible,RootPaneContainer,WindowConstants
BaseMDIApplication is the top-level JFrame that hosts:
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:
-
Nested Class Summary
Nested classes/interfaces inherited from class javax.swing.JFrame
JFrame.AccessibleJFrameNested classes/interfaces inherited from class java.awt.Frame
Frame.AccessibleAWTFrameNested classes/interfaces inherited from class java.awt.Window
Window.AccessibleAWTWindow, Window.TypeNested classes/interfaces inherited from class java.awt.Container
Container.AccessibleAWTContainerNested classes/interfaces inherited from class java.awt.Component
Component.AccessibleAWTComponent, Component.BaselineResizeBehavior, Component.BltBufferStrategy, Component.FlipBufferStrategy -
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final PropertiesParsed application properties created from constructor key-value pairs.Fields inherited from class javax.swing.JFrame
accessibleContext, rootPane, rootPaneCheckingEnabledFields inherited from class java.awt.Frame
CROSSHAIR_CURSOR, DEFAULT_CURSOR, E_RESIZE_CURSOR, HAND_CURSOR, ICONIFIED, MAXIMIZED_BOTH, MAXIMIZED_HORIZ, MAXIMIZED_VERT, MOVE_CURSOR, N_RESIZE_CURSOR, NE_RESIZE_CURSOR, NORMAL, NW_RESIZE_CURSOR, S_RESIZE_CURSOR, SE_RESIZE_CURSOR, SW_RESIZE_CURSOR, TEXT_CURSOR, W_RESIZE_CURSOR, WAIT_CURSORFields inherited from class java.awt.Component
BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENTFields inherited from interface java.awt.image.ImageObserver
ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTHFields inherited from interface javax.swing.WindowConstants
DISPOSE_ON_CLOSE, DO_NOTHING_ON_CLOSE, EXIT_ON_CLOSE, HIDE_ON_CLOSE -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedBaseMDIApplication(Object... keyVals) Protected constructor. -
Method Summary
Modifier and TypeMethodDescriptionprotected voidCreate and register the initial set of views shown in the application.protected voidOverride to define the default view placement.protected booleanWhether the JVM should terminate once the main frame has actually been disposed — that is, afterprepareForShutdown()has run and every openWindow(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.static BaseMDIApplicationReturns the singletonBaseMDIApplicationinstance for this JVM.protected StringReturns a stable application identifier used for persistence (window placement, saved desktop configuration, etc.).static StringAttempt to determine the framework version from the manifest or pom.properties.protected intOverride to opt in to a virtual desktop with the given column count.protected booleanhasSavedLayout(BaseView view) Returnstrueif the desktop has a saved layout entry for the given view (i.e.static voidlaunch(Supplier<? extends BaseMDIApplication> factory) Launch the application on the EDT using the provided factory.protected voidCalled once, after the application frame is first shown and Swing layout has stabilized.protected voidCalled after the application frame is resized or moved (debounced).protected voidPerforms framework-level shutdown work prior to disposing the application frame.protected voidEnable virtual desktop support using a sensible default debounce delay.protected voidstandardVirtualDesktopReady(VirtualView vv, Runnable defaultLayout, boolean applySavedLayout) protected voidprotected voidvirtualViewMove(BaseView view, int col, int constraint) Overload ofvirtualViewMove(BaseView, int, int, int, int)for zero deltas.protected voidvirtualViewMove(BaseView view, int col, int delh, int delv, int constraint) Moves the given view to the specified virtual desktop column and position.Methods inherited from class javax.swing.JFrame
addImpl, createRootPane, frameInit, getAccessibleContext, getContentPane, getDefaultCloseOperation, getGlassPane, getGraphics, getJMenuBar, getLayeredPane, getRootPane, getTransferHandler, isDefaultLookAndFeelDecorated, isRootPaneCheckingEnabled, paramString, processWindowEvent, remove, repaint, setContentPane, setDefaultCloseOperation, setDefaultLookAndFeelDecorated, setGlassPane, setIconImage, setJMenuBar, setLayeredPane, setLayout, setRootPane, setRootPaneCheckingEnabled, setTransferHandler, updateMethods inherited from class java.awt.Frame
addNotify, getCursorType, getExtendedState, getFrames, getIconImage, getMaximizedBounds, getMenuBar, getState, getTitle, isResizable, isUndecorated, remove, removeNotify, setBackground, setCursor, setExtendedState, setMaximizedBounds, setMenuBar, setOpacity, setResizable, setShape, setState, setTitle, setUndecoratedMethods inherited from class java.awt.Window
addPropertyChangeListener, addPropertyChangeListener, addWindowFocusListener, addWindowListener, addWindowStateListener, applyResourceBundle, applyResourceBundle, createBufferStrategy, createBufferStrategy, dispose, getBackground, getBufferStrategy, getFocusableWindowState, getFocusCycleRootAncestor, getFocusOwner, getFocusTraversalKeys, getIconImages, getInputContext, getListeners, getLocale, getModalExclusionType, getMostRecentFocusOwner, getOpacity, getOwnedWindows, getOwner, getOwnerlessWindows, getShape, getToolkit, getType, getWarningString, getWindowFocusListeners, getWindowListeners, getWindows, getWindowStateListeners, hide, isActive, isAlwaysOnTop, isAlwaysOnTopSupported, isAutoRequestFocus, isFocusableWindow, isFocusCycleRoot, isFocused, isLocationByPlatform, isOpaque, isShowing, isValidateRoot, pack, paint, postEvent, processEvent, processWindowFocusEvent, processWindowStateEvent, removeWindowFocusListener, removeWindowListener, removeWindowStateListener, reshape, setAlwaysOnTop, setAutoRequestFocus, setBounds, setBounds, setCursor, setFocusableWindowState, setFocusCycleRoot, setIconImages, setLocation, setLocation, setLocationByPlatform, setLocationRelativeTo, setMinimumSize, setModalExclusionType, setSize, setSize, setType, setVisible, show, toBack, toFrontMethods inherited from class java.awt.Container
add, add, add, add, add, addContainerListener, applyComponentOrientation, areFocusTraversalKeysSet, countComponents, deliverEvent, doLayout, findComponentAt, findComponentAt, getAlignmentX, getAlignmentY, getComponent, getComponentAt, getComponentAt, getComponentCount, getComponents, getComponentZOrder, getContainerListeners, getFocusTraversalPolicy, getInsets, getLayout, getMaximumSize, getMinimumSize, getMousePosition, getPreferredSize, insets, invalidate, isAncestorOf, isFocusCycleRoot, isFocusTraversalPolicyProvider, isFocusTraversalPolicySet, layout, list, list, locate, minimumSize, paintComponents, preferredSize, print, printComponents, processContainerEvent, remove, removeAll, removeContainerListener, setComponentZOrder, setFocusTraversalKeys, setFocusTraversalPolicy, setFocusTraversalPolicyProvider, setFont, transferFocusDownCycle, validate, validateTreeMethods inherited from class java.awt.Component
action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, createVolatileImage, createVolatileImage, disable, disableEvents, dispatchEvent, enable, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, getBaseline, getBaselineResizeBehavior, getBounds, getBounds, getColorModel, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusListeners, getFocusTraversalKeysEnabled, getFont, getFontMetrics, getForeground, getGraphicsConfiguration, getHeight, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getLocation, getLocation, getLocationOnScreen, getMouseListeners, getMouseMotionListeners, getMousePosition, getMouseWheelListeners, getName, getParent, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getSize, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, imageUpdate, inside, isBackgroundSet, isCursorSet, isDisplayable, isDoubleBuffered, isEnabled, isFocusable, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isMaximumSizeSet, isMinimumSizeSet, isPreferredSizeSet, isValid, isVisible, keyDown, keyUp, list, list, list, location, lostFocus, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, prepareImage, prepareImage, printAll, processComponentEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, processMouseWheelEvent, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, requestFocus, requestFocus, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, requestFocusInWindow, resize, resize, revalidate, setComponentOrientation, setDropTarget, setEnabled, setFocusable, setFocusTraversalKeysEnabled, setForeground, setIgnoreRepaint, setLocale, setMaximumSize, setMixingCutoutShape, setName, setPreferredSize, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycleMethods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitMethods inherited from interface java.awt.MenuContainer
getFont, postEvent
-
Field Details
-
_properties
Parsed application properties created from constructor key-value pairs.
-
-
Constructor Details
-
BaseMDIApplication
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 viaPropertyUtils.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 secondBaseMDIApplicationis 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
WindowListenerinstalled by this class). The default implementation delegates to theDesktopso 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(...). SeeexitOnClose()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, afterprepareForShutdown()has run and every openWindow(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 callSystem.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 returntrue.- Returns:
trueto callSystem.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
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
Returns the singletonBaseMDIApplicationinstance 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
nullif not yet constructed
-
standardVirtualDesktopReady
protected void standardVirtualDesktopReady(VirtualView vv, Runnable defaultLayout, boolean applySavedLayout) -
hasSavedLayout
Returnstrueif 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:
trueif a saved position exists for this view
-
virtualViewMove
Moves the given view to the specified virtual desktop column and position.- Parameters:
view- the view to movecol- the target virtual desktop columndelh- 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
Overload ofvirtualViewMove(BaseView, int, int, int, int)for zero deltas. -
standardVirtualDesktopRelayout
-
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.
- Reconfigure a
-
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
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
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
-