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.jmrit.permission.DefaultPermissionManager; 013import jmri.swing.PreferencesPanel; 014import jmri.util.swing.JmriJOptionPane; 015 016import org.openide.util.lookup.ServiceProvider; 017 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 permissionManager; 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 permissionManager = (DefaultPermissionManager)mngr; 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<>(permissionManager.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<>(permissionManager.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(permissionManager.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 permissionManager.setEnabled(enablePermissionManagerCheckBox.isSelected()); 079 _dirty = true; 080 } else { 081 enablePermissionManagerCheckBox.setSelected(false); 082 } 083 } 084 }); 085 settingsPanel.add(enablePermissionManagerCheckBox); 086 087 JCheckBox allowEmptyPasswordsCheckBox = new JCheckBox(Bundle.getMessage( 088 "PermissionPreferencesPanel_AllowEmptyPasswords")); 089 allowEmptyPasswordsCheckBox.setSelected(permissionManager.isAllowEmptyPasswords()); 090 allowEmptyPasswordsCheckBox.addActionListener((evt) -> { 091 permissionManager.setAllowEmptyPasswords(allowEmptyPasswordsCheckBox.isSelected()); 092 _dirty = true; 093 }); 094 settingsPanel.add(allowEmptyPasswordsCheckBox); 095 096 outerPanel.add(settingsPanel); 097 098 outerPanel.add(Box.createVerticalStrut(10)); 099 100 JPanel rolesPanel = new JPanel(); 101 rolesPanel.setLayout(new BoxLayout(rolesPanel, BoxLayout.PAGE_AXIS)); 102 103 for (Role role : roleList) { 104 rolesTabbedPane.addTab(role.getName(), new JScrollPane( 105 getRolePanel(role, rolesTabbedPane, usersTabbedPane, 106 roleList, userList))); 107 } 108 109 rolesPanel.add(rolesTabbedPane); 110 111 JButton addRoleButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_AddRole")); 112 addRoleButton.addActionListener((evt) -> { createNewRole(rolesTabbedPane, usersTabbedPane, roleList, userList); }); 113 rolesPanel.add(addRoleButton); 114 115 116 JPanel usersPanel = new JPanel(); 117 usersPanel.setLayout(new BoxLayout(usersPanel, BoxLayout.PAGE_AXIS)); 118 119 reloadUsersTabbedPane(usersTabbedPane, roleList, userList); 120 121 usersPanel.add(usersTabbedPane); 122 123 JButton addUserButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_AddUser")); 124 addUserButton.addActionListener((evt) -> { 125 new AddUserDialog(getFrame(), (user) -> { 126 // Find the index of the new user 127 userList.clear(); 128 userList.addAll(permissionManager.getUsers()); 129 userList.sort((a,b) -> { 130 if (a.getPriority() != b.getPriority()) { 131 return Integer.compare(b.getPriority(), a.getPriority()); 132 } 133 return a.getUserName().toLowerCase().compareTo(b.getUserName().toLowerCase()); 134 }); 135 usersTabbedPane.insertTab(user.getUserName(), null, 136 new JScrollPane(getUserPanel(user, usersTabbedPane, roleList, userList)), 137 null, userList.indexOf(user)); 138 getFrame().pack(); 139 _dirty = true; 140 }).setVisible(true); 141 }); 142 usersPanel.add(addUserButton); 143 144 145 JTabbedPane tabbedPane = new JTabbedPane(); 146 tabbedPane.addTab(Bundle.getMessage("PermissionPreferencesPanel_Roles"), 147 new JScrollPane(rolesPanel)); 148 tabbedPane.addTab(Bundle.getMessage("PermissionPreferencesPanel_Users"), 149 new JScrollPane(usersPanel)); 150 151 JPanel outerTabbedPanel = new JPanel(); 152 outerTabbedPanel.add(tabbedPane); 153 outerPanel.add(outerTabbedPanel); 154 add(outerPanel); 155 } 156 157 private Frame getFrame() { 158 Container c = this; 159 while (c != null && !(c instanceof Frame)) { 160 c = c.getParent(); 161 } 162 // c is either a Frame or null 163 return (Frame)c; 164 } 165 166 private void createNewRole(JTabbedPane rolesTabbedPane, 167 JTabbedPane usersTabbedPane, List<Role> roleList, List<User> userList) { 168 169 String roleName = JOptionPane.showInputDialog(getFrame(), 170 Bundle.getMessage("PermissionPreferencesPanel_EnterRoleName")); 171 172 if (roleName == null) { 173 return; // User selected "Cancel" 174 } 175 176 if (roleName.isBlank()) { 177 JmriJOptionPane.showMessageDialog(null, 178 Bundle.getMessage("PermissionPreferencesPanel_NameEmpty"), 179 jmri.Application.getApplicationName(), 180 JmriJOptionPane.ERROR_MESSAGE); 181 return; 182 } 183 184 if (!roleName.equals(roleName.trim())) { 185 JmriJOptionPane.showMessageDialog(null, 186 Bundle.getMessage("PermissionPreferencesPanel_SpaceNotAllowedInRoleName"), 187 jmri.Application.getApplicationName(), 188 JmriJOptionPane.ERROR_MESSAGE); 189 return; 190 } 191 192 try { 193 Role role = permissionManager.addRole(roleName); 194 195 // Find the index of the new role 196 roleList.clear(); 197 roleList.addAll(permissionManager.getRoles()); 198 roleList.sort((a,b) -> { 199 if (a.getPriority() != b.getPriority()) { 200 return Integer.compare(b.getPriority(), a.getPriority()); 201 } 202 return a.getName().toLowerCase().compareTo(b.getName().toLowerCase()); 203 }); 204 205 rolesTabbedPane.insertTab(role.getName(), null, 206 new JScrollPane(getRolePanel(role, rolesTabbedPane, 207 usersTabbedPane, roleList, userList)), 208 null, roleList.indexOf(role)); 209 210 reloadUsersTabbedPane(usersTabbedPane, roleList, userList); 211 getFrame().pack(); 212 _dirty = true; 213 214 } catch (PermissionManager.RoleAlreadyExistsException e) { 215 JmriJOptionPane.showMessageDialog(null, 216 Bundle.getMessage("PermissionPreferencesPanel_RoleNameExists"), 217 jmri.Application.getApplicationName(), 218 JmriJOptionPane.ERROR_MESSAGE); 219 } 220 } 221 222 private JPanel getRolePanel(Role role, JTabbedPane rolesTabbedPane, 223 JTabbedPane usersTabbedPane, List<Role> roleList, List<User> userList) { 224 JPanel rolePanel = new JPanel(); 225 rolePanel.setLayout(new BoxLayout(rolePanel, BoxLayout.PAGE_AXIS)); 226 227 JLabel roleLabel = new JLabel("<html><font size=\"+1\"><b>"+role.getName()+"</b></font></html>"); 228 roleLabel.setBorder(new EmptyBorder(4,4,0,4)); 229 rolePanel.add(roleLabel); 230 231 for (PermissionOwner owner : permissionManager.getOwners()) { 232 JPanel ownerPanel = new JPanel(); 233 ownerPanel.setLayout(new BoxLayout(ownerPanel, BoxLayout.PAGE_AXIS)); 234 235 JLabel ownerLabel = new JLabel("<html><font size=\"0.5\"><b>"+owner.getName()+"</b></font></html>"); 236 ownerLabel.setBorder(new EmptyBorder(15,4,4,4)); 237 rolePanel.add(ownerLabel); 238 239 for (Permission permission : permissionManager.getPermissions(owner)) { 240 JCheckBox checkBox = new JCheckBox(permission.getName()); 241 checkBox.setSelected(role.hasPermission(permission)); 242 checkBox.addActionListener((evt) -> { 243 role.setPermission(permission, checkBox.isSelected()); 244 _dirty = true; 245 }); 246 ownerPanel.add(checkBox); 247 } 248 rolePanel.add(ownerPanel); 249 } 250 251 rolePanel.add(Box.createVerticalStrut(10)); 252 JButton removeRoleButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_RemoveRole")); 253 removeRoleButton.addActionListener((evt) -> { 254 if (JmriJOptionPane.YES_OPTION == JmriJOptionPane.showConfirmDialog( 255 null, 256 Bundle.getMessage("PermissionPreferencesPanel_RemoveRoleConfirmation", role.getName()), 257 Bundle.getMessage("PermissionPreferencesPanel_RemoveRoleTitle"), 258 JmriJOptionPane.YES_NO_OPTION)) { 259 try { 260 permissionManager.removeRole(role.getName()); 261 rolesTabbedPane.remove(roleList.indexOf(role)); 262 roleList.remove(role); 263 reloadUsersTabbedPane(usersTabbedPane, roleList, userList); 264 getFrame().pack(); 265 _dirty = true; 266 } catch (PermissionManager.RoleDoesNotExistException e) { 267 log.error("Unexpected exception", e); 268 } 269 } 270 }); 271 if (role.isSystemRole()) { 272 removeRoleButton.setEnabled(false); 273 } 274 rolePanel.add(removeRoleButton); 275 276 return rolePanel; 277 } 278 279 private void reloadUsersTabbedPane(JTabbedPane usersTabbedPane, 280 List<Role> roleList, List<User> userList) { 281 282 usersTabbedPane.removeAll(); 283 for (User user : userList) { 284 usersTabbedPane.addTab(user.getUserName(), new JScrollPane( 285 getUserPanel(user, usersTabbedPane, roleList, userList))); 286 } 287 } 288 289 private JPanel getUserPanel(User user, JTabbedPane usersTabbedPane, 290 List<Role> roleList, List<User> userList) { 291 JPanel userPanel = new JPanel(); 292 userPanel.setLayout(new BoxLayout(userPanel, BoxLayout.PAGE_AXIS)); 293 294 UserFields userFields = new UserFields(); 295 _userFieldsMap.put(user, userFields); 296 297 JLabel usernameLabel = new JLabel("<html><font size=\"+1\"><b>"+user.getUserName()+"</b></font></html>"); 298 usernameLabel.setBorder(new EmptyBorder(4,4,4,4)); 299 userPanel.add(usernameLabel); 300 userPanel.add(new JLabel(Bundle.getMessage("PermissionPreferencesPanel_Name"))); 301 userFields._nameTextField = new JTextField(20); 302 userFields._nameTextField.setText(user.getName()); 303 userPanel.add(userFields._nameTextField); 304 userPanel.add(new JLabel(Bundle.getMessage("PermissionPreferencesPanel_Comment"))); 305 userFields._commentTextField = new JTextField(40); 306 userFields._commentTextField.setText(user.getComment()); 307 userPanel.add(userFields._commentTextField); 308 309 userPanel.add(Box.createVerticalStrut(10)); 310 311 userPanel.add(new JLabel(Bundle.getMessage("PermissionPreferencesPanel_Roles"))); 312 userPanel.add(Box.createVerticalStrut(5)); 313 314 int lastPriority = 0; 315 for (Role role : roleList) { 316 if (role.getPriority() == 0 && lastPriority != 0) { 317 userPanel.add(Box.createVerticalStrut(10)); 318 } 319 JCheckBox checkBox = new JCheckBox(role.getName()); 320 checkBox.setSelected(user.getRoles().contains(role)); 321 checkBox.addActionListener((evt) -> { 322 if (checkBox.isSelected()) { 323 user.addRole(role); 324 } else { 325 user.removeRole(role); 326 } 327 _dirty = true; 328 }); 329 userPanel.add(checkBox); 330 lastPriority = role.getPriority(); 331 } 332 333 userPanel.add(Box.createVerticalStrut(10)); 334 335 JButton changePasswordButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_ChangePassword")); 336 changePasswordButton.setEnabled(!permissionManager.isGuestUser(user)); 337 changePasswordButton.addActionListener((evt) -> { 338 new ChangeUserPasswordDialog(getFrame(), user, ()->{_dirty = true;}) 339 .setVisible(true); 340 }); 341 userPanel.add(changePasswordButton); 342 343 JButton removeUserButton = new JButton(Bundle.getMessage("PermissionPreferencesPanel_RemoveUser")); 344 removeUserButton.addActionListener((evt) -> { 345 if (JmriJOptionPane.YES_OPTION == JmriJOptionPane.showConfirmDialog( 346 null, 347 Bundle.getMessage("PermissionPreferencesPanel_RemoveUserConfirmation", user.getUserName(), user.getName()), 348 Bundle.getMessage("PermissionPreferencesPanel_RemoveUserTitle"), 349 JmriJOptionPane.YES_NO_OPTION)) { 350 try { 351 permissionManager.removeUser(user.getUserName()); 352 usersTabbedPane.remove(userList.indexOf(user)); 353 userList.remove(user); 354 _dirty = true; 355 } catch (PermissionManager.UserDoesNotExistException e) { 356 log.error("Unexpected exception", e); 357 } 358 } 359 }); 360 if (user.isSystemUser()) { 361 removeUserButton.setEnabled(false); 362 } 363 userPanel.add(removeUserButton); 364 365 return userPanel; 366 } 367 368 @Override 369 public String getPreferencesItem() { 370 return "PREFERENCES"; // NOI18N 371 } 372 373 @Override 374 public String getPreferencesItemText() { 375 return Bundle.getMessage("MenuPermission"); // NOI18N 376 } 377 378 @Override 379 public String getTabbedPreferencesTitle() { 380 return getPreferencesItemText(); 381 } 382 383 @Override 384 public String getLabelKey() { 385 return null; 386 } 387 388 @Override 389 public JComponent getPreferencesComponent() { 390 return this; 391 } 392 393 @Override 394 public boolean isPersistant() { 395 return false; 396 } 397 398 @Override 399 public String getPreferencesTooltip() { 400 return null; 401 } 402 403 @Override 404 public void savePreferences() { 405 for (var entry : _userFieldsMap.entrySet()) { 406 entry.getKey().setName(entry.getValue()._nameTextField.getText()); 407 entry.getKey().setComment(entry.getValue()._commentTextField.getText()); 408 } 409 permissionManager.storePermissionSettings(); 410 _dirty = false; 411 } 412 413 @Override 414 public boolean isDirty() { 415 return _dirty; 416 } 417 418 @Override 419 public boolean isRestartRequired() { 420 return true; 421 } 422 423 @Override 424 public boolean isPreferencesValid() { 425 return true; 426 } 427 428// @Override 429// public int getSortOrder() { 430// return PreferencesPanel.super.getSortOrder(); 431// } 432 433 @Override 434 public BooleanSupplier getIsEnabled() { 435 return () -> { 436 return InstanceManager.getDefault(PermissionManager.class) 437 .checkPermission(PermissionsSystemAdmin.PERMISSION_EDIT_PERMISSIONS); 438 }; 439 } 440 441 442 private static class UserFields { 443 JTextField _nameTextField; 444 JTextField _commentTextField; 445 } 446 447 448 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PermissionPreferencesPanel.class); 449}