From 65f5a34cfa385644dbb5a25213b390cdc06d5d8f Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Sat, 9 Aug 2025 10:47:52 +0000
Subject: [PATCH 1/8] This commit includes multiple improvements to the
project, including critical bug fixes and an expansion of the unit test
suite.
The key changes are:
1. **Fix Font Loading Bug:**
- Resolved a `FontFormatException` that occurred on startup by wrapping the font resource `InputStream` in a `BufferedInputStream` in `FontManager.java`.
- Added `FontManagerTest.java` to verify the fix and prevent future regressions.
2. **Add New Unit Tests for PackageManager:**
- Added a test to ensure an `IOException` is thrown when attempting to add a file that exceeds the maximum size limit.
- Added tests to verify that the `isModified` flag is correctly set after `updateAssetContent`, `updateAssetMeta`, and `removeDirectory` operations. This improves the reliability of the unsaved changes tracking.
3. **Refactor for Testability:**
- Refactored `PackageManager` to allow its max asset size limit to be configurable via a new constructor, making the size-limit logic testable without using reflection.
4. **Fix Checkstyle and Build Issues:**
- Addressed numerous checkstyle warnings throughout the codebase, including replacing wildcard imports, fixing naming conventions, and adding missing braces.
- Resolved several compilation and formatting errors that were discovered during the development process.
---
.../java/io/github/pixelclover/uview/App.java | 2 +-
.../uview/core/PackageManager.java | 32 ++++++---
.../uview/core/SettingsManager.java | 2 +-
.../uview/gui/AssetViewerFrame.java | 19 ++++--
.../uview/gui/AudioPlayerPanel.java | 16 ++++-
.../uview/gui/ButtonTabComponent.java | 14 +++-
.../uview/gui/FileTypeTreeCellRenderer.java | 4 +-
.../pixelclover/uview/gui/FontManager.java | 7 +-
.../pixelclover/uview/gui/IconManager.java | 2 +-
.../pixelclover/uview/gui/MainWindow.java | 60 ++++++++++++++---
.../uview/gui/MetaEditorFrame.java | 24 ++++---
.../uview/gui/PackageViewPanel.java | 22 ++++++-
.../pixelclover/uview/gui/PdfViewerPanel.java | 13 +++-
.../uview/gui/SyntaxTextPanel.java | 12 +++-
.../pixelclover/uview/io/PackageIO.java | 6 +-
.../uview/core/PackageManagerTest.java | 65 +++++++++++++++++++
.../uview/gui/FontManagerTest.java | 21 ++++++
test_assets/test_image.png | 1 +
test_assets/test_script.cs | 4 ++
19 files changed, 271 insertions(+), 55 deletions(-)
create mode 100644 src/test/java/io/github/pixelclover/uview/gui/FontManagerTest.java
create mode 100644 test_assets/test_image.png
create mode 100644 test_assets/test_script.cs
diff --git a/src/main/java/io/github/pixelclover/uview/App.java b/src/main/java/io/github/pixelclover/uview/App.java
index f736c6b..1bd772f 100644
--- a/src/main/java/io/github/pixelclover/uview/App.java
+++ b/src/main/java/io/github/pixelclover/uview/App.java
@@ -5,7 +5,7 @@
import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
import io.github.pixelclover.uview.gui.FontManager;
import io.github.pixelclover.uview.gui.MainWindow;
-import javax.swing.*;
+import javax.swing.SwingUtilities;
/** The main entry point for the UView application. */
public final class App {
diff --git a/src/main/java/io/github/pixelclover/uview/core/PackageManager.java b/src/main/java/io/github/pixelclover/uview/core/PackageManager.java
index 3ec02c2..0d0baf6 100644
--- a/src/main/java/io/github/pixelclover/uview/core/PackageManager.java
+++ b/src/main/java/io/github/pixelclover/uview/core/PackageManager.java
@@ -20,18 +20,30 @@
*/
public class PackageManager {
private static final Logger LOGGER = LogManager.getLogger(PackageManager.class);
- private static final long MAX_ASSET_SIZE_BYTES = 512 * 1024 * 1024; // 512 MB limit
- private final PackageIO packageIO;
+ private static final long DEFAULT_MAX_ASSET_SIZE_BYTES = 512 * 1024 * 1024; // 512 MB limit
+ private final PackageIO packageIo;
+ private final long maxAssetSizeBytes;
private UnityPackage activePackage = new UnityPackage();
private boolean isModified = false;
/**
- * Constructs a PackageManager with a given PackageIO handler.
+ * Constructs a PackageManager with a given PackageIO handler and default max asset size.
*
- * @param packageIO The I/O handler for reading and writing package files.
+ * @param packageIo The I/O handler for reading and writing package files.
*/
- public PackageManager(PackageIO packageIO) {
- this.packageIO = packageIO;
+ public PackageManager(PackageIO packageIo) {
+ this(packageIo, DEFAULT_MAX_ASSET_SIZE_BYTES);
+ }
+
+ /**
+ * Constructs a PackageManager with a given PackageIO handler and a custom max asset size.
+ *
+ * @param packageIo The I/O handler for reading and writing package files.
+ * @param maxAssetSizeBytes The maximum allowed size for an asset in bytes.
+ */
+ public PackageManager(PackageIO packageIo, long maxAssetSizeBytes) {
+ this.packageIo = packageIo;
+ this.maxAssetSizeBytes = maxAssetSizeBytes;
}
/** Creates a new, empty package, discarding any existing active package data. */
@@ -47,7 +59,7 @@ public void createNew() {
* @throws IOException If an error occurs during file loading.
*/
public void loadPackage(File packageFile) throws IOException {
- activePackage = packageIO.load(packageFile);
+ activePackage = packageIo.load(packageFile);
isModified = false;
LOGGER.info("Loaded package: {}", packageFile.getAbsolutePath());
}
@@ -59,7 +71,7 @@ public void loadPackage(File packageFile) throws IOException {
* @throws IOException If an error occurs during file saving.
*/
public void savePackage(File packageFile) throws IOException {
- packageIO.save(activePackage, packageFile);
+ packageIo.save(activePackage, packageFile);
isModified = false;
LOGGER.info("Saved package: {}", packageFile.getAbsolutePath());
}
@@ -110,11 +122,11 @@ public Collection getAssetsUnderPath(String pathPrefix) {
* @throws IOException If the file is too large or cannot be read.
*/
public void addAsset(Path sourceFile, String assetPath) throws IOException {
- if (Files.size(sourceFile) > MAX_ASSET_SIZE_BYTES) {
+ if (Files.size(sourceFile) > maxAssetSizeBytes) {
throw new IOException(
String.format(
"File is too large (%.1f MB). Maximum allowed size is %d MB.",
- Files.size(sourceFile) / (1024.0 * 1024.0), MAX_ASSET_SIZE_BYTES / (1024 * 1024)));
+ Files.size(sourceFile) / (1024.0 * 1024.0), maxAssetSizeBytes / (1024 * 1024)));
}
byte[] content = Files.readAllBytes(sourceFile);
String metaGuid = java.util.UUID.randomUUID().toString().replace("-", "");
diff --git a/src/main/java/io/github/pixelclover/uview/core/SettingsManager.java b/src/main/java/io/github/pixelclover/uview/core/SettingsManager.java
index 107eaa7..68a718e 100644
--- a/src/main/java/io/github/pixelclover/uview/core/SettingsManager.java
+++ b/src/main/java/io/github/pixelclover/uview/core/SettingsManager.java
@@ -1,7 +1,7 @@
package io.github.pixelclover.uview.core;
import io.github.pixelclover.uview.App;
-import java.awt.*;
+import java.awt.Font;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/main/java/io/github/pixelclover/uview/gui/AssetViewerFrame.java b/src/main/java/io/github/pixelclover/uview/gui/AssetViewerFrame.java
index 98dc3d2..27bce33 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/AssetViewerFrame.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/AssetViewerFrame.java
@@ -2,7 +2,10 @@
import io.github.pixelclover.uview.core.PackageManager;
import io.github.pixelclover.uview.model.UnityAsset;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Desktop;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
@@ -11,7 +14,16 @@
import java.nio.file.Files;
import java.text.DecimalFormat;
import java.util.Set;
-import javax.swing.*;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
/**
* A frame for viewing and potentially editing a single {@link UnityAsset}. It determines the
@@ -177,8 +189,6 @@ private JPanel createContentPanel(UnityAsset asset) {
}
private JPanel createTextEditorPanel(UnityAsset asset) {
- JPanel editorPanel = new JPanel(new BorderLayout(0, 5));
-
JButton saveButton = new JButton("Save");
saveButton.setEnabled(false);
JButton revertButton = new JButton("Revert");
@@ -206,6 +216,7 @@ private JPanel createTextEditorPanel(UnityAsset asset) {
buttonPanel.add(revertButton);
buttonPanel.add(saveButton);
+ JPanel editorPanel = new JPanel(new BorderLayout(0, 5));
editorPanel.add(syntaxTextPanel, BorderLayout.CENTER);
editorPanel.add(buttonPanel, BorderLayout.SOUTH);
diff --git a/src/main/java/io/github/pixelclover/uview/gui/AudioPlayerPanel.java b/src/main/java/io/github/pixelclover/uview/gui/AudioPlayerPanel.java
index aa65fa9..0fc3100 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/AudioPlayerPanel.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/AudioPlayerPanel.java
@@ -1,11 +1,21 @@
package io.github.pixelclover.uview.gui;
-import java.awt.*;
+import java.awt.FlowLayout;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import javax.sound.sampled.*;
-import javax.swing.*;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
/**
* A panel with simple controls to play an audio clip. It implements {@link LineListener} to react
diff --git a/src/main/java/io/github/pixelclover/uview/gui/ButtonTabComponent.java b/src/main/java/io/github/pixelclover/uview/gui/ButtonTabComponent.java
index 6b2f0a9..23513d5 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/ButtonTabComponent.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/ButtonTabComponent.java
@@ -1,11 +1,21 @@
package io.github.pixelclover.uview.gui;
-import java.awt.*;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
-import javax.swing.*;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicButtonUI;
/** A component to be used as a tab in a JTabbedPane. It contains a label and a close button. */
diff --git a/src/main/java/io/github/pixelclover/uview/gui/FileTypeTreeCellRenderer.java b/src/main/java/io/github/pixelclover/uview/gui/FileTypeTreeCellRenderer.java
index e40ab89..9cbc707 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/FileTypeTreeCellRenderer.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/FileTypeTreeCellRenderer.java
@@ -1,8 +1,8 @@
package io.github.pixelclover.uview.gui;
import io.github.pixelclover.uview.gui.tree.TreeEntry;
-import java.awt.*;
-import javax.swing.*;
+import java.awt.Component;
+import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
diff --git a/src/main/java/io/github/pixelclover/uview/gui/FontManager.java b/src/main/java/io/github/pixelclover/uview/gui/FontManager.java
index fd97cf9..4b9074a 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/FontManager.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/FontManager.java
@@ -1,6 +1,9 @@
package io.github.pixelclover.uview.gui;
-import java.awt.*;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.GraphicsEnvironment;
+import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.logging.log4j.LogManager;
@@ -29,7 +32,7 @@ public static void loadAndRegisterFonts() {
LOGGER.error("Custom font not found at resource path: {}", path);
continue;
}
- Font customFont = Font.createFont(Font.TRUETYPE_FONT, is);
+ Font customFont = Font.createFont(Font.TRUETYPE_FONT, new BufferedInputStream(is));
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(customFont);
LOGGER.info("Successfully registered font: {}", customFont.getFontName());
} catch (IOException | FontFormatException e) {
diff --git a/src/main/java/io/github/pixelclover/uview/gui/IconManager.java b/src/main/java/io/github/pixelclover/uview/gui/IconManager.java
index bc0c27a..d982880 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/IconManager.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/IconManager.java
@@ -3,7 +3,7 @@
import com.formdev.flatlaf.extras.FlatSVGIcon;
import java.util.HashMap;
import java.util.Map;
-import javax.swing.*;
+import javax.swing.Icon;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
diff --git a/src/main/java/io/github/pixelclover/uview/gui/MainWindow.java b/src/main/java/io/github/pixelclover/uview/gui/MainWindow.java
index 097268d..930e550 100644
--- a/src/main/java/io/github/pixelclover/uview/gui/MainWindow.java
+++ b/src/main/java/io/github/pixelclover/uview/gui/MainWindow.java
@@ -7,7 +7,12 @@
import io.github.pixelclover.uview.core.PackageManager;
import io.github.pixelclover.uview.core.SettingsManager;
import io.github.pixelclover.uview.model.UnityAsset;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Desktop;
+import java.awt.Dimension;
+import java.awt.Font;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.MouseAdapter;
@@ -18,10 +23,33 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
-import java.util.*;
+import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
-import javax.swing.*;
+import java.util.Map;
+import java.util.Properties;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.Icon;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JSeparator;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
import javax.swing.Timer;
+import javax.swing.TransferHandler;
+import javax.swing.UIManager;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.filechooser.FileNameExtensionFilter;
@@ -79,7 +107,9 @@ public void windowClosing(WindowEvent e) {
}
private static String formatSize(long bytes) {
- if (bytes < 1024) return bytes + " B";
+ if (bytes < 1024) {
+ return bytes + " B";
+ }
int exp = (int) (Math.log(bytes) / Math.log(1024));
char pre = "KMGTPE".charAt(exp - 1);
return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre);
@@ -241,7 +271,8 @@ public void menuCanceled(MenuEvent e) {}
settingsManager.resetUiSettings();
JOptionPane.showMessageDialog(
this,
- "UI settings have been reset.\nPlease restart the application for all changes to take effect.",
+ "UI settings have been reset.\nPlease restart the application for all changes to take"
+ + " effect.",
"Restart Required",
JOptionPane.INFORMATION_MESSAGE);
});
@@ -354,7 +385,8 @@ private void showAboutDialog() {
+ version
+ "
"
+ "A desktop tool for viewing and modifying Unity packages.
"
- + "GitHub: https://github.com/habedi/uview
"
+ + "GitHub: "
+ + "https://github.com/habedi/uview
"
+ "