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

de.lessvoid.nifty.controls.tabs.TabGroupControl Maven / Gradle / Ivy

There is a newer version: 1.4.3
Show newest version
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package de.lessvoid.nifty.controls.tabs;

import de.lessvoid.nifty.EndNotify;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.controls.*;
import de.lessvoid.nifty.controls.tabs.builder.TabBuilder;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.events.ElementShowEvent;
import de.lessvoid.nifty.input.NiftyInputEvent;
import de.lessvoid.nifty.loaderv2.types.ElementType;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.tools.SizeValue;
import org.bushe.swing.event.EventTopicSubscriber;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.logging.Logger;

/**
 * This is the controller for the tab group.
 *
 * @author ractoc
 * @author Martin Karing <[email protected]>
 * @deprecated This class is not meant to be used in a final application. Rather use the {@link TabGroup} interface.
 */
@Deprecated
public class TabGroupControl extends AbstractController implements TabGroup {
  private static final int BUTTON_LEFT_MARGIN = -16;

  /**
   * This class is used for the event handlers that are needed for the tab group controls. It will force the tab group
   * to update the visibility settings of all tabs in case the element is shown.
   */
  private static final class TabGroupShowEventSubscriber implements EventTopicSubscriber {
    @Override
    public void onEvent(@Nonnull final String topic, @Nonnull final ElementShowEvent data) {
      final TabGroupControl control = data.getElement().getControl(TabGroupControl.class);
      if (control != null) {
        control.checkVisibility();
      }
    }
  }

  /**
   * This class is used for the event handlers that monitor the clicks on the buttons that are used to select the active
   * tab in a tab group.
   */
  private static final class ButtonClickEventSubscriber implements EventTopicSubscriber {
    /**
     * The tab group that is effected by this click.
     */
    private final TabGroupControl parentControl;

    /**
     * Create a instance of this event subscriber and set the tab group control that will be effected by this
     * subscriber.
     *
     * @param parent the tab group control that is the parent of this class
     */
    private ButtonClickEventSubscriber(final TabGroupControl parent) {
      parentControl = parent;
    }

    @Override
    public void onEvent(final String topic, @Nonnull final ButtonClickedEvent data) {
      Element element = data.getButton().getElement();
      if (element != null) {
        parentControl.processButtonClick(element);
      }
    }
  }

  /**
   * This end notification is supposed to used in case a check of the visibility values of the tab control is required
   * once a operation is done.
   */
  private static final class CheckVisibilityEndNotify implements EndNotify {
    /**
     * The tab group control that is the target for the visibility check.
     */
    @Nonnull
    private final TabGroupControl parentControl;

    /**
     * The next notification that is supposed to be called in chain.
     */
    @Nullable
    private final EndNotify next;

    /**
     * Constructor for the check visibility end notification.
     *
     * @param control    the tab group control that is the target
     * @param nextNotify the next notification to call or {@code null} in case there is none
     */
    private CheckVisibilityEndNotify(@Nonnull final TabGroupControl control, @Nullable final EndNotify nextNotify) {
      parentControl = control;
      next = nextNotify;
    }

    @Override
    public void perform() {
      parentControl.checkVisibility();
      if (next != null) {
        next.perform();
      }
    }
  }

  /**
   * This class is used to call the adding operation for a tab again, once the tab was moved to the proper location.
   * Hopefully people manage to add the tab at the right spot from the start, so using this class won't be needed that
   * often.
   */
  private static final class TabAddMoveEndNotify implements EndNotify {
    /**
     * The tab group control where the tab is supposed to be added to.
     */
    @Nonnull
    private final TabGroupControl parentControl;

    /**
     * The tab that is supposed to be added.
     */
    @Nonnull
    private final Tab tabToAdd;

    /**
     * Create a instance of this notification handler.
     *
     * @param control the tab group control where the tab is added to
     * @param tab     the tab that is added
     */
    private TabAddMoveEndNotify(@Nonnull final TabGroupControl control, @Nonnull final Tab tab) {
      parentControl = control;
      tabToAdd = tab;
    }

    @Override
    public void perform() {
      parentControl.addTab(tabToAdd);
    }
  }

  /**
   * The logger that takes care for the output of log messages in this class.
   */
  private static final Logger log = Logger.getLogger(TabGroupControl.class.getName());

