/* * ModuleTabLayoutPanel.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.core.client.theme; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.*; import org.rstudio.core.client.events.*; import org.rstudio.core.client.layout.WindowState; import org.rstudio.core.client.resources.ImageResource2x; import org.rstudio.core.client.theme.res.ThemeResources; import org.rstudio.core.client.theme.res.ThemeStyles; import org.rstudio.core.client.widget.DoubleClickState; import org.rstudio.core.client.widget.model.ProvidesBusy; import org.rstudio.studio.client.workbench.events.BusyEvent; import org.rstudio.studio.client.workbench.events.BusyHandler; public class ModuleTabLayoutPanel extends TabLayoutPanel { public static class ModuleTab extends Composite implements BusyHandler { public ModuleTab(String title, ThemeStyles styles, boolean canClose) { layoutPanel_ = new HorizontalPanel(); layoutPanel_.setStylePrimaryName(styles.tabLayout()); HTML left = new HTML(); left.setStylePrimaryName(styles.tabLayoutLeft()); layoutPanel_.add(left); HorizontalPanel center = new HorizontalPanel(); center.setStylePrimaryName(styles.tabLayoutCenter()); Label label = new Label(title, false); center.add(label); if (canClose) { closeButton_ = new Image(new ImageResource2x(ThemeResources.INSTANCE.closeTab2x())); closeButton_.setStylePrimaryName(styles.closeTabButton()); closeButton_.addStyleName(ThemeStyles.INSTANCE.handCursor()); center.add(closeButton_); } layoutPanel_.add(center); HTML right = new HTML(); right.setStylePrimaryName(styles.tabLayoutRight()); layoutPanel_.add(right); addDomHandler(new MouseDownHandler() { public void onMouseDown(MouseDownEvent event) { // Stop double-click of tab from selecting the tab title text event.preventDefault(); } }, MouseDownEvent.getType()); initWidget(layoutPanel_); } public Widget getWidget() { return super.getWidget(); } public HandlerRegistration addClickHandler(ClickHandler handler) { return addDomHandler(handler, ClickEvent.getType()); } public HandlerRegistration addCloseButtonClickHandler(ClickHandler handler) { return closeButton_.addClickHandler(handler); } @Override public void onBusy(BusyEvent event) { setBusy(event.isBusy()); } private void setBusy(boolean isBusy) { if (isBusy) { if (busyImage_ == null) { busyImage_ = new Image(ThemeResources.INSTANCE.busyTab()); busyImage_.setHeight("9px"); busyImage_.setWidth("9px"); busyImage_.getElement().getStyle().setMarginLeft(4, Unit.PX); busyImage_.getElement().getStyle().setMarginTop(6, Unit.PX); HorizontalPanel center = (HorizontalPanel)closeButton_.getParent(); if (center != null) center.add(busyImage_); } closeButton_.setVisible(false); busyImage_.setVisible(true); } else { if (busyImage_ != null) busyImage_.setVisible(false); closeButton_.setVisible(true); } } private HorizontalPanel layoutPanel_; private Image closeButton_; private Image busyImage_; } public ModuleTabLayoutPanel(final WindowFrame owner) { super(BAR_HEIGHT, Style.Unit.PX); owner_ = owner; styles_ = ThemeResources.INSTANCE.themeStyles(); addStyleName(styles_.moduleTabPanel()); addDomHandler(new MouseDownHandler() { public void onMouseDown(MouseDownEvent event) { if (!isWithinTopBand(event.getNativeEvent())) return; // Stop click-drag selection from working in top band event.preventDefault(); } }, MouseDownEvent.getType()); addDomHandler(new ClickHandler() { public void onClick(ClickEvent event) { if (!isWithinTopBand(event.getNativeEvent())) return; event.preventDefault(); event.stopPropagation(); if (doubleClickState_.checkForDoubleClick(event.getNativeEvent())) { owner.fireEvent(new WindowStateChangeEvent(WindowState.MAXIMIZE)); } } }, ClickEvent.getType()); } private boolean isWithinTopBand(NativeEvent event) { int absTop = getAbsoluteTop(); return absTop + BAR_HEIGHT > event.getClientY(); } @Override public void add(Widget child, String text) { add(child, text, false); } @Override public void add(Widget child, String text, boolean asHtml) { add(child, text, asHtml, null); } public void add(Widget child, String text, boolean asHtml, ClickHandler closeHandler) { add(child, text, asHtml, closeHandler, null); } public void add(final Widget child, String text, boolean asHtml, ClickHandler closeHandler, ProvidesBusy providesBusy) { if (asHtml) throw new UnsupportedOperationException("HTML tab names not supported"); ModuleTab tab = new ModuleTab(text, styles_, closeHandler != null); super.add(child, tab); if (closeHandler != null) tab.addCloseButtonClickHandler(closeHandler); if (providesBusy != null) providesBusy.addBusyHandler(tab); } @Override public void selectTab(int index) { super.selectTab(Math.max(0, Math.min(index, getWidgetCount() - 1))); if (index == 0) owner_.addStyleName(styles_.firstTabSelected()); else owner_.removeStyleName(styles_.firstTabSelected()); } @Override public void add(Widget child, Widget tab) { throw new UnsupportedOperationException(); } private final ThemeStyles styles_; private final DoubleClickState doubleClickState_ = new DoubleClickState(); public static final int BAR_HEIGHT = 23; private final WindowFrame owner_; }