Tabbed Windows

This gives the option to open all of the window dialogs as tabbed resources. The plugin writer and plugin console tab could be merged into a single pane at a later date. The error dialog might be over-kill and should remain an external window.

This is mostly an experiment for better UIs, because of this everything is optional and can be turned off within the configuration class
This commit is contained in:
Konloch 2021-07-23 15:12:53 -07:00
parent 582dccdb96
commit 15df6abfc9
9 changed files with 178 additions and 36 deletions

View file

@ -33,6 +33,13 @@ public class Configuration
//if true it will show a settings dialog on click instead of more menu items //if true it will show a settings dialog on click instead of more menu items
public static boolean useNewSettingsDialog = true; //TODO add to GUI public static boolean useNewSettingsDialog = true; //TODO add to GUI
//if true it will put force error UIs and console UIs to be added as a tab
public static boolean pluginConsoleAsNewTab = true; //TODO add to GUI
//if true it will put force error UIs and console UIs to be added as a tab
public static boolean errorLogsAsNewTab = true; //TODO add to GUI
//if true the plugin writer will open inside of a tab
public static boolean pluginWriterAsNewTab = true; //TODO add to GUI
public static boolean forceResourceUpdateFromClassNode = false; //TODO add to GUI public static boolean forceResourceUpdateFromClassNode = false; //TODO add to GUI
public static boolean showDarkLAFComponentIcons = false; public static boolean showDarkLAFComponentIcons = false;
public static boolean currentlyDumping = false; public static boolean currentlyDumping = false;

View file

