diff --git a/js/qz-tray.js b/js/qz-tray.js index 8f71f6104..5217477f0 100644 --- a/js/qz-tray.js +++ b/js/qz-tray.js @@ -2653,6 +2653,43 @@ var qz = (function() { } }, + /** + * @namespace qz.gui + */ + gui: { + /** + * Show the the actions/options menu + * @memberof qz.gui + */ + showMenu: function(event) { + return _qz.websocket.dataPromise('gui.showMenu'); + }, + + /** + * Show the About dialog + * @memberof qz.gui + */ + showAbout: function() { + return _qz.websocket.dataPromise('gui.showAbout'); + }, + + /** + * Show the Site Manager dialog + * @memberof qz.gui + */ + showSites: function() { + return _qz.websocket.dataPromise('gui.showSites'); + }, + + /** + * Show the Log dialog + * @memberof qz.gui + */ + showLog: function() { + return _qz.websocket.dataPromise('gui.showLog'); + } + }, + /** * Calls related to compatibility adjustments * @namespace qz.api diff --git a/sample.html b/sample.html index b8511cdf2..3f2ee1ef3 100755 --- a/sample.html +++ b/sample.html @@ -53,6 +53,9 @@

QZ Tray v0

+ @@ -3017,8 +3020,10 @@

Options

if (text === "Inactive" || text === "Error") { $("#launch").show(); + $("#menu").hide(); } else { $("#launch").hide(); + $("#menu").show(); } } diff --git a/src/qz/common/Constants.java b/src/qz/common/Constants.java index 3dcf9f889..af3b04227 100644 --- a/src/qz/common/Constants.java +++ b/src/qz/common/Constants.java @@ -93,6 +93,10 @@ public class Constants { public static final Color TRUSTED_COLOR_LITE = Color.BLUE; public static final Color WARNING_COLOR_DARK = Color.decode("#EB6261"); public static final Color TRUSTED_COLOR_DARK = Color.decode("#589DF6"); + public static final Color RUNNING_COLOR = Color.decode("#00AD47"); + public static final Color PENDING_COLOR = Color.decode("#B2B247"); + public static final Color STOPPED_COLOR = Color.decode("#AE4745"); + public static Color WARNING_COLOR = WARNING_COLOR_LITE; public static Color TRUSTED_COLOR = TRUSTED_COLOR_LITE; diff --git a/src/qz/common/TrayManager.java b/src/qz/common/TrayManager.java index b620b48f0..313868a8a 100644 --- a/src/qz/common/TrayManager.java +++ b/src/qz/common/TrayManager.java @@ -26,12 +26,11 @@ import qz.utils.*; import qz.ws.PrintSocketServer; import qz.ws.SingleInstanceChecker; +import qz.ws.SocketMethod; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; +import java.awt.event.*; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -62,6 +61,7 @@ public class TrayManager { private AboutDialog aboutDialog; private LogDialog logDialog; private SiteManagerDialog sitesDialog; + private ControlDialog controlDialog; private ArrayList componentList; private IconCache.Icon shownIcon; @@ -254,6 +254,10 @@ private void addMenuItems() { sitesDialog = new SiteManagerDialog(sitesItem, iconCache, prefs); componentList.add(sitesDialog); + JMenuItem controlMenuItem = new JMenuItem("Control Menu...", iconCache.getIcon(SAVED_ICON)); + controlMenuItem.setMnemonic(KeyEvent.VK_C); + controlMenuItem.addActionListener(controlMenuListener); + JMenuItem diagnosticMenu = new JMenu("Diagnostic"); JMenuItem browseApp = new JMenuItem("Browse App folder...", iconCache.getIcon(FOLDER_ICON)); @@ -328,6 +332,7 @@ private void addMenuItems() { advancedMenu.add(new JSeparator()); } advancedMenu.add(sitesItem); + advancedMenu.add(controlMenuItem); advancedMenu.add(desktopItem); advancedMenu.add(new JSeparator()); advancedMenu.add(anonymousItem); @@ -369,26 +374,87 @@ private void addMenuItems() { popup.add(separator); popup.add(exitItem); + controlDialog = new ControlDialog(iconCache); + componentList.add(controlDialog); + + // Status/control section + controlDialog.add(reloadItem, ControlDialog.Category.STATUS); + controlDialog.add(exitItem, "Shut down", ControlDialog.Category.STATUS); + + // General section + controlDialog.add(aboutItem, ControlDialog.Category.GENERAL); + controlDialog.add(sitesItem, ControlDialog.Category.GENERAL); + controlDialog.add(logItem, ControlDialog.Category.GENERAL); + + // Advanced section + controlDialog.add(startupItem, ControlDialog.Category.ADVANCED); + controlDialog.add(notificationsItem, ControlDialog.Category.ADVANCED); + controlDialog.add(monocleItem, ControlDialog.Category.ADVANCED); + controlDialog.add(anonymousItem, ControlDialog.Category.ADVANCED); + controlDialog.add(new JSeparator(), ControlDialog.Category.ADVANCED); + controlDialog.add(desktopItem, ControlDialog.Category.ADVANCED); + + // Diagnostic section + controlDialog.add(zipLogs, ControlDialog.Category.DIAGNOSTIC); + controlDialog.add(new JSeparator(), ControlDialog.Category.DIAGNOSTIC); + controlDialog.add(browseApp, ControlDialog.Category.DIAGNOSTIC); + controlDialog.add(browseUser, ControlDialog.Category.DIAGNOSTIC); + controlDialog.add(browseShared, ControlDialog.Category.DIAGNOSTIC); + if (tray != null) { tray.setJPopupMenu(popup); + } // FIXME REMOVE THIS COMMENT // else { + // Display and minimize + controlDialog.setPersistent(true); + controlDialog.setVisible(true); + controlDialog.setState(Frame.ICONIFIED); + // FIXME REMOVE THIS COMMENT // controlMenuDialog.setState(Frame.ICONIFIED); + // FIXME REMOVE THIS COMMENT // } + + + } + + private static boolean getCheckBoxState(ActionEvent e) { + Object o = e.getSource(); + if(o instanceof JCheckBox) { + return ((JCheckBox)o).isSelected(); + } else if(o instanceof JCheckBoxMenuItem) { + return ((JCheckBoxMenuItem)o).getState(); + } else if(o instanceof CheckboxMenuItem) { + return ((CheckboxMenuItem)o).getState(); } + throw new UnsupportedOperationException("Cannot get checkbox state of " + o.getClass().getSimpleName()); } + private static void setCheckBoxState(ActionEvent e, boolean state) { + Object o = e.getSource(); + if(o instanceof JCheckBox) { + ((JCheckBox)o).setSelected(state); + return; + } else if(o instanceof JCheckBoxMenuItem) { + ((JCheckBoxMenuItem)o).setState(state); + return; + } else if(o instanceof CheckboxMenuItem) { + ((CheckboxMenuItem)o).setState(state); + return; + } + throw new UnsupportedOperationException("Cannot get checkbox state of " + o.getClass().getSimpleName()); + } private final ActionListener notificationsListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - prefs.setProperty(Constants.PREFS_NOTIFICATIONS, ((JCheckBoxMenuItem)e.getSource()).getState()); + prefs.setProperty(Constants.PREFS_NOTIFICATIONS, getCheckBoxState(e)); } }; private final ActionListener monocleListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - JCheckBoxMenuItem j = (JCheckBoxMenuItem)e.getSource(); - prefs.setProperty(Constants.PREFS_MONOCLE, j.getState()); + boolean state = getCheckBoxState(e); + prefs.setProperty(Constants.PREFS_MONOCLE, state); displayWarningMessage(String.format("A restart of %s is required to ensure this feature is %sabled.", - Constants.ABOUT_TITLE, j.getState()? "en":"dis")); + Constants.ABOUT_TITLE, state? "en":"dis")); } }; @@ -405,10 +471,7 @@ public void actionPerformed(ActionEvent e) { }; private final ActionListener anonymousListener = e -> { - boolean checkBoxState = true; - if (e.getSource() instanceof JCheckBoxMenuItem) { - checkBoxState = ((JCheckBoxMenuItem)e.getSource()).getState(); - } + boolean checkBoxState = getCheckBoxState(e); log.debug("Block unsigned: {}", checkBoxState); @@ -429,17 +492,18 @@ public void actionPerformed(ActionEvent e) { private ActionListener startupListener() { return e -> { - JCheckBoxMenuItem source = (JCheckBoxMenuItem)e.getSource(); - if (!source.getState() && !confirmDialog.prompt("Remove " + name + " from startup?")) { - source.setState(true); + if (!getCheckBoxState(e) && !confirmDialog.prompt("Remove " + name + " from startup?")) { + setCheckBoxState(e,true); return; } - if (FileUtilities.setAutostart(source.getState())) { - displayInfoMessage("Successfully " + (source.getState() ? "enabled" : "disabled") + " autostart"); + + boolean state = getCheckBoxState(e); + if (FileUtilities.setAutostart(state)) { + displayInfoMessage("Successfully " + (state ? "enabled" : "disabled") + " autostart"); } else { - displayErrorMessage("Error " + (source.getState() ? "enabling" : "disabling") + " autostart"); + displayErrorMessage("Error " + (state ? "enabling" : "disabling") + " autostart"); } - source.setState(FileUtilities.isAutostart()); + setCheckBoxState(e, FileUtilities.isAutostart()); }; } @@ -475,6 +539,11 @@ public void actionPerformed(ActionEvent e) { } }; + + private final ActionListener controlMenuListener = e -> { + controlDialog.setVisible(true); + }; + public void exit(int returnCode) { prefs.save(); System.exit(returnCode); @@ -602,6 +671,7 @@ private void setIcon(final IconCache.Icon i) { public void refreshIcon(final Runnable whenDone) { SwingUtilities.invokeLater(() -> { tray.setIcon(shownIcon); + controlDialog.setRunningIndicator(shownIcon); if(whenDone != null) { whenDone.run(); } @@ -630,6 +700,31 @@ private void displayMessage(final String caption, final String text, final TrayI } } + public void displayComponent(SocketMethod method, Point location) { + SwingUtilities.invokeLater(() -> { + switch(method) { + case GUI_SHOW_ABOUT: + SystemUtilities.centerWindow(aboutDialog, location); + aboutDialog.setVisible(true); + break; + case GUI_SHOW_LOG: + SystemUtilities.centerWindow(logDialog, location); + logDialog.setVisible(true); + break; + case GUI_SHOW_SITES: + SystemUtilities.centerWindow(sitesDialog, location); + sitesDialog.setVisible(true); + break; + case GUI_SHOW_MENU: + SystemUtilities.centerWindow(controlDialog, location); + controlDialog.setVisible(true); + break; + default: + throw new UnsupportedOperationException("Call \"" + method.getCallName() + "\" is not yet supported"); + } + }); + } + public void singleInstanceCheck(java.util.List insecurePorts, Integer insecurePortIndex) { for(int port : insecurePorts) { if (port != insecurePorts.get(insecurePortIndex)) { diff --git a/src/qz/ui/BasicDialog.java b/src/qz/ui/BasicDialog.java index 40829d070..07576a0bf 100644 --- a/src/qz/ui/BasicDialog.java +++ b/src/qz/ui/BasicDialog.java @@ -17,7 +17,7 @@ /** * Created by Tres on 2/23/2015. */ -public class BasicDialog extends JDialog implements Themeable { +public class BasicDialog extends JFrame implements Themeable { private JPanel mainPanel; private JComponent headerComponent; private JComponent contentComponent; @@ -30,13 +30,13 @@ public class BasicDialog extends JDialog implements Themeable { private int stockButtonCount = 0; public BasicDialog(JMenuItem caller, IconCache iconCache) { - super((Frame)null, caller.getText().replaceAll("\\.+", ""), true); + super(caller.getText().replaceAll("\\.+", "")); this.iconCache = iconCache; initBasicComponents(); } - public BasicDialog(Frame owner, String title, IconCache iconCache) { - super(owner, title, true); + public BasicDialog(String title, IconCache iconCache) { + super(title); this.iconCache = iconCache; initBasicComponents(); } diff --git a/src/qz/ui/ControlDialog.java b/src/qz/ui/ControlDialog.java new file mode 100644 index 000000000..359c5a9c9 --- /dev/null +++ b/src/qz/ui/ControlDialog.java @@ -0,0 +1,232 @@ +package qz.ui; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import qz.common.Constants; +import qz.ui.component.IconCache; + +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import java.util.Arrays; + +/** + * Created by Tres on 11/16/2022 + * A container for all the System Tray menu items + */ +public class ControlDialog extends BasicDialog implements Themeable { + private static final Logger log = LogManager.getLogger(ControlDialog.class); + + public enum Category { + STATUS, + GENERAL, + ADVANCED, + DIAGNOSTIC + } + + private boolean persistent = false; + + private JPanel statusPanel; + private JPanel statusLeftPanel; + private JPanel statusRightPanel; + private JPanel generalPanel; + private JPanel advancedPanel; + private JPanel diagnosticPanel; + + private JLabel runningIndicator; + private JLabel runningLabel; + + public ControlDialog(IconCache iconCache) { + super(Constants.ABOUT_TITLE, iconCache); + initComponents(); + } + + public void add(Component component, Category category) { + add(component, null, category); + } + + public void add(Component component, String text, Category category) { + JComponent toAdd = null; + if(component instanceof JCheckBoxMenuItem) { + JCheckBoxMenuItem checkBoxMenuItem = (JCheckBoxMenuItem)component; + JCheckBox checkBox = new JCheckBox(text == null ? checkBoxMenuItem.getText() : text, checkBoxMenuItem.getIcon(), checkBoxMenuItem.getState()); + Arrays.stream(checkBoxMenuItem.getActionListeners()).forEach(checkBox::addActionListener); + + // Keep original in sync + checkBox.addChangeListener(e -> { + checkBoxMenuItem.setState(checkBox.isSelected()); + }); + + // Add change listener on the original too + checkBoxMenuItem.addChangeListener(e -> checkBox.setSelected(checkBoxMenuItem.getState())); + + toAdd = checkBox; + } else if(component instanceof JMenuItem) { + JMenuItem menuItem = (JMenuItem)component; + JButton button = new JButton(text == null ? menuItem.getText() : text, menuItem.getIcon()); + Arrays.stream(menuItem.getActionListeners()).forEach(button::addActionListener); + toAdd = button; + } else if(component instanceof JSeparator){ + toAdd = (JSeparator)component; + } else if (component instanceof JComponent){ + toAdd = (JComponent)component; + } else { + log.warn("Cannot add {}, not yet supported.", component.getClass().getSimpleName()); + } + if(toAdd != null) { + switch(category) { + case STATUS: + statusRightPanel.add(toAdd); + break; + case ADVANCED: + advancedPanel.add(toAdd); + break; + case DIAGNOSTIC: + diagnosticPanel.add(toAdd); + break; + case GENERAL: + default: + generalPanel.add(toAdd); + } + } + pack(); + } + + private void initComponents() { + + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.setBorder(createPaddedLineBorder(5, SwingConstants.SOUTH)); + + statusLeftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + statusRightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + + statusPanel = new JPanel(new GridLayout(1, 3)); + + // Running indicator + runningIndicator = new JLabel("•"); + runningIndicator.setFont(new Font("", Font.BOLD, 24)); + runningIndicator.setForeground(Constants.STOPPED_COLOR); + runningIndicator.setBorder(new EmptyBorder(0, 2, 2, 2)); + runningLabel = new JLabel("Stopped"); + runningLabel.setBorder(new EmptyBorder(0, 0, 0, 4)); + statusLeftPanel.add(runningIndicator); + statusLeftPanel.add(runningLabel); + statusPanel.add(statusLeftPanel); + + // Version label + JLabel versionLabel = new JLabel(Constants.ABOUT_TITLE + " " + Constants.VERSION); + versionLabel.setFont(runningLabel.getFont()); + statusPanel.add(versionLabel); + + // Additional controls added with .add() + statusPanel.add(statusRightPanel); + + Font headingFont = new JLabel().getFont().deriveFont(16f).deriveFont(Font.BOLD); + + generalPanel = new JPanel(); + generalPanel.setLayout(new BoxLayout(generalPanel, BoxLayout.Y_AXIS)); + generalPanel.setBorder(createPaddedLineBorder(5, SwingConstants.EAST)); + JLabel generalLabel = new JLabel("General"); + generalLabel.setFont(headingFont); + generalPanel.add(generalLabel); + + advancedPanel = new JPanel(); + advancedPanel.setLayout(new BoxLayout(advancedPanel, BoxLayout.Y_AXIS)); + advancedPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + JLabel advancedLabel = new JLabel("Advanced"); + advancedLabel.setFont(headingFont); + advancedPanel.add(advancedLabel); + + diagnosticPanel = new JPanel(); + diagnosticPanel.setLayout(new BoxLayout(diagnosticPanel, BoxLayout.Y_AXIS)); + diagnosticPanel.setBorder(createPaddedLineBorder(5, SwingConstants.WEST)); + JLabel diagnosticLabel = new JLabel("Diagnostic"); + diagnosticLabel.setFont(headingFont); + diagnosticPanel.add(diagnosticLabel); + + setHeader(statusPanel); + statusPanel.setBorder(new BevelBorder(BevelBorder.LOWERED)); + mainPanel.add(generalPanel, BorderLayout.LINE_START); + mainPanel.add(advancedPanel, BorderLayout.CENTER); + mainPanel.add(diagnosticPanel, BorderLayout.LINE_END); + setContent(mainPanel, false); + + if(persistent) { + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + setExtendedState(JFrame.ICONIFIED); + } + }); + } + + setResizable(false); + pack(); + + setLocationRelativeTo(null); // center on main display + } + + private static Border createPaddedLineBorder(int padding, int position) { + Color borderColor = new JSeparator().getForeground(); + Border margins = new EmptyBorder(padding, padding, padding, padding); + Border border; + + switch(position) { + case SwingConstants.NORTH: + border = new MatteBorder(1, 0, 0, 0, borderColor); + break; + case SwingConstants.WEST: + border = new MatteBorder(0, 1, 0, 0, borderColor); + break; + case SwingConstants.SOUTH: + border = new MatteBorder(0, 0, 1, 0, borderColor); + break; + default: + case SwingConstants.EAST: + border = new MatteBorder(0, 0, 0, 1, borderColor); + } + return new CompoundBorder(border, margins); + } + + @Override + public void setVisible(boolean b) { + // Prevent closing if persistent mode is enabled + if(!b && persistent) { + setExtendedState(JFrame.ICONIFIED); + } else { + super.setVisible(b); + } + } + + @Override + public void refresh() { + ThemeUtilities.refreshAll(this); + } + + public void setRunningIndicator(IconCache.Icon icon) { + switch(icon) { + case WARNING_ICON: + runningIndicator.setForeground(Constants.PENDING_COLOR); + runningLabel.setText("Pending"); + break; + case DANGER_ICON: + runningIndicator.setForeground(Constants.STOPPED_COLOR); + runningLabel.setText("Stopped"); + break; + case DEFAULT_ICON: + default: + runningIndicator.setForeground(Constants.RUNNING_COLOR); + runningLabel.setText("Running"); + } + } + + /** + * Sets persistent mode, window can't be closed unless shutdown + */ + public void setPersistent(boolean persistent) { + this.persistent = persistent; + } +} + diff --git a/src/qz/ui/GatewayDialog.java b/src/qz/ui/GatewayDialog.java index e9aa3cdb0..1e1ebd94f 100644 --- a/src/qz/ui/GatewayDialog.java +++ b/src/qz/ui/GatewayDialog.java @@ -220,7 +220,7 @@ public boolean prompt(String description, RequestState request, Point position) setDescription(description); setRequest(request); refreshComponents(); - SystemUtilities.centerDialog(this, position); + SystemUtilities.centerWindow(this, position); setVisible(true); return isApproved(); diff --git a/src/qz/ui/tray/AWTMenuWrapper.java b/src/qz/ui/tray/AWTMenuWrapper.java index 99304e9f2..c103c6325 100644 --- a/src/qz/ui/tray/AWTMenuWrapper.java +++ b/src/qz/ui/tray/AWTMenuWrapper.java @@ -75,7 +75,10 @@ private void wrapItemListeners(final JMenuItem item) { private void wrapState(JMenuItem item) { if (this.item instanceof CheckboxMenuItem && item instanceof JCheckBoxMenuItem) { + // Match initial state ((CheckboxMenuItem)this.item).setState(((JCheckBoxMenuItem)item).getState()); + // Monitor future state + item.addChangeListener(e -> ((CheckboxMenuItem)AWTMenuWrapper.this.item).setState(((JCheckBoxMenuItem)item).getState())); } } diff --git a/src/qz/ui/tray/TrayType.java b/src/qz/ui/tray/TrayType.java index 3167e9c33..80aa0fa30 100644 --- a/src/qz/ui/tray/TrayType.java +++ b/src/qz/ui/tray/TrayType.java @@ -2,7 +2,6 @@ import org.jdesktop.swinghelper.tray.JXTrayIcon; import qz.ui.component.IconCache; - import javax.swing.*; import java.awt.*; import java.awt.event.ActionListener; diff --git a/src/qz/utils/MacUtilities.java b/src/qz/utils/MacUtilities.java index 26822b7f5..20be2e007 100644 --- a/src/qz/utils/MacUtilities.java +++ b/src/qz/utils/MacUtilities.java @@ -38,7 +38,7 @@ */ public class MacUtilities { private static final Logger log = LogManager.getLogger(MacUtilities.class); - private static Dialog aboutDialog; + private static Window aboutDialog; private static TrayManager trayManager; private static String bundleId; private static Boolean jdkSupportsTemplateIcon; @@ -56,7 +56,7 @@ public static void showExitPrompt() { /** * Adds a listener to register the Apple "About" dialog to call {@code setVisible()} on the specified Dialog */ - public static void registerAboutDialog(Dialog aboutDialog) { + public static void registerAboutDialog(Window aboutDialog) { MacUtilities.aboutDialog = aboutDialog; try { diff --git a/src/qz/utils/SystemUtilities.java b/src/qz/utils/SystemUtilities.java index ea6442662..969fce7ed 100644 --- a/src/qz/utils/SystemUtilities.java +++ b/src/qz/utils/SystemUtilities.java @@ -517,11 +517,11 @@ public static boolean setSystemLookAndFeel() { * @param position The center point of a screen as calculated from a web browser at 96-dpi * @return true if the operation is successful */ - public static void centerDialog(Dialog dialog, Point position) { + public static void centerWindow(Window window, Point position) { // Assume 0,0 are bad coordinates if (position == null || (position.getX() == 0 && position.getY() == 0)) { log.debug("Invalid dialog position provided: {}, we'll center on first monitor instead", position); - dialog.setLocationRelativeTo(null); + window.setLocationRelativeTo(null); return; } @@ -529,22 +529,22 @@ public static void centerDialog(Dialog dialog, Point position) { double dpiScale = getWindowScaleFactor(); if (dpiScale == 0) { log.debug("Invalid window scale value: {}, we'll center on the primary monitor instead", dpiScale); - dialog.setLocationRelativeTo(null); + window.setLocationRelativeTo(null); return; } - Rectangle rect = new Rectangle((int)(position.x * dpiScale), (int)(position.y * dpiScale), dialog.getWidth(), dialog.getHeight()); - rect.translate(-dialog.getWidth() / 2, -dialog.getHeight() / 2); + Rectangle rect = new Rectangle((int)(position.x * dpiScale), (int)(position.y * dpiScale), window.getWidth(), window.getHeight()); + rect.translate(-window.getWidth() / 2, -window.getHeight() / 2); Point p = new Point((int)rect.getCenterX(), (int)rect.getCenterY()); log.debug("Calculated dialog centered at: {}", p); if (!isWindowLocationValid(rect)) { log.debug("Dialog position provided is out of bounds: {}, we'll center on the primary monitor instead", p); - dialog.setLocationRelativeTo(null); + window.setLocationRelativeTo(null); return; } - dialog.setLocation(rect.getLocation()); + window.setLocation(rect.getLocation()); } /** diff --git a/src/qz/ws/PrintSocketClient.java b/src/qz/ws/PrintSocketClient.java index 4133f5cb5..edc59653c 100644 --- a/src/qz/ws/PrintSocketClient.java +++ b/src/qz/ws/PrintSocketClient.java @@ -633,6 +633,16 @@ private void processMessage(Session session, JSONObject json, SocketConnection c case GET_VERSION: sendResult(session, UID, Constants.VERSION); break; + case GUI_SHOW_MENU: + case GUI_SHOW_SITES: + case GUI_SHOW_ABOUT: + case GUI_SHOW_LOG: + if(trayManager != null) { + trayManager.displayComponent(call, findDialogPosition(session, json.optJSONObject("position"))); + } else { + log.warn("Cannot call \"{}\" when trayManager is null", call.getCallName()); + } + break; case WEBSOCKET_STOP: log.info("Another instance of {} is asking this to close", Constants.ABOUT_TITLE); String challenge = json.optString("challenge", ""); diff --git a/src/qz/ws/SocketMethod.java b/src/qz/ws/SocketMethod.java index 0caf37998..ba50ca0a2 100644 --- a/src/qz/ws/SocketMethod.java +++ b/src/qz/ws/SocketMethod.java @@ -1,5 +1,7 @@ package qz.ws; +import qz.common.Constants; + public enum SocketMethod { PRINTERS_GET_DEFAULT("printers.getDefault", true, "access connected printers"), PRINTERS_FIND("printers.find", true, "access connected printers"), @@ -55,6 +57,11 @@ public enum SocketMethod { NETWORKING_DEVICE_LEGACY("websocket.getNetworkInfo", true), GET_VERSION("getVersion", false), + GUI_SHOW_MENU("gui.showMenu", true, "show " + Constants.ABOUT_TITLE + " menu"), + GUI_SHOW_SITES("gui.showSites", true, "show " + Constants.ABOUT_TITLE + " Site Manager"), + GUI_SHOW_ABOUT("gui.showAbout", true, "show " + Constants.ABOUT_TITLE + " About Dialog"), + GUI_SHOW_LOG("gui.showLog", true, "show " + Constants.ABOUT_TITLE + " Log Dialog"), + WEBSOCKET_STOP("websocket.stop", false), INVALID("", false);