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

com.hfg.html.custom.TabbedPaneSet Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.html.custom;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.awt.*;

import com.hfg.html.Div;
import com.hfg.html.HTMLTag;
import com.hfg.html.Span;
import com.hfg.html.Table;
import com.hfg.html.Td;
import com.hfg.html.Tr;
import com.hfg.html.HTML;
import com.hfg.xml.XMLTag;
import com.hfg.xml.XMLUtil;
import com.hfg.graphics.ColorUtil;
import com.hfg.util.Orientation;

//------------------------------------------------------------------------------
/**
 Convenience class for constructing a tabbed pane set.
 
See this page for examples.
Example:
     HTMLDoc doc = new HTMLDoc();
     HTML html = new HTML();
     doc.setRootTag(html);

     // Add the CSS classes needed for the tabs
     html.getHead().addStyle(TabbedPaneSet.generateCSS());
     // Add the javascript needed for the tabs
     html.getHead().addJavascript(TabbedPaneSet.generateJavascript());

     TabbedPaneSet tabSet1 = new TabbedPaneSet();
     tabSet1.addTab("Tab 1", new InputButton("Button 1"));
     tabSet1.addTab("Tab 2", new InputText("foo", "bar"));
     tabSet1.addTab("Tab 3", new Span("pane3");

     Body body = html.getBody();
     // Set the onload to initialize the tabs
     body.setOnLoad(tabSet1.generateOnLoad());

     body.addSubtag(tabSet1);

 
@author J. Alex Taylor, hairyfatguy.com */ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // 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. // // 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 // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class TabbedPaneSet extends Div { private String mSetId; private Table mLabelTable; private Div mPaneDiv; private String mSelectedTabId; private Orientation mOrientation; private boolean mRoundedTabs = true; private static Font sDefaultLabelFont = new Font("Ariel", Font.PLAIN, 10); private static Color sDefaultSelectedTabColor = Color.decode("#6666ff"); private static Color sDefaultUnselectedTabColor = Color.decode("#c0c0ff"); private static Color sDefaultSelectedTabFontColor = Color.decode("#ffffff"); private static Color sDefaultUnselectedTabFontColor = Color.decode("#2b4353"); private static Orientation sDefaultOrientation = Orientation.HORIZONAL; private static int sSetCount = 0; private static int sTabCount = 0; // CSS classes private static final String TAB_PANE_SET = "tabPaneSet"; private static final String TAB_LABELS = "tabLabels"; private static final String TAB_PANES = "tabPanes"; private static final String HORIZ_TAB = "tab tab-horiz"; private static final String VERT_TAB = ""; //########################################################################## // CONSTRUCTORS //########################################################################## //-------------------------------------------------------------------------- public TabbedPaneSet() { this(sDefaultOrientation); } //-------------------------------------------------------------------------- public TabbedPaneSet(Orientation inOrientation) { super(); mOrientation = inOrientation; sSetCount++; mSetId = "tabPaneSet" + sSetCount + "_" + (horizontal() ? "h" : "v"); setId(mSetId); // The enclosing table keeps the panes from expanding the width too far. Table enclosingTable = addTable().setClass(TAB_PANE_SET); Tr row = enclosingTable.addRow(); Td cell = row.addCell(); mLabelTable = cell.addTable().setClass(TAB_LABELS).setId(mSetId + '_' + TAB_LABELS); if (horizontal()) { mLabelTable.addRow(); mPaneDiv = cell.addDiv().setClass(TAB_PANES); } else { mPaneDiv = row.addCell().addDiv().setClass(TAB_PANES).addDiv(); } mPaneDiv.setId(mSetId + "_" + TAB_PANES); } //########################################################################## // PUBLIC METHODS //########################################################################## //-------------------------------------------------------------------------- public static void setDefaultLabelFont(Font inValue) { sDefaultLabelFont = inValue; } //-------------------------------------------------------------------------- public static void setDefaultSelectedTabColor(Color inValue) { sDefaultSelectedTabColor = inValue; } //-------------------------------------------------------------------------- public static void setDefaultUnselectedTabColor(Color inValue) { sDefaultUnselectedTabColor = inValue; } //-------------------------------------------------------------------------- public static void setDefaultSelectedTabFontColor(Color inValue) { sDefaultSelectedTabFontColor = inValue; } //-------------------------------------------------------------------------- public static void setDefaultUnselectedTabFontColor(Color inValue) { sDefaultUnselectedTabFontColor = inValue; } //-------------------------------------------------------------------------- public static String generateCSS() { StringBuffer css = new StringBuffer("\n"); css.append(".tab {\n" + " background-color: #" + ColorUtil.colorToHex(sDefaultUnselectedTabColor) + ";\n" + " color: #" + ColorUtil.colorToHex(sDefaultUnselectedTabFontColor) + ";\n" + " text-decoration: none;\n" + " cursor: default;\n" + " border-right:1px solid #" + ColorUtil.colorToHex(sDefaultSelectedTabColor) + ";\n" + " padding: 2px 4px 1px 4px;\n" + " margin: 0px 1px;\n" + " display: block;\n" + " }\n\n"); css.append(".tab-horiz {\n" + " margin: 0px 1px;\n" + " }\n\n"); css.append(".tab-vert {\n" + " margin: 0px 0px;\n" + " }\n\n"); css.append(".tab-selected {\n" + " background-color: #" + ColorUtil.colorToHex(sDefaultSelectedTabColor) + ";\n" + " color: #" + ColorUtil.colorToHex(sDefaultSelectedTabFontColor) + ";\n" + " }\n\n"); css.append(".tab:hover {\n" + " color: #" + ColorUtil.colorToHex(sDefaultSelectedTabFontColor) + ";\n" + " }\n\n"); css.append("table." + TAB_PANE_SET + " {\n" + " padding: 0px;\n" + " border-collapse: collapse;\n" // + " table-layout: fixed;\n" + " }\n\n"); css.append("table." + TAB_PANE_SET + " td {\n" + " padding: 0px;\n" + " vertical-align: top\n" + " }\n\n"); css.append("table." + TAB_LABELS + " {\n" + " font-family: '" + sDefaultLabelFont.getName() + (!sDefaultLabelFont.getName().equals(sDefaultLabelFont.getFamily()) ? "', '" + sDefaultLabelFont.getFamily() : "") + "', sans-serif;\n" + " font-size: " + sDefaultLabelFont.getSize() + "pt;\n" + " padding: 0px;\n" + " border-collapse: collapse\n" + " }\n\n"); css.append("table." + TAB_LABELS + " td {\n" + " padding: 0px;\n" + " }\n\n"); css.append("." + TAB_PANES + " {\n" + " border: solid #" + ColorUtil.colorToHex(sDefaultUnselectedTabColor) + ";\n" + " border-width: 1px;\n" + " padding: 3px;\n" + " }\n\n"); // For rounding the corners of the tabs. css.append(".rndS1, .rndS2, .rndS3, .rndS4, .rndU1, .rndU2, .rndU3, .rndU4 {\n" + " border: 0px;\n" + " border-right:1px solid #" + ColorUtil.colorToHex(sDefaultSelectedTabColor) + ";\n" + " height: 1px;\n" + " padding: 0px;\n" + " display: block;\n" ///////////// + " overflow: hidden;\n" ///////////// + " }\n\n" + ".rndS1, .rndS2, .rndS3, .rndS4 {\n" + " background-color: #" + ColorUtil.colorToHex(sDefaultSelectedTabColor) + ";\n" + " }\n\n" + ".rndU1, .rndU2, .rndU3, .rndU4 {\n" + " background-color: #" + ColorUtil.colorToHex(sDefaultUnselectedTabColor) + ";\n" + " }\n\n" + ".rndHzS4, .rndHzU4 { margin: 0px 1px; height: 1px; }\n" + ".rndHzS3, .rndHzU3 { margin: 0px 2px; }\n" + ".rndHzS2, .rndHzU2 { margin: 0px 3px; }\n" + ".rndHzS1, .rndHzU1 { margin: 0px 5px; }\n" + ".rndVertS4, .rndVertU4 { margin: 0px 0px 0px 1px; height: 1px; }\n" + ".rndVertS3, .rndVertU3 { margin: 0px 0px 0px 2px; }\n" + ".rndVertS2, .rndVertU2 { margin: 0px 0px 0px 3px; }\n" + ".rndVertS1, .rndVertU1 { margin: 0px 0px 0px 5px; }\n\n"); // Work around for IE margin issues // Kinda kludgy but so is IE. XMLTag styleTag = new XMLTag(HTML.STYLE); styleTag.setAttribute(HTML.TYPE, "text/css"); css.append(XMLUtil.composeEndTag(styleTag.getTagName()) + "\n\n\n\n" + XMLUtil.composeStartTag(styleTag.getTagName(), styleTag.getAttributes())); return css.toString(); } //-------------------------------------------------------------------------- public static String generateJavascript() { StringBuffer js = new StringBuffer(); js.append("var tabPaneSets = new Array();\n\n"); js.append("function TabPaneSet()\n" + "{\n" + " this.labels = new Array();\n" + " this.labelEdges = new Array();\n" // Div's for rounded corners + " this.panes = new Array();\n" + " this.orientation;\n" + " this.paneDiv;\n" // Div holding the content panes + "}\n\n"); js.append("//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + "TabPaneSet.prototype.adjustSize = function()\n" + "{\n" + " var maxHeight = 0;\n" + " var maxWidth = 0;\n" // Force a recalculation of the nax natural content size + " this.paneDiv.style.height = null;\n" + " this.paneDiv.style.width = null;\n" + " \n" + " for (var paneIndex=0; paneIndex < this.panes.length; paneIndex++)\n" + " {\n" + " var pane = this.panes[paneIndex];\n" + " var hiding = false;\n" + " if (pane.style.display == 'none')\n" + " {\n" + " hiding = true;\n" + " pane.style.visibility = 'hidden';\n" + " pane.style.display = 'block';\n" + " }\n" + " if (pane.offsetHeight > maxHeight) maxHeight = pane.offsetHeight;\n" + " if (pane.offsetWidth > maxWidth) maxWidth = pane.offsetWidth;\n" // + "alert('offsetWidth: ' + pane.offsetWidth + ', pixelWidth: ' + pane.pixelWidth + ', clientWidth: ' + pane.clientWidth);\n"////////////////////////////// + " if (hiding)\n" + " {\n" + " pane.style.display = 'none';\n" + " pane.style.visibility = 'visible';\n" + " }\n" + " }\n" + " \n" + " this.paneDiv.style.height = maxHeight + 'px';\n" + " this.paneDiv.style.width = maxWidth + 'px';\n" + "}\n"); js.append("//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + "TabPaneSet.prototype.switchTab = function(inPaneId)\n" + "{\n" + " // First, hide the unselected panes.\n" + " for (var paneIndex=0; paneIndex < this.panes.length; paneIndex++)\n" + " {\n" + " var pane = this.panes[paneIndex];\n" + " if (pane.id != 'pane' + inPaneId) pane.style.display = 'none';\n" + " }\n" + " \n" + " // Now display the selected pane.\n" + " for (var paneIndex=0; paneIndex < this.panes.length; paneIndex++)\n" + " {\n" + " var pane = this.panes[paneIndex];\n" + " if (pane.id == 'pane' + inPaneId) pane.style.display = 'block';\n" + " }\n" + " \n" + " for (var labelIndex=0; labelIndex < this.labels.length; labelIndex++)\n" + " {\n" + " var label = this.labels[labelIndex];\n" + " label.className = (label.id == 'tab' + inPaneId ? 'tab tab-selected' : 'tab')\n" + " + (this.orientation == 'horiz' ? ' tab-horiz' : ' tab-vert');\n" + " for (var i = 0; i < this.labelEdges[labelIndex].length; i++)\n" + " {\n" + " var suffix = this.labelEdges[labelIndex][i].className.charAt(this.labelEdges[labelIndex][i].className.length - 1);\n" + " this.labelEdges[labelIndex][i].className = 'rnd' + (label.id == 'tab' + inPaneId ? 'S': 'U') + suffix\n" + " + ' rnd' + (this.orientation == 'horiz' ? 'Hz' : 'Vert')\n" + " + (label.id == 'tab' + inPaneId ? 'S': 'U') + suffix;\n" + " }\n" + " }\n" + "}\n\n"); js.append("//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + "function setupTabPaneSet(inSetId, inSelectedTabId)\n" + "{\n" + " var tabPaneSet = new TabPaneSet();\n" + " tabPaneSets[inSetId] = tabPaneSet;\n" + " tabPaneSet.orientation = (inSetId.match(/_h$/) ? 'horiz' : 'vert');\n" + " \n" + " // Extract the labels\n" + " var labelTable = document.getElementById(inSetId + '_" + TAB_LABELS + "');\n" + " var cells = labelTable.getElementsByTagName('td');\n" + " for (var cellIndex = 0; cellIndex < cells.length; cellIndex++)\n" + " {\n" + " var cell = cells[cellIndex];\n" + " var labels = cell.getElementsByTagName('span');\n" + " for (var i=0; i < labels.length; i++)\n" + " {\n" + " var label = labels[i];\n" + " if (label.id && label.id.indexOf('tab') == 0)\n" + " {\n" + " tabPaneSet.labels[tabPaneSet.labels.length] = label;\n" + " tabPaneSet.labelEdges[tabPaneSet.labelEdges.length] = cell.getElementsByTagName('div');\n" + " }\n" + " }\n" + " }\n" + " \n" + " // Extract the panes\n" + " tabPaneSet.paneDiv = document.getElementById(inSetId + '_" + TAB_PANES + "');\n" + " var panes = tabPaneSet.paneDiv.getElementsByTagName('div');\n" + " for (var paneIndex=0; paneIndex < panes.length; paneIndex++)\n" + " {\n" + " var pane = panes[paneIndex];\n" + " if (pane.parentNode != tabPaneSet.paneDiv || !pane.id || !pane.id.match(/^pane/)) continue;\n" + " tabPaneSet.panes[tabPaneSet.panes.length] = pane;\n" + " }\n" + " \n" + " tabPaneSet.adjustSize();\n" // TabbedPaneSet needs to be large enough to accomodate the largest pane. + " \n" + " document.getElementById(inSelectedTabId).parentNode.onclick();\n" + "}\n\n"); js.append("//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + "function switchTab(inPaneSetId, inPaneId)\n" + "{\n" + " var tabPaneSet = tabPaneSets[inPaneSetId];\n" + " if (!tabPaneSet)\n" + " {\n" + " alert('Programming Error!\\ngenerateOnLoad() for this tab pane set was not added to the body.onLoad() during html generation!\\nSee the example in the javadoc.');\n" + " return;\n" + " }\n" + " \n" + " tabPaneSet.switchTab(inPaneId);\n" + " \n" + "}\n\n"); js.append("//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + "function resizeTabPanes(inPaneSetId)\n" + "{\n" + " var tabPaneSet = tabPaneSets[inPaneSetId];\n" + " if (!tabPaneSet)\n" + " {\n" + " alert('Programming Error!\\ngenerateOnLoad() for this tab pane set was not added to the body.onLoad() during html generation!\\nSee the example in the javadoc.');\n" + " return;\n" + " }\n" + " \n" + " tabPaneSet.adjustSize();\n" + " \n" + "}\n\n"); return js.toString(); } //-------------------------------------------------------------------------- @Override public String getId() { return mSetId; } //-------------------------------------------------------------------------- /** Tabs are rounded by default. Must be set before addTab() is called. */ public TabbedPaneSet useRoundedTabs(boolean inValue) { mRoundedTabs = inValue; return this; } //-------------------------------------------------------------------------- /** * Createds the javascript for the body's onload() that is necessary to * initialize the tabbed pane set (and any tabbed pane sets contained within it). */ public String generateOnLoad() { StringBuffer buffer = new StringBuffer(); List tabPaneSets = new ArrayList(); tabPaneSets.add(this); findNestedTabPaneSets(mPaneDiv, tabPaneSets); for (int i = tabPaneSets.size() - 1; i >= 0; i--) { TabbedPaneSet paneSet = tabPaneSets.get(i); buffer.append("setupTabPaneSet('" + paneSet.mSetId + "', '" + paneSet.mSelectedTabId + "');"); } return buffer.toString(); } //-------------------------------------------------------------------------- public void addTab(String inLabel, HTMLTag inPaneContent) { addTab(inLabel, inPaneContent, false); } //-------------------------------------------------------------------------- public void addTab(HTMLTag inLabel, HTMLTag inPaneContent) { addTab(inLabel, inPaneContent, false); } //-------------------------------------------------------------------------- public void addTab(String inLabel, HTMLTag inPaneContent, boolean inIsSelected) { addTab(new Span(inLabel), inPaneContent, inIsSelected); } //-------------------------------------------------------------------------- public void addTab(String inLabel, HTMLTag inPaneContent, boolean inIsSelected, String inOnClick) { addTab(new Span(inLabel), inPaneContent, inIsSelected, inOnClick); } //-------------------------------------------------------------------------- public void addTab(HTMLTag inLabel, HTMLTag inPaneContent, boolean inIsSelected) { addTab(new Span(inLabel), inPaneContent, inIsSelected, null); } //-------------------------------------------------------------------------- public void addTab(HTMLTag inLabel, HTMLTag inPaneContent, boolean inIsSelected, String inOnClick) { sTabCount++; Td cell = null; if (horizontal()) { cell = mLabelTable.getRows().get(0).addCell(); } else // VERTICAL { cell = mLabelTable.addRow().addCell(); } // Runs thru the switchTab function to get a better error msg if generateOnLoad() wasn't done. cell.setOnClick((inOnClick != null ? inOnClick + ";" : "") + "switchTab('" + mSetId + "', '" + sTabCount + "');"); if (mRoundedTabs) { /* Wanted to use hr but stoopid IE gives them some crazy unalterable vertical margins. cell.addSubtag(new Hr().setClass("u1")); cell.addSubtag(new Hr().setClass("u2")); cell.addSubtag(new Hr().setClass("u3")); cell.addSubtag(new Hr().setClass("u4")); */ // For some reason the empty tag renders differently (wrong) compared to the empty tag pair cell.addDiv().setClass("rndU1 " + (horizontal() ? "rndHzU1" : "rndVertU1")).setContent(""); cell.addDiv().setClass("rndU2 " + (horizontal() ? "rndHzU2" : "rndVertU2")).setContent(""); cell.addDiv().setClass("rndU3 " + (horizontal() ? "rndHzU3" : "rndVertU3")).setContent(""); cell.addDiv().setClass("rndU4 " + (horizontal() ? "rndHzU4" : "rndVertU4")).setContent(""); } Span tab = cell.addSpan(inLabel); String tabId = "tab" + sTabCount; tab.setId(tabId); tab.setClass(horizontal() ? HORIZ_TAB : VERT_TAB); if (mRoundedTabs && !horizontal()) { // For some reason the empty tag renders differently (wrong) compared to the empty tag pair cell.addDiv().setClass("rndU4 rndVertU4").setContent(""); cell.addDiv().setClass("rndU3 rndVertU3").setContent(""); cell.addDiv().setClass("rndU2 rndVertU2").setContent(""); cell.addDiv().setClass("rndU1 rndVertU1").setStyle("border-bottom:1px solid #" + ColorUtil.colorToHex(sDefaultSelectedTabColor)).setContent(""); } mPaneDiv.addDiv(inPaneContent).setId("pane" + sTabCount); if (null == mSelectedTabId || inIsSelected) mSelectedTabId = tabId; } //########################################################################## // PRIVATE METHODS //########################################################################## //-------------------------------------------------------------------------- private boolean horizontal() { return mOrientation == Orientation.HORIZONAL; } //-------------------------------------------------------------------------- private void findNestedTabPaneSets(XMLTag inCurrentTag, List inTabPaneSetList) { // Find any nested tabpane sets Iterator iter = inCurrentTag.getSubtags().iterator(); while (iter.hasNext()) { XMLTag tag = (XMLTag) iter.next(); if (tag instanceof TabbedPaneSet) { inTabPaneSetList.add(tag); } findNestedTabPaneSets(tag, inTabPaneSetList); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy