1 /*
2 * *************************************************************************************************************************************************************
3 *
4 * SteelBlue: DCI User Interfaces
5 * http://tidalwave.it/projects/steelblue
6 *
7 * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8 *
9 * *************************************************************************************************************************************************************
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * 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
17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18 *
19 * *************************************************************************************************************************************************************
20 *
21 * git clone https://bitbucket.org/tidalwave/steelblue-src
22 * git clone https://github.com/tidalwave-it/steelblue-src
23 *
24 * *************************************************************************************************************************************************************
25 */
26 package it.tidalwave.ui.core.spi;
27
28 import jakarta.annotation.Nonnull;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.function.Function;
35 import it.tidalwave.ui.core.PanelGroupControl;
36 import it.tidalwave.ui.core.PanelGroupProvider;
37 import org.apiguardian.api.API;
38 import it.tidalwave.util.As;
39 import it.tidalwave.util.ShortNames;
40 import lombok.RequiredArgsConstructor;
41 import lombok.experimental.Delegate;
42 import lombok.extern.slf4j.Slf4j;
43 import static org.apiguardian.api.API.Status.EXPERIMENTAL;
44 import static java.util.stream.Collectors.*;
45
46 /***************************************************************************************************************************************************************
47 *
48 * A support implementation of {@link PanelGroupControl}.
49 *
50 * @param <T> the type of the top container
51 * @param <S>
52 * @since 2.0-ALPHA-3
53 * @author Fabrizio Giudici
54 *
55 **************************************************************************************************************************************************************/
56 @API(status = EXPERIMENTAL)
57 @RequiredArgsConstructor @Slf4j
58 public abstract class PanelGroupControlSupport<T, S> implements As, PanelGroupControl<T>
59 {
60 @Delegate @Nonnull
61 private final As delegate = As.forObject(this);
62
63 @Nonnull
64 private final Function<As, Collection<? extends PanelGroupProvider<S>>> pgpProvider;
65
66 /***********************************************************************************************************************************************************
67 *
68 **********************************************************************************************************************************************************/
69 protected PanelGroupControlSupport()
70 {
71 this(PanelGroupControlSupport::defaultPanelGroupProviders);
72 }
73
74 /***********************************************************************************************************************************************************
75 * {@inheritDoc}
76 **********************************************************************************************************************************************************/
77 @Override
78 public void setup (@Nonnull final Configuration<T> configuration)
79 {
80 final var topContainersByGroup = configuration.getTopContainersByGroup();
81 final var providersByGroup = new HashMap<Group, List<PanelGroupProvider<S>>>();
82 pgpProvider.apply(this).forEach(p -> providersByGroup.computeIfAbsent(p.getGroup(), ignored -> new ArrayList<>()).add(p));
83 log.debug("Providers by placement:");
84 providersByGroup.forEach((placement, provider) -> log.debug(">>>> {}: {}", placement, ShortNames.shortIds(provider)));
85 final var unboundPlacements = providersByGroup.keySet().stream().filter(p -> !topContainersByGroup.containsKey(p)).collect(toList());
86
87 if (!unboundPlacements.isEmpty())
88 {
89 throw new RuntimeException("No top container(s) provider for " + unboundPlacements);
90 }
91
92 providersByGroup.forEach((group, providers) ->
93 assemble(group, providers, topContainersByGroup.get(group), configuration.getGroupOptions(), configuration.getOptions()));
94 }
95
96 /***********************************************************************************************************************************************************
97 * Assemble a set of panes for the given group.
98 * @param group the {@code Group}
99 * @param panelProviders the {@code PanelGroupProvider}s associated to the given {@code Group}
100 * @param topContainer the top container
101 * @param groupOptions options for each group
102 * @param options options for doing the job
103 **********************************************************************************************************************************************************/
104 protected abstract void assemble (@Nonnull final Group group,
105 @Nonnull final List<? extends PanelGroupProvider<S>> panelProviders,
106 @Nonnull final T topContainer,
107 @Nonnull final Map<Group, List<Options>> groupOptions,
108 @Nonnull final List<Options> options);
109
110 /***********************************************************************************************************************************************************
111 *
112 **********************************************************************************************************************************************************/
113 @Nonnull
114 private static <S> Collection<PanelGroupProvider<S>> defaultPanelGroupProviders (@Nonnull final As as)
115 {
116 return as.asMany(As.<PanelGroupProvider<S>>type(PanelGroupProvider.class));
117 }
118 }