/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.gwt.client.ui; import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle; import org.opencms.gwt.client.util.CmsDomUtil; import org.opencms.util.CmsStringUtil; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.logical.shared.AttachEvent; import com.google.gwt.event.logical.shared.BeforeSelectionHandler; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.TabLayoutPanel; import com.google.gwt.user.client.ui.Widget; /** * Wrapper class for @see com.google.user.client.ui.TabLayoutPanel.<p> * * Layout class for a panel with several tabs. The tabbed panel should be set inside a widget with given width and height. * For table based layouts the height of the parent cell should be set explicitly. * * As layout options two height for the tabbar are provided: 32px("standard") and 25px("small"). * * @param <E> the tab widget type * * @since 8.0.0 * */ public class CmsTabbedPanel<E extends Widget> extends Composite { /** Enumeration with layout keys. */ public enum CmsTabbedPanelStyle { /** Button style. */ buttonTabs(25, I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().buttonTabs(), I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().black()), /** Classic style. */ classicTabs(25, I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().classicTabs(), null); /** The default tabbar height. */ public static final CmsTabbedPanelStyle DEFAULT = buttonTabs; /** Property name. */ private int m_barHeight; /** The general panel style name. */ private String m_styleClass; /** The tab color style name. */ private String m_tabColorClass; /** * Constructor.<p> * * @param barHeight the height of the bar */ private CmsTabbedPanelStyle(int barHeight, String styleClass, String tabColorClass) { m_barHeight = barHeight; m_styleClass = styleClass; m_tabColorClass = tabColorClass; } /** * Returns the barHeight.<p> * * @return the barHeight */ public int getBarHeight() { return m_barHeight; } /** * Returns the styleClass.<p> * * @return the styleClass */ public String getStyleClass() { return m_styleClass; } /** * Returns the tabColorClass.<p> * * @return the tabColorClass */ public String getTabColorClass() { return m_tabColorClass; } } /** Stores the indexes and the title of disabled tabs. */ private Map<Integer, String> m_disabledTabIndexes = new HashMap<Integer, String>(); private CmsTabbedPanelStyle m_panelStyle; /** The TabLayoutPanel widget. */ private TabLayoutPanel m_tabPanel; /** A map from ids to tabs. */ private Map<String, E> m_tabsById = new HashMap<String, E>(); /** * The default constructor for an empty tabbed panel. <p> */ public CmsTabbedPanel() { this(CmsTabbedPanelStyle.DEFAULT); } /** * The constructor for an empty tabbed panel. <p> * * @param tabbedPanelStyle the pre-defined height of the tabbar, can be "small" or "standard" */ public CmsTabbedPanel(CmsTabbedPanelStyle tabbedPanelStyle) { m_tabPanel = new TabLayoutPanel(tabbedPanelStyle.getBarHeight(), Unit.PX); m_panelStyle = tabbedPanelStyle; // All composites must call initWidget() in their constructors. initWidget(m_tabPanel); Element tabRootEl = m_tabPanel.getElement(); // set an additional css class for the parent element of the .gwt-TabLayoutPanelTabs element List<Element> tabBarDivs = CmsDomUtil.getElementsByClass( I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cmsTabLayoutPanelTabs(), CmsDomUtil.Tag.div, tabRootEl); if (tabBarDivs.size() == 1) { tabBarDivs.get(0).getParentElement().setClassName( I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cmsTabLayoutPanelTabBar() + " " + I_CmsLayoutBundle.INSTANCE.generalCss().cornerAll()); if (m_panelStyle.getTabColorClass() != null) { tabBarDivs.get(0).getParentElement().addClassName(m_panelStyle.getTabColorClass()); } } m_tabPanel.setStyleName(m_panelStyle.getStyleClass()); m_tabPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cmsTabLayoutPanel()); m_tabPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().cornerAll() + " " + I_CmsLayoutBundle.INSTANCE.generalCss().textMedium()); m_tabPanel.addAttachHandler(new AttachEvent.Handler() { /** * @see com.google.gwt.event.logical.shared.AttachEvent.Handler#onAttachOrDetach(com.google.gwt.event.logical.shared.AttachEvent) */ public void onAttachOrDetach(AttachEvent event) { setOverflowVisibleToContent(); } }); } /** * Add a new tab with the provided name and content.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#add(Widget, String)} * * @param tabContent the widget to add as a tab * @param tabName the name of the tab to display in the tabbar */ public void add(E tabContent, String tabName) { tabContent.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().cornerAll()); m_tabPanel.add(tabContent, tabName); Element tabRootEl = m_tabPanel.getElement(); // set an additional css class for the parent element of the .gwt-TabLayoutPanelTabs element List<Element> tabDivs = CmsDomUtil.getElementsByClass( I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cmsTabLayoutPanelTab(), CmsDomUtil.Tag.div, tabRootEl); Iterator<Element> it = tabDivs.iterator(); boolean first = true; while (it.hasNext()) { Element e = it.next(); e.removeClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cornerLeft()); e.removeClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cornerRight()); if (first) { e.addClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cornerLeft()); first = false; } if (!it.hasNext()) { e.addClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cornerRight()); } } } /** * Add the before selection handler to the tabbed panel.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#addBeforeSelectionHandler(BeforeSelectionHandler)} * * @param handler the before selection handler * @return the registration for the event */ public HandlerRegistration addBeforeSelectionHandler(BeforeSelectionHandler<Integer> handler) { return m_tabPanel.addBeforeSelectionHandler(handler); } /** * Adds a tab with a user-defined id.<p> * * @param tabContent * @param tabName * @param tabId */ public void addNamed(E tabContent, String tabName, String tabId) { add(tabContent, tabName); m_tabsById.put(tabId, tabContent); } /** * Adds a SelectionEvent handler to the tabbed panel.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#addSelectionHandler(SelectionHandler)} * * @param handler the selection handler * @return the registration for the event */ public HandlerRegistration addSelectionHandler(SelectionHandler<Integer> handler) { return m_tabPanel.addSelectionHandler(handler); } /** * Add a new tab with the provided name and content and additional left margin.<p> * * @param tabContent the widget to add as a tab * @param tabName the name of the tab to display in the tabbar */ public void addWithLeftMargin(E tabContent, String tabName) { tabContent.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().cornerAll()); m_tabPanel.add(tabContent, tabName); int tabIndex = m_tabPanel.getWidgetIndex(tabContent); Element tabElement = getTabElement(tabIndex); if (tabElement != null) { tabElement.addClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().tabLeftMargin()); if (!m_panelStyle.equals(CmsTabbedPanelStyle.classicTabs)) { tabElement.addClassName(I_CmsLayoutBundle.INSTANCE.generalCss().buttonCornerAll()); tabElement.addClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().borderAll()); } } } /** * Disables the tab with the given index.<p> * * @param tabContent the content of the tab that should be disabled * @param reason the reason why the tab is disabled */ public void disableTab(E tabContent, String reason) { Integer index = new Integer(m_tabPanel.getWidgetIndex(tabContent)); Element tab = getTabElement(index.intValue()); if ((tab != null) && !m_disabledTabIndexes.containsKey(index)) { if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(tab.getTitle())) { m_disabledTabIndexes.put(index, tab.getTitle()); } else { m_disabledTabIndexes.put(index, ""); } tab.addClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().tabDisabled()); tab.setTitle(reason); } } /** * Enables the tab with the given index.<p> * * @param tabContent the content of the tab that should be enabled */ public void enableTab(E tabContent) { Integer index = new Integer(m_tabPanel.getWidgetIndex(tabContent)); Element tab = getTabElement(index.intValue()); if ((tab != null) && m_disabledTabIndexes.containsKey(index)) { tab.removeClassName(I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().tabDisabled()); tab.setTitle(m_disabledTabIndexes.get(index)); m_disabledTabIndexes.remove(index); } } /** * Gets the index of the currently-selected tab.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#getSelectedIndex()} * * @return the selected index, or -1 if none is selected. */ public int getSelectedIndex() { return m_tabPanel.getSelectedIndex(); } /** * Finds a tab with a given id.<p> * * @param tabId a tab id * * @return the tab with the given id */ public E getTabById(String tabId) { return m_tabsById.get(tabId); } /** * Gets the number of child widgets in this panel.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#getWidgetCount()} * * @return the number of children */ public int getTabCount() { return m_tabPanel.getWidgetCount(); } /** * Returns the tab text for a given tab.<p> * * @param pos the index of the tab * * @return the text of the tab */ public String getTabText(int pos) { return m_tabPanel.getTabWidget(pos).getElement().getInnerText(); } /** * Gets the child widget at the specified index.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#getWidget(int)} * * @param tabIndex the child widget's index * @return the child widget */ @SuppressWarnings("unchecked") public E getWidget(int tabIndex) { return (E)m_tabPanel.getWidget(tabIndex); } /** * Inserts a widget into the panel. If the Widget is already attached, it will be moved to the requested index.<p> * * Wrapper function for {@link com.google.gwt.user.client.ui.TabLayoutPanel#insert(Widget, String, int)} * * @param tabContent the widget to be added * @param tabName the text to be shown on its tab * @param beforeIndex the index before which it will be inserted */ public void insert(E tabContent, String tabName, int beforeIndex) { m_tabPanel.insert(tabContent, tabName, beforeIndex); } /** * Returns <code>true</code> if the tab with the given index is disabled, <code>false</code> otherwise.<p> * * @param tabIndex the tab index * * @return <code>true</code> if the tab with the given index is disabled, <code>false</code> otherwise */ public boolean isDisabledTab(int tabIndex) { return m_disabledTabIndexes.containsKey(new Integer(tabIndex)); } /** * Returns an iterator over all tabs.<p> * * @return the iterator */ @SuppressWarnings("unchecked") public Iterator<E> iterator() { return (Iterator<E>)m_tabPanel.iterator(); } /** * Removes the tab with the given index.<p> * * @param tabIndex the index of the tab which should be removed */ public void removeTab(int tabIndex) { m_tabPanel.remove(tabIndex); } /** * Delegate method.<p> * * @see com.google.gwt.user.client.ui.TabLayoutPanel#selectTab(Widget index) * * @param tabWidget the tab widget to select */ public void selectTab(E tabWidget) { m_tabPanel.selectTab(tabWidget); } /** * Delegate method.<p> * * @see com.google.gwt.user.client.ui.TabLayoutPanel#selectTab(Widget index) * * @param tabWidget the tab widget to select * @param fireEvent <code>true</code> to fire the tab event */ public void selectTab(E tabWidget, boolean fireEvent) { m_tabPanel.selectTab(tabWidget, fireEvent); } /** * Delegate method.<p> * * @see com.google.gwt.user.client.ui.TabLayoutPanel#selectTab(int index) * * @param tabIndex the index of the tab to be selected */ public void selectTab(int tabIndex) { m_tabPanel.selectTab(tabIndex); } /** * Delegate method.<p> * * @see com.google.gwt.user.client.ui.TabLayoutPanel#selectTab(int index) * * @param tabIndex the index of the tab to be selected * @param fireEvent <code>true</code> to fire the tab event */ public void selectTab(int tabIndex, boolean fireEvent) { m_tabPanel.selectTab(tabIndex, fireEvent); } /** * Sets the text of a given tab.<p> * * @param pos the index of the tab * @param text the new text for the tab */ public void setTabText(int pos, String text) { m_tabPanel.setTabText(pos, text); } /** * Returns the tab layout panel.<p> * * @return the tab layout panel */ protected TabLayoutPanel getTabPanel() { return m_tabPanel; } /** * @see com.google.gwt.user.client.ui.Widget#onLoad() */ @Override protected void onLoad() { super.onLoad(); // force layout after insertion into DOM to deal with IE layout problems Scheduler.get().scheduleDeferred(new ScheduledCommand() { public void execute() { getTabPanel().forceLayout(); } }); } /** * Sets the overflow of the tab layout content's parent to visible.<p> */ protected void setOverflowVisibleToContent() { Element tabRoot = m_tabPanel.getElement(); // set an additional css class for the parent element of the .gwt-TabLayoutPanelTabs element List<Element> tabContentDivs = CmsDomUtil.getElementsByClass( I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cmsTabLayoutPanelContent(), CmsDomUtil.Tag.div, tabRoot); tabContentDivs.addAll(CmsDomUtil.getElementsByClass( "gwt-TabLayoutPanelContentContainer", CmsDomUtil.Tag.div, tabRoot)); for (Element e : tabContentDivs) { e.getParentElement().getStyle().setOverflow(Overflow.VISIBLE); } } /** * Returns the tab element for the given index.<p> * * @param tabIndex the tab index to get the tab element for * * @return the tab element for the given index */ private Element getTabElement(int tabIndex) { Element tabRootEl = m_tabPanel.getElement(); // set an additional css class for the parent element of the .gwt-TabLayoutPanelTabs element List<Element> tabDivs = CmsDomUtil.getElementsByClass( I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().cmsTabLayoutPanelTab(), CmsDomUtil.Tag.div, tabRootEl); if ((tabDivs != null) && (tabDivs.size() > tabIndex)) { return tabDivs.get(tabIndex); } return null; } }