JFrameView.java
/*******************************************************************************
* Copyhacked (H) 2012-2020.
* This program and the accompanying materials
* are made available under no term at all, use it like
* you want, but share and discuss about it
* every time possible with every body.
*
* Contributors:
* ron190 at ymail dot com - initial implementation
******************************************************************************/
package com.jsql.view.swing;
import com.jsql.model.InjectionModel;
import com.jsql.util.I18nUtil;
import com.jsql.view.interaction.SubscriberInteraction;
import com.jsql.view.swing.action.HotkeyUtil;
import com.jsql.view.swing.menubar.Menubar;
import com.jsql.view.swing.panel.PanelAddressBar;
import com.jsql.view.swing.panel.split.SplitHorizontalTopBottom;
import com.jsql.view.swing.shadow.ShadowPopupFactory;
import com.jsql.view.swing.shell.AbstractShell;
import com.jsql.view.swing.tab.TabManagers;
import com.jsql.view.swing.util.MediatorHelper;
import com.jsql.view.swing.util.UiUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.prefs.Preferences;
import java.util.stream.Stream;
/**
* View in the MVC pattern, defines all the components
* and process actions sent by the model.<br>
* Main groups of components:<br>
* - at the top: textfield inputs,<br>
* - at the center: tree on the left, table on the right,<br>
* - at the bottom: information labels.
*/
public class JFrameView extends JFrame {
// Main center panel
private SplitHorizontalTopBottom splitHorizontalTopBottom;
// List of terminal by unique identifier
private final Map<UUID, AbstractShell> mapShells = new HashMap<>();
private final transient SubscriberInteraction subscriber = new SubscriberInteraction("com.jsql.view.swing.interaction");
// Build the GUI: add app icon, tree icons, the 3 main panels
public JFrameView() {
super("jSQL Injection");
MediatorHelper.register(this);
// Load UI before any component
UiUtil.prepareGUI();
ShadowPopupFactory.install();
this.initializePaneComponents();
this.initializeWindow();
this.initializeShortcuts();
}
private void initializeWindow() {
// Define a small and large app icon
this.setIconImages(UiUtil.getIcons());
this.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent event) {
super.windowOpened(event);
var preferences = Preferences.userRoot().node(InjectionModel.class.getName());
var horizontalTopBottomSplitter = preferences.getDouble(SplitHorizontalTopBottom.getNameHSplitpane(), 0.75);
if (!(0.0 <= horizontalTopBottomSplitter && horizontalTopBottomSplitter <= 1.0)) {
horizontalTopBottomSplitter = 0.75;
}
JFrameView.this.splitHorizontalTopBottom.setDividerLocation(horizontalTopBottomSplitter);
}
@Override
public void windowClosing(WindowEvent e) {
var preferences = Preferences.userRoot().node(InjectionModel.class.getName());
preferences.putInt(
SplitHorizontalTopBottom.getNameVSplitpane(),
JFrameView.this.splitHorizontalTopBottom.getSplitVerticalLeftRight().getDividerLocation()
);
var roundDecimal = BigDecimal.valueOf(
JFrameView.this.splitHorizontalTopBottom.getDividerLocation() * 100.0
/ JFrameView.this.splitHorizontalTopBottom.getHeight()
/ 100
);
roundDecimal = roundDecimal.setScale(2, RoundingMode.HALF_UP);
// Divider location change when window is maximized, we can't save getDividerLocation()
preferences.putDouble(
SplitHorizontalTopBottom.getNameHSplitpane(),
// Fix scale
roundDecimal.doubleValue() - 0.01
);
preferences.putBoolean(UiUtil.BINARY_VISIBLE, false);
preferences.putBoolean(UiUtil.CHUNK_VISIBLE, false);
preferences.putBoolean(UiUtil.NETWORK_VISIBLE, false);
preferences.putBoolean(UiUtil.JAVA_VISIBLE, false);
for (var i = 0 ; i < MediatorHelper.tabConsoles().getTabCount() ; i++) {
if ("CONSOLE_BINARY_LABEL".equals(MediatorHelper.tabConsoles().getTabComponentAt(i).getName())) {
preferences.putBoolean(UiUtil.BINARY_VISIBLE, true);
} else if ("CONSOLE_CHUNK_LABEL".equals(MediatorHelper.tabConsoles().getTabComponentAt(i).getName())) {
preferences.putBoolean(UiUtil.CHUNK_VISIBLE, true);
} else if ("CONSOLE_NETWORK_LABEL".equals(MediatorHelper.tabConsoles().getTabComponentAt(i).getName())) {
preferences.putBoolean(UiUtil.NETWORK_VISIBLE, true);
} else if ("CONSOLE_JAVA_LABEL".equals(MediatorHelper.tabConsoles().getTabComponentAt(i).getName())) {
preferences.putBoolean(UiUtil.JAVA_VISIBLE, true);
}
}
}
});
// Size of window
this.setSize(1024, 768);
this.setVisible(true);
// Center the window
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
MediatorHelper.panelAddressBar().getTextFieldAddress().requestFocusInWindow();
}
private void initializeShortcuts() {
// Define the keyword shortcuts for tabs #Need to work even if the focus is not on tabs
HotkeyUtil.addShortcut(this.getRootPane(), MediatorHelper.tabResults());
HotkeyUtil.addTextFieldShortcutSelectAll();
}
private void initializePaneComponents() {
// Save controller
var menubar = new Menubar();
this.setJMenuBar(menubar);
MediatorHelper.register(menubar);
// Define the default panel: each component on a vertical line
this.getContentPane().setLayout(new BoxLayout(this.getContentPane(), BoxLayout.PAGE_AXIS));
// Main panel for tree and tables in the middle
// Set proxy tabs dependency
var mainPanel = new JPanel(new GridLayout(1, 0));
this.splitHorizontalTopBottom = new SplitHorizontalTopBottom();
mainPanel.add(this.splitHorizontalTopBottom);
var panelAddressBar = new PanelAddressBar(); // Textfields at the top
JTabbedPane tabManagers = new TabManagers(); // Tab manager use proxy tabs dependency
this.add(tabManagers);
this.add(panelAddressBar);
MediatorHelper.register(panelAddressBar);
this.add(mainPanel);
menubar.switchLocale(Locale.ENGLISH, I18nUtil.getLocaleDefault(), true);
}
// Empty the interface
public void resetInterface() {
MediatorHelper.panelAddressBar().getAddressMenuBar().reset();
MediatorHelper.treeDatabase().getTreeNodeModels().clear();
this.mapShells.clear();
MediatorHelper.panelConsoles().reset();
MediatorHelper.treeDatabase().reset();
for (var i = 0 ; i < MediatorHelper.tabConsoles().getTabCount() ; i++) {
var tabComponent = MediatorHelper.tabConsoles().getTabComponentAt(i);
if (tabComponent != null) {
tabComponent.setFont(tabComponent.getFont().deriveFont(Font.PLAIN));
}
}
Stream.of(
MediatorHelper.managerUpload(),
MediatorHelper.managerFile(),
MediatorHelper.managerWebshell(),
MediatorHelper.managerSqlshell()
)
.forEach(managerList -> {
managerList.setButtonEnable(false);
managerList.changePrivilegeIcon(UiUtil.ICON_SQUARE_GREY);
});
}
// Getters and setters
/**
* Get list of terminal by unique identifier.
* @return Map of key/value UUID => Terminal
*/
public final Map<UUID, AbstractShell> getConsoles() {
return this.mapShells;
}
public SubscriberInteraction getSubscriber() {
return this.subscriber;
}
public SplitHorizontalTopBottom getSplitHorizontalTopBottom() {
return this.splitHorizontalTopBottom;
}
}