  /**
   * The subscriber of the show events for this control. This is required to fix the visibility values one the tab
   * control is displayed.
   */
  @Nonnull
  private static final EventTopicSubscriber showEventSubscriber = new TabGroupShowEventSubscriber();

  /**
   * This subscriber is used to monitor the click events on the buttons.
   */
  @Nonnull
  private final EventTopicSubscriber buttonClickedSubscriber;

  /**
   * This is the panel that is supposed to hold the buttons used to change the currently visible tab.
   */
  @Nullable
  private Element tabButtonPanel;

  /**
   * This is the content panel that stores all tabs.
   */
  @Nullable
  private Element contentPanel;

  /**
   * The instance of the Nifty-GUI that is parent to this tab group control.
   */
  @Nullable
  private Nifty nifty;

  /**
   * The screen that is parent to the element this control is assigned to.
   */
  @Nullable
  private Screen screen;

  /**
   * The template of the button that is supposed to be used for each new tab.
   */
  @Nullable
  private ElementType buttonTemplate;

  /**
   * The index of the tab that is currently selected or {@code -1} in case no tab is visible.
   */
  private int selectedIndex;

  /**
   * This value is set true once the template is gone.
   */
  private boolean templateRemoved;

  public TabGroupControl() {
    //noinspection ThisEscapedInObjectConstruction
    buttonClickedSubscriber = new ButtonClickEventSubscriber(this);
    selectedIndex = -1;
  }

  @Override
  public void addTab(@Nonnull final Element tab) {
    final Tab tabControl = tab.getNiftyControl(Tab.class);
    if (tabControl == null) {
      throw new IllegalArgumentException("Element to add is not a tab.");
    }
    addTab(tabControl);
  }

  @Override
  public void addTab(@Nonnull final TabBuilder tabBuilder) {
    if (nifty == null || screen == null || contentPanel == null) {
      throw new IllegalStateException("Element is not bound yet. Can't add tabs.");
    }
    final Element tab = tabBuilder.build(nifty, screen, contentPanel);
    final Tab tabControl = tab.getNiftyControl(Tab.class);
    if (tabControl == null) {
      throw new IllegalStateException("Tab builder did not create a tab... WTF?!");
    }
    addTab(tabControl);
  }

  @Override
  public void bind(
      @Nonnull final Nifty nifty,
      @Nonnull final Screen screen,
      @Nonnull final Element element,
      @Nonnull final Parameters parameter) {
    bind(element);

    this.nifty = nifty;
    this.screen = screen;

    tabButtonPanel = element.findElementById("#tab-button-panel");
    contentPanel = element.findElementById("#tab-content-panel");

    if (tabButtonPanel == null) {
      log.severe("Panel for the tabs not found. Tab group will not work properly. Looked for: #tab-button-panel");
    } else {
      final Element buttonElement = tabButtonPanel.findElementById("#button-template");
      if (buttonElement == null) {
        log.severe("No template for tab button found. Tab group will be unable to display tabs. Looked for: " +
            "#button-template");
      } else {
        buttonTemplate = buttonElement.getElementType().copy();
        buttonElement.markForRemoval(new EndNotify() {
          @Override
          public void perform() {
            templateRemoved = true;
          }
        });
      }
    }
    if (contentPanel == null) {
      log.severe("Content panel not found. Tab group will be unable to display tab content. Looked for: " +
          "#tab-content-pane");
    }
  }

  @Nullable
  @Override
  public Tab getSelectedTab() {
    if (selectedIndex == -1 || contentPanel == null) {
      return null;
    }
    return contentPanel.getChildren().get(selectedIndex).getNiftyControl(Tab.class);
  }

  @Override
  public int getSelectedTabIndex() {
    return selectedIndex;
  }

  @Override
  public void init(@Nonnull final Parameters parameter) {
    super.init(parameter);

    if (contentPanel != null) {
      for (final Element element : contentPanel.getChildren()) {
        final Tab tabControl = element.getNiftyControl(Tab.class);
        if (tabControl == null) {
          log.warning("Element without tab control detected. Removing: " + element.getId());
          element.markForRemoval();
        } else {
          initTab(tabControl);
          selectedIndex = 0;
        }
      }
    }

    checkVisibility();
  }

