diff --git a/pom.xml b/pom.xml
index d1787bf..35fb2b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
us.deathmarine
luyten
- 0.5.4
+ 0.7.0
com.fifesoft
diff --git a/src/us/deathmarine/luyten/FindAllBox.java b/src/us/deathmarine/luyten/FindAllBox.java
index 92bb1e3..bf35849 100644
--- a/src/us/deathmarine/luyten/FindAllBox.java
+++ b/src/us/deathmarine/luyten/FindAllBox.java
@@ -65,11 +65,14 @@ public class FindAllBox extends JDialog {
private Thread tmp_thread;
+ private MainWindow mainWindow;
+
public FindAllBox(final MainWindow mainWindow) {
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
this.setHideOnEscapeButton();
progressBar = new JProgressBar(0, 100);
+ this.mainWindow = mainWindow;
JLabel label = new JLabel("Find What:");
textField = new JTextField();
@@ -99,7 +102,7 @@ public class FindAllBox extends JDialog {
String internalName = StringUtilities.removeRight(entryName, ".class");
TypeReference type = Model.metadataSystem.lookupType(internalName);
try {
- mainWindow.getModel().extractClassToTextPane(type, array[array.length - 1], entryName,
+ mainWindow.getSelectedModel().extractClassToTextPane(type, array[array.length - 1], entryName,
null);
} catch (Exception e) {
Luyten.showExceptionDialog("Exception!", e);
@@ -107,8 +110,8 @@ public class FindAllBox extends JDialog {
} else {
try {
- JarFile jfile = new JarFile(MainWindow.model.getOpenedFile());
- mainWindow.getModel().extractSimpleFileEntryToTextPane(
+ JarFile jfile = new JarFile(mainWindow.getSelectedModel().getOpenedFile());
+ mainWindow.getSelectedModel().extractSimpleFileEntryToTextPane(
jfile.getInputStream(jfile.getEntry(entryName)), array[array.length - 1],
entryName);
jfile.close();
@@ -196,7 +199,7 @@ public class FindAllBox extends JDialog {
classesList.clear();
ConfigSaver configSaver = ConfigSaver.getLoadedInstance();
DecompilerSettings settings = configSaver.getDecompilerSettings();
- File inFile = MainWindow.model.getOpenedFile();
+ File inFile = mainWindow.getSelectedModel().getOpenedFile();
boolean filter = ConfigSaver.getLoadedInstance().getLuytenPreferences()
.isFilterOutInnerClassEntries();
try {
diff --git a/src/us/deathmarine/luyten/FindBox.java b/src/us/deathmarine/luyten/FindBox.java
index d43dc8f..0c14256 100644
--- a/src/us/deathmarine/luyten/FindBox.java
+++ b/src/us/deathmarine/luyten/FindBox.java
@@ -54,7 +54,7 @@ public class FindBox extends JDialog {
JLabel label = new JLabel("Find What:");
textField = new JTextField();
- RSyntaxTextArea pane = mainWindow.getModel().getCurrentTextArea();
+ RSyntaxTextArea pane = mainWindow.getSelectedModel().getCurrentTextArea();
if (pane != null) {
textField.setText(pane.getSelectedText());
}
@@ -132,7 +132,7 @@ public class FindBox extends JDialog {
if (textField.getText().length() == 0)
return;
- RSyntaxTextArea pane = mainWindow.getModel().getCurrentTextArea();
+ RSyntaxTextArea pane = mainWindow.getSelectedModel().getCurrentTextArea();
if (pane == null)
return;
@@ -207,7 +207,7 @@ public class FindBox extends JDialog {
public void actionPerformed(ActionEvent e) {
if (textField.getText().length() == 0)
return;
- RSyntaxTextArea pane = mainWindow.getModel().getCurrentTextArea();
+ RSyntaxTextArea pane = mainWindow.getSelectedModel().getCurrentTextArea();
if (pane == null)
return;
SearchContext context = new SearchContext();
diff --git a/src/us/deathmarine/luyten/Luyten.java b/src/us/deathmarine/luyten/Luyten.java
index d8139d7..6c5bd7b 100644
--- a/src/us/deathmarine/luyten/Luyten.java
+++ b/src/us/deathmarine/luyten/Luyten.java
@@ -7,13 +7,11 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.io.StringWriter;
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
import java.net.URI;
+import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import java.util.List;
import java.util.ArrayList;
@@ -40,8 +38,20 @@ public class Luyten {
private static final AtomicReference mainWindowRef = new AtomicReference<>();
private static final List pendingFiles = new ArrayList<>();
+ private static ServerSocket lockSocket = null;
- public static void main(String[] args) {
+ public static void main(final String[] args) {
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (lockSocket != null) {
+ lockSocket.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+ }));
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
@@ -55,12 +65,41 @@ public class Luyten {
// .zip or .jar)
final File fileFromCommandLine = getFileFromCommandLine(args);
+ try {
+ launchMainInstance(fileFromCommandLine);
+ } catch (Exception e) {
+ // Instance already exists. Open new file in running instance
+ try {
+ Socket socket = new Socket("localhost", 3456);
+ DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
+ dos.writeUTF(args[0]);
+ dos.flush();
+ dos.close();
+ socket.close();
+ } catch (IOException ex) {
+ showExceptionDialog("Exception", e);
+ }
+ }
+ }
+
+ private static void launchMainInstance(final File fileFromCommandLine) throws IOException {
+ lockSocket = new ServerSocket(3456);
+ launchSession(fileFromCommandLine);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ launchServer();
+ }
+ }).start();
+ }
+
+ private static void launchSession(final File fileFromCommandLine) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (!mainWindowRef.compareAndSet(null, new MainWindow(fileFromCommandLine))) {
// Already set - so add the files to open
- openFileInInstance(fileFromCommandLine);
+ addToPendingFiles(fileFromCommandLine);
}
processPendingFiles();
mainWindowRef.get().setVisible(true);
@@ -68,14 +107,29 @@ public class Luyten {
});
}
+ private static void launchServer() {
+ try { // Server
+ while (true) {
+ Socket socket = lockSocket.accept();
+ DataInputStream dis = new DataInputStream(socket.getInputStream());
+ addToPendingFiles(getFileFromCommandLine(dis.readUTF()));
+ processPendingFiles();
+ dis.close();
+ socket.close();
+ }
+ } catch (IOException e) { // Client
+ showExceptionDialog("Exception", e);
+ }
+ }
+
// Private function which processes all pending files - synchronized on the
// list of pending files
- private static void processPendingFiles() {
+ public static void processPendingFiles() {
final MainWindow mainWindow = mainWindowRef.get();
if (mainWindow != null) {
synchronized (pendingFiles) {
for (File f : pendingFiles) {
- mainWindow.getModel().loadFile(f);
+ mainWindow.loadNewFile(f);
}
pendingFiles.clear();
}
@@ -84,13 +138,12 @@ public class Luyten {
// Function which opens the given file in the instance, if it's running -
// and if not, it processes the files
- public static void openFileInInstance(File fileToOpen) {
+ public static void addToPendingFiles(File fileToOpen) {
synchronized (pendingFiles) {
if (fileToOpen != null) {
pendingFiles.add(fileToOpen);
}
}
- processPendingFiles();
}
// Function which exits the application if it's running
@@ -101,7 +154,7 @@ public class Luyten {
}
}
- public static File getFileFromCommandLine(String[] args) {
+ public static File getFileFromCommandLine(String... args) {
File fileFromCommandLine = null;
try {
if (args.length > 0) {
diff --git a/src/us/deathmarine/luyten/LuytenOsx.java b/src/us/deathmarine/luyten/LuytenOsx.java
index 46670ae..3ba653d 100644
--- a/src/us/deathmarine/luyten/LuytenOsx.java
+++ b/src/us/deathmarine/luyten/LuytenOsx.java
@@ -16,7 +16,8 @@ public class LuytenOsx extends Luyten {
Application app = new Application();
app.addApplicationListener(new ApplicationAdapter() {
public void handleOpenFile(ApplicationEvent e) {
- Luyten.openFileInInstance(new File(e.getFilename()));
+ Luyten.addToPendingFiles(new File(e.getFilename()));
+ Luyten.processPendingFiles();
}
public void handleQuit(ApplicationEvent e) {
diff --git a/src/us/deathmarine/luyten/MainMenuBar.java b/src/us/deathmarine/luyten/MainMenuBar.java
index b9af8ba..bd108c7 100644
--- a/src/us/deathmarine/luyten/MainMenuBar.java
+++ b/src/us/deathmarine/luyten/MainMenuBar.java
@@ -167,7 +167,7 @@ public class MainMenuBar extends JMenuBar {
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- mainWindow.getModel().loadFile(file);
+ mainWindow.loadNewFile(file);
}
});
recentFiles.add(menuItem);
@@ -196,12 +196,12 @@ public class MainMenuBar extends JMenuBar {
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- JTabbedPane house = mainWindow.getModel().house;
+ JTabbedPane house = mainWindow.getSelectedModel().house;
if (e.getModifiers() != 2 || house.getTabCount() == 0)
mainWindow.onCloseFileMenu();
else {
- mainWindow.getModel().closeOpenTab(house.getSelectedIndex());
+ mainWindow.getSelectedModel().closeOpenTab(house.getSelectedIndex());
}
}
});
diff --git a/src/us/deathmarine/luyten/MainWindow.java b/src/us/deathmarine/luyten/MainWindow.java
index 68d27dc..ab89c04 100644
--- a/src/us/deathmarine/luyten/MainWindow.java
+++ b/src/us/deathmarine/luyten/MainWindow.java
@@ -15,20 +15,12 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.util.Iterator;
-import java.util.Vector;
+import java.util.*;
+import java.util.concurrent.Callable;
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.ImageIcon;
-import javax.swing.JComponent;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JProgressBar;
-import javax.swing.JSplitPane;
-import javax.swing.KeyStroke;
+import javax.swing.*;
import javax.swing.border.BevelBorder;
+import javax.swing.plaf.basic.BasicTabbedPaneUI;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
@@ -39,8 +31,8 @@ public class MainWindow extends JFrame {
private static final long serialVersionUID = 5265556630724988013L;
private static final String TITLE = "Luyten";
+ private static final String DEFAULT_TAB = "#DEFAULT";
- public static Model model;
private JProgressBar bar;
private JLabel label;
FindBox findBox;
@@ -50,13 +42,16 @@ public class MainWindow extends JFrame {
private LuytenPreferences luytenPrefs;
private FileDialog fileDialog;
private FileSaver fileSaver;
+ private JTabbedPane jarsTabbedPane;
+ private Map jarModels;
public MainMenuBar mainMenuBar;
public MainWindow(File fileFromCommandLine) {
configSaver = ConfigSaver.getLoadedInstance();
windowPosition = configSaver.getMainWindowPosition();
luytenPrefs = configSaver.getLuytenPreferences();
-
+
+ jarModels = new HashMap();
mainMenuBar = new MainMenuBar(this);
this.setJMenuBar(mainMenuBar);
@@ -84,8 +79,18 @@ public class MainWindow extends JFrame {
panel2.setPreferredSize(new Dimension(this.getWidth() / 3, 20));
panel2.add(bar);
- model = new Model(this);
- this.getContentPane().add(model);
+ jarsTabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
+ jarsTabbedPane.setUI(new BasicTabbedPaneUI() {
+ @Override
+ protected int calculateTabAreaHeight(int tab_placement, int run_count, int max_tab_height) {
+ if (jarsTabbedPane.indexOfTab(DEFAULT_TAB) == -1)
+ return super.calculateTabAreaHeight(tab_placement, run_count, max_tab_height);
+ else
+ return 0;
+ }
+ });
+ jarsTabbedPane.addTab(DEFAULT_TAB, new Model(this));
+ this.getContentPane().add(jarsTabbedPane);
JSplitPane spt = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panel1, panel2) {
private static final long serialVersionUID = 2189946972124687305L;
@@ -108,8 +113,9 @@ public class MainWindow extends JFrame {
spt.setBorder(new BevelBorder(BevelBorder.LOWERED));
spt.setPreferredSize(new Dimension(this.getWidth(), 24));
this.add(spt, BorderLayout.SOUTH);
+ Model jarModel = null;
if (fileFromCommandLine != null) {
- model.loadFile(fileFromCommandLine);
+ jarModel = loadNewFile(fileFromCommandLine);
}
try {
@@ -123,34 +129,80 @@ public class MainWindow extends JFrame {
fileDialog = new FileDialog(this);
fileSaver = new FileSaver(bar, label);
- this.setExitOnEscWhenEnabled(model);
+ if (jarModel != null) {
+ this.setExitOnEscWhenEnabled(jarModel);
+ }
- if (fileFromCommandLine == null || fileFromCommandLine.getName().toLowerCase().endsWith(".jar")
- || fileFromCommandLine.getName().toLowerCase().endsWith(".zip")) {
- model.startWarmUpThread();
+ if (jarModel != null && (fileFromCommandLine.getName().toLowerCase().endsWith(".jar")
+ || fileFromCommandLine.getName().toLowerCase().endsWith(".zip"))) {
+ jarModel.startWarmUpThread();
}
if(RecentFiles.load() > 0) mainMenuBar.updateRecentFiles();
}
+ private void createDefaultTab() {
+ jarsTabbedPane.addTab(DEFAULT_TAB, new Model(this));
+ }
+
+ private void removeDefaultTab() {
+ jarsTabbedPane.remove(jarsTabbedPane.indexOfTab(DEFAULT_TAB));
+ }
+
public void onOpenFileMenu() {
File selectedFile = fileDialog.doOpenDialog();
if (selectedFile != null) {
System.out.println("[Open]: Opening " + selectedFile.getAbsolutePath());
-
- this.getModel().loadFile(selectedFile);
+ this.loadNewFile(selectedFile);
}
}
+
+ public Model loadNewFile(final File file) {
+ // In case we open the same file again
+ // we remove the old entry to force a refresh
+ if (jarModels.containsKey(file.getAbsolutePath())) {
+ jarModels.remove(file.getAbsolutePath());
+ int index = jarsTabbedPane.indexOfTab(file.getName());
+ jarsTabbedPane.remove(index);
+ }
+
+ Model jarModel = new Model(this);
+ jarModel.loadFile(file);
+ jarModels.put(file.getAbsolutePath(), jarModel);
+ jarsTabbedPane.addTab(file.getName(), jarModel);
+ jarsTabbedPane.setSelectedComponent(jarModel);
+
+ final String tabName = file.getName();
+ int index = jarsTabbedPane.indexOfTab(tabName);
+ Model.Tab tabUI = new Model.Tab(tabName, new Callable() {
+ @Override
+ public Void call() {
+ int index = jarsTabbedPane.indexOfTab(tabName);
+ jarModels.remove(file.getAbsolutePath());
+ jarsTabbedPane.remove(index);
+ if (jarsTabbedPane.getTabCount() == 0) {
+ createDefaultTab();
+ }
+ return null;
+ }
+ });
+ jarsTabbedPane.setTabComponentAt(index, tabUI);
+ if (jarsTabbedPane.indexOfTab(DEFAULT_TAB) != -1 && jarsTabbedPane.getTabCount() > 1) {
+ removeDefaultTab();
+ }
+ return jarModel;
+ }
public void onCloseFileMenu() {
- this.getModel().closeFile();
+ this.getSelectedModel().closeFile();
+ jarModels.remove(getSelectedModel());
}
public void onSaveAsMenu() {
- RSyntaxTextArea pane = this.getModel().getCurrentTextArea();
+ RSyntaxTextArea pane = this.getSelectedModel().getCurrentTextArea();
if (pane == null)
return;
- String tabTitle = this.getModel().getCurrentTabTitle();
+ String tabTitle = this.getSelectedModel().getCurrentTabTitle();
if (tabTitle == null)
return;
@@ -162,7 +214,7 @@ public class MainWindow extends JFrame {
}
public void onSaveAllMenu() {
- File openedFile = this.getModel().getOpenedFile();
+ File openedFile = this.getSelectedModel().getOpenedFile();
if (openedFile == null)
return;
@@ -187,7 +239,7 @@ public class MainWindow extends JFrame {
public void onSelectAllMenu() {
try {
- RSyntaxTextArea pane = this.getModel().getCurrentTextArea();
+ RSyntaxTextArea pane = this.getSelectedModel().getCurrentTextArea();
if (pane != null) {
pane.requestFocusInWindow();
pane.setSelectionStart(0);
@@ -200,7 +252,7 @@ public class MainWindow extends JFrame {
public void onFindMenu() {
try {
- RSyntaxTextArea pane = this.getModel().getCurrentTextArea();
+ RSyntaxTextArea pane = this.getSelectedModel().getCurrentTextArea();
if (pane != null) {
if (findBox == null)
findBox = new FindBox(this);
@@ -229,7 +281,7 @@ public class MainWindow extends JFrame {
bar.setVisible(true);
bar.setIndeterminate(true);
String legalStr = getLegalStr();
- MainWindow.this.getModel().showLegal(legalStr);
+ getSelectedModel().showLegal(legalStr);
} finally {
bar.setIndeterminate(false);
bar.setVisible(false);
@@ -251,7 +303,7 @@ public class MainWindow extends JFrame {
}
myCL = myCL.getParent();
}
- MainWindow.this.getModel().show("Debug", sb.toString());
+ this.getSelectedModel().show("Debug", sb.toString());
} finally {
bar.setIndeterminate(false);
bar.setVisible(false);
@@ -295,21 +347,27 @@ public class MainWindow extends JFrame {
}
public void onThemesChanged() {
- this.getModel().changeTheme(luytenPrefs.getThemeXml());
- luytenPrefs.setFont_size(this.getModel().getTheme().baseFont.getSize());
+ for (Model jarModel : jarModels.values()) {
+ jarModel.changeTheme(luytenPrefs.getThemeXml());
+ luytenPrefs.setFont_size(jarModel.getTheme().baseFont.getSize());
+ }
}
public void onSettingsChanged() {
- this.getModel().updateOpenClasses();
+ for (Model jarModel : jarModels.values()) {
+ jarModel.updateOpenClasses();
+ }
}
public void onTreeSettingsChanged() {
- this.getModel().updateTree();
+ for (Model jarModel : jarModels.values()) {
+ jarModel.updateTree();
+ }
}
public void onFileDropped(File file) {
if (file != null) {
- this.getModel().loadFile(file);
+ this.loadNewFile(file);
}
}
@@ -326,7 +384,7 @@ public class MainWindow extends JFrame {
}
public void onNavigationRequest(String uniqueStr) {
- this.getModel().navigateTo(uniqueStr);
+ this.getSelectedModel().navigateTo(uniqueStr);
}
private void adjustWindowPositionBySavedState() {
@@ -426,8 +484,8 @@ public class MainWindow extends JFrame {
mainComponent.getActionMap().put("ESCAPE", escapeAction);
}
- public Model getModel() {
- return model;
+ public Model getSelectedModel() {
+ return (Model) jarsTabbedPane.getSelectedComponent();
}
public JProgressBar getBar() {
diff --git a/src/us/deathmarine/luyten/Model.java b/src/us/deathmarine/luyten/Model.java
index 2d0b802..2ecfb8e 100644
--- a/src/us/deathmarine/luyten/Model.java
+++ b/src/us/deathmarine/luyten/Model.java
@@ -5,12 +5,7 @@ import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
+import java.awt.event.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -28,6 +23,7 @@ import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.concurrent.Callable;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -213,8 +209,14 @@ public class Model extends JSplitPane {
house.addTab(title, rTextScrollPane);
index = house.indexOfComponent(rTextScrollPane);
house.setSelectedIndex(index);
- Tab ct = new Tab(title);
- ct.getButton().addMouseListener(new CloseTab(title));
+ Tab ct = new Tab(title, new Callable() {
+ @Override
+ public Void call() throws Exception {
+ int index = house.indexOfTab(title);
+ closeOpenTab(index);
+ return null;
+ }
+ });
house.setTabComponentAt(index, ct);
} else {
house.setSelectedIndex(index);
@@ -586,25 +588,28 @@ public class Model extends JSplitPane {
}
}
- private class Tab extends JPanel {
- private static final long serialVersionUID = -514663009333644974L;
+ public static class Tab extends JPanel {
+ private JLabel tabTitle;
private JLabel closeButton = new JLabel(new ImageIcon(
Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/resources/icon_close.png"))));
- private JLabel tabTitle = new JLabel();
- private String title = "";
- public Tab(String t) {
+ public Tab(String title, final Callable onCloseTabAction) {
super(new GridBagLayout());
this.setOpaque(false);
-
- this.title = t;
this.tabTitle = new JLabel(title);
-
this.createTab();
- }
-
- public JLabel getButton() {
- return this.closeButton;
+ closeButton.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ try {
+ if (onCloseTabAction != null) {
+ onCloseTabAction.call();
+ }
+ } catch (Exception ex) {
+ Luyten.showExceptionDialog("Exception!", ex);
+ }
+ }
+ });
}
public void createTab() {