/* * ConfigViewImpl.java * * Copyright (c) 2003-2004 Digi International * This program and the information contained in it is confidential and * proprietary to Digi International and may not be used, copied, or re- * produced without the prior written permission of Digi International. * */ package com.digi.config.ui; import com.digi.config.core.*; import com.digi.config.util.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.border.*; import javax.swing.text.*; import java.awt.*; import java.util.*; import java.net.*; import java.io.Serializable; import java.text.*; /** * This interface defines the basic operations required for all configuration views * that are used in the configuration application. */ public abstract class ConfigViewImpl implements ConfigView { /** The device we are configuring */ Device device; protected boolean active; protected boolean editView; protected boolean includeSettingsFields; protected boolean includeStateFields; /** Generic heading label based on view name */ JLabel heading; /** Generic button panel with Save, Cancel, Refresh, & Help */ private JPanel buttonPanel; /** * Basic constructor of a readonly config view */ public ConfigViewImpl() throws Exception { this(false); } /** * Constructor that specifies if this view allows editting of the kvpGroup. If it * does, then the view will show the Save & Cancel buttons in the button panel. * @param editView identifies if this view can edit the device kvpGroup */ public ConfigViewImpl(boolean editView) throws Exception { this.initializeActions(); active = false; this.editView = editView; includeSettingsFields = true; includeStateFields = false; } /** * Directs the view to Save and Refresh Setting data. * * @param flag is true if State data is to be included in view processing. */ public void setIncludeSettingsFields(boolean flag) { includeSettingsFields = flag; } /** * Directs the view to Save and Refresh State data. * * @param flag is true if State data is to be included in view processing. */ public void setIncludeStateFields(boolean flag) { includeStateFields = flag; } /** * Returns the Component that displays the heading of the view. * If this view has no heading to display this method returns null. */ public Component getViewHeading() { if (heading==null) { heading = new JLabel(ConfigResource.getUiRbString(getName()+"Title")); heading.setBackground(new Color(0, 0, 139)); heading.setForeground(Color.WHITE); heading.setOpaque(true); } return heading; } /** * Returns the Component that displays the buttons below the view. * If this view has no buttons to display this method returns null. * * Default buttons provide ability to Save changes, Cancel changes, Refresh kvpGroup, and get Help */ public Component getViewButtons(){ if (buttonPanel==null) { buttonPanel = new CustomPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); // Add standard Config View Action Buttons if (editView) { buttonPanel.add(Box.createHorizontalGlue()); buttonPanel.add(new JButton(saveChangesAction)); buttonPanel.add(Box.createHorizontalGlue()); buttonPanel.add(new JButton(cancelChangesAction)); } buttonPanel.add(Box.createHorizontalGlue()); buttonPanel.add(new JButton(refreshAction)); //buttonPanel.add(Box.createHorizontalGlue()); Panel help disabled for initial release //buttonPanel.add(new JButton(viewHelpAction)); buttonPanel.add(Box.createHorizontalGlue()); } return buttonPanel; } /** * Informs view what device to work with. Subclass Views should flush any * cached device data and mark current view content as invalid * so that it is refreshed appropriatly. */ public void setDevice(Device device) { // update device reference this.device = device; } /** * This method is called to instruct the view that it is about to be made * active. When a view is active it needs to make sure its content is correct. * An example of why a panel may be inactive is if it were on a tabbed pane * and was not currently visible or if the user selected some other view. * * Views can use this method to create their content on first touch or to refresh their * content when the device kvpGroup have been reset. */ public void activate() { // Default implementation is to simply mark the panel active. active = true; } /** * This method is called to instruct the view that it is about to be made * inactive. When a view is inactive, it does not need to worry * about maintaining its content in a correct state. An example of why a panel * may be inactive is if it were on a tabbed pane and was not currently visible * or if the user selected some other view. */ public void deactivate() { // Default implementation is to simply mark the panel inactive active = false; } /** * Returns a resource key to the help information for this view. The actual * URL will be looked up in the Help Resource bundle. The default behavior is * to base the resource key off the view name */ public String getHelpResource(){ return this.getName()+"Help"; } /** * This method instructs the view to validate any of the changes the user has made * within the view. Any errors are to be added to the provided errorList. * * @param errorList is a collection of ViewValidationError objects */ public void validateChanges(Collection errorList) { // Default implementation is to not check for errors } ////////////////////////////////////////////////////////////////////////////////////// // Internal Support Methods ////////////////////////////////////////////////////////////////////////////////////// ConfigAction saveChangesAction; ConfigAction cancelChangesAction; ConfigAction refreshAction; ConfigAction viewHelpAction; /** * Defines the main actions that can be invoked from the menus or * toolbar buttons. These actions will be used to construct the menus & * toolbar buttons. */ protected void initializeActions() throws Exception { saveChangesAction = new ConfigAction("SaveChanges", this, "doSaveChangesAction"); cancelChangesAction = new ConfigAction("CancelChanges", this, "doCancelChangesAction"); refreshAction = new ConfigAction("Refresh", this, "doRefreshAction"); viewHelpAction = new ConfigAction("ViewHelp", this, "doViewHelpAction"); } // // Action Methods offered by this view to its subclasses. // /** * This action saves any user modified Fields in the view to the device */ public void doSaveChangesAction() { Busy.begin(ConfigResource.getUiRbString("SaveChangesStatus")); SystemLog.debug("ConfigViewImpl.doSaveChangesAction invoked"); // If the view has changes if (this.isChanged()) { // If view has changes, have it validate them Vector errorList = new Vector(); this.validateChanges(errorList); if (errorList.size()>0) { // If there are validation errors, display them in a dialog StringBuffer msgBuff = new StringBuffer(); for (Iterator i=errorList.iterator(); i.hasNext();) { ValidationError error = (ValidationError)i.next(); if (error.getDetailedMsg()!=null) { msgBuff.append(error.getDetailedMsg()+"\n"); } else { msgBuff.append(error.getMsg()+"\n"); } } // popup a dialog describing the error StringBuffer popupMsg = new StringBuffer(); popupMsg.append(ConfigResource.getUiRbString("ValidationErrorDesc")+"\n"); popupMsg.append(msgBuff); JOptionPane.showMessageDialog(buttonPanel, popupMsg.toString(), ConfigResource.getUiRbString("ValidationErrorTitle"), JOptionPane.ERROR_MESSAGE); // Also add a log entry SystemLog.log("ValidationError", new Serializable[] {msgBuff.toString()}); Busy.end(); return; // don't do the save until all validation errors have been fixed } // If the view has changes, get them KvpNode tempSettingTree = new KvpNode(); KvpNode tempStateTree = new KvpNode(); this.getChanges(tempSettingTree, tempStateTree); // now try saving them on the device try { if ((tempSettingTree.getAllGroups().size() > 0) && includeSettingsFields) { device.setSettingTree(tempSettingTree); } if ((tempStateTree.getAllGroups().size() > 0) && includeStateFields) { device.setStateTree(tempStateTree); } this.commitChanges(); SystemLog.log("Op1Succ",new Serializable[]{ConfigResource.getUiRbString("SaveChangesMenu")}); } catch (DeviceCommandException dce) { SystemLog.log("Op1Fail",new Serializable[]{ConfigResource.getUiRbString("SaveChangesMenu")},dce); } catch (DeviceValidationException dse) { // Find out what device fields are invalid SystemLog.debug("Invalid fields detected while saving to device", dse); KvpNode errorCluster = dse.getCluster(); Collection errors = errorCluster.getErrors(); StringBuffer msgBuff = new StringBuffer(); for (Iterator i=errors.iterator(); i.hasNext();) { RciCommandError error = (RciCommandError)i.next(); msgBuff.append(error.toString()+"\n"); } // popup a dialog showing the errors StringBuffer popupMsg = new StringBuffer(); popupMsg.append(ConfigResource.getUiRbString("ValidationErrorDesc")+"\n"); popupMsg.append(msgBuff); JOptionPane.showMessageDialog(buttonPanel, popupMsg.toString(), ConfigResource.getUiRbString("ValidationErrorTitle"), JOptionPane.ERROR_MESSAGE); // Also add a log entry SystemLog.log("ValidationError", new Serializable[] {msgBuff.toString()}); Busy.end(); return; // don't do the save until all validation errors have been fixed } } else { SystemLog.log("SaveNotRequired"); } Busy.end(); } /** * This action cancells any user modified field changes in the view and * reverts the view to its prior state or to a newly refreshed state. */ public void doCancelChangesAction() { // Tell view to cancel its changes and revert to current kvpGroup this.cancelChanges(); SystemLog.log("Op1Succ",new Serializable[]{ConfigResource.getUiRbString("CancelChangesMenu")}); } /** * Instructs the device proxy to refresh its cached settings which in turn * notifies device listeners of any change in setting state. */ public void doRefreshAction() { Busy.begin(ConfigResource.getUiRbString("RefreshStatus")); // Tell the device to refresh its settings. Note, that views who are // listening to device setting changes will receive notification if // field values change as a result of the refresh operation. try { if (includeSettingsFields) { device.refreshSettingTree(); // refresh the devices cached setting cluster } if (includeStateFields) { device.refreshStateTree(); // refresh the devices cached state cluster } this.cancelChanges(); // cancel any outstanding edits to the view SystemLog.log("Op1Succ",new Serializable[]{ConfigResource.getUiRbString("RefreshMenu")}); } catch (DeviceCommandException dce) { SystemLog.log("Op1Fail",new Serializable[]{ConfigResource.getUiRbString("RefreshMenu")}, dce); } Busy.end(); } /** * Displays help information on the current view */ public void doViewHelpAction() { SystemLog.debug("ConfigViewImpl.doHelpAction invoked"); String key = getHelpResource(); if (key==null) { SystemLog.log("NoHelpAvailable"); } else { SystemLog.debug("Launching view help . Help key = "+key); HelpDisplay.showHelp(key); } } /** * Creates a Text Field Document for Text Validation for Text Fields * requiring Integer input */ protected Document createIntegerDocument() { return new PlainDocument() { public void sendBeep() { java.awt.Toolkit.getDefaultToolkit().beep(); } public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (str == null) return; // Create Actual String String newString = null; if (getLength() == 0) newString = str; else if (offs == 0) newString = str + getText(0, getLength()); else if (offs == (getLength() - 1)) newString = getText(0, getLength()) + str; else newString = getText(0, offs) + str + getText(offs, getLength() - offs); // Verify Length if (newString.length() > 5) { sendBeep(); return; } // Verify only Numeric if (!newString.matches("^[0-9]+")) { sendBeep(); return; } // All is Good super.insertString(offs, new String(str), a); } }; } /** * Creates a Text Field Document for Text Validation for Text Fields * requiring Network Address input such as IP Addresses */ protected Document createNetworkAddressDocument() { return new PlainDocument() { public void sendBeep() { java.awt.Toolkit.getDefaultToolkit().beep(); } public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (str == null) return; // Create Actual String String newString = null; if (getLength() == 0) newString = str; else if (offs == 0) newString = str + getText(0, getLength()); else if (offs == (getLength() - 1)) newString = getText(0, getLength()) + str; else newString = getText(0, offs) + str + getText(offs, getLength() - offs); // Verify String only numbers and decimals if (!newString.matches("^[0-9.]*$")) { sendBeep(); return; } // Split String into each address and verify max of 4 String[] addressList = newString.split("[.]", -1); if (addressList.length > 4) { sendBeep(); return; } // Verify Each Address for Length and Value for (int i = 0; i < addressList.length; i++) { if (addressList[i].length() == 0) continue; if ((addressList[i].length() > 3) || (Integer.parseInt(addressList[i]) > 255)) { sendBeep(); return; } } // All is Good super.insertString(offs, new String(str), a); } }; } /** * Creates a Text Field Document for Text Validation for Text Fields * requiring any input - verifies no non-XML chars exist */ protected Document createGeneralDocument() { return new PlainDocument() { public void sendBeep() { java.awt.Toolkit.getDefaultToolkit().beep(); } public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (str == null) return; // Verify no invalid XML characters if (str.matches("[<>&]")) { sendBeep(); return; } // All is Good super.insertString(offs, new String(str), a); } }; } /** * Creates a Text Field Document for Text Validation for Text Fields * requiring Email addresses */ protected Document createEmailDocument() { return new PlainDocument() { public void sendBeep() { java.awt.Toolkit.getDefaultToolkit().beep(); } public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (str == null) return; // Create Actual String String newString = null; if (getLength() == 0) newString = str; else if (offs == 0) newString = str + getText(0, getLength()); else if (offs == (getLength() - 1)) newString = getText(0, getLength()) + str; else newString = getText(0, offs) + str + getText(offs, getLength() - offs); // Verify String valid email address characters if (!newString.matches("^[a-zA-Z0-9_.@-]*$")) { sendBeep(); return; } // Verify only 1 '@' int count = 0; for (int i = 0; i < newString.length(); i++) { if (newString.charAt(i) == '@') count++; if (count > 1) { sendBeep(); return; } } // All is Good super.insertString(offs, new String(str), a); } }; } }