From e7f767562f79b63943747767e769ae09a9f2e695 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sat, 29 Jul 2023 17:17:49 +0200
Subject: [PATCH 01/23] Limit icon preview to ResourceBitmap subtype IwdRef
Prevents ProRef projectile list from displaying preview icons.
---
src/org/infinity/gui/TextListPanel.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/org/infinity/gui/TextListPanel.java b/src/org/infinity/gui/TextListPanel.java
index 77b29feda..e749f5de6 100644
--- a/src/org/infinity/gui/TextListPanel.java
+++ b/src/org/infinity/gui/TextListPanel.java
@@ -41,6 +41,7 @@
import org.infinity.NearInfinity;
import org.infinity.datatype.AbstractBitmap;
+import org.infinity.datatype.IwdRef;
import org.infinity.datatype.ResourceBitmap;
import org.infinity.datatype.ResourceRef;
import org.infinity.icon.Icons;
@@ -345,7 +346,8 @@ public Component getListCellRendererComponent(JList> list, Object value, int i
} else if (value instanceof AbstractBitmap.FormattedData>) {
// resolving Resource Bitmap
final AbstractBitmap.FormattedData> fmt = (AbstractBitmap.FormattedData>) value;
- if (fmt.getParent() != null) {
+ // Limit icon preview to parent type: IwdRef
+ if (fmt.getParent() instanceof IwdRef) {
final AbstractBitmap> bmp = fmt.getParent();
Object o = bmp.getDataOf(fmt.getValue());
if (o instanceof ResourceBitmap.RefEntry) {
From fd480aa4703f1be5deebe613e83f14ca012b5325 Mon Sep 17 00:00:00 2001
From: Mark
Date: Thu, 17 Aug 2023 18:45:41 +0400
Subject: [PATCH 02/23] fixed #123
---
src/org/infinity/datatype/ResourceRef.java | 24 ++++++++++++++-
.../resource/sound/SoundResource.java | 29 +++++++++++++------
2 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/src/org/infinity/datatype/ResourceRef.java b/src/org/infinity/datatype/ResourceRef.java
index 99888d640..a38d648ba 100644
--- a/src/org/infinity/datatype/ResourceRef.java
+++ b/src/org/infinity/datatype/ResourceRef.java
@@ -40,6 +40,7 @@
import org.infinity.resource.AbstractStruct;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.key.ResourceEntry;
+import org.infinity.resource.sound.SoundResource;
import org.infinity.util.Misc;
import org.infinity.util.io.StreamUtils;
@@ -80,6 +81,9 @@ public class ResourceRef extends Datatype
/** Button that used to open editor of current selected element in the list. */
private JButton bView;
+ /** Button that used to play sound of current selected element in the list. */
+ private JButton bPlay;
+
/**
* GUI component that lists all available resources that can be set to this resource reference and have edit field for
* ability to enter resource reference manually.
@@ -117,6 +121,12 @@ public void actionPerformed(ActionEvent event) {
if (isEditable(selected)) {
new ViewFrame(list.getTopLevelAncestor(), ResourceFactory.getResource(selected.entry));
}
+ } else if (event.getSource() == bPlay) {
+ final ResourceRefEntry selected = list.getSelectedValue();
+ if (isSound(selected)) {
+ SoundResource res = (SoundResource) ResourceFactory.getResource(selected.entry);
+ res.playSound();
+ }
}
}
@@ -183,12 +193,15 @@ public void mouseClicked(MouseEvent event) {
bView = new JButton("View/Edit", Icons.ICON_ZOOM_16.getIcon());
bView.addActionListener(this);
bView.setEnabled(isEditable(list.getSelectedValue()));
+ bPlay = new JButton("Play", Icons.ICON_PLAY_16.getIcon());
+ bPlay.addActionListener(this);
+ bPlay.setEnabled(isSound(list.getSelectedValue()));
list.addListSelectionListener(this);
GridBagConstraints gbc = null;
JPanel panel = new JPanel(new GridBagLayout());
- gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 2, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
+ gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 3, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0);
panel.add(list, gbc);
gbc = ViewerUtil.setGBC(gbc, 1, 0, 1, 1, 0.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL,
@@ -198,6 +211,10 @@ public void mouseClicked(MouseEvent event) {
new Insets(3, 6, 3, 0), 0, 0);
panel.add(bView, gbc);
+ gbc = ViewerUtil.setGBC(gbc, 1, 2, 1, 1, 0.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL,
+ new Insets(3, 6, 3, 0), 0, 0);
+ panel.add(bPlay, gbc);
+
panel.setMinimumSize(Misc.getScaledDimension(DIM_MEDIUM));
panel.setPreferredSize(panel.getMinimumSize());
return panel;
@@ -252,6 +269,7 @@ public boolean updateValue(AbstractStruct struct) {
@Override
public void valueChanged(ListSelectionEvent e) {
bView.setEnabled(isEditable(list.getSelectedValue()));
+ bPlay.setEnabled(isSound(list.getSelectedValue()));
}
@Override
@@ -377,6 +395,10 @@ private boolean isEditable(ResourceRefEntry ref) {
return ref != null && ref != NONE && ref.entry != null;
}
+ private boolean isSound(ResourceRefEntry ref) {
+ return ref != null && ref != NONE && ref.entry != null && ref.entry.getExtension().equalsIgnoreCase("WAV");
+ }
+
private void setValue(String newValue) {
final String oldValue = NONE.name.equals(resname) ? null : resname;
resname = newValue;
diff --git a/src/org/infinity/resource/sound/SoundResource.java b/src/org/infinity/resource/sound/SoundResource.java
index 83b3731a8..214a8ee14 100644
--- a/src/org/infinity/resource/sound/SoundResource.java
+++ b/src/org/infinity/resource/sound/SoundResource.java
@@ -168,8 +168,10 @@ public void searchReferences(Component parent) {
@Override
public void run() {
- bPlay.setIcon(PLAY_ICONS.get(false));
- bStop.setEnabled(true);
+ if (bPlay != null) {
+ bPlay.setIcon(PLAY_ICONS.get(false));
+ bStop.setEnabled(true);
+ }
if (audioBuffer != null) {
final TimerElapsedTask timerTask = new TimerElapsedTask(250L);
try {
@@ -182,8 +184,10 @@ public void run() {
player.stopPlay();
timerTask.stop();
}
- bStop.setEnabled(false);
- bPlay.setIcon(PLAY_ICONS.get(true));
+ if (bPlay != null) {
+ bStop.setEnabled(false);
+ bPlay.setIcon(PLAY_ICONS.get(true));
+ }
}
// --------------------- End Interface Runnable ---------------------
@@ -294,10 +298,11 @@ private synchronized void setLoaded(boolean b) {
if (bPlay != null) {
bPlay.setEnabled(b);
bPlay.setIcon(PLAY_ICONS.get(true));
+
+ updateTimeLabel(0);
+ miConvert.setEnabled(b);
+ buttonPanel.getControlByType(PROPERTIES).setEnabled(true);
}
- updateTimeLabel(0);
- miConvert.setEnabled(b);
- buttonPanel.getControlByType(PROPERTIES).setEnabled(true);
}
private synchronized void setClosed(boolean b) {
@@ -448,16 +453,22 @@ public void stop() {
timer.cancel();
timer = null;
paused = false;
- updateTimeLabel(0L);
+ if (bPlay != null) {
+ updateTimeLabel(0L);
+ }
}
}
@Override
public void run() {
- if (!paused && timer != null && player != null && player.getDataLine() != null) {
+ if (!paused && timer != null && player != null && player.getDataLine() != null && bPlay != null) {
updateTimeLabel(player.getDataLine().getMicrosecondPosition() / 1000L);
}
}
+ }
+ public void playSound() {
+ loadAudio();
+ new Thread(this).start();
}
}
From 80a5c68d65070ce2a46a1418a28251b9864e28a0 Mon Sep 17 00:00:00 2001
From: Mark
Date: Fri, 18 Aug 2023 15:10:11 +0400
Subject: [PATCH 03/23] introduce isSound in ResourceRef
---
src/org/infinity/datatype/ResourceRef.java | 2 +-
src/org/infinity/resource/key/ResourceEntry.java | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/org/infinity/datatype/ResourceRef.java b/src/org/infinity/datatype/ResourceRef.java
index a38d648ba..816f9cca2 100644
--- a/src/org/infinity/datatype/ResourceRef.java
+++ b/src/org/infinity/datatype/ResourceRef.java
@@ -396,7 +396,7 @@ private boolean isEditable(ResourceRefEntry ref) {
}
private boolean isSound(ResourceRefEntry ref) {
- return ref != null && ref != NONE && ref.entry != null && ref.entry.getExtension().equalsIgnoreCase("WAV");
+ return ref != null && ref != NONE && ref.entry != null && ref.entry.isSound();
}
private void setValue(String newValue) {
diff --git a/src/org/infinity/resource/key/ResourceEntry.java b/src/org/infinity/resource/key/ResourceEntry.java
index cdf316a13..e67976704 100644
--- a/src/org/infinity/resource/key/ResourceEntry.java
+++ b/src/org/infinity/resource/key/ResourceEntry.java
@@ -280,4 +280,10 @@ public boolean isVisible() {
public abstract ResourceTreeFolder getTreeFolder();
public abstract boolean hasOverride();
+
+ public boolean isSound() {
+ String extension = getExtension().toUpperCase();
+
+ return extension.equals("WAV") || extension.equals("MUS") || extension.equals("ACM");
+ }
}
From 49fe2793d07f9493dbc14a2e980c3e929aad6596 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sun, 3 Sep 2023 11:00:13 +0200
Subject: [PATCH 04/23] Improve sound playback in ResourceRef datatype
- Improved placement of sound playback button.
- Opened sound resource is properly closed when another resource is
selected.
- Current playback is stopped when a new sound playback is initiated to
prevent overlapping sound playback.
TODO: Sound resource should be closed when the parent resource is closed.
---
src/org/infinity/datatype/ResourceRef.java | 62 ++++++++++++++++++----
1 file changed, 52 insertions(+), 10 deletions(-)
diff --git a/src/org/infinity/datatype/ResourceRef.java b/src/org/infinity/datatype/ResourceRef.java
index 816f9cca2..c84033364 100644
--- a/src/org/infinity/datatype/ResourceRef.java
+++ b/src/org/infinity/datatype/ResourceRef.java
@@ -4,6 +4,7 @@
package org.infinity.datatype;
+import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
@@ -38,6 +39,8 @@
import org.infinity.gui.menu.BrowserMenuBar;
import org.infinity.icon.Icons;
import org.infinity.resource.AbstractStruct;
+import org.infinity.resource.Closeable;
+import org.infinity.resource.Resource;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.resource.sound.SoundResource;
@@ -90,6 +93,9 @@ public class ResourceRef extends Datatype
*/
private TextListPanel list;
+ /** Contains the {@link Resource} of the currently selected resource reference. */
+ private Resource currentResource;
+
/**
* Returns a list of resource extensions that can be used to display associated icons.
* @return String set with file extensions (without leading dot).
@@ -124,8 +130,11 @@ public void actionPerformed(ActionEvent event) {
} else if (event.getSource() == bPlay) {
final ResourceRefEntry selected = list.getSelectedValue();
if (isSound(selected)) {
+ // prevent overlapping sound playback
+ closeResource(currentResource);
SoundResource res = (SoundResource) ResourceFactory.getResource(selected.entry);
res.playSound();
+ currentResource = res;
}
}
}
@@ -192,29 +201,42 @@ public void mouseClicked(MouseEvent event) {
bUpdate.setActionCommand(StructViewer.UPDATE_VALUE);
bView = new JButton("View/Edit", Icons.ICON_ZOOM_16.getIcon());
bView.addActionListener(this);
- bView.setEnabled(isEditable(list.getSelectedValue()));
bPlay = new JButton("Play", Icons.ICON_PLAY_16.getIcon());
bPlay.addActionListener(this);
- bPlay.setEnabled(isSound(list.getSelectedValue()));
list.addListSelectionListener(this);
+ setResourceEntryUpdated(list.getSelectedValue());
GridBagConstraints gbc = null;
JPanel panel = new JPanel(new GridBagLayout());
- gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 3, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
+ gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 5, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0);
panel.add(list, gbc);
- gbc = ViewerUtil.setGBC(gbc, 1, 0, 1, 1, 0.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL,
+
+ // spacer keeps controls in the center
+ final JPanel spacerTop = new JPanel();
+ spacerTop.setMinimumSize(new Dimension());
+ gbc = ViewerUtil.setGBC(gbc, 1, 0, 1, 1, 0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+ new Insets(0, 0, 0, 0), 0, 0);
+ panel.add(spacerTop, gbc);
+
+ gbc = ViewerUtil.setGBC(gbc, 1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(3, 6, 3, 0), 0, 0);
panel.add(bUpdate, gbc);
- gbc = ViewerUtil.setGBC(gbc, 1, 1, 1, 1, 0.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL,
+ gbc = ViewerUtil.setGBC(gbc, 1, 2, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(3, 6, 3, 0), 0, 0);
panel.add(bView, gbc);
-
- gbc = ViewerUtil.setGBC(gbc, 1, 2, 1, 1, 0.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL,
- new Insets(3, 6, 3, 0), 0, 0);
+ gbc = ViewerUtil.setGBC(gbc, 1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+ new Insets(24, 6, 3, 0), 0, 0);
panel.add(bPlay, gbc);
+ // spacer keeps controls in the center
+ final JPanel spacerBottom = new JPanel();
+ spacerTop.setMinimumSize(new Dimension());
+ gbc = ViewerUtil.setGBC(gbc, 1, 4, 1, 1, 0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+ new Insets(0, 0, 0, 0), 0, 0);
+ panel.add(spacerBottom, gbc);
+
panel.setMinimumSize(Misc.getScaledDimension(DIM_MEDIUM));
panel.setPreferredSize(panel.getMinimumSize());
return panel;
@@ -268,8 +290,7 @@ public boolean updateValue(AbstractStruct struct) {
@Override
public void valueChanged(ListSelectionEvent e) {
- bView.setEnabled(isEditable(list.getSelectedValue()));
- bPlay.setEnabled(isSound(list.getSelectedValue()));
+ setResourceEntryUpdated(list.getSelectedValue());
}
@Override
@@ -391,6 +412,27 @@ public boolean isLegalEntry(ResourceEntry entry) {
void addExtraEntries(List entries) {
}
+ private void setResourceEntryUpdated(ResourceRefEntry entry) {
+ closeResource(currentResource);
+ if (entry != null) {
+ bView.setEnabled(isEditable(entry));
+ bPlay.setEnabled(isSound(entry));
+ } else {
+ bView.setEnabled(false);
+ bPlay.setEnabled(false);
+ }
+ }
+
+ private void closeResource(Resource resource) {
+ if (resource instanceof Closeable) {
+ try {
+ ((Closeable) resource).close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
private boolean isEditable(ResourceRefEntry ref) {
return ref != null && ref != NONE && ref.entry != null;
}
From d34292c293ccf62f81ff47dfc91730e2286fa83c Mon Sep 17 00:00:00 2001
From: Bubb13 <36863623+Bubb13@users.noreply.github.com>
Date: Wed, 11 Oct 2023 17:18:46 -0700
Subject: [PATCH 05/23] Fix advanced search not opening the correct viewable
- showResourceEntry() runs on the background thread, so subsequent calls to NearInfinity.getInstance().getViewable() might fetch the old viewable.
---
src/org/infinity/NearInfinity.java | 6 ++-
src/org/infinity/check/BCSIDSChecker.java | 11 ++++--
src/org/infinity/check/CreInvChecker.java | 11 ++++--
src/org/infinity/check/DialogChecker.java | 12 ++++--
src/org/infinity/check/ScriptChecker.java | 12 ++++--
src/org/infinity/gui/ResourceTree.java | 39 +++++++++++++------
.../infinity/search/ReferenceHitFrame.java | 17 +++++---
src/org/infinity/search/TextHitFrame.java | 15 ++++---
.../search/advanced/AdvancedSearch.java | 17 +++++---
9 files changed, 98 insertions(+), 42 deletions(-)
diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java
index 716c9958e..251f25904 100644
--- a/src/org/infinity/NearInfinity.java
+++ b/src/org/infinity/NearInfinity.java
@@ -888,7 +888,11 @@ public boolean removeViewable() {
}
public void showResourceEntry(ResourceEntry resourceEntry) {
- tree.select(resourceEntry);
+ showResourceEntry(resourceEntry, null);
+ }
+
+ public void showResourceEntry(ResourceEntry resourceEntry, Operation doneOperation) {
+ tree.select(resourceEntry, doneOperation);
}
public void quit() {
diff --git a/src/org/infinity/check/BCSIDSChecker.java b/src/org/infinity/check/BCSIDSChecker.java
index 30eb6a78d..e4e28163d 100644
--- a/src/org/infinity/check/BCSIDSChecker.java
+++ b/src/org/infinity/check/BCSIDSChecker.java
@@ -41,6 +41,7 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
/** Performs checking {@link BcsResource BCS} & {@code BS} resources. */
public final class BCSIDSChecker extends AbstractSearcher implements Runnable, ActionListener, ListSelectionListener {
@@ -65,9 +66,13 @@ public void actionPerformed(ActionEvent event) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry);
- BcsResource bcsfile = (BcsResource) NearInfinity.getInstance().getViewable();
- bcsfile.highlightText(((Integer) table.getValueAt(row, 2)), null);
+ NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
+ @Override
+ public void perform() {
+ BcsResource bcsfile = (BcsResource) NearInfinity.getInstance().getViewable();
+ bcsfile.highlightText(((Integer) table.getValueAt(row, 2)), null);
+ }
+ });
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/check/CreInvChecker.java b/src/org/infinity/check/CreInvChecker.java
index f15a0baaf..f991d8f86 100644
--- a/src/org/infinity/check/CreInvChecker.java
+++ b/src/org/infinity/check/CreInvChecker.java
@@ -44,6 +44,7 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
/** Performs checking {@link CreResource CRE} & {@code CHR} resources. */
public final class CreInvChecker extends AbstractSearcher implements Runnable, ActionListener, ListSelectionListener {
@@ -68,9 +69,13 @@ public void actionPerformed(ActionEvent event) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry);
- ((AbstractStruct) NearInfinity.getInstance().getViewable()).getViewer()
- .selectEntry(((Item) table.getValueAt(row, 2)).getName());
+ NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
+ @Override
+ public void perform() {
+ ((AbstractStruct) NearInfinity.getInstance().getViewable()).getViewer()
+ .selectEntry(((Item) table.getValueAt(row, 2)).getName());
+ }
+ });
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/check/DialogChecker.java b/src/org/infinity/check/DialogChecker.java
index d8e5841f4..2abe82778 100644
--- a/src/org/infinity/check/DialogChecker.java
+++ b/src/org/infinity/check/DialogChecker.java
@@ -48,6 +48,7 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
/** Performs checking {@link DlgResource DLG} resources. */
public final class DialogChecker extends AbstractSearcher
@@ -84,9 +85,14 @@ public void actionPerformed(ActionEvent event) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry);
- ((AbstractStruct) NearInfinity.getInstance().getViewable()).getViewer()
- .selectEntry((String) table.getValueAt(row, 1));
+ final SortableTable tableCapture = table;
+ NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
+ @Override
+ public void perform() {
+ ((AbstractStruct) NearInfinity.getInstance().getViewable()).getViewer()
+ .selectEntry((String) tableCapture.getValueAt(row, 1));
+ }
+ });
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/check/ScriptChecker.java b/src/org/infinity/check/ScriptChecker.java
index 93d56cf35..ff4a5949c 100644
--- a/src/org/infinity/check/ScriptChecker.java
+++ b/src/org/infinity/check/ScriptChecker.java
@@ -43,6 +43,7 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
/** Performs checking {@link BcsResource BCS} & {@code BS} resources. */
public final class ScriptChecker extends AbstractSearcher
@@ -76,9 +77,14 @@ public void actionPerformed(ActionEvent event) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry);
- ((BcsResource) NearInfinity.getInstance().getViewable()).highlightText(((Integer) table.getValueAt(row, 2)),
- null);
+ final SortableTable tableCapture = table;
+ NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
+ @Override
+ public void perform() {
+ ((BcsResource) NearInfinity.getInstance().getViewable())
+ .highlightText(((Integer) tableCapture.getValueAt(row, 2)), null);
+ }
+ });
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/gui/ResourceTree.java b/src/org/infinity/gui/ResourceTree.java
index c1e61779d..9b7330c93 100644
--- a/src/org/infinity/gui/ResourceTree.java
+++ b/src/org/infinity/gui/ResourceTree.java
@@ -68,6 +68,7 @@
import org.infinity.resource.key.ResourceTreeFolder;
import org.infinity.resource.key.ResourceTreeModel;
import org.infinity.util.IconCache;
+import org.infinity.util.Operation;
import org.infinity.util.io.FileEx;
import org.infinity.util.io.FileManager;
import org.infinity.util.io.StreamUtils;
@@ -192,24 +193,38 @@ public void select(ResourceEntry entry) {
}
public void select(ResourceEntry entry, boolean forced) {
+ select(entry, forced, null);
+ }
+
+ public void select(ResourceEntry entry, Operation doneOperation) {
+ select(entry, false, doneOperation);
+ }
+
+ public void select(ResourceEntry entry, boolean forced, Operation doneOperation) {
new SwingWorker() {
@Override
protected Void doInBackground() throws Exception {
- if (entry == null) {
- tree.clearSelection();
- } else if (forced || entry != shownResource) {
- TreePath tp = ResourceFactory.getResourceTreeModel().getPathToNode(entry);
- try {
- expandListener.treeWillExpand(new TreeExpansionEvent(tree, tp));
- tree.scrollPathToVisible(tp);
- tree.addSelectionPath(tp);
- tree.repaint();
- } finally {
- expandListener.treeExpanded(new TreeExpansionEvent(tree, tp));
- }
+ if (entry == null) {
+ tree.clearSelection();
+ } else if (forced || entry != shownResource) {
+ TreePath tp = ResourceFactory.getResourceTreeModel().getPathToNode(entry);
+ try {
+ expandListener.treeWillExpand(new TreeExpansionEvent(tree, tp));
+ tree.scrollPathToVisible(tp);
+ tree.addSelectionPath(tp);
+ tree.repaint();
+ } finally {
+ expandListener.treeExpanded(new TreeExpansionEvent(tree, tp));
}
+ }
return null;
}
+ @Override
+ protected void done() {
+ if (doneOperation != null) {
+ doneOperation.perform();
+ }
+ }
}.execute();
}
diff --git a/src/org/infinity/search/ReferenceHitFrame.java b/src/org/infinity/search/ReferenceHitFrame.java
index ae290c188..d43f88c07 100644
--- a/src/org/infinity/search/ReferenceHitFrame.java
+++ b/src/org/infinity/search/ReferenceHitFrame.java
@@ -43,6 +43,7 @@
import org.infinity.resource.key.FileResourceEntry;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
public final class ReferenceHitFrame extends ChildFrame implements ActionListener, ListSelectionListener {
private static final String QUERY_STRING = "string reference";
@@ -130,12 +131,16 @@ public void actionPerformed(ActionEvent event) {
((ViewFrame) parent).toFront();
}
} else {
- NearInfinity.getInstance().showResourceEntry(entry);
- Viewable viewable = NearInfinity.getInstance().getViewable();
- showEntryInViewer(row, viewable);
- if (viewable instanceof DlgResource) {
- NearInfinity.getInstance().toFront();
- }
+ NearInfinity.getInstance().showResourceEntry(entry, new Operation() {
+ @Override
+ public void perform() {
+ Viewable viewable = NearInfinity.getInstance().getViewable();
+ showEntryInViewer(row, viewable);
+ if (viewable instanceof DlgResource) {
+ NearInfinity.getInstance().toFront();
+ }
+ }
+ });
}
}
} else if (event.getSource() == bopennew) {
diff --git a/src/org/infinity/search/TextHitFrame.java b/src/org/infinity/search/TextHitFrame.java
index 5c1a11f4a..a4438836a 100644
--- a/src/org/infinity/search/TextHitFrame.java
+++ b/src/org/infinity/search/TextHitFrame.java
@@ -36,6 +36,7 @@
import org.infinity.resource.Viewable;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
final class TextHitFrame extends ChildFrame implements ActionListener, ListSelectionListener {
private final Component parent;
@@ -119,11 +120,15 @@ public void actionPerformed(ActionEvent event) {
((TextResource) res).highlightText(((Integer) table.getValueAt(row, 2)), query);
}
} else {
- NearInfinity.getInstance().showResourceEntry(entry);
- Viewable viewable = NearInfinity.getInstance().getViewable();
- if (viewable instanceof TextResource) {
- ((TextResource) viewable).highlightText(((Integer) table.getValueAt(row, 2)), query);
- }
+ NearInfinity.getInstance().showResourceEntry(entry, new Operation() {
+ @Override
+ public void perform() {
+ Viewable viewable = NearInfinity.getInstance().getViewable();
+ if (viewable instanceof TextResource) {
+ ((TextResource) viewable).highlightText(((Integer) table.getValueAt(row, 2)), query);
+ }
+ }
+ });
}
}
} else if (event.getSource() == bopennew) {
diff --git a/src/org/infinity/search/advanced/AdvancedSearch.java b/src/org/infinity/search/advanced/AdvancedSearch.java
index ef82f8f22..69d76f552 100644
--- a/src/org/infinity/search/advanced/AdvancedSearch.java
+++ b/src/org/infinity/search/advanced/AdvancedSearch.java
@@ -77,6 +77,7 @@
import org.infinity.search.ReferenceHitFrame;
import org.infinity.util.Debugging;
import org.infinity.util.Misc;
+import org.infinity.util.Operation;
import org.infinity.util.SimpleListModel;
public class AdvancedSearch extends ChildFrame implements Runnable {
@@ -819,12 +820,16 @@ public void actionPerformed(ActionEvent event) {
if (row != -1) {
ResourceEntry entry = (ResourceEntry) listResults.getValueAt(row, 0);
if (entry != null) {
- NearInfinity.getInstance().showResourceEntry(entry);
- Viewable viewable = NearInfinity.getInstance().getViewable();
- showEntryInViewer(row, viewable);
- if (viewable instanceof DlgResource) {
- NearInfinity.getInstance().toFront();
- }
+ NearInfinity.getInstance().showResourceEntry(entry, new Operation() {
+ @Override
+ public void perform() {
+ Viewable viewable = NearInfinity.getInstance().getViewable();
+ showEntryInViewer(row, viewable);
+ if (viewable instanceof DlgResource) {
+ NearInfinity.getInstance().toFront();
+ }
+ }
+ });
}
}
} else if (event.getSource() == bOpenNew) {
From 4037ee7b8acd9170b3576f2e5a3c1fba5bed7ae0 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Thu, 12 Oct 2023 10:30:46 +0200
Subject: [PATCH 06/23] Code cleanup
---
src/org/infinity/check/BCSIDSChecker.java | 10 +++-------
src/org/infinity/check/CreInvChecker.java | 11 +++--------
src/org/infinity/check/DialogChecker.java | 11 +++--------
src/org/infinity/check/ScriptChecker.java | 11 +++--------
src/org/infinity/gui/ResourceTree.java | 1 +
src/org/infinity/search/ReferenceHitFrame.java | 14 +++++---------
src/org/infinity/search/TextHitFrame.java | 12 ++++--------
.../infinity/search/advanced/AdvancedSearch.java | 14 +++++---------
8 files changed, 27 insertions(+), 57 deletions(-)
diff --git a/src/org/infinity/check/BCSIDSChecker.java b/src/org/infinity/check/BCSIDSChecker.java
index e4e28163d..dd931a119 100644
--- a/src/org/infinity/check/BCSIDSChecker.java
+++ b/src/org/infinity/check/BCSIDSChecker.java
@@ -41,7 +41,6 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
/** Performs checking {@link BcsResource BCS} & {@code BS} resources. */
public final class BCSIDSChecker extends AbstractSearcher implements Runnable, ActionListener, ListSelectionListener {
@@ -66,12 +65,9 @@ public void actionPerformed(ActionEvent event) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
- @Override
- public void perform() {
- BcsResource bcsfile = (BcsResource) NearInfinity.getInstance().getViewable();
- bcsfile.highlightText(((Integer) table.getValueAt(row, 2)), null);
- }
+ NearInfinity.getInstance().showResourceEntry(resourceEntry, () -> {
+ final BcsResource bcsfile = (BcsResource) NearInfinity.getInstance().getViewable();
+ bcsfile.highlightText(((Integer) table.getValueAt(row, 2)), null);
});
}
} else if (event.getSource() == bopennew) {
diff --git a/src/org/infinity/check/CreInvChecker.java b/src/org/infinity/check/CreInvChecker.java
index f991d8f86..23a8aeecf 100644
--- a/src/org/infinity/check/CreInvChecker.java
+++ b/src/org/infinity/check/CreInvChecker.java
@@ -44,7 +44,6 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
/** Performs checking {@link CreResource CRE} & {@code CHR} resources. */
public final class CreInvChecker extends AbstractSearcher implements Runnable, ActionListener, ListSelectionListener {
@@ -69,13 +68,9 @@ public void actionPerformed(ActionEvent event) {
int row = table.getSelectedRow();
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
- @Override
- public void perform() {
- ((AbstractStruct) NearInfinity.getInstance().getViewable()).getViewer()
- .selectEntry(((Item) table.getValueAt(row, 2)).getName());
- }
- });
+ NearInfinity.getInstance().showResourceEntry(resourceEntry,
+ () -> ((AbstractStruct)NearInfinity.getInstance().getViewable()).getViewer()
+ .selectEntry(((Item)table.getValueAt(row, 2)).getName()));
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/check/DialogChecker.java b/src/org/infinity/check/DialogChecker.java
index 2abe82778..3d0915621 100644
--- a/src/org/infinity/check/DialogChecker.java
+++ b/src/org/infinity/check/DialogChecker.java
@@ -48,7 +48,6 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
/** Performs checking {@link DlgResource DLG} resources. */
public final class DialogChecker extends AbstractSearcher
@@ -86,13 +85,9 @@ public void actionPerformed(ActionEvent event) {
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
final SortableTable tableCapture = table;
- NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
- @Override
- public void perform() {
- ((AbstractStruct) NearInfinity.getInstance().getViewable()).getViewer()
- .selectEntry((String) tableCapture.getValueAt(row, 1));
- }
- });
+ NearInfinity.getInstance().showResourceEntry(resourceEntry,
+ () -> ((AbstractStruct)NearInfinity.getInstance().getViewable()).getViewer()
+ .selectEntry((String)tableCapture.getValueAt(row, 1)));
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/check/ScriptChecker.java b/src/org/infinity/check/ScriptChecker.java
index ff4a5949c..096dc2b99 100644
--- a/src/org/infinity/check/ScriptChecker.java
+++ b/src/org/infinity/check/ScriptChecker.java
@@ -43,7 +43,6 @@
import org.infinity.resource.key.ResourceEntry;
import org.infinity.search.AbstractSearcher;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
/** Performs checking {@link BcsResource BCS} & {@code BS} resources. */
public final class ScriptChecker extends AbstractSearcher
@@ -78,13 +77,9 @@ public void actionPerformed(ActionEvent event) {
if (row != -1) {
ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
final SortableTable tableCapture = table;
- NearInfinity.getInstance().showResourceEntry(resourceEntry, new Operation() {
- @Override
- public void perform() {
- ((BcsResource) NearInfinity.getInstance().getViewable())
- .highlightText(((Integer) tableCapture.getValueAt(row, 2)), null);
- }
- });
+ NearInfinity.getInstance().showResourceEntry(resourceEntry,
+ () -> ((BcsResource)NearInfinity.getInstance().getViewable())
+ .highlightText(((Integer)tableCapture.getValueAt(row, 2)), null));
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
diff --git a/src/org/infinity/gui/ResourceTree.java b/src/org/infinity/gui/ResourceTree.java
index 9b7330c93..05f751c4e 100644
--- a/src/org/infinity/gui/ResourceTree.java
+++ b/src/org/infinity/gui/ResourceTree.java
@@ -219,6 +219,7 @@ protected Void doInBackground() throws Exception {
}
return null;
}
+
@Override
protected void done() {
if (doneOperation != null) {
diff --git a/src/org/infinity/search/ReferenceHitFrame.java b/src/org/infinity/search/ReferenceHitFrame.java
index d43f88c07..609b46248 100644
--- a/src/org/infinity/search/ReferenceHitFrame.java
+++ b/src/org/infinity/search/ReferenceHitFrame.java
@@ -43,7 +43,6 @@
import org.infinity.resource.key.FileResourceEntry;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
public final class ReferenceHitFrame extends ChildFrame implements ActionListener, ListSelectionListener {
private static final String QUERY_STRING = "string reference";
@@ -131,14 +130,11 @@ public void actionPerformed(ActionEvent event) {
((ViewFrame) parent).toFront();
}
} else {
- NearInfinity.getInstance().showResourceEntry(entry, new Operation() {
- @Override
- public void perform() {
- Viewable viewable = NearInfinity.getInstance().getViewable();
- showEntryInViewer(row, viewable);
- if (viewable instanceof DlgResource) {
- NearInfinity.getInstance().toFront();
- }
+ NearInfinity.getInstance().showResourceEntry(entry, () -> {
+ Viewable viewable = NearInfinity.getInstance().getViewable();
+ showEntryInViewer(row, viewable);
+ if (viewable instanceof DlgResource) {
+ NearInfinity.getInstance().toFront();
}
});
}
diff --git a/src/org/infinity/search/TextHitFrame.java b/src/org/infinity/search/TextHitFrame.java
index a4438836a..08484ff87 100644
--- a/src/org/infinity/search/TextHitFrame.java
+++ b/src/org/infinity/search/TextHitFrame.java
@@ -36,7 +36,6 @@
import org.infinity.resource.Viewable;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
final class TextHitFrame extends ChildFrame implements ActionListener, ListSelectionListener {
private final Component parent;
@@ -120,13 +119,10 @@ public void actionPerformed(ActionEvent event) {
((TextResource) res).highlightText(((Integer) table.getValueAt(row, 2)), query);
}
} else {
- NearInfinity.getInstance().showResourceEntry(entry, new Operation() {
- @Override
- public void perform() {
- Viewable viewable = NearInfinity.getInstance().getViewable();
- if (viewable instanceof TextResource) {
- ((TextResource) viewable).highlightText(((Integer) table.getValueAt(row, 2)), query);
- }
+ NearInfinity.getInstance().showResourceEntry(entry, () -> {
+ Viewable viewable = NearInfinity.getInstance().getViewable();
+ if (viewable instanceof TextResource) {
+ ((TextResource) viewable).highlightText(((Integer) table.getValueAt(row, 2)), query);
}
});
}
diff --git a/src/org/infinity/search/advanced/AdvancedSearch.java b/src/org/infinity/search/advanced/AdvancedSearch.java
index 69d76f552..5796bf657 100644
--- a/src/org/infinity/search/advanced/AdvancedSearch.java
+++ b/src/org/infinity/search/advanced/AdvancedSearch.java
@@ -77,7 +77,6 @@
import org.infinity.search.ReferenceHitFrame;
import org.infinity.util.Debugging;
import org.infinity.util.Misc;
-import org.infinity.util.Operation;
import org.infinity.util.SimpleListModel;
public class AdvancedSearch extends ChildFrame implements Runnable {
@@ -820,14 +819,11 @@ public void actionPerformed(ActionEvent event) {
if (row != -1) {
ResourceEntry entry = (ResourceEntry) listResults.getValueAt(row, 0);
if (entry != null) {
- NearInfinity.getInstance().showResourceEntry(entry, new Operation() {
- @Override
- public void perform() {
- Viewable viewable = NearInfinity.getInstance().getViewable();
- showEntryInViewer(row, viewable);
- if (viewable instanceof DlgResource) {
- NearInfinity.getInstance().toFront();
- }
+ NearInfinity.getInstance().showResourceEntry(entry, () -> {
+ Viewable viewable = NearInfinity.getInstance().getViewable();
+ showEntryInViewer(row, viewable);
+ if (viewable instanceof DlgResource) {
+ NearInfinity.getInstance().toFront();
}
});
}
From ea553b15e9c6bface95ece9a6917c8c2e278a3a9 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 16 Oct 2023 11:52:36 +0200
Subject: [PATCH 07/23] Allow opening games in hidden folders from the "Open
Game" file dialog
---
src/org/infinity/NearInfinity.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java
index 251f25904..96ad70ec9 100644
--- a/src/org/infinity/NearInfinity.java
+++ b/src/org/infinity/NearInfinity.java
@@ -247,6 +247,7 @@ private static Path findKeyfile() {
} else {
chooser = new JFileChooser(Profile.getGameRoot().toFile());
}
+ chooser.setFileHidingEnabled(false);
chooser.setDialogTitle("Open game: Locate keyfile");
chooser.setFileFilter(new FileFilter() {
@Override
From db7efe9688a50489d1799bae4d4f5c86560644dd Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Wed, 25 Oct 2023 21:58:24 +0200
Subject: [PATCH 08/23] Update GH Action
---
.github/workflows/ant.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ant.yml b/.github/workflows/ant.yml
index f1fda9b3a..6e111fdb5 100644
--- a/.github/workflows/ant.yml
+++ b/.github/workflows/ant.yml
@@ -23,7 +23,7 @@ jobs:
sed -i 's/debug="false"/debug="true"/' build.xml
ant -noinput -buildfile build.xml
- name: Upload artifact
- if: ${{ github.actor != 'NearInfinityBrowser' }}
+ if: ${{ github.actor == 'Argent77' }}
uses: pyTooling/Actions/releaser@r0
with:
tag: nightly
From 907d7dff600b35e84811b7eddd9b4c4eb2865987 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sat, 28 Oct 2023 19:02:37 +0200
Subject: [PATCH 09/23] Update GH actions
---
.github/workflows/ant.yml | 2 +-
.github/workflows/deploy.yml | 120 +++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+), 1 deletion(-)
create mode 100644 .github/workflows/deploy.yml
diff --git a/.github/workflows/ant.yml b/.github/workflows/ant.yml
index 6e111fdb5..5be229a07 100644
--- a/.github/workflows/ant.yml
+++ b/.github/workflows/ant.yml
@@ -23,7 +23,7 @@ jobs:
sed -i 's/debug="false"/debug="true"/' build.xml
ant -noinput -buildfile build.xml
- name: Upload artifact
- if: ${{ github.actor == 'Argent77' }}
+ if: ${{ github.repository == 'Argent77/NearInfinity' }}
uses: pyTooling/Actions/releaser@r0
with:
tag: nightly
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 000000000..261a61659
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,120 @@
+# This workflow will build a Java project with Apache Ant and upload the created artifacts
+# on pushes to the master branch.
+
+name: Java CD with Apache Ant
+
+on:
+ push:
+ branches: [ "master" ]
+ workflow_dispatch:
+ branches: [ "master", "devel" ]
+
+permissions:
+ contents: read
+
+jobs:
+ # Build and upload NearInfinity.jar
+ deploy-jar:
+ if: ${{ github.repository == 'Argent77/NearInfinity' }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v3
+ with:
+ java-version: '8'
+ distribution: 'temurin'
+
+ - name: Build with Ant
+ run: |
+ ant -noinput -buildfile build.xml
+
+ - name: Upload JAR artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: NearInfinity
+ path: NearInfinity.jar
+
+ # Build and upload installer versions for Windows and macOS
+ deploy-installer:
+ if: ${{ github.repository == 'Argent77/NearInfinity' }}
+ needs: deploy-jar
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ windows-latest, macos-latest ]
+ java: [ '21' ]
+ runs-on: ${{ matrix.os }}
+ name: Create installer for ${{ matrix.os }}, JDK ${{ matrix.java }}
+ steps:
+ # Initializations
+ - name: Git checkout
+ uses: actions/checkout@v4
+
+ - name: Set up JDK
+ uses: actions/setup-java@v3
+ with:
+ java-version: ${{ matrix.java }}
+ distribution: 'temurin'
+
+ - name: Echo JAVA_HOME (windows)
+ if: (matrix.os == 'windows-latest')
+ run: echo $env:JAVA_HOME
+
+ - name: Echo JAVA_HOME (macos)
+ if: (matrix.os != 'windows-latest')
+ run: echo $JAVA_HOME
+
+ # Preparations
+ - name: Download JAR artifact
+ uses: actions/download-artifact@v3
+ with:
+ name: NearInfinity
+ path: jar
+
+ - name: Set up installer data
+ uses: actions/checkout@v4
+ with:
+ repository: NearInfinityBrowser/NearInfinity-assets
+ path: assets
+
+ # Building
+ - name: Build installer (windows)
+ if: (matrix.os == 'windows-latest')
+ run: |
+ move assets\redistributable\windows\package .
+ move assets\redistributable\windows\build.cmd .
+ .\build.cmd
+
+ - name: Build installer (macos)
+ if: (matrix.os == 'macos-latest')
+ run: |
+ mv assets/redistributable/macos/package .
+ mv assets/redistributable/macos/build.command .
+ chmod +x build.command
+ ./build.command
+
+ # Validation
+ - name: List built files (windows)
+ if: (matrix.os == 'windows-latest')
+ run: dir
+
+ - name: List built files (macos)
+ if: (matrix.os == 'macos-latest')
+ run: ls -l
+
+ # Uploading
+ - name: Upload exe artifact (windows)
+ if: (matrix.os == 'windows-latest')
+ uses: actions/upload-artifact@v3
+ with:
+ name: installer-windows
+ path: NearInfinity-*.exe
+
+ - name: Upload pkg artifact (macos)
+ if: (matrix.os == 'macos-latest')
+ uses: actions/upload-artifact@v3
+ with:
+ name: installer-macos
+ path: NearInfinity-*.pkg
From 0188894d0da1965c93057dacf215d0dcb0e4cdfe Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sun, 29 Oct 2023 10:34:48 +0100
Subject: [PATCH 10/23] Improve deploy.yml
---
.github/workflows/deploy.yml | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 261a61659..0e54bec05 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -17,6 +17,9 @@ jobs:
deploy-jar:
if: ${{ github.repository == 'Argent77/NearInfinity' }}
runs-on: ubuntu-latest
+ name: Build NearInfinity.jar
+ outputs:
+ ni_version: ${{ steps.ni-build.outputs.NI_VERSION }}
steps:
- uses: actions/checkout@v4
@@ -27,13 +30,15 @@ jobs:
distribution: 'temurin'
- name: Build with Ant
+ id: ni-build
run: |
ant -noinput -buildfile build.xml
+ echo "NI_VERSION=$(java -jar "NearInfinity.jar" -version 2>/dev/null | grep -Eo '[0-9]{8}')" >> "$GITHUB_OUTPUT"
- name: Upload JAR artifact
uses: actions/upload-artifact@v3
with:
- name: NearInfinity
+ name: NearInfinity-${{ steps.ni-build.outputs.NI_VERSION }}
path: NearInfinity.jar
# Build and upload installer versions for Windows and macOS
@@ -70,7 +75,7 @@ jobs:
- name: Download JAR artifact
uses: actions/download-artifact@v3
with:
- name: NearInfinity
+ name: NearInfinity-${{ needs.deploy-jar.outputs.ni_version }}
path: jar
- name: Set up installer data
From f97dac6bef74517e447970c677f23661d3b8be72 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sun, 29 Oct 2023 18:10:53 +0100
Subject: [PATCH 11/23] WMP: Show travel distances for all areas if no area is
selected
---
src/org/infinity/resource/wmp/ViewerMap.java | 168 ++++++++++---------
1 file changed, 93 insertions(+), 75 deletions(-)
diff --git a/src/org/infinity/resource/wmp/ViewerMap.java b/src/org/infinity/resource/wmp/ViewerMap.java
index 1363294e7..9785611b8 100644
--- a/src/org/infinity/resource/wmp/ViewerMap.java
+++ b/src/org/infinity/resource/wmp/ViewerMap.java
@@ -24,6 +24,8 @@
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import javax.imageio.ImageIO;
@@ -346,86 +348,102 @@ private void showMapIconLabels() {
}
}
- /** Displays all map distances from the specified area (by index). */
+ /**
+ * Displays all map distances from the specified area (by index).
+ *
+ * @param areaIndex Map index for showing distances. Specify negative value to show distances for all available maps.
+ */
private void showMapDistances(int areaIndex) {
- AreaEntry area = getAreaEntry(areaIndex, true);
- if (area != null) {
- final Direction[] srcDir = { Direction.NORTH, Direction.WEST, Direction.SOUTH, Direction.EAST };
- final Color[] dirColor = { Color.GREEN, Color.RED, Color.CYAN, Color.YELLOW };
- final int[] links = new int[8];
- final int linkSize = 216; // size of a single area link structure
- int ofsLinkBase = ((IsNumeric) getEntry().getAttribute(MapEntry.WMP_MAP_OFFSET_AREA_LINKS)).getValue();
-
- links[0] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_NORTH)).getValue();
- links[1] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_NORTH)).getValue();
- links[2] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_WEST)).getValue();
- links[3] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_WEST)).getValue();
- links[4] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_SOUTH)).getValue();
- links[5] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_SOUTH)).getValue();
- links[6] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_EAST)).getValue();
- links[7] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_EAST)).getValue();
- for (int dir = 0; dir < srcDir.length; dir++) {
- Direction curDir = srcDir[dir];
- Point ptOrigin = getMapIconCoordinate(areaIndex, curDir, true);
- for (int dirIndex = 0, dirCount = links[dir * 2 + 1]; dirIndex < dirCount; dirIndex++) {
- int ofsLink = ofsLinkBase + (links[dir * 2] + dirIndex) * linkSize;
- AreaLink destLink = (AreaLink) area.getAttribute(ofsLink, false);
-
- if (destLink != null) {
- int dstAreaIndex = ((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_TARGET_AREA)).getValue();
- Flag flag = (Flag) destLink.getAttribute(AreaLink.WMP_LINK_DEFAULT_ENTRANCE);
- Direction dstDir = Direction.NORTH;
- if (flag.isFlagSet(1)) {
- dstDir = Direction.EAST;
- } else if (flag.isFlagSet(2)) {
- dstDir = Direction.SOUTH;
- } else if (flag.isFlagSet(3)) {
- dstDir = Direction.WEST;
- }
- Point ptTarget = getMapIconCoordinate(dstAreaIndex, dstDir, false);
-
- // checking for random encounters during travels
- boolean hasRandomEncounters = false;
- if (((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_RANDOM_ENCOUNTER_PROBABILITY)).getValue() > 0) {
- for (int rnd = 1; rnd < 6; rnd++) {
- String rndArea = ((IsReference) destLink
- .getAttribute(String.format(AreaLink.WMP_LINK_RANDOM_ENCOUNTER_AREA_FMT, rnd))).getResourceName();
- if (ResourceFactory.resourceExists(rndArea)) {
- hasRandomEncounters = true;
- break;
+ final List areaIndices = new ArrayList<>();
+ if (areaIndex >= 0) {
+ areaIndices.add(areaIndex);
+ } else {
+ int numAreas = ((IsNumeric) mapEntry.getAttribute(MapEntry.WMP_MAP_NUM_AREAS)).getValue();
+ for (int i = 0; i < numAreas; i++) {
+ areaIndices.add(i);
+ }
+ }
+
+ for (final int curAreaIndex : areaIndices) {
+ AreaEntry area = getAreaEntry(curAreaIndex, true);
+ if (area != null) {
+ final Direction[] srcDir = { Direction.NORTH, Direction.WEST, Direction.SOUTH, Direction.EAST };
+ final Color[] dirColor = { Color.GREEN, Color.RED, Color.CYAN, Color.YELLOW };
+ final int[] links = new int[8];
+ final int linkSize = 216; // size of a single area link structure
+ int ofsLinkBase = ((IsNumeric) getEntry().getAttribute(MapEntry.WMP_MAP_OFFSET_AREA_LINKS)).getValue();
+
+ links[0] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_NORTH)).getValue();
+ links[1] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_NORTH)).getValue();
+ links[2] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_WEST)).getValue();
+ links[3] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_WEST)).getValue();
+ links[4] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_SOUTH)).getValue();
+ links[5] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_SOUTH)).getValue();
+ links[6] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_FIRST_LINK_EAST)).getValue();
+ links[7] = ((IsNumeric) area.getAttribute(AreaEntry.WMP_AREA_NUM_LINKS_EAST)).getValue();
+ for (int dir = 0; dir < srcDir.length; dir++) {
+ Direction curDir = srcDir[dir];
+ Point ptOrigin = getMapIconCoordinate(curAreaIndex, curDir, true);
+ for (int dirIndex = 0, dirCount = links[dir * 2 + 1]; dirIndex < dirCount; dirIndex++) {
+ int ofsLink = ofsLinkBase + (links[dir * 2] + dirIndex) * linkSize;
+ AreaLink destLink = (AreaLink) area.getAttribute(ofsLink, false);
+
+ if (destLink != null) {
+ int dstAreaIndex = ((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_TARGET_AREA)).getValue();
+ Flag flag = (Flag) destLink.getAttribute(AreaLink.WMP_LINK_DEFAULT_ENTRANCE);
+ Direction dstDir = Direction.NORTH;
+ if (flag.isFlagSet(1)) {
+ dstDir = Direction.EAST;
+ } else if (flag.isFlagSet(2)) {
+ dstDir = Direction.SOUTH;
+ } else if (flag.isFlagSet(3)) {
+ dstDir = Direction.WEST;
+ }
+ Point ptTarget = getMapIconCoordinate(dstAreaIndex, dstDir, false);
+
+ // checking for random encounters during travels
+ boolean hasRandomEncounters = false;
+ if (((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_RANDOM_ENCOUNTER_PROBABILITY)).getValue() > 0) {
+ for (int rnd = 1; rnd < 6; rnd++) {
+ String rndArea = ((IsReference) destLink
+ .getAttribute(String.format(AreaLink.WMP_LINK_RANDOM_ENCOUNTER_AREA_FMT, rnd))).getResourceName();
+ if (ResourceFactory.resourceExists(rndArea)) {
+ hasRandomEncounters = true;
+ break;
+ }
}
}
- }
- Graphics2D g = ((BufferedImage) rcMap.getImage()).createGraphics();
- g.setFont(g.getFont().deriveFont(g.getFont().getSize2D() * 0.8f));
- try {
- // drawing line
- g.setColor(dirColor[dir]);
- if (hasRandomEncounters) {
- g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f,
- new float[] { 6.0f, 4.0f }, 0.0f));
- } else {
- g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ Graphics2D g = ((BufferedImage) rcMap.getImage()).createGraphics();
+ g.setFont(g.getFont().deriveFont(g.getFont().getSize2D() * 0.8f));
+ try {
+ // drawing line
+ g.setColor(dirColor[dir]);
+ if (hasRandomEncounters) {
+ g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f,
+ new float[] { 6.0f, 4.0f }, 0.0f));
+ } else {
+ g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ }
+ g.drawLine(ptOrigin.x, ptOrigin.y, ptTarget.x, ptTarget.y);
+
+ // printing travel time (in hours)
+ String duration = String.format("%d h",
+ ((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_DISTANCE_SCALE)).getValue() * 4);
+ LineMetrics lm = g.getFont().getLineMetrics(duration, g.getFontRenderContext());
+ Rectangle2D rectText = g.getFont().getStringBounds(duration, g.getFontRenderContext());
+ int textX = ptOrigin.x + ((ptTarget.x - ptOrigin.x) - rectText.getBounds().width) / 3;
+ int textY = ptOrigin.y + ((ptTarget.y - ptOrigin.y) - rectText.getBounds().height) / 3;
+ int textWidth = rectText.getBounds().width;
+ int textHeight = rectText.getBounds().height;
+ g.setColor(Color.LIGHT_GRAY);
+ g.fillRect(textX - 2, textY, textWidth + 4, textHeight);
+ g.setColor(Color.BLUE);
+ g.drawString(duration, textX, textY + lm.getAscent() + lm.getLeading());
+ } finally {
+ g.dispose();
+ g = null;
}
- g.drawLine(ptOrigin.x, ptOrigin.y, ptTarget.x, ptTarget.y);
-
- // printing travel time (in hours)
- String duration = String.format("%d h",
- ((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_DISTANCE_SCALE)).getValue() * 4);
- LineMetrics lm = g.getFont().getLineMetrics(duration, g.getFontRenderContext());
- Rectangle2D rectText = g.getFont().getStringBounds(duration, g.getFontRenderContext());
- int textX = ptOrigin.x + ((ptTarget.x - ptOrigin.x) - rectText.getBounds().width) / 2;
- int textY = ptOrigin.y + ((ptTarget.y - ptOrigin.y) - rectText.getBounds().height) / 2;
- int textWidth = rectText.getBounds().width;
- int textHeight = rectText.getBounds().height;
- g.setColor(Color.LIGHT_GRAY);
- g.fillRect(textX - 2, textY, textWidth + 4, textHeight);
- g.setColor(Color.BLUE);
- g.drawString(duration, textX, textY + lm.getAscent() + lm.getLeading());
- } finally {
- g.dispose();
- g = null;
}
}
}
From 5e96fbcb2a7696e70c5d8b75fb3e96aa66fae1b4 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 30 Oct 2023 11:33:55 +0100
Subject: [PATCH 12/23] Update GH action
---
.github/workflows/deploy.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 0e54bec05..8877f1fe4 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -89,8 +89,8 @@ jobs:
if: (matrix.os == 'windows-latest')
run: |
move assets\redistributable\windows\package .
- move assets\redistributable\windows\build.cmd .
- .\build.cmd
+ move assets\redistributable\windows\build-installer.cmd .
+ .\build-installer.cmd
- name: Build installer (macos)
if: (matrix.os == 'macos-latest')
From 45836e3e507a191ed16527c6f3eeed8ed0925f92 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 30 Oct 2023 12:26:35 +0100
Subject: [PATCH 13/23] WMP: Make area list multi-selectable
Allows selective display of travel distances between maps.
---
src/org/infinity/resource/wmp/ViewerMap.java | 23 ++++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/org/infinity/resource/wmp/ViewerMap.java b/src/org/infinity/resource/wmp/ViewerMap.java
index 9785611b8..ac65775ae 100644
--- a/src/org/infinity/resource/wmp/ViewerMap.java
+++ b/src/org/infinity/resource/wmp/ViewerMap.java
@@ -41,6 +41,7 @@
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
+import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
@@ -169,6 +170,7 @@ private enum Direction {
listPanel = (StructListPanel) ViewerUtil.makeListPanel("Areas", wmpMap, AreaEntry.class,
AreaEntry.WMP_AREA_CURRENT, new WmpAreaListRenderer(mapIcons), listeners);
+ listPanel.getList().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
JScrollPane mapScroll = new JScrollPane(rcMap);
mapScroll.getVerticalScrollBar().setUnitIncrement(16);
mapScroll.getHorizontalScrollBar().setUnitIncrement(16);
@@ -232,7 +234,7 @@ private void showOverlays(boolean showIcons, boolean showIconLabels, boolean sho
showMapIconLabels();
}
if (showDistances) {
- showMapDistances(listPanel.getList().getSelectedIndex());
+ showMapDistances(listPanel.getList().getSelectedIndices());
}
}
showDot((AreaEntry) listPanel.getList().getSelectedValue(), false);
@@ -351,20 +353,23 @@ private void showMapIconLabels() {
/**
* Displays all map distances from the specified area (by index).
*
- * @param areaIndex Map index for showing distances. Specify negative value to show distances for all available maps.
+ * @param areaIndices Sequence of map indices for showing distances. Specify no parameters to show distances for all
+ * available maps.
*/
- private void showMapDistances(int areaIndex) {
- final List areaIndices = new ArrayList<>();
- if (areaIndex >= 0) {
- areaIndices.add(areaIndex);
- } else {
+ private void showMapDistances(int... areaIndices) {
+ final List areaIndicesList = new ArrayList<>();
+ if (areaIndices.length == 0) {
int numAreas = ((IsNumeric) mapEntry.getAttribute(MapEntry.WMP_MAP_NUM_AREAS)).getValue();
for (int i = 0; i < numAreas; i++) {
- areaIndices.add(i);
+ areaIndicesList.add(i);
+ }
+ } else {
+ for (final int idx : areaIndices) {
+ areaIndicesList.add(idx);
}
}
- for (final int curAreaIndex : areaIndices) {
+ for (final int curAreaIndex : areaIndicesList) {
AreaEntry area = getAreaEntry(curAreaIndex, true);
if (area != null) {
final Direction[] srcDir = { Direction.NORTH, Direction.WEST, Direction.SOUTH, Direction.EAST };
From ff1caff2626d258cdd4d4c8fa69a814eaa7a20b5 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 30 Oct 2023 15:17:20 +0100
Subject: [PATCH 14/23] WMP: Show only corresponding travel routes between
selected areas
Current area selection behavior:
- no selection: show all travel routes for all areas
- single selection: show all travel routes starting from the selected
area
- multi-selection: show corresponding travel routes between selected
areas
---
src/org/infinity/resource/wmp/ViewerMap.java | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/org/infinity/resource/wmp/ViewerMap.java b/src/org/infinity/resource/wmp/ViewerMap.java
index ac65775ae..7ba4e3c28 100644
--- a/src/org/infinity/resource/wmp/ViewerMap.java
+++ b/src/org/infinity/resource/wmp/ViewerMap.java
@@ -393,6 +393,23 @@ private void showMapDistances(int... areaIndices) {
int ofsLink = ofsLinkBase + (links[dir * 2] + dirIndex) * linkSize;
AreaLink destLink = (AreaLink) area.getAttribute(ofsLink, false);
+ // finding corresponding travel distances between selected areas
+ if (destLink != null && areaIndices.length > 1) {
+ final int destAreaIdx = ((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_TARGET_AREA)).getValue();
+ final AreaEntry destArea = getAreaEntry(destAreaIdx, false);
+ boolean found = false;
+ if (destArea != null) {
+ found = areaIndicesList
+ .stream()
+ .filter(idx -> curAreaIndex != idx && destArea.equals(getAreaEntry(idx, true)))
+ .findAny()
+ .isPresent();
+ }
+ if (!found) {
+ destLink = null;
+ }
+ }
+
if (destLink != null) {
int dstAreaIndex = ((IsNumeric) destLink.getAttribute(AreaLink.WMP_LINK_TARGET_AREA)).getValue();
Flag flag = (Flag) destLink.getAttribute(AreaLink.WMP_LINK_DEFAULT_ENTRANCE);
From 21e3ff3662765afa21245d54fb9150d3cb25a276 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 30 Oct 2023 17:54:43 +0100
Subject: [PATCH 15/23] Update GH action
---
.github/workflows/deploy.yml | 36 +++++++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 8877f1fe4..fb03d6f35 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -65,13 +65,32 @@ jobs:
- name: Echo JAVA_HOME (windows)
if: (matrix.os == 'windows-latest')
- run: echo $env:JAVA_HOME
+ run: |
+ echo $env:JAVA_HOME
+ java -version
- name: Echo JAVA_HOME (macos)
if: (matrix.os != 'windows-latest')
- run: echo $JAVA_HOME
+ run: |
+ echo $JAVA_HOME
+ java -version
# Preparations
+ - name: Download and install zip tool (windows)
+ if: (matrix.os == 'windows-latest')
+ run: |
+ $BaseDir=".\tools"
+ $UrlZip="http://downloads.sourceforge.net/gnuwin32/zip-3.0-bin.zip"
+ $PathZip="zip-3.0-bin.zip"
+ $UrlZipDep="http://downloads.sourceforge.net/gnuwin32/zip-3.0-dep.zip"
+ $PathZipDep="zip-3.0-dep.zip"
+ (New-Object System.Net.WebClient).DownloadFile($UrlZip, $PathZip)
+ (New-Object System.Net.WebClient).DownloadFile($UrlZipDep, $PathZipDep)
+ Expand-Archive -LiteralPath $PathZip -DestinationPath $BaseDir
+ Expand-Archive -LiteralPath $PathZipDep -DestinationPath $BaseDir
+ del $PathZip
+ del $PathZipDep
+
- name: Download JAR artifact
uses: actions/download-artifact@v3
with:
@@ -85,11 +104,15 @@ jobs:
path: assets
# Building
- - name: Build installer (windows)
+ - name: Build portable archive and installer (windows)
if: (matrix.os == 'windows-latest')
run: |
+ $BaseDir=".\tools"
+ $env:Path += ";$([IO.Path]::GetFullPath($BaseDir))\bin"
move assets\redistributable\windows\package .
+ move assets\redistributable\windows\build-image.cmd .
move assets\redistributable\windows\build-installer.cmd .
+ .\build-image.cmd
.\build-installer.cmd
- name: Build installer (macos)
@@ -110,6 +133,13 @@ jobs:
run: ls -l
# Uploading
+ - name: Upload portable artifact (windows)
+ if: (matrix.os == 'windows-latest')
+ uses: actions/upload-artifact@v3
+ with:
+ name: portable-windows
+ path: NearInfinity-*.zip
+
- name: Upload exe artifact (windows)
if: (matrix.os == 'windows-latest')
uses: actions/upload-artifact@v3
From 5577b93b47bcf1fa278c93ed03be523385c1d84b Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Tue, 31 Oct 2023 13:14:51 +0100
Subject: [PATCH 16/23] Update GH action
---
.github/workflows/deploy.yml | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index fb03d6f35..07fadba21 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -76,21 +76,6 @@ jobs:
java -version
# Preparations
- - name: Download and install zip tool (windows)
- if: (matrix.os == 'windows-latest')
- run: |
- $BaseDir=".\tools"
- $UrlZip="http://downloads.sourceforge.net/gnuwin32/zip-3.0-bin.zip"
- $PathZip="zip-3.0-bin.zip"
- $UrlZipDep="http://downloads.sourceforge.net/gnuwin32/zip-3.0-dep.zip"
- $PathZipDep="zip-3.0-dep.zip"
- (New-Object System.Net.WebClient).DownloadFile($UrlZip, $PathZip)
- (New-Object System.Net.WebClient).DownloadFile($UrlZipDep, $PathZipDep)
- Expand-Archive -LiteralPath $PathZip -DestinationPath $BaseDir
- Expand-Archive -LiteralPath $PathZipDep -DestinationPath $BaseDir
- del $PathZip
- del $PathZipDep
-
- name: Download JAR artifact
uses: actions/download-artifact@v3
with:
From 60c2c05520ee9cafb7c7b7ff6551ad041fffd84b Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Tue, 31 Oct 2023 19:45:42 +0100
Subject: [PATCH 17/23] Update GH action
---
.github/workflows/deploy.yml | 2 --
1 file changed, 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 07fadba21..fd85e7579 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -92,8 +92,6 @@ jobs:
- name: Build portable archive and installer (windows)
if: (matrix.os == 'windows-latest')
run: |
- $BaseDir=".\tools"
- $env:Path += ";$([IO.Path]::GetFullPath($BaseDir))\bin"
move assets\redistributable\windows\package .
move assets\redistributable\windows\build-image.cmd .
move assets\redistributable\windows\build-installer.cmd .
From 0ec3c89c87202f1d4b10a18c81d3e35424542a5e Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Wed, 1 Nov 2023 11:45:16 +0100
Subject: [PATCH 18/23] Auto-update indices in names of removable substructures
after add/insert/remove operations in structured resources
---
src/org/infinity/resource/AbstractStruct.java | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/src/org/infinity/resource/AbstractStruct.java b/src/org/infinity/resource/AbstractStruct.java
index f025e3462..920119d94 100644
--- a/src/org/infinity/resource/AbstractStruct.java
+++ b/src/org/infinity/resource/AbstractStruct.java
@@ -19,6 +19,8 @@
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.swing.JComponent;
@@ -588,6 +590,7 @@ public int addDatatype(AddRemovable addedEntry, int index) {
}
setStructChanged(true);
fireTableRowsInserted(index, index);
+ updateRemovableIndices(addedEntry.getClass());
return index;
}
@@ -947,6 +950,7 @@ public void removeDatatype(AddRemovable removedEntry, boolean removeRecurse) {
superStruct.datatypeRemovedInChild(this, removedEntry);
}
fireTableRowsDeleted(index, index);
+ updateRemovableIndices(removedEntry.getClass());
setStructChanged(true);
}
@@ -1047,6 +1051,52 @@ public void setStructChanged(boolean changed) {
}
}
+ /**
+ * Ensures that all {@link AddRemovable} of the specified type are properly indexed in sequential order.
+ *
+ * @param cls Class type of the AddRemovables to update.
+ */
+ public void updateRemovableIndices(Class extends AddRemovable> cls) {
+ if (cls == null) {
+ return;
+ }
+
+ final List fieldList = new ArrayList<>(getFields(cls));
+ if (fieldList.isEmpty()) {
+ return;
+ }
+ fieldList.sort((f1, f2) -> f1.getOffset() - f2.getOffset());
+
+ int minIndex = Integer.MAX_VALUE;
+ int maxIndex = Integer.MIN_VALUE;
+ final Pattern patName = Pattern.compile("^(.+) ([0-9]+)$");
+ for (int i = 0, size = fieldList.size(); i < size; i++) {
+ final StructEntry entry = fieldList.get(i);
+ final Matcher m = patName.matcher(entry.getName());
+ final String name;
+ if (m.matches()) {
+ // existing or copy-pasted entry
+ name = m.group(1);
+// System.out.printf("Existing/pasted: name=%s, newIndex=%d\n", entry.getName(), i);
+ } else {
+ // newly added entry
+ name = entry.getName();
+// System.out.printf("Newly added: name=%s, newIndex=%d\n", name, i);
+ }
+
+ final String newName = name + " " + i;
+ entry.setName(newName);
+
+ final int fieldIdx = fields.indexOf(entry);
+ minIndex = Math.min(minIndex, fieldIdx);
+ maxIndex = Math.max(maxIndex, fieldIdx);
+ }
+
+ if (minIndex != Integer.MAX_VALUE && maxIndex != Integer.MIN_VALUE) {
+ fireTableRowsUpdated(minIndex, maxIndex);
+ }
+ }
+
public String toMultiLineString() {
final StringBuilder sb = new StringBuilder(30 * fields.size());
for (final StructEntry e : fields) {
From 9bc14e20eba8dcabbfb0dc81dfac523cb0826994 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 6 Nov 2023 11:01:04 +0100
Subject: [PATCH 19/23] Added new game variant: IWD2EE
Includes:
- Specific game title
- LUA resource type support
- Updated executable to launch game
---
src/org/infinity/resource/Profile.java | 21 +++++++++++++++++--
.../infinity/resource/ResourceFactory.java | 9 ++++----
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/src/org/infinity/resource/Profile.java b/src/org/infinity/resource/Profile.java
index 809596f41..0a078e4e9 100644
--- a/src/org/infinity/resource/Profile.java
+++ b/src/org/infinity/resource/Profile.java
@@ -111,6 +111,8 @@ public enum Game {
IWDHowTotLM(Engine.IWD, "Icewind Dale: Trials of the Luremaster"),
/** Icewind Dale II */
IWD2(Engine.IWD2, "Icewind Dale II"),
+ /** Icewind Dale II: Enhanced Edition */
+ IWD2EE(Engine.IWD2, "Icewind Dale II: Enhanced Edition"),
/** Baldur's Gate: Enhanced Edition */
BG1EE(Engine.EE, "Baldur's Gate: Enhanced Edition"),
/** Baldur's Gate: Siege of Dragonspear */
@@ -512,6 +514,7 @@ public enum Key {
GAME_EXTRA_FOLDERS.put(Game.IWDHoW, new ArrayList<>(Arrays.asList(BG_EXTRA_FOLDERS)));
GAME_EXTRA_FOLDERS.put(Game.IWDHowTotLM, new ArrayList<>(Arrays.asList(BG_EXTRA_FOLDERS)));
GAME_EXTRA_FOLDERS.put(Game.IWD2, new ArrayList<>(Arrays.asList(BG_EXTRA_FOLDERS)));
+ GAME_EXTRA_FOLDERS.put(Game.IWD2EE, new ArrayList<>(Arrays.asList(BG_EXTRA_FOLDERS)));
GAME_EXTRA_FOLDERS.put(Game.BG1EE, new ArrayList<>(Arrays.asList(EE_EXTRA_FOLDERS)));
GAME_EXTRA_FOLDERS.put(Game.BG1SoD, new ArrayList<>(Arrays.asList(EE_EXTRA_FOLDERS)));
GAME_EXTRA_FOLDERS.put(Game.BG2EE, new ArrayList<>(Arrays.asList(EE_EXTRA_FOLDERS)));
@@ -533,6 +536,7 @@ public enum Key {
GAME_SAVE_FOLDERS.put(Game.IWDHoW, new ArrayList<>(Arrays.asList(BG_SAVE_FOLDERS)));
GAME_SAVE_FOLDERS.put(Game.IWDHowTotLM, new ArrayList<>(Arrays.asList(BG_SAVE_FOLDERS)));
GAME_SAVE_FOLDERS.put(Game.IWD2, new ArrayList<>(Arrays.asList(BG_SAVE_FOLDERS)));
+ GAME_SAVE_FOLDERS.put(Game.IWD2EE, new ArrayList<>(Arrays.asList(BG_SAVE_FOLDERS)));
GAME_SAVE_FOLDERS.put(Game.BG1EE, new ArrayList<>(Arrays.asList(EE_SAVE_FOLDERS)));
GAME_SAVE_FOLDERS.put(Game.BG1SoD, new ArrayList<>(Arrays.asList(EE_SAVE_FOLDERS)));
GAME_SAVE_FOLDERS.put(Game.BG2EE, new ArrayList<>(Arrays.asList(EE_SAVE_FOLDERS)));
@@ -1527,6 +1531,15 @@ private static void initDefaultGameBinaries() {
osMap.put(Platform.OS.WINDOWS, list);
DEFAULT_GAME_BINARIES.put(Game.IWD2, osMap);
+ // IWD2EE (Windows)
+ osMap = new EnumMap<>(Platform.OS.class);
+ osMap.put(Platform.OS.UNIX, emptyList);
+ osMap.put(Platform.OS.MAC_OS, emptyList);
+ list = new ArrayList<>();
+ list.add("iwd2ee.exe");
+ osMap.put(Platform.OS.WINDOWS, list);
+ DEFAULT_GAME_BINARIES.put(Game.IWD2EE, osMap);
+
// BG1EE (Linux, macOS, Windows)
osMap = new EnumMap<>(Platform.OS.class);
list = new ArrayList<>();
@@ -1828,7 +1841,9 @@ && getLuaValue(FileManager.query(gameRoots, "engine.lua"), "engine_mode", "0", f
if (ini != null && FileEx.create(ini).isFile()) {
addEntry(Key.GET_GAME_INI_FILE, Type.PATH, ini);
}
- } else if (game == Game.IWD2 || (FileEx.create(FileManager.query(gameRoots, "iwd2.exe")).isFile())
+ } else if (game == Game.IWD2 || game == Game.IWD2EE
+ || (FileEx.create(FileManager.query(gameRoots, "iwd2.exe")).isFile()
+ || FileEx.create(FileManager.query(gameRoots, "iwd2ee.exe")).isFile())
&& (FileEx.create(FileManager.query(gameRoots, "Data/Credits.mve")).isFile())) {
if (game == null) {
game = Game.IWD2;
@@ -1965,6 +1980,8 @@ && getLuaValue(FileManager.query(gameRoots, "engine.lua"), "engine_mode", "0", f
}
} else if (!isForced && game == Game.BG1 && ResourceFactory.resourceExists("DURLAG.MVE")) {
game = Game.BG1TotSC;
+ } else if (!isForced && game == Game.IWD2 && FileEx.create(FileManager.query(gameRoots, "IEex.dll")).isFile()) {
+ game = Game.IWD2EE;
}
// updating game type
@@ -2287,7 +2304,7 @@ private void initResourceTypes() {
addEntry(Key.IS_SUPPORTED_LOG, Type.BOOLEAN, true);
- addEntry(Key.IS_SUPPORTED_LUA, Type.BOOLEAN, isEnhancedEdition());
+ addEntry(Key.IS_SUPPORTED_LUA, Type.BOOLEAN, isEnhancedEdition() || game == Game.IWD2EE);
addEntry(Key.IS_SUPPORTED_MAZE, Type.BOOLEAN, game == Game.PSTEE);
diff --git a/src/org/infinity/resource/ResourceFactory.java b/src/org/infinity/resource/ResourceFactory.java
index c6d793c3a..eb9ae616e 100644
--- a/src/org/infinity/resource/ResourceFactory.java
+++ b/src/org/infinity/resource/ResourceFactory.java
@@ -164,10 +164,11 @@ public static Class extends Resource> getResourceType(ResourceEntry entry, Str
} else if (ext.equals("MUS")) {
cls = MusResource.class;
} else if (ext.equals("IDS") || ext.equals("2DA") || ext.equals("BIO") || ext.equals("RES") || ext.equals("TXT")
- || ext.equals("LOG") || // WeiDU log files
- (ext.equals("SRC") && Profile.getEngine() == Profile.Engine.IWD2)
- || (Profile.isEnhancedEdition() && (ext.equals("SQL") || ext.equals("GUI") || ext.equals("LUA")
- || ext.equals("MENU") || ext.equals("GLSL")))) {
+ || ext.equals("LOG") // WeiDU log files
+ || (ext.equals("SRC") && Profile.getEngine() == Profile.Engine.IWD2)
+ || (ext.equals("LUA") && (Profile.isEnhancedEdition() || Profile.getGame() == Profile.Game.IWD2EE))
+ || (Profile.isEnhancedEdition()
+ && (ext.equals("SQL") || ext.equals("GUI") || ext.equals("MENU") || ext.equals("GLSL")))) {
cls = PlainTextResource.class;
} else if (ext.equals("INI")) {
final boolean isPST = Profile.getEngine() == Profile.Engine.PST;
From 84a4e0f19ed063a3c271805e78c866dbc618e748 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sat, 18 Nov 2023 22:07:46 +0100
Subject: [PATCH 20/23] Remove "Nimbus" Look&Feel theme support
Fixes #169
This theme was already incomplete in Java 8 and appears to be completely
broken in later Java versions.
---
src/org/infinity/gui/PreferencesDialog.java | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java
index 547e5fc1c..256f45ac2 100644
--- a/src/org/infinity/gui/PreferencesDialog.java
+++ b/src/org/infinity/gui/PreferencesDialog.java
@@ -95,6 +95,14 @@
* that were formerly presented as individual entries in the "Options" menu.
*/
public class PreferencesDialog extends JDialog {
+ /**
+ * Blacklisted L&F themes: These themes should not be listed in the Preferences dialog.
+ *
+ * List contains the fully qualified class names of L&F themes.
+ *
+ */
+ private static final List LOOK_AND_FEEL_BLACKLIST = Arrays.asList("javax.swing.plaf.nimbus.NimbusLookAndFeel");
+
/** Definition of category names. */
public enum Category {
DEFAULT(""),
@@ -455,9 +463,7 @@ public String toString() {
OptionGroupBox.create(AppOption.LOOK_AND_FEEL_CLASS.getName(), AppOption.LOOK_AND_FEEL_CLASS.getLabel(),
"Choose a Look & Feel theme for the GUI."
+ "Metal is the default L&F theme and provides the most consistent user experience. "
- + "It is available on all platforms.
"
- + "Note: It is not recommended to use the \"Nimbus\" L&F theme. The theme "
- + "initializes an incomplete set of UI properties, which can result in display errors.
",
+ + "It is available on all platforms.
",
0, new DataItem>[0], AppOption.LOOK_AND_FEEL_CLASS)
.setOnInit(this::lookAndFeelClassOnInit).setOnAccept(this::lookAndFeelClassOnAccept),
OptionGroupBox.create(AppOption.TEXT_FONT.getName(), AppOption.TEXT_FONT.getLabel(),
@@ -1379,6 +1385,12 @@ private void lookAndFeelClassOnInit(OptionGroupBox gb) {
LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
for (int i = 0, curIdx = 0; i < info.length; i++) {
final LookAndFeelInfo lf = info[i];
+
+ // check if theme is black-listed
+ if (lf != null && LOOK_AND_FEEL_BLACKLIST.contains(lf.getClassName())) {
+ continue;
+ }
+
try {
// L&F description is only available from class instance
final Class> cls = Class.forName(lf.getClassName());
From dea0662c868a04cbb29e02da767208f00ea7a914 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Tue, 21 Nov 2023 20:16:30 +0100
Subject: [PATCH 21/23] Improve check for corrupted files: validate offset
field values
Triggered if offset points to static header data or outside of resource
data
---
src/org/infinity/check/StructChecker.java | 153 ++++++++++++++++++++--
1 file changed, 141 insertions(+), 12 deletions(-)
diff --git a/src/org/infinity/check/StructChecker.java b/src/org/infinity/check/StructChecker.java
index f740bea03..15abd7a2b 100644
--- a/src/org/infinity/check/StructChecker.java
+++ b/src/org/infinity/check/StructChecker.java
@@ -11,6 +11,7 @@
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -29,6 +30,7 @@
import org.infinity.datatype.IsNumeric;
import org.infinity.datatype.IsReference;
import org.infinity.datatype.IsTextual;
+import org.infinity.datatype.SectionOffset;
import org.infinity.datatype.StringRef;
import org.infinity.datatype.TextString;
import org.infinity.gui.Center;
@@ -39,12 +41,16 @@
import org.infinity.gui.menu.BrowserMenuBar;
import org.infinity.icon.Icons;
import org.infinity.resource.AbstractStruct;
+import org.infinity.resource.AddRemovable;
+import org.infinity.resource.Profile;
import org.infinity.resource.Resource;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.StructEntry;
+import org.infinity.resource.Viewable;
import org.infinity.resource.bcs.Compiler;
import org.infinity.resource.bcs.ScriptMessage;
import org.infinity.resource.bcs.ScriptType;
+import org.infinity.resource.cre.CreResource;
import org.infinity.resource.key.ResourceEntry;
import org.infinity.resource.sto.ItemSale11;
import org.infinity.resource.wed.Overlay;
@@ -99,14 +105,12 @@ public void actionPerformed(ActionEvent event) {
if (event.getSource() == bopen) {
int row = table.getSelectedRow();
if (row != -1) {
- ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- NearInfinity.getInstance().showResourceEntry(resourceEntry);
+ showInViewer((Corruption) table.getTableItemAt(row), false);
}
} else if (event.getSource() == bopennew) {
int row = table.getSelectedRow();
if (row != -1) {
- ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- new ViewFrame(resultFrame, ResourceFactory.getResource(resourceEntry));
+ showInViewer((Corruption) table.getTableItemAt(row), true);
}
} else if (event.getSource() == bsave) {
table.saveCheckResult(resultFrame, "Corrupted files");
@@ -170,10 +174,7 @@ public void mouseReleased(MouseEvent event) {
if (event.getClickCount() == 2) {
final int row = table.getSelectedRow();
if (row != -1) {
- final ResourceEntry resourceEntry = (ResourceEntry) table.getValueAt(row, 0);
- final Resource resource = ResourceFactory.getResource(resourceEntry);
- new ViewFrame(resultFrame, resource);
- ((AbstractStruct) resource).getViewer().selectEntry((String) table.getValueAt(row, 1));
+ showInViewer((Corruption) table.getTableItemAt(row), true);
}
}
}
@@ -260,6 +261,67 @@ private void search(ResourceEntry entry, AbstractStruct struct) {
}
}
+ // Checking for valid substructure offsets and counts
+ // calculating size of static portion of the resource data
+ final HashSet> removableSet = new HashSet<>();
+ int headerSize = 0;
+ if (Profile.hasProperty(Profile.Key.IS_SUPPORTED_CRE_V22) && entry.getExtension().equalsIgnoreCase("CRE")) {
+ // special: CRE V2.2 static size cannot be determined dynamically
+ final String version = ((TextString) struct.getAttribute(AbstractStruct.COMMON_VERSION)).getText();
+ if ("V2.2".equalsIgnoreCase(version)) {
+ headerSize = 0x62e;
+ }
+ }
+ if (headerSize == 0) {
+ for (final StructEntry field : struct.getFields()) {
+ if (field instanceof SectionOffset) {
+ final Class extends StructEntry> cls = ((SectionOffset) field).getSection();
+ removableSet.add(cls);
+ }
+ if (field instanceof AddRemovable || removableSet.contains(field.getClass())) {
+ headerSize = field.getOffset();
+ break;
+ } else {
+ headerSize = field.getOffset() + field.getSize();
+ }
+ }
+ }
+ removableSet.clear();
+
+ // CHR offset correction for embedded CRE data
+ int ofsOffset = 0;
+ if (entry.getExtension().equalsIgnoreCase("CHR")) {
+ final StructEntry se = struct.getAttribute(CreResource.CHR_SIGNATURE_2);
+ if (se != null) {
+ ofsOffset = se.getOffset();
+ }
+ }
+
+ // checking offsets
+ for (final StructEntry field : struct.getFields()) {
+ if (field.getOffset() >= headerSize) {
+ break;
+ }
+ if (field instanceof SectionOffset) {
+ final SectionOffset so = (SectionOffset) field;
+ if (so.getValue() + ofsOffset < headerSize) {
+ synchronized (table) {
+ table.addTableItem(new Corruption(entry, so.getOffset(),
+ "Offset field points to header data (field name: \"" + so.getName() + "\", offset: "
+ + Integer.toHexString(so.getValue()) + "h, header size: "
+ + Integer.toHexString(headerSize - ofsOffset) + "h)"));
+ }
+ } else if (so.getValue() + ofsOffset > struct.getSize()) {
+ synchronized (table) {
+ table.addTableItem(new Corruption(entry, so.getOffset(),
+ "Offset field value is out of range (field name: \"" + so.getName() + "\", offset: "
+ + Integer.toHexString(so.getValue()) + "h, resource size: "
+ + Integer.toHexString(struct.getSize() - ofsOffset) + "h)"));
+ }
+ }
+ }
+ }
+
// Type-specific checks
if (entry.getExtension().equalsIgnoreCase("WED")) {
List list = getWedCorruption(entry, struct);
@@ -415,16 +477,71 @@ private List getWedCorruption(ResourceEntry entry, AbstractStruct st
}
return list;
}
+
+ /**
+ * Opens a view of the referenced resources and selects the field at the offset in question.
+ *
+ * @param corruption {@link Corruption} instance with error information.
+ * @param newWindow Whether to open the resource in a new window.
+ */
+ private void showInViewer(Corruption corruption, boolean newWindow) {
+ if (corruption == null) {
+ return;
+ }
+
+ if (newWindow) {
+ final ResourceEntry entry = corruption.getResourceEntry();
+ final Resource res = ResourceFactory.getResource(entry);
+ final int offset = corruption.getOffset();
+ new ViewFrame(resultFrame, res);
+ if (res instanceof AbstractStruct) {
+ try {
+ ((AbstractStruct) res).getViewer().selectEntry(offset);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ final ResourceEntry entry = corruption.getResourceEntry();
+ final int offset = corruption.getOffset();
+ NearInfinity.getInstance().showResourceEntry(entry);
+ if (parent instanceof ViewFrame && parent.isVisible()) {
+ final Resource res = ResourceFactory.getResource(entry);
+ ((ViewFrame) parent).setViewable(res);
+ if (res instanceof AbstractStruct) {
+ try {
+ ((AbstractStruct) res).getViewer().selectEntry(offset);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ NearInfinity.getInstance().showResourceEntry(entry, () -> {
+ final Viewable viewable = NearInfinity.getInstance().getViewable();
+ if (viewable instanceof AbstractStruct) {
+ try {
+ ((AbstractStruct) viewable).getViewer().selectEntry(offset);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+ }
+
// -------------------------- INNER CLASSES --------------------------
private static final class Corruption implements TableItem {
private final ResourceEntry resourceEntry;
- private final String offset;
+ private final int offset;
+ private final String offsetString;
private final String errorMsg;
private Corruption(ResourceEntry resourceEntry, int offset, String errorMsg) {
this.resourceEntry = resourceEntry;
- this.offset = Integer.toHexString(offset) + 'h';
+ this.offset= offset;
+ this.offsetString = Integer.toHexString(offset) + 'h';
this.errorMsg = errorMsg;
}
@@ -433,15 +550,27 @@ public Object getObjectAt(int columnIndex) {
if (columnIndex == 0) {
return resourceEntry;
} else if (columnIndex == 1) {
- return offset;
+ return offsetString;
} else {
return errorMsg;
}
}
+ public ResourceEntry getResourceEntry() {
+ return resourceEntry;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public String getMessage() {
+ return errorMsg;
+ }
+
@Override
public String toString() {
- return "File: " + resourceEntry.getResourceName() + ", Offset: " + offset + ", Error: " + errorMsg;
+ return "File: " + resourceEntry.getResourceName() + ", Offset: " + offsetString + ", Error: " + errorMsg;
}
}
From 6d1380adbb0e708e503a2165964cfbb56dac9a51 Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Mon, 25 Dec 2023 20:41:48 +0100
Subject: [PATCH 22/23] Add option "Auto-align 2DA columns"
Automatically aligns table columns when a 2DA resource is opened.
Changes are discarded when resource is closed.
---
src/org/infinity/AppOption.java | 3 ++
src/org/infinity/gui/PreferencesDialog.java | 10 ++++
.../infinity/gui/menu/OptionsMenuItem.java | 31 +++++++++++
.../resource/text/PlainTextResource.java | 52 +++++++++++++++++--
4 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/src/org/infinity/AppOption.java b/src/org/infinity/AppOption.java
index c693eaaf9..16034647b 100644
--- a/src/org/infinity/AppOption.java
+++ b/src/org/infinity/AppOption.java
@@ -206,6 +206,9 @@ public class AppOption {
public static final AppOption BCS_INDENT = new AppOption(OptionsMenuItem.OPTION_BCS_INDENT, "Indentation", 1);
// Category: Misc. Types
+ /** Menu Options > Misc. Types: AutoAlign2da (Integer, Default: 0) */
+ public static final AppOption AUTO_ALIGN_2DA = new AppOption(OptionsMenuItem.OPTION_2DA_AUTOALIGN,
+ "Auto-Align 2DA Columns", 0);
/** Menu Options > Misc. Types: GlslColorScheme (Integer, Default: 0) */
public static final AppOption GLSL_COLOR_SCHEME = new AppOption(OptionsMenuItem.OPTION_GLSL_COLORSCHEME,
"GLSL Color Scheme", 0);
diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java
index 256f45ac2..4d7465c49 100644
--- a/src/org/infinity/gui/PreferencesDialog.java
+++ b/src/org/infinity/gui/PreferencesDialog.java
@@ -285,6 +285,16 @@ public String toString() {
)
),
OptionCategory.create(Category.MISC_RESOURCE_TYPES,
+ OptionGroup.create("2DA",
+ OptionGroupBox.create(AppOption.AUTO_ALIGN_2DA.getName(), AppOption.AUTO_ALIGN_2DA.getLabel(),
+ "Choose how to to automatically align 2DA table columns when the resource is opened."
+ + "Disabled: Table data is not modified.
"
+ + "Compact: Column widths are calculated individually.
"
+ + "Uniform: Column widths are calculated evenly (comparable to Weidu's PRETTY_PRINT_2DA.)"
+ + "
Note: Formatting is discarded when the resource is closed unless the changes "
+ + "are explicitly saved.
",
+ 0, OptionsMenuItem.AutoAlign2da.values(), AppOption.AUTO_ALIGN_2DA)
+ ),
OptionGroup.create("GLSL",
OptionGroupBox.create(AppOption.GLSL_COLOR_SCHEME.getName(), AppOption.GLSL_COLOR_SCHEME.getLabel(),
"Select a color scheme for GLSL resources."
diff --git a/src/org/infinity/gui/menu/OptionsMenuItem.java b/src/org/infinity/gui/menu/OptionsMenuItem.java
index 86604f6f8..9a31ef589 100644
--- a/src/org/infinity/gui/menu/OptionsMenuItem.java
+++ b/src/org/infinity/gui/menu/OptionsMenuItem.java
@@ -58,6 +58,28 @@
* Handles Option menu items for the {@link BrowserMenuBar}.
*/
public class OptionsMenuItem extends JMenuItem implements ActionListener {
+ /** Alignment types available for 2DA resources. */
+ public enum AutoAlign2da {
+ /** Do not align columns. */
+ DISABLED("Disabled"),
+ /** Align columns individually. */
+ COMPACT("Compact"),
+ /** Align columns evenly (comparable to WeiDU's PRETTY_PRINT_2DA). */
+ UNIFORM("Uniform"),
+ ;
+
+ private final String label;
+
+ private AutoAlign2da(String label) {
+ this.label = label;
+ }
+
+ @Override
+ public String toString() {
+ return label;
+ }
+ }
+
// Symbolic name for the default character set
private static final String DEFAULT_CHARSET = "Auto";
@@ -151,6 +173,7 @@ public class OptionsMenuItem extends JMenuItem implements ActionListener {
public static final String OPTION_BCS_CODEFOLDING = "BcsCodeFolding";
public static final String OPTION_BCS_AUTO_INDENT = "BcsAutoIndent";
public static final String OPTION_BCS_INDENT = "BcsIndent";
+ public static final String OPTION_2DA_AUTOALIGN = "AutoAlign2da";
public static final String OPTION_GLSL_SYNTAXHIGHLIGHTING = "GlslSyntaxHighlighting";
public static final String OPTION_GLSL_COLORSCHEME = "GlslColorScheme";
public static final String OPTION_GLSL_CODEFOLDING = "GlslCodeFolding";
@@ -648,6 +671,14 @@ public String getWeiDUColorScheme() {
return COLOR_SCHEME.get(idx).getPath();
}
+ public AutoAlign2da getAutoAlign2da() {
+ int idx = AppOption.AUTO_ALIGN_2DA.getIntValue();
+ if (idx >= 0 && idx < AutoAlign2da.values().length) {
+ return AutoAlign2da.values()[idx];
+ }
+ return AutoAlign2da.DISABLED;
+ }
+
/** Returns whether the dialog tree viewer shows icons in front of state and response entries. */
public boolean showDlgTreeIcons() {
return AppOption.DLG_SHOW_ICONS.getBoolValue();
diff --git a/src/org/infinity/resource/text/PlainTextResource.java b/src/org/infinity/resource/text/PlainTextResource.java
index 5b0f99c77..fbe77f4c9 100644
--- a/src/org/infinity/resource/text/PlainTextResource.java
+++ b/src/org/infinity/resource/text/PlainTextResource.java
@@ -137,6 +137,26 @@ public static String trimSpaces(String text, boolean trailing, boolean leading)
return retVal;
}
+ /**
+ * Aligns table columns individually.
+ *
+ * @param text The text content with table columns.
+ * @return The aligned text. Returns {@code null} if {@code text} argument is {@code null}.
+ */
+ public static String alignTableColumnsCompact(String text) {
+ return alignTableColumns(text, 2, true, 4);
+ }
+
+ /**
+ * Aligns all table columns evenly, comparable to WeiDU's PRETTY_PRINT_2DA.
+ *
+ * @param text The text content with table columns.
+ * @return The aligned text. Returns {@code null} if {@code text} argument is {@code null}.
+ */
+ public static String alignTableColumnsUniform(String text) {
+ return alignTableColumns(text, 1, false, 1);
+ }
+
/**
* Aligns table columns to improve readability.
*
@@ -329,7 +349,7 @@ public PlainTextResource(ResourceEntry entry) throws Exception {
buffer = StaticSimpleXorDecryptor.decrypt(buffer, 2);
}
final Charset cs = Misc.getCharsetFrom(BrowserMenuBar.getInstance().getOptions().getSelectedCharset());
- text = StreamUtils.readString(buffer, buffer.limit(), cs);
+ text = applyTransformText(StreamUtils.readString(buffer, buffer.limit(), cs));
}
// --------------------- Begin Interface ActionListener ---------------------
@@ -416,9 +436,9 @@ public void itemStateChanged(ItemEvent event) {
if (bpmFormat.getSelectedItem() == miFormatTrim) {
setText(trimSpaces(editor.getText(), true, false));
} else if (bpmFormat.getSelectedItem() == miFormatAlignCompact) {
- setText(alignTableColumns(editor.getText(), 2, true, 4));
+ setText(alignTableColumnsCompact(editor.getText()));
} else if (bpmFormat.getSelectedItem() == miFormatAlignUniform) {
- setText(alignTableColumns(editor.getText(), 1, false, 1));
+ setText(alignTableColumnsUniform(editor.getText()));
} else if (bpmFormat.getSelectedItem() == miFormatSort) {
setText(sortTable(editor.getText(), true, entry.getResourceRef().equalsIgnoreCase("TRIGGER")));
}
@@ -638,4 +658,30 @@ private void setSyntaxHighlightingEnabled(InfinityTextArea edit, InfinityScrollP
pane.applyExtendedSettings(language);
}
}
+
+ private String applyTransformText(String data) {
+ if (data == null) {
+ return data;
+ }
+
+ final String ext = (entry != null) ? entry.getExtension() : "";
+ if (ext.equals("2DA")) {
+ return applyAutoAlign2da(data);
+ }
+
+ return data;
+ }
+
+ private String applyAutoAlign2da(String data) {
+ switch (BrowserMenuBar.getInstance().getOptions().getAutoAlign2da()) {
+ case COMPACT:
+ return alignTableColumnsCompact(data);
+ case UNIFORM:
+ return alignTableColumnsUniform(data);
+ default:
+ }
+
+ return data;
+ }
+
}
From b1f75e628909eb0279c3a71f49d32021be528dae Mon Sep 17 00:00:00 2001
From: Argent77 <4519923+Argent77@users.noreply.github.com>
Date: Sun, 31 Dec 2023 11:26:46 +0100
Subject: [PATCH 23/23] Version 2.4-20231231
---
src/org/infinity/NearInfinity.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java
index 96ad70ec9..f6517e91f 100644
--- a/src/org/infinity/NearInfinity.java
+++ b/src/org/infinity/NearInfinity.java
@@ -136,7 +136,7 @@
public final class NearInfinity extends JFrame implements ActionListener, ViewableContainer {
// the current Near Infinity version
- private static final String VERSION = "v2.4-20230729";
+ private static final String VERSION = "v2.4-20231231";
// the minimum supported Java version
private static final int JAVA_VERSION_MIN = 8;