Skip to content

Commit

Permalink
Remove menu code, add initial control dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
tresf committed Apr 26, 2023
1 parent 36ad1fb commit 0f77646
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 99 deletions.
9 changes: 2 additions & 7 deletions js/qz-tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -2658,16 +2658,11 @@ var qz = (function() {
*/
gui: {
/**
* Show the System Tray menu
* Show the the actions/options menu
* @memberof qz.gui
*/
showMenu: function(event) {
var position = event ? { x: event.screenX, y: event.screenY } : null;
if(position) {
return _qz.websocket.dataPromise('gui.showMenu', position);
} else {
_qz.log.warn("Menu requires a MouseEvent");
}
return _qz.websocket.dataPromise('gui.showMenu');
},

/**
Expand Down
2 changes: 1 addition & 1 deletion sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ <h1 id="title" class="page-header">QZ Tray v<span id="qz-version">0</span></h1>
<div class="col-md-4">
<div id="qz-connection" class="panel panel-default">
<div class="panel-heading">
<button class="close tip" data-toggle="tooltip" title="QZ Tray Menu" id="menu" href="#" onclick="qz.gui.showMenu(event);" style="display: none;">
<button class="close tip" data-toggle="tooltip" title="QZ Tray Menu" id="menu" href="#" onclick="qz.gui.showMenu();" style="display: none;">
<i class="fa fa-bars"></i>
</button>
<button class="close tip" data-toggle="tooltip" title="Launch QZ" id="launch" href="#" onclick="launchQZ();" style="display: none;">
Expand Down
109 changes: 90 additions & 19 deletions src/qz/common/TrayManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public class TrayManager {
private AboutDialog aboutDialog;
private LogDialog logDialog;
private SiteManagerDialog sitesDialog;
private ControlDialog controlDialog;
private ArrayList<Component> componentList;
private IconCache.Icon shownIcon;

Expand Down Expand Up @@ -253,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));
Expand Down Expand Up @@ -327,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);
Expand Down Expand Up @@ -368,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"));
}
};

Expand All @@ -404,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);

Expand All @@ -428,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());
};
}

Expand Down Expand Up @@ -474,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);
Expand Down Expand Up @@ -632,19 +702,20 @@ private void displayMessage(final String caption, final String text, final TrayI
public void displayComponent(SocketMethod method, Point location) {
switch(method) {
case GUI_SHOW_ABOUT:
SystemUtilities.centerDialog(aboutDialog, location);
SystemUtilities.centerWindow(aboutDialog, location);
aboutDialog.setVisible(true);
break;
case GUI_SHOW_LOG:
SystemUtilities.centerDialog(logDialog, location);
SystemUtilities.centerWindow(logDialog, location);
logDialog.setVisible(true);
break;
case GUI_SHOW_SITES:
SystemUtilities.centerDialog(sitesDialog, location);
SystemUtilities.centerWindow(sitesDialog, location);
sitesDialog.setVisible(true);
break;
case GUI_SHOW_MENU:
tray.showOrphaned(location);
SystemUtilities.centerWindow(controlDialog, location);
controlDialog.setVisible(true);
break;
default:
throw new UnsupportedOperationException("Call \"" + method.getCallName() + "\" is not yet supported");
Expand Down
8 changes: 4 additions & 4 deletions src/qz/ui/BasicDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/qz/ui/GatewayDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
3 changes: 3 additions & 0 deletions src/qz/ui/tray/AWTMenuWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}

Expand Down
4 changes: 0 additions & 4 deletions src/qz/ui/tray/TaskbarTrayIcon.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,6 @@ public void keyReleased(KeyEvent keyEvent) {}
});
}

public JPopupMenu getJPopupMenu() {
return popup;
}

public void displayMessage(String caption, String text, TrayIcon.MessageType level) {
int messageType;
switch(level) {
Expand Down
45 changes: 0 additions & 45 deletions src/qz/ui/tray/TrayType.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@

import org.jdesktop.swinghelper.tray.JXTrayIcon;
import qz.ui.component.IconCache;
import qz.utils.MacUtilities;
import qz.utils.SystemUtilities;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

/**
* Wrapper class to allow popup menu on a tray-less OS
Expand Down Expand Up @@ -108,44 +103,4 @@ public void showTaskbar() {
taskbar.setState(Frame.ICONIFIED);
}
}

/**
* A convenience for displaying the menu without a tray
*/
public void showOrphaned(Point location) {
JDialog dialog = new JDialog();
dialog.setSize(new Dimension(1, 1));
dialog.getContentPane().setBackground(Color.white);
dialog.setUndecorated(true);
if(SystemUtilities.isMac()) {
dialog.add(tray.getPopupMenu());
} else {
dialog.add(tray != null ? tray.getJPopupMenu() : taskbar.getJPopupMenu());
}
dialog.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
if(SystemUtilities.isMac()) {
tray.getPopupMenu().show(dialog, 0, 0);
} else {
tray.getJPopupMenu().show(dialog, 0, 0);
}
super.focusGained(e);
}

@Override
public void focusLost(FocusEvent e) {
dialog.removeAll();
dialog.validate();
dialog.dispose();
super.focusLost(e);
}
});
dialog.setLocation(location);
dialog.setVisible(true);
dialog.requestFocus();
if(SystemUtilities.isMac()) {
MacUtilities.setFocus();
}
}
}
4 changes: 2 additions & 2 deletions src/qz/utils/MacUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
14 changes: 7 additions & 7 deletions src/qz/utils/SystemUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -517,34 +517,34 @@ public static boolean setSystemLookAndFeel() {
* @param position The center point of a screen as calculated from a web browser at 96-dpi
* @return <code>true</code> 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;
}

//adjust for dpi scaling
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());
}

/**
Expand Down
Loading

0 comments on commit 0f77646

Please sign in to comment.