Skip to content

Commit

Permalink
New timeline sync editor
Browse files Browse the repository at this point in the history
  • Loading branch information
xpdota committed Dec 17, 2023
1 parent df137e0 commit 59a238b
Show file tree
Hide file tree
Showing 11 changed files with 521 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package gg.xp.xivsupport.timelines;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import gg.xp.reevent.events.Event;
import gg.xp.xivsupport.timelines.cbevents.CbEventFmt;
import gg.xp.xivsupport.timelines.cbevents.CbEventType;
import gg.xp.xivsupport.timelines.intl.LanguageReplacements;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CustomEventSyncController implements EventSyncController {

private final Class<? extends Event> eventClass;
private Map<String, List<String>> conditions;
@JsonIgnore
private EventSyncController wrapped;
@JsonIgnore
private final CbEventType eventType;

@JsonCreator
public CustomEventSyncController(@JsonProperty("type") CbEventType eventType, @JsonProperty("conditions") Map<String, List<String>> conditions) {
this.eventType = eventType;
this.eventClass = eventType.eventType();
this.conditions = new HashMap<>(conditions);
recalc();
}

public static CustomEventSyncController from(EventSyncController other) {
return new CustomEventSyncController(other.getType(), other.getRawConditions());
}

private void recalc() {
wrapped = CbEventFmt.parse(eventType, conditions);
}

public void setConditions(Map<String, List<String>> conditions) {
this.conditions = TimelineUtils.cloneConditions(conditions);
recalc();
}

@Override
public boolean shouldSync(Event event) {
return wrapped.shouldSync(event);
}

@Override
public Class<? extends Event> eventType() {
return eventClass;
}

@Override
public EventSyncController translateWith(LanguageReplacements replacements) {
// No translation for custom entries
return this;
}

@Override
public String toTextFormat() {
return wrapped.toTextFormat();
}

@Override
public CbEventType getType() {
return eventType;
}

@Override
public Map<String, List<String>> getRawConditions() {
return TimelineUtils.cloneConditions(conditions);
}

@Override
public String toString() {
// TODO: there should be something to differentiate this from a builtin
return wrapped.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class CustomTimelineEntry implements CustomTimelineItem, Serializable {
public double time;
public @Nullable String name;
public @Nullable Pattern sync;
public @Nullable CustomEventSyncController esc;
public @Nullable Double duration;
public @Nullable Double windowStart;
public @Nullable Double windowEnd;
Expand All @@ -52,6 +53,7 @@ public CustomTimelineEntry(
double time,
@Nullable String name,
@Nullable Pattern sync,
@Nullable CustomEventSyncController esc,
@Nullable Double duration,
@NotNull TimelineWindow timelineWindow,
@Nullable Double jump,
Expand All @@ -68,6 +70,7 @@ public CustomTimelineEntry(
this.time = time;
this.name = name;
this.sync = sync;
this.esc = esc;
this.callout = callout;
this.calloutPreTime = calloutPreTime;
this.duration = duration;
Expand All @@ -86,6 +89,7 @@ public CustomTimelineEntry(
@JsonProperty("time") double time,
@JsonProperty("name") @Nullable String name,
@JsonProperty("sync") @Nullable String sync,
@JsonProperty("esc") @Nullable CustomEventSyncController esc,
@JsonProperty("duration") @Nullable Double duration,
@JsonProperty("timelineWindow") @NotNull TimelineWindow timelineWindow,
@JsonProperty("jump") @Nullable Double jump,
Expand All @@ -96,7 +100,7 @@ public CustomTimelineEntry(
@JsonProperty(value = "disabled", defaultValue = "false") boolean disabled,
@JsonProperty(value = "callout", defaultValue = "false") boolean callout,
@JsonProperty(value = "calloutPreTime", defaultValue = "0") double calloutPreTime,
@JsonProperty(value = "jobs") @Nullable CombatJobSelection jobs
@JsonProperty("jobs") @Nullable CombatJobSelection jobs
) {
// TODO: this wouldn't be a bad place to do the JAR url correction. Perhaps not the cleanest way,
// but it works.
Expand All @@ -115,6 +119,7 @@ public CustomTimelineEntry(
this.replaces = replaces;
this.enabled = !disabled;
this.enabledJobs = jobs == null ? CombatJobSelection.all() : jobs;
this.esc = esc;
}

@Override
Expand Down Expand Up @@ -196,9 +201,9 @@ public int hashCode() {
}

@Override
@JsonProperty("esc")
public @Nullable EventSyncController eventSyncController() {
// TODO
return null;
return esc;
}

@Override
Expand All @@ -207,6 +212,7 @@ public String toString() {
"time=" + time +
", name='" + name + '\'' +
", sync=" + sync +
", esc=" + esc +
", duration=" + duration +
", windowStart=" + windowStart +
", windowEnd=" + windowEnd +
Expand Down Expand Up @@ -249,10 +255,12 @@ public static CustomTimelineEntry overrideFor(TimelineEntry other) {
if (other.isLabel()) {
throw new IllegalArgumentException("Cannot override a label with a real entry");
}
EventSyncController otherEsc = other.eventSyncController();
CustomTimelineEntry newCte = new CustomTimelineEntry(
other.time(),
other.name(),
other.sync(),
otherEsc == null ? null : CustomEventSyncController.from(otherEsc),
other.duration(),
other.timelineWindow(),
other.jump(),
Expand All @@ -269,10 +277,12 @@ public static CustomTimelineEntry overrideFor(TimelineEntry other) {
}

public static CustomTimelineEntry cloneFor(TimelineEntry other) {
EventSyncController otherEsc = other.eventSyncController();
CustomTimelineEntry newCte = new CustomTimelineEntry(
other.time(),
other.name() + " copy",
other.sync(),
otherEsc == null ? null : CustomEventSyncController.from(otherEsc),
other.duration(),
other.timelineWindow(),
other.jump(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
package gg.xp.xivsupport.timelines;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import gg.xp.reevent.events.Event;
import gg.xp.xivsupport.timelines.cbevents.CbEventType;
import gg.xp.xivsupport.timelines.intl.LanguageReplacements;

import java.util.List;
import java.util.Map;

public interface EventSyncController {
boolean shouldSync(Event event);

Class<? extends Event> eventType();

default boolean isEditable() {
return false;
};

EventSyncController translateWith(LanguageReplacements replacements);

String toTextFormat();

@JsonProperty("type")
CbEventType getType();

@JsonProperty("conditions")
Map<String, List<String>> getRawConditions();
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,14 @@ public String toTextFormat() {
public String toString() {
return type.displayName() + CbEventFmt.flattenListMap(original);
}

@Override
public CbEventType getType() {
return type;
}

@Override
public Map<String, List<String>> getRawConditions() {
return TimelineUtils.cloneConditions(original);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package gg.xp.xivsupport.timelines;

import gg.xp.xivsupport.gui.lists.FriendlyNameListCellRenderer;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.ListDataListener;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class NullableEnumComboBox<X extends Enum<X>> extends JComboBox<X> {

private @Nullable X selectedItem;

public NullableEnumComboBox(Class<X> enumCls, String nullLabel, Consumer<@Nullable X> consumer, @Nullable X initialValue) {
X[] constants = enumCls.getEnumConstants();
List<X> list = new ArrayList<>(Arrays.asList(constants));
list.add(0, null);
selectedItem = initialValue;
ComboBoxModel<X> model = new ComboBoxModel<>() {

@Override
public int getSize() {
return list.size();
}

@Override
public X getElementAt(int index) {
return list.get(index);
}

@Override
public void addListDataListener(ListDataListener l) {

}

@Override
public void removeListDataListener(ListDataListener l) {

}

@Override
public void setSelectedItem(Object anItem) {
selectedItem = (X) anItem;
consumer.accept((X) anItem);
}

@Override
public Object getSelectedItem() {
return selectedItem;
}
};
setModel(model);
setRenderer(new FriendlyNameListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value == null) {
return super.getListCellRendererComponent(list, nullLabel, index, isSelected, cellHasFocus);
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
});

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,12 @@ private static String propStubForZoneId(long zoneId) {
private final Map<Long, TimelineCustomizations> customizations = new ConcurrentHashMap<>();

public TimelineCustomizations getCustomSettings(long zoneId) {
return customizations.computeIfAbsent(zoneId, (k) -> pers.get(propStubForZoneId(k), TimelineCustomizations.class, new TimelineCustomizations()));
try {
return customizations.computeIfAbsent(zoneId, (k) -> pers.get(propStubForZoneId(k), TimelineCustomizations.class, new TimelineCustomizations()));
}
catch (Throwable t) {
throw new RuntimeException("Error loading timeline customizations for zone " + zoneId, t);
}
}

public void commitCustomSettings(long zoneId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package gg.xp.xivsupport.timelines;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public final class TimelineUtils {

private TimelineUtils() {
}

public static Map<String, List<String>> cloneConditions(Map<String, List<String>> in) {
return in.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
e -> new ArrayList<>(e.getValue())
));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,8 @@ public List<CbfMap<? super X>> getFieldMappings() {
return Collections.unmodifiableList(fieldMap);
}
}

public List<CbfMap<?>> getFieldMappings() {
return (List<CbfMap<?>>) this.data.getFieldMappings();
}
}
Loading

0 comments on commit 59a238b

Please sign in to comment.