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

com.google.gwt.user.client.ui.StackPanel Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.user.client.ui;

import com.google.gwt.dom.client.Element;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.annotations.IsSafeHtml;
import com.google.gwt.safehtml.shared.annotations.SuppressIsSafeHtmlCastCheck;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;

/**
 * A panel that stacks its children vertically, displaying only one at a time,
 * with a header for each child which the user can click to display.
 *
 * 

* This widget will only work in quirks mode. If your application is in * Standards Mode, use {@link StackLayoutPanel} instead. *

* *

* *

*

CSS Style Rules

*
    *
  • .gwt-StackPanel { the panel itself }
  • *
  • .gwt-StackPanel .gwt-StackPanelItem { unselected items }
  • *
  • .gwt-StackPanel .gwt-StackPanelItem-selected { selected items }
  • *
  • .gwt-StackPanel .gwt-StackPanelContent { the wrapper around the contents * of the item }
  • *
*

*

Example

* {@example com.google.gwt.examples.StackPanelExample} *

* * @see StackLayoutPanel */ public class StackPanel extends ComplexPanel implements InsertPanel.ForIsWidget { private static final String DEFAULT_STYLENAME = "gwt-StackPanel"; private static final String DEFAULT_ITEM_STYLENAME = DEFAULT_STYLENAME + "Item"; private Element body; private int visibleStack = -1; /** * Creates an empty stack panel. */ public StackPanel() { Element table = DOM.createTable(); setElement(table); body = DOM.createTBody(); DOM.appendChild(table, body); table.setPropertyInt("cellSpacing", 0); table.setPropertyInt("cellPadding", 0); DOM.sinkEvents(table, Event.ONCLICK); setStyleName(DEFAULT_STYLENAME); } @Override public void add(Widget w) { insert(w, getWidgetCount()); } /** * Adds a new child with the given widget and header. * * @param w the widget to be added * @param stackText the header text associated with this widget */ @SuppressIsSafeHtmlCastCheck public void add(Widget w, String stackText) { add(w, stackText, false); } /** * Adds a new child with the given widget and header, optionally interpreting * the header as HTML. * * @param w the widget to be added * @param stackHtml the header html associated with this widget */ public void add(Widget w, SafeHtml stackHtml) { add(w, stackHtml.asString(), true); } /** * Adds a new child with the given widget and header, optionally interpreting * the header as HTML. * * @param w the widget to be added * @param stackText the header text associated with this widget * @param asHTML true to treat the specified text as HTML */ public void add(Widget w, @IsSafeHtml String stackText, boolean asHTML) { add(w); setStackText(getWidgetCount() - 1, stackText, asHTML); } /** * Gets the currently selected child index. * * @return selected child */ public int getSelectedIndex() { return visibleStack; } public void insert(IsWidget w, int beforeIndex) { insert(asWidgetOrNull(w), beforeIndex); } public void insert(Widget w, int beforeIndex) { // header Element trh = DOM.createTR(); Element tdh = DOM.createTD(); DOM.appendChild(trh, tdh); DOM.appendChild(tdh, createHeaderElem()); // body Element trb = DOM.createTR(); Element tdb = DOM.createTD(); DOM.appendChild(trb, tdb); // DOM indices are 2x logical indices; 2 dom elements per stack item beforeIndex = adjustIndex(w, beforeIndex); int effectiveIndex = beforeIndex * 2; // this ordering puts the body below the header DOM.insertChild(body, trb, effectiveIndex); DOM.insertChild(body, trh, effectiveIndex); // header styling setStyleName(tdh, DEFAULT_ITEM_STYLENAME, true); tdh.setPropertyInt("__owner", hashCode()); tdh.setPropertyString("height", "1px"); // body styling setStyleName(tdb, DEFAULT_STYLENAME + "Content", true); tdb.setPropertyString("height", "100%"); tdb.setPropertyString("vAlign", "top"); // Now that the DOM is connected, call insert (this ensures that onLoad() is // not fired until the child widget is attached to the DOM). insert(w, tdb, beforeIndex, false); // Update indices of all elements to the right. updateIndicesFrom(beforeIndex); // Correct visible stack for new location. if (visibleStack == -1) { showStack(0); } else { setStackVisible(beforeIndex, false); if (visibleStack >= beforeIndex) { ++visibleStack; } // Reshow the stack to apply style names setStackVisible(visibleStack, true); } } @Override public void onBrowserEvent(Event event) { if (DOM.eventGetType(event) == Event.ONCLICK) { Element target = DOM.eventGetTarget(event); int index = findDividerIndex(target); if (index != -1) { showStack(index); } } super.onBrowserEvent(event); } @Override public boolean remove(int index) { return remove(getWidget(index), index); } @Override public boolean remove(Widget child) { return remove(child, getWidgetIndex(child)); } /** * Sets the text associated with a child by its index. * * @param index the index of the child whose text is to be set * @param text the text to be associated with it */ @SuppressIsSafeHtmlCastCheck public void setStackText(int index, String text) { setStackText(index, text, false); } /** * Sets the html associated with a child by its index. * * @param index the index of the child whose text is to be set * @param html the html to be associated with it */ public void setStackText(int index, SafeHtml html) { setStackText(index, html.asString(), true); } /** * Sets the text associated with a child by its index. * * @param index the index of the child whose text is to be set * @param text the text to be associated with it * @param asHTML true to treat the specified text as HTML */ public void setStackText(int index, @IsSafeHtml String text, boolean asHTML) { if (index >= getWidgetCount()) { return; } Element tdWrapper = DOM.getChild(DOM.getChild(body, index * 2), 0); Element headerElem = DOM.getFirstChild(tdWrapper); if (asHTML) { getHeaderTextElem(headerElem).setInnerHTML(text); } else { getHeaderTextElem(headerElem).setInnerText(text); } } /** * Shows the widget at the specified child index. * * @param index the index of the child to be shown */ public void showStack(int index) { if ((index >= getWidgetCount()) || (index < 0) || (index == visibleStack)) { return; } if (visibleStack >= 0) { setStackVisible(visibleStack, false); } visibleStack = index; setStackVisible(visibleStack, true); } /** * Affected Elements: *
    *
  • -text# = The element around the header at the specified index.
  • *
  • -text-wrapper# = The element around the header at the specified index.
  • *
  • -content# = The element around the body at the specified index.
  • *
* * @see UIObject#onEnsureDebugId(String) */ @Override protected void onEnsureDebugId(String baseID) { super.onEnsureDebugId(baseID); int numHeaders = DOM.getChildCount(body) >> 1; for (int i = 0; i < numHeaders; i++) { Element tdWrapper = DOM.getFirstChild(DOM.getChild(body, 2 * i)); Element headerElem = DOM.getFirstChild(tdWrapper); Element bodyElem = DOM.getFirstChild(DOM.getChild(body, 2 * i + 1)); ensureDebugId(tdWrapper, baseID, "text-wrapper" + i); ensureDebugId(bodyElem, baseID, "content" + i); ensureDebugId(getHeaderTextElem(headerElem), baseID, "text" + i); } } /** * Returns a header element. */ Element createHeaderElem() { return DOM.createDiv(); } /** * Get the element that holds the header text given the header element created * by #createHeaderElement. * * @param headerElem the header element * @return the element around the header text */ Element getHeaderTextElem(Element headerElem) { return headerElem; } /** * Adds the {@code styleName} on the {@code } for the header specified by {@code index}. * * @param index the index of the header row to apply to the style to * @param styleName the name of the class to add */ public void addHeaderStyleName(int index, String styleName) { if (index >= getWidgetCount()) { return; } Element tr = DOM.getChild(body, index * 2); setStyleName(tr, styleName, true /* add */); } /** * Removes the {@code styleName} off the {@code } for the header specified by {@code index}. * * @param index the index of the header row to remove the style from * @param styleName the name of the class to remove */ public void removeHeaderStyleName(int index, String styleName) { if (index >= getWidgetCount()) { return; } Element tr = DOM.getChild(body, index * 2); setStyleName(tr, styleName, false /* remove */); } private int findDividerIndex(Element elem) { while (elem != null && elem != getElement()) { String expando = elem.getPropertyString("__index"); if (expando != null) { // Make sure it belongs to me! int ownerHash = elem.getPropertyInt("__owner"); if (ownerHash == hashCode()) { // Yes, it's mine. return Integer.parseInt(expando); } else { // It must belong to some nested StackPanel. return -1; } } elem = DOM.getParent(elem); } return -1; } private boolean remove(Widget child, int index) { // Make sure to call this before disconnecting the DOM. boolean removed = super.remove(child); if (removed) { // Calculate which internal table elements to remove. int rowIndex = 2 * index; Element tr = DOM.getChild(body, rowIndex); body.removeChild(tr); tr = DOM.getChild(body, rowIndex); body.removeChild(tr); // Correct visible stack for new location. if (visibleStack == index) { visibleStack = -1; } else if (visibleStack > index) { --visibleStack; } // Update indices of all elements to the right. updateIndicesFrom(index); } return removed; } private void setStackContentVisible(int index, boolean visible) { Element tr = DOM.getChild(body, (index * 2) + 1); UIObject.setVisible(tr, visible); getWidget(index).setVisible(visible); } private void setStackVisible(int index, boolean visible) { // Get the first table row containing the widget's selector item. Element tr = DOM.getChild(body, (index * 2)); if (tr == null) { return; } // Style the stack selector item. Element td = DOM.getFirstChild(tr); setStyleName(td, DEFAULT_ITEM_STYLENAME + "-selected", visible); // Show/hide the contained widget. setStackContentVisible(index, visible); // Set the style of the next header Element trNext = DOM.getChild(body, ((index + 1) * 2)); if (trNext != null) { Element tdNext = DOM.getFirstChild(trNext); setStyleName(tdNext, DEFAULT_ITEM_STYLENAME + "-below-selected", visible); } } private void updateIndicesFrom(int beforeIndex) { for (int i = beforeIndex, c = getWidgetCount(); i < c; ++i) { Element childTR = DOM.getChild(body, i * 2); Element childTD = DOM.getFirstChild(childTR); childTD.setPropertyInt("__index", i); // Update the special style on the first element if (beforeIndex == 0) { setStyleName(childTD, DEFAULT_ITEM_STYLENAME + "-first", true); } else { setStyleName(childTD, DEFAULT_ITEM_STYLENAME + "-first", false); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy