Bug 4104: Highlight most current tag when timer changes. Also removed direct write-access to list of tags at TagListProvider.

This commit is contained in:
Henri Kohlberg committed 2018-09-19 17:18:32 +02:00
1 parent f2b1fafc2c
commit 18b9bdd86d
2 files changed
+130 -32

No files matched your search

@@ -1,22 +1,26 @@
package com.sap.sailing.gwt.ui.raceboard.tagging;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import com.google.gwt.view.client.ListDataProvider;
import com.sap.sailing.domain.common.dto.TagDTO;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.filter.Filter;
import com.sap.sse.common.filter.FilterSet;
/**
* Provides list of {@link TagDTO tags} and is able to filter theses {@link TagDTO tags} with the current selected
* {@link FilterSet}.
* Provides list of {@link TagDTO tags} sorted by race timepoint and is able to filter theses {@link TagDTO tags} with
* the current selected {@link FilterSet}.
*/
public class TagListProvider extends ListDataProvider<TagDTO> {
private FilterSet<TagDTO, Filter<TagDTO>> currentFilterSet;
/**
* Stores {@link TagDTO tags} sorted by their {@link TagDTO#getRaceTimepoint() race timepoint}.
*/
private final List<TagDTO> allTags;
private final List<TagFilterLabel> observingLabels;
@@ -28,6 +32,69 @@ public class TagListProvider extends ListDataProvider<TagDTO> {
observingLabels = new ArrayList<TagFilterLabel>();
}
/**
* Adds {@link TagDTO tag} to {@link #getAllTags() list of all tags}.
*
* @param tag
* tag to be added
*/
protected void add(TagDTO tag) {
// tags are sorted by race timepoint
for (int i = 0; i < allTags.size(); i++) {
if (allTags.get(i).getRaceTimepoint().after(tag.getRaceTimepoint())) {
allTags.add(i, tag);
return;
}
}
// add tag to end in case there is no newer tag
allTags.add(tag);
}
/**
* Adds list of {@link TagDTO tags} to {@link #getAllTags() list of all tags}.
*
* @param tags
* tags to be added
*/
protected void addAll(List<TagDTO> tags) {
for (TagDTO tag : tags) {
add(tag);
}
}
/**
* Removes {@link TagDTO tag} from {@link #getAllTags() list of all tags}.
*
* @param tag
* tag to be removed
*/
protected void remove(TagDTO tag) {
allTags.remove(tag);
}
/**
* Removes all private {@link TagDTO tags} from {@link #getAllTags() list of all tags}.
*/
protected void removePrivateTags() {
allTags.removeIf(tag -> !tag.isVisibleForPublic());
}
/**
* Clears {@link #getAllTags() list of all tags}.
*/
protected void clear() {
allTags.clear();
}
/**
* Returns unmodifiable list of all {@link TagDTO tags} ignoring the {@link #currentFilterSet current filter set}.
*
* @return list of all {@link TagDTO tags}
*/
protected List<TagDTO> getAllTags() {
return Collections.unmodifiableList(allTags);
}
/**
* Used by {@link TagFilterLabel} to inform {@link TagFilterLabel} about changes of the {@link #currentFilterSet
* current filter set}.
@@ -48,15 +115,6 @@ public class TagListProvider extends ListDataProvider<TagDTO> {
}
}
/**
* Returns list of all {@link TagDTO tags} ignoring the {@link #currentFilterSet current filter set}.
*
* @return list of all {@link TagDTO tags}
*/
protected List<TagDTO> getAllTags() {
return allTags;
}
/**
* Returns list of all {@link TagDTO tags} which are filtered by {@link #currentFilterSet current filter set}.
*
@@ -82,12 +140,15 @@ public class TagListProvider extends ListDataProvider<TagDTO> {
}
}
currentFilteredList.sort(new Comparator<TagDTO>() {
@Override
public int compare(TagDTO tag1, TagDTO tag2) {
long time1 = tag1.getRaceTimepoint().asMillis();
long time2 = tag2.getRaceTimepoint().asMillis();
return time1 < time2 ? -1 : time1 == time2 ? 0 : 1;
currentFilteredList.sort((tag1, tag2) -> {
TimePoint tag1Time = tag1.getRaceTimepoint();
TimePoint tag2Time = tag2.getRaceTimepoint();
if (tag1Time.before(tag2Time)) {
return -1;
} else if (tag1Time.after(tag2Time)) {
return 1;
} else {
return 0;
}
});
setList(currentFilteredList);
@@ -34,6 +34,7 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.player.TimeListener;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.ComponentWithoutSettings;
@@ -57,7 +58,7 @@ import com.sap.sse.security.ui.shared.UserDTO;
* TaggingPanel itself.
*/
public class TaggingPanel extends ComponentWithoutSettings
implements RaceTimesInfoProviderListener, UserStatusEventHandler {
implements RaceTimesInfoProviderListener, UserStatusEventHandler, TimeListener {
/**
* Describes the {@link TaggingPanel#currentState current state} of the {@link TaggingPanel}.
@@ -159,7 +160,15 @@ public class TaggingPanel extends ComponentWithoutSettings
tagCellList.setSelectionModel(tagSelectionModel);
tagSelectionModel.addSelectionChangeHandler(event -> {
// set time slider to corresponding position
timer.setTime(tagSelectionModel.getSelectedObject().getRaceTimepoint().asMillis());
TagDTO selectedTag = tagSelectionModel.getSelectedObject();
if (selectedTag != null) {
// remove time change listener when manual selecting tag cells as this could end in an infinite loop of
// timer change -> automatic selection change -> timer change -> ...
timer.removeTimeListener(this);
timer.setTime(selectedTag.getRaceTimepoint().asMillis());
// adding time change listener again
timer.addTimeListener(this);
}
});
createTagsButton.setTitle(stringMessages.tagAddTags());
@@ -307,7 +316,7 @@ public class TaggingPanel extends ComponentWithoutSettings
@Override
public void onSuccess(SuccessInfo result) {
if (result.isSuccessful()) {
tagListProvider.getAllTags().remove(tag);
tagListProvider.remove(tag);
updateContent();
if (!silent) {
Notification.notify(stringMessages.tagRemovedSuccessfully(), NotificationType.SUCCESS);
@@ -340,7 +349,7 @@ public class TaggingPanel extends ComponentWithoutSettings
@Override
public void onSuccess(SuccessInfo result) {
if (result.isSuccessful()) {
tagListProvider.getAllTags().remove(tagToUpdate);
tagListProvider.remove(tagToUpdate);
// If old tag was or new tag is private, reload all private tags. Otherwise just refresh UI.
if (!tagToUpdate.isVisibleForPublic() || !visibleForPublic) {
reloadPrivateTags();
@@ -370,9 +379,9 @@ public class TaggingPanel extends ComponentWithoutSettings
@Override
public void onSuccess(List<TagDTO> result) {
tagListProvider.getAllTags().removeIf(tag -> !tag.isVisibleForPublic());
tagListProvider.removePrivateTags();
if (result != null && !result.isEmpty()) {
tagListProvider.getAllTags().addAll(result);
tagListProvider.addAll(result);
}
updateContent();
}
@@ -492,7 +501,8 @@ public class TaggingPanel extends ComponentWithoutSettings
// Setting footerPanel.setVisible(false) is not sufficient as panel would still be
// rendered as 20px high white space instead of being hidden.
// Fix: remove panel completely from footer.
if (!currentState.equals(State.VIEW) || (currentState.equals(State.VIEW) && !getTagButtons().isEmpty())) {
if (currentState != null && (!currentState.equals(State.VIEW)
|| (currentState.equals(State.VIEW) && !getTagButtons().isEmpty()))) {
taggingPanel.setFooterWidget(footerPanel);
footerPanel.setCurrentState(currentState);
} else {
@@ -524,8 +534,6 @@ public class TaggingPanel extends ComponentWithoutSettings
boolean modifiedTags = false;
// Will be true if latestReceivedTagTime needs to be updated in raceTimesInfoprovider, otherwise false.
boolean updatedLatestTag = false;
// local list of already received tags
List<TagDTO> currentTags = tagListProvider.getAllTags();
// createdAt or revokedAt timepoint of latest received tag
TimePoint latestReceivedTagTime = raceTimesInfoProvider.getLatestReceivedTagTime(raceIdentifier);
// get difference in tags since latestReceivedTagTime
@@ -534,17 +542,17 @@ public class TaggingPanel extends ComponentWithoutSettings
if (tag.getRevokedAt() != null) {
// received tag is revoked => latestReceivedTagTime will be revokedAt if revoke event
// occured before latestReceivedTagTime
currentTags.remove(tag);
tagListProvider.remove(tag);
modifiedTags = true;
if (latestReceivedTagTime == null || (latestReceivedTagTime != null
&& latestReceivedTagTime.before(tag.getRevokedAt()))) {
latestReceivedTagTime = tag.getRevokedAt();
updatedLatestTag = true;
}
} else if (!currentTags.contains(tag)) {
} else if (!tagListProvider.getAllTags().contains(tag)) {
// received tag is NOT revoked => latestReceivedTagTime will be createdAt if tag event
// occured before latestReceivedTagTime
currentTags.add(tag);
tagListProvider.add(tag);
modifiedTags = true;
if (latestReceivedTagTime == null || (latestReceivedTagTime != null
&& latestReceivedTagTime.before(tag.getCreatedAt()))) {
@@ -586,7 +594,7 @@ public class TaggingPanel extends ComponentWithoutSettings
@Override
public void onUserStatusChange(UserDTO user, boolean preAuthenticated) {
// clear list of local tags to hide private tags of previous user and reset cache
tagListProvider.getAllTags().clear();
tagListProvider.clear();
raceTimesInfoProvider.getRaceIdentifiers().forEach((raceIdentifier) -> {
raceTimesInfoProvider.setLatestReceivedTagTime(raceIdentifier, null);
});
@@ -598,7 +606,33 @@ public class TaggingPanel extends ComponentWithoutSettings
// update UI
setCurrentState(State.VIEW);
updateContent();
}
/**
* Highlights most current tag when timer changes.
*/
@Override
public void timeChanged(Date newTime, Date oldTime) {
// When reopening Tagging-Panel after it was opened and closed by the user, the TouchSplitLayoutPanel will
// set the timer to the current time and not the race time, oldTime will be null in this case. This would cause
// a jump in time as TaggingPanel selects most current tag when time changes. When time continues while timer is
// in "play"-mode, oldValue won't be null. This can be used as a workaround to discover this "false" time
// change.
// => workaround: Check if oldValue is not null to avoid jumps in time
if (oldTime != null) {
TagDTO toHighlight = null;
for (TagDTO tag : tagListProvider.getAllTags()) {
if (tag.getRaceTimepoint().asDate().getTime() <= newTime.getTime()) {
toHighlight = tag;
} else if (tag.getRaceTimepoint().asDate().getTime() > newTime.getTime()) {
break;
}
}
tagSelectionModel.clear();
if (toHighlight != null) {
tagSelectionModel.setSelected(toHighlight, true);
}
}
}
@Override
@@ -629,8 +663,10 @@ public class TaggingPanel extends ComponentWithoutSettings
if (raceTimesInfoProvider != null) {
if (visible) {
raceTimesInfoProvider.enableTagRequests();
timer.addTimeListener(this);
} else {
raceTimesInfoProvider.disableTagRequests();
timer.removeTimeListener(this);
}
}
taggingPanel.setVisible(visible);
@@ -640,4 +676,5 @@ public class TaggingPanel extends ComponentWithoutSettings
public String getDependentCssClassName() {
return "tags";
}
}