001package jmri.jmrit.permission.swing; 002 003import java.awt.*; 004import java.util.*; 005import java.util.List; 006import java.util.function.BooleanSupplier; 007 008import javax.swing.*; 009import javax.swing.border.EmptyBorder; 010 011import jmri.*; 012import jmri.PermissionsSystemAdmin; 013import jmri.jmrit.permission.DefaultPermissionManager; 014import jmri.swing.*; 015import jmri.util.swing.JmriJOptionPane; 016 017import org.openide.util.lookup.ServiceProvider; 018 019/** 020 * Preferences panel for Permission manager. 021 * 022 * @author Daniel Bergqvist Copyright 2024 023 */ 024@ServiceProvider(service = PreferencesPanel.class) 025public class PermissionPreferencesPanel extends JPanel implements PreferencesPanel { 026 027 private final DefaultPermissionManager _temporaryPermissionManager; 028 private final Map<User, UserFields> _userFieldsMap = new HashMap<>(); 029 private boolean _dirty = false; 030 031 public PermissionPreferencesPanel() { 032 PermissionManager mngr = InstanceManager.getDefault(PermissionManager.class); 033 if (!(mngr instanceof DefaultPermissionManager)) { 034 throw new RuntimeException("PermissionManager is not of type DefaultPermissionManager"); 035 } 036 _temporaryPermissionManager = ((DefaultPermissionManager)mngr).getTemporaryInstance(); 037 initGUI(); 038 } 039 040 private void initGUI() { 041 042 JTabbedPane rolesTabbedPane = new JTabbedPane(); 043 JTabbedPane usersTabbedPane = new JTabbedPane(); 044 045 List<Role> roleList = new ArrayList<>(_temporaryPermissionManager.getRoles()); 046 roleList.sort((a,b) -> { 047 if (a.getPriority() != b.getPriority()) { 048 return Integer.compare(b.getPriority(), a.getPriority()); 049 } 050 return a.getName().toLowerCase().compareTo(b.getName().toLowerCase()); 051 }); 052 053 List<User> userList = new ArrayList<>(_temporaryPermissionManager.getUsers()); 054 userList.sort((a,b) -> { 055 if (a.getPriority() != b.getPriority()) { 056 return Integer.compare(b.getPriority(), a.getPriority()); 057 } 058 return a.getUserName().toLowerCase().compareTo(b.getUserName().toLowerCase()); 059 }); 060 061 062 JPanel outerPanel = new JPanel(); 063 064 outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.PAGE_AXIS)); 065 066 JPanel settingsPanel = new JPanel(); 067 settingsPanel.setLayout(new BoxLayout(settingsPanel, BoxLayout.PAGE_AXIS)); 068 settingsPanel.setBorder(BorderFactory.createCompoundBorder( 069 BorderFactory.createLineBorder(Color.black, 1), new EmptyBorder(4,4,4,4))); 070 071 JCheckBox enablePermissionManagerCheckBox = new JCheckBox(Bundle.getMessage( 072 "PermissionPreferencesPanel_EnablePermissionManager")); 073 enablePermissionManagerCheckBox.setSelected(_temporaryPermissionManager.isEnabled()); 074 enablePermissionManagerCheckBox.addActionListener((evt) -> { 075 if (enablePermissionManagerCheckBox.isSelected()) { 076 // Ask for confirmation before turning Permission Manager on 077 if (JmriJOptionPane.YES_OPTION == JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("PermissionPreferencesPanel_WarnStartPermissions"), Bundle.getMessage("WarningTitle"), JmriJOptionPane.YES_NO_OPTION)) { 078 _temporaryPermissionManager.setEnabled(enablePermissionManagerCheckBox.isSelected()); 079 _dirty = true; 080 } else { 081 enablePermissionManagerCheckBox.setSelected(false); 082 } 083 } else { 084 _temporaryPermissionManager.setEnabled(false); 085 _dirty = true; 086 } 087 }); 088 settingsPanel.add(enablePermissionManagerCheckBox); 089 090 JCheckBox allowEmptyPasswordsCheckBox = new JCheckBox(Bundle.getMessage( 091 "PermissionPreferencesPanel_AllowEmptyPasswords")); 092 allowEmptyPasswordsCheckBox.setSelected(_temporaryPermissionManager.isAllowEmptyPasswords()); 093 allowEmptyPasswordsCheckBox.addActionListener((evt) -> { 094 _temporaryPermissionManager.setAllowEmptyPasswords(allowEmptyPasswordsCheckBox.isSelected()); 095 _dirty = true; 096 }); 097 settingsPanel.add(allowEmptyPasswordsCheckBox); 098 099 outerPanel.add(settingsPanel); 100 101 outerPanel.add(Box.createVerticalStrut(10)); 102 103 JPanel rolesPanel = new JPanel(); 104 rolesPanel.setLayout(new BoxLayout(rolesPanel, BoxLayout.PAGE_AXIS)); 105 106 for (Role role : roleList) { 107 rolesTabbedPane.addTab(role.getName(), new JScrollPane( 108 getRolePanel(role, rolesTabbedPane, usersTabbedPane, 109 roleList, userList))); 110 } 111 112 rolesPanel.add(rolesTabbedPane); 113 114 JButton addRoleButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_AddRole")); 115 addRoleButton.addActionListener((evt) -> { createNewRole(rolesTabbedPane, usersTabbedPane, roleList, userList); }); 116 rolesPanel.add(addRoleButton); 117 118 119 JPanel usersPanel = new JPanel(); 120 usersPanel.setLayout(new BoxLayout(usersPanel, BoxLayout.PAGE_AXIS)); 121 122 reloadUsersTabbedPane(usersTabbedPane, roleList, userList); 123 124 usersPanel.add(usersTabbedPane); 125 126 JButton addUserButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_AddUser")); 127 addUserButton.addActionListener((evt) -> { 128 new AddUserDialog(_temporaryPermissionManager, getFrame(), (user) -> { 129 // Find the index of the new user 130 userList.clear(); 131 userList.addAll(_temporaryPermissionManager.getUsers()); 132 userList.sort((a,b) -> { 133 if (a.getPriority() != b.getPriority()) { 134 return Integer.compare(b.getPriority(), a.getPriority()); 135 } 136 return a.getUserName().toLowerCase().compareTo(b.getUserName().toLowerCase()); 137 }); 138 usersTabbedPane.insertTab(user.getUserName(), null, 139 new JScrollPane(getUserPanel(user, usersTabbedPane, roleList, userList)), 140 null, userList.indexOf(user)); 141 getFrame().pack(); 142 _dirty = true; 143 }).setVisible(true); 144 }); 145 usersPanel.add(addUserButton); 146 147 usersPanel.add(Box.createGlue()); 148 149 JTabbedPane tabbedPane = new JTabbedPane(); 150 tabbedPane.addTab(Bundle.getMessage("PermissionPreferencesPanel_Roles"), 151 new JScrollPane(rolesPanel)); 152 tabbedPane.addTab(Bundle.getMessage("PermissionPreferencesPanel_Users"), 153 new JScrollPane(usersPanel)); 154 155 JPanel outerTabbedPanel = new JPanel(); 156 outerTabbedPanel.add(tabbedPane); 157 outerPanel.add(outerTabbedPanel); 158 add(outerPanel); 159 } 160 161 private Frame getFrame() { 162 Container c = this; 163 while (c != null && !(c instanceof Frame)) { 164 c = c.getParent(); 165 } 166 // c is either a Frame or null 167 return (Frame)c; 168 } 169 170 private void createNewRole(JTabbedPane rolesTabbedPane, 171 JTabbedPane usersTabbedPane, List<Role> roleList, List<User> userList) { 172 173 String roleName = JOptionPane.showInputDialog(getFrame(), 174 Bundle.getMessage("PermissionPreferencesPanel_EnterRoleName")); 175 176 if (roleName == null) { 177 return; // User selected "Cancel" 178 } 179 180 if (roleName.isBlank()) { 181 JmriJOptionPane.showMessageDialog(null, 182 Bundle.getMessage("PermissionPreferencesPanel_NameEmpty"), 183 jmri.Application.getApplicationName(), 184 JmriJOptionPane.ERROR_MESSAGE); 185 return; 186 } 187 188 if (!roleName.equals(roleName.trim())) { 189 JmriJOptionPane.showMessageDialog(null, 190 Bundle.getMessage("PermissionPreferencesPanel_SpaceNotAllowedInRoleName"), 191 jmri.Application.getApplicationName(), 192 JmriJOptionPane.ERROR_MESSAGE); 193 return; 194 } 195 196 try { 197 Role role = _temporaryPermissionManager.addRole(roleName); 198 199 // Find the index of the new role 200 roleList.clear(); 201 roleList.addAll(_temporaryPermissionManager.getRoles()); 202 roleList.sort((a,b) -> { 203 if (a.getPriority() != b.getPriority()) { 204 return Integer.compare(b.getPriority(), a.getPriority()); 205 } 206 return a.getName().toLowerCase().compareTo(b.getName().toLowerCase()); 207 }); 208 209 rolesTabbedPane.insertTab(role.getName(), null, 210 new JScrollPane(getRolePanel(role, rolesTabbedPane, 211 usersTabbedPane, roleList, userList)), 212 null, roleList.indexOf(role)); 213 214 reloadUsersTabbedPane(usersTabbedPane, roleList, userList); 215 getFrame().pack(); 216 _dirty = true; 217 218 } catch (PermissionManager.RoleAlreadyExistsException e) { 219 JmriJOptionPane.showMessageDialog(null, 220 Bundle.getMessage("PermissionPreferencesPanel_RoleNameExists"), 221 jmri.Application.getApplicationName(), 222 JmriJOptionPane.ERROR_MESSAGE); 223 } 224 } 225 226 private JPanel getRolePanel(Role role, JTabbedPane rolesTabbedPane, 227 JTabbedPane usersTabbedPane, List<Role> roleList, List<User> userList) { 228 229 JPanel rolePanel = new JPanel(); 230 rolePanel.setLayout(new GridBagLayout()); 231 GridBagConstraints c = new GridBagConstraints(); 232 c.gridwidth = 3; 233 c.gridheight = 1; 234 c.gridx = 0; 235 c.gridy = 0; 236 c.anchor = java.awt.GridBagConstraints.WEST; 237 238 JLabel roleLabel = new JLabel("<html><font size=\"+1\"><b>"+role.getName()+"</b></font></html>"); 239 roleLabel.setBorder(new EmptyBorder(4,4,0,4)); 240 rolePanel.add(roleLabel, c); 241 c.gridy++; 242 243 List<PermissionOwner> owners = new ArrayList<>(_temporaryPermissionManager.getOwners()); 244 owners.sort((a,b) -> {return a.getName().compareTo(b.getName());}); 245 for (PermissionOwner owner : owners) { 246 247 JLabel ownerLabel = new JLabel("<html><font size=\"0.5\"><b>"+owner.getName()+"</b></font></html>"); 248 ownerLabel.setBorder(new EmptyBorder(15,4,4,4)); 249 rolePanel.add(ownerLabel, c); 250 c.gridy++; 251 252 List<Permission> permissions = new ArrayList<>(_temporaryPermissionManager.getPermissions(owner)); 253 permissions.sort((a,b) -> { return a.getName().compareTo(b.getName()); }); 254 for (Permission permission : permissions) { 255 PermissionSwing permissionSwing = 256 PermissionSwingTools.getPermissionSwingForClass(permission); 257 JLabel label = permissionSwing.getLabel(permission); 258 if (label != null) { 259 c.gridwidth = 1; 260 c.gridx = 0; 261 rolePanel.add(label, c); 262 c.gridx = 1; 263 rolePanel.add(Box.createHorizontalStrut(5), c); 264 c.gridx = 2; 265 } 266 rolePanel.add(permissionSwing.getComponent( 267 role, permission, this::setDirtyFlag), c); 268 c.gridy++; 269 c.gridx = 0; 270 c.gridwidth = 3; 271 } 272 } 273 274 rolePanel.add(Box.createVerticalStrut(10)); 275 JButton removeRoleButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_RemoveRole")); 276 removeRoleButton.addActionListener((evt) -> { 277 if (JmriJOptionPane.YES_OPTION == JmriJOptionPane.showConfirmDialog( 278 null, 279 Bundle.getMessage("PermissionPreferencesPanel_RemoveRoleConfirmation", role.getName()), 280 Bundle.getMessage("PermissionPreferencesPanel_RemoveRoleTitle"), 281 JmriJOptionPane.YES_NO_OPTION)) { 282 try { 283 _temporaryPermissionManager.removeRole(role.getName()); 284 rolesTabbedPane.remove(roleList.indexOf(role)); 285 roleList.remove(role); 286 reloadUsersTabbedPane(usersTabbedPane, roleList, userList); 287 getFrame().pack(); 288 _dirty = true; 289 } catch (PermissionManager.RoleDoesNotExistException e) { 290 log.error("Unexpected exception", e); 291 } 292 } 293 }); 294 if (role.isSystemRole()) { 295 removeRoleButton.setEnabled(false); 296 } 297 c.gridy++; 298 rolePanel.add(Box.createVerticalStrut(5), c); 299 c.gridy++; 300 c.anchor = GridBagConstraints.CENTER; 301 rolePanel.add(removeRoleButton, c); 302 303 return rolePanel; 304 } 305 306 private void setDirtyFlag() { 307 _dirty = true; 308 } 309 310 private void reloadUsersTabbedPane(JTabbedPane usersTabbedPane, 311 List<Role> roleList, List<User> userList) { 312 313 usersTabbedPane.removeAll(); 314 for (User user : userList) { 315 usersTabbedPane.addTab(user.getUserName(), new JScrollPane( 316 getUserPanel(user, usersTabbedPane, roleList, userList))); 317 } 318 } 319 320 private JPanel getUserPanel(User user, JTabbedPane usersTabbedPane, 321 List<Role> roleList, List<User> userList) { 322 JPanel userPanel = new JPanel(); 323 userPanel.setLayout(new BoxLayout(userPanel, BoxLayout.PAGE_AXIS)); 324 325 UserFields userFields = new UserFields(); 326 _userFieldsMap.put(user, userFields); 327 328 JLabel usernameLabel = new JLabel("<html><font size=\"+1\"><b>"+user.getUserName()+"</b></font></html>"); 329 usernameLabel.setBorder(new EmptyBorder(4,4,4,4)); 330 userPanel.add(usernameLabel); 331 userPanel.add(new JLabel(Bundle.getMessage("PermissionPreferencesPanel_Name"))); 332 userFields._nameTextField = new JTextField(20); 333 userFields._nameTextField.setText(user.getName()); 334 userPanel.add(userFields._nameTextField); 335 userPanel.add(new JLabel(Bundle.getMessage("PermissionPreferencesPanel_Comment"))); 336 userFields._commentTextField = new JTextField(40); 337 userFields._commentTextField.setText(user.getComment()); 338 userPanel.add(userFields._commentTextField); 339 340 userPanel.add(Box.createVerticalStrut(10)); 341 342 userPanel.add(new JLabel(Bundle.getMessage("PermissionPreferencesPanel_Roles"))); 343 userPanel.add(Box.createVerticalStrut(5)); 344 345 int lastPriority = 0; 346 for (Role role : roleList) { 347 if (role.getPriority() == 0 && lastPriority != 0) { 348 userPanel.add(Box.createVerticalStrut(10)); 349 } 350 JCheckBox checkBox = new JCheckBox(role.getName()); 351 checkBox.setSelected(user.getRoles().contains(role)); 352 checkBox.addActionListener((evt) -> { 353 if (checkBox.isSelected()) { 354 user.addRole(role); 355 } else { 356 user.removeRole(role); 357 } 358 _dirty = true; 359 }); 360 userPanel.add(checkBox); 361 lastPriority = role.getPriority(); 362 } 363 364 userPanel.add(Box.createVerticalStrut(10)); 365 366 JButton changePasswordButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_ChangePassword")); 367 changePasswordButton.setEnabled(!_temporaryPermissionManager.isAGuestUser(user)); 368 changePasswordButton.addActionListener((evt) -> { 369 new ChangeUserPasswordDialog( 370 _temporaryPermissionManager, getFrame(), user, ()->{_dirty = true;}) 371 .setVisible(true); 372 }); 373 userPanel.add(changePasswordButton); 374 375 JButton removeUserButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_RemoveUser")); 376 removeUserButton.addActionListener((evt) -> { 377 if (JmriJOptionPane.YES_OPTION == JmriJOptionPane.showConfirmDialog( 378 null, 379 Bundle.getMessage("PermissionPreferencesPanel_RemoveUserConfirmation", user.getUserName(), user.getName()), 380 Bundle.getMessage("PermissionPreferencesPanel_RemoveUserTitle"), 381 JmriJOptionPane.YES_NO_OPTION)) { 382 try { 383 _temporaryPermissionManager.removeUser(user.getUserName()); 384 usersTabbedPane.remove(userList.indexOf(user)); 385 userList.remove(user); 386 _dirty = true; 387 } catch (PermissionManager.UserDoesNotExistException e) { 388 log.error("Unexpected exception", e); 389 } 390 } 391 }); 392 if (user.isSystemUser()) { 393 removeUserButton.setEnabled(false); 394 } 395 userPanel.add(removeUserButton); 396 397 return userPanel; 398 } 399 400 @Override 401 public String getPreferencesItem() { 402 return "PREFERENCES"; // NOI18N 403 } 404 405 @Override 406 public String getPreferencesItemText() { 407 return Bundle.getMessage("MenuPermission"); // NOI18N 408 } 409 410 @Override 411 public String getTabbedPreferencesTitle() { 412 return getPreferencesItemText(); 413 } 414 415 @Override 416 public String getLabelKey() { 417 return null; 418 } 419 420 @Override 421 public JComponent getPreferencesComponent() { 422 return this; 423 } 424 425 @Override 426 public boolean isPersistant() { 427 return false; 428 } 429 430 @Override 431 public String getPreferencesTooltip() { 432 return null; 433 } 434 435 @Override 436 public void savePreferences() { 437 for (var entry : _userFieldsMap.entrySet()) { 438 entry.getKey().setName(entry.getValue()._nameTextField.getText()); 439 entry.getKey().setComment(entry.getValue()._commentTextField.getText()); 440 } 441 _temporaryPermissionManager.storePermissionSettings(); 442 _dirty = false; 443 } 444 445 @Override 446 public boolean isDirty() { 447 return _dirty; 448 } 449 450 @Override 451 public boolean isRestartRequired() { 452 return true; 453 } 454 455 @Override 456 public boolean isPreferencesValid() { 457 return true; 458 } 459 460// @Override 461// public int getSortOrder() { 462// return PreferencesPanel.super.getSortOrder(); 463// } 464 465 @Override 466 public BooleanSupplier getIsEnabled() { 467 return () -> { 468 return InstanceManager.getDefault(PermissionManager.class) 469 .ensureAtLeastPermission(PermissionsSystemAdmin.PERMISSION_EDIT_PREFERENCES, 470 BooleanPermission.BooleanValue.TRUE); 471 }; 472 } 473 474 475 private static class UserFields { 476 JTextField _nameTextField; 477 JTextField _commentTextField; 478 } 479 480 481 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PermissionPreferencesPanel.class); 482}