Java tutorial
package ch.unifr.pai.twice.layout.client.eclipseLayout; /* * Copyright 2013 Oliver Schmid * 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. */ import java.util.HashSet; import java.util.Set; import ch.unifr.pai.twice.dragndrop.client.DragNDrop; import ch.unifr.pai.twice.dragndrop.client.configuration.DragConfiguration; import ch.unifr.pai.twice.dragndrop.client.factories.DropHandlerFactory; import ch.unifr.pai.twice.dragndrop.client.factories.DropTargetHandlerFactory.Priority; import ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler; import ch.unifr.pai.twice.module.client.TWICEModule; import ch.unifr.pai.twice.module.client.TWICEModuleController; import com.google.gwt.core.client.GWT; 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.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HasMouseOutHandlers; import com.google.gwt.event.dom.client.HasMouseOverHandlers; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.DeckLayoutPanel; import com.google.gwt.user.client.ui.DockLayoutPanel.Direction; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.LayoutPanel; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.ResizeLayoutPanel; import com.google.gwt.user.client.ui.SimpleLayoutPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.TabLayoutPanel; import com.google.gwt.user.client.ui.Widget; /** * The {@link MiceLayoutTabPanel} is a panel which provides tabs that can contain multiple widget components. The labels of the tab are draggable and can be * * rearranged as it is known from the eclipse user interface. Additionally, the screen can be split if a tab is dragged to a border of the tab panel. * * @author Oliver Schmid * */ public class MiceLayoutTabPanel extends TabLayoutPanel implements HasMouseOverHandlers, HasMouseOutHandlers { /** * If a tab is selected (becoming active and the underlying component is a {@link TWICEModule}, the component is started through th * {@link TWICEModuleController} * * @see com.google.gwt.user.client.ui.TabLayoutPanel#selectTab(int, boolean) */ @Override public void selectTab(int index, boolean fireEvents) { super.selectTab(index, fireEvents); final Widget w = getWidget(index); if (w instanceof RequiresResize) { ((RequiresResize) getWidget(index)).onResize(); } // TWICE modules are wrapped with a simple layout panel. So let's try to // start the component. if (w instanceof SimpleLayoutPanel && ((SimpleLayoutPanel) w).getWidget() != null) { Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { TWICEModuleController.start(((SimpleLayoutPanel) w).getWidget()); } }); } } /** * The resource bundle */ private static MiceResourceBundle RESOURCES = GWT.create(MiceResourceBundle.class); /** * the root panel */ LayoutPanel panel; /** * the bar on the top holding the different tab segments */ FlowPanel tabBar; DeckLayoutPanel deckPanel; FocusPanel tabBarFocus; boolean fullscreen; SimplePanel fullscreenButton = new SimplePanel(); Image showFullscreenButton; Image hideFullscreenButton; private final Set<MiceTabLabel> labels = new HashSet<MiceTabLabel>(); private final MiceTabLabel hoverGhost = new MiceTabLabel(" ", new Label()); /** * Shows a temporary, semi-transparent representation of the dragged tab label which is currently hovering the tab bar. This represents the position, where * the component would be placed at if it would be dropped on its current position * * @param dragProxy */ private void showHoverGhost(Element dragProxy) { hoverGhost.setText(dragProxy.getInnerText()); tabBarFocus.addStyleName(RESOURCES.miceLayoutStyle().hoverTabBar()); add(hoverGhost); } /** * Hides the temporary, semi-transparent representation of the dragged tab label since it has left the area of the tab bar. * * @param dragProxy */ private void hideHoverGhost(Element dragProxy) { tabBarFocus.removeStyleName(RESOURCES.miceLayoutStyle().hoverTabBar()); remove(hoverGhost.getWidget()); remove(hoverGhost); } /** * Adds a component to the tab panel. If it the widget is an instance of {@link MiceTabLabel}, it takes the predefined label value for the labelling of the * tab. Otherwise it looks after a title attribute of the widget and labels the tab after this value. If no such value exists, its tab will get an empty * label. * * @see com.google.gwt.user.client.ui.TabLayoutPanel#add(com.google.gwt.user.client.ui.Widget) */ @Override public void add(Widget w) { if (w instanceof MiceTabLabel) { add((MiceTabLabel) w); if (((MiceTabLabel) w).getWidget() instanceof RequiresResize) { ((RequiresResize) ((MiceTabLabel) w).getWidget()).onResize(); } } else add(new MiceTabLabel(w.getTitle() != null && !w.getTitle().isEmpty() ? w.getTitle() : " ", w)); } /** * Actually adds the {@link MiceTabLabel} to the tab layout while making it draggable (for the repositioning) * * @param tab */ private void add(MiceTabLabel tab) { labels.add(tab); add(tab.getWidget(), tab); tab.setCurrentParent(this); if (!tab.isInitializedAsDraggable()) { DragNDrop.makeDraggable(tab, DragConfiguration.withProxy(DropHandlerFactory.resetWhenNotOnDropArea())); tab.initializeAsDraggable(); } } /** * Removes a {@link MiceTabLabel} from the tab layout. If this was the last label of the tab panel, the tab panel removes itself from its parent split * layout panel. * * @param tab */ public void remove(MiceTabLabel tab) { labels.remove(tab); if (labels.size() == 0) { MiceSplitLayoutPanel parent = getParentSplitLayoutPanel(); boolean removed = parent.remove(this); if (!removed) return; } super.remove(tab.getWidget()); } /** * The drop handler which handles drops of {@link MiceTabLabel}s on the borders of existing {@link MiceLayoutTabPanel}s. * * @author Oliver Schmid * */ private static class NewAreaDropHandler implements DropTargetHandler { private final Direction direction; private final FocusPanel focusPanel; private final MiceLayoutTabPanel tabPanel; /** * @param direction * - the direction of the new area handler (relative to the parent layout {@link MiceLayoutTabPanel}) * @param focusPanel * - the widget whose drag events actually represent the drop area (these are widgets which are attached at the different borders of the * {@link MiceLayoutTabPanel}). * @param tabPanel * - the tab panel, the dragged tab originates from */ public NewAreaDropHandler(Direction direction, FocusPanel focusPanel, MiceLayoutTabPanel tabPanel) { this.direction = direction; this.focusPanel = focusPanel; this.tabPanel = tabPanel; } /** * @return the size of a widget in pixels dependent on its scaling direction (width for horizontally scaled, height for vertically scaled) */ private int getSize() { switch (direction) { case WEST: case EAST: return tabPanel.getOffsetWidth(); } return tabPanel.getOffsetHeight(); } /** * The actual drop handler. It only accepts drops of {@link MiceTabLabel}s and handles the creation of a new {@link MiceSplitLayoutPanel} to which the * dropped widget is attached to. * * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#onDrop(java.lang.String, com.google.gwt.user.client.ui.Widget, * com.google.gwt.dom.client.Element, com.google.gwt.user.client.Event, java.lang.Double, java.lang.Double) */ @Override public boolean onDrop(String deviceId, Widget widget, Element dragProxy, Event event, Double intersectionPercentage, Double intersectionPercentageWithTarget) { if (widget instanceof MiceTabLabel) { ResizeLayoutPanel parent = (ResizeLayoutPanel) tabPanel.getParent(); int size = getSize() / 2; MiceSplitLayoutPanel newPanel = new MiceSplitLayoutPanel(); parent.setWidget(newPanel); final MiceTabLabel tab = (MiceTabLabel) widget; MiceLayoutTabPanel newTabPanel = new MiceLayoutTabPanel(20); newPanel.insert(newTabPanel, direction, size, null); newPanel.add(tabPanel); MiceLayoutTabPanel originalParent = tab.getCurrentParent(); originalParent.remove(tab); newTabPanel.add(tab); return true; } return false; } /** * Highlights the area if a {@link MiceTabLabel} is hovering the focus panel * * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#onHover(java.lang.String, com.google.gwt.user.client.ui.Widget, * com.google.gwt.dom.client.Element, com.google.gwt.user.client.Event, java.lang.Double, java.lang.Double) */ @Override public void onHover(String deviceId, Widget widget, Element dragProxy, Event event, Double intersectionPercentage, Double intersectionPercentageWithTarget) { if (widget instanceof MiceTabLabel) focusPanel.setStyleName(RESOURCES.miceLayoutStyle().hoverAddPanel()); } /** * Removes the highlighting of the focus panel if the {@link MiceTabLabel} leaves its area * * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#onHoverEnd(java.lang.String, com.google.gwt.user.client.ui.Widget, * com.google.gwt.dom.client.Element, com.google.gwt.user.client.Event) */ @Override public void onHoverEnd(String deviceId, Widget widget, Element dragProxy, Event event) { if (widget instanceof MiceTabLabel) focusPanel.removeStyleName(RESOURCES.miceLayoutStyle().hoverAddPanel()); } /* * (non-Javadoc) * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#getPriority() */ @Override public Priority getPriority() { return Priority.HIGH; } } /** * The constructor creates the panel and adds the necessary drop handlers. * * @param barHeight * - the height of the tab bar in pixels */ public MiceLayoutTabPanel(double barHeight) { super(barHeight, Unit.PX); RESOURCES.miceLayoutStyle().ensureInjected(); hoverGhost.addStyleName(RESOURCES.miceLayoutStyle().hoverGhostTab()); panel = (LayoutPanel) getWidget(); tabBar = (FlowPanel) panel.getWidget(0); deckPanel = (DeckLayoutPanel) panel.getWidget(1); tabBarFocus = new FocusPanel(tabBar); panel.add(tabBarFocus); panel.setWidgetTopHeight(tabBarFocus, 0, Unit.PX, barHeight + 10, Unit.PX); panel.setWidgetTopBottom(deckPanel, barHeight + 10, Unit.PX, 0, Unit.PX); final FocusPanel southArea = new FocusPanel(); panel.insert(southArea, 0); panel.setWidgetBottomHeight(southArea, 0, Unit.PX, 2, Unit.PX); DragNDrop.setDropHandler(southArea, new NewAreaDropHandler(Direction.SOUTH, southArea, this), true); final FocusPanel westArea = new FocusPanel(); panel.insert(westArea, 0); panel.setWidgetLeftWidth(westArea, 0, Unit.PX, 2, Unit.PX); DragNDrop.setDropHandler(westArea, new NewAreaDropHandler(Direction.WEST, westArea, this), true); final FocusPanel eastArea = new FocusPanel(); panel.insert(eastArea, 0); panel.setWidgetRightWidth(eastArea, 0, Unit.PX, 2, Unit.PX); DragNDrop.setDropHandler(eastArea, new NewAreaDropHandler(Direction.EAST, eastArea, this), true); final FocusPanel northArea = new FocusPanel(); panel.insert(northArea, 0); panel.setWidgetTopHeight(northArea, 0, Unit.PX, 2, Unit.PX); DragNDrop.setDropHandler(northArea, new NewAreaDropHandler(Direction.NORTH, northArea, this), true); DragNDrop.setDropHandler(tabBarFocus, new DropTargetHandler() { /** * Handles the drop of a dragged {@link MiceTabLabel} hovering the tab bar * * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#onDrop(java.lang.String, com.google.gwt.user.client.ui.Widget, * com.google.gwt.dom.client.Element, com.google.gwt.user.client.Event, java.lang.Double, java.lang.Double) */ @Override public boolean onDrop(String deviceId, Widget widget, Element dragProxy, Event event, Double intersectionPercentage, Double intersectionPercentageWithTarget) { if (widget instanceof MiceTabLabel && !labels.contains(widget)) { final MiceTabLabel tab = (MiceTabLabel) widget; if (MiceLayoutTabPanel.this != tab.getCurrentParent()) { MiceLayoutTabPanel originalParent = tab.getCurrentParent(); add((MiceTabLabel) widget); originalParent.remove(tab); } } return false; } /** * Shows the "ghost" of the dragged {@link MiceTabLabel} when hovering the tab bar * * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#onHover(java.lang.String, com.google.gwt.user.client.ui.Widget, * com.google.gwt.dom.client.Element, com.google.gwt.user.client.Event, java.lang.Double, java.lang.Double) */ @Override public void onHover(String deviceId, Widget widget, Element dragProxy, Event event, Double intersectionPercentage, Double intersectionPercentageWithTarget) { if (widget instanceof MiceTabLabel && !labels.contains(widget)) showHoverGhost(dragProxy); } /** * Hides the "ghost" of the dragged {@link MiceTabLabel} when leaving the area of the tab bar * * @see ch.unifr.pai.twice.dragndrop.client.intf.DropTargetHandler#onHoverEnd(java.lang.String, com.google.gwt.user.client.ui.Widget, * com.google.gwt.dom.client.Element, com.google.gwt.user.client.Event) */ @Override public void onHoverEnd(String deviceId, Widget widget, Element dragProxy, Event event) { if (widget instanceof MiceTabLabel && !labels.contains(widget)) hideHoverGhost(dragProxy); } @Override public Priority getPriority() { return Priority.NORMAL; } }, true); showFullscreenButton = new Image(RESOURCES.fullscreenButton()); showFullscreenButton.setTitle("show fullscreen"); showFullscreenButton.setStyleName(RESOURCES.miceLayoutStyle().tabPanelButton()); showFullscreenButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { setFullscreen(true); } }); hideFullscreenButton = new Image(RESOURCES.nofullscreenButton()); hideFullscreenButton.setTitle("hide fullscreen"); hideFullscreenButton.setStyleName(RESOURCES.miceLayoutStyle().tabPanelButton()); hideFullscreenButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { setFullscreen(false); } }); Widget tabPanelButtonBar = createTabButtonBar(); panel.insert(tabPanelButtonBar, 0); panel.setWidgetTopHeight(tabPanelButtonBar, 7, Unit.PX, 16, Unit.PX); panel.setWidgetRightWidth(tabPanelButtonBar, 5, Unit.PX, 40, Unit.PX); addSelectionHandler(new SelectionHandler<Integer>() { @Override public void onSelection(SelectionEvent<Integer> event) { for (int i = 0; i < getWidgetCount(); i++) { MiceTabLabel w = (MiceTabLabel) getTabWidget(i); if (event.getSelectedItem().equals(i)) { if (!w.isSelected()) w.setSelected(true); } else { if (w.isSelected()) w.setSelected(false); } } } }); } /** * Switches to fullscreen mode * * @param fullscreen */ private void setFullscreen(boolean fullscreen) { if (fullscreen) { fullscreenButton.setWidget(hideFullscreenButton); MiceSplitLayoutPanel topPanel = getTopSplitLayoutPanel(getParentSplitLayoutPanel()); MiceLayout layout = (MiceLayout) topPanel.getParent(); layout.setFullscreen(MiceLayoutTabPanel.this); } else { fullscreenButton.setWidget(showFullscreenButton); // MiceSplitLayoutPanel topPanel = // getTopSplitLayoutPanel(getParentSplitLayoutPanel()); MiceLayout layout = (MiceLayout) getParent(); layout.unsetFullscreen(); } } /** * Sets up the tab button bar (including the full screen button) * * @return */ private Widget createTabButtonBar() { HorizontalPanel p = new HorizontalPanel(); fullscreenButton.setWidget(showFullscreenButton); p.add(fullscreenButton); return p; } /** * @param p * @return the very root {@link MiceSplitLayoutPanel} */ private MiceSplitLayoutPanel getTopSplitLayoutPanel(MiceSplitLayoutPanel p) { if (p.getParentMiceSplitLayoutPanel() == null) return p; return getTopSplitLayoutPanel(p.getParentMiceSplitLayoutPanel()); } /** * register mouse out handlers * * @see com.google.gwt.event.dom.client.HasMouseOutHandlers#addMouseOutHandler(com.google.gwt.event.dom.client.MouseOutHandler) */ @Override public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) { return addDomHandler(handler, MouseOutEvent.getType()); } /** * register mouse over handler * * @see com.google.gwt.event.dom.client.HasMouseOverHandlers#addMouseOverHandler(com.google.gwt.event.dom.client.MouseOverHandler) */ @Override public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) { return addDomHandler(handler, MouseOverEvent.getType()); } /** * @return the direct {@link MiceSplitLayoutPanel} */ private MiceSplitLayoutPanel getParentSplitLayoutPanel() { return (MiceSplitLayoutPanel) getParent().getParent(); } }