diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index 036b6dccb4c..5b8d87bba19 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.List; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.EventDTO; @@ -10,9 +11,9 @@ import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; public class EventCreateDialog extends EventDialog { - public EventCreateDialog(Collection existingEvents, StringMessages stringConstants, DialogCallback callback) { + public EventCreateDialog(Collection existingEvents, List availableLeaderboardGroups, StringMessages stringConstants, DialogCallback callback) { super(new EventParameterValidator(stringConstants, existingEvents), stringConstants, - /* leaderboardGroups */ Collections.emptyList(), callback); + availableLeaderboardGroups, /* leaderboardGroups */ Collections.emptyList(), callback); nameEntryField = createTextBox(null); nameEntryField.setVisibleLength(50); descriptionEntryField = createTextArea(null); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java new file mode 100644 index 00000000000..f4c9f0b8cd2 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java @@ -0,0 +1,190 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HasVerticalAlignment; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; +import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sse.common.Util; +import com.sap.sse.gwt.client.ErrorReporter; + +public class EventDetailsComposite extends Composite { + private EventDTO event; + private final StringMessages stringMessages; + private final Label eventId; + private final Label eventName; + private final Label venueName; + private final Label description; + private final Label startDate; + private final Label endDate; + private final Label isPublic; + private final Anchor officialWebsiteURL; + private final Anchor logoImageURL; + private final SimpleStringListComposite courseAreaNamesList; + private final SimpleStringListComposite imageURLList; + private final SimpleStringListComposite videoURLList; + private final SimpleStringListComposite sponsorImageURLList; + private final SimpleStringListComposite leaderboardGroupList; + + private final CaptionPanel mainPanel; + + public EventDetailsComposite(final SailingServiceAsync sailingService, final ErrorReporter errorReporter, final StringMessages stringMessages) { + super(); + this.stringMessages = stringMessages; + + event = null; + mainPanel = new CaptionPanel(stringMessages.regatta()); + VerticalPanel vPanel = new VerticalPanel(); + mainPanel.add(vPanel); + + int rows = 14; + Grid grid = new Grid(rows, 2); + vPanel.add(grid); + + int currentRow = 0; + eventId = createLabelAndValueWidget(grid, currentRow++, stringMessages.id(), "IdLabel"); + eventName = createLabelAndValueWidget(grid, currentRow++, stringMessages.eventName(), "NameLabel"); + description = createLabelAndValueWidget(grid, currentRow++, stringMessages.description(), "DescriptionLabel"); + venueName = createLabelAndValueWidget(grid, currentRow++, stringMessages.venue(), "VenueLabel"); + startDate = createLabelAndValueWidget(grid, currentRow++, stringMessages.startDate(), "StartDateLabel"); + endDate = createLabelAndValueWidget(grid, currentRow++, stringMessages.endDate(), "EndDateLabel"); + isPublic = createLabelAndValueWidget(grid, currentRow++, stringMessages.isPublic(), "IsPublicLabel"); + officialWebsiteURL = createAnchorAndValueWidget(grid, currentRow++, stringMessages.eventOfficialWebsiteURL(), "OfficialWebsiteURLLabel"); + logoImageURL = createAnchorAndValueWidget(grid, currentRow++, stringMessages.eventLogoImageURL(), "LogoImageURLLabel"); + courseAreaNamesList = createLableAndValueListWidget(grid, currentRow++, stringMessages.courseAreas(), "CourseAreaValueList"); + imageURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.imageURLs(), "ImageURLValueList"); + videoURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.videoURLs(), "VideoURLValueList"); + sponsorImageURLList = createLableAndValueListWidget(grid, currentRow++, stringMessages.sponsorImageURLs(), "SponsorImageURLValueList"); + leaderboardGroupList = createLableAndValueListWidget(grid, currentRow++, stringMessages.leaderboardGroups(), "LeaderboardGroupValueList"); + + for(int i=0; i < rows; i++) { + grid.getCellFormatter().setVerticalAlignment(i, 0, HasVerticalAlignment.ALIGN_TOP); + grid.getCellFormatter().setVerticalAlignment(i, 1, HasVerticalAlignment.ALIGN_TOP); + } + + initWidget(mainPanel); + } + + private Label createLabelAndValueWidget(Grid grid, int row, String label, String debugId) { + Label valueLabel = new Label(); + valueLabel.ensureDebugId(debugId); + grid.setWidget(row , 0, new Label(label + ":")); + grid.setWidget(row , 1, valueLabel); + return valueLabel; + } + + private Anchor createAnchorAndValueWidget(Grid grid, int row, String label, String debugId) { + Anchor valueAnchor = new Anchor(); + valueAnchor.setTarget("_blank"); + valueAnchor.ensureDebugId(debugId); + grid.setWidget(row , 0, new Label(label + ":")); + grid.setWidget(row , 1, valueAnchor); + return valueAnchor; + } + + private SimpleStringListComposite createLableAndValueListWidget(Grid grid, int row, String label, String debugId) { + SimpleStringListComposite valueList = new SimpleStringListComposite(); + valueList.ensureDebugId(debugId); + grid.setWidget(row , 0, new Label(label + ":")); + grid.setWidget(row , 1, valueList); + return valueList; + } + + public EventDTO getEvent() { + return event; + } + + public void setEvent(EventDTO event) { + this.event = event; + updateEventDetails(); + } + + private void updateEventDetails() { + if (event != null) { + mainPanel.setCaptionText(stringMessages.event() + " " + event.getName()); + eventName.setText(event.getName()); + eventId.setText(event.id.toString()); + venueName.setText(event.venue.getName()); + description.setText(event.getDescription()); + startDate.setText(event.startDate != null ? event.startDate.toString() : ""); + endDate.setText(event.endDate != null ? event.endDate.toString() : ""); + isPublic.setText(String.valueOf(event.isPublic)); + officialWebsiteURL.setText(event.getOfficialWebsiteURL()); + officialWebsiteURL.setHref(event.getOfficialWebsiteURL()); + logoImageURL.setText(event.getLogoImageURL()); + logoImageURL.setHref(event.getLogoImageURL()); + + List courseAreaNames = new ArrayList<>(); + if (event.venue.getCourseAreas() != null && event.venue.getCourseAreas().size() > 0) { + for (CourseAreaDTO courseArea : event.venue.getCourseAreas()) { + courseAreaNames.add(courseArea.getName()); + } + } + courseAreaNamesList.setValues(courseAreaNames); + + List imageURLStringsAsList = new ArrayList<>(); + Util.addAll(event.getImageURLs(), imageURLStringsAsList); + imageURLList.setValues(imageURLStringsAsList); + List videoURLStringsAsList = new ArrayList<>(); + Util.addAll(event.getVideoURLs(), videoURLStringsAsList); + videoURLList.setValues(videoURLStringsAsList); + List sponsorImageURLStringsAsList = new ArrayList<>(); + Util.addAll(event.getSponsorImageURLs(), sponsorImageURLStringsAsList); + sponsorImageURLList.setValues(sponsorImageURLStringsAsList); + List leaderboardGroupNamesAsList = new ArrayList<>(); + for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { + leaderboardGroupNamesAsList.add(leaderboardGroupDTO.getName()); + } + leaderboardGroupList.setValues(leaderboardGroupNamesAsList); + } + } + + private class SimpleStringListComposite extends Composite { + private final FlowPanel panel; + + public SimpleStringListComposite() { + super(); + panel = new FlowPanel(); + this.initWidget(panel); + } + + public void setValues(List values) { + panel.clear(); + for(String value: values) { + panel.add(new ListItemWidget(value)); + } + } + } + + public class ListItemWidget extends SimplePanel { + public ListItemWidget() { + super((Element) Document.get().createLIElement().cast()); + getElement().getStyle().setProperty("listStylePosition", "inside"); + } + + public ListItemWidget(String s) { + this(); + getElement().setInnerText(s); + } + + public ListItemWidget(Widget w) { + this(); + this.add(w); + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 8e1bb131edc..9a3caf331a2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -9,11 +9,14 @@ import java.util.List; import java.util.UUID; import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ScrollPanel; +import com.google.gwt.user.client.ui.TabLayoutPanel; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; @@ -25,6 +28,7 @@ import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO; +import com.sap.sse.gwt.client.controls.listedit.StringConstantsListEditorComposite; import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite; public abstract class EventDialog extends DataEntryDialogWithBootstrap { @@ -43,13 +47,9 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected StringListInlineEditorComposite imageURLList; protected StringListInlineEditorComposite videoURLList; protected StringListInlineEditorComposite sponsorImageURLList; + protected StringConstantsListEditorComposite leaderboardGroupList; + protected List availableLeaderboardGroups; - /** - * Allows subclasses to "park" a set of associated leaderboard groups for re-attachment to the new {@link EventDTO} produced - * by {@link #getResult()}. - */ - private final Iterable leaderboardGroups; - protected static class EventParameterValidator implements Validator { private StringMessages stringMessages; @@ -113,21 +113,23 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap } /** - * @param leaderboardGroups even though not editable in this dialog, this parameter gives an editing subclass a chance to "park" the leaderboard group + * @param leaderboardGroupsOfEvent even though not editable in this dialog, this parameter gives an editing subclass a chance to "park" the leaderboard group * assignments for re-association with the new {@link EventDTO} created by the {@link #getResult} method. */ - public EventDialog(EventParameterValidator validator, StringMessages stringMessages, Iterable leaderboardGroups, - DialogCallback callback) { + public EventDialog(EventParameterValidator validator, StringMessages stringMessages, List availableLeaderboardGroups, + Iterable leaderboardGroupsOfEvent, DialogCallback callback) { super(stringMessages.event(), null, stringMessages.ok(), stringMessages.cancel(), validator, callback); - this.leaderboardGroups = leaderboardGroups; this.stringMessages = stringMessages; + this.availableLeaderboardGroups = availableLeaderboardGroups; + getDialogBox().setWidth("750px"); final ValueChangeHandler> valueChangeHandler = new ValueChangeHandler>() { @Override public void onValueChange(ValueChangeEvent> event) { validate(); } }; + courseAreaNameList = new StringListInlineEditorComposite(Collections. emptyList(), new StringListInlineEditorComposite.ExpandedUi(stringMessages, resources.removeIcon(), /* suggestValues */ SuggestedCourseAreaNames.suggestedCourseAreaNames, stringMessages.enterCourseAreaName(), 50)); @@ -147,13 +149,24 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap new StringListInlineEditorComposite.ExpandedUi(stringMessages, resources.removeIcon(), /* suggestValues */ imageSuggestionURLs, stringMessages.enterSponsorImageURL(), 80)); sponsorImageURLList.addValueChangeHandler(valueChangeHandler); + List leaderboardGroupNames = new ArrayList<>(); + for(LeaderboardGroupDTO leaderboardGroupDTO: availableLeaderboardGroups) { + leaderboardGroupNames.add(leaderboardGroupDTO.getName()); + } + leaderboardGroupList = new StringConstantsListEditorComposite(Collections. emptyList(), + new StringConstantsListEditorComposite.ExpandedUi(stringMessages, resources.removeIcon(), + leaderboardGroupNames, "Select a leaderboard group...")); + leaderboardGroupList.addValueChangeHandler(valueChangeHandler); } @Override protected EventDTO getResult() { EventDTO result = new EventDTO(); - for (LeaderboardGroupDTO lg : leaderboardGroups) { - result.addLeaderboardGroup(lg); + List leaderboardGroupNames = leaderboardGroupList.getValue(); + for(LeaderboardGroupDTO lg: availableLeaderboardGroups) { + if(leaderboardGroupNames.contains(lg.getName())) { + result.addLeaderboardGroup(lg); + } } result.setName(nameEntryField.getText()); result.setDescription(descriptionEntryField.getText()); @@ -186,6 +199,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap @Override protected Widget getAdditionalWidget() { final VerticalPanel panel = new VerticalPanel(); + panel.setWidth("100%"); Widget additionalWidget = super.getAdditionalWidget(); if (additionalWidget != null) { panel.add(additionalWidget); @@ -211,14 +225,14 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap formGrid.setWidget(7, 0, new Label(stringMessages.eventLogoImageURL() + ":")); formGrid.setWidget(7, 1, logoImageURLEntryField); - panel.add(createHeadlineLabel(stringMessages.courseAreas())); - panel.add(courseAreaNameList); - panel.add(createHeadlineLabel(stringMessages.imageURLs())); - panel.add(imageURLList); - panel.add(createHeadlineLabel(stringMessages.videoURLs())); - panel.add(videoURLList); - panel.add(createHeadlineLabel(stringMessages.sponsorImageURLs())); - panel.add(sponsorImageURLList); + TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX); + tabPanel.setHeight("250px"); + panel.add(tabPanel); + tabPanel.add(new ScrollPanel(leaderboardGroupList), stringMessages.leaderboardGroups()); + tabPanel.add(new ScrollPanel(courseAreaNameList), stringMessages.courseAreas()); + tabPanel.add(new ScrollPanel(imageURLList), stringMessages.imageURLs()); + tabPanel.add(new ScrollPanel(videoURLList), stringMessages.videoURLs()); + tabPanel.add(new ScrollPanel(sponsorImageURLList), stringMessages.sponsorImageURLs()); return panel; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index e5b5684f3ec..97a25711eab 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -7,11 +7,12 @@ import java.util.List; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sse.common.Util; public class EventEditDialog extends EventDialog { - public EventEditDialog(EventDTO event, Collection otherExistingEvents, StringMessages stringMessages, DialogCallback callback) { - super(new EventParameterValidator(stringMessages, otherExistingEvents), stringMessages, event.getLeaderboardGroups(), callback); + public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, StringMessages stringMessages, DialogCallback callback) { + super(new EventParameterValidator(stringMessages, otherExistingEvents), stringMessages, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); nameEntryField = createTextBox(event.getName()); nameEntryField.setVisibleLength(50); descriptionEntryField = createTextArea(event.getDescription()); @@ -48,5 +49,10 @@ public class EventEditDialog extends EventDialog { List sponsorImageURLStringsAsList = new ArrayList<>(); Util.addAll(event.getSponsorImageURLs(), sponsorImageURLStringsAsList); sponsorImageURLList.setValue(sponsorImageURLStringsAsList); + List leaderboardGroupNames = new ArrayList<>(); + for(LeaderboardGroupDTO leaderboardGroupDTO: event.getLeaderboardGroups()) { + leaderboardGroupNames.add(leaderboardGroupDTO.getName()); + } + leaderboardGroupList.setValue(leaderboardGroupNames); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java new file mode 100644 index 00000000000..9286ed987e3 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -0,0 +1,650 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import com.google.gwt.cell.client.AbstractCell; +import com.google.gwt.cell.client.FieldUpdater; +import com.google.gwt.cell.client.SafeHtmlCell; +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.safehtml.client.SafeHtmlTemplates; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.cellview.client.CellTable; +import com.google.gwt.user.cellview.client.Column; +import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; +import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.view.client.ListDataProvider; +import com.google.gwt.view.client.MultiSelectionModel; +import com.google.gwt.view.client.SelectionChangeEvent; +import com.sap.sailing.domain.common.impl.NaturalComparator; +import com.sap.sailing.gwt.ui.client.EventSelectionProvider; +import com.sap.sailing.gwt.ui.client.EventsRefresher; +import com.sap.sailing.gwt.ui.client.LeaderboardGroupsDisplayer; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn; +import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; +import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; +import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.RegattaDTO; +import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; +import com.sap.sse.gwt.client.ErrorReporter; +import com.sap.sse.gwt.client.URLEncoder; +import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; +import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; + +/** +/** + * A composite showing the list of all sailing events + * @author Frank Mittag (C5163974) + */ +public class EventListComposite extends Composite implements EventsRefresher, LeaderboardGroupsDisplayer { + private final SailingServiceAsync sailingService; + private final EventSelectionProvider eventSelectionProvider; + private final ErrorReporter errorReporter; + private final StringMessages stringMessages; + + private CellTable eventTable; + private MultiSelectionModel eventSelectionModel; + private ListDataProvider eventListDataProvider; + private List allEvents; + private LabeledAbstractFilterablePanel filterTextbox; + private Button removeEventsButton; + private final Label noEventsLabel; + + private final SimplePanel mainPanel; + private final VerticalPanel panel; + + private Iterable availableLeaderboardGroups; + + public static class AnchorCell extends AbstractCell { + @Override + public void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml safeHtml, SafeHtmlBuilder sb) { + sb.append(safeHtml); + } + } + + interface AnchorTemplates extends SafeHtmlTemplates { + @SafeHtmlTemplates.Template("{1}") + SafeHtml cell(String url, String displayName); + } + + private static AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class); + + private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); + + public EventListComposite(final SailingServiceAsync sailingService, final EventSelectionProvider eventSelectionProvider, + final ErrorReporter errorReporter, final StringMessages stringMessages) { + this.sailingService = sailingService; + this.eventSelectionProvider = eventSelectionProvider; + this.stringMessages = stringMessages; + this.errorReporter = errorReporter; + availableLeaderboardGroups = Collections.emptyList(); + allEvents = new ArrayList(); + + mainPanel = new SimplePanel(); + panel = new VerticalPanel(); + mainPanel.setWidget(panel); + + HorizontalPanel eventControlsPanel = new HorizontalPanel(); + eventControlsPanel.setSpacing(5); + panel.add(eventControlsPanel); + + Button refreshButton = new Button(stringMessages.refresh()); + refreshButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + fillEvents(); + } + }); + eventControlsPanel.add(refreshButton); + + Button createEventBtn = new Button(stringMessages.actionAddEvent()); + createEventBtn.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + openCreateEventDialog(); + } + }); + eventControlsPanel.add(createEventBtn); + + removeEventsButton = new Button(stringMessages.remove()); + removeEventsButton.setEnabled(false); + removeEventsButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + if (Window.confirm(stringMessages.doYouReallyWantToRemoveEvents())) { + removeEvents(eventSelectionModel.getSelectedSet()); + } + } + }); + eventControlsPanel.add(removeEventsButton); + + eventListDataProvider = new ListDataProvider(); + eventTable = createEventTable(); + eventTable.ensureDebugId("EventsCellTable"); + eventTable.setVisible(false); + + @SuppressWarnings("unchecked") + MultiSelectionModel multiSelectionModel = (MultiSelectionModel) eventTable.getSelectionModel(); + eventSelectionModel = multiSelectionModel; + + eventSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { + @Override + public void onSelectionChange(SelectionChangeEvent event) { + final boolean somethingSelected = !eventSelectionModel.getSelectedSet().isEmpty(); + removeEventsButton.setEnabled(somethingSelected); + + List selectedEvents = getSelectedEvents(); + List selectedEventUUIDs = new ArrayList(); + for (EventDTO selectedEvent : selectedEvents) { + selectedEventUUIDs.add(selectedEvent.id); + } + EventListComposite.this.eventSelectionProvider.setSelection(selectedEventUUIDs); + } + }); + + panel.add(eventTable); + filterTextbox = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterEventsByName()), allEvents, + eventTable, eventListDataProvider) { + @Override + public Iterable getSearchableStrings(EventDTO t) { + List result = new ArrayList(); + result.add(t.getName()); + result.add(t.venue.getName()); + for (CourseAreaDTO c : t.venue.getCourseAreas()) { + result.add(c.getName()); + } + for (LeaderboardGroupDTO lg : t.getLeaderboardGroups()) { + result.add(lg.getName()); + } + return result; + } + }; + eventControlsPanel.add(filterTextbox); + + noEventsLabel = new Label("No events defined yet."); + noEventsLabel.ensureDebugId("NoRegattasLabel"); + noEventsLabel.setWordWrap(false); + panel.add(noEventsLabel); + + fillEvents(); + + initWidget(mainPanel); + } + + private CellTable createEventTable() { + CellTable table = new CellTable(/* pageSize */10000, tableRes); + eventListDataProvider.addDataDisplay(table); + table.setWidth("100%"); + + SelectionCheckboxColumn eventSelectionCheckboxColumn = new SelectionCheckboxColumn(tableRes.cellTableStyle().cellTableCheckboxSelected(), + tableRes.cellTableStyle().cellTableCheckboxDeselected(), tableRes.cellTableStyle().cellTableCheckboxColumnCell()) { + @Override + protected ListDataProvider getListDataProvider() { + return eventListDataProvider; + } + + @Override + public Boolean getValue(EventDTO row) { + return eventTable.getSelectionModel().isSelected(row); + } + }; + + AnchorCell anchorCell = new AnchorCell(); + Column eventNameColumn = new Column(anchorCell) { + @Override + public SafeHtml getValue(EventDTO event) { + String debugParam = Window.Location.getParameter("gwt.codesvr"); + String link = URLEncoder.encode("/gwt/RegattaOverview.html?event=" + event.id + + (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "")); + return ANCHORTEMPLATE.cell(link, event.getName()); + } + }; + + TextColumn venueNameColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + return event.venue != null ? event.venue.getName() : ""; + } + }; + + TextColumn startEndDateColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + return DateAndTimeFormatterUtil.formatDateRange(event.startDate, event.endDate); + } + }; + + TextColumn isPublicColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + return event.isPublic ? stringMessages.yes() : stringMessages.no(); + } + }; + + SafeHtmlCell courseAreasCell = new SafeHtmlCell(); + Column courseAreasColumn = new Column(courseAreasCell) { + @Override + public SafeHtml getValue(EventDTO event) { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + int courseAreasCount = event.venue.getCourseAreas().size(); + int i = 1; + for (CourseAreaDTO courseArea : event.venue.getCourseAreas()) { + builder.appendEscaped(courseArea.getName()); + if (i < courseAreasCount) { + builder.appendHtmlConstant(", "); + // not more than 4 course areas per line + if(i % 4 == 0) { + builder.appendHtmlConstant("
"); + } + } + i++; + } + return builder.toSafeHtml(); + } + }; + + SafeHtmlCell leaderboardGroupsCell = new SafeHtmlCell(); + Column leaderboardGroupsColumn = new Column(leaderboardGroupsCell) { + @Override + public SafeHtml getValue(EventDTO event) { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + boolean first = true; + for (LeaderboardGroupDTO lg : event.getLeaderboardGroups()) { + if (first) { + first = false; + } else { + builder.appendHtmlConstant("
"); + } + builder.appendEscaped(lg.getName()); + } + return builder.toSafeHtml(); + } + }; + + TextColumn imageURLsColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + String result = ""; + int imageCount = Util.size(event.getImageURLs()); + if(imageCount > 0) { + result = imageCount + " image(s)"; + } + return result; + } + }; + + TextColumn videoURLsColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + String result = ""; + int videoCount = Util.size(event.getVideoURLs()); + if(videoCount > 0) { + result = videoCount + " video(s)"; + } + return result; + } + }; + + TextColumn sponsorImageURLsColumn = new TextColumn() { + @Override + public String getValue(EventDTO event) { + String result = ""; + int sponsorImageCount = Util.size(event.getSponsorImageURLs()); + if(sponsorImageCount > 0) { + result = sponsorImageCount + " sponsor image(s)"; + } + return result; + } + }; + + SafeHtmlCell associatedRegattasCell = new SafeHtmlCell(); + Column associatedRegattasColumn = new Column(associatedRegattasCell) { + @Override + public SafeHtml getValue(EventDTO event) { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + int regattaCount = event.regattas.size(); + int i = 1; + for (RegattaDTO regatta : event.regattas) { + builder.appendEscaped(regatta.getName()); + if (i < regattaCount) { + builder.appendHtmlConstant("
"); + } + i++; + } + return builder.toSafeHtml(); + } + }; + + ImagesBarColumn eventActionColumn = new ImagesBarColumn( + new EventConfigImagesBarCell(stringMessages)); + eventActionColumn.setFieldUpdater(new FieldUpdater() { + @Override + public void update(int index, EventDTO event, String value) { + if (EventConfigImagesBarCell.ACTION_REMOVE.equals(value)) { + if (Window.confirm(stringMessages.doYouReallyWantToRemoveEvent(event.getName()))) { + removeEvent(event); + } + } else if (EventConfigImagesBarCell.ACTION_EDIT.equals(value)) { + openEditEventDialog(event); + } + } + }); + + eventNameColumn.setSortable(true); + venueNameColumn.setSortable(true); + isPublicColumn.setSortable(true); + startEndDateColumn.setSortable(true); + courseAreasColumn.setSortable(true); + imageURLsColumn.setSortable(true); + videoURLsColumn.setSortable(true); + sponsorImageURLsColumn.setSortable(true); + leaderboardGroupsColumn.setSortable(true); + + table.addColumn(eventSelectionCheckboxColumn, eventSelectionCheckboxColumn.getHeader()); + table.addColumn(eventNameColumn, stringMessages.event()); + table.addColumn(venueNameColumn, stringMessages.venue()); + table.addColumn(startEndDateColumn, stringMessages.from() + "/" + stringMessages.to()); + table.addColumn(isPublicColumn, stringMessages.isPublic()); + table.addColumn(courseAreasColumn, stringMessages.courseAreas()); + table.addColumn(leaderboardGroupsColumn, stringMessages.leaderboardGroups()); + table.addColumn(imageURLsColumn, stringMessages.imageURLs()); + table.addColumn(videoURLsColumn, stringMessages.videoURLs()); + table.addColumn(sponsorImageURLsColumn, stringMessages.sponsorImageURLs()); + table.addColumn(associatedRegattasColumn, stringMessages.regattas()); + table.addColumn(eventActionColumn, stringMessages.actions()); + table.setSelectionModel(eventSelectionCheckboxColumn.getSelectionModel(), eventSelectionCheckboxColumn.getSelectionManager()); + + table.addColumnSortHandler(getEventTableColumnSortHandler(eventListDataProvider.getList(), eventNameColumn, + venueNameColumn, startEndDateColumn, isPublicColumn)); + table.getColumnSortList().push(startEndDateColumn); + + return table; + } + + private ListHandler getEventTableColumnSortHandler(List eventRecords, + Column eventNameColumn, TextColumn venueNameColumn, + TextColumn startEndDateColumn, TextColumn isPublicColumn) { + ListHandler result = new ListHandler(eventRecords); + result.setComparator(eventNameColumn, new Comparator() { + @Override + public int compare(EventDTO e1, EventDTO e2) { + return new NaturalComparator().compare(e1.getName(), e2.getName()); + } + }); + result.setComparator(venueNameColumn, new Comparator() { + @Override + public int compare(EventDTO e1, EventDTO e2) { + return new NaturalComparator().compare(e1.venue.getName(), e2.venue.getName()); + } + }); + result.setComparator(startEndDateColumn, new Comparator() { + @Override + public int compare(EventDTO e1, EventDTO e2) { + int result; + if(e1.startDate != null && e2.startDate != null) { + result = e2.startDate.compareTo(e1.startDate); + } else if(e1.startDate == null && e2.startDate != null) { + result = 1; + } else if(e1.startDate != null && e2.startDate == null) { + result = -1; + } else { + result = 0; + } + return result; + } + }); + result.setComparator(isPublicColumn, new Comparator() { + @Override + public int compare(EventDTO e1, EventDTO e2) { + return e1.isPublic == e2.isPublic ? 0 : e1.isPublic ? 1 : -1; + } + }); + return result; + } + + private void removeEvents(Collection events) { + if (!events.isEmpty()) { + Collection eventIds = new HashSet(); + for (EventDTO event : events) { + eventIds.add(event.id); + } + sailingService.removeEvents(eventIds, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Error trying to remove the events:" + caught.getMessage()); + } + @Override + public void onSuccess(Void result) { + fillEvents(); + } + }); + } + } + + private void removeEvent(final EventDTO event) { + sailingService.removeEvent(event.id, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Error trying to remove event " + event.getName() + ": " + caught.getMessage()); + } + + @Override + public void onSuccess(Void result) { + fillEvents(); + } + }); + } + + private void openCreateEventDialog() { + List existingEvents = new ArrayList(eventListDataProvider.getList()); + List existingLeaderboardGroups = new ArrayList(); + Util.addAll(availableLeaderboardGroups, existingLeaderboardGroups); + EventCreateDialog dialog = new EventCreateDialog(Collections.unmodifiableCollection(existingEvents), existingLeaderboardGroups, + stringMessages, new DialogCallback() { + @Override + public void cancel() { + } + + @Override + public void ok(EventDTO newEvent) { + createNewEvent(newEvent); + } + }); + dialog.show(); + } + + private void openEditEventDialog(final EventDTO selectedEvent) { + List existingEvents = new ArrayList(eventListDataProvider.getList()); + existingEvents.remove(selectedEvent); + List existingLeaderboardGroups = new ArrayList(); + Util.addAll(availableLeaderboardGroups, existingLeaderboardGroups); + EventEditDialog dialog = new EventEditDialog(selectedEvent, Collections.unmodifiableCollection(existingEvents), + existingLeaderboardGroups, stringMessages, + new DialogCallback() { + @Override + public void cancel() { + } + + @Override + public void ok(EventDTO updatedEvent) { + updateEvent(selectedEvent, updatedEvent); + } + }); + dialog.show(); + } + + private void updateEvent(final EventDTO oldEvent, final EventDTO updatedEvent) { + Pair, List> courseAreasToAddAndRemove = getCourseAreasToAdd(oldEvent, updatedEvent); + List courseAreasToAdd = courseAreasToAddAndRemove.getA(); + List courseAreasToRemove = courseAreasToAddAndRemove.getB(); + List updatedEventLeaderboardGroupIds = new ArrayList<>(); + for (LeaderboardGroupDTO leaderboardGroup : updatedEvent.getLeaderboardGroups()) { + updatedEventLeaderboardGroupIds.add(leaderboardGroup.getId()); + } + sailingService.updateEvent(oldEvent.id, oldEvent.getName(), updatedEvent.getDescription(), + updatedEvent.startDate, updatedEvent.endDate, updatedEvent.venue, + updatedEvent.isPublic, updatedEventLeaderboardGroupIds, + updatedEvent.getOfficialWebsiteURL(), updatedEvent.getLogoImageURL(), + updatedEvent.getImageURLs(), updatedEvent.getVideoURLs(), updatedEvent.getSponsorImageURLs(), + new AsyncCallback() { + @Override + public void onFailure(Throwable t) { + errorReporter.reportError("Error trying to update sailing event" + oldEvent.getName() + ": " + t.getMessage()); + } + + @Override + public void onSuccess(EventDTO result) { + fillEvents(); + if (!oldEvent.getName().equals(updatedEvent.getName())) { + sailingService.renameEvent(oldEvent.id, updatedEvent.getName(), new AsyncCallback() { + @Override + public void onSuccess(Void result) { + fillEvents(); + } + + @Override + public void onFailure(Throwable t) { + errorReporter.reportError("Error trying to rename sailing event " + oldEvent.getName() + ": " + t.getMessage()); + } + }); + } + } + }); + for (CourseAreaDTO courseArea : courseAreasToAdd) { + sailingService.createCourseArea(oldEvent.id, courseArea.getName(), new AsyncCallback() { + + @Override + public void onFailure(Throwable t) { + errorReporter.reportError("Error trying to add course area to sailing event " + oldEvent.getName() + + ": " + t.getMessage()); + } + + @Override + public void onSuccess(Void result) { + fillEvents(); + } + + }); + } + for (CourseAreaDTO courseArea : courseAreasToRemove) { + sailingService.removeCourseArea(oldEvent.id, courseArea.id, new AsyncCallback() { + @Override + public void onFailure(Throwable t) { + errorReporter.reportError("Error trying to remove course area from sailing event " + oldEvent.getName() + + ": " + t.getMessage()); + } + + @Override + public void onSuccess(Void result) { + fillEvents(); + } + }); + } + } + + private Pair, List> getCourseAreasToAdd(final EventDTO oldEvent, final EventDTO updatedEvent) { + List courseAreasToAdd = new ArrayList(updatedEvent.venue.getCourseAreas()); + courseAreasToAdd.removeAll(oldEvent.venue.getCourseAreas()); + List courseAreasToRemove = new ArrayList(oldEvent.venue.getCourseAreas()); + courseAreasToRemove.removeAll(updatedEvent.venue.getCourseAreas()); + return new Pair, List>(courseAreasToAdd, courseAreasToRemove); + } + + private void createNewEvent(final EventDTO newEvent) { + List courseAreaNames = new ArrayList(); + for (CourseAreaDTO courseAreaDTO : newEvent.venue.getCourseAreas()) { + courseAreaNames.add(courseAreaDTO.getName()); + } + sailingService.createEvent(newEvent.getName(), newEvent.getDescription(), newEvent.startDate, newEvent.endDate, + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getImageURLs(), + newEvent.getVideoURLs(), newEvent.getSponsorImageURLs(), newEvent.getLogoImageURL(), + newEvent.getOfficialWebsiteURL(), new AsyncCallback() { + @Override + public void onFailure(Throwable t) { + errorReporter.reportError("Error trying to create new event " + newEvent.getName() + ": " + t.getMessage()); + } + + @Override + public void onSuccess(EventDTO newEvent) { + fillEvents(); + } + }); + } + + @Override + public void fillLeaderboardGroups(Iterable leaderboardGroups) { + availableLeaderboardGroups = leaderboardGroups; + } + + @Override + public void fillEvents() { + sailingService.getEvents(new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError("Remote Procedure Call getEvents() - Failure: " + caught.getMessage()); + } + + @Override + public void onSuccess(List events) { + if (events.isEmpty()) { + eventTable.setVisible(false); + noEventsLabel.setVisible(true); + } else { + eventTable.setVisible(true); + noEventsLabel.setVisible(false); + } + + Set selectedEventUUIDs = new HashSet<>(); + for (EventDTO selectedEvent : eventSelectionModel.getSelectedSet()) { + selectedEventUUIDs.add(selectedEvent.id); + } + eventSelectionModel.clear(); + allEvents.clear(); + allEvents.addAll(events); + filterTextbox.updateAll(allEvents); + for (EventDTO e : allEvents) { + if (selectedEventUUIDs.contains(e.id)) { + eventSelectionModel.setSelected(e, true); + } + } + } + }); + } + + public List getAllEvents() { + return allEvents; + } + + private List getSelectedEvents() { + List result = new ArrayList(); + if (eventListDataProvider != null) { + for (EventDTO Event : eventListDataProvider.getList()) { + if (eventSelectionModel.isSelected(Event)) { + result.add(Event); + } + } + } + return result; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventManagementPanel.java index 5c64c6e5aa4..fd6c47395b5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventManagementPanel.java @@ -1,878 +1,83 @@ package com.sap.sailing.gwt.ui.adminconsole; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.UUID; -import com.google.gwt.cell.client.AbstractCell; -import com.google.gwt.cell.client.FieldUpdater; -import com.google.gwt.cell.client.SafeHtmlCell; -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.safehtml.client.SafeHtmlTemplates; -import com.google.gwt.safehtml.shared.SafeHtml; -import com.google.gwt.safehtml.shared.SafeHtmlBuilder; -import com.google.gwt.user.cellview.client.CellTable; -import com.google.gwt.user.cellview.client.Column; -import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; -import com.google.gwt.user.cellview.client.TextColumn; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CaptionPanel; -import com.google.gwt.user.client.ui.HorizontalPanel; -import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; -import com.google.gwt.user.client.ui.Widget; -import com.google.gwt.view.client.ListDataProvider; -import com.google.gwt.view.client.MultiSelectionModel; -import com.google.gwt.view.client.SelectionChangeEvent; -import com.sap.sailing.domain.common.impl.NaturalComparator; +import com.sap.sailing.gwt.ui.client.EventSelectionChangeListener; +import com.sap.sailing.gwt.ui.client.EventSelectionModel; +import com.sap.sailing.gwt.ui.client.EventSelectionProvider; import com.sap.sailing.gwt.ui.client.EventsRefresher; import com.sap.sailing.gwt.ui.client.LeaderboardGroupsDisplayer; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; -import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; -import com.sap.sailing.gwt.ui.shared.RegattaDTO; -import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; -import com.sap.sse.common.Util; -import com.sap.sse.common.Util.Pair; import com.sap.sse.gwt.client.ErrorReporter; -import com.sap.sse.gwt.client.URLEncoder; -import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; -import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; /** - * Allows administrators to manage data of a sailing event. This is a temporary panel because the managed event is not - * connected with any regatta and it used only to manage of basic attributes of the an event. + * Allows administrators to manage a sailing event. * * @author Frank Mittag (C5163974) * @author Axel Uhl (d043530) */ -public class EventManagementPanel extends SimplePanel implements EventsRefresher, LeaderboardGroupsDisplayer { - private final SailingServiceAsync sailingService; - private final ErrorReporter errorReporter; - private final StringMessages stringMessages; - - private CellTable eventTable; - private MultiSelectionModel eventSelectionModel; - private ListDataProvider eventProvider; - private List allEvents; - private LabeledAbstractFilterablePanel filterTextbox; - private Button removeEventsButton; - private TextColumn startEndDateColumn; - - private CellTable selectedEventLeaderboardGroupsTable; - private MultiSelectionModel selectedEventLeaderboardGroupsSelectionModel; - private ListDataProvider selectedEventLeaderboardGroupsProvider; +public class EventManagementPanel extends SimplePanel implements EventsRefresher, LeaderboardGroupsDisplayer, EventSelectionChangeListener { + private EventListComposite eventListComposite; + private EventDetailsComposite eventDetailsComposite; + private final CaptionPanel eventsPanel; + private EventSelectionProvider eventSelectionProvider; - private LabeledAbstractFilterablePanel availableLeaderboardGroupsFilterablePanel; - private CellTable availableLeaderboardGroupsTable; - private MultiSelectionModel availableLeaderboardGroupsSelectionModel; - private ListDataProvider availableLeaderboardGroupsProvider; - - public static class AnchorCell extends AbstractCell { - @Override - public void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml safeHtml, SafeHtmlBuilder sb) { - sb.append(safeHtml); - } - } - - interface AnchorTemplates extends SafeHtmlTemplates { - @SafeHtmlTemplates.Template("{1}") - SafeHtml cell(String url, String displayName); - } - - private static AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class); - - private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); - private final HorizontalPanel splitPanel; - private Button addToEventButton; - private Button removeFromEventButton; - private Iterable availableLeaderboardGroups; - public EventManagementPanel(final SailingServiceAsync sailingService, final ErrorReporter errorReporter, final StringMessages stringMessages) { - availableLeaderboardGroups = Collections.emptySet(); - this.sailingService = sailingService; - this.stringMessages = stringMessages; - this.errorReporter = errorReporter; - VerticalPanel mainPanel = new VerticalPanel(); - this.setWidget(mainPanel); + setWidget(mainPanel); mainPanel.setWidth("100%"); - HorizontalPanel eventsPanel = new HorizontalPanel(); - eventsPanel.setSpacing(5); + eventsPanel = new CaptionPanel(stringMessages.events()); mainPanel.add(eventsPanel); + VerticalPanel eventsContentPanel = new VerticalPanel(); + eventsPanel.setContentWidget(eventsContentPanel); - Button refreshButton = new Button(stringMessages.refresh()); - refreshButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - fillEvents(); - } - }); - eventsPanel.add(refreshButton); + eventSelectionProvider = new EventSelectionModel(true); + eventSelectionProvider.addEventSelectionChangeListener(this); - Button createEventBtn = new Button(stringMessages.actionAddEvent()); - createEventBtn.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - openCreateEventDialog(); - } - }); - eventsPanel.add(createEventBtn); - - removeEventsButton = new Button(stringMessages.remove()); - removeEventsButton.setEnabled(false); - removeEventsButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - if (Window.confirm(stringMessages.doYouReallyWantToRemoveEvents())) { - removeEvents(eventSelectionModel.getSelectedSet()); - } - } - }); - eventsPanel.add(removeEventsButton); - - // sailing events table - AnchorCell anchorCell = new AnchorCell(); - final Column eventNameColumn = new Column(anchorCell) { - @Override - public SafeHtml getValue(EventDTO event) { - String debugParam = Window.Location.getParameter("gwt.codesvr"); - String link = URLEncoder.encode("/gwt/RegattaOverview.html?event=" + event.id - + (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "")); - return ANCHORTEMPLATE.cell(link, event.getName()); - } - }; - - TextColumn venueNameColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - return event.venue != null ? event.venue.getName() : ""; - } - }; - - startEndDateColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - return DateAndTimeFormatterUtil.formatDateRange(event.startDate, event.endDate); - } - }; - - final TextColumn isPublicColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - return event.isPublic ? stringMessages.yes() : stringMessages.no(); - } - }; - - final SafeHtmlCell courseAreasCell = new SafeHtmlCell(); - final Column courseAreasColumn = new Column(courseAreasCell) { - @Override - public SafeHtml getValue(EventDTO event) { - SafeHtmlBuilder builder = new SafeHtmlBuilder(); - int courseAreasCount = event.venue.getCourseAreas().size(); - int i = 1; - for (CourseAreaDTO courseArea : event.venue.getCourseAreas()) { - builder.appendEscaped(courseArea.getName()); - if (i < courseAreasCount) { - builder.appendHtmlConstant(", "); - // not more than 4 course areas per line - if(i % 4 == 0) { - builder.appendHtmlConstant("
"); - } - } - i++; - } - return builder.toSafeHtml(); - } - }; + eventListComposite = new EventListComposite(sailingService, eventSelectionProvider, errorReporter, stringMessages); + eventListComposite.ensureDebugId("EventListComposite"); + eventsContentPanel.add(eventListComposite); - final SafeHtmlCell leaderboardGroupsCell = new SafeHtmlCell(); - final Column leaderboardGroupsColumn = new Column(leaderboardGroupsCell) { - @Override - public SafeHtml getValue(EventDTO event) { - SafeHtmlBuilder builder = new SafeHtmlBuilder(); - boolean first = true; - for (LeaderboardGroupDTO lg : event.getLeaderboardGroups()) { - if (first) { - first = false; - } else { - builder.appendHtmlConstant("
"); - } - builder.appendEscaped(lg.getName()); - } - return builder.toSafeHtml(); - } - }; - - final TextColumn imageURLsColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - String result = ""; - int imageCount = Util.size(event.getImageURLs()); - if(imageCount > 0) { - result = imageCount + " image(s)"; - } - return result; - } - }; - - final TextColumn videoURLsColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - String result = ""; - int videoCount = Util.size(event.getVideoURLs()); - if(videoCount > 0) { - result = videoCount + " video(s)"; - } - return result; - } - }; - - final TextColumn sponsorImageURLsColumn = new TextColumn() { - @Override - public String getValue(EventDTO event) { - String result = ""; - int sponsorImageCount = Util.size(event.getSponsorImageURLs()); - if(sponsorImageCount > 0) { - result = sponsorImageCount + " sponsor image(s)"; - } - return result; - } - }; - - final SafeHtmlCell associatedRegattasCell = new SafeHtmlCell(); - final Column associatedRegattasColumn = new Column(associatedRegattasCell) { - @Override - public SafeHtml getValue(EventDTO event) { - SafeHtmlBuilder builder = new SafeHtmlBuilder(); - int regattaCount = event.regattas.size(); - int i = 1; - for (RegattaDTO regatta : event.regattas) { - builder.appendEscaped(regatta.getName()); - if (i < regattaCount) { - builder.appendHtmlConstant("
"); - } - i++; - } - return builder.toSafeHtml(); - } - }; - - final ImagesBarColumn eventActionColumn = new ImagesBarColumn( - new EventConfigImagesBarCell(stringMessages)); - eventActionColumn.setFieldUpdater(new FieldUpdater() { - @Override - public void update(int index, EventDTO event, String value) { - if (EventConfigImagesBarCell.ACTION_REMOVE.equals(value)) { - if (Window.confirm(stringMessages.doYouReallyWantToRemoveEvent(event.getName()))) { - removeEvent(event); - } - } else if (EventConfigImagesBarCell.ACTION_EDIT.equals(value)) { - openEditEventDialog(event); - } - } - }); - - eventNameColumn.setSortable(true); - venueNameColumn.setSortable(true); - isPublicColumn.setSortable(true); - startEndDateColumn.setSortable(true); - courseAreasColumn.setSortable(true); - imageURLsColumn.setSortable(true); - videoURLsColumn.setSortable(true); - sponsorImageURLsColumn.setSortable(true); - leaderboardGroupsColumn.setSortable(true); - - eventTable = new CellTable(10000, tableRes); - eventTable.addColumn(eventNameColumn, stringMessages.event()); - eventTable.addColumn(venueNameColumn, stringMessages.venue()); - eventTable.addColumn(startEndDateColumn, stringMessages.from() + "/" + stringMessages.to()); - eventTable.addColumn(isPublicColumn, stringMessages.isPublic()); - eventTable.addColumn(courseAreasColumn, stringMessages.courseAreas()); - eventTable.addColumn(leaderboardGroupsColumn, stringMessages.leaderboardGroups()); - eventTable.addColumn(imageURLsColumn, stringMessages.imageURLs()); - eventTable.addColumn(videoURLsColumn, stringMessages.videoURLs()); - eventTable.addColumn(sponsorImageURLsColumn, stringMessages.sponsorImageURLs()); - eventTable.addColumn(associatedRegattasColumn, stringMessages.regattas()); - eventTable.addColumn(eventActionColumn, stringMessages.actions()); - - eventSelectionModel = new MultiSelectionModel(); - eventSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { - @Override - public void onSelectionChange(SelectionChangeEvent event) { - final boolean somethingSelected = !eventSelectionModel.getSelectedSet().isEmpty(); - removeEventsButton.setEnabled(somethingSelected); - updateLeaderboardGroupAssignmentPanel(eventSelectionModel.getSelectedSet()); - } - }); - eventTable.setSelectionModel(eventSelectionModel); - - eventProvider = new ListDataProvider(); - eventProvider.addDataDisplay(eventTable); - mainPanel.add(eventTable); - allEvents = new ArrayList(); - eventTable.addColumnSortHandler(getEventTableColumnSortHandler(eventProvider.getList(), eventNameColumn, - venueNameColumn, startEndDateColumn, isPublicColumn)); - eventTable.getColumnSortList().push(startEndDateColumn); - filterTextbox = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterEventsByName()), allEvents, - eventTable, eventProvider) { - @Override - public Iterable getSearchableStrings(EventDTO t) { - List result = new ArrayList(); - result.add(t.getName()); - result.add(t.venue.getName()); - for (CourseAreaDTO c : t.venue.getCourseAreas()) { - result.add(c.getName()); - } - for (LeaderboardGroupDTO lg : t.getLeaderboardGroups()) { - result.add(lg.getName()); - } - return result; - } - }; - eventsPanel.add(filterTextbox); - fillEvents(); - - // prepare the caption panels and buttons for leaderboard group assignment but leave invisible for now - splitPanel = new HorizontalPanel(); - splitPanel.ensureDebugId("EventLeaderboardGroupsAssignmentDetailsPanel"); - splitPanel.setSpacing(5); - splitPanel.setWidth("100%"); - splitPanel.setVisible(false); - mainPanel.add(splitPanel); - - splitPanel.setVerticalAlignment(HorizontalPanel.ALIGN_TOP); - final Widget switchingButtonsPanel = createSwitchLeaderboardGroupsGUI(); // initialize this before the two tables because their event - // handlers require the buttons to be assigned - splitPanel.add(createLeaderboardGroupOfEventsPanel()); - splitPanel.add(switchingButtonsPanel); - splitPanel.add(createAvailableLeaderboardGroupsPanel()); - } - - private Widget createLeaderboardGroupOfEventsPanel() { - selectedEventLeaderboardGroupsTable = new CellTable(10000000, tableRes); - CaptionPanel result = new CaptionPanel(stringMessages.leaderboardGroupsOfSelectedEvent()); - result.add(selectedEventLeaderboardGroupsTable); - selectedEventLeaderboardGroupsSelectionModel = new MultiSelectionModel<>(); - selectedEventLeaderboardGroupsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { - @Override - public void onSelectionChange(SelectionChangeEvent event) { - removeFromEventButton.setEnabled(!selectedEventLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); - } - }); - selectedEventLeaderboardGroupsTable.setSelectionModel(selectedEventLeaderboardGroupsSelectionModel); - selectedEventLeaderboardGroupsProvider = new ListDataProvider<>(); - selectedEventLeaderboardGroupsProvider.addDataDisplay(selectedEventLeaderboardGroupsTable); - - TextColumn leaderboardGroupNameColumn = new TextColumn() { - @Override - public String getValue(LeaderboardGroupDTO event) { - return event.getName(); - } - }; - TextColumn leaderboardGroupDescriptionColumn = new TextColumn() { - @Override - public String getValue(LeaderboardGroupDTO event) { - String result = event.description; - if(event.description != null && event.description.length() > 40) { - result = event.description.substring(0, 40) + "..."; - } - return result; - } - }; - final SafeHtmlCell leaderboardsCell = new SafeHtmlCell(); - Column associatedLeaderboardsColumn = new Column(leaderboardsCell) { - @Override - public SafeHtml getValue(LeaderboardGroupDTO leaderboardGroup) { - SafeHtmlBuilder builder = new SafeHtmlBuilder(); - boolean first = true; - for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) { - if (first) { - first = false; - } else { - builder.appendHtmlConstant("
"); - } - builder.appendEscaped(leaderboard.name); - } - return builder.toSafeHtml(); - } - }; - - leaderboardGroupNameColumn.setSortable(true); - leaderboardGroupDescriptionColumn.setSortable(true); - selectedEventLeaderboardGroupsTable.addColumn(leaderboardGroupNameColumn, stringMessages.name()); - selectedEventLeaderboardGroupsTable.addColumn(leaderboardGroupDescriptionColumn, stringMessages.description()); - selectedEventLeaderboardGroupsTable.addColumn(associatedLeaderboardsColumn, stringMessages.leaderboards()); - ListHandler sortHandler = new ListHandler(selectedEventLeaderboardGroupsProvider.getList()); - sortHandler.setComparator(leaderboardGroupNameColumn, new Comparator() { - @Override - public int compare(LeaderboardGroupDTO e1, LeaderboardGroupDTO e2) { - return new NaturalComparator().compare(e1.getName(), e2.getName()); - } - }); - sortHandler.setComparator(leaderboardGroupDescriptionColumn, new Comparator() { - @Override - public int compare(LeaderboardGroupDTO e1, LeaderboardGroupDTO e2) { - return new NaturalComparator().compare(e1.description, e2.description); - } - }); - selectedEventLeaderboardGroupsTable.addColumnSortHandler(sortHandler); - return result; - } - - private Widget createAvailableLeaderboardGroupsPanel() { - availableLeaderboardGroupsTable = new CellTable(10000000, tableRes); - CaptionPanel result = new CaptionPanel(stringMessages.availableLeaderboardGroups()); - availableLeaderboardGroupsSelectionModel = new MultiSelectionModel<>(); - availableLeaderboardGroupsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { - @Override - public void onSelectionChange(SelectionChangeEvent event) { - addToEventButton.setEnabled(!availableLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); - } - }); - availableLeaderboardGroupsTable.setSelectionModel(availableLeaderboardGroupsSelectionModel); - availableLeaderboardGroupsProvider = new ListDataProvider<>(); - availableLeaderboardGroupsProvider.addDataDisplay(availableLeaderboardGroupsTable); - availableLeaderboardGroupsFilterablePanel = new LabeledAbstractFilterablePanel(new Label( - stringMessages.filterLeaderboardGroupsByName()), Collections. emptyList(), - availableLeaderboardGroupsTable, availableLeaderboardGroupsProvider) { - @Override - public Iterable getSearchableStrings(LeaderboardGroupDTO t) { - List result = new ArrayList<>(); - result.add(t.getName()); - result.add(t.description); - return result; - } - }; - VerticalPanel vp = new VerticalPanel(); - vp.add(availableLeaderboardGroupsFilterablePanel); - vp.add(availableLeaderboardGroupsTable); - result.add(vp); - - TextColumn leaderboardGroupNameColumn = new TextColumn() { - @Override - public String getValue(LeaderboardGroupDTO event) { - return event.getName(); - } - }; - TextColumn leaderboardGroupDescriptionColumn = new TextColumn() { - @Override - public String getValue(LeaderboardGroupDTO event) { - String result = event.description; - if(event.description != null && event.description.length() > 40) { - result = event.description.substring(0, 40) + "..."; - } - return result; - } - }; - final SafeHtmlCell leaderboardsCell = new SafeHtmlCell(); - Column associatedLeaderboardsColumn = new Column(leaderboardsCell) { - @Override - public SafeHtml getValue(LeaderboardGroupDTO leaderboardGroup) { - SafeHtmlBuilder builder = new SafeHtmlBuilder(); - boolean first = true; - for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) { - if (first) { - first = false; - } else { - builder.appendHtmlConstant("
"); - } - builder.appendEscaped(leaderboard.name); - } - return builder.toSafeHtml(); - } - }; - - leaderboardGroupNameColumn.setSortable(true); - leaderboardGroupDescriptionColumn.setSortable(true); - availableLeaderboardGroupsTable.addColumn(leaderboardGroupNameColumn, stringMessages.name()); - availableLeaderboardGroupsTable.addColumn(leaderboardGroupDescriptionColumn, stringMessages.description()); - availableLeaderboardGroupsTable.addColumn(associatedLeaderboardsColumn, stringMessages.leaderboards()); - ListHandler sortHandler = new ListHandler(availableLeaderboardGroupsProvider.getList()); - sortHandler.setComparator(leaderboardGroupNameColumn, new Comparator() { - @Override - public int compare(LeaderboardGroupDTO e1, LeaderboardGroupDTO e2) { - return new NaturalComparator().compare(e1.getName(), e2.getName()); - } - }); - sortHandler.setComparator(leaderboardGroupDescriptionColumn, new Comparator() { - @Override - public int compare(LeaderboardGroupDTO e1, LeaderboardGroupDTO e2) { - return new NaturalComparator().compare(e1.description, e2.description); - } - }); - availableLeaderboardGroupsTable.addColumnSortHandler(sortHandler); - return result; - } - - private void updateLeaderboardGroupAssignmentPanel(Set set) { - if (set.isEmpty() || set.size() > 1) { - splitPanel.setVisible(false); - } else { - splitPanel.setVisible(true); - selectedEventLeaderboardGroupsProvider.getList().clear(); - final Iterable leaderboardGroupsOfSelectedEvent = set.iterator().next().getLeaderboardGroups(); - Util.addAll(leaderboardGroupsOfSelectedEvent, selectedEventLeaderboardGroupsProvider.getList()); - // deselect all items that are no longer in the list; this shall adjust the switch button enablement - for (LeaderboardGroupDTO lg : selectedEventLeaderboardGroupsSelectionModel.getSelectedSet()) { - if (!selectedEventLeaderboardGroupsProvider.getList().contains(lg)) { - selectedEventLeaderboardGroupsSelectionModel.setSelected(lg, false); - } - } - selectedEventLeaderboardGroupsProvider.refresh(); - List allButEventsLeaderboardGroups = new ArrayList<>(); - Util.addAll(availableLeaderboardGroups, allButEventsLeaderboardGroups); - Util.removeAll(leaderboardGroupsOfSelectedEvent, allButEventsLeaderboardGroups); - availableLeaderboardGroupsFilterablePanel.updateAll(allButEventsLeaderboardGroups); - // deselect all items that are no longer in the list; this shall adjust the switch button enablement - for (LeaderboardGroupDTO lg : availableLeaderboardGroupsSelectionModel.getSelectedSet()) { - if (!allButEventsLeaderboardGroups.contains(lg)) { - availableLeaderboardGroupsSelectionModel.setSelected(lg, false); - } - } - addToEventButton.setEnabled(!availableLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); - removeFromEventButton.setEnabled(!selectedEventLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); - } - } - - private Widget createSwitchLeaderboardGroupsGUI() { - VerticalPanel switchLeaderboardGroupsPanel = new VerticalPanel(); - switchLeaderboardGroupsPanel.setSpacing(5); - switchLeaderboardGroupsPanel.setWidth("5%"); - addToEventButton = new Button("<-"); - addToEventButton.ensureDebugId("AddLeaderboardGroupsButton"); - addToEventButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - addSelectedLeaderboardGroupsToEvent(); - } - }); - addToEventButton.setEnabled(false); - switchLeaderboardGroupsPanel.add(addToEventButton); - - removeFromEventButton = new Button("->"); - removeFromEventButton.ensureDebugId("RemoveLeaderboardGroupsButton"); - removeFromEventButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - removeSelectedLeaderboardGroupsFromEvent(); - } - }); - removeFromEventButton.setEnabled(false); - switchLeaderboardGroupsPanel.add(removeFromEventButton); - return switchLeaderboardGroupsPanel; - } - - private void addSelectedLeaderboardGroupsToEvent() { - Set leaderboardGroupsToAdd = availableLeaderboardGroupsSelectionModel.getSelectedSet(); - EventDTO selectedEvent = eventSelectionModel.getSelectedSet().iterator().next(); - List eventLeaderboardGroupUUIDs = new ArrayList<>(); - for (LeaderboardGroupDTO lg : selectedEvent.getLeaderboardGroups()) { - eventLeaderboardGroupUUIDs.add(lg.getId()); - } - for (LeaderboardGroupDTO lg : leaderboardGroupsToAdd) { - eventLeaderboardGroupUUIDs.add(lg.getId()); - } - updateEventLeaderboardGroups(selectedEvent, eventLeaderboardGroupUUIDs); - } - - private void updateEventLeaderboardGroups(final EventDTO event, List eventLeaderboardGroupUUIDs) { - sailingService.updateEvent(event.id, event.getName(), event.getDescription(), event.startDate, event.endDate, event.venue, - event.isPublic, eventLeaderboardGroupUUIDs, event.getOfficialWebsiteURL(), event.getLogoImageURL(), - event.getImageURLs(), event.getVideoURLs(), event.getSponsorImageURLs(), - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to update event's leaderboard list: "+caught.getMessage()); - } - - @Override - public void onSuccess(EventDTO updatedEvent) { - final boolean eventWasSelected = eventSelectionModel.getSelectedSet().contains(event); - if (eventWasSelected) { - eventSelectionModel.setSelected(event, false); - } - // replace event in events table and re-calculate everything else from there - int i=0; - for (EventDTO e : allEvents) { - if (e.id.equals(updatedEvent.id)) { - allEvents.set(i, updatedEvent); - filterTextbox.updateAll(allEvents); - if (eventWasSelected) { - eventSelectionModel.setSelected(updatedEvent, true); - } - updateLeaderboardGroupAssignmentPanel(eventSelectionModel.getSelectedSet()); - break; - } - i++; - } - } - }); - } - - private void removeSelectedLeaderboardGroupsFromEvent() { - Set leaderboardGroupsToRemove = selectedEventLeaderboardGroupsSelectionModel.getSelectedSet(); - EventDTO selectedEvent = eventSelectionModel.getSelectedSet().iterator().next(); - List eventLeaderboardGroupUUIDs = new ArrayList<>(); - for (LeaderboardGroupDTO lg : selectedEvent.getLeaderboardGroups()) { - eventLeaderboardGroupUUIDs.add(lg.getId()); - } - for (LeaderboardGroupDTO lg : leaderboardGroupsToRemove) { - eventLeaderboardGroupUUIDs.remove(lg.getId()); - } - updateEventLeaderboardGroups(selectedEvent, eventLeaderboardGroupUUIDs); - } - - private ListHandler getEventTableColumnSortHandler(List eventRecords, - Column eventNameColumn, TextColumn venueNameColumn, - TextColumn startEndDateColumn, TextColumn isPublicColumn) { - ListHandler result = new ListHandler(eventRecords); - result.setComparator(eventNameColumn, new Comparator() { - @Override - public int compare(EventDTO e1, EventDTO e2) { - return new NaturalComparator().compare(e1.getName(), e2.getName()); - } - }); - result.setComparator(venueNameColumn, new Comparator() { - @Override - public int compare(EventDTO e1, EventDTO e2) { - return new NaturalComparator().compare(e1.venue.getName(), e2.venue.getName()); - } - }); - result.setComparator(startEndDateColumn, new Comparator() { - @Override - public int compare(EventDTO e1, EventDTO e2) { - int result; - if(e1.startDate != null && e2.startDate != null) { - result = e2.startDate.compareTo(e1.startDate); - } else if(e1.startDate == null && e2.startDate != null) { - result = 1; - } else if(e1.startDate != null && e2.startDate == null) { - result = -1; - } else { - result = 0; - } - return result; - } - }); - result.setComparator(isPublicColumn, new Comparator() { - @Override - public int compare(EventDTO e1, EventDTO e2) { - return e1.isPublic == e2.isPublic ? 0 : e1.isPublic ? 1 : -1; - } - }); - return result; - } - - private void removeEvents(Collection events) { - if (!events.isEmpty()) { - Collection eventIds = new HashSet(); - for (EventDTO event : events) { - eventIds.add(event.id); - } - sailingService.removeEvents(eventIds, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to remove the events:" + caught.getMessage()); - } - @Override - public void onSuccess(Void result) { - fillEvents(); - } - }); - } - } - - private void removeEvent(final EventDTO event) { - sailingService.removeEvent(event.id, new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Error trying to remove event " + event.getName() + ": " + caught.getMessage()); - } - - @Override - public void onSuccess(Void result) { - fillEvents(); - } - }); - } - - private void openCreateEventDialog() { - List existingEvents = new ArrayList(eventProvider.getList()); - EventCreateDialog dialog = new EventCreateDialog(Collections.unmodifiableCollection(existingEvents), stringMessages, - new DialogCallback() { - @Override - public void cancel() { - } - - @Override - public void ok(EventDTO newEvent) { - createNewEvent(newEvent); - } - }); - dialog.show(); - } - - private void openEditEventDialog(final EventDTO selectedEvent) { - List existingEvents = new ArrayList(eventProvider.getList()); - existingEvents.remove(selectedEvent); - EventEditDialog dialog = new EventEditDialog(selectedEvent, Collections.unmodifiableCollection(existingEvents), stringMessages, - new DialogCallback() { - @Override - public void cancel() { - } - - @Override - public void ok(EventDTO updatedEvent) { - updateEvent(selectedEvent, updatedEvent); - } - }); - dialog.show(); - } - - private void updateEvent(final EventDTO oldEvent, final EventDTO updatedEvent) { - Pair, List> courseAreasToAddAndRemove = getCourseAreasToAdd(oldEvent, updatedEvent); - List courseAreasToAdd = courseAreasToAddAndRemove.getA(); - List courseAreasToRemove = courseAreasToAddAndRemove.getB(); - List updatedEventLeaderboardGroupIds = new ArrayList<>(); - for (LeaderboardGroupDTO leaderboardGroup : updatedEvent.getLeaderboardGroups()) { - updatedEventLeaderboardGroupIds.add(leaderboardGroup.getId()); - } - sailingService.updateEvent(oldEvent.id, oldEvent.getName(), updatedEvent.getDescription(), - updatedEvent.startDate, updatedEvent.endDate, updatedEvent.venue, - updatedEvent.isPublic, updatedEventLeaderboardGroupIds, - updatedEvent.getOfficialWebsiteURL(), updatedEvent.getLogoImageURL(), - updatedEvent.getImageURLs(), updatedEvent.getVideoURLs(), updatedEvent.getSponsorImageURLs(), - new AsyncCallback() { - @Override - public void onFailure(Throwable t) { - errorReporter.reportError("Error trying to update sailing event" + oldEvent.getName() + ": " + t.getMessage()); - } - - @Override - public void onSuccess(EventDTO result) { - fillEvents(); - if (!oldEvent.getName().equals(updatedEvent.getName())) { - sailingService.renameEvent(oldEvent.id, updatedEvent.getName(), new AsyncCallback() { - @Override - public void onSuccess(Void result) { - fillEvents(); - } - - @Override - public void onFailure(Throwable t) { - errorReporter.reportError("Error trying to rename sailing event " + oldEvent.getName() + ": " + t.getMessage()); - } - }); - } - } - }); - for (CourseAreaDTO courseArea : courseAreasToAdd) { - sailingService.createCourseArea(oldEvent.id, courseArea.getName(), new AsyncCallback() { - - @Override - public void onFailure(Throwable t) { - errorReporter.reportError("Error trying to add course area to sailing event " + oldEvent.getName() - + ": " + t.getMessage()); - } - - @Override - public void onSuccess(Void result) { - fillEvents(); - } - - }); - } - for (CourseAreaDTO courseArea : courseAreasToRemove) { - sailingService.removeCourseArea(oldEvent.id, courseArea.id, new AsyncCallback() { - @Override - public void onFailure(Throwable t) { - errorReporter.reportError("Error trying to remove course area from sailing event " + oldEvent.getName() - + ": " + t.getMessage()); - } - - @Override - public void onSuccess(Void result) { - fillEvents(); - } - }); - } - } - - private Pair, List> getCourseAreasToAdd(final EventDTO oldEvent, final EventDTO updatedEvent) { - List courseAreasToAdd = new ArrayList(updatedEvent.venue.getCourseAreas()); - courseAreasToAdd.removeAll(oldEvent.venue.getCourseAreas()); - List courseAreasToRemove = new ArrayList(oldEvent.venue.getCourseAreas()); - courseAreasToRemove.removeAll(updatedEvent.venue.getCourseAreas()); - return new Pair, List>(courseAreasToAdd, courseAreasToRemove); - } - - private void createNewEvent(final EventDTO newEvent) { - List courseAreaNames = new ArrayList(); - for (CourseAreaDTO courseAreaDTO : newEvent.venue.getCourseAreas()) { - courseAreaNames.add(courseAreaDTO.getName()); - } - sailingService.createEvent(newEvent.getName(), newEvent.getDescription(), newEvent.startDate, newEvent.endDate, - newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getImageURLs(), - newEvent.getVideoURLs(), newEvent.getSponsorImageURLs(), newEvent.getLogoImageURL(), - newEvent.getOfficialWebsiteURL(), new AsyncCallback() { - @Override - public void onFailure(Throwable t) { - errorReporter.reportError("Error trying to create new event " + newEvent.getName() + ": " + t.getMessage()); - } - - @Override - public void onSuccess(EventDTO newEvent) { - fillEvents(); - } - }); + eventDetailsComposite = new EventDetailsComposite(sailingService, errorReporter, stringMessages); + eventDetailsComposite.ensureDebugId("EventDetailsComposite"); + eventDetailsComposite.setVisible(false); + mainPanel.add(eventDetailsComposite); } + @Override public void fillEvents() { - sailingService.getEvents(new AsyncCallback>() { - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Remote Procedure Call getEvents() - Failure: " + caught.getMessage()); - } - - @Override - public void onSuccess(List result) { - Set selectedEventUUIDs = new HashSet<>(); - for (EventDTO selectedEvent : eventSelectionModel.getSelectedSet()) { - selectedEventUUIDs.add(selectedEvent.id); - } - eventSelectionModel.clear(); - allEvents.clear(); - allEvents.addAll(result); - filterTextbox.updateAll(allEvents); - for (EventDTO e : allEvents) { - if (selectedEventUUIDs.contains(e.id)) { - eventSelectionModel.setSelected(e, true); - } - } - updateLeaderboardGroupAssignmentPanel(eventSelectionModel.getSelectedSet()); - } - }); + eventListComposite.fillEvents(); } @Override public void fillLeaderboardGroups(Iterable leaderboardGroups) { - availableLeaderboardGroups = leaderboardGroups; - updateLeaderboardGroupAssignmentPanel(eventSelectionModel.getSelectedSet()); + eventListComposite.fillLeaderboardGroups(leaderboardGroups); + } + + @Override + public void onEventSelectionChange(List selectedEvents) { + final UUID selectedEventUUID; + if (selectedEvents.size() == 1 && eventListComposite.getAllEvents() != null) { + selectedEventUUID = selectedEvents.get(0); + for (EventDTO eventDTO : eventListComposite.getAllEvents()) { + if (eventDTO.id.equals(selectedEventUUID)) { + eventDetailsComposite.setEvent(eventDTO); + eventDetailsComposite.setVisible(true); + break; + } + } + } else { + eventDetailsComposite.setEvent(null); + eventDetailsComposite.setVisible(false); + } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java new file mode 100644 index 00000000000..1c303db0e5a --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupSelectorComposite.java @@ -0,0 +1,289 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import com.google.gwt.cell.client.SafeHtmlCell; +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.event.logical.shared.HasValueChangeHandlers; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.cellview.client.CellTable; +import com.google.gwt.user.cellview.client.Column; +import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; +import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.view.client.ListDataProvider; +import com.google.gwt.view.client.MultiSelectionModel; +import com.google.gwt.view.client.SelectionChangeEvent; +import com.sap.sailing.domain.common.impl.NaturalComparator; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; +import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; +import com.sap.sse.common.Util; +import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; + +public class LeaderboardGroupSelectorComposite extends Composite implements HasValueChangeHandlers> { + private final StringMessages stringMessages; + + private CellTable selectedEventLeaderboardGroupsTable; + private MultiSelectionModel selectedEventLeaderboardGroupsSelectionModel; + private ListDataProvider selectedEventLeaderboardGroupsProvider; + + private LabeledAbstractFilterablePanel availableLeaderboardGroupsFilterablePanel; + private CellTable availableLeaderboardGroupsTable; + private MultiSelectionModel availableLeaderboardGroupsSelectionModel; + private ListDataProvider availableLeaderboardGroupsProvider; + + private List availableLeaderboardGroups; + private List leaderboardGroups; + + private Button addToEventButton; + private Button removeFromEventButton; + private final HorizontalPanel splitPanel; + + private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); + + public LeaderboardGroupSelectorComposite(List leaderboardGroups, List availableLeaderboardGroups, final StringMessages stringMessages) { + super(); + this.leaderboardGroups = leaderboardGroups; + this.availableLeaderboardGroups = availableLeaderboardGroups; + this.stringMessages = stringMessages; + + splitPanel = new HorizontalPanel(); + splitPanel.ensureDebugId("EventLeaderboardGroupsAssignmentDetailsPanel"); + splitPanel.setSpacing(5); + splitPanel.setWidth("100%"); + + splitPanel.setVerticalAlignment(HorizontalPanel.ALIGN_TOP); + + final Widget switchingButtonsPanel = createSwitchLeaderboardGroupsGUI(); + splitPanel.add(createLeaderboardGroupOfEventsPanel()); + splitPanel.add(switchingButtonsPanel); + splitPanel.add(createAvailableLeaderboardGroupsPanel()); + + initWidget(splitPanel); + } + + private Widget createLeaderboardGroupOfEventsPanel() { + selectedEventLeaderboardGroupsTable = new CellTable(10000000, tableRes); + CaptionPanel result = new CaptionPanel(stringMessages.leaderboardGroupsOfSelectedEvent()); + result.add(selectedEventLeaderboardGroupsTable); + selectedEventLeaderboardGroupsSelectionModel = new MultiSelectionModel<>(); + selectedEventLeaderboardGroupsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { + @Override + public void onSelectionChange(SelectionChangeEvent event) { + removeFromEventButton.setEnabled(!selectedEventLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); + } + }); + selectedEventLeaderboardGroupsTable.setSelectionModel(selectedEventLeaderboardGroupsSelectionModel); + selectedEventLeaderboardGroupsProvider = new ListDataProvider<>(); + selectedEventLeaderboardGroupsProvider.addDataDisplay(selectedEventLeaderboardGroupsTable); + + TextColumn leaderboardGroupNameColumn = new TextColumn() { + @Override + public String getValue(LeaderboardGroupDTO event) { + return event.getName(); + } + }; + final SafeHtmlCell leaderboardsCell = new SafeHtmlCell(); + Column associatedLeaderboardsColumn = new Column(leaderboardsCell) { + @Override + public SafeHtml getValue(LeaderboardGroupDTO leaderboardGroup) { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + boolean first = true; + for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) { + if (first) { + first = false; + } else { + builder.appendHtmlConstant("
"); + } + builder.appendEscaped(leaderboard.name); + } + return builder.toSafeHtml(); + } + }; + + leaderboardGroupNameColumn.setSortable(true); + selectedEventLeaderboardGroupsTable.addColumn(leaderboardGroupNameColumn, stringMessages.name()); + selectedEventLeaderboardGroupsTable.addColumn(associatedLeaderboardsColumn, stringMessages.leaderboards()); + ListHandler sortHandler = new ListHandler(selectedEventLeaderboardGroupsProvider.getList()); + sortHandler.setComparator(leaderboardGroupNameColumn, new Comparator() { + @Override + public int compare(LeaderboardGroupDTO e1, LeaderboardGroupDTO e2) { + return new NaturalComparator().compare(e1.getName(), e2.getName()); + } + }); + selectedEventLeaderboardGroupsTable.addColumnSortHandler(sortHandler); + return result; + } + + private Widget createAvailableLeaderboardGroupsPanel() { + availableLeaderboardGroupsTable = new CellTable(10000000, tableRes); + CaptionPanel result = new CaptionPanel(stringMessages.availableLeaderboardGroups()); + availableLeaderboardGroupsSelectionModel = new MultiSelectionModel<>(); + availableLeaderboardGroupsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { + @Override + public void onSelectionChange(SelectionChangeEvent event) { + addToEventButton.setEnabled(!availableLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); + } + }); + availableLeaderboardGroupsTable.setSelectionModel(availableLeaderboardGroupsSelectionModel); + availableLeaderboardGroupsProvider = new ListDataProvider<>(); + availableLeaderboardGroupsProvider.setList(availableLeaderboardGroups); + availableLeaderboardGroupsProvider.addDataDisplay(availableLeaderboardGroupsTable); + availableLeaderboardGroupsFilterablePanel = new LabeledAbstractFilterablePanel(new Label( + stringMessages.filterLeaderboardGroupsByName()), Collections. emptyList(), + availableLeaderboardGroupsTable, availableLeaderboardGroupsProvider) { + @Override + public Iterable getSearchableStrings(LeaderboardGroupDTO t) { + List result = new ArrayList<>(); + result.add(t.getName()); + return result; + } + }; + VerticalPanel vp = new VerticalPanel(); + vp.add(availableLeaderboardGroupsFilterablePanel); + vp.add(availableLeaderboardGroupsTable); + result.add(vp); + + TextColumn leaderboardGroupNameColumn = new TextColumn() { + @Override + public String getValue(LeaderboardGroupDTO event) { + return event.getName(); + } + }; + final SafeHtmlCell leaderboardsCell = new SafeHtmlCell(); + Column associatedLeaderboardsColumn = new Column(leaderboardsCell) { + @Override + public SafeHtml getValue(LeaderboardGroupDTO leaderboardGroup) { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + boolean first = true; + for (StrippedLeaderboardDTO leaderboard : leaderboardGroup.getLeaderboards()) { + if (first) { + first = false; + } else { + builder.appendHtmlConstant("
"); + } + builder.appendEscaped(leaderboard.name); + } + return builder.toSafeHtml(); + } + }; + + leaderboardGroupNameColumn.setSortable(true); + availableLeaderboardGroupsTable.addColumn(leaderboardGroupNameColumn, stringMessages.name()); + availableLeaderboardGroupsTable.addColumn(associatedLeaderboardsColumn, stringMessages.leaderboards()); + ListHandler sortHandler = new ListHandler(availableLeaderboardGroupsProvider.getList()); + sortHandler.setComparator(leaderboardGroupNameColumn, new Comparator() { + @Override + public int compare(LeaderboardGroupDTO e1, LeaderboardGroupDTO e2) { + return new NaturalComparator().compare(e1.getName(), e2.getName()); + } + }); + availableLeaderboardGroupsTable.addColumnSortHandler(sortHandler); + return result; + } + + private void updateLeaderboardGroupAssignmentPanel() { + selectedEventLeaderboardGroupsProvider.getList().clear(); + Util.addAll(leaderboardGroups, selectedEventLeaderboardGroupsProvider.getList()); + // deselect all items that are no longer in the list; this shall adjust the switch button enablement + for (LeaderboardGroupDTO lg : selectedEventLeaderboardGroupsSelectionModel.getSelectedSet()) { + if (!selectedEventLeaderboardGroupsProvider.getList().contains(lg)) { + selectedEventLeaderboardGroupsSelectionModel.setSelected(lg, false); + } + } + selectedEventLeaderboardGroupsProvider.refresh(); + List allButEventsLeaderboardGroups = new ArrayList<>(); + Util.addAll(availableLeaderboardGroups, allButEventsLeaderboardGroups); + Util.removeAll(leaderboardGroups, allButEventsLeaderboardGroups); + availableLeaderboardGroupsFilterablePanel.updateAll(allButEventsLeaderboardGroups); + // deselect all items that are no longer in the list; this shall adjust the switch button enablement + for (LeaderboardGroupDTO lg : availableLeaderboardGroupsSelectionModel.getSelectedSet()) { + if (!allButEventsLeaderboardGroups.contains(lg)) { + availableLeaderboardGroupsSelectionModel.setSelected(lg, false); + } + } + addToEventButton.setEnabled(!availableLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); + removeFromEventButton.setEnabled(!selectedEventLeaderboardGroupsSelectionModel.getSelectedSet().isEmpty()); + } + + private Widget createSwitchLeaderboardGroupsGUI() { + VerticalPanel switchLeaderboardGroupsPanel = new VerticalPanel(); + switchLeaderboardGroupsPanel.setSpacing(5); + switchLeaderboardGroupsPanel.setWidth("5%"); + addToEventButton = new Button("<-"); + addToEventButton.ensureDebugId("AddLeaderboardGroupsButton"); + addToEventButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + addSelectedLeaderboardGroupsToEvent(); + } + }); + addToEventButton.setEnabled(false); + switchLeaderboardGroupsPanel.add(addToEventButton); + + removeFromEventButton = new Button("->"); + removeFromEventButton.ensureDebugId("RemoveLeaderboardGroupsButton"); + removeFromEventButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + removeSelectedLeaderboardGroupsFromEvent(); + } + }); + removeFromEventButton.setEnabled(false); + switchLeaderboardGroupsPanel.add(removeFromEventButton); + return switchLeaderboardGroupsPanel; + } + + private void addSelectedLeaderboardGroupsToEvent() { + Set leaderboardGroupsToAdd = availableLeaderboardGroupsSelectionModel.getSelectedSet(); + List eventLeaderboardGroupUUIDs = new ArrayList<>(); + for (LeaderboardGroupDTO lg : leaderboardGroups) { + eventLeaderboardGroupUUIDs.add(lg.getId()); + } + for (LeaderboardGroupDTO lg : leaderboardGroupsToAdd) { + eventLeaderboardGroupUUIDs.add(lg.getId()); + } + } + + private void removeSelectedLeaderboardGroupsFromEvent() { + Set leaderboardGroupsToRemove = selectedEventLeaderboardGroupsSelectionModel.getSelectedSet(); + List eventLeaderboardGroupUUIDs = new ArrayList<>(); + for (LeaderboardGroupDTO lg : leaderboardGroups) { + eventLeaderboardGroupUUIDs.add(lg.getId()); + } + for (LeaderboardGroupDTO lg : leaderboardGroupsToRemove) { + eventLeaderboardGroupUUIDs.remove(lg.getId()); + } + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler> handler) { + return addHandler(handler, ValueChangeEvent.getType()); + } + + public Set getSelectedLeaderboardGroups() { + return selectedEventLeaderboardGroupsSelectionModel.getSelectedSet(); + } + + public void setLeaderboardGroups(List leaderboardGroups) { + selectedEventLeaderboardGroupsProvider.setList(leaderboardGroups); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java index be096c5b59d..2db5d5829b0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaDetailsComposite.java @@ -46,6 +46,7 @@ public class RegattaDetailsComposite extends Composite { private final StringMessages stringMessages; private final RegattaRefresher regattaRefresher; + private final Label regattaId; private final Label regattaName; private final Label boatClassName; private final Label scoringSystem; @@ -69,38 +70,19 @@ public class RegattaDetailsComposite extends Composite { mainPanel = new CaptionPanel(stringMessages.regatta()); VerticalPanel vPanel = new VerticalPanel(); mainPanel.add(vPanel); - Grid grid = new Grid(6, 2); + + int rows = 7; + Grid grid = new Grid(rows, 2); vPanel.add(grid); - regattaName = new Label(); - regattaName.ensureDebugId("NameLabel"); - grid.setWidget(0 , 0, new Label(stringMessages.regattaName() + ":")); - grid.setWidget(0 , 1, regattaName); - - boatClassName = new Label(); - boatClassName.ensureDebugId("BoatClassLabel"); - grid.setWidget(1 , 0, new Label(stringMessages.boatClass() + ":")); - grid.setWidget(1 , 1, boatClassName); - - defaultCourseArea = new Label(); - defaultCourseArea.ensureDebugId("CourseAreaLabel"); - grid.setWidget(2 , 0, new Label(stringMessages.courseArea() + ":")); - grid.setWidget(2 , 1, defaultCourseArea); - - useStartTimeInference = new Label(); - useStartTimeInference.ensureDebugId("UseStartTimeInferenceLabel"); - grid.setWidget(3 , 0, new Label(stringMessages.useStartTimeInference() + ":")); - grid.setWidget(3 , 1, useStartTimeInference); - - configuration = new Label(); - configuration.ensureDebugId("RacingProcedureLabel"); - grid.setWidget(4, 0, new Label(stringMessages.racingProcedureConfiguration() + ":")); - grid.setWidget(4, 1, configuration); - - scoringSystem = new Label(); - scoringSystem.ensureDebugId("ScoringSystemLabel"); - grid.setWidget(5 , 0, new Label(stringMessages.scoringSystem() + ":")); - grid.setWidget(5 , 1, scoringSystem); + int currentRow = 0; + regattaId = createLabelAndValueWidget(grid, currentRow++, stringMessages.id(), "RegattaIdLabel"); + regattaName = createLabelAndValueWidget(grid, currentRow++, stringMessages.regattaName(), "NameLabel"); + boatClassName = createLabelAndValueWidget(grid, currentRow++, stringMessages.boatClass(), "BoatClassLabel"); + defaultCourseArea = createLabelAndValueWidget(grid, currentRow++, stringMessages.courseArea(), "CourseAreaLabel"); + useStartTimeInference = createLabelAndValueWidget(grid, currentRow++, stringMessages.useStartTimeInference(), "UseStartTimeInferenceLabel"); + configuration = createLabelAndValueWidget(grid, currentRow++, stringMessages.racingProcedureConfiguration(), "RacingProcedureLabel"); + scoringSystem = createLabelAndValueWidget(grid, currentRow++, stringMessages.scoringSystem(), "ScoringSystemLabel"); seriesTable = createRegattaSeriesTable(); seriesTable.ensureDebugId("SeriesCellTable"); @@ -117,6 +99,14 @@ public class RegattaDetailsComposite extends Composite { initWidget(mainPanel); } + private Label createLabelAndValueWidget(Grid grid, int row, String label, String debugId) { + Label valueLabel = new Label(); + valueLabel.ensureDebugId(debugId); + grid.setWidget(row , 0, new Label(label + ":")); + grid.setWidget(row , 1, valueLabel); + return valueLabel; + } + private CellTable createRegattaSeriesTable() { CellTable table = new CellTable(/* pageSize */10000, tableRes); table.setWidth("100%"); @@ -375,6 +365,7 @@ public class RegattaDetailsComposite extends Composite { private void updateRegattaDetails() { if (regatta != null) { mainPanel.setCaptionText(stringMessages.regatta() + " " + regatta.getName()); + regattaId.setText(regatta.getName()); regattaName.setText(regatta.getName()); boatClassName.setText(regatta.boatClass != null ? regatta.boatClass.getName() : ""); defaultCourseArea.setText(regatta.defaultCourseAreaUuid == null ? "" : regatta.defaultCourseAreaName); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java index 6ff0661b40c..2f0108507b8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java @@ -40,6 +40,11 @@ import com.sap.sse.gwt.client.async.MarkedAsyncCallback; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; +/** + * A composite showing the list of all regattas + * @author Frank + * + */ public class RegattaListComposite extends Composite implements RegattasDisplayer { private final MultiSelectionModel regattaSelectionModel; @@ -76,6 +81,8 @@ public class RegattaListComposite extends Composite implements RegattasDisplayer this.regattaRefresher = regattaRefresher; this.errorReporter = errorReporter; this.stringMessages = stringMessages; + allRegattas = new ArrayList(); + mainPanel = new SimplePanel(); panel = new VerticalPanel(); mainPanel.setWidget(panel); @@ -103,7 +110,7 @@ public class RegattaListComposite extends Composite implements RegattasDisplayer return string; } }; - filterablePanelRegattas.getTextBox().ensureDebugId("ReggatasFilterTextBox"); + filterablePanelRegattas.getTextBox().ensureDebugId("RegattasFilterTextBox"); panel.add(filterablePanelRegattas); @SuppressWarnings("unchecked") diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionChangeListener.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionChangeListener.java new file mode 100644 index 00000000000..013b258e080 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionChangeListener.java @@ -0,0 +1,22 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.List; +import java.util.UUID; + + +/** + * Allows UI components to observe a saling event selector, such as a drop-down box showing a list of sailing events + * + * @author Axel Uhl (d043530) + * + */ +public interface EventSelectionChangeListener { + + /** + * The first element is the first one selected + * + * @param selectedEvents a non-null list which is empty if nothing is selected + */ + void onEventSelectionChange(List selectedEvents); + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionModel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionModel.java new file mode 100644 index 00000000000..56a23c7202d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionModel.java @@ -0,0 +1,90 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class EventSelectionModel implements EventSelectionProvider { + private final List selection; + private final List allEvents; + private final Set listeners; + private final boolean hasMultiSelection; + + public EventSelectionModel(boolean hasMultiSelection) { + this.hasMultiSelection = hasMultiSelection; + this.selection = new ArrayList(); + this.allEvents = new ArrayList(); + listeners = new HashSet(); + } + + @Override + public List getSelectedEvents() { + return Collections.unmodifiableList(selection); + } + + @Override + public void addEventSelectionChangeListener(EventSelectionChangeListener listener) { + listeners.add(listener); + } + + @Override + public void removeEventSelectionChangeListener(EventSelectionChangeListener listener) { + listeners.remove(listener); + } + + @Override + public void setSelection(List newSelection, EventSelectionChangeListener... listenersNotToNotify) { + boolean notify = !selection.equals(newSelection); + selection.clear(); + selection.addAll(newSelection); + if (notify) { + notifyListeners(listenersNotToNotify); + } + } + + private void notifyListeners(EventSelectionChangeListener[] listenersNotToNotify) { + List selectedEvents = getSelectedEvents(); + for (EventSelectionChangeListener listener : listeners) { + if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) { + listener.onEventSelectionChange(selectedEvents); + } + } + } + + /** + * Sets the universe of all (sailing) events from which this selection model may select. An equal list will subsequently be + * returned by {@link #getallEvents()}. Events from the {@link #getSelectedEvents() selection} not in + * newEvents are removed from the selection. If this happens, the selection listeners are notified. + */ + @Override + public void setAllEvents(List newEvents, EventSelectionChangeListener... listenersNotToNotify) { + allEvents.clear(); + for (UUID r : newEvents) { + allEvents.add(r); + } + for (Iterator i=selection.iterator(); i.hasNext(); ) { + UUID selectedRegatta = i.next(); + if (!allEvents.contains(selectedRegatta)) { + i.remove(); + } + } + // when setting all events, the actual EventDTOs will usually have changed their identity and maybe also their state; + // so notifying the selection listeners is necessary anyhow + notifyListeners(listenersNotToNotify); + } + + @Override + public List getAllEvents() { + return Collections.unmodifiableList(allEvents); + } + + @Override + public boolean hasMultiSelection() { + return hasMultiSelection; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionProvider.java new file mode 100644 index 00000000000..d4b9e197934 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EventSelectionProvider.java @@ -0,0 +1,26 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.List; +import java.util.UUID; + +public interface EventSelectionProvider { + /** + * @return a non-null list which may be empty + */ + List getSelectedEvents(); + + void addEventSelectionChangeListener(EventSelectionChangeListener listener); + + void removeEventSelectionChangeListener(EventSelectionChangeListener listener); + + void setSelection(List newSelection, EventSelectionChangeListener... listenersNotToNotify); + + boolean hasMultiSelection(); + + /** + * @return a non-null list which may be empty + */ + List getAllEvents(); + + void setAllEvents(List events, EventSelectionChangeListener... listenersNotToNotify); +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/StringConstantsListEditorComposite.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/StringConstantsListEditorComposite.java new file mode 100644 index 00000000000..2f4b1dd7bfe --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/StringConstantsListEditorComposite.java @@ -0,0 +1,165 @@ +package com.sap.sse.gwt.client.controls.listedit; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.resources.client.ImageResource; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sse.common.Util; +import com.sap.sse.gwt.client.StringMessages; + +public class StringConstantsListEditorComposite extends ListEditorComposite { + public StringConstantsListEditorComposite(Iterable initialValues, StringMessages stringMessages, + String popupDialogTitle, ImageResource removeImage, Iterable availableConstantValuesToAdd) { + this(initialValues, stringMessages, popupDialogTitle, removeImage, availableConstantValuesToAdd, /* placeholderTextForAddTextbox */ null); + } + + public StringConstantsListEditorComposite(Iterable initialValues, StringMessages stringMessages, + String popupDialogTitle, ImageResource removeImage, Iterable availableConstantValuesToAdd, String placeholderTextForAddTextbox) { + super(initialValues, new CollapsedUi(stringMessages, popupDialogTitle, + new ExpandedUi(stringMessages, removeImage, availableConstantValuesToAdd, placeholderTextForAddTextbox))); + } + + public StringConstantsListEditorComposite(Iterable initialValues, StringMessages stringMessages, + ImageResource removeImage, Iterable availableConstantValuesToAdd) { + super(initialValues, new ExpandedUi(stringMessages, removeImage, availableConstantValuesToAdd)); + } + + public StringConstantsListEditorComposite(Iterable initialValues, StringMessages stringMessages, + ImageResource removeImage, Iterable availableConstantValuesToAdd, String placeholderTextForAddTextbox) { + super(initialValues, new ExpandedUi(stringMessages, removeImage, availableConstantValuesToAdd, placeholderTextForAddTextbox)); + } + + public StringConstantsListEditorComposite(Iterable initialValues, ListEditorUiStrategy activeUi) { + super(initialValues, activeUi); + } + + public static class CollapsedUi extends CollapsedListEditorUi { + + public CollapsedUi(StringMessages stringMessages, String dialogTitle, ExpandedListEditorUi expandedUi) { + super(stringMessages, dialogTitle, expandedUi); + } + + @Override + protected String getCollapsedValueText(List value) { + StringBuilder valuesText = new StringBuilder(); + for (int i = 0; i < value.size(); i++) { + if (i > 0) { + valuesText.append(','); + } + valuesText.append(value.get(i)); + } + String condensedValue = valuesText.toString(); + return condensedValue; + } + + @Override + protected ListEditorComposite createExpandedUi(Iterable initialValues, ExpandedListEditorUi ui) { + return new StringConstantsListEditorComposite(initialValues, ui); + } + } + + public static class ExpandedUi extends ExpandedListEditorUi { + + protected final String placeholderTextForAddListbox; + protected final List availableConstantValuesToAdd; + private ListBox selectionBox; + + public ExpandedUi(StringMessages stringMessages, ImageResource removeImage, Iterable availableConstantValuesToAdd) { + this(stringMessages, removeImage, availableConstantValuesToAdd, /* placeholderTextForAddTextbox */ null); + } + + public ExpandedUi(StringMessages stringMessages, ImageResource removeImage, Iterable constantValuesToAdd, String placeholderTextForAddListbox) { + super(stringMessages, removeImage, /*canRemoveItems*/true); + this.availableConstantValuesToAdd = new ArrayList(); + Util.addAll(constantValuesToAdd, availableConstantValuesToAdd); + Collections.sort(availableConstantValuesToAdd); + + this.placeholderTextForAddListbox = placeholderTextForAddListbox; + this.selectionBox = null; + } + + @Override + public void setContext(final ListEditorComposite context) { + super.setContext(context); + context.addValueChangeHandler(new ValueChangeHandler>() { + @Override + public void onValueChange(ValueChangeEvent> event) { + if(selectionBox != null) { + // add a removed value item back to the list of available items + List diffList = new ArrayList<>(); + Util.addAll(availableConstantValuesToAdd, diffList); + diffList.removeAll(context.getValue()); + Collections.sort(diffList); + updateSelectionListBox(selectionBox, diffList); + } + } + }); + } + + private void updateSelectionListBox(ListBox listBox, Iterable values) { + listBox.clear(); + if(placeholderTextForAddListbox != null) { + listBox.addItem(placeholderTextForAddListbox); + } else { + listBox.addItem("Please select"); + } + for (String value : values) { + listBox.addItem(value); + } + } + + protected ListBox createListBox() { + ListBox result = new ListBox(false); + updateSelectionListBox(result, availableConstantValuesToAdd); + return result; + } + + @Override + protected Widget createAddWidget() { + selectionBox = createListBox(); + selectionBox.ensureDebugId("SelectionListBox"); + final Button addButton = new Button(getStringMessages().add()); + addButton.ensureDebugId("AddButton"); + addButton.setEnabled(false); + addButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + int selIndex = selectionBox.getSelectedIndex(); + String seletedItemText = selectionBox.getItemText(selIndex); + addValue(seletedItemText); + selectionBox.setSelectedIndex(0); + addButton.setEnabled(false); + } + }); + + selectionBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + int selIndex = selectionBox.getSelectedIndex(); + addButton.setEnabled(selIndex > 0); + } + }); + HorizontalPanel panel = new HorizontalPanel(); + panel.add(selectionBox); + panel.add(addButton); + return panel; + } + + @Override + protected Widget createValueWidget(int rowIndex, String newValue) { + return new Label(newValue); + } + } +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/dialog/DataEntryDialog.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/dialog/DataEntryDialog.java index 62ad29afe6b..da3ef0ad045 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/dialog/DataEntryDialog.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/dialog/DataEntryDialog.java @@ -473,6 +473,10 @@ public abstract class DataEntryDialog { dateEntryDialog.center(); } + protected DialogBox getDialogBox() { + return dateEntryDialog; + } + public void ensureDebugId(String debugId) { dateEntryDialog.ensureDebugId(debugId); }