  private void initTab(@Nonnull final Tab tab) {
    final int tabIndex = indexOf(tab);
    Element button = getButton(tabIndex);
    if (button == null) {
      if (buttonTemplate == null || nifty == null || screen == null || tabButtonPanel == null) {
        log.severe("Tab can't be initialized. Binding not done yet or binding failed.");
        return;
      }
      final ElementType newButtonTemplate = buttonTemplate.copy();
      newButtonTemplate.getAttributes().set("id", buildTabButtonName(tabIndex));
      button = nifty.createElementFromType(screen, tabButtonPanel, newButtonTemplate);
    }
    String buttonId = button.getId();
    if (buttonId != null) {
      nifty.subscribe(screen, buttonId, ButtonClickedEvent.class, buttonClickedSubscriber);
    }

    if (!button.isVisible()) {
      button.show();
    }

    final Button btnControl = button.getNiftyControl(Button.class);
    if (btnControl == null) {
      log.warning("Can't set label of tab selection element that is not a button.");
    } else {
      btnControl.setText(tab.getCaption());
    }

    if (tab instanceof TabGroupMember) {
      ((TabGroupMember) tab).setParentTabGroup(this);
    }
  }

  @Nonnull
  private String buildTabButtonName(final int index) {
    String tabButtonId = "#tabButton-" + index;
    if (tabButtonPanel != null) {
      tabButtonId = tabButtonPanel.getId() + tabButtonId;
    }
    return tabButtonId;
  }

  @Override
  public void addTab(@Nonnull final Tab tab) {
    Element tabElement = tab.getElement();
    if (tabElement != null) {
      Element tabParentElement = tabElement.getParent();
      if (contentPanel != null && !tabParentElement.equals(contentPanel)) {
        tabElement.markForMove(contentPanel, new TabAddMoveEndNotify(this, tab));
        return;
      }
    }

    initTab(tab);
    checkVisibility();
  }

  @Override
  public int indexOf(@Nonnull final Tab tab) {
    if (contentPanel == null) {
      return -1;
    }
    final int length = getTabCount();
    final List elementList = contentPanel.getChildren();
    int result = -1;
    for (int i = 0; i < length; i++) {
      if (tab.equals(elementList.get(i).getNiftyControl(Tab.class))) {
        result = i;
        break;
      }
    }
    return result;
  }

  @Override
  public int getTabCount() {
    return contentPanel != null ? contentPanel.getChildren().size() : 0;
  }