@ -1,8 +1,6 @@
package the.bytecode.club.bytecodeviewer.api; package the.bytecode.club.bytecodeviewer.api;
import java.awt.CardLayout; import java.awt.*;
import java.awt.Color;
import java.awt.Dimension;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import javax.swing.JFrame; import javax.swing.JFrame;
@ -12,6 +10,7 @@ import javax.swing.JTextArea;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsole; import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsole;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ComponentViewer;
import the.bytecode.club.bytecodeviewer.resources.IconResources; import the.bytecode.club.bytecodeviewer.resources.IconResources;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
@ -46,6 +45,7 @@ public class ExceptionUI extends JFrameConsole
public static final String KONLOCH = "https://github.com/Konloch/bytecode-viewer/issues or Konloch at https://the.bytecode.club or konloch@gmail.com"; public static final String KONLOCH = "https://github.com/Konloch/bytecode-viewer/issues or Konloch at https://the.bytecode.club or konloch@gmail.com";
public static final String SEND_STACKTRACE_TO = buildErrorLogHeader(KONLOCH); public static final String SEND_STACKTRACE_TO = buildErrorLogHeader(KONLOCH);
public static final String SEND_STACKTRACE_TO_NL = SEND_STACKTRACE_TO + nl + nl; public static final String SEND_STACKTRACE_TO_NL = SEND_STACKTRACE_TO + nl + nl;
public static int errorCounter = 1;
/** /**
* @param e The exception to be shown * @param e The exception to be shown
@ -105,7 +105,7 @@ public class ExceptionUI extends JFrameConsole
*/ */
private void setupFrame(String error, String author) private void setupFrame(String error, String author)
{ {
this.setIconImages(IconResources.iconList); setIconImages(IconResources.iconList);
setSize(new Dimension(600, 400)); setSize(new Dimension(600, 400));
setTitle("Bytecode Viewer " + VERSION + " - Error Log - Send this to " + author); setTitle("Bytecode Viewer " + VERSION + " - Error Log - Send this to " + author);
getContentPane().setLayout(new CardLayout(0, 0)); getContentPane().setLayout(new CardLayout(0, 0));
@ -113,8 +113,17 @@ public class ExceptionUI extends JFrameConsole
getTextArea().setText(buildErrorLogHeader(author) + nl + nl + error); getTextArea().setText(buildErrorLogHeader(author) + nl + nl + error);
getTextArea().setCaretPosition(0); getTextArea().setCaretPosition(0);
this.setLocationRelativeTo(BytecodeViewer.viewer); //embed error log as a new tab
this.setVisible(true); if(Configuration.errorLogsAsNewTab)
{
ComponentViewer.addComponentAsTab("Error #" + errorCounter++, getComponent(0));
}
//pop open a new window frame
else
{
setLocationRelativeTo(BytecodeViewer.viewer);
setVisible(true);
}
} }
/** /**

View file

@ -1,5 +1,6 @@
package the.bytecode.club.bytecodeviewer.api; package the.bytecode.club.bytecodeviewer.api;
import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole; import the.bytecode.club.bytecodeviewer.gui.components.SystemConsole;
import the.bytecode.club.bytecodeviewer.plugin.PluginManager; import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
@ -35,7 +36,7 @@ public class PluginConsole extends SystemConsole
public PluginConsole(String pluginName) public PluginConsole(String pluginName)
{ {
super(TranslatedStrings.PLUGIN_CONSOLE_TITLE + " - " + pluginName); super(Configuration.pluginConsoleAsNewTab ? (pluginName + " Output") : (TranslatedStrings.PLUGIN_CONSOLE_TITLE + " - " + pluginName));
PluginManager.addConsole(this); PluginManager.addConsole(this);
} }

View file

@ -187,32 +187,7 @@ public class Workspace extends TranslatedVisibleComponent
//create a new tab if the resource isn't opened currently //create a new tab if the resource isn't opened currently
if (!openedTabs.contains(workingName)) if (!openedTabs.contains(workingName))
{ {
//start processing the resource to be viewed addResourceToTab(resourceView, workingName, container.name, name);
if(resourceView instanceof ClassViewer)
resourceView.refresh(null);
//add the resource view to the tabs
tabs.add(resourceView);
//get the resource view index
final int tabIndex = tabs.indexOfComponent(resourceView);
//create a new tabbed pane
TabbedPane tabbedPane = new TabbedPane(tabIndex, workingName, container.name, name, tabs, resourceView);
resourceView.tabbedPane = tabbedPane;
resourceView.resource.workingName = workingName;
//set the tabs index
tabs.setTabComponentAt(tabIndex, tabbedPane);
//open the tab that was just added
tabs.setSelectedIndex(tabIndex);
//set resource as opened in a tab
openedTabs.add(workingName);
//refresh the tab title
resourceView.refreshTitle();
} }
else //if the resource is already opened select this tab as the active one else //if the resource is already opened select this tab as the active one
{ {
@ -231,6 +206,36 @@ public class Workspace extends TranslatedVisibleComponent
} }
} }
} }
public void addResourceToTab(ResourceViewer resourceView, String workingName, String containerName, String name)
{
//start processing the resource to be viewed
if(resourceView instanceof ClassViewer)
resourceView.refresh(null);
//add the resource view to the tabs
tabs.add(resourceView);
//get the resource view index
final int tabIndex = tabs.indexOfComponent(resourceView);
//create a new tabbed pane
TabbedPane tabbedPane = new TabbedPane(tabIndex, workingName, containerName, name, tabs, resourceView);
resourceView.tabbedPane = tabbedPane;
resourceView.resource.workingName = workingName;
//set the tabs index
tabs.setTabComponentAt(tabIndex, tabbedPane);
//open the tab that was just added
tabs.setSelectedIndex(tabIndex);
//set resource as opened in a tab
openedTabs.add(workingName);
//refresh the tab title
resourceView.refreshTitle();
}
public ResourceViewer getActiveResource() { public ResourceViewer getActiveResource() {
return (ResourceViewer) tabs.getSelectedComponent(); return (ResourceViewer) tabs.getSelectedComponent();

View file

@ -0,0 +1,64 @@
package the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.resources.Resource;
import javax.swing.*;
import java.awt.*;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* This represents a component opened as a tab
*
* @author Konloch
* @since 7/23/2021
*/
public class ComponentViewer extends ResourceViewer
{
private Component component;
private static final String containerName = "internalComponent.";
public ComponentViewer(String title, Component component)
{
super(new Resource(title, containerName + title, null));
this.component = component;
setLayout(new BorderLayout());
setName(title);
add(component, BorderLayout.CENTER);
}
public static ComponentViewer addComponentAsTab(String title, Component c)
{
String workingName = containerName + title;
ComponentViewer componentViewer = new ComponentViewer(title, c);
BytecodeViewer.viewer.workPane.addResourceToTab(componentViewer,
workingName, containerName, title);
return componentViewer;
}
@Override
public void refresh(JButton button) {
//TODO add a refresh event so the component can be updated
}
}

View file

