Java tutorial
/** * Copyright (C) 2012-2014 52North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2 as publishedby the Free * Software Foundation. * * If the program is linked with libraries which are licensed under one of the * following licenses, the combination of the program with the linked library is * not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed under * the aforementioned licenses, is permitted by the copyright holders if the * distribution is compliant with both the GNU General Public License version 2 * and the aforementioned licenses. * * This program 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 General Public License for more details. */ package org.n52.client.sos.ui; import org.eesgmbh.gimv.client.controls.KeystrokeControl; import org.eesgmbh.gimv.client.event.SetDomainBoundsEvent; import org.eesgmbh.gimv.client.event.SetDomainBoundsEventHandler; import org.eesgmbh.gimv.client.event.SetViewportPixelBoundsEvent; import org.eesgmbh.gimv.client.event.StateChangeEvent; import org.eesgmbh.gimv.client.presenter.ImagePresenter; import org.eesgmbh.gimv.client.presenter.MousePointerPresenter; import org.eesgmbh.gimv.client.presenter.TooltipPresenter; import org.eesgmbh.gimv.client.view.GenericWidgetView; import org.eesgmbh.gimv.client.view.GenericWidgetViewImpl; import org.eesgmbh.gimv.client.view.ImageViewImpl; import org.eesgmbh.gimv.client.widgets.Viewport; import org.eesgmbh.gimv.shared.util.Bound; import org.eesgmbh.gimv.shared.util.Bounds; import org.eesgmbh.gimv.shared.util.Direction; import org.n52.client.Application; import org.n52.client.bus.EventBus; import org.n52.client.ctrl.DataControls; import org.n52.client.ctrl.ExceptionHandler; import org.n52.client.sos.ctrl.DiagramTabController; import org.n52.client.sos.ctrl.DragImageControl; import org.n52.client.sos.ctrl.MouseWheelControl; import org.n52.client.sos.data.TimeseriesDataStore; import org.n52.client.ui.DataPanelTab; import org.n52.shared.Constants; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.smartgwt.client.types.Alignment; import com.smartgwt.client.types.DragAppearance; import com.smartgwt.client.widgets.Img; import com.smartgwt.client.widgets.Label; import com.smartgwt.client.widgets.layout.Layout; import com.smartgwt.client.widgets.layout.VStack; import org.eesgmbh.gimv.client.presenter.OverviewPresenter; public class DiagramTab extends DataPanelTab { private static DiagramTabController controller; /* * TODO: monitor impact of setting this public */ public static Layout layout; private Viewport mainChartViewport; private HTML verticalMousePointerLine; private Viewport overviewChartViewport; private EventBus overviewEventBus = EventBus.getOverviewChartEventBus(); private EventBus mainChartEventBus = EventBus.getMainEventBus(); protected TooltipPresenter tooltipPresenter; private HorizontalPanel horizontalSlider; // TODO use a flowpanel instead private int lastSliderPosition; private HTML leftHandleWidget; private HTML rightHandleWidget; private HTML mainHandleWidget; private Img mainChartLoadingSpinner; public DiagramTab(String ID, String title) { super("DiagramTab"); layout = new Layout(); MousePointerDomainBoundsHandler listener = new MousePointerDomainBoundsHandler(); this.mainChartEventBus.addHandler(SetDomainBoundsEvent.TYPE, listener); controller = new DiagramTabController(this); setID(ID); setTitle(title); setIcon("../img/icons/chart_curve.png"); } public static int getPanelHeight() { // - 100 overview height - 5 margin correction int height = layout.getParentElement().getHeight() - 100 - 5; if (Application.isHasStarted() && controller.getControls().isVisible()) { height -= controller.getControls().getHeight(); } return height; } public static int getPanelWidth() { int width = layout.getParentElement().getWidth() - 5; return width; } public void init() { try { setPane(layout); DiagramTab.layout.setVertical(true); this.mainChartViewport = getMainChartViewport(); this.overviewChartViewport = getOverviewChartViewport(); DiagramTab.layout.addMember(this.mainChartViewport); DiagramTab.layout.addMember(this.overviewChartViewport); initKeyControls(); initZooming(); initTooltips(); this.mainChartLoadingSpinner = new Img("../img/loader.gif"); this.mainChartLoadingSpinner.setWidth(32); this.mainChartLoadingSpinner.setHeight(32); this.mainChartLoadingSpinner.setLeft(getPanelWidth() / 2); this.mainChartLoadingSpinner.setTop(getPanelHeight() / 2); this.mainChartLoadingSpinner.hide(); this.mainChartViewport.add(this.mainChartLoadingSpinner); this.mainChartViewport.setHandlerManager(this.mainChartEventBus); this.overviewChartViewport.setHandlerManager(this.overviewEventBus); this.overviewEventBus.fireEvent(StateChangeEvent.createMove()); this.mainChartEventBus.fireEvent(StateChangeEvent.createMove()); this.mainChartEventBus.fireEvent(StateChangeEvent.createZoom()); int mainOffsetWidth = this.mainChartViewport.getOffsetWidth(); int mainOffsetHeight = this.mainChartViewport.getOffsetHeight(); Bounds mainBounds = new Bounds(mainOffsetWidth, 0, mainOffsetHeight, 0); int overviewOffsetWidth = this.overviewChartViewport.getOffsetWidth(); int overviewOffsetHeight = this.overviewChartViewport.getOffsetHeight(); Bounds overviewBounds = new Bounds(overviewOffsetWidth, 0, overviewOffsetHeight, 0); this.mainChartEventBus.fireEvent(new SetViewportPixelBoundsEvent(mainBounds)); this.overviewEventBus.fireEvent(new SetViewportPixelBoundsEvent(overviewBounds)); } catch (Exception e) { ExceptionHandler.handleUnexpectedException(e); } } private Viewport getMainChartViewport() { Image mainChartImage = new Image("img/blank.gif"); Viewport mainchart = new Viewport("100%", "100%"); mainchart.setEnableZoomWhenShiftkeyPressed(true); mainchart.add(mainChartImage); // as it is focusable, we do not want to see an outline DOM.setStyleAttribute(mainchart.getElement(), "outline", "none"); DOM.setStyleAttribute(mainchart.getElement(), "overflow", "visible"); ImageViewImpl imageView = new ImageViewImpl(mainChartImage); new ImagePresenter(this.mainChartEventBus, imageView); new DragImageControl(this.mainChartEventBus); new MouseWheelControl(this.mainChartEventBus); return mainchart; } private Viewport getOverviewChartViewport() { Image overviewChartImage = new Image("img/blank.gif"); Viewport overview = new Viewport("100%", "100px"); overview.add(overviewChartImage); DOM.setStyleAttribute(overview.getElement(), "outline", "none"); this.horizontalSlider = createOverviewSlider(); overview.add(this.horizontalSlider); ImageViewImpl imageView = new ImageViewImpl(overviewChartImage); new ImagePresenter(this.overviewEventBus, imageView); return overview; } /** * Creates the Slider the user can interact with to change the shown time intervals of the given * timeseries'. * * @return the TimeSlider as a whole */ private HorizontalPanel createOverviewSlider() { HorizontalPanel horizontalSlider = new HorizontalPanel(); DOM.setStyleAttribute(horizontalSlider.getElement(), "marginTop", "6px"); horizontalSlider.setHeight("75px"); this.leftHandleWidget = buildSliderPart("8px", "75px", "w-resize", "#6585d0", 0.5); this.rightHandleWidget = buildSliderPart("8px", "75px", "e-resize", "#6585d0", 0.5); this.mainHandleWidget = buildSliderPart("100%", "75px", "move", "#aaa", 0.5); horizontalSlider.add(this.leftHandleWidget); horizontalSlider.setCellWidth(this.leftHandleWidget, "15px"); horizontalSlider.add(this.mainHandleWidget); horizontalSlider.setCellWidth(this.mainHandleWidget, "100%"); horizontalSlider.add(this.rightHandleWidget); horizontalSlider.setCellWidth(this.rightHandleWidget, "15px"); DOM.setStyleAttribute(horizontalSlider.getElement(), "visibility", "hidden"); GenericWidgetViewImpl view = new GenericWidgetViewImpl(horizontalSlider); OverviewPresenter overviewPresenter = new OverviewPresenter(view, this.overviewEventBus, this.mainChartEventBus); // Define handles for overview control GenericWidgetView leftHandle = new GenericWidgetViewImpl(this.leftHandleWidget); GenericWidgetView mainHandle = new GenericWidgetViewImpl(this.mainHandleWidget); GenericWidgetView rightHandle = new GenericWidgetViewImpl(this.rightHandleWidget); overviewPresenter.addHandle(leftHandle, Bound.LEFT); overviewPresenter.addHandle(mainHandle, Bound.RIGHT, Bound.LEFT); overviewPresenter.addHandle(rightHandle, Bound.RIGHT); overviewPresenter.setMinClippingWidth(40); // min width overviewPresenter.setVerticallyLocked(true); // drag horizontally only return horizontalSlider; } private HTML buildSliderPart(String width, String height, String cursor, String color, double transparancy) { HTML container = new HTML(); container.setWidth(width); container.setHeight(height); DOM.setStyleAttribute(container.getElement(), "cursor", cursor); DOM.setStyleAttribute(container.getElement(), "backgroundColor", color); // transparency styling (see also bug#449 and http://www.quirksmode.org/css/opacity.html) // note: since GWT complains, '-msFilter' has to be in plain camelCase (w/o '-') // ordering is important here DOM.setStyleAttribute(container.getElement(), "opacity", Double.toString(transparancy)); DOM.setStyleAttribute(container.getElement(), "mozOpacity", Double.toString(transparancy)); String opacity = "(opacity=" + Double.toString(transparancy * 100) + ")"; DOM.setStyleAttribute(container.getElement(), "msFilter", "\"progid:DXImageTransform.Microsoft.Alpha" + opacity + "\""); DOM.setStyleAttribute(container.getElement(), "filter", "alpha" + opacity); return container; } private void initKeyControls() { KeystrokeControl kCtrl = new KeystrokeControl(this.mainChartEventBus); kCtrl.addTargetElement(this.mainChartViewport.getElement()); kCtrl.addTargetElement(this.overviewChartViewport.getElement()); kCtrl.addDocumentAndBodyAsTarget(); // 10px offset each kCtrl.registerKey(KeyCodes.KEY_LEFT, Direction.EAST, 10); kCtrl.registerKey(KeyCodes.KEY_UP, Direction.SOUTH, 10); kCtrl.registerKey(KeyCodes.KEY_RIGHT, Direction.WEST, 10); kCtrl.registerKey(KeyCodes.KEY_DOWN, Direction.NORTH, 10); // 30px offset if ctrl is pressed kCtrl.registerKey(KeyCodes.KEY_LEFT, true, false, false, false, Direction.EAST, 30); kCtrl.registerKey(KeyCodes.KEY_UP, true, false, false, false, Direction.NORTH, 30); kCtrl.registerKey(KeyCodes.KEY_RIGHT, true, false, false, false, Direction.WEST, 30); kCtrl.registerKey(KeyCodes.KEY_DOWN, true, false, false, false, Direction.SOUTH, 30); } private void initZooming() { HTML zoomBox = new HTML(); DOM.setStyleAttribute(zoomBox.getElement(), "opacity", "0.15"); DOM.setStyleAttribute(zoomBox.getElement(), "mozOpacity", "0.15"); DOM.setStyleAttribute(zoomBox.getElement(), "msFilter", "\"progid:DXImageTransform.Microsoft.Alpha(Opacity=15)\""); DOM.setStyleAttribute(zoomBox.getElement(), "filter", "alpha(opacity=15)"); DOM.setStyleAttribute(zoomBox.getElement(), "outline", "black dashed 1px"); DOM.setStyleAttribute(zoomBox.getElement(), "backgroundColor", "blue"); DOM.setStyleAttribute(zoomBox.getElement(), "visibility", "hidden"); this.mainChartViewport.add(zoomBox); GenericWidgetView zoomBoxView = new GenericWidgetViewImpl(zoomBox); new ZoomBoxPresenter(this.mainChartEventBus, zoomBoxView); } private void initTooltips() { Element mousePointerElement = getMousePointerLineElement(); DOM.setStyleAttribute(mousePointerElement, "backgroundColor", "blue"); DOM.setStyleAttribute(mousePointerElement, "width", "0px"); DOM.setStyleAttribute(mousePointerElement, "height", "0px"); DOM.setStyleAttribute(mousePointerElement, "visibility", "hidden"); DOM.setStyleAttribute(mousePointerElement, "marginTop", "6px"); this.mainChartViewport.add(this.verticalMousePointerLine); this.tooltipPresenter = new TooltipPresenter(this.mainChartEventBus); this.tooltipPresenter.configureHoverMatch(true, false, false); this.tooltipPresenter.setTooltipZIndex(Constants.Z_INDEX_ON_TOP); GenericWidgetViewImpl widget = new GenericWidgetViewImpl(this.verticalMousePointerLine); MousePointerPresenter mpp = new MousePointerPresenter(this.mainChartEventBus, widget); mpp.configure(true, false); } public void setVisibleSlider(boolean isVisible) { if (this.horizontalSlider != null) { this.horizontalSlider.setVisible(isVisible); } } public void addSlider() { if (this.horizontalSlider == null && this.overviewChartViewport != null) { this.horizontalSlider = createOverviewSlider(); this.overviewChartViewport.add(this.horizontalSlider, this.lastSliderPosition, 0); } } public void removeSlider() { if (this.horizontalSlider != null) { this.lastSliderPosition = this.overviewChartViewport.getWidgetLeft(this.horizontalSlider); // int left = this.leftHandleWidget.getAbsoluteLeft() + this.leftHandleWidget.getOffsetWidth(); // int right = this.rightHandleWidget.getAbsoluteLeft(); // this.lastMainHandleWidth = right - left; this.overviewChartViewport.remove(this.horizontalSlider); this.horizontalSlider = null; } } protected Element getMousePointerLineElement() { if (this.verticalMousePointerLine == null) { this.verticalMousePointerLine = new HTML(); } return this.verticalMousePointerLine.getElement(); } @Override public DataControls getDataControls() { return controller.getControls(); } public void redraw() { layout.markForRedraw(); } public EventBus getOvervieweventBus() { return this.overviewEventBus; } protected class MousePointerDomainBoundsHandler implements SetDomainBoundsEventHandler { public void onSetDomainBounds(SetDomainBoundsEvent event) { if (!TimeseriesDataStore.getTimeSeriesDataStore().getDataItems().isEmpty()) { String[] widthHeight = getBoundValues(event); Element mousePointerElement = DiagramTab.this.getMousePointerLineElement(); DOM.setStyleAttribute(mousePointerElement, "width", widthHeight[0]); DOM.setStyleAttribute(mousePointerElement, "height", widthHeight[1]); setTooltipsOnTop(event); } } /** * @return String array with width as 1st and height as 2nd element. */ private String[] getBoundValues(SetDomainBoundsEvent event) { String absWidth = (isWidthWiderOne(event)) ? "1px" : "0px"; String absHeight = Double.toString(event.getBounds().getAbsHeight()) + "px"; return new String[] { absWidth, absHeight }; } private void setTooltipsOnTop(SetDomainBoundsEvent event) { if (isWidthWiderOne(event)) { DiagramTab.this.tooltipPresenter.setTooltipZIndex(Constants.Z_INDEX_ON_TOP); } else { DiagramTab.this.tooltipPresenter.setTooltipZIndex(0); } } private boolean isWidthWiderOne(SetDomainBoundsEvent event) { return event.getBounds().getAbsWidth() > 1; } } /** * */ public void hideTooltips() { DOM.setStyleAttribute(DiagramTab.this.verticalMousePointerLine.getElement(), "width", "0px"); this.tooltipPresenter.setTooltipZIndex(0); } class DraggableVStack extends VStack { public DraggableVStack() { setSize("200", "30"); setCanDrag(true); setBackgroundColor("#000000"); } } public static class DragLabel extends Label { public DragLabel() { setAlign(Alignment.CENTER); setPadding(4); setShowEdges(true); setMinWidth(70); setMinHeight(70); setMaxWidth(300); setMaxHeight(200); setKeepInParentRect(true); setCanDragReposition(true); setDragAppearance(DragAppearance.TARGET); } } public void hideLoadingSpinner() { mainChartLoadingSpinner.hide(); } public void showLoadingSpinner() { if (mainChartLoadingSpinner != null) { mainChartLoadingSpinner.show(); } } }