PanelGroupControl.java

/*
 * *************************************************************************************************************************************************************
 *
 * SteelBlue: DCI User Interfaces
 * http://tidalwave.it/projects/steelblue
 *
 * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
 *
 * *************************************************************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
 *
 * *************************************************************************************************************************************************************
 *
 * git clone https://bitbucket.org/tidalwave/steelblue-src
 * git clone https://github.com/tidalwave-it/steelblue-src
 *
 * *************************************************************************************************************************************************************
 */
package it.tidalwave.ui.core;

import jakarta.annotation.Nonnull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apiguardian.api.API;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
import static lombok.AccessLevel.PRIVATE;

/***************************************************************************************************************************************************************
 *
 * This service looks up {@link PanelGroupProvider}s that describe portions of the User Interface and places them in the desired region of the main window.
 * Calling the method {@link #setup(Configuration)} with the proper configuration, the desired panel groups can be bound to existing UI controls. The runtime
 * will scan for instances of {@link PanelGroupProvider} that declare and instantiate panels to be associated to each group.
 * Calling the method {@link #show(Object)} one of possibly many panels in the same group is brought to visibility. If the system includes a
 * message bus implementing {@link it.tidalwave.messagebus.MessageBus}, it is also possible to pick the shown panel by publishing the event
 * {@link it.tidalwave.ui.core.message.PanelShowRequest}; the event {@link it.tidalwave.ui.core.message.PanelShownNotification} will be published back to
 * confirm the operation.
 *
 * @param   <T> the concrete type of the top container (depending on the UI technology)
 * @since       2.0-ALPHA-3
 * @see         PanelGroupProvider
 * @author      Fabrizio Giudici
 *
 **************************************************************************************************************************************************************/
@API(status = EXPERIMENTAL)
public interface PanelGroupControl<T>
  {
    /***********************************************************************************************************************************************************
     * The group in the main window.
     **********************************************************************************************************************************************************/
    public static interface Group {}

    /***********************************************************************************************************************************************************
     * Standard groups.
     **********************************************************************************************************************************************************/
    public enum DefaultGroups implements Group
      {
        LEFT, RIGHT, CENTER, BOTTOM
      }

    /***********************************************************************************************************************************************************
     * A bag of configuration settings for {@code PanelGroupProvider}.
     **********************************************************************************************************************************************************/
    @RequiredArgsConstructor(access = PRIVATE) @Getter @ToString
    public static class Configuration<T>
      {
        @Nonnull
        private final Map<Group, T> topContainersByGroup;

        @Nonnull
        private final Map<Group, List<Options>> groupOptions;

        @Nonnull
        private final List<Options> options;

        /*******************************************************************************************************************************************************
         * Specifies the configuration for a group.
         * @see       Options
         * @param     group           the group
         * @param     topContainer    the concrete UI container that will be associated to the group
         * @param     groupOptions    {@link Options} for this group
         * @return                    a copy of itself in chaining invocation fashion
         ******************************************************************************************************************************************************/
        @Nonnull
        public Configuration<T> withGroup (@Nonnull final Group group, @Nonnull final T topContainer, @Nonnull final Options ... groupOptions)
          {
            final var tcbs = new HashMap<>(topContainersByGroup);
            final var so = new HashMap<>(this.groupOptions);
            tcbs.put(group, topContainer);
            so.computeIfAbsent(group, s -> new ArrayList<>()).addAll(List.of(groupOptions));
            return new Configuration<>(tcbs, so, this.options);
          }

        /*******************************************************************************************************************************************************
         * Specifies global configuration {@link Options} that are applied to all groups.
         * @see       Options
         * @param     options         the options
         * @return                    a copy of itself in chaining invocation fashion
         ******************************************************************************************************************************************************/
        @Nonnull
        public final Configuration<T> withOptions (@Nonnull final Options ... options)
          {
            return new Configuration<>(topContainersByGroup, groupOptions, List.of(options));
          }
      }

    /***********************************************************************************************************************************************************
     * Options for the {@link #setup(Configuration)} method.
     * @see   Configuration#withGroup(Group, Object, Options...) 
     * @see   Configuration#withOptions(Options...)
     **********************************************************************************************************************************************************/
    public static enum Options
      {
        /** Use a wrapper container even when there is a single element in a group. */
        ALWAYS_WRAP,
        /** Use an Accordion wrapper. */
        USE_ACCORDION,
        /** Disable animation when expanding/collapsing the Accordion. */
        DISABLE_ACCORDION_ANIMATION
      }

    /***********************************************************************************************************************************************************
     * Sets up panel groups according to the given {@link Configuration}.
     * @param   configuration   the configuration
     **********************************************************************************************************************************************************/
    public void setup (@Nonnull final Configuration<T> configuration);

    /***********************************************************************************************************************************************************
     * Sets the shown object in a group.
     * @param   object    the object to show
     **********************************************************************************************************************************************************/
    public void show (@Nonnull Object object);

    /***********************************************************************************************************************************************************
     * {@return an empty {@link Configuration}}.
     **********************************************************************************************************************************************************/
    @Nonnull
    public default Configuration<T> config()
      {
        return new Configuration<>(Map.of(), Map.of(), List.of());
      }
  }