Class ViewManager

java.lang.Object
edu.cnu.mdi.view.ViewManager
All Implemented Interfaces:
Iterable<BaseView>

public class ViewManager extends Object implements Iterable<BaseView>
Singleton registry and UI coordinator for all BaseView instances in an MDI application.

Responsibilities

  • Maintain the ordered collection of currently-registered views.
  • Maintain the "Views" JMenu: one item per registered view, plus italic placeholder items for lazy configurations whose views have not yet been created.
  • Notify IViewListeners when views are added or removed.
  • Track the active VirtualView (if any) and route view activation requests to it.
  • Support lazy registration of views through ViewConfiguration.

Views menu conventions

Each realized view has a normal-weight menu item labelled with the view's title. Unrealized lazy configurations have an italic item labelled with the configuration's menu title (no "Create " prefix — the italic style alone signals "not yet open"). When a lazy view is realized its italic placeholder is replaced in-place by the normal item so that menu ordering is preserved.

Threading

All Swing state mutations (menu items, view visibility) are dispatched to the EDT. The backing view list is guarded by synchronized(this) for all add, remove, and iteration operations.

Migration note

This class previously extended Vector for legacy iteration compatibility. It now implements Iterable<BaseView> instead, which is sufficient for for-each loops and is a strictly cleaner contract. Code that called Vector-specific methods (e.g. elementAt, indexOf) should migrate to get(int) and getViews() respectively.

  • Method Details

    • getInstance

      public static ViewManager getInstance()
      Returns the singleton ViewManager instance, creating it on first call.
      Returns:
      the global ViewManager
    • iterator

      public Iterator<BaseView> iterator()
      Returns an iterator over the currently registered views in registration order.

      The iterator operates on a snapshot copy taken at call time, so it is safe to call add(BaseView) or remove(BaseView) while iterating without a ConcurrentModificationException. The snapshot reflects the state of the registry at the moment iterator() is called; views added or removed afterwards are not visible through the returned iterator.

      Specified by:
      iterator in interface Iterable<BaseView>
      Returns:
      a snapshot iterator; never null
    • getViews

      public List<BaseView> getViews()
      Returns an unmodifiable, point-in-time snapshot List of all currently registered views in registration order.

      The returned list will not reflect subsequent additions or removals. Callers that need to iterate once should prefer iterator(); callers that need random access or must pass a List to other APIs should use this method.

      Returns:
      an unmodifiable snapshot; never null
    • setViewMenu

      public void setViewMenu(JMenu viewMenu)
      Replace the managed Views menu.

      The new menu is immediately populated from the current set of registered views and unrealized lazy configurations.

      Parameters:
      viewMenu - the menu to manage; null clears the reference
    • getViewMenu

      public JMenu getViewMenu()
      Returns the managed Views menu, creating a default one lazily if none has been set via setViewMenu(JMenu).

      This method never returns null.

      Returns:
      the Views menu
    • add

      public boolean add(BaseView view)
      Register a view with this manager.

      A corresponding menu item is added to the Views menu. Registered IViewListeners are notified. If the view is a VirtualView it becomes the active virtual desktop.

      This method is idempotent: registering the same instance twice is a no-op.

      Parameters:
      view - the view to register; ignored if null or already registered
      Returns:
      true if the view was newly added
    • remove

      public boolean remove(BaseView view)
      Unregister a view.

      Its menu item is removed, registered listeners are notified, and the view is disposed on the EDT.

      Parameters:
      view - the view to remove; ignored if null or not registered
      Returns:
      true if the view was removed
    • clear

      public void clear()
      Removes all registered views through the standard cleanup path.

      Each view is disposed and its listeners are notified in reverse registration order so that dependent views are torn down before the views they depend on.

    • contains

      public boolean contains(BaseView view)
      Returns true if the given view is currently registered.
      Parameters:
      view - the view to test; null always returns false
      Returns:
      true if registered
    • size

      public int size()
      Returns the number of currently registered views.
      Returns:
      the view count; never negative
    • get

      public BaseView get(int index)
      Returns the view at the given zero-based index in registration order.
      Parameters:
      index - zero-based position
      Returns:
      the view at that position
      Throws:
      IndexOutOfBoundsException - if index is out of range
    • addConfiguration

      public void addConfiguration(ViewConfiguration<?> config)
      Register a ViewConfiguration.

      If the configuration is eager (ViewConfiguration.lazily is false) the view is created immediately by calling ViewConfiguration.getView(). If it is lazy, an italic placeholder item is inserted into the Views menu; the view is created only when the user selects that item.

      Parameters:
      config - the configuration to register; ignored if null
    • restorePreviouslyOpenLazyViews

      public void restorePreviouslyOpenLazyViews()
      Realizes every currently-unrealized lazy configuration that was open the last time Desktop's layout was saved -- the counterpart to Desktop's own position-only restoration, which can only reposition views the application already creates on its own; it has no way to reopen an optional (lazy) view the application doesn't otherwise create.

      Call this once at startup, after the saved layout has already been loaded (see Desktop#loadConfigurationFile(), invoked by BaseMDIApplication#standardVirtualDesktopReady before it runs the application's own default-layout hook) so that ViewConfiguration.wasOpenInSavedLayout() has saved data to check against -- calling this before the layout is loaded is a harmless no-op, not an error, since every probe simply reports false.

      Each newly-realized view's own ViewConfiguration.getView() call restores its saved position through the exact same path already used when a user manually opens a lazy view that happens to have saved layout data. Two things that path assumes are true only for a single, user-initiated open are corrected here for the bulk-restore case:

      • Menu placeholder. Realizing a lazy configuration by calling getView() directly (as opposed to clicking its italic placeholder, whose action listener also swaps the placeholder for the real menu item) leaves the stale italic placeholder in the Views menu next to a second, correct item -- ensureRealizedMenuItem(edu.cnu.mdi.view.BaseView) unconditionally appends one the moment the view registers itself. Swapped here exactly as the placeholder's own listener would.
      • Virtual-desktop column. Each restored view's placement independently navigates to its own saved column -- correct for a single interactive open, but restoring several views at once would leave whichever one finishes last silently deciding the startup column, undoing the application's own explicit startup placement (e.g. a defaultViewLayout() override that documents relying on running last to "win" the same placement race, for exactly this reason). The column showing when this method was called is restored via one more invokeLater, which FIFO ordering guarantees runs after every placement this method triggered.
    • makeViewVisibleInVirtualWorld

      public void makeViewVisibleInVirtualWorld(BaseView view)
      Ask the active VirtualView to scroll so that the column containing the given view becomes visible.

      This is a no-op if no virtual view is registered, or if view is itself the virtual view.

      Parameters:
      view - the view to make visible in the virtual desktop
    • addViewListener

      public void addViewListener(IViewListener listener)
      Add a view lifecycle listener.

      Duplicate registrations are silently ignored.

      Parameters:
      listener - the listener to add; ignored if null
    • removeViewListener

      public void removeViewListener(IViewListener listener)
      Remove a view lifecycle listener.
      Parameters:
      listener - the listener to remove; ignored if null