All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pushingpixels.radiance.component.api.common.JCommandButtonPanel Maven / Gradle / Ivy

Go to download

Demonstrating the abilities of the Swing UI Toolkit swingset2 and swingx aka swingset3

The newest version!
/*
 * Copyright (c) 2005-2022 Radiance Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  o Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  o Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  o Neither the name of the copyright holder nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.pushingpixels.radiance.component.api.common;

import org.pushingpixels.radiance.component.api.common.model.*;
import org.pushingpixels.radiance.component.api.common.projection.CommandButtonProjection;
import org.pushingpixels.radiance.component.api.common.projection.Projection;
import org.pushingpixels.radiance.component.internal.theming.common.ui.RadianceCommandButtonPanelUI;
import org.pushingpixels.radiance.component.internal.ui.common.CommandButtonPanelUI;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Panel that hosts command buttons. Provides support for button groups, single
 * selection mode (for toggle command buttons), same icon state / dimension and
 * column-fill / row-fill layout. Note that while this class is a part of public API,
 * it is highly recommended to use the {@link CommandPanelContentModel} and
 * {@link CommandPanelPresentationModel} instances used to project the command button panel
 * on screen for any dynamic manipulation of the state.
 *
 * 

* Under the default {@link CommandPanelPresentationModel.LayoutKind#ROW_FILL}, the buttons are * laid out in rows, never exceeding the available horizontal space. A vertical scroll bar * will kick in once there is not enough vertical space to show all the buttons. * The schematic below shows a row-fill command button panel: *

* *
 * +-----------------------------+-+
 * |                             |o|
 * | +----+ +----+ +----+ +----+ |o|
 * | | 01 | | 02 | | 03 | | 04 | |o|
 * | +----+ +----+ +----+ +----+ |o|
 * |                             | |
 * | +----+ +----+ +----+ +----+ | |
 * | | 05 | | 06 | | 07 | | 07 | | |
 * | +----+ +----+ +----+ +----+ | |
 * |                             | |
 * | +----+ +----+ +----+ +----+ | |
 * | | 09 | | 10 | | 11 | | 12 | | |
 * | +----+ +----+ +----+ +----+ | |
 * |                             | |
 * | +----+ +----+ +----+ +----+ | |
 * | | 13 | | 14 | | 15 | | 16 | | |
 * +-----------------------------+-+
 * 
* *

* Each row hosts four buttons, and the vertical scroll bar allows scrolling the * content up and down. *

* *

* Under the {@link CommandPanelPresentationModel.LayoutKind#COLUMN_FILL}, the buttons are laid * out in columns, never exceeding the available vertical space. A horizontal scroll * bar will kick in once there is not enough horizontal space to show all the * buttons. The schematic below shows a column-fill command button panel: *

* *
 * +---------------------------------+
 * |                                 |
 * | +----+ +----+ +----+ +----+ +---|
 * | | 01 | | 04 | | 07 | | 10 | | 13|
 * | +----+ +----+ +----+ +----+ +---|
 * |                                 |
 * | +----+ +----+ +----+ +----+ +---|
 * | | 02 | | 05 | | 08 | | 11 | | 14|
 * | +----+ +----+ +----+ +----+ +---|
 * |                                 |
 * | +----+ +----+ +----+ +----+ +---|
 * | | 03 | | 06 | | 09 | | 12 | | 15|
 * | +----+ +----+ +----+ +----+ +---|
 * |                                 |
 * +---------------------------------+
 * |oooo                             |
 * +---------------------------------+
 * 
* *

* Each column hosts three buttons, and the horizontal scroll bar allows * scrolling the content left and right. *

* * @author Kirill Grouchnikov */ public class JCommandButtonPanel extends JComponent implements Scrollable { /** * @see #getUIClassID */ public static final String uiClassID = "CommandButtonPanelUI"; private Projection projection; private CommandPanelContentModel panelContentModel; private CommandPanelPresentationModel panelPresentationModel; /** * List of titles for all button groups. * * @see #getGroupCount() * @see #getGroupTitleAt(int) */ private List groupTitles; /** * List of all button groups. * * @see #getGroupCount() * @see #getGroupButtons(int) */ private List> buttons; private ChangeListener contentChangeListener; /** * The button group for the single selection mode. */ private CommandToggleGroupModel buttonGroup; public JCommandButtonPanel(Projection projection) { this.projection = projection; this.panelContentModel = projection.getContentModel(); this.panelPresentationModel = projection.getPresentationModel(); this.buttons = new ArrayList<>(); this.groupTitles = new ArrayList<>(); populateContent(); this.contentChangeListener = (ChangeEvent changeEvent) -> populateContent(); this.panelContentModel.addChangeListener(this.contentChangeListener); this.updateUI(); } public Projection getProjection() { return this.projection; } private CommandButtonPresentationModel createBaseCommandPresentation() { return CommandButtonPresentationModel.builder() .setPresentationState(this.panelPresentationModel.getCommandPresentationState()) .setIconDimension(this.panelPresentationModel.getCommandIconDimension()) .setMenu(this.panelPresentationModel.isMenu()) .setHorizontalAlignment(this.panelPresentationModel.getCommandHorizontalAlignment()) .setPopupOrientationKind(this.panelPresentationModel.getPopupOrientationKind()) .build(); } private void populateContent() { this.groupTitles.clear(); this.buttons.clear(); this.removeAll(); if (this.panelContentModel.isSingleSelectionMode()) { this.buttonGroup = new CommandToggleGroupModel(); } else { this.buttonGroup = null; } int groupIndex = 0; CommandButtonPresentationModel baseCommandPresentation = createBaseCommandPresentation(); Command.CommandActionPreview commandPreviewListener = panelContentModel.getCommandPreviewListener(); for (CommandGroup groupModel : panelContentModel.getCommandGroups()) { this.groupTitles.add(groupIndex, groupModel.getTitle()); List list = new ArrayList<>(); this.buttons.add(groupIndex, list); for (Command command : groupModel.getCommands()) { // Apply overlay if we have it in the top-level projection CommandButtonPresentationModel commandPresentation = this.projection.getCommandOverlays().containsKey(command) ? baseCommandPresentation.overlayWith( this.projection.getCommandOverlays().get(command)) : baseCommandPresentation; CommandButtonProjection commandProjection = command.project(commandPresentation); // Propagate command overlays so that key tips are properly displayed // on secondary content of this command's projection commandProjection.setCommandOverlays(this.projection.getCommandOverlays()); JCommandButton button = commandProjection.buildComponent(); // Wire preview listener is configured on the panel content model if (commandPreviewListener != null) { button.getActionModel().addChangeListener(new ChangeListener() { boolean wasRollover = false; @Override public void stateChanged(ChangeEvent e) { boolean isRollover = button.getActionModel().isRollover(); if (wasRollover && !isRollover) { commandPreviewListener.onCommandPreviewCanceled(command); } if (!wasRollover && isRollover) { commandPreviewListener.onCommandPreviewActivated(command); } wasRollover = isRollover; } }); } this.addButtonToLastGroup(command, button); } groupIndex++; } } private void addButtonToLastGroup(Command command, JCommandButton commandButton) { if (this.groupTitles.size() == 0) { return; } int groupIndex = this.groupTitles.size() - 1; this.addButtonToGroup(this.groupTitles.get(groupIndex), this.buttons.get(groupIndex).size(), command, commandButton); } private void addButtonToGroup(String buttonGroupName, int indexInGroup, Command command, JCommandButton commandButton) { int groupIndex = this.groupTitles.indexOf(buttonGroupName); if (groupIndex < 0) { return; } commandButton.setIconDimension(this.panelPresentationModel.getCommandIconDimension()); commandButton.setPresentationState( this.panelPresentationModel.getCommandPresentationState()); this.add(commandButton); this.buttons.get(groupIndex).add(indexInGroup, commandButton); if (this.panelContentModel.isSingleSelectionMode() && command.isToggle()) { this.buttonGroup.add(command); } } /** * Returns the number of button groups in this panel. * * @return Number of button groups in this panel. */ public int getGroupCount() { return (this.groupTitles != null) ? this.groupTitles.size() : 0; } /** * Returns the title of the command group at the specified index. * * @param index Command group index. * @return Title of the command group at the specified index. */ public String getGroupTitleAt(int index) { return this.panelContentModel.getCommandGroups().get(index).getTitle(); } /** * Returns the UI delegate for this component. * * @return a CommandButtonPanelUI object * @see #setUI */ public CommandButtonPanelUI getUI() { return (CommandButtonPanelUI) ui; } @Override public void updateUI() { setUI(RadianceCommandButtonPanelUI.createUI(this)); } @Override public String getUIClassID() { return uiClassID; } /** * Returns the list of all buttons in the specified button group. Note that this method should only * be used sparingly when your UI logic has to work with the projected buttons instead of the original * (canonical) commands that define the content itself. * * @param groupIndex Group index. * @return Unmodifiable view on the list of all buttons in the specified button group. * @see #getGroupCount() */ public List getGroupButtons(int groupIndex) { return Collections.unmodifiableList(this.buttons.get(groupIndex)); } public Command getSelectedCommand() { if (this.panelContentModel.isSingleSelectionMode()) { for (List commandButtons : this.buttons) { for (JCommandButton commandButton : commandButtons) { Command curr = commandButton.getProjection().getContentModel(); if (curr.isToggleSelected()) { return curr; } } } } return null; } public void scrollToSelectedCommand() { if (this.panelContentModel.isSingleSelectionMode()) { for (List commandButtons : this.buttons) { for (JCommandButton commandButton : commandButtons) { Command curr = commandButton.getProjection().getContentModel(); if (curr.isToggleSelected()) { Rectangle selectionButtonBounds = commandButton.getBounds(); scrollRectToVisible(selectionButtonBounds); return; } } } } } @Override public Dimension getPreferredScrollableViewportSize() { return this.getPreferredSize(); } @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { return 30; } @Override public boolean getScrollableTracksViewportHeight() { return (this.getProjection().getPresentationModel().getLayoutKind() == CommandPanelPresentationModel.LayoutKind.COLUMN_FILL); } @Override public boolean getScrollableTracksViewportWidth() { return (this.getProjection().getPresentationModel().getLayoutKind() == CommandPanelPresentationModel.LayoutKind.ROW_FILL); } @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { return 10; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy