1 /*
2 * Tethys: GUI Utilities
3 * Copyright 2012-2026. Tony Washer
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17 package io.github.tonywasher.joceanus.tethys.core.pane;
18
19 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
20 import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
21 import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
22 import io.github.tonywasher.joceanus.tethys.api.pane.TethysUITabPaneManager;
23 import io.github.tonywasher.joceanus.tethys.core.base.TethysUICoreComponent;
24 import io.github.tonywasher.joceanus.tethys.core.factory.TethysUICoreFactory;
25
26 /**
27 * Tab Manager.
28 */
29 public abstract class TethysUICoreTabPaneManager
30 extends TethysUICoreComponent
31 implements TethysUITabPaneManager {
32 /**
33 * The gui factory.
34 */
35 private final TethysUICoreFactory<?> theGuiFactory;
36
37 /**
38 * The id.
39 */
40 private final Integer theId;
41
42 /**
43 * The Event Manager.
44 */
45 private final OceanusEventManager<TethysUIEvent> theEventManager;
46
47 /**
48 * The first child item.
49 */
50 private TethysUICoreTabItem theFirstChild;
51
52 /**
53 * The last child item.
54 */
55 private TethysUICoreTabItem theLastChild;
56
57 /**
58 * Is the pane enabled?
59 */
60 private boolean isEnabled;
61
62 /**
63 * Constructor.
64 *
65 * @param pFactory the factory
66 */
67 protected TethysUICoreTabPaneManager(final TethysUICoreFactory<?> pFactory) {
68 theGuiFactory = pFactory;
69 theId = pFactory.getNextId();
70 theEventManager = new OceanusEventManager<>();
71 isEnabled = true;
72 }
73
74 @Override
75 public Integer getId() {
76 return theId;
77 }
78
79 @Override
80 public OceanusEventRegistrar<TethysUIEvent> getEventRegistrar() {
81 return theEventManager.getEventRegistrar();
82 }
83
84 @Override
85 public TethysUICoreTabItem findItemByName(final String pName) {
86 /* loop through children */
87 TethysUICoreTabItem myChild = theFirstChild;
88 while (myChild != null) {
89 /* Break if we have found the item */
90 if (myChild.getName().equals(pName)) {
91 break;
92 }
93
94 /* Move to next child */
95 myChild = myChild.theNextSibling;
96 }
97
98 /* return the relevant child */
99 return myChild;
100 }
101
102 @Override
103 public TethysUICoreTabItem findItemByIndex(final int pIndex) {
104 /* loop through children */
105 TethysUICoreTabItem myChild = theFirstChild;
106 int myIndex = 0;
107 while (myChild != null) {
108 /* If the child is visible */
109 if (myChild.isVisible()) {
110 /* If this is the required index */
111 if (pIndex == myIndex) {
112 break;
113 }
114 myIndex++;
115 }
116
117 /* Move to next child */
118 myChild = myChild.theNextSibling;
119 }
120
121 /* return the relevant child */
122 return myChild;
123 }
124
125 @Override
126 public void enableItemByName(final String pName,
127 final boolean pEnabled) {
128 /* Look up child and adjust */
129 final TethysUICoreTabItem myItem = findItemByName(pName);
130 if (myItem != null) {
131 myItem.setEnabled(pEnabled);
132 }
133 }
134
135 /**
136 * Notify of selection.
137 *
138 * @param pItem the item that has been selected
139 */
140 protected void notifySelection(final Object pItem) {
141 theEventManager.fireEvent(TethysUIEvent.NEWVALUE, pItem);
142 }
143
144 @Override
145 public void setEnabled(final boolean pEnabled) {
146 /* If we are changing enabled state */
147 if (pEnabled != isEnabled) {
148 /* Set new enabled state */
149 isEnabled = pEnabled;
150
151 /* enable the tab */
152 enablePane(isEnabled);
153
154 /* loop through children */
155 TethysUICoreTabItem myChild = theFirstChild;
156 while (myChild != null) {
157 /* If the child is visible */
158 if (myChild.isVisible()) {
159 /* set correct enabled status */
160 myChild.enableTab(pEnabled
161 && myChild.isEnabled());
162 }
163
164 /* Move to next child */
165 myChild = myChild.theNextSibling;
166 }
167 }
168 }
169
170 /**
171 * Enable/disable the pane.
172 *
173 * @param pEnabled true/false
174 */
175 protected abstract void enablePane(boolean pEnabled);
176
177 /**
178 * TabItem class.
179 */
180 public abstract static class TethysUICoreTabItem
181 implements TethysUITabItem {
182 /**
183 * The pane to which this item belongs.
184 */
185 private final TethysUICoreTabPaneManager thePane;
186
187 /**
188 * The name of this item.
189 */
190 private final String theName;
191
192 /**
193 * The id of this item.
194 */
195 private final Integer theId;
196
197 /**
198 * The previous sibling of this item.
199 */
200 private TethysUICoreTabItem thePrevSibling;
201
202 /**
203 * The next sibling of this item.
204 */
205 private TethysUICoreTabItem theNextSibling;
206
207 /**
208 * Is the item visible (i.e. part of the actual tabs)?
209 */
210 private boolean isVisible;
211
212 /**
213 * Is the item enabled?
214 */
215 private boolean isEnabled;
216
217 /**
218 * Constructor.
219 *
220 * @param pPane the containing pane
221 * @param pName the name of the tab
222 */
223 protected TethysUICoreTabItem(final TethysUICoreTabPaneManager pPane,
224 final String pName) {
225 /* Store parameters */
226 thePane = pPane;
227 theName = pName;
228 isVisible = true;
229 isEnabled = true;
230
231 /* Create id */
232 theId = pPane.theGuiFactory.getNextId();
233
234 /* If the pane already has children */
235 final TethysUICoreTabItem myChild = thePane.theLastChild;
236 if (myChild != null) {
237 /* Link to last child */
238 myChild.theNextSibling = this;
239 thePrevSibling = myChild;
240
241 /* else set as first child */
242 } else {
243 thePane.theFirstChild = this;
244 }
245
246 /* Add as last child of pane */
247 thePane.theLastChild = this;
248 }
249
250 @Override
251 public String getName() {
252 return theName;
253 }
254
255 @Override
256 public Integer getId() {
257 return theId;
258 }
259
260 @Override
261 public TethysUICoreTabPaneManager getPane() {
262 return thePane;
263 }
264
265 @Override
266 public boolean isVisible() {
267 return isVisible;
268 }
269
270 @Override
271 public boolean isEnabled() {
272 return isEnabled;
273 }
274
275 @Override
276 public void setVisible(final boolean pVisible) {
277 /* If we are changing visibility */
278 if (pVisible != isVisible) {
279 /* Set new visibility */
280 isVisible = pVisible;
281
282 /* If we are showing the item */
283 if (pVisible) {
284 /* Attach to parent at required position */
285 attachToPane();
286
287 /* make sure that we have correct enable state */
288 enableTab(isEnabled);
289
290 /* else just detach item */
291 } else {
292 detachFromPane();
293 }
294 }
295 }
296
297 @Override
298 public void setEnabled(final boolean pEnabled) {
299 /* If we are changing enabled state */
300 if (pEnabled != isEnabled) {
301 /* Set new enabled state */
302 isEnabled = pEnabled;
303
304 /* If the pane is enabled and the tab is visible */
305 if (thePane.isEnabled
306 && isVisible) {
307 /* enable the tab */
308 enableTab(isEnabled);
309 }
310 }
311 }
312
313 /**
314 * Enable/disable the tab.
315 *
316 * @param pEnabled true/false
317 */
318 protected abstract void enableTab(boolean pEnabled);
319
320 /**
321 * Attach to pane.
322 */
323 protected abstract void attachToPane();
324
325 /**
326 * Detach from pane.
327 */
328 protected abstract void detachFromPane();
329
330 /**
331 * Notify of selection.
332 */
333 protected void notifySelection() {
334 getPane().notifySelection(this);
335 }
336
337 /**
338 * Count previous visible items.
339 *
340 * @return the count
341 */
342 public int countPreviousVisibleSiblings() {
343 /* Determine the previous visible sibling */
344 int myCount = 0;
345 TethysUICoreTabItem mySibling = thePrevSibling;
346 while (mySibling != null) {
347 if (mySibling.isVisible) {
348 myCount++;
349 }
350 mySibling = mySibling.thePrevSibling;
351 }
352 return myCount;
353 }
354 }
355 }