Initial version
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
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 = "JAR files (*.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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user