001package jmri.jmrit.display; 002 003import java.awt.*; 004import java.awt.event.*; 005 006import javax.swing.*; 007 008import jmri.InstanceManager; 009import jmri.PermissionManager; 010import jmri.util.JmriJFrame; 011import jmri.util.swing.*; 012 013/** 014 * A JmriJFrame with permissions. 015 * 016 * @author Daniel Bergqvist (C) 2024 017 */ 018public class JmriJFrameWithPermissions extends JmriJFrame { 019 020 private final JPanel _hiddenPane = new JPanel(); 021 private Container _contentPane = new JPanel(); 022 private final JMenuBar _hiddenMenuBar = new JMenuBar(); 023 private JMenuBar _menuBar = super.getJMenuBar(); 024 private boolean _keepSize = true; 025 026 public JmriJFrameWithPermissions() { 027 setupContentPaneAndMenu(); 028 } 029 030 public JmriJFrameWithPermissions(String name) { 031 super(name); 032 setupContentPaneAndMenu(); 033 } 034 035 public JmriJFrameWithPermissions(String name, boolean saveSize, boolean savePosition) { 036 super(name, saveSize, savePosition); 037 setupContentPaneAndMenu(); 038 } 039 040 /** 041 * Setup a fake content pane and a fake menu to be used if 042 * the user doesn't have permission to view the panel. 043 */ 044 private void setupContentPaneAndMenu() { 045 _contentPane.setLayout(new BorderLayout() { 046 /* This BorderLayout subclass maps a null constraint to CENTER. 047 * Although the reference BorderLayout also does this, some VMs 048 * throw an IllegalArgumentException. 049 */ 050 @Override 051 public void addLayoutComponent(Component comp, Object constraints) { 052 if (constraints == null) { 053 constraints = BorderLayout.CENTER; 054 } 055 super.addLayoutComponent(comp, constraints); 056 } 057 }); 058 059 if (!InstanceManager.getDefault(PermissionManager.class).isEnabled()) { 060 return; 061 } 062 setGlassPane(new MyGlassPane().init()); 063 _hiddenPane.setLayout(new GridBagLayout()); // Center innerPanel 064 JPanel innerPanel = new JPanel(); 065 innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.Y_AXIS)); 066 innerPanel.add(new JLabel(Bundle.getMessage("Editor_PermissionDenied"))); 067 innerPanel.add(Box.createVerticalStrut(5)); 068 innerPanel.add(new JLabel(Bundle.getMessage("Editor_LoginToViewPanel"))); 069 _hiddenPane.add(innerPanel); 070 switchContentPaneAndMenu(); 071 InstanceManager.getDefault(PermissionManager.class).addLoginListener((isLogin) -> { 072 switchContentPaneAndMenu(); 073 }); 074 } 075 076 @Override 077 public void setContentPane(Container contentPane) { 078 this._contentPane = contentPane; 079 } 080 081 /** 082 * Switch contentPane and menu depending on whenether 083 * the user has read access to the panel or not. 084 */ 085 private void switchContentPaneAndMenu() { 086 if (! InstanceManager.getDefault(PermissionManager.class) 087 .hasAtLeastPermission(EditorPermissions.EDITOR_PERMISSION, 088 EditorPermissions.EditorPermissionEnum.View)) { 089 super.getGlassPane().setVisible(false); 090 super.setContentPane(_hiddenPane); 091 super.setJMenuBar(_hiddenMenuBar); 092 } else { 093 super.setContentPane(_contentPane); 094 super.setJMenuBar(_menuBar); 095 super.getGlassPane().setVisible( 096 ! InstanceManager.getDefault(PermissionManager.class) 097 .hasAtLeastPermission(EditorPermissions.EDITOR_PERMISSION, 098 EditorPermissions.EditorPermissionEnum.ViewControl) 099 ); 100 } 101 // Save the bounds before pack() since pack() might resize the panel 102 Rectangle bounds = getBounds(); 103 pack(); 104 if (_keepSize) { 105 setBounds(bounds); 106 } else { 107 setLocation(bounds.x, bounds.y); 108 } 109 revalidate(); 110 } 111 112 @Override 113 public void revalidate() { 114 if (_contentPane != super.getContentPane()) { 115 // Ensure the contentPane is validated as well 116 super.setContentPane(_contentPane); 117 _contentPane.revalidate(); 118 super.setContentPane(_hiddenPane); 119 } 120 super.revalidate(); 121 } 122 123 @Override 124 public void setVisible(boolean b) { 125 if (b && _contentPane != super.getContentPane()) { 126 // Ensure the contentPane is validated as well 127 super.setContentPane(_contentPane); 128 super.setVisible(b); 129 super.setContentPane(_hiddenPane); 130 } 131 super.setVisible(b); 132 } 133 134 @Override 135 public Container getContentPane() { 136 // We have our own content pane which may or may not be the content 137 // pane that's actually in use. If the user doesn't have permission 138 // to view the panel, we show another content pane instead which only 139 // has a message: "Permission denied. Login to view the panel". 140 return _contentPane; 141 } 142 143 @Override 144 public JMenuBar getJMenuBar() { 145 // We have our own menu which may or may not be the menu 146 // that's actually in use. If the user doesn't have permission 147 // to view the panel, we show another menu instead which is 148 // empty. 149 return _menuBar; 150 } 151 152 @Override 153 public void setJMenuBar(JMenuBar menuBar) { 154 this._menuBar = menuBar; 155 switchContentPaneAndMenu(); 156 } 157 158 /** 159 * Should the panel keep its size when switching between normal and 160 * hidden panel? 161 * @param keepSize true if to keep size, false if only keep location 162 */ 163 public final void setKeepSize(boolean keepSize) { 164 this._keepSize = keepSize; 165 } 166 167 168 /** 169 * This pane consumes all the mouse events and key events when visible. 170 * It's used when the panel is read only. 171 */ 172 private static class MyGlassPane extends JPanel 173 implements JmriMouseListener, KeyListener { 174 175 private MyGlassPane init() { 176 setOpaque(false); 177 addMouseListener(JmriMouseListener.adapt(this)); 178 addKeyListener(this); 179 return this; 180 } 181 182 private void showReadOnly() { 183 JmriJOptionPane.showMessageDialog(this, 184 Bundle.getMessage("JmriJFrameWithPermissions_PanelReadOnly"), 185 Bundle.getMessage("JmriJFrameWithPermissions_TitleError"), 186 JmriJOptionPane.ERROR_MESSAGE); 187 } 188 189 @Override 190 public void mouseClicked(JmriMouseEvent e) { 191 // Do nothing 192 } 193 194 @Override 195 public void mousePressed(JmriMouseEvent e) { 196 e.consume(); 197 requestFocusInWindow(); 198 showReadOnly(); 199 } 200 201 @Override 202 public void mouseReleased(JmriMouseEvent e) { 203 // Do nothing 204 } 205 206 @Override 207 public void mouseEntered(JmriMouseEvent e) { 208 // Do nothing 209 } 210 211 @Override 212 public void mouseExited(JmriMouseEvent e) { 213 // Do nothing 214 } 215 216 @Override 217 public void keyTyped(KeyEvent e) { 218 e.consume(); 219 showReadOnly(); 220 } 221 222 @Override 223 public void keyPressed(KeyEvent e) { 224 // Do nothing 225 } 226 227 @Override 228 public void keyReleased(KeyEvent e) { 229 // Do nothing 230 } 231 232 } 233 234}