mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-04 11:23:50 +00:00
Merge branch 'generic_fixes' into gwt
This commit is contained in:
commit
6a759a6158
22 files changed
+859
-127
No files matched your search
+3
@@ -5,6 +5,9 @@ import com.google.gwt.resources.client.ImageResource;
|
||||
|
||||
interface AdminConsoleResources extends ClientBundle {
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settings.png")
|
||||
ImageResource settingsIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/remove.png")
|
||||
ImageResource removeIcon();
|
||||
|
||||
|
||||
+8
-3
@@ -3,12 +3,14 @@ package com.sap.sailing.gwt.ui.adminconsole;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.maps.client.geom.LatLng;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.AbstractImagePrototype;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Grid;
|
||||
@@ -48,6 +50,8 @@ public class RaceMapPanel extends FormPanel implements EventDisplayer, TimeListe
|
||||
private final RaceMap raceMap;
|
||||
private final QuickRanksListBoxComposite quickRanksListBox;
|
||||
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
public RaceMapPanel(SailingServiceAsync sailingService, CompetitorSelectionProvider competitorSelectionProvider,
|
||||
ErrorReporter errorReporter, final EventRefresher eventRefresher, final StringMessages stringMessages) {
|
||||
this.sailingService = sailingService;
|
||||
@@ -79,8 +83,9 @@ public class RaceMapPanel extends FormPanel implements EventDisplayer, TimeListe
|
||||
/* time interval between displays in milliseconds */5000, stringMessages, errorReporter);
|
||||
raceListBox.addRaceSelectionChangeListener(windHistory);
|
||||
grid.setWidget(1, 0, windHistory);
|
||||
Anchor showConfigAnchor = new Anchor(new SafeHtmlBuilder().appendHtmlConstant(
|
||||
"<img class=\"linkNoBorder\" src=\"/gwt/images/settings.png\"/>").toSafeHtml());
|
||||
|
||||
ImageResource settingsImage = resources.settingsIcon();
|
||||
Anchor showConfigAnchor = new Anchor(AbstractImagePrototype.create(settingsImage).getSafeHtml());
|
||||
showConfigAnchor.setTitle(stringMessages.configuration());
|
||||
showConfigAnchor.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.components.CollapsablePanel;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentGroup;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentToolbar;
|
||||
|
||||
/**
|
||||
* A GWT component that visualizes a {@link Component} or a {@link Component} including menus to scroll quickly to the embedded view
|
||||
* of the respective component, collapse/expand buttons for the views embedded and homogeneous settings buttons for
|
||||
* those components that have settings.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CollapsableComponentViewer<SettingsType> {
|
||||
private final CollapsablePanel disclosurePanel;
|
||||
|
||||
private final Component<SettingsType> component;
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public CollapsableComponentViewer(Component<SettingsType> component, StringMessages stringMessages) {
|
||||
this.component = component;
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
AbsolutePanel contentPanel = new AbsolutePanel();
|
||||
disclosurePanel = createDisclosePanel(contentPanel, component.getLocalizedShortName(), 150);
|
||||
}
|
||||
|
||||
public Widget getViewerWidget() {
|
||||
return disclosurePanel;
|
||||
}
|
||||
|
||||
public Component<?> getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
private CollapsablePanel createDisclosePanel(Panel contentPanel, String panelTitle, int heightInPx)
|
||||
{
|
||||
CollapsablePanel disclosurePanel = new CollapsablePanel (panelTitle);
|
||||
disclosurePanel.setSize("100%", "100%");
|
||||
disclosurePanel.setOpen(true);
|
||||
|
||||
ComponentToolbar<SettingsType> toolbar = new ComponentToolbar<SettingsType>(component, stringMessages);
|
||||
toolbar.addSettingsButton();
|
||||
disclosurePanel.setHeaderToolbar(toolbar);
|
||||
|
||||
contentPanel.setSize("100%", heightInPx + "px");
|
||||
disclosurePanel.setContent(contentPanel);
|
||||
if(component.getEntryWidget() != null) {
|
||||
contentPanel.add(component.getEntryWidget());
|
||||
} else {
|
||||
if(component instanceof ComponentGroup) {
|
||||
Iterable<Component<?>> components = ((ComponentGroup<?>) component).getComponents();
|
||||
for(Component<?> c: components) {
|
||||
if(c.getEntryWidget() != null)
|
||||
contentPanel.add(c.getEntryWidget());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return disclosurePanel;
|
||||
}
|
||||
|
||||
}
|
||||
+27
-53
@@ -1,26 +1,20 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.DisclosurePanel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.RaceMap;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.Timer;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
import com.sap.sailing.server.api.DefaultLeaderboardName;
|
||||
|
||||
public class RaceBoardPanel extends FormPanel implements Component<RaceBoardSettings> {
|
||||
|
||||
@@ -28,66 +22,45 @@ public class RaceBoardPanel extends FormPanel implements Component<RaceBoardSett
|
||||
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
// TODO Frank to use these later
|
||||
// private final StringMessages stringMessages;
|
||||
|
||||
private String raceBoardName;
|
||||
|
||||
private static RaceBoardResources resources = GWT.create(RaceBoardResources.class);
|
||||
|
||||
// TODO Frank to use these later
|
||||
// private List<DisclosurePanel> collapsablePanels;
|
||||
|
||||
private final CompetitorSelectionProvider competitorSelectionProvider;
|
||||
private final List<CollapsableComponentViewer<?>> collapsableViewers;
|
||||
|
||||
public RaceBoardPanel(SailingServiceAsync sailingService, String raceBoardName, ErrorReporter errorReporter,
|
||||
final StringMessages stringMessages) {
|
||||
this.sailingService = sailingService;
|
||||
this.setRaceBoardName(raceBoardName);
|
||||
this.errorReporter = errorReporter;
|
||||
// TODO Frank to use these later
|
||||
// this.stringMessages = stringMessages;
|
||||
|
||||
VerticalPanel mainPanel = new VerticalPanel();
|
||||
mainPanel.setSize("100%", "100%");
|
||||
setWidget(mainPanel);
|
||||
competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true);
|
||||
RaceMap raceMap = new RaceMap(sailingService, errorReporter, new Timer(
|
||||
/* delayBetweenAutoAdvancesInMilliseconds */500), competitorSelectionProvider, stringMessages);
|
||||
collapsableViewers = new ArrayList<CollapsableComponentViewer<?>>();
|
||||
for(int i = 0; i < 4; i++) {
|
||||
if(i == 0) {
|
||||
AbsolutePanel contentPanel = new AbsolutePanel();
|
||||
DisclosurePanel panel = createDisclosePanel(contentPanel, "Panel " + i, 300);
|
||||
CompetitorSelectionModel competitorSelectionModel = new CompetitorSelectionModel(/* hasMultiSelection */ true);
|
||||
//final RaceMapPanel raceMapPanel = new RaceMapPanel(sailingService, competitorSelectionModel, this, this, stringMessages);
|
||||
LeaderboardPanel defaultLeaderboardPanel = new LeaderboardPanel(sailingService, competitorSelectionModel,
|
||||
DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME, errorReporter, stringMessages);
|
||||
|
||||
raceMap.loadMapsAPI(contentPanel);
|
||||
mainPanel.add(panel);
|
||||
CollapsableComponentViewer<LeaderboardSettings> viewer = new CollapsableComponentViewer<LeaderboardSettings>(
|
||||
defaultLeaderboardPanel, stringMessages);
|
||||
collapsableViewers.add(viewer);
|
||||
} else {
|
||||
VerticalPanel contentPanel = new VerticalPanel();
|
||||
DisclosurePanel panel = createDisclosePanel(contentPanel, "Panel " + i, 100);
|
||||
contentPanel.add(new Label("Content of panel " + i));
|
||||
mainPanel.add(panel);
|
||||
SimpleComponentGroup<Object> componentGroup = new SimpleComponentGroup<Object>("Component Group " + i);
|
||||
componentGroup.addComponent(new SimpleComponent("My Component"));
|
||||
componentGroup.addComponent(new SimpleComponent("My Component 2"));
|
||||
componentGroup.addComponent(new SimpleComponent("My Component 3"));
|
||||
|
||||
//LeaderboardPanel leaderboardPanel = LeaderboardPanel();
|
||||
CollapsableComponentViewer<Object> viewer = new CollapsableComponentViewer<Object>(componentGroup, stringMessages);
|
||||
collapsableViewers.add(viewer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DisclosurePanel createDisclosePanel(Panel contentPanel, String panelTitle, int heightInPx) {
|
||||
DisclosurePanel disclosurePanel = new DisclosurePanel (resources.openIcon(), resources.closeIcon(), panelTitle);
|
||||
disclosurePanel.setSize("100%", "100%");
|
||||
disclosurePanel.setOpen(true);
|
||||
contentPanel.setSize("100%", heightInPx + "px");
|
||||
disclosurePanel.setContent(contentPanel);
|
||||
|
||||
disclosurePanel.addOpenHandler(new OpenHandler<DisclosurePanel>() {
|
||||
@Override
|
||||
public void onOpen(OpenEvent<DisclosurePanel> event) {
|
||||
}
|
||||
});
|
||||
disclosurePanel.addCloseHandler(new CloseHandler<DisclosurePanel>() {
|
||||
@Override
|
||||
public void onClose(CloseEvent<DisclosurePanel> event) {
|
||||
}
|
||||
});
|
||||
return disclosurePanel;
|
||||
for (CollapsableComponentViewer<?> viewer : collapsableViewers) {
|
||||
mainPanel.add(viewer.getViewerWidget());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,3 +103,4 @@ public class RaceBoardPanel extends FormPanel implements Component<RaceBoardSett
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -11,4 +11,6 @@ interface RaceBoardResources extends ClientBundle {
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/close.png")
|
||||
ImageResource closeIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settings.png")
|
||||
ImageResource settingsIcon();
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class SimpleComponent implements Component<SimpleComponentSettings> {
|
||||
|
||||
private String componentName;
|
||||
|
||||
private final Label label;
|
||||
public SimpleComponent(String componentName) {
|
||||
this.componentName = componentName;
|
||||
|
||||
label = new Label("Ich bin eine Label component");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedShortName() {
|
||||
return componentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getEntryWidget() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<SimpleComponentSettings> getSettingsDialogComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(SimpleComponentSettings newSettings) {
|
||||
}
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentGroup;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class SimpleComponentGroup<SettingsType> implements ComponentGroup<SettingsType> {
|
||||
|
||||
private String groupName;
|
||||
|
||||
private final List<Component<?>> components;
|
||||
|
||||
public SimpleComponentGroup(String groupName) {
|
||||
this.groupName = groupName;
|
||||
components = new ArrayList<Component<?>>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSettings() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<SettingsType> getSettingsDialogComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(SettingsType newSettings) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalizedShortName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget getEntryWidget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addComponent(Component<?> component) {
|
||||
return components.add(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeComponent(Component<?> component) {
|
||||
return components.remove(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Component<?>> getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
public class SimpleComponentSettings {
|
||||
|
||||
}
|
||||
+427
@@ -0,0 +1,427 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.gwt.animation.client.Animation;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.HasCloseHandlers;
|
||||
import com.google.gwt.event.logical.shared.HasOpenHandlers;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.DockPanel;
|
||||
import com.google.gwt.user.client.ui.HasAnimation;
|
||||
import com.google.gwt.user.client.ui.HasText;
|
||||
import com.google.gwt.user.client.ui.HasWidgets;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.IsWidget;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
* A widget that consists of a header and a content panel that discloses the content when a user clicks on the header.
|
||||
*
|
||||
* <h3>CSS Style Rules</h3>
|
||||
* <dl class="css">
|
||||
* <dt>.gwt-DisclosurePanel
|
||||
* <dd>the panel's primary style
|
||||
* <dt>.gwt-DisclosurePanel-open
|
||||
* <dd>dependent style set when panel is open
|
||||
* <dt>.gwt-DisclosurePanel-closed
|
||||
* <dd>dependent style set when panel is closed
|
||||
* </dl>
|
||||
* <p>
|
||||
* The header and content sections can be easily selected using css with a child selector:<br/>
|
||||
* .gwt-DisclosurePanel-open .header { ... }
|
||||
* </p>
|
||||
*/
|
||||
public final class CollapsablePanel extends Composite implements HasWidgets.ForIsWidget, HasAnimation,
|
||||
HasOpenHandlers<CollapsablePanel>, HasCloseHandlers<CollapsablePanel> {
|
||||
|
||||
private static ComponentResources resources = GWT.create(ComponentResources.class);
|
||||
|
||||
/**
|
||||
* Used to wrap widgets in the header to provide click support. Effectively wraps the widget in an
|
||||
* <code>anchor</code> to get automatic keyboard access.
|
||||
*/
|
||||
private final class ClickableHeader extends SimplePanel {
|
||||
|
||||
private ClickableHeader() {
|
||||
// Anchor is used to allow keyboard access.
|
||||
super(DOM.createAnchor());
|
||||
Element elem = getElement();
|
||||
DOM.setElementProperty(elem, "href", "javascript:void(0);");
|
||||
// Avoids layout problems from having blocks in inlines.
|
||||
DOM.setStyleAttribute(elem, "display", "block");
|
||||
sinkEvents(Event.ONCLICK);
|
||||
setStyleName(STYLENAME_HEADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Event event) {
|
||||
// no need to call super.
|
||||
switch (DOM.eventGetType(event)) {
|
||||
case Event.ONCLICK:
|
||||
// Prevent link default action.
|
||||
DOM.eventPreventDefault(event);
|
||||
setOpen(!isOpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link Animation} used to open the content.
|
||||
*/
|
||||
private static class ContentAnimation extends Animation {
|
||||
/**
|
||||
* Whether the item is being opened or closed.
|
||||
*/
|
||||
private boolean opening;
|
||||
|
||||
/**
|
||||
* The {@link CollapsablePanel} being affected.
|
||||
*/
|
||||
private CollapsablePanel curPanel;
|
||||
|
||||
/**
|
||||
* Open or close the content.
|
||||
*
|
||||
* @param panel
|
||||
* the panel to open or close
|
||||
* @param animate
|
||||
* true to animate, false to open instantly
|
||||
*/
|
||||
public void setOpen(CollapsablePanel panel, boolean animate) {
|
||||
// Immediately complete previous open
|
||||
cancel();
|
||||
|
||||
// Open the new item
|
||||
if (animate) {
|
||||
curPanel = panel;
|
||||
opening = panel.isOpen;
|
||||
run(ANIMATION_DURATION);
|
||||
} else {
|
||||
panel.contentWrapper.setVisible(panel.isOpen);
|
||||
if (panel.isOpen) {
|
||||
// Special treatment on the visible case to ensure LazyPanel works
|
||||
panel.getContent().setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onComplete() {
|
||||
if (!opening) {
|
||||
curPanel.contentWrapper.setVisible(false);
|
||||
}
|
||||
DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height", "auto");
|
||||
curPanel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
if (opening) {
|
||||
curPanel.contentWrapper.setVisible(true);
|
||||
// Special treatment on the visible case to ensure LazyPanel works
|
||||
curPanel.getContent().setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdate(double progress) {
|
||||
int scrollHeight = DOM.getElementPropertyInt(curPanel.contentWrapper.getElement(), "scrollHeight");
|
||||
int height = (int) (progress * scrollHeight);
|
||||
if (!opening) {
|
||||
height = scrollHeight - height;
|
||||
}
|
||||
height = Math.max(height, 1);
|
||||
DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "height", height + "px");
|
||||
DOM.setStyleAttribute(curPanel.contentWrapper.getElement(), "width", "auto");
|
||||
}
|
||||
}
|
||||
|
||||
public interface Imager {
|
||||
Image makeImage();
|
||||
|
||||
void updateImage(boolean open, Image image);
|
||||
}
|
||||
|
||||
/**
|
||||
* The duration of the animation.
|
||||
*/
|
||||
private static final int ANIMATION_DURATION = 350;
|
||||
|
||||
// Stylename constants.
|
||||
private static final String STYLENAME_DEFAULT = "gwt-DisclosurePanel";
|
||||
|
||||
private static final String STYLENAME_SUFFIX_OPEN = "open";
|
||||
|
||||
private static final String STYLENAME_SUFFIX_CLOSED = "closed";
|
||||
|
||||
private static final String STYLENAME_HEADER = "header";
|
||||
|
||||
private static final String STYLENAME_CONTENT = "content";
|
||||
|
||||
/**
|
||||
* The {@link Animation} used to open and close the content.
|
||||
*/
|
||||
private static ContentAnimation contentAnimation;
|
||||
|
||||
/**
|
||||
* top level widget. The first child will be a reference to {@link #header}. The second child will be a reference to
|
||||
* {@link #contentWrapper}.
|
||||
*/
|
||||
private final VerticalPanel mainPanel = new VerticalPanel();
|
||||
|
||||
/**
|
||||
* The wrapper around the content widget.
|
||||
*/
|
||||
private final SimplePanel contentWrapper = new SimplePanel();
|
||||
|
||||
/**
|
||||
* holds the header widget.
|
||||
*/
|
||||
private final DockPanel header = new DockPanel();
|
||||
|
||||
private final ClickableHeader clickableHeader = new ClickableHeader();
|
||||
|
||||
private boolean isAnimationEnabled = false;
|
||||
|
||||
private boolean isOpen = false;
|
||||
|
||||
/**
|
||||
* Creates an empty ThePanel that is initially closed.
|
||||
*/
|
||||
private CollapsablePanel() {
|
||||
initWidget(mainPanel);
|
||||
|
||||
header.setStyleName("hallo");
|
||||
mainPanel.add(header);
|
||||
mainPanel.add(contentWrapper);
|
||||
DOM.setStyleAttribute(contentWrapper.getElement(), "padding", "0px");
|
||||
DOM.setStyleAttribute(contentWrapper.getElement(), "overflow", "hidden");
|
||||
setStyleName(STYLENAME_DEFAULT);
|
||||
setContentDisplay(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ThePanel with the specified header text, an initial open/close state and a bundle of images to be used
|
||||
* in the default header widget.
|
||||
*
|
||||
* @param openImage
|
||||
* the open state image resource
|
||||
* @param closedImage
|
||||
* the closed state image resource
|
||||
* @param headerText
|
||||
* the text to be displayed in the header
|
||||
*/
|
||||
public CollapsablePanel(ImageResource openImage, ImageResource closedImage, String headerText) {
|
||||
this();
|
||||
setClickableHeader(new CollapsablePanelDefaultHeader(this, openImage, closedImage, headerText));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ThePanel that will be initially closed using the specified text in the header.
|
||||
*
|
||||
* @param headerText
|
||||
* the text to be displayed in the header
|
||||
*/
|
||||
public CollapsablePanel(String headerText) {
|
||||
this(resources.openIcon(), resources.closeIcon(), headerText);
|
||||
}
|
||||
|
||||
private void setClickableHeader(Widget widget) {
|
||||
clickableHeader.add(widget);
|
||||
header.add(clickableHeader, DockPanel.WEST);
|
||||
}
|
||||
|
||||
public void setHeaderToolbar(HorizontalPanel toolbar) {
|
||||
header.add(toolbar, DockPanel.EAST);
|
||||
}
|
||||
|
||||
public void add(Widget w) {
|
||||
if (this.getContent() == null) {
|
||||
setContent(w);
|
||||
} else {
|
||||
throw new IllegalStateException("A DisclosurePanel can only contain two Widgets.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded version for IsWidget.
|
||||
*
|
||||
* @see #add(Widget)
|
||||
*/
|
||||
public void add(IsWidget w) {
|
||||
this.add(asWidgetOrNull(w));
|
||||
}
|
||||
|
||||
public HandlerRegistration addCloseHandler(CloseHandler<CollapsablePanel> handler) {
|
||||
return addHandler(handler, CloseEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addOpenHandler(OpenHandler<CollapsablePanel> handler) {
|
||||
return addHandler(handler, OpenEvent.getType());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
setContent(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the widget that was previously set in {@link #setContent(Widget)}.
|
||||
*
|
||||
* @return the panel's current content widget
|
||||
*/
|
||||
public Widget getContent() {
|
||||
return contentWrapper.getWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the widget that is currently being used as a header.
|
||||
*
|
||||
* @return the widget currently being used as a header
|
||||
*/
|
||||
public Widget getHeader() {
|
||||
return header.asWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link HasText} instance to provide access to the headers's text, if the header widget does provide such
|
||||
* access.
|
||||
*
|
||||
* @return a reference to the header widget if it implements {@link HasText}, <code>null</code> otherwise
|
||||
*/
|
||||
public HasText getHeaderTextAccessor() {
|
||||
Widget widget = header.asWidget();
|
||||
return (widget instanceof HasText) ? (HasText) widget : null;
|
||||
}
|
||||
|
||||
public boolean isAnimationEnabled() {
|
||||
return isAnimationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the panel is open.
|
||||
*
|
||||
* @return <code>true</code> if panel is in open state
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
public Iterator<Widget> iterator() {
|
||||
return null;
|
||||
// return WidgetIterators.createWidgetIterator(this,
|
||||
// new Widget[] {getContent()});
|
||||
}
|
||||
|
||||
public boolean remove(Widget w) {
|
||||
if (w == getContent()) {
|
||||
setContent(null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded version for IsWidget.
|
||||
*
|
||||
* @see #remove(Widget)
|
||||
*/
|
||||
public boolean remove(IsWidget w) {
|
||||
return this.remove(asWidgetOrNull(w));
|
||||
}
|
||||
|
||||
public void setAnimationEnabled(boolean enable) {
|
||||
isAnimationEnabled = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content widget which can be opened and closed by this panel. If there is a preexisting content widget,
|
||||
* it will be detached.
|
||||
*
|
||||
* @param content
|
||||
* the widget to be used as the content panel
|
||||
*/
|
||||
public void setContent(Widget content) {
|
||||
final Widget currentContent = getContent();
|
||||
|
||||
// Remove existing content widget.
|
||||
if (currentContent != null) {
|
||||
contentWrapper.setWidget(null);
|
||||
currentContent.removeStyleName(STYLENAME_CONTENT);
|
||||
}
|
||||
|
||||
// Add new content widget if != null.
|
||||
if (content != null) {
|
||||
contentWrapper.setWidget(content);
|
||||
content.addStyleName(STYLENAME_CONTENT);
|
||||
setContentDisplay(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the visible state of this <code>ThePanel</code>.
|
||||
*
|
||||
* @param isOpen
|
||||
* <code>true</code> to open the panel, <code>false</code> to close
|
||||
*/
|
||||
public void setOpen(boolean isOpen) {
|
||||
if (this.isOpen != isOpen) {
|
||||
this.isOpen = isOpen;
|
||||
setContentDisplay(true);
|
||||
fireEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Affected Elements:</b>
|
||||
* <ul>
|
||||
* <li>-header = the clickable header.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see UIObject#onEnsureDebugId(String)
|
||||
*/
|
||||
@Override
|
||||
protected void onEnsureDebugId(String baseID) {
|
||||
super.onEnsureDebugId(baseID);
|
||||
header.ensureDebugId(baseID + "-header");
|
||||
}
|
||||
|
||||
private void fireEvent() {
|
||||
if (isOpen) {
|
||||
OpenEvent.fire(this, this);
|
||||
} else {
|
||||
CloseEvent.fire(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void setContentDisplay(boolean animate) {
|
||||
if (isOpen) {
|
||||
removeStyleDependentName(STYLENAME_SUFFIX_CLOSED);
|
||||
addStyleDependentName(STYLENAME_SUFFIX_OPEN);
|
||||
} else {
|
||||
removeStyleDependentName(STYLENAME_SUFFIX_OPEN);
|
||||
addStyleDependentName(STYLENAME_SUFFIX_CLOSED);
|
||||
}
|
||||
|
||||
if (getContent() != null) {
|
||||
if (contentAnimation == null) {
|
||||
contentAnimation = new ContentAnimation();
|
||||
}
|
||||
contentAnimation.setOpen(this, animate && isAnimationEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.ui.HasText;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.shared.components.CollapsablePanel.Imager;
|
||||
|
||||
/**
|
||||
* The default header widget used within a {@link CollapsablePanel}.
|
||||
*/
|
||||
public class CollapsablePanelDefaultHeader extends Widget implements HasText, OpenHandler<CollapsablePanel>,
|
||||
CloseHandler<CollapsablePanel> {
|
||||
|
||||
/**
|
||||
* imageTD holds the image for the icon, not null. labelTD holds the text for the label.
|
||||
*/
|
||||
private final Element labelTD;
|
||||
|
||||
private final Image iconImage;
|
||||
private final Imager imager;
|
||||
private final CollapsablePanel collapsablePanel;
|
||||
|
||||
protected CollapsablePanelDefaultHeader(CollapsablePanel collapsablePanel, Imager imager, String text) {
|
||||
this.imager = imager;
|
||||
this.collapsablePanel = collapsablePanel;
|
||||
iconImage = imager.makeImage();
|
||||
|
||||
// I do not need any Widgets here, just a DOM structure.
|
||||
Element root = DOM.createTable();
|
||||
Element tbody = DOM.createTBody();
|
||||
Element tr = DOM.createTR();
|
||||
final Element imageTD = DOM.createTD();
|
||||
labelTD = DOM.createTD();
|
||||
|
||||
setElement(root);
|
||||
|
||||
DOM.appendChild(root, tbody);
|
||||
DOM.appendChild(tbody, tr);
|
||||
DOM.appendChild(tr, imageTD);
|
||||
DOM.appendChild(tr, labelTD);
|
||||
|
||||
// set image TD to be same width as image.
|
||||
DOM.setElementProperty(imageTD, "align", "center");
|
||||
DOM.setElementProperty(imageTD, "valign", "middle");
|
||||
DOM.setStyleAttribute(imageTD, "width", iconImage.getWidth() + "px");
|
||||
|
||||
DOM.appendChild(imageTD, iconImage.getElement());
|
||||
|
||||
setText(text);
|
||||
|
||||
collapsablePanel.addOpenHandler(this);
|
||||
collapsablePanel.addCloseHandler(this);
|
||||
setStyle();
|
||||
}
|
||||
|
||||
protected CollapsablePanelDefaultHeader(CollapsablePanel collapsablePanel, final ImageResource openImage,
|
||||
final ImageResource closedImage, String text) {
|
||||
this(collapsablePanel, new Imager() {
|
||||
public Image makeImage() {
|
||||
return new Image(closedImage);
|
||||
}
|
||||
|
||||
public void updateImage(boolean open, Image image) {
|
||||
if (open) {
|
||||
image.setResource(openImage);
|
||||
} else {
|
||||
image.setResource(closedImage);
|
||||
}
|
||||
}
|
||||
}, text);
|
||||
}
|
||||
|
||||
public final String getText() {
|
||||
return DOM.getInnerText(labelTD);
|
||||
}
|
||||
|
||||
public final void onClose(CloseEvent<CollapsablePanel> event) {
|
||||
setStyle();
|
||||
}
|
||||
|
||||
public final void onOpen(OpenEvent<CollapsablePanel> event) {
|
||||
setStyle();
|
||||
}
|
||||
|
||||
public final void setText(String text) {
|
||||
DOM.setInnerText(labelTD, text);
|
||||
}
|
||||
|
||||
private void setStyle() {
|
||||
imager.updateImage(collapsablePanel.isOpen(), iconImage);
|
||||
}
|
||||
}
|
||||
+10
-14
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
@@ -8,23 +10,17 @@ package com.sap.sailing.gwt.ui.shared.components;
|
||||
* the type that describes this component's settings (if any). Use {@link Object} in case your components
|
||||
* doesn't support any settings.
|
||||
*/
|
||||
public interface Component<SettingsType> extends ComponentForestEntry {
|
||||
public interface Component<SettingsType> extends ComponentSettings<SettingsType> {
|
||||
|
||||
/**
|
||||
* @return whether this component has settings that a user may change; if so,
|
||||
* @return the name to display to a user for quick navigation to this component
|
||||
*/
|
||||
boolean hasSettings();
|
||||
String getLocalizedShortName();
|
||||
|
||||
/**
|
||||
* If this component {@link #hasSettings has settings}, this method may return a component for the settings dialog.
|
||||
* It will be used to obtain a widget shown in the settings dialog, a validator for the component-specific settings,
|
||||
* as well as to produce a result from the widget's state when the settings dialog wants to validate or return the
|
||||
* settings.
|
||||
* A component may or may not have a {@link Widget} used to render its contents. Typically,
|
||||
* entries with sub-entries don't afford a widget of their own but let the framework choose a container
|
||||
* in which to aggregate their entries' widgets.
|
||||
*/
|
||||
SettingsDialogComponent<SettingsType> getSettingsDialogComponent();
|
||||
|
||||
/**
|
||||
* Updates the settings of this component. Expected to be called when a settings dialog using this component's
|
||||
* {@link #getSettingsDialogComponent()} has been confirmed.
|
||||
*/
|
||||
void updateSettings(SettingsType newSettings);
|
||||
Widget getEntryWidget();
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
/**
|
||||
* {@link Component}s are arranged in an "ordered forest" structure (multi-rooted tree with the roots ordered in a sequence).
|
||||
* Each hierarchy level can optionally provide a localized name. Each hierarchy level consists of one or more
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public interface ComponentForest extends ComponentForestEntry {
|
||||
Iterable<ComponentForest> getEntries();
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public interface ComponentForestEntry {
|
||||
/**
|
||||
* @return the name to display to a user for quick navigation to this component
|
||||
*/
|
||||
String getLocalizedShortName();
|
||||
|
||||
/**
|
||||
* A component forest entry may or may not have a {@link Widget} used to render its contents. Typically,
|
||||
* entries with sub-entries don't afford a widget of their own but let the framework choose a container
|
||||
* in which to aggregate their entries' widgets.
|
||||
*/
|
||||
Widget getEntryWidget();
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
public interface ComponentGroup<SettingsType> extends Component<SettingsType> {
|
||||
|
||||
boolean addComponent(Component<?> component);
|
||||
|
||||
boolean removeComponent(Component<?> component);
|
||||
|
||||
Iterable<Component<?>> getComponents();
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
|
||||
interface ComponentResources extends ClientBundle {
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/open.png")
|
||||
ImageResource openIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/close.png")
|
||||
ImageResource closeIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settings.png")
|
||||
ImageResource settingsIcon();
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
* @param <SettingsType>
|
||||
* the type that describes this component's settings (if any). Use {@link Object} in case your components
|
||||
* doesn't support any settings.
|
||||
*/public interface ComponentSettings<SettingsType> {
|
||||
|
||||
/**
|
||||
* @return whether this component has settings that a user may change; if so,
|
||||
*/
|
||||
boolean hasSettings();
|
||||
|
||||
/**
|
||||
* If this component {@link #hasSettings has settings}, this method may return a component for the settings dialog.
|
||||
* It will be used to obtain a widget shown in the settings dialog, a validator for the component-specific settings,
|
||||
* as well as to produce a result from the widget's state when the settings dialog wants to validate or return the
|
||||
* settings.
|
||||
*/
|
||||
SettingsDialogComponent<SettingsType> getSettingsDialogComponent();
|
||||
|
||||
/**
|
||||
* Updates the settings of this component. Expected to be called when a settings dialog using this component's
|
||||
* {@link #getSettingsDialogComponent()} has been confirmed.
|
||||
*/
|
||||
void updateSettings(SettingsType newSettings);
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
|
||||
public class ComponentTitleBar extends HorizontalPanel {
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.user.client.ui.AbstractImagePrototype;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class ComponentToolbar<SettingsType> extends HorizontalPanel {
|
||||
|
||||
private static ComponentResources resources = GWT.create(ComponentResources.class);
|
||||
|
||||
private final Component<SettingsType> component;
|
||||
final StringMessages stringMessages;
|
||||
|
||||
public ComponentToolbar(final Component<SettingsType> component, final StringMessages stringMessages) {
|
||||
super();
|
||||
|
||||
this.setSpacing(10);
|
||||
this.component = component;
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
public void addSettingsButton() {
|
||||
if(component.hasSettings()) {
|
||||
ImageResource settingsImage = resources.settingsIcon();
|
||||
Anchor showConfigAnchor = new Anchor(AbstractImagePrototype.create(settingsImage).getSafeHtml());
|
||||
showConfigAnchor.setTitle(stringMessages.configuration());
|
||||
showConfigAnchor.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
});
|
||||
|
||||
this.add(showConfigAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.shared.components;
|
||||
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
|
||||
/**
|
||||
* A GWT component that visualizes a {@link ComponentForest} including menus to scroll quickly to the embedded view
|
||||
* of the respective component, collapse/expand buttons for the views embedded and homogeneous settings buttons for
|
||||
* those components that have settings.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompositePanel extends VerticalPanel {
|
||||
|
||||
public CompositePanel(ComponentForest components) {
|
||||
super();
|
||||
for (ComponentForestEntry entry : components.getEntries()) {
|
||||
entry.toString(); // TODO continue here...
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -46,6 +46,7 @@
|
||||
<!-- Specify the paths for translatable code -->
|
||||
<extend-property name="locale" values="de"/>
|
||||
<source path='client'/>
|
||||
<source path='components'/>
|
||||
<source path='adminconsole'/>
|
||||
<source path='leaderboard'/>
|
||||
<source path='shared'/>
|
||||
|
||||
+1
@@ -34,6 +34,7 @@
|
||||
<extend-property name="locale" values="de"/>
|
||||
<source path='client'/>
|
||||
<source path='raceboard'/>
|
||||
<source path='leaderboard'/>
|
||||
<source path='adminconsole'/>
|
||||
<source path='shared'/>
|
||||
</module>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Reference in new issue
Block a user