@ -41,7 +41,7 @@ import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage;
***************************************************************************/ ***************************************************************************/
/** /**
* Represents any open non-class file. * Represents any open non-class file inside of a tab.
* *
* @author Konloch * @author Konloch
*/ */

View file

@ -26,7 +26,7 @@ import the.bytecode.club.bytecodeviewer.util.MiscUtils;
***************************************************************************/ ***************************************************************************/
/** /**
* A ResourceViewer * Represents an opened tab
* *
* @author Konloch * @author Konloch
*/ */

View file

@ -1,12 +1,16 @@
package the.bytecode.club.bytecodeviewer.plugin; package the.bytecode.club.bytecodeviewer.plugin;
import java.awt.*;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
import java.util.List;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.api.Plugin; import the.bytecode.club.bytecodeviewer.api.Plugin;
import the.bytecode.club.bytecodeviewer.api.PluginConsole; import the.bytecode.club.bytecodeviewer.api.PluginConsole;
import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsoleTabbed; import the.bytecode.club.bytecodeviewer.gui.components.JFrameConsoleTabbed;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ComponentViewer;
import the.bytecode.club.bytecodeviewer.plugin.strategies.*; import the.bytecode.club.bytecodeviewer.plugin.strategies.*;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.util.MiscUtils; import the.bytecode.club.bytecodeviewer.util.MiscUtils;
@ -128,7 +132,11 @@ public final class PluginManager
if(activeTabbedConsole == null) if(activeTabbedConsole == null)
{ {
activeTabbedConsole = new JFrameConsoleTabbed(console.getTitle()); activeTabbedConsole = new JFrameConsoleTabbed(console.getTitle());
activeTabbedConsole.setVisible(true);
if(Configuration.pluginConsoleAsNewTab)
ComponentViewer.addComponentAsTab(console.getTitle(), activeTabbedConsole.getComponent(0));
else
activeTabbedConsole.setVisible(true);
} }
console.setConsoleID(id); console.setConsoleID(id);

View file

@ -5,6 +5,8 @@ import me.konloch.kontainer.io.DiskWriter;
import org.apache.commons.compress.utils.FileNameUtils; import org.apache.commons.compress.utils.FileNameUtils;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Configuration; import the.bytecode.club.bytecodeviewer.Configuration;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ComponentViewer;
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
import the.bytecode.club.bytecodeviewer.resources.IconResources; import the.bytecode.club.bytecodeviewer.resources.IconResources;
import the.bytecode.club.bytecodeviewer.gui.components.FileChooser; import the.bytecode.club.bytecodeviewer.gui.components.FileChooser;
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea; import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
@ -24,10 +26,29 @@ import static the.bytecode.club.bytecodeviewer.Constants.fs;
import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory; import static the.bytecode.club.bytecodeviewer.Constants.tempDirectory;
import static the.bytecode.club.bytecodeviewer.Settings.addRecentPlugin; import static the.bytecode.club.bytecodeviewer.Settings.addRecentPlugin;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/** /**
* @author Konloch * @author Konloch
* @since 7/1/2021 * @since 7/1/2021
*/ */
public class PluginWriter extends JFrame public class PluginWriter extends JFrame
{ {
private SearchableRSyntaxTextArea area; private SearchableRSyntaxTextArea area;
@ -93,6 +114,33 @@ public class PluginWriter extends JFrame
this.setLocationRelativeTo(null); this.setLocationRelativeTo(null);
} }
@Override
public void setVisible(boolean b)
{
if(Configuration.pluginWriterAsNewTab)
{
Component component = getComponent(0);
JPanel p = new JPanel(new BorderLayout());
JPanel p2 = new JPanel(new BorderLayout());
p.add(p2, BorderLayout.NORTH);
p.add(component, BorderLayout.CENTER);
if(Configuration.lafTheme == LAFTheme.SYSTEM)
p2.add(getJMenuBar(), BorderLayout.CENTER);
else //TODO DarkLAF wont display the jMenuBar due to how it handles them, instead display the menu
//TODO make the menu interactable and display the menu manually
p2.add(getJMenuBar().getMenu(0), BorderLayout.CENTER);
ComponentViewer.addComponentAsTab(pluginName, p);
}
else
{
super.setVisible(b);
}
}
public void setPluginName(String name) public void setPluginName(String name)
{ {
this.pluginName = name; this.pluginName = name;