diff --git a/reevent/src/main/java/gg/xp/reevent/events/Event.java b/reevent/src/main/java/gg/xp/reevent/events/Event.java index d9f7d48ea82b..e23eebe9025a 100644 --- a/reevent/src/main/java/gg/xp/reevent/events/Event.java +++ b/reevent/src/main/java/gg/xp/reevent/events/Event.java @@ -33,6 +33,7 @@ default boolean delayedEnqueueAtFront() { return false; } + @Deprecated // Use Groovy methods instead default Map dumpFields() { return Utils.dumpAllFields(this); } diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/GuiMain.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/GuiMain.java index 0101848d01d7..69750c078520 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/GuiMain.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/GuiMain.java @@ -49,6 +49,7 @@ import gg.xp.xivsupport.gui.tables.filters.SystemLogLoggerNameFilter; import gg.xp.xivsupport.gui.tables.filters.SystemLogTextFilter; import gg.xp.xivsupport.gui.tables.filters.SystemLogThreadFilter; +import gg.xp.xivsupport.gui.tables.groovy.GroovyColumns; import gg.xp.xivsupport.gui.tables.renderers.ActionAndStatusRenderer; import gg.xp.xivsupport.gui.tables.renderers.NameJobRenderer; import gg.xp.xivsupport.gui.tabs.AdvancedTab; @@ -80,6 +81,7 @@ import gg.xp.xivsupport.speech.TtsRequest; import gg.xp.xivsupport.sys.Threading; import gg.xp.xivsupport.sys.XivMain; +import groovy.lang.PropertyValue; import org.apache.commons.io.IOUtils; import org.intellij.lang.annotations.Language; import org.jetbrains.annotations.NotNull; @@ -728,20 +730,9 @@ private void getAndAddTabs() { private JPanel getCombatantsPanel() { // Main table XivState state = container.getComponent(XivStateImpl.class); - TableWithFilterAndDetails> table = TableWithFilterAndDetails.builder("Combatants", + TableWithFilterAndDetails table = TableWithFilterAndDetails.builder("Combatants", () -> state.getCombatantsListCopy().stream().sorted(Comparator.comparing(XivEntity::getId)).collect(Collectors.toList()), - combatant -> { - if (combatant == null) { - return Collections.emptyList(); - } - else { - return Utils.dumpAllFields(combatant) - .entrySet() - .stream() - .filter(e -> !"serialVersionUID".equals(e.getKey().getName())) - .collect(Collectors.toList()); - } - }) + GroovyColumns::getValues) .addMainColumn(StandardColumns.entityIdColumn) .addMainColumn(StandardColumns.nameJobColumn) .addMainColumn(columns.statusEffectsColumn()) @@ -750,13 +741,8 @@ private JPanel getCombatantsPanel() { .addMainColumn(columns.hpColumnWithUnresolved()) .addMainColumn(StandardColumns.mpColumn) .addMainColumn(StandardColumns.posColumn) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .setSelectionEquivalence((a, b) -> a.getId() == b.getId()) - .setDetailsSelectionEquivalence((a, b) -> a.getKey().equals(b.getKey())) .addFilter(EventEntityFilter::selfFilter) .addFilter(NonCombatEntityFilter::new) .withRightClickRepo(rightClicks) @@ -773,19 +759,8 @@ private JPanel getCombatantsPanel() { private JPanel getStatusEffectsPanel() { // Main table StatusEffectRepository repo = container.getComponent(StatusEffectRepository.class); - TableWithFilterAndDetails> table = TableWithFilterAndDetails.builder("Status Effects", repo::getBuffs, - combatant -> { - if (combatant == null) { - return Collections.emptyList(); - } - else { - return Utils.dumpAllFields(combatant) - .entrySet() - .stream() - .filter(e -> !"serialVersionUID".equals(e.getKey().getName())) - .collect(Collectors.toList()); - } - }) + TableWithFilterAndDetails table = TableWithFilterAndDetails.builder("Status Effects", repo::getBuffs, + GroovyColumns::getValues) .addMainColumn(new CustomColumn<>("Source", BuffApplied::getSource, c -> c.setCellRenderer(new NameJobRenderer()))) .addMainColumn(new CustomColumn<>("Target", BuffApplied::getTarget, c -> c.setCellRenderer(new NameJobRenderer()))) .addMainColumn(new CustomColumn<>("Buff/Ability", BuffApplied::getBuff, c -> c.setCellRenderer(new ActionAndStatusRenderer()))) @@ -799,11 +774,7 @@ private JPanel getStatusEffectsPanel() { c.setMinWidth(100); c.setMaxWidth(100); })) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .setSelectionEquivalence(Object::equals) .addFilter(EventEntityFilter::buffSourceFilter) .addFilter(EventEntityFilter::buffTargetFilter) @@ -827,26 +798,11 @@ private JPanel getActLogPanel() { // The second way was to stream and filter the raw event storage, but that is inefficient because it scales // very poorly and causes higher CPU usage. // The third, not-hacky way is to just have RawEventStorage track events of a particular type for us - TableWithFilterAndDetails> table = TableWithFilterAndDetails.builder("ACT Log", + TableWithFilterAndDetails table = TableWithFilterAndDetails.builder("ACT Log", () -> rawStorage.getEventsOfType(ACTLogLineEvent.class), - currentEvent -> { - if (currentEvent == null) { - return Collections.emptyList(); - } - else { - return currentEvent.dumpFields() - .entrySet() - .stream() - .filter(e -> !"serialVersionUID".equals(e.getKey().getName())) - .collect(Collectors.toList()); - } - }) + GroovyColumns::getValues) .addMainColumn(new CustomColumn<>("Line", ACTLogLineEvent::getLogLine)) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .withRightClickRepo(rightClicks) .addFilter(ActLineFilter::new) .addWidget(replayNextPseudoFilter(ACTLogLineEvent.class)) @@ -867,17 +823,9 @@ private JPanel getSystemLogPanel() { return panel; } else { - TableWithFilterAndDetails> table = TableWithFilterAndDetails.builder("System Log", + TableWithFilterAndDetails table = TableWithFilterAndDetails.builder("System Log", instance::getEvents, - e -> { - if (e == null) { - return Collections.emptyList(); - } - return Stream.concat( - Utils.dumpAllFields(e).entrySet().stream(), - Utils.dumpAllFields(e.getEvent()).entrySet().stream() - ).collect(Collectors.toList()); - }) + GroovyColumns::getValues) .addMainColumn(new CustomColumn<>("Time", e -> Instant.ofEpochMilli(e.getEvent().getTimeStamp()) .atZone(ZoneId.systemDefault()) @@ -925,11 +873,7 @@ else if (value == Level.WARN) { col.setPreferredWidth(900); })) .withRightClickRepo(rightClicks) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .addFilter(LogLevelVisualFilter::new) .addFilter(SystemLogThreadFilter::new) .addFilter(SystemLogLoggerNameFilter::new) @@ -957,20 +901,9 @@ private String formatLocalTime(@NotNull Instant t) { private JPanel getPullsTab() { PullTracker pulls = state.get(PullTracker.class); - TableWithFilterAndDetails> table = TableWithFilterAndDetails.builder("Pulls", + TableWithFilterAndDetails table = TableWithFilterAndDetails.builder("Pulls", pulls::getPulls, - currentPull -> { - if (currentPull == null) { - return Collections.emptyList(); - } - else { - return Utils.dumpAllFields(currentPull) - .entrySet() - .stream() - .filter(e -> !"serialVersionUID".equals(e.getKey().getName())) - .collect(Collectors.toList()); - } - }) + GroovyColumns::getValues) .addMainColumn(new CustomColumn<>("Number", Pull::getPullNum, col -> { col.setMinWidth(50); col.setMaxWidth(50); @@ -1008,11 +941,7 @@ private JPanel getPullsTab() { }, col -> { col.setPreferredWidth(200); })) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .withRightClickRepo(rightClicks.withMore(CustomRightClickOption.forRow("Filter Events Tab to This", Pull.class, pull -> { PullNumberFilter pnf = container.getComponent(PullNumberFilter.class); pnf.setPullNumberExternally(pull.getPullNum()); diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/GroovyPanel.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/GroovyPanel.java index 18335cf112df..ad5219472066 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/GroovyPanel.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/GroovyPanel.java @@ -7,6 +7,7 @@ import gg.xp.xivsupport.gui.components.ReadOnlyText; import gg.xp.xivsupport.gui.tables.CustomColumn; import gg.xp.xivsupport.gui.tables.CustomTableModel; +import gg.xp.xivsupport.gui.tables.groovy.GroovyColumns; import gg.xp.xivsupport.gui.tabs.GroovyTab; import gg.xp.xivsupport.gui.util.EasyAction; import gg.xp.xivsupport.persistence.gui.BoundCheckbox; @@ -314,7 +315,7 @@ private JTextArea errorDisplayComponent(String text) { private JTable simpleListDisplay(Collection values) { return CustomTableModel.builder(() -> new ArrayList<>(values)) - .addColumn(new CustomColumn<>("Value", GroovyPanel::singleValueConversion)) + .addColumn(new CustomColumn<>("Value", GroovyColumns::singleValueConversion)) .build() .makeTable(); } @@ -323,37 +324,19 @@ private JTable customTableListDisplay(DisplayControl dc, Collection values) { return dc.getListDisplay().makeTable(sbx, values); } - private JTable simpleMapDisplay(Map map) { - return CustomTableModel.builder(() -> new ArrayList<>(map.entrySet())) - .addColumn(new CustomColumn<>("Key", e -> singleValueConversion(e.getKey()))) - .addColumn(new CustomColumn<>("Value", e -> singleValueConversion(e.getValue()))) + private JTable simplePropsDisplay(Object object) { + return CustomTableModel.builder(() -> GroovyColumns.getValues(object)) + .apply(GroovyColumns::addColumns) .build() .makeTable(); } - // TODO: move this - @SuppressWarnings("MalformedFormatString") - public static String singleValueConversion(Object obj) { - if (obj == null) { - return "(null)"; - } - if (obj instanceof Byte || obj instanceof Integer || obj instanceof Long || obj instanceof Short) { - return String.format("%d (0x%x)", obj, obj); - } - // TODO: arrays -// if (obj instanceof Array arr) { -// arr.getClass().arrayType() -// } - if (obj.getClass().isArray()) { - int length = Array.getLength(obj); - List converted = new ArrayList<>(); - for (int i = 0; i < length; i++) { - converted.add(Array.get(obj, i)); - } - return converted.stream().map(GroovyPanel::singleValueConversion).collect(Collectors.joining(", ", "[", "]")); - } - return obj.toString(); - + private JTable simpleMapDisplay(Map map) { + return CustomTableModel.builder(() -> new ArrayList<>(map.entrySet())) + .addColumn(new CustomColumn<>("Key", e -> GroovyColumns.singleValueConversion(e.getKey()))) + .addColumn(new CustomColumn<>("Value", e -> GroovyColumns.singleValueConversion(e.getValue()))) + .build() + .makeTable(); } private void submit() { @@ -457,19 +440,7 @@ private Component listDisplay(GroovyScriptResult result, Collection coll) { } private void setResultDisplay(@Nullable Object obj, Component display) { - Map props; - if (obj == null) { - props = Collections.emptyMap(); - } - else { - try { - props = DefaultGroovyMethods.getProperties(obj); - } - catch (Throwable t) { - props = Collections.emptyMap(); - } - } - JTable md = simpleMapDisplay(props); + JTable md = simplePropsDisplay(obj); SwingUtilities.invokeLater(() -> { resultPropertiesScroll.setViewportView(md); resultScroll.setViewportView(display); diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/ListTableDisplay.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/ListTableDisplay.java index 3a4dc833c2e9..5035f9ecf6ec 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/ListTableDisplay.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/groovy/ListTableDisplay.java @@ -2,6 +2,7 @@ import gg.xp.xivsupport.gui.tables.CustomColumn; import gg.xp.xivsupport.gui.tables.CustomTableModel; +import gg.xp.xivsupport.gui.tables.groovy.GroovyColumns; import org.codehaus.groovy.runtime.DefaultGroovyMethods; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox; import org.jetbrains.annotations.Nullable; @@ -18,7 +19,6 @@ import java.util.Map; import java.util.function.Function; -import static gg.xp.xivsupport.gui.groovy.GroovyPanel.singleValueConversion; public class ListTableDisplay { private final List cols; @@ -123,7 +123,7 @@ private Object convertValue(@Nullable TableColumn colDef, @Nullable Obj .filter(td -> td.applicableTo(value)) .findFirst() .map(td -> td.func().apply(value)) - .orElseGet(() -> singleValueConversion(value)); + .orElseGet(() -> GroovyColumns.singleValueConversion(value)); } public static ListTableDisplay autoPropTable() { diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/map/MapTab.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/map/MapTab.java index 8faa3aee96a0..8f4ae95cbc6f 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/map/MapTab.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/map/MapTab.java @@ -14,8 +14,10 @@ import gg.xp.xivsupport.gui.tables.filters.EventEntityFilter; import gg.xp.xivsupport.gui.tables.filters.GroovyFilter; import gg.xp.xivsupport.gui.tables.filters.NonCombatEntityFilter; +import gg.xp.xivsupport.gui.tables.groovy.GroovyColumns; import gg.xp.xivsupport.models.XivCombatant; import gg.xp.xivsupport.models.XivEntity; +import groovy.lang.PropertyValue; import javax.swing.*; import java.awt.*; @@ -30,7 +32,7 @@ @ScanMe public class MapTab extends JPanel { - private final TableWithFilterAndDetails> table; + private final TableWithFilterAndDetails table; private final RefreshLoop mapRefresh; private final MapPanel mapPanel; private final MapDataController mapDataController; @@ -54,18 +56,7 @@ public MapTab(GroovyManager mgr, MapDataController mdc, MapConfig config, MapDis table = TableWithFilterAndDetails.builder("Combatants", () -> mdc.getCombatants().stream().sorted(Comparator.comparing(XivEntity::getId)).collect(Collectors.toList()), - combatant -> { - if (combatant == null) { - return Collections.emptyList(); - } - else { - return Utils.dumpAllFields(combatant) - .entrySet() - .stream() - .filter(e -> !"serialVersionUID".equals(e.getKey().getName())) - .collect(Collectors.toList()); - } - }) + GroovyColumns::getValues) .addMainColumn(StandardColumns.entityIdColumn) .addMainColumn(StandardColumns.nameJobColumn) .addMainColumn(StandardColumns.sortedStatusEffectsColumn(mdc::buffsOnCombatant)) @@ -75,13 +66,8 @@ public MapTab(GroovyManager mgr, MapDataController mdc, MapConfig config, MapDis .addMainColumn(StandardColumns.hpColumnWithUnresolved(mdc::unresolvedDamage)) // .addMainColumn(StandardColumns.mpColumn) // .addMainColumn(StandardColumns.posColumn) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .setSelectionEquivalence((a, b) -> a.getId() == b.getId()) - .setDetailsSelectionEquivalence((a, b) -> a.getKey().equals(b.getKey())) .addFilter(EventEntityFilter::selfFilter) .addFilter(NonCombatEntityFilter::new) .addFilter(GroovyFilter.forClass(XivCombatant.class, mgr, "it")) diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/CustomTableModel.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/CustomTableModel.java index 2455cabf71ea..8be5ac9b4abe 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/CustomTableModel.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/CustomTableModel.java @@ -19,6 +19,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -41,6 +43,15 @@ public CustomTableModelBuilder addColumn(CustomColumn colDef) { return this; } + public CustomTableModelBuilder apply(Consumer> func) { + func.accept(this); + return this; + } + + public CustomTableModelBuilder transform(Function, CustomTableModelBuilder> func) { + return func.apply(this); + } + public CustomTableModel build() { return new CustomTableModel(dataGetter, columns, selectionEquivalence); } diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/TableWithFilterAndDetails.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/TableWithFilterAndDetails.java index 419288ebbe1c..ea9ed58b0249 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/TableWithFilterAndDetails.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/TableWithFilterAndDetails.java @@ -22,6 +22,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiPredicate; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -182,7 +183,7 @@ public void setBounds(int x, int y, int width, int height) { }); c.weighty = 1; - JTable detailsTable = new JTable(detailsModel); + JTable detailsTable = detailsModel.makeTable(); JScrollPane detailsScroller = new JScrollPane(detailsTable); detailsScroller.setPreferredSize(detailsScroller.getMaximumSize()); @@ -436,6 +437,15 @@ public TableWithFilterAndDetailsBuilder setFixedData(boolean fixedData) { this.fixedData = fixedData; return this; } + + public TableWithFilterAndDetailsBuilder apply(Consumer> func) { + func.accept(this); + return this; + } + + public TableWithFilterAndDetailsBuilder transform(Function, TableWithFilterAndDetailsBuilder> func) { + return func.apply(this); + } } public static TableWithFilterAndDetailsBuilder builder(String title, Supplier> dataGetter) { diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/groovy/GroovyColumns.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/groovy/GroovyColumns.java new file mode 100644 index 000000000000..7f7e63b77dbe --- /dev/null +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tables/groovy/GroovyColumns.java @@ -0,0 +1,117 @@ +package gg.xp.xivsupport.gui.tables.groovy; + +import gg.xp.xivsupport.gui.groovy.GroovyPanel; +import gg.xp.xivsupport.gui.tables.CustomColumn; +import gg.xp.xivsupport.gui.tables.CustomTableModel; +import gg.xp.xivsupport.gui.tables.TableWithFilterAndDetails; +import groovy.lang.GroovyRuntimeException; +import groovy.lang.PropertyValue; +import org.codehaus.groovy.runtime.DefaultGroovyMethods; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.*; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public final class GroovyColumns { + private static final Logger log = LoggerFactory.getLogger(GroovyColumns.class); + public static final CustomColumn propName = new CustomColumn<>("Name", PropertyValue::getName); + public static final CustomColumn propVal = new CustomColumn<>("Value", propertyValue -> { + try { + return propertyValue.getValue(); + } + catch (Throwable t) { + return t; + } + }, c -> { + c.setCellRenderer(new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + value = singleValueConversion(value); + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + }); + }); + public static final CustomColumn propType = new CustomColumn<>("Type", PropertyValue::getType); + + private GroovyColumns() { + } + + public static List getValues(Object obj) { + if (obj == null) { + return Collections.emptyList(); + } + else { + return DefaultGroovyMethods.getMetaPropertyValues(obj) + .stream() + .filter(GroovyColumns::isReadable) + .filter(pv -> !"serialVersionUID".equals(pv.getName())) + .toList(); + } + } + + public static boolean isReadable(PropertyValue pv) { + try { + pv.getValue(); + return true; + } + catch (GroovyRuntimeException gre) { + if (gre.getMessage() != null && gre.getMessage().startsWith("Cannot read write-only property")) { + return false; + } + else { + throw gre; + } + } + } + + public static boolean propEquals(PropertyValue a, PropertyValue b) { + return Objects.equals(a.getName(), b.getName()); + } + + public static void addColumns(CustomTableModel.CustomTableModelBuilder builder) { + builder.addColumn(propName) + .addColumn(propVal) + .addColumn(propType); + builder.setItemEquivalence(GroovyColumns::propEquals); + } + + public static void addDetailColumns(TableWithFilterAndDetails.TableWithFilterAndDetailsBuilder builder) { + builder.addDetailsColumn(propName) + .addDetailsColumn(propVal) + .addDetailsColumn(propType); + builder.setDetailsSelectionEquivalence(GroovyColumns::propEquals); + } + + @SuppressWarnings("MalformedFormatString") + public static Object singleValueConversion(Object obj) { + if (obj == null) { + return "(null)"; + } + if (obj instanceof Byte || obj instanceof Integer || obj instanceof Long || obj instanceof Short) { + return String.format("%d (0x%x)", obj, obj); + } + if (obj.getClass().isArray()) { + int length = Array.getLength(obj); + List converted = new ArrayList<>(); + for (int i = 0; i < length; i++) { + converted.add(Array.get(obj, i)); + } + return converted.stream() + .map(GroovyColumns::singleValueConversion) + .map(Object::toString) + .collect(Collectors.joining(", ", "[", "]")); + } + return obj; + + } +} + diff --git a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tabs/EventsTabFactory.java b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tabs/EventsTabFactory.java index 4d51a6f4c264..86a6df5fd6e6 100644 --- a/xivsupport/src/main/java/gg/xp/xivsupport/gui/tabs/EventsTabFactory.java +++ b/xivsupport/src/main/java/gg/xp/xivsupport/gui/tabs/EventsTabFactory.java @@ -14,7 +14,6 @@ import gg.xp.xivsupport.gui.tables.CustomColumn; import gg.xp.xivsupport.gui.tables.GlobalGuiOptions; import gg.xp.xivsupport.gui.tables.RightClickOptionRepo; -import gg.xp.xivsupport.gui.tables.StandardColumns; import gg.xp.xivsupport.gui.tables.TableWithFilterAndDetails; import gg.xp.xivsupport.gui.tables.filters.AbilityResolutionFilter; import gg.xp.xivsupport.gui.tables.filters.EventAbilityOrBuffFilter; @@ -24,6 +23,7 @@ import gg.xp.xivsupport.gui.tables.filters.PullNumberFilter; import gg.xp.xivsupport.gui.tables.filters.QuickFilters; import gg.xp.xivsupport.gui.tables.filters.SystemEventFilter; +import gg.xp.xivsupport.gui.tables.groovy.GroovyColumns; import gg.xp.xivsupport.gui.tables.renderers.AbilityEffectListRenderer; import gg.xp.xivsupport.gui.tables.renderers.ActionAndStatusRenderer; import gg.xp.xivsupport.gui.tables.renderers.NameJobRenderer; @@ -32,20 +32,17 @@ import gg.xp.xivsupport.persistence.settings.BooleanSetting; import gg.xp.xivsupport.replay.ReplayController; import gg.xp.xivsupport.replay.gui.ReplayAdvancePseudoFilter; +import groovy.lang.PropertyValue; import org.jetbrains.annotations.Nullable; import org.picocontainer.MutablePicoContainer; import javax.swing.*; import java.awt.*; import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import java.util.stream.Collectors; @ScanMe public class EventsTabFactory { @@ -75,19 +72,9 @@ public Component getEventsTab() { displayIdsSetting.addAndRunListener(() -> asRenderer.setShowId(displayIdsSetting.get())); displayIdsSetting.addAndRunListener(() -> nameJobRenderer.setShowId(displayIdsSetting.get())); TimeDisplayController tdc = new TimeDisplayController(); - TableWithFilterAndDetails> table = TableWithFilterAndDetails.builder("Events", rawStorage::getEvents, - currentEvent -> { - if (currentEvent == null) { - return Collections.emptyList(); - } - else { - return currentEvent.dumpFields() - .entrySet() - .stream() - .filter(e -> !"serialVersionUID".equals(e.getKey().getName())) - .collect(Collectors.toList()); - } - }) + TableWithFilterAndDetails table = TableWithFilterAndDetails.builder("Events", + rawStorage::getEvents, + GroovyColumns::getValues) .addMainColumn(tdc.getColumnDef()) .addMainColumn(new CustomColumn<>("Type", e -> e.getClass().getSimpleName())) .addMainColumn(new CustomColumn<>("Source", e -> e instanceof HasSourceEntity ? ((HasSourceEntity) e).getSource() : null, c -> c.setCellRenderer(nameJobRenderer))) @@ -101,15 +88,7 @@ public Component getEventsTab() { } return null; }, c -> c.setCellRenderer(new AbilityEffectListRenderer()))) - .addMainColumn(new CustomColumn<>("Parent", e -> { - Event parent = e.getParent(); - return parent == null ? null : parent.getClass().getSimpleName(); - })) - .addDetailsColumn(StandardColumns.fieldName) - .addDetailsColumn(StandardColumns.fieldValue) - .addDetailsColumn(StandardColumns.identity) - .addDetailsColumn(StandardColumns.fieldType) - .addDetailsColumn(StandardColumns.fieldDeclaredIn) + .apply(GroovyColumns::addDetailColumns) .withRightClickRepo(rightClicks) .addFilter(SystemEventFilter::new) .addFilter(EventClassFilterFilter::new) diff --git a/xivsupport/src/main/resources/te_changelog.html b/xivsupport/src/main/resources/te_changelog.html index 935d3bd704cd..a735f717ddb0 100644 --- a/xivsupport/src/main/resources/te_changelog.html +++ b/xivsupport/src/main/resources/te_changelog.html @@ -1,5 +1,10 @@ +

July 15, 2024

+
    +
  • Cleaned up events tab.
  • +
  • Revamped table details to better show which properties can be used in scripts.
  • +

July 13, 2024

  • More Ex1