Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

311
LINES

< > BotCompany Repo | #1016948 // installInternalFrameSwitcher_v2

JavaX fragment (include)

sbool installInternalFrameSwitcher_v2_debug;

svoid installInternalFrameSwitcher_v2(final JDesktopPane desktop) {
  swing {
    new DesktopListener desktopListener;
    desktop.addContainerListener(desktopListener);
  
    new SwitchDispatcher<JInternalFrame>(new DesktopSwitcher(desktop), desktopListener).start();
  }
}

sclass JInternalFrameCellRenderer extends DefaultListCellRenderer {
  static int marginW = 20, marginH = 3;
  
  public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    setText(((JInternalFrame) value).getTitle());
    setMargin(marginW, marginH, this);
    ret c;
  }
}

sclass DesktopListener extends ContainerAdapter implements SwitchableComponentsListener<JInternalFrame> {
  private final List<JInternalFrame> frames = new ArrayList<>();
  private final boolean titleOptional;
  private final InternalFrameAdapter frameActivatedListener = new InternalFrameAdapter() {
      @Override
      public void internalFrameActivated(InternalFrameEvent e) {
          JInternalFrame frame = e.getInternalFrame();
          frames.remove(frame);
          frames.add(0, frame);
      }
  };

  public DesktopListener() {
      this(false);
  }

  public DesktopListener(boolean titleOptional) {
      this.titleOptional = titleOptional;
  }

  @Override
  public void componentAdded(final ContainerEvent e) {
      if (e.getChild() instanceof JInternalFrame) {
          final JInternalFrame frame = (JInternalFrame) e.getChild();
          if (isTitleOptional() || frame.getTitle() != null && !frame.getTitle().trim().isEmpty()) {
              frames.add(frame);
              frame.addInternalFrameListener(frameActivatedListener);
          }
      }
  }

  @Override
  public void componentRemoved(final ContainerEvent e) {
      if (e.getChild() instanceof JInternalFrame) {
          JInternalFrame frame = (JInternalFrame) e.getChild();
          frames.remove(frame);
          frame.removeInternalFrameListener(frameActivatedListener);
      }
  }

  private boolean isTitleOptional() {
      return titleOptional;
  }

  public List<JInternalFrame> getSwitchableComponentList() {
      return frames;
  }
}

sclass DesktopSwitcher implements Switcher<JInternalFrame> {
  private final JDesktopPane jDesktopPane;
  private SwitchDialog<JInternalFrame> switchDialog;

  public DesktopSwitcher(JDesktopPane jDesktopPane) {
      this.jDesktopPane = jDesktopPane;
      switchDialog = new SwitchDialog<>(SwingUtilities.getWindowAncestor(jDesktopPane), new ArrayList<JInternalFrame>());
      initMouseListener();
  }

  public void previous(List<JInternalFrame> switchableComponentList) {
      showMenu(switchableComponentList);
      switchDialog.selectPrevious();
  }

  public void next(List<JInternalFrame> switchableComponentList) {
      showMenu(switchableComponentList);
      switchDialog.selectNext();
  }

  public void dismiss() {
      hideMenu();
  }

  @Override
  public JDesktopPane getDesktop() {
      return jDesktopPane;
  }

  @Override
  public boolean hasFocus() {
      return switchDialog.hasFocus() || switchDialog.getList().hasFocus();
  }

  public SwitchDialog<JInternalFrame> getSwitchDialog() {
      return switchDialog;
  }

  private void showMenu(List<JInternalFrame> switchableComponentList) {
      switchDialog.setSwitchableComponents(switchableComponentList);
      if (!switchableComponentList.isEmpty()) {
          switchDialog.pack();
          switchDialog.setLocationRelativeTo(jDesktopPane);
          switchDialog.setVisible(true);
      }
  }

  private void hideMenu() {
    if (switchDialog != null && switchDialog.isVisible()) {
      pcall {
        JInternalFrame selected = switchDialog.getSelected();
        if (selected != null) {
            switchDialog.unselect();
            selected.setSelected(true);
            selected.toFront();
        }
      }
      switchDialog.dispose();
    }
  }

  private void initMouseListener() {
      switchDialog.getList().addMouseListener(new MouseAdapter() {
          @Override
          public void mouseReleased(final MouseEvent e) {
              hideMenu();
          }
      });
  }
}

sclass SwitchDispatcher<T> implements KeyEventDispatcher {
  private static final KeyStroke nextStroke = KeyStroke.getKeyStroke("ctrl TAB");
  private static final KeyStroke previousStroke = KeyStroke.getKeyStroke("ctrl shift TAB");

  private final Switcher<T> switcher;
  private final SwitchableComponentsListener<T> desktopListener;

  public SwitchDispatcher(Switcher<T> switcher, SwitchableComponentsListener<T> switchableComponentsListener) {
      this.switcher = switcher;
      this.desktopListener = switchableComponentsListener;
  }

  public void start() {
      KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
  }

  public void stop() {
      KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
  }

  public boolean dispatchKeyEvent(KeyEvent e) {
      boolean shouldSwitch = isDesktopPaneFocused(e.getComponent(), switcher.getDesktop())
              || switcher.hasFocus();
      if (!shouldSwitch) {
          return false;
      }

      KeyStroke keyStrokeForEvent = KeyStroke.getKeyStrokeForEvent(e);
      boolean next = nextStroke.equals(keyStrokeForEvent);
      boolean previous = previousStroke.equals(keyStrokeForEvent);
      boolean dismiss = e.getKeyCode() == KeyEvent.VK_CONTROL && !e.isControlDown();

      if (installInternalFrameSwitcher_v2_debug) print("Have keystroke: " + keyStrokeForEvent + ", " + next + "/" + previous + "/" + dismiss);
      
      if (next) {
          switcher.next(desktopListener.getSwitchableComponentList());
      } else if (previous) {
          switcher.previous(desktopListener.getSwitchableComponentList());
      } else if (dismiss) {
          switcher.dismiss();
      }
      return next || previous || dismiss;
  }

  private boolean isDesktopPaneFocused(Component component, JDesktopPane desktop) {
      return getDesktopPaneParent(component) == desktop;
  }

  private JDesktopPane getDesktopPaneParent(Component component) {
      Component parent = component;
      while (parent != null && !(parent instanceof JDesktopPane)) {
          parent = parent.getParent();
      }
      return (JDesktopPane) parent;
  }
}

sinterface SwitchableComponentsListener<T> {
  /**
   * Get a list of the components that the user can switch through.
   * Ideally, this would be sorted by the last focused order.
   *
   * @return - list of switchable components of type T
   */
  List<T> getSwitchableComponentList();
}

/**
 * This class will do the actual switching based on the lists of components it receives.
 *
 * @param <T> - The type of the components that can be switched. {@link javax.swing.JInternalFrame} initially but
 *            will be extended for tabs and other components.
 */
sinterface Switcher<T> {
  /**
   * Trigger this to select the previous component in the list
   *
   * @param switchableComponentList - list of all the switchable components
   */
  void previous(List<T> switchableComponentList);

  /**
   * Trigger this to select the next component in the list
   *
   * @param switchableComponentList - list of all the switchable components
   */
  void next(List<T> switchableComponentList);

  /**
   * This method will hide the dialog that shows all the switchable components if it exists.
   */
  void dismiss();

  /**
   * Returns the desktop pane on which the switcher is working
   */
  JDesktopPane getDesktop();

  /**
   * Checks whether the switcher component currently has focus
   * @return - true if the switch dialog is open and has focus; false otherwise
   */
  boolean hasFocus();
}

sclass SwitchDialog<T> extends JDialog {
  private final JList<T> list;

  public SwitchDialog(Window owner, List<T> titles) {
    super(owner);
    setUndecorated(true);
    list = new JList<>(new Vector<>(titles));
    addFocusListener(focusLostListener);
    initList();
    setContentPane(jCenteredSection(" Frames ", list));
    pack();
  }

  private void initList() {
    list.setCellRenderer(new JInternalFrameCellRenderer);
    list.setSelectedIndex(0);
    list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    list.addFocusListener(focusLostListener);
    list.setSelectionModel(new DefaultListSelectionModel() {
      public void removeSelectionInterval(int index0, int index1) {}
      public void addSelectionInterval(int index0, int index1) {
        super.setSelectionInterval(index0, index1);
      }
    });
  }

  public void selectNext() {
    int indexToSelect = list.getSelectedIndex() != list.getModel().getSize() - 1
            ? list.getSelectedIndex() + 1
            : 0;
    list.setSelectedIndex(indexToSelect);
  }

  public void selectPrevious() {
    int indexToSelect = list.getSelectedIndex() != 0
            ? list.getSelectedIndex() - 1
            : list.getModel().getSize() - 1;
    list.setSelectedIndex(indexToSelect > -1 ? indexToSelect : 0);
  }

  public T getSelected() {
    return list.getSelectedValue();
  }
  
  public void unselect() {
    list.setSelectedIndex(-1);
  }

  public void setSwitchableComponents(List<T> switchableComponents) {
    T oldSelection = list.getSelectedValue();
    list.setListData(new Vector<>(switchableComponents));
    list.setSelectedValue(oldSelection, false);
  }

  public JList<T> getList() {
    return list;
  }

  private final FocusAdapter focusLostListener = new FocusAdapter {
    public void focusLost(FocusEvent e) {
      dispose();
    }
  };
}

Author comment

Began life as a copy of #1016825

download  show line numbers  debug dex  old transpilations   

Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1016948
Snippet name: installInternalFrameSwitcher_v2
Eternal ID of this version: #1016948/14
Text MD5: f0c4e3ee36cf88d4eaff3456c7eb859f
Author: stefan
Category: javax / gui
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2018-09-26 17:21:32
Source code size: 10033 bytes / 311 lines
Pitched / IR pitched: No / No
Views / Downloads: 339 / 396
Version history: 13 change(s)
Referenced in: #1006654 - Standard functions list 2 (LIVE, continuation of #761)
#1019718 - installInternalFrameSwitcher_v3