Files
2026-07-04 20:24:40 +02:00

317 lines
8.7 KiB
C#
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using EonaCat.Editor.Language.Highlighting;
using EonaCat.Editor.Language.Highlighting.Eeh;
using Microsoft.Win32;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Xml;
namespace EonaCat.JavaDecompile;
public partial class MainWindow : Window
{
string? jarPath;
bool maximized;
List<TreeViewItem>? OriginalTree;
public MainWindow()
{
InitializeComponent();
LoadIcons();
LoadCustomJavaTheme();
Loaded += AnimateIntro;
}
void AnimateIntro(object s, RoutedEventArgs e)
{
var a = new DoubleAnimation(0, 1, new Duration(System.TimeSpan.FromSeconds(0.6)));
BeginAnimation(OpacityProperty, a);
}
void LoadIcons()
{
string basePath = Path.Combine(AppContext.BaseDirectory, "assets", "external", "icons");
void SetIcon(Image img, string file)
{
var p = Path.Combine(basePath, file);
if (File.Exists(p))
{
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.UriSource = new System.Uri(p, System.UriKind.Absolute);
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
img.Source = bmp;
}
}
SetIcon(IconLogo, "icon.png");
SetIcon(IconFile, "extension.png");
//SetIcon(IconCode, "code_page.png");
SetIcon(IconFilter, "filter.png");
//SetIcon(IconFull, "full.png");
//SetIcon(IconClose, "close.png");
}
void LoadCustomJavaTheme()
{
var theme = Path.Combine(AppContext.BaseDirectory, "assets", "external", "themes", "EonaCat.JavaDecompile.eeh");
if (!File.Exists(theme))
{
return;
}
using var reader = XmlReader.Create(theme);
var definition = HighlightsLoader.Load(reader, HighlightsManager.Instance);
HighlightsManager.Instance.RegisterHighlights("EonaCat.JavaDecompile", new[] { ".java" }, definition);
CodeViewer.SyntaxHighlights = definition;
}
void OpenJarClick(object s, RoutedEventArgs e)
{
var d = new OpenFileDialog { Filter = "JARfiles(*.jar)|*.jar" };
if (d.ShowDialog() == true)
{
jarPath = d.FileName;
LoadJar(jarPath);
}
}
void LoadJar(string path)
{
JarTree.Items.Clear();
OriginalTree = JarProcessor.ExtractStructure(path);
foreach (var item in OriginalTree)
{
JarTree.Items.Add(item);
}
EmptyState.Visibility = Visibility.Collapsed;
}
void FilterBox_TextChanged(object s, TextChangedEventArgs e)
{
if (OriginalTree == null)
{
return;
}
string query = FilterBox.Text.Trim().ToLower();
JarTree.Items.Clear();
if (string.IsNullOrEmpty(query))
{
foreach (var node in OriginalTree)
{
JarTree.Items.Add(node);
}
return;
}
var filtered = new List<TreeViewItem>();
foreach (var node in OriginalTree)
{
var result = FilterTree(node, query);
if (result != null)
{
filtered.Add(result);
}
}
foreach (var n in filtered)
{
JarTree.Items.Add(n);
}
}
TreeViewItem? FilterTree(TreeViewItem node, string query)
{
bool match = node.Header.ToString()!.ToLower().Contains(query);
var matches = new List<TreeViewItem>();
foreach (TreeViewItem child in node.Items)
{
var res = FilterTree(child, query);
if (res != null)
{
matches.Add(res);
}
}
if (match || matches.Count > 0)
{
var clone = new TreeViewItem { Header = node.Header, Tag = node.Tag };
foreach (var m in matches)
{
clone.Items.Add(m);
}
return clone;
}
return null;
}
void JarTree_SelectedItemChanged(object s, RoutedPropertyChangedEventArgs<object> e)
{
if (jarPath == null)
{
return;
}
if (e.NewValue is not TreeViewItem item)
{
return;
}
if (item.Tag is not string entryPath || string.IsNullOrWhiteSpace(entryPath))
{
return;
}
string ext = System.IO.Path.GetExtension(entryPath).ToLower();
if (ext == ".class")
{
ShowCode(JarProcessor.DecompileClass(jarPath, entryPath));
return;
}
if (JarProcessor.IsImage(entryPath))
{
var img = JarProcessor.ExtractImage(jarPath, entryPath);
if (img != null)
{
ShowImage(img);
}
else
{
ShowCode("// Image could not be loaded");
}
return;
}
if (ext == ".jar")
{
if (item.Items.Count == 0)
{
var sub = JarProcessor.ExtractStructureFromInnerJar(jarPath, entryPath);
if (sub != null)
{
foreach (var node in sub)
{
item.Items.Add(node);
}
item.IsExpanded = true;
}
else
{
ShowCode("// Could not open inner JAR");
}
}
return;
}
ShowCode(JarProcessor.ReadTextFromJar(jarPath, entryPath));
}
void ShowCode(string text)
{
ImageViewer.Visibility = Visibility.Collapsed;
CodeViewer.Visibility = Visibility.Visible;
CodeViewer.ApplyTemplate();
CodeViewer.Text = text;
CodeViewer.ScrollToHome();
// Run post-layout work at Loaded priority so the control is measured/arranged.
CodeViewer.Dispatcher.BeginInvoke(new Action(() => {
try {
var ta = CodeViewer.TextArea;
if (ta != null) {
var tv = ta.TextView;
if (tv != null) {
try {
tv.EnsureVisualLines();
} catch (Exception ex) { Debug.WriteLine("EnsureVisualLines scheduled failed: " + ex.Message); }
}
}
} catch (Exception ex) { Debug.WriteLine("ShowCode scheduled work failed: " + ex.Message); }
}), System.Windows.Threading.DispatcherPriority.Loaded);
}
void ShowImage(BitmapImage? img)
{
if (img == null)
{
return;
}
CodeViewer.Visibility = Visibility.Collapsed;
ImageViewer.Visibility = Visibility.Visible;
ImageViewer.Source = img;
}
void DragWindow(object s, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
DragMove();
}
}
void ToggleMaximize(object s, RoutedEventArgs e)
{
double targetScale = maximized ? 1.0 : 1.04;
var scale = new System.Windows.Media.ScaleTransform(1, 1);
Root.RenderTransformOrigin = new Point(0.5, 0.5);
Root.RenderTransform = scale;
var anim = new DoubleAnimation(targetScale, new Duration(System.TimeSpan.FromMilliseconds(300)))
{
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut },
AutoReverse = true
};
scale.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleXProperty, anim);
scale.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleYProperty, anim);
if (maximized)
{
WindowState = WindowState.Normal;
Root.Margin = new Thickness(0);
maximized = false;
}
else
{
WindowState = WindowState.Maximized;
Root.Margin = new Thickness(6);
maximized = true;
}
}
void CloseApp(object s, RoutedEventArgs e) => Close();
void OnDropJar(object s, DragEventArgs e)
{
if (!e.Data.GetDataPresent(DataFormats.FileDrop))
{
return;
}
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
var jar = files.FirstOrDefault(f => f.EndsWith(".jar"));
if (jar == null)
{
return;
}
jarPath = jar;
LoadJar(jarPath);
}
void OnPreviewDragOver(object s, DragEventArgs e)
{
e.Handled = true;
e.Effects = DragDropEffects.Copy;
}
}