
com.pekinsoft.framework.ToolBarGenerator Maven / Gradle / Ivy
/*
* Copyright (C) 2024 PekinSOFT Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* *****************************************************************************
* Project : application-framework-api
* Class : ToolBarGenerator.java
* Author : Sean Carrick
* Created : Jul 14, 2024
* Modified : Jul 14, 2024
*
* Purpose: See class JavaDoc for explanation
*
* Revision History:
*
* WHEN BY REASON
* ------------ ------------------- -----------------------------------------
* Jul 14, 2024 Sean Carrick Initial creation.
* *****************************************************************************
*/
package com.pekinsoft.framework;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.*;
import javax.swing.*;
/**
* The {@code ToolBarGenerator} is used by the {@link GlobalActionSystem} to
* create a {@link java.util.List list} of {@link javax.swing.JToolBar toolbars}
* that can be added to an {@link Application Application's} main window.
*
* @status TESTED: Good to Go
*
* @author Sean Carrick <sean at pekinsoft dot com>
*
* @version 2.4
* @since 1.5
*/
class ToolBarGenerator {
/**
* Generates a list of {@link JToolBar toolbars} that is returned to the
* calling {@code Application}. This list is generated from all
* {@link ActionX} instances contained within the supplied list of
* {@link ActionMap ActionMaps} that desire to be installed into a toolbar.
*
* This method is guaranteed to never return {@code null}.
*
* @param ctx the {@link ApplicationContext} in which we are running
* @param actionMaps a list of ActionMap instances from which the actions
* may be obtained
*
* @return a list of toolbars, or an empty list if no actions should be
* included in a toolbar
*/
static List createToolBars(ApplicationContext ctx, List actionMaps) {
context = ctx;
final List toolBarsList = new ArrayList<>();
final List allToolBarActions = new ArrayList<>();
/*
* First, get a list of all actions, but only keep those that are to be
* installed into a toolbar. These are actions that have showInToolbar
* set to true.
*/
for (ActionMap actionMap : actionMaps) {
if (actionMap.keys() != null) {
for (Object key : actionMap.keys()) {
Action a = actionMap.get(key);
if (a instanceof ActionX action) {
if (action.isShowInToolBar()) {
ResourceMap rm = action.getResourceMap();
String tbName = action.getToolbarName();
if (tbName != null && !tbName.isBlank()
&& !tbName.isEmpty()) {
logger.log(Level.DEBUG, "Adding ActionX \"{0}\" "
+ "to toolbar {1}.",
action.getActionCommand(), tbName);
allToolBarActions.add(action);
}
}
}
}
} else if (actionMap.allKeys() != null) {
for (Object key : actionMap.allKeys()) {
Action a = actionMap.get(key);
if (a instanceof ActionX action) {
if (action.isShowInToolBar()) {
ResourceMap rm = action.getResourceMap();
String tbName = action.getToolbarName();
if (tbName != null && !tbName.isBlank()
&& !tbName.isEmpty()) {
logger.log(Level.DEBUG, "Adding ActionX \"{0}\" "
+ "to toolbar {1}.",
action.getActionCommand(), tbName);
allToolBarActions.add(action);
}
}
}
}
}
}
/*
* Once we have all of the actions that are to be installed in the
* toolbars, we need to sort them by toolbar.
*/
for (ActionX action : allToolBarActions) {
String tbName = action.getToolbarName();
if (!actionsByToolbar.containsKey(tbName)) {
actionsByToolbar.put(tbName, new ArrayList<>());
}
actionsByToolbar.get(tbName).add(action);
}
/*
* Now, we need to get the toolbars ordered by their index position hint.
*/
Map> toolbarsByIndex = new HashMap<>();
for (String tbName : actionsByToolbar.keySet()) {
ActionX zero = actionsByToolbar.get(tbName).get(0);
byte index = zero.getToolBarIndex();
toolbarsByIndex.put(index, actionsByToolbar.get(tbName));
}
/*
* With the toolbars mapped by their index hint, we need to order the
* actions within them.
*/
List tbIndices = new ArrayList<>(toolbarsByIndex.keySet());
Collections.sort(tbIndices);
for (Byte tbi : tbIndices) {
List actions = toolbarsByIndex.remove(tbi);
List actionIndices = new ArrayList<>();
for (ActionX action : actions) {
byte index = action.getToolBarActionIndex();
actionIndices.add(index);
}
Collections.sort(actionIndices);
Map indexedActions = new HashMap<>();
for (ActionX action : actions) {
byte index = action.getToolBarActionIndex();
indexedActions.put(index, action);
}
actions.clear();
for (Byte index : actionIndices) {
actions.add(indexedActions.get(index));
}
Collections.sort(actions, (ActionX a1, ActionX a2) -> {
byte a1Idx = a1.getToolBarActionIndex();
byte a2Idx = a2.getToolBarActionIndex();
return Byte.compare(a1Idx, a2Idx);
});
toolbarsByIndex.put(tbi, actions);
}
/*
* With both the toolbars sorted by their index hints, and the actions
* within the toolbars sorted by their index hints, we can now build the
* toolbars into our toolbars list.
*/
for (Byte tbi : tbIndices) {
List tbActions = toolbarsByIndex.get(tbi);
JToolBar toolBar = new JToolBar();
toolBar.setName(tbActions.get(0).getToolbarName());
toolBar.setFloatable(false);
boolean sepAdded = false;
for (ActionX action : tbActions) {
AbstractButton button;
if (!sepAdded && action.isToolBarSeparatorBefore()) {
toolBar.addSeparator();
}
if (action.isStateAction()) {
button = createToggleButton(action, toolBar);
} else {
button = createButton(action);
}
button.addMouseListener(new ActionHelpProvider(context));
toolBar.add(button);
sepAdded = false;
if (action.isToolBarSeparatorAfter()) {
toolBar.addSeparator();
sepAdded = true;
}
}
if (toolBar.getComponent(0) instanceof JSeparator) {
toolBar.remove(0);
}
int compCount = toolBar.getComponentCount();
if (compCount > 0) {
if (toolBar.getComponent(compCount - 1) instanceof JSeparator) {
toolBar.remove(compCount - 1);
}
}
toolBar.putClientProperty("hideActionText", true);
toolBarsList.add(toolBar);
}
return toolBarsList;
}
private static JButton createButton(ActionX action) {
if (action == null) {
return null;
}
JButton button = new JButton(action);
String name = action.getActionCommand();
if (name == null) {
name = action.getName();
}
button.setName(name + "Button");
button.putClientProperty("hideActionText", true);
button.setIconTextGap(4);
button.setHorizontalAlignment(SwingConstants.CENTER);
return button;
}
private static JToggleButton createToggleButton(ActionX action, JToolBar toolBar) {
if (!action.isStateAction()) {
return null;
}
String groupId = MenuGenerator.groupName;
if (groupId != null) {
int hashCode = -1;
hashCode = Objects.hashCode(action);
hashCode ^= Objects.hashCode(toolBar);
if (!buttonGroups.containsKey(hashCode)) {
buttonGroups.put(hashCode, new ButtonGroup());
}
action.putValue(ActionX.GROUP, String.valueOf(hashCode));
groupId = String.valueOf(hashCode);
}
ButtonGroup group = buttonGroups.get(Integer.valueOf(groupId));
JToggleButton button = new JToggleButton(action);
String name = action.getActionCommand();
if (name == null) {
name = action.getName();
}
button.setName(name + "Button");
button.putClientProperty("hideActionText", true);
if (group != null) {
group.add(button);
}
return button;
}
private ToolBarGenerator() {
// No instantiation necessary.
}
private static ApplicationContext context;
private static final Logger logger = System.getLogger(ToolBarGenerator.class.getName());
private static final Map> actionsByToolbar = new HashMap<>();
private static final Map buttonGroups = new HashMap<>();
}