  /**
   * Get the button element at a specified index.
   * 

* This function ignores the template-button as needed. This is required because Nifty does not provide a blocking way * to remove a element from the GUI. * * @param index the index of the button * @return the element of the button or {@code null} in case there is no button assigned to this index */ @Nullable private Element getButton(final int index) { if (tabButtonPanel == null) { return null; } int realIndex = index; final List buttonList = tabButtonPanel.getChildren(); if (buttonList.isEmpty()) { return null; } if (!templateRemoved) { realIndex++; } if (realIndex >= buttonList.size()) { return null; } return tabButtonPanel.getChildren().get(realIndex); } /** * Get the tab control at a specified index. * * @param index the index of the tab control * @return the tab control */ @Nullable public Tab getTabAtIndex(final int index) { if (contentPanel == null) { return null; } return contentPanel.getChildren().get(index).getNiftyControl(Tab.class); } /** * Check the visibility settings of all tabs and correct it as needed. */ private void checkVisibility() { if (contentPanel == null) { return; } final int length = getTabCount(); final List tabList = contentPanel.getChildren(); for (int i = 0; i < length; i++) { final Element tab = tabList.get(i); final Element button = getButton(i); if (button == null) { log.warning("Something is wrong with the tabs. Tab button not there anymore."); continue; } if (i == selectedIndex) { if (!tab.isVisible()) { tab.show(); } if (!"nifty-tab-button-active".equals(button.getStyle())) { button.setStyle("nifty-tab-button-active"); addMargin(i, button); } button.setRenderOrder(100000); } else { if (tab.isVisible()) { tab.hide(); } if (!"nifty-tab-button".equals(button.getStyle())) { button.setStyle("nifty-tab-button"); addMargin(i, button); } button.setRenderOrder(0); } } Element element = getElement(); if (element != null) { element.layoutElements(); } } private void addMargin(final int i, @Nonnull final Element button) { if (i > 0) { button.setMarginLeft(SizeValue.px(BUTTON_LEFT_MARGIN)); } else { button.setMarginLeft(SizeValue.px(0)); } } @Override public boolean inputEvent(@Nonnull final NiftyInputEvent inputEvent) { return true; } @Override public boolean isTabInGroup(@Nonnull final Tab tab) { return indexOf(tab) > -1; } @Override public void onStartScreen() { if (nifty == null || screen == null) { log.severe("Starting screen failed. Seems the binding is not done yet."); } String id = getId(); if (id != null) { nifty.subscribe(screen, id, ElementShowEvent.class, showEventSubscriber); } } @Override public void removeTab(final int index) { removeTab(index, null); } @Override public void removeTab(@Nonnull final Tab tab) { removeTab(tab, null); } @Override public void removeTab(@Nonnull final Element tab) { removeTab(tab, null); } @Override public void removeTab(final int index, @Nullable final EndNotify notify) { if (nifty == null) { throw new IllegalStateException("Can't remove tab as long as binding is not done."); } if ((index < 0) || (index >= getTabCount())) { throw new IndexOutOfBoundsException("Index out of bounds: " + index); } EndNotify triggeredNotification = notify; if (selectedIndex == index) { selectedIndex = Math.max(0, Math.min(selectedIndex, getTabCount() - 1)); triggeredNotification = new CheckVisibilityEndNotify(this, triggeredNotification); } if (tabButtonPanel != null) { final Element button; if (templateRemoved) { button = tabButtonPanel.getChildren().get(index); } else { button = tabButtonPanel.getChildren().get(index + 1); } nifty.unsubscribe(button.getId(), buttonClickedSubscriber); button.markForRemoval(); } if (contentPanel != null) { contentPanel.getChildren().get(index).markForRemoval(triggeredNotification); } } @Override public void removeTab(@Nonnull final Tab tab, @Nullable final EndNotify notify) { final int index = indexOf(tab); if (index == -1) { throw new IllegalArgumentException("The tab to remove is not part of this tab group."); } removeTab(index, notify); } @Override public void removeTab(@Nonnull final Element tab, @Nullable final EndNotify notify) { final Tab tabControl = tab.getNiftyControl(Tab.class); if (tabControl == null) { throw new IllegalArgumentException("Element to add is not a tab."); } removeTab(tabControl, notify); } @Override public void setSelectedTab(@Nonnull final Tab tab) { final int index = indexOf(tab); if (index == -1) { throw new IllegalArgumentException("The tab to remove is not part of this tab group."); } setSelectedTabIndex(index); } @Override public void setSelectedTabIndex(final int index) { if ((index < 0) || (index >= getTabCount())) { throw new IndexOutOfBoundsException("Index out of bounds: " + index); } selectedIndex = index; checkVisibility(); if (nifty != null) { String id = getId(); if (id != null) { Tab tab = getTabAtIndex(index); if (tab == null) { log.severe("Tab with valid index returned null. This looks like a internal error."); } else { nifty.publishEvent(id, new TabSelectedEvent(this, tab, index)); } } } } @Override public void setTabCaption(final int index, @Nonnull final String caption) { if ((index < 0) || (index >= getTabCount())) { throw new IndexOutOfBoundsException("Index out of bounds: " + index); } if (contentPanel != null) { final Tab tabControl = contentPanel.getChildren().get(index).getNiftyControl(Tab.class); if (tabControl == null) { log.severe("Tab control seems to be corrupted. Expected tab control not located."); } else { tabControl.setCaption(caption); } } Element buttonElement = getButton(index); if (buttonElement == null) { log.severe("Tab control seems corrupted. Expected button element not located."); } else { final Button button = buttonElement.getNiftyControl(Button.class); if (button == null) { log.severe("Tab button does not seem to contain a button control."); } else { button.setText(caption); } } } @Override public void setTabCaption(@Nonnull final Tab tab, @Nonnull final String caption) { final int index = indexOf(tab); if (index == -1) { throw new IllegalArgumentException("The tab to remove is not part of this tab group."); } setTabCaption(index, caption); } /** * Handle a click on a button and switch the tab. * * @param clickedButton the button that was clicked */ private void processButtonClick(@Nonnull final Element clickedButton) { if (tabButtonPanel == null) { return; } final List buttons = tabButtonPanel.getChildren(); if (buttons.isEmpty()) { return; } int indexOffset = 0; if (!templateRemoved) { indexOffset = -1; } setSelectedTabIndex(buttons.indexOf(clickedButton) + indexOffset); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy