Search in sources :

Example 56 with JTextComponent

use of javax.swing.text.JTextComponent in project CCDD by nasa.

the class CcddKeyboardHandler method setKeyboardHandler.

/**
 ********************************************************************************************
 * Adjust the handling of Enter and space key inputs in order to activate dialog controls, and
 * keyboard focus changes in order to use the arrow keys like Tab keys
 ********************************************************************************************
 */
private void setKeyboardHandler() {
    // Get the keyboard focus manager
    focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    // Listen for key presses
    focusManager.addKeyEventDispatcher(new KeyEventDispatcher() {

        boolean isShowMacros = false;

        Timer releaseTimer = null;

        /**
         ************************************************************************************
         * Alter the response to the Enter key to act like the Space key to activate button and
         * check box controls, and the arrow keys so as to mimic the Tab and Shift+Tab keys,
         * unless the key press originates within a table or combo box. For a tabbed pane the
         * left/right arrows are left unchanged so that these are used for traversing the
         * tabbed panes, but the down and up arrows act like Tab and Shift+Tab respectively
         ************************************************************************************
         */
        @Override
        public boolean dispatchKeyEvent(final KeyEvent ke) {
            // Flag that indicates if the key event has been handled by this method (true) or
            // that it still needs to be processed (false)
            boolean handled = false;
            // Get a reference to the component with the focus in order to shorten the
            // subsequent calls
            Component comp = ke.getComponent();
            // pressed
            if (ke.getID() == KeyEvent.KEY_PRESSED && !ke.isControlDown() && !ke.isShiftDown() && !ke.isAltDown()) {
                // Check if the Enter key is pressed
                if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
                    // Check if this is a button
                    if (comp instanceof JButton) {
                        // Activate the control (same as if Space key is pressed)
                        ((AbstractButton) comp).doClick();
                        handled = true;
                    } else // Check if this is a table
                    if (comp instanceof CcddJTableHandler || (comp.getParent() instanceof CcddJTableHandler && !(comp instanceof JComboBox))) {
                        // Handle the Enter key in the table
                        handled = tableEditCellHandler(comp);
                    }
                } else // Check if the space key is pressed
                if (ke.getKeyCode() == KeyEvent.VK_SPACE) {
                    // Check if this is a table
                    if (comp instanceof CcddJTableHandler) {
                        // Handle the space key in the table
                        handled = tableEditCellHandler(comp);
                    } else // Check this is a combo box in a table
                    if (comp.getParent() instanceof CcddJTableHandler && comp instanceof JComboBox) {
                        // Ignore the key press
                        handled = true;
                    }
                } else // produce a character and is not a modifier; this covers the arrow keys)
                if (ke.isActionKey()) {
                    // Assume that the default handling will be used with an arrow key
                    ArrowFocusOption arrowResponse = USE_DEFAULT_HANDLER;
                    // Check if the focus is on a tabbed pane's tab or on a slider
                    if (comp instanceof JTabbedPane || comp instanceof JSlider) {
                        // The left and right arrows traverse the tabs, and the up and down
                        // arrows behave like (Shift+)Tab
                        arrowResponse = HANDLE_UP_AND_DOWN_ARROWS;
                    } else // Check if the focus is in a text field within a table
                    if ((comp instanceof JTextField || comp instanceof JTextArea) && comp.getParent() instanceof CcddJTableHandler) {
                        // The up and down arrows are ignored. This prevents accidently exiting
                        // edit mode on a table cell and losing any changes
                        arrowResponse = IGNORE_UP_AND_DOWN_ARROWS;
                    } else // button, or check box
                    if (comp instanceof JButton || comp instanceof JRadioButton || comp instanceof JCheckBox) {
                        // The up and left arrow keys behave as Shift+Tab, and the down and
                        // right arrow keys behave as Tab
                        arrowResponse = HANDLE_ALL_ARROWS;
                    } else // Check if the focus is within a table
                    if (comp instanceof CcddJTableHandler) {
                        // Get the reference to the table with the focus
                        CcddJTableHandler table = (CcddJTableHandler) comp;
                        // Get the row containing the cell with the focus in order to shorten
                        // the subsequent calls
                        int row = table.getSelectedRow();
                        // Check if the table has no rows
                        if (row == -1) {
                            // Treat the table as if it wasn't there; i.e., the left and right
                            // arrows behave like the (Shift+)Tab key
                            arrowResponse = HANDLE_ALL_ARROWS;
                        } else // Check if the table has only a single row
                        if (table.getRowCount() == 1) {
                            // The up and down arrows behave like the (Shift+)Tab key
                            arrowResponse = HANDLE_UP_AND_DOWN_ARROWS;
                        } else // Check if the top row is selected
                        if (row == 0) {
                            // The up arrow behaves like the Shift+Tab key
                            arrowResponse = HANDLE_UP_ARROW;
                        } else // Check if the bottom row is selected
                        if (row == table.getRowCount() - 1) {
                            // The down arrow behaves like the Tab key
                            arrowResponse = HANDLE_DOWN_ARROW;
                        }
                    }
                    // Check if the key pressed is an arrow key and if so adjust its behavior
                    switch(ke.getKeyCode()) {
                        case KeyEvent.VK_LEFT:
                        case KeyEvent.VK_KP_LEFT:
                            // Check if the left arrow key should be handled
                            if (arrowResponse == HANDLE_ALL_ARROWS) {
                                // Treat the left arrow as a Shift+Tab key and indicate that
                                // the key has been handled
                                focusManager.focusPreviousComponent();
                                handled = true;
                            }
                            break;
                        case KeyEvent.VK_UP:
                        case KeyEvent.VK_KP_UP:
                            // Check if the up arrow key should be handled
                            if (arrowResponse == HANDLE_ALL_ARROWS || arrowResponse == HANDLE_UP_ARROW || arrowResponse == HANDLE_UP_AND_DOWN_ARROWS) {
                                // Treat the up arrow as a Shift+Tab key and indicate that the
                                // key has been handled
                                focusManager.focusPreviousComponent();
                                handled = true;
                            } else // Check if the up arrow should be ignored
                            if (arrowResponse == IGNORE_UP_AND_DOWN_ARROWS) {
                                // Indicate that the key has been handled
                                handled = true;
                            }
                            break;
                        case KeyEvent.VK_RIGHT:
                        case KeyEvent.VK_KP_RIGHT:
                            // Check if the right arrow key should be handled
                            if (arrowResponse == HANDLE_ALL_ARROWS) {
                                // Treat the right arrow as a Tab key and indicate that the key
                                // has been handled
                                focusManager.focusNextComponent();
                                handled = true;
                            }
                            break;
                        case KeyEvent.VK_DOWN:
                        case KeyEvent.VK_KP_DOWN:
                            // Check if the down arrow key should be handled
                            if (arrowResponse == HANDLE_ALL_ARROWS || arrowResponse == HANDLE_DOWN_ARROW || arrowResponse == HANDLE_UP_AND_DOWN_ARROWS) {
                                // Treat the down arrow as a Tab key and indicate that the key
                                // has been handled
                                focusManager.focusNextComponent();
                                handled = true;
                            } else // Check if the down arrow should be ignored
                            if (arrowResponse == IGNORE_UP_AND_DOWN_ARROWS) {
                                // Indicate that the key has been handled
                                handled = true;
                            }
                            break;
                    }
                }
            } else // Check if the Ctrl key is pressed
            if (ke.getID() == KeyEvent.KEY_PRESSED && ke.isControlDown() && !ke.isAltDown()) {
                // Check if the Ctrl-Z key is pressed
                if (ke.getKeyCode() == KeyEvent.VK_Z) {
                    // Get the currently active undo manager
                    final CcddUndoManager undoManager = getActiveUndoManager();
                    // Check if an active undo manager was found
                    if (undoManager != null) {
                        // Create a runnable object to be executed
                        SwingUtilities.invokeLater(new Runnable() {

                            /**
                             ****************************************************************
                             * Execute after all pending Swing events are finished so that the
                             * events occur in the desired order
                             ****************************************************************
                             */
                            @Override
                            public void run() {
                                // Undo the previous edit action
                                undoManager.undo();
                                // associated with the component
                                if (editPnlHandler != null) {
                                    // Update the data field background colors
                                    editPnlHandler.setFieldBackgound();
                                }
                                // Force the component to repaint so that the change is visible
                                ke.getComponent().repaint();
                            }
                        });
                        // Set the flag to indicate this key press was handled
                        handled = true;
                    }
                } else // Check if the Ctrl-Y key is pressed
                if (ke.getKeyCode() == KeyEvent.VK_Y) {
                    // Get the currently active undo manager
                    final CcddUndoManager undoManager = getActiveUndoManager();
                    // Check if an active undo manager was found
                    if (undoManager != null) {
                        // Create a runnable object to be executed
                        SwingUtilities.invokeLater(new Runnable() {

                            /**
                             ****************************************************************
                             * Execute after all pending Swing events are finished so that the
                             * events occur in the desired order
                             ****************************************************************
                             */
                            @Override
                            public void run() {
                                // Redo the previous undo action
                                undoManager.redo();
                                // associated with the component
                                if (editPnlHandler != null) {
                                    // Update the data field background colors
                                    editPnlHandler.setFieldBackgound();
                                }
                                // Force the component to repaint so that the change is visible
                                ke.getComponent().repaint();
                            }
                        });
                        // Set the flag to indicate this key press was handled
                        handled = true;
                    }
                } else // focus
                if (ke.getKeyCode() == KeyEvent.VK_F && ccddMain.getMainFrame().isFocused()) {
                    // Open the event log search dialog
                    ccddMain.showSearchDialog(SearchDialogType.LOG, null, ccddMain.getSessionEventLog(), ccddMain.getMainFrame());
                    // Set the flag to indicate this key press was handled
                    handled = true;
                } else // insertion
                if (ke.getKeyCode() == KeyEvent.VK_S) {
                    // Get the table editor dialog with the focus
                    CcddTableEditorDialog editorDialog = getFocusedTableEditorDialog();
                    // contain a combo box
                    if (editorDialog != null && !(comp instanceof JComboBox)) {
                        // Check if a cell in the table is being edited
                        if (editorDialog.getTableEditor().getTable().isEditing()) {
                            // Insert the structure name chosen by the user into the text field
                            // at the current text insertion point
                            dataTypeHandler.insertDataTypeName((JFrame) editorDialog, (JTextArea) comp, true, editorDialog.getTableEditor().getValidDataTypes().toArray(new String[0]));
                        }
                    } else // Check if the data type editor editing is active
                    if (SwingUtilities.getWindowAncestor(comp) instanceof CcddDataTypeEditorDialog && modalTable.isEditing()) {
                        // Get the row and column being edited in the table, and the contents
                        // of the edited row's base data type
                        int row = modalTable.getEditingRow();
                        int column = modalTable.convertColumnIndexToModel(modalTable.getEditingColumn());
                        String baseType = modalTable.getValueAt(row, DataTypeEditorColumnInfo.BASE_TYPE.ordinal()).toString();
                        // base data type is empty or a pointer
                        if ((column == DataTypeEditorColumnInfo.USER_NAME.ordinal() || column == DataTypeEditorColumnInfo.C_NAME.ordinal()) && (baseType.isEmpty() || baseType.equals(BaseDataTypeInfo.POINTER.getName()))) {
                            // Insert the structure name chosen by the user into the text field
                            // at the current text insertion point
                            dataTypeHandler.insertDataTypeName((JDialog) SwingUtilities.getWindowAncestor(comp), (JTextArea) comp, false, null);
                        }
                    } else // Check if the macro editor editing is active
                    if (SwingUtilities.getWindowAncestor(comp) instanceof CcddMacroEditorDialog && modalTable.isEditing()) {
                        // Insert the structure name chosen by the user into the text field at
                        // the current text insertion point
                        dataTypeHandler.insertDataTypeName((JDialog) SwingUtilities.getWindowAncestor(comp), (JTextArea) comp, true, null);
                    }
                    // Set the flag to indicate this key press was handled
                    handled = true;
                } else // and expansion
                if (ke.getKeyCode() == KeyEvent.VK_M) {
                    // Check if the shift key is also pressed (Ctrl-Shift-M)
                    if (ke.isShiftDown()) {
                        // Check if the macros aren't already expanded
                        if (!isShowMacros) {
                            // Get the table editor dialog with the focus
                            CcddTableEditorDialog editorDialog = getFocusedTableEditorDialog();
                            // Check if a table editor dialog has the focus
                            if (editorDialog != null) {
                                // Replace the macro names with their corresponding values in
                                // the currently selected table in this editor
                                editorDialog.getTableEditor().expandMacros(true, true);
                                isShowMacros = true;
                            } else // Check if this is the macro editor
                            if (SwingUtilities.getWindowAncestor(comp) instanceof CcddMacroEditorDialog) {
                                // Expand the macros in the macro value column
                                ((CcddMacroEditorDialog) SwingUtilities.getWindowAncestor(comp)).expandMacros(true);
                                isShowMacros = true;
                            }
                        }
                    } else // The shift key isn't pressed (Ctrl-M only). Check if this is a table cell
                    if (comp.getParent() instanceof CcddJTableHandler) {
                        // Get the table editor dialog with the focus
                        CcddTableEditorDialog editorDialog = getFocusedTableEditorDialog();
                        // doesn't contain a combo box
                        if (editorDialog != null && !(comp instanceof JComboBox)) {
                            // Get references to shorten subsequent calls
                            CcddTableEditorHandler editor = editorDialog.getTableEditor();
                            CcddJTableHandler table = editor.getTable();
                            // Check if a cell in the table is being edited
                            if (table.isEditing()) {
                                // Get the index of the column being edited in model
                                // coordinates
                                int column = table.convertColumnIndexToModel(table.getEditingColumn());
                                // Get the input type for the column being edited
                                InputDataType inputType = editor.getTableTypeDefinition().getInputTypes()[column];
                                // Insert the macro name chosen by the user into the text
                                // component at the current text insertion point
                                macroHandler.insertMacroName(editorDialog, (JTextComponent) comp, inputType, editor.getValidDataTypes());
                            }
                        } else // column is being edited
                        if (SwingUtilities.getWindowAncestor(comp) instanceof CcddMacroEditorDialog && modalTable.isEditing() && modalTable.convertColumnIndexToModel(modalTable.getEditingColumn()) == MacroEditorColumnInfo.VALUE.ordinal()) {
                            // Insert the macro name chosen by the user into the text component
                            // at the current text insertion point
                            macroHandler.insertMacroName((JDialog) SwingUtilities.getWindowAncestor(comp), (JTextComponent) comp, InputDataType.TEXT, null);
                        }
                    }
                    // Set the flag to indicate this key press was handled
                    handled = true;
                } else // Check if the Ctrl-E key is pressed while the focus is on a tree
                if (ke.getKeyCode() == KeyEvent.VK_E && comp instanceof CcddCommonTreeHandler) {
                    // Expand/collapse the selected node(s)
                    ((CcddCommonTreeHandler) comp).expandCollapseSelectedNodes();
                }
            } else // text
            if (ke.getID() == KeyEvent.KEY_PRESSED && ke.isAltDown() && !ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_ENTER && comp.getParent() instanceof CcddJTableHandler && comp instanceof JTextArea) {
                // Get the table editor dialog with the focus
                CcddTableEditorDialog editorDialog = getFocusedTableEditorDialog();
                // Check if a table editor dialog has the focus
                if (editorDialog != null) {
                    // Check if a cell in the table is being edited
                    if (editorDialog.getTableEditor().getTable().isEditing()) {
                        JTextComponent textComp = (JTextComponent) comp;
                        // Get the cell's current value
                        String cellValue = textComp.getText();
                        // Get the starting position of the selected text
                        int caretPosn = textComp.getSelectionStart();
                        // Replace the currently selected text with a line feed
                        textComp.setText(cellValue.substring(0, caretPosn) + "\n" + cellValue.substring(textComp.getSelectionEnd()));
                        // Position the cursor after the newly inserted line feed
                        textComp.setCaretPosition(caretPosn + 1);
                    }
                }
            }
            // key sequence is no longer active
            if (isShowMacros && ke.getID() == KeyEvent.KEY_RELEASED && ke.getKeyCode() == KeyEvent.VK_M) {
                // Check if the key release action timer doesn't exist
                if (releaseTimer == null) {
                    // Create the key release action timer. In Linux if a key is held it
                    // generates continuous key release events. This timer is used to ignore
                    // the key release events that are close together time-wise
                    releaseTimer = new Timer(75, new ActionListener() {

                        /**
                         ********************************************************************
                         * Handle the key release action
                         ********************************************************************
                         */
                        @Override
                        public void actionPerformed(ActionEvent ae) {
                            // Get the table editor dialog with the focus
                            CcddTableEditorDialog editorDialog = getFocusedTableEditorDialog();
                            // Check if a table editor dialog has the focus
                            if (editorDialog != null) {
                                // Restore the macro names in the currently selected table in
                                // this editor
                                editorDialog.getTableEditor().expandMacros(false, true);
                                isShowMacros = false;
                            } else // Check if this is the macro editor
                            if (SwingUtilities.getWindowAncestor(modalTable) instanceof CcddMacroEditorDialog) {
                                // Expand the macros in the macro value column
                                ((CcddMacroEditorDialog) SwingUtilities.getWindowAncestor(modalTable)).expandMacros(false);
                                isShowMacros = false;
                            }
                        }
                    });
                    // Allow the timer to send only a single expiration event
                    releaseTimer.setRepeats(false);
                }
                // (Re)start the key release action timer
                releaseTimer.restart();
                // Set the flag to indicate this key press was handled
                handled = true;
            }
            return handled;
        }
    });
}
Also used : JTextArea(javax.swing.JTextArea) JRadioButton(javax.swing.JRadioButton) ActionEvent(java.awt.event.ActionEvent) ArrowFocusOption(CCDD.CcddConstants.ArrowFocusOption) JTabbedPane(javax.swing.JTabbedPane) JButton(javax.swing.JButton) JTextComponent(javax.swing.text.JTextComponent) JTextField(javax.swing.JTextField) KeyEvent(java.awt.event.KeyEvent) JFrame(javax.swing.JFrame) JSlider(javax.swing.JSlider) Component(java.awt.Component) JTextComponent(javax.swing.text.JTextComponent) InputDataType(CCDD.CcddConstants.InputDataType) JComboBox(javax.swing.JComboBox) KeyEventDispatcher(java.awt.KeyEventDispatcher) JCheckBox(javax.swing.JCheckBox) Timer(javax.swing.Timer) ActionListener(java.awt.event.ActionListener) JDialog(javax.swing.JDialog)

Example 57 with JTextComponent

use of javax.swing.text.JTextComponent in project CCDD by nasa.

the class CcddScriptHandler method getAssociationsPanel.

/**
 ********************************************************************************************
 * Create the panel containing the script associations table
 *
 * @param title
 *            text to display above the script associations table; null or blank if no text is
 *            to be displayed
 *
 * @param allowSelectDisabled
 *            true if disabled associations can be selected; false if not. In the script
 *            manager disabled associations are selectable so that these can be deleted if
 *            desired. Scripts that are selected and disabled are ignored when executing
 *            scripts
 *
 * @param parent
 *            GUI component calling this method
 *
 * @return Reference to the JPanel containing the script associations table
 ********************************************************************************************
 */
@SuppressWarnings("serial")
protected JPanel getAssociationsPanel(String title, final boolean allowSelectDisabled, final Component parent) {
    // Set the initial layout manager characteristics
    GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(ModifiableSpacingInfo.LABEL_VERTICAL_SPACING.getSpacing(), 0, 0, 0), 0, 0);
    // Define the panel to contain the table
    JPanel assnsPnl = new JPanel(new GridBagLayout());
    // Check if a table title is provided
    if (title != null && !title.isEmpty()) {
        // Create the script associations label
        JLabel assnsLbl = new JLabel(title);
        assnsLbl.setFont(ModifiableFontInfo.LABEL_BOLD.getFont());
        assnsLbl.setForeground(ModifiableColorInfo.SPECIAL_LABEL_TEXT.getColor());
        assnsPnl.add(assnsLbl, gbc);
        gbc.gridy++;
    }
    // Create the table to display the search results
    assnsTable = new CcddJTableHandler() {

        /**
         ************************************************************************************
         * Allow multiple line display in all columns
         ************************************************************************************
         */
        @Override
        protected boolean isColumnMultiLine(int column) {
            return true;
        }

        /**
         ************************************************************************************
         * Allow HTML-formatted text in the specified column(s)
         ************************************************************************************
         */
        @Override
        protected boolean isColumnHTML(int column) {
            return column == AssociationsTableColumnInfo.MEMBERS.ordinal();
        }

        /**
         ************************************************************************************
         * Hide the the specified columns
         ************************************************************************************
         */
        @Override
        protected boolean isColumnHidden(int column) {
            return column == AssociationsTableColumnInfo.AVAILABLE.ordinal();
        }

        /**
         ************************************************************************************
         * Allow editing the description in the script manager's associations table
         ************************************************************************************
         */
        @Override
        public boolean isCellEditable(int row, int column) {
            return (column == convertColumnIndexToModel(AssociationsTableColumnInfo.NAME.ordinal()) || column == convertColumnIndexToModel(AssociationsTableColumnInfo.DESCRIPTION.ordinal())) && allowSelectDisabled;
        }

        /**
         ************************************************************************************
         * Validate changes to the editable cells
         *
         * @param tableData
         *            list containing the table data row arrays
         *
         * @param row
         *            table model row number
         *
         * @param column
         *            table model column number
         *
         * @param oldValue
         *            original cell contents
         *
         * @param newValue
         *            new cell contents
         *
         * @param showMessage
         *            true to display the invalid input dialog, if applicable
         *
         * @param isMultiple
         *            true if this is one of multiple cells to be entered and checked; false if
         *            only a single input is being entered
         *
         * @return Always returns false
         ***********************************************************************************
         */
        @Override
        protected Boolean validateCellContent(List<Object[]> tableData, int row, int column, Object oldValue, Object newValue, Boolean showMessage, boolean isMultiple) {
            // Reset the flag that indicates the last edited cell's content is invalid
            setLastCellValid(true);
            // Create a string version of the new value
            String newValueS = newValue.toString();
            try {
                // Check if the value isn't blank
                if (!newValueS.isEmpty()) {
                    // blank
                    if (column == AssociationsTableColumnInfo.NAME.ordinal()) {
                        // type
                        if (!newValueS.matches(InputDataType.ALPHANUMERIC.getInputMatch())) {
                            throw new CCDDException("Illegal character(s) in association name");
                        }
                        // avoid creating a duplicate
                        for (int otherRow = 0; otherRow < getRowCount(); otherRow++) {
                            // association name matches the one being added (case insensitive)
                            if (otherRow != row && newValueS.equalsIgnoreCase(tableData.get(otherRow)[column].toString())) {
                                throw new CCDDException("Association name already in use");
                            }
                        }
                    }
                }
            } catch (CCDDException ce) {
                // Set the flag that indicates the last edited cell's content is invalid
                setLastCellValid(false);
                // Check if the input error dialog should be displayed
                if (showMessage) {
                    // Inform the user that the input value is invalid
                    new CcddDialogHandler().showMessageDialog(parent, "<html><b>" + ce.getMessage(), "Invalid Input", JOptionPane.WARNING_MESSAGE, DialogOption.OK_OPTION);
                }
                // Restore the cell contents to its original value and pop the edit from the
                // stack
                tableData.get(row)[column] = oldValue;
                getUndoManager().undoRemoveEdit();
            }
            return false;
        }

        /**
         ************************************************************************************
         * Load the script associations data into the table and format the table cells
         ************************************************************************************
         */
        @Override
        protected void loadAndFormatData() {
            // Place the data into the table model along with the column names, set up the
            // editors and renderers for the table cells, set up the table grid lines, and
            // calculate the minimum width required to display the table information
            int totalWidth = setUpdatableCharacteristics(getScriptAssociationData(allowSelectDisabled, parent), AssociationsTableColumnInfo.getColumnNames(), null, AssociationsTableColumnInfo.getToolTips(), true, true, true);
            // Check if the script manager or executive is active
            if (scriptDialog != null) {
                // Set the script manager or executive width to the associations table width
                scriptDialog.setTableWidth(totalWidth + LAF_SCROLL_BAR_WIDTH + ModifiableSpacingInfo.LABEL_HORIZONTAL_SPACING.getSpacing() * 2);
            }
        }

        /**
         ************************************************************************************
         * Alter the association table cell color or contents
         *
         * @param component
         *            reference to the table cell renderer component
         *
         * @param value
         *            cell value
         *
         * @param isSelected
         *            true if the cell is to be rendered with the selection highlighted
         *
         * @param int
         *            row cell row, view coordinates
         *
         * @param column
         *            cell column, view coordinates
         ************************************************************************************
         */
        @Override
        protected void doSpecialRendering(Component component, String text, boolean isSelected, int row, int column) {
            // Check if the association on the specified row is flagged as unavailable
            if (!isAssociationAvailable(convertRowIndexToModel(row))) {
                // Set the text color for this row to indicate it's not available
                ((JTextComponent) component).setForeground(Color.GRAY);
                // Check if selection of disabled associations isn't allowed
                if (!allowSelectDisabled) {
                    // Set the background color to indicate the row isn't selectable
                    ((JTextComponent) component).setBackground(ModifiableColorInfo.TABLE_BACK.getColor());
                }
            }
            // displayed
            if (column == convertColumnIndexToView(AssociationsTableColumnInfo.SCRIPT_FILE.ordinal()) && hideScriptFilePath.isSelected()) {
                // Remove the path, leaving only the script file name
                ((JTextComponent) component).setText(((JTextComponent) component).getText().replaceFirst(".*" + Pattern.quote(File.separator), ""));
            }
        }

        /**
         ************************************************************************************
         * Override the method that sets the row sorter so that special sorting can be
         * performed on the script file column
         ************************************************************************************
         */
        @Override
        protected void setTableSortable() {
            super.setTableSortable();
            // Get a reference to the sorter
            @SuppressWarnings("unchecked") TableRowSorter<UndoableTableModel> sorter = (TableRowSorter<UndoableTableModel>) getRowSorter();
            // rows in the table
            if (sorter != null) {
                // Add a sort comparator for the script file column
                sorter.setComparator(AssociationsTableColumnInfo.SCRIPT_FILE.ordinal(), new Comparator<String>() {

                    /**
                     ************************************************************************
                     * Override the comparison when sorting the script file column to ignore
                     * the script file paths if these are currently hidden
                     ************************************************************************
                     */
                    @Override
                    public int compare(String filePath1, String filePath2) {
                        return (hideScriptFilePath.isSelected() ? filePath1.replaceFirst(".*" + Pattern.quote(File.separator), "") : filePath1).compareTo(hideScriptFilePath.isSelected() ? filePath2.replaceFirst(".*" + Pattern.quote(File.separator), "") : filePath2);
                    }
                });
            }
        }

        /**
         ************************************************************************************
         * Handle a change to the table's content
         ************************************************************************************
         */
        @Override
        protected void processTableContentChange() {
            // associations manager dialog is open)
            if (scriptDialog != null && scriptDialog instanceof CcddScriptManagerDialog) {
                // Update the script associations manager change indicator
                ((CcddScriptManagerDialog) scriptDialog).updateChangeIndicator();
            }
        }
    };
    // Set the list selection model in order to detect table rows that aren't allowed to be
    // selected
    assnsTable.setSelectionModel(new DefaultListSelectionModel() {

        /**
         ************************************************************************************
         * Check if the script association table item is selected, ignoring associations that
         * are flagged as unavailable
         ************************************************************************************
         */
        @Override
        public boolean isSelectedIndex(int row) {
            return allowSelectDisabled || isAssociationAvailable(assnsTable.convertRowIndexToModel(row)) ? super.isSelectedIndex(row) : false;
        }
    });
    // Place the table into a scroll pane
    JScrollPane scrollPane = new JScrollPane(assnsTable);
    // Set up the search results table parameters
    assnsTable.setFixedCharacteristics(scrollPane, false, ListSelectionModel.MULTIPLE_INTERVAL_SELECTION, TableSelectionMode.SELECT_BY_ROW, true, ModifiableColorInfo.TABLE_BACK.getColor(), true, true, ModifiableFontInfo.OTHER_TABLE_CELL.getFont(), true);
    // Define the panel to contain the table and add it to the dialog
    JPanel assnsTblPnl = new JPanel();
    assnsTblPnl.setLayout(new BoxLayout(assnsTblPnl, BoxLayout.X_AXIS));
    assnsTblPnl.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
    assnsTblPnl.add(scrollPane);
    gbc.weighty = 1.0;
    assnsPnl.add(assnsTblPnl, gbc);
    // Create the check box for hiding/showing the file paths in the associations table script
    // file column
    hideScriptFilePath = new JCheckBox("Hide script file path", ccddMain.getProgPrefs().getBoolean(HIDE_SCRIPT_PATH, false));
    hideScriptFilePath.setFont(ModifiableFontInfo.LABEL_BOLD.getFont());
    hideScriptFilePath.setBorder(BorderFactory.createEmptyBorder());
    hideScriptFilePath.setToolTipText(CcddUtilities.wrapText("Remove the file paths from the script file column", ModifiableSizeInfo.MAX_TOOL_TIP_LENGTH.getSize()));
    // Add a listener for check box selection changes
    hideScriptFilePath.addActionListener(new ActionListener() {

        /**
         ************************************************************************************
         * Handle a change in the hide script file path check box state
         ************************************************************************************
         */
        @Override
        public void actionPerformed(ActionEvent ae) {
            assnsTable.repaint();
            ccddMain.getProgPrefs().putBoolean(HIDE_SCRIPT_PATH, hideScriptFilePath.isSelected());
        }
    });
    gbc.weighty = 0.0;
    gbc.gridy++;
    assnsPnl.add(hideScriptFilePath, gbc);
    // Create a panel to contain the environment variable override label and field
    JPanel envVarOverridePnl = new JPanel(new GridBagLayout());
    JLabel envVarOverrideLbl = new JLabel("Environment variable override");
    envVarOverrideLbl.setFont(ModifiableFontInfo.LABEL_BOLD.getFont());
    gbc.insets.right = ModifiableSpacingInfo.LABEL_HORIZONTAL_SPACING.getSpacing();
    gbc.weightx = 0.0;
    gbc.gridy++;
    envVarOverridePnl.add(envVarOverrideLbl, gbc);
    envVarOverrideFld = new JTextField(ModifiableOtherSettingInfo.ENV_VAR_OVERRIDE.getValue());
    envVarOverrideFld.setFont(ModifiableFontInfo.INPUT_TEXT.getFont());
    envVarOverrideFld.setEditable(true);
    envVarOverrideFld.setForeground(ModifiableColorInfo.INPUT_TEXT.getColor());
    envVarOverrideFld.setBackground(ModifiableColorInfo.INPUT_BACK.getColor());
    envVarOverrideFld.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.LIGHT_GRAY, Color.GRAY), BorderFactory.createEmptyBorder(ModifiableSpacingInfo.INPUT_FIELD_PADDING.getSpacing(), ModifiableSpacingInfo.INPUT_FIELD_PADDING.getSpacing(), ModifiableSpacingInfo.INPUT_FIELD_PADDING.getSpacing(), ModifiableSpacingInfo.INPUT_FIELD_PADDING.getSpacing())));
    // Add a listener for focus changes on the environment variable override field
    envVarOverrideFld.addFocusListener(new FocusAdapter() {

        /**
         ************************************************************************************
         * Handle a loss of focus
         ************************************************************************************
         */
        @Override
        public void focusLost(FocusEvent fe) {
            // Update the environment variable map and association availability
            getEnvironmentVariableMap(parent);
        }
    });
    gbc.insets.right = 0;
    gbc.weightx = 1.0;
    gbc.gridx++;
    envVarOverridePnl.add(envVarOverrideFld, gbc);
    gbc.gridx = 0;
    assnsPnl.add(envVarOverridePnl, gbc);
    // Initialize the environment variable map
    getEnvironmentVariableMap(parent);
    return assnsPnl;
}
Also used : JPanel(javax.swing.JPanel) FocusAdapter(java.awt.event.FocusAdapter) GridBagConstraints(java.awt.GridBagConstraints) Insets(java.awt.Insets) CCDDException(CCDD.CcddClassesDataTable.CCDDException) GridBagLayout(java.awt.GridBagLayout) ActionEvent(java.awt.event.ActionEvent) BoxLayout(javax.swing.BoxLayout) DefaultListSelectionModel(javax.swing.DefaultListSelectionModel) JTextField(javax.swing.JTextField) FocusEvent(java.awt.event.FocusEvent) Comparator(java.util.Comparator) Component(java.awt.Component) JTextComponent(javax.swing.text.JTextComponent) TableRowSorter(javax.swing.table.TableRowSorter) JScrollPane(javax.swing.JScrollPane) JLabel(javax.swing.JLabel) JCheckBox(javax.swing.JCheckBox) ActionListener(java.awt.event.ActionListener) UndoableTableModel(CCDD.CcddUndoHandler.UndoableTableModel)

Example 58 with JTextComponent

use of javax.swing.text.JTextComponent in project CCDD by nasa.

the class CcddTableEditorDialog method initialize.

/**
 ********************************************************************************************
 * Create the data table editor dialog
 *
 * @param tableInformation
 *            list containing information for each table
 *
 * @param editor
 *            reference to an existing table editor
 ********************************************************************************************
 */
private void initialize(List<TableInformation> tableInformation, CcddTableEditorHandler editor) {
    // Menu ///////////////////////////////////////////////////////////////////////////////////
    // Create the data table menu bar
    JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);
    // Create the File menu and menu items
    JMenu mnFile = ccddMain.createMenu(menuBar, "File", KeyEvent.VK_F, 1, null);
    mntmOpen = ccddMain.createMenuItem(mnFile, "Edit table(s)", KeyEvent.VK_E, 1, "Open one or more data tables for editing");
    mntmOpenPrototype = ccddMain.createMenuItem(mnFile, "Edit prototype", KeyEvent.VK_T, 2, "Open the prototype for the current table");
    mnFile.addSeparator();
    mntmStore = ccddMain.createMenuItem(mnFile, "Store current", KeyEvent.VK_U, 1, "Store changes to the current editor table");
    mntmStoreAll = ccddMain.createMenuItem(mnFile, "Store all", KeyEvent.VK_L, 1, "Store the changes to all tables in this editor");
    mnFile.addSeparator();
    mntmImport = ccddMain.createMenuItem(mnFile, "Import data", KeyEvent.VK_I, 1, "Import data from a CSV, EDS XML, JSON, or XTCE XML file into the current editor table");
    JMenu mnExport = ccddMain.createSubMenu(mnFile, "Export table", KeyEvent.VK_X, 1, null);
    mntmExportCSV = ccddMain.createMenuItem(mnExport, "CSV", KeyEvent.VK_C, 1, "Export the current editor table in CSV format");
    mntmExportEDS = ccddMain.createMenuItem(mnExport, "EDS", KeyEvent.VK_E, 1, "Export the current editor table in EDS XML format");
    mntmExportJSON = ccddMain.createMenuItem(mnExport, "JSON", KeyEvent.VK_J, 1, "Export the current editor table in JSON format");
    mntmExportXTCE = ccddMain.createMenuItem(mnExport, "XTCE", KeyEvent.VK_X, 1, "Export the current editor table in XTCE XML format");
    mnFile.addSeparator();
    mntmPrint = ccddMain.createMenuItem(mnFile, "Print current", KeyEvent.VK_P, 1, "Print the current editor table information");
    mntmSearchTable = ccddMain.createMenuItem(mnFile, "Search tables", KeyEvent.VK_S, 1, "Search the project database tables");
    mnFile.addSeparator();
    mntmCloseActive = ccddMain.createMenuItem(mnFile, "Close current", KeyEvent.VK_C, 2, "Close the current editor table");
    mntmCloseAll = ccddMain.createMenuItem(mnFile, "Close all", KeyEvent.VK_A, 1, "Close all tables in this editor");
    // Create the Edit menu and menu items
    JMenu mnEdit = ccddMain.createMenu(menuBar, "Edit", KeyEvent.VK_E, 1, null);
    mntmCopy = ccddMain.createMenuItem(mnEdit, "Copy", KeyEvent.VK_C, 1, "Copy the selected cell(s) to the clipboard");
    mntmPaste = ccddMain.createMenuItem(mnEdit, "Paste (Ctrl-V)", KeyEvent.VK_V, 1, "Paste the clipboard contents at the current focus location");
    mntmInsert = ccddMain.createMenuItem(mnEdit, "Insert", KeyEvent.VK_I, 1, "Insert the clipboard contents at the current focus location");
    mnEdit.addSeparator();
    mntmUndo = ccddMain.createMenuItem(mnEdit, "Undo (Ctrl-Z)", KeyEvent.VK_Z, 1, "Undo the last edit operation");
    mntmRedo = ccddMain.createMenuItem(mnEdit, "Redo (Ctrl-Y)", KeyEvent.VK_Y, 1, "Redo the last undone edit operation");
    mnEdit.addSeparator();
    mntmInsertMacro = ccddMain.createMenuItem(mnEdit, "Insert macro", KeyEvent.VK_M, 1, "Insert a macro selected from the pop-up list");
    mntmShowMacros = ccddMain.createCheckBoxMenuItem(mnEdit, "Show macros", KeyEvent.VK_S, 1, "Temporarily replace macro(s) with the corresponding value(s)", false);
    mnEdit.addSeparator();
    JMenu mnClearSelected = ccddMain.createSubMenu(mnEdit, "Replace selected", KeyEvent.VK_L, 1, null);
    mntmWithBlanks = ccddMain.createMenuItem(mnClearSelected, "With blank", KeyEvent.VK_B, 1, "Replace the values in the selected cells with blanks");
    mntmWithPrototype = ccddMain.createMenuItem(mnClearSelected, "With prototype", KeyEvent.VK_P, 1, "Replace the values in the selected cells with the prototype's values");
    // Create the Row menu and menu items
    JMenu mnRow = ccddMain.createMenu(menuBar, "Row", KeyEvent.VK_R, 1, null);
    mntmInsertRow = ccddMain.createMenuItem(mnRow, "Insert row", KeyEvent.VK_I, 1, "Insert a row below the current focus location");
    mntmDeleteRow = ccddMain.createMenuItem(mnRow, "Delete row(s)", KeyEvent.VK_D, 1, "Delete the currently selected row(s)");
    mnRow.addSeparator();
    mntmMoveUp = ccddMain.createMenuItem(mnRow, "Move up", KeyEvent.VK_U, 1, "Move the currently selected row(s) up one row");
    mntmMoveDown = ccddMain.createMenuItem(mnRow, "Move down", KeyEvent.VK_N, 1, "Move the currently selected row(s) down one row");
    mnRow.addSeparator();
    mntmExpColArray = ccddMain.createCheckBoxMenuItem(mnRow, "Expand arrays", KeyEvent.VK_E, 1, "Expand/collapse display of array members", false);
    JMenu mnOverwrite = ccddMain.createSubMenu(mnRow, "Array overwrite", KeyEvent.VK_O, 1, null);
    mntmOverwriteAll = ccddMain.createRadioButtonMenuItem(mnOverwrite, "Overwrite all", KeyEvent.VK_A, 1, "Copy array definition value change to all members", true);
    mntmOverwriteEmpty = ccddMain.createRadioButtonMenuItem(mnOverwrite, "Overwrite empty", KeyEvent.VK_E, 3, "Copy array definition value change only to empty members", false);
    mntmOverwriteNone = ccddMain.createRadioButtonMenuItem(mnOverwrite, "Overwrite none", KeyEvent.VK_N, 1, "Do not copy definition value change to members", false);
    ButtonGroup rbtnGroup = new ButtonGroup();
    rbtnGroup.add(mntmOverwriteAll);
    rbtnGroup.add(mntmOverwriteEmpty);
    rbtnGroup.add(mntmOverwriteNone);
    // Create the Column menu and menu items
    JMenu mnColumn = ccddMain.createMenu(menuBar, "Column", KeyEvent.VK_M, 1, null);
    mntmMoveLeft = ccddMain.createMenuItem(mnColumn, "Move left", KeyEvent.VK_L, 1, "Move the currently selected column(s) left one column");
    mntmMoveRight = ccddMain.createMenuItem(mnColumn, "Move right", KeyEvent.VK_R, 1, "Move the currently selected column(s) right one column");
    mntmResetOrder = ccddMain.createMenuItem(mnColumn, "Reset order", KeyEvent.VK_O, 1, "Reset the column order to the default");
    // Create the Field menu and menu items
    JMenu mnField = ccddMain.createMenu(menuBar, "Field", KeyEvent.VK_L, 1, null);
    mntmManageFields = ccddMain.createMenuItem(mnField, "Manage fields", KeyEvent.VK_M, 1, "Open the data field manager");
    mntmClearValues = ccddMain.createMenuItem(mnField, "Clear values", KeyEvent.VK_C, 1, "Clear the data field values");
    // Add a listener for the Open Table command
    mntmOpen.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Open a table in this editor dialog
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Open a table and add it to the tabbed pane. This calls TableSelectDialog, but
            // doesn't spawn a separate editor
            new CcddTableManagerDialog(ccddMain, ManagerDialogType.EDIT, CcddTableEditorDialog.this);
        }
    });
    // Add a listener for the Open Prototype Table command
    mntmOpenPrototype.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Open the currently displayed table's prototype table in this editor dialog
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Open the active table's prototype table
            dbTable.loadTableDataInBackground(activeEditor.getTableInformation().getPrototypeName(), CcddTableEditorDialog.this);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Import command
    mntmImport.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Import a file into the table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            fileIOHandler.importSelectedFileIntoTable(activeEditor);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Export - CSV command
    mntmExportCSV.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Export the table to a file in CSV format
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            new CcddTableManagerDialog(ccddMain, ManagerDialogType.EXPORT_CSV, CcddTableEditorDialog.this);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Export - EDS command
    mntmExportEDS.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Export the table to a file in EDS XML format
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            new CcddTableManagerDialog(ccddMain, ManagerDialogType.EXPORT_EDS, CcddTableEditorDialog.this);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Export - JSON command
    mntmExportJSON.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Export the table to a file in JSON format
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            new CcddTableManagerDialog(ccddMain, ManagerDialogType.EXPORT_JSON, CcddTableEditorDialog.this);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Export - XTCE command
    mntmExportXTCE.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Export the table to a file in XTCE XML format
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            new CcddTableManagerDialog(ccddMain, ManagerDialogType.EXPORT_XTCE, CcddTableEditorDialog.this);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Print command
    mntmPrint.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Output the table to the printer
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Print the table
            activeEditor.getTable().printTable("Table: " + activeEditor.getOwnerName(), activeEditor.getFieldHandler(), CcddTableEditorDialog.this, PageFormat.LANDSCAPE);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Search tables menu item
    mntmSearchTable.addActionListener(new ActionListener() {

        /**
         ************************************************************************************
         * Display the search tables dialog
         ************************************************************************************
         */
        @Override
        public void actionPerformed(ActionEvent ae) {
            ccddMain.showSearchDialog(SearchDialogType.TABLES, CcddTableEditorDialog.this);
        }
    });
    // Add a listener for the Copy command
    mntmCopy.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Copy the selected table cell(s) contents into the clipboard
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Send a Ctrl-C key press
            controlKeyAction(KeyEvent.VK_C);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Paste command
    mntmPaste.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Paste the clipboard contents in the table, overwriting any existing data in the
         * target cells and adding new rows at the end of the table if needed
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Send a Ctrl-V key press
            controlKeyAction(KeyEvent.VK_V);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Insert command
    mntmInsert.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Insert the clipboard contents in the table, creating new rows to contain the data
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Send a ctrl-I key press
            controlKeyAction(KeyEvent.VK_I);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Clear selected | With blanks command
    mntmWithBlanks.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Erase the data in the selected cell(s)
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Check if there are any rows to clear
            if (activeEditor.getTableModel().getRowCount() != 0) {
                // Clear the selected cell(s)
                activeEditor.getTable().deleteCell(false);
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Clear selected | With prototype command
    mntmWithPrototype.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Erase the data in the selected cell(s) and the corresponding entry(s) in the custom
         * values table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Check if there are any rows to clear
            if (activeEditor.getTableModel().getRowCount() != 0) {
                // Clear the selected cell(s)
                activeEditor.getTable().deleteCell(true);
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the insert macro command
    mntmInsertMacro.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Insert the macro chosen from the pop-up list into the current cell
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // and end values are valid
            if (getTable().getLastSelectionStart() != -1 && getTable().getLastSelectionEnd() != -1) {
                // Initiate editing in the selected cell
                getTable().editCellAt(getTable().getSelectedRow(), getTable().getSelectedColumn());
                // Get the cell's component
                final Component comp = getTable().getEditorComponent();
                // Check if the cell represents a text component (text area, text field, etc.)
                if (comp instanceof JTextComponent) {
                    // Set the focus to the cell
                    comp.requestFocusInWindow();
                    // Execute the event after any pending events
                    EventQueue.invokeLater(new Runnable() {

                        /**
                         ********************************************************************
                         * Set the selected text start and end positions
                         ********************************************************************
                         */
                        @Override
                        public void run() {
                            // Set the text selected text to the last known positions
                            ((JTextComponent) comp).setSelectionStart(getTable().getLastSelectionStart());
                            ((JTextComponent) comp).setSelectionEnd(getTable().getLastSelectionEnd());
                        }
                    });
                }
                // Send a Ctrl-M key press to display the insert macro pop-up
                controlKeyAction(KeyEvent.VK_M);
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Show macros command
    mntmShowMacros.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Temporarily replace any macros with the corresponding values
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // If the check box is selected then disable the controls that are not allowed
            // while macros are shown, else enable the controls
            setControlsEnabled(!mntmShowMacros.isSelected());
            // Step through each table opened in the editor dialog
            for (CcddTableEditorHandler editor : tableEditors) {
                // Expand all macros in the table if the check box is selected and disable
                // editing for the table, else restore all macros and enable editing
                editor.expandMacros(mntmShowMacros.isSelected(), false);
                editor.setTableEditEnable(!mntmShowMacros.isSelected());
            }
            // Redraw the visible table
            activeEditor.getTable().repaint();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Store All command
    mntmStoreAll.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Store the changes to all open table contents, if any, in the database
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // action
            if (isTablesChanged() && new CcddDialogHandler().showMessageDialog(CcddTableEditorDialog.this, "<html><b>Store changes for all?", "Store Changes", JOptionPane.QUESTION_MESSAGE, DialogOption.OK_CANCEL_OPTION) == OK_BUTTON) {
                // Update the database for every table that has changes
                storeAllChanges();
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Reset Order command
    mntmResetOrder.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Reset the column order to the default
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.resetColumnOrder();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Manage Fields command
    mntmManageFields.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Manage the data fields
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Create the field editor dialog showing the fields for this table
            new CcddFieldEditorDialog(ccddMain, activeEditor, activeEditor.getTableInformation().getTablePath(), (activeEditor.getTableTypeDefinition().isStructure() && !activeEditor.getTableInformation().getTablePath().contains(",")), MIN_WINDOW_WIDTH);
            // Enable/disable the Clear values command depending on if any data fields remain
            mntmClearValues.setEnabled(!activeEditor.getFieldHandler().getFieldInformation().isEmpty());
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add a listener for the Clear values command
    mntmClearValues.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Clear the table data field values
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Check if there are any data fields to clear
            if (!activeEditor.getFieldHandler().getFieldInformation().isEmpty()) {
                // Remove all of the data field values from the table
                activeEditor.getInputFieldPanelHandler().clearFieldValues();
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Create the lower (button) panel
    JPanel buttonPnl = new JPanel();
    // Define the buttons for the lower panel: New button
    btnInsertRow = CcddButtonPanelHandler.createButton("Ins Row", INSERT_ICON, KeyEvent.VK_I, "Insert a new row into the table");
    // Create a listener for the Insert Row command
    ActionListener insertAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Insert a new row into the table at the selected location
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getTable().insertEmptyRow(true);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the insert listener to the Insert Row button and menu command
    btnInsertRow.addActionListener(insertAction);
    mntmInsertRow.addActionListener(insertAction);
    // Delete button
    btnDeleteRow = CcddButtonPanelHandler.createButton("Del Row", DELETE_ICON, KeyEvent.VK_D, "Delete the selected row(s) from the table");
    // Create a listener for the Delete Row command
    ActionListener deleteAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Delete the selected row(s) from the table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getTable().deleteRow(true);
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the delete listener to the Delete Row button and menu command
    btnDeleteRow.addActionListener(deleteAction);
    mntmDeleteRow.addActionListener(deleteAction);
    // Create a listener for the Expand arrays command
    mntmExpColArray.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Expand or collapse the array members
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // Toggle between showing and hiding the array member rows
            activeEditor.showHideArrayMembers();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Move Up button
    btnMoveUp = CcddButtonPanelHandler.createButton("Up", UP_ICON, KeyEvent.VK_U, "Move the selected row(s) up");
    // Create a listener for the Move Up command
    ActionListener moveUpAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Move the selected row(s) up in the table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getTable().moveRowUp();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the move up listener to the Move Up button and menu command
    btnMoveUp.addActionListener(moveUpAction);
    mntmMoveUp.addActionListener(moveUpAction);
    // Move Down button
    btnMoveDown = CcddButtonPanelHandler.createButton("Down", DOWN_ICON, KeyEvent.VK_N, "Move the selected row(s) down");
    // Create a listener for the Move Down command
    ActionListener moveDownAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Move the selected row(s) down in the table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getTable().moveRowDown();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the move down listener to the Move Down button and menu command
    btnMoveDown.addActionListener(moveDownAction);
    mntmMoveDown.addActionListener(moveDownAction);
    // Move Left button
    btnMoveLeft = CcddButtonPanelHandler.createButton("Left", LEFT_ICON, KeyEvent.VK_L, "Move the selected column(s) left");
    // Create a listener for the Move Left command
    ActionListener moveLeftAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Move the selected column(s) left in the table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getTable().moveColumnLeft();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the move left listener to the Move Left button and menu command
    btnMoveLeft.addActionListener(moveLeftAction);
    mntmMoveLeft.addActionListener(moveLeftAction);
    // Move Right button
    btnMoveRight = CcddButtonPanelHandler.createButton("Right", RIGHT_ICON, KeyEvent.VK_R, "Move the selected column(s) right");
    // Create a listener for the Move Right command
    ActionListener moveRightAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Move the selected column(s) right in the table
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getTable().moveColumnRight();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the move right listener to the Move Right button and menu command
    btnMoveRight.addActionListener(moveRightAction);
    mntmMoveRight.addActionListener(moveRightAction);
    // Undo button
    btnUndo = CcddButtonPanelHandler.createButton("Undo", UNDO_ICON, KeyEvent.VK_Z, "Undo the last edit action");
    // Create a listener for the Undo command
    ActionListener undoAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Undo the last cell edit
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getFieldPanelUndoManager().undo();
            // Update the data field background colors
            activeEditor.getInputFieldPanelHandler().setFieldBackgound();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the undo listener to the Undo button and menu command
    mntmUndo.addActionListener(undoAction);
    btnUndo.addActionListener(undoAction);
    // Redo button
    btnRedo = CcddButtonPanelHandler.createButton("Redo", REDO_ICON, KeyEvent.VK_Y, "Redo the last undone edit action");
    // Create a listener for the Redo command
    ActionListener redoAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Redo the last cell edit that was undone
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            activeEditor.getFieldPanelUndoManager().redo();
            // Update the data field background colors
            activeEditor.getInputFieldPanelHandler().setFieldBackgound();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the redo listener to the Redo button and menu command
    mntmRedo.addActionListener(redoAction);
    btnRedo.addActionListener(redoAction);
    // Store button
    btnStore = CcddButtonPanelHandler.createButton("Store", STORE_ICON, KeyEvent.VK_S, "Store the table updates in the database");
    // Create a listener for the Store command
    ActionListener storeAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Store the changes to the table contents, if any, in the database
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // required columns are empty, and the user confirms the action
            if (activeEditor.isTableChanged() && !activeEditor.checkForMissingColumns() && new CcddDialogHandler().showMessageDialog(CcddTableEditorDialog.this, "<html><b>Store changes in project database?", "Store Changes", JOptionPane.QUESTION_MESSAGE, DialogOption.OK_CANCEL_OPTION) == OK_BUTTON) {
                // Store the changes for the currently displayed editor in the database
                storeChanges(activeEditor);
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the store listener to the Store button and menu command
    btnStore.addActionListener(storeAction);
    mntmStore.addActionListener(storeAction);
    // Close button
    btnCloseActive = CcddButtonPanelHandler.createButton("Close", CLOSE_ICON, KeyEvent.VK_C, "Close the table editor");
    // Add a listener for the Close active table command
    ActionListener closeAction = new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Close the active editor
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            // confirm discarding the changes
            if (activeEditor.getTable().isLastCellValid() && (!activeEditor.isTableChanged() || new CcddDialogHandler().showMessageDialog(CcddTableEditorDialog.this, "<html><b>Discard changes?", "Discard Changes", JOptionPane.QUESTION_MESSAGE, DialogOption.OK_CANCEL_OPTION) == OK_BUTTON)) {
                // Close the active table. If this is the only table in the editor then close
                // the editor
                closeTableEditor(activeEditor.getOwnerName());
            }
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    };
    // Add the close listener to the Close button and menu command
    btnCloseActive.addActionListener(closeAction);
    mntmCloseActive.addActionListener(closeAction);
    // Create a listener for the Close All menu command
    mntmCloseAll.addActionListener(new ValidateCellActionListener() {

        /**
         ************************************************************************************
         * Close the table editor
         ************************************************************************************
         */
        @Override
        protected void performAction(ActionEvent ae) {
            windowCloseButtonAction();
        }

        /**
         ************************************************************************************
         * Get the reference to the currently displayed table
         ************************************************************************************
         */
        @Override
        protected CcddJTableHandler getTable() {
            return activeEditor.getTable();
        }
    });
    // Add buttons in the order in which they'll appear (left to right, top to bottom)
    buttonPnl.add(btnInsertRow);
    buttonPnl.add(btnMoveUp);
    buttonPnl.add(btnMoveLeft);
    buttonPnl.add(btnUndo);
    buttonPnl.add(btnStore);
    buttonPnl.add(btnDeleteRow);
    buttonPnl.add(btnMoveDown);
    buttonPnl.add(btnMoveRight);
    buttonPnl.add(btnRedo);
    buttonPnl.add(btnCloseActive);
    // Distribute the buttons across two rows
    setButtonRows(2);
    // Table Editors //////////////////////////////////////////////////////////////////////////
    // Create a tabbed pane for the editors to appear in
    tabbedPane = new DnDTabbedPane(JTabbedPane.TOP, CcddTableEditorDialog.class, true) {

        /**
         ************************************************************************************
         * Update the table editor list order following a tab move
         ************************************************************************************
         */
        @Override
        protected Object tabMoveCleanup(int oldTabIndex, int newTabIndex, Object tabContents) {
            CcddTableEditorHandler editor = (CcddTableEditorHandler) tabContents;
            // Check if the tab originated in the editor dialog
            if (oldTabIndex != -1) {
                // Get the reference to the moved tab's original location in the list
                editor = tableEditors.get(oldTabIndex);
                // Remove the table editor reference associated with the tab
                tableEditors.remove(oldTabIndex);
            } else // The tab originated in another editor dialog
            {
                // Bring the editor dialog to the foreground
                CcddTableEditorDialog.this.toFront();
            }
            // Check if the tab is to be placed within this editor
            if (newTabIndex != -1) {
                // Update the editor's reference to the dialog that owns it to this editor
                // dialog
                editor.setEditorDialog(CcddTableEditorDialog.this);
                // Add the table editor reference at the specified location
                tableEditors.add(newTabIndex - (oldTabIndex != -1 && newTabIndex > oldTabIndex ? 1 : 0), editor);
            }
            // Check if the last editor was removed from the dialog
            if (tableEditors.isEmpty()) {
                // Close the editor dialog
                CcddTableEditorDialog.this.closeFrame();
            } else // An editor remains in the dialog
            {
                // Update the active tab pointer
                activeEditor = tableEditors.get(tabbedPane.getSelectedIndex());
            }
            return editor;
        }

        /**
         ************************************************************************************
         * Move the specified tab's table to a new table editor dialog
         ************************************************************************************
         */
        @Override
        protected void spawnContainer(int tabIndex, Object tabContents) {
            // Create a new table editor dialog and place the editor from the other dialog into
            // it
            ccddMain.getTableEditorDialogs().add(new CcddTableEditorDialog(ccddMain, (CcddTableEditorHandler) tabContents));
        }
    };
    tabbedPane.setFont(ModifiableFontInfo.LABEL_BOLD.getFont());
    // Listen for tab selection changes
    tabbedPane.addChangeListener(new ChangeListener() {

        /**
         ************************************************************************************
         * Update the editor to the one associated with the selected tab
         ************************************************************************************
         */
        @Override
        public void stateChanged(ChangeEvent ce) {
            // Check if the tab index is within bounds
            if (tabbedPane.getSelectedIndex() >= 0 && tabbedPane.getSelectedIndex() < tableEditors.size()) {
                // Set the active editor to the selected tab
                activeEditor = tableEditors.get(tabbedPane.getSelectedIndex());
                // Change the dialog's title to the active table's name
                (CcddTableEditorDialog.this).setTitle(activeEditor.getOwnerName());
                // Update the expand/collapse arrays check box
                updateExpandArrayCheckBox();
                // Check if the Show macros command is not in effect
                if (!mntmShowMacros.isSelected()) {
                    // Update the editor controls state
                    setControlsEnabled(true);
                }
            }
        }
    });
    // Add each table as a tab in the editor dialog tabbed pane
    addTablePanes(tableInformation, editor);
    // Set the first tab as the active editor
    activeEditor = tableEditors.get(0);
    // Display the table editor dialog
    createFrame(ccddMain.getMainFrame(), tabbedPane, buttonPnl, null, activeEditor.getOwnerName(), null);
    // Enable the editor controls
    setControlsEnabled(true);
}
Also used : JPanel(javax.swing.JPanel) ActionEvent(java.awt.event.ActionEvent) JTextComponent(javax.swing.text.JTextComponent) DnDTabbedPane(CCDD.CcddClassesComponent.DnDTabbedPane) ActionListener(java.awt.event.ActionListener) ValidateCellActionListener(CCDD.CcddClassesComponent.ValidateCellActionListener) ChangeEvent(javax.swing.event.ChangeEvent) ButtonGroup(javax.swing.ButtonGroup) ValidateCellActionListener(CCDD.CcddClassesComponent.ValidateCellActionListener) ChangeListener(javax.swing.event.ChangeListener) Component(java.awt.Component) JTextComponent(javax.swing.text.JTextComponent) JMenuBar(javax.swing.JMenuBar) JMenu(javax.swing.JMenu)

Example 59 with JTextComponent

use of javax.swing.text.JTextComponent in project CCDD by nasa.

the class CcddTableEditorHandler method initialize.

/**
 ********************************************************************************************
 * Create the table editor
 ********************************************************************************************
 */
private void initialize() {
    // Set the table type definition
    setTypeDefinition();
    // Get the model column indices for columns with special input types
    getSpecialColumnIndices();
    // Create a copy of the table information
    setCommittedInformation(tableInfo);
    // Get the array size and index column indices and create a row filter to show/hide the
    // array member rows if an array size column exists
    setUpArraySizeColumn();
    // Define the table editor JTable
    table = new CcddJTableHandler(ModifiableSizeInfo.INIT_VIEWABLE_DATA_TABLE_ROWS.getSize()) {

        /**
         ************************************************************************************
         * Highlight any macros or special flags in the table cells
         *
         * @param component
         *            reference to the table cell renderer component
         *
         * @param text
         *            cell text
         *
         * @param isSelected
         *            true if the cell is to be rendered with the selection highlighted
         *
         * @param int
         *            row cell row, view coordinates
         *
         * @param column
         *            cell column, view coordinates
         ************************************************************************************
         */
        @Override
        protected void doSpecialRendering(Component component, String text, boolean isSelected, int row, int column) {
            // Highlight any macro names in the table cell. Adjust the highlight color to
            // account for the cell selection highlighting so that the macro is easily readable
            macroHandler.highlightMacro(component, text, isSelected ? ModifiableColorInfo.INPUT_TEXT.getColor() : ModifiableColorInfo.TEXT_HIGHLIGHT.getColor());
            // Highlight 'sizeof(data type)' instances
            CcddDataTypeHandler.highlightSizeof(component, text, isSelected ? ModifiableColorInfo.INPUT_TEXT.getColor() : ModifiableColorInfo.TEXT_HIGHLIGHT.getColor());
            // Highlight the flag that indicates the custom value for this cell is to be
            // removed and the prototype's value used instead. Create a highlighter painter
            DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(isSelected ? ModifiableColorInfo.INPUT_TEXT.getColor() : Color.MAGENTA);
            // Create the match pattern
            Pattern pattern = Pattern.compile("^" + Pattern.quote(REPLACE_INDICATOR));
            // Create the pattern matcher from the pattern
            Matcher matcher = pattern.matcher(text);
            // Check if there is a match in the cell value
            if (matcher.find()) {
                try {
                    // Highlight the matching text. Adjust the highlight color to account for
                    // the cell selection highlighting so that the search text is easily
                    // readable
                    ((JTextComponent) component).getHighlighter().addHighlight(matcher.start(), matcher.end(), painter);
                } catch (BadLocationException ble) {
                // Ignore highlighting failure
                }
            }
        }

        /**
         ************************************************************************************
         * Get the tool tip text for a table cell, showing any macro name replaced with its
         * corresponding macro value
         ************************************************************************************
         */
        @Override
        public String getToolTipText(MouseEvent me) {
            String toolTipText = null;
            // Get the row and column of the cell over which the mouse pointer is hovering
            Point point = me.getPoint();
            int row = rowAtPoint(point);
            int column = columnAtPoint(point);
            // Check if a cell is beneath the mouse pointer
            if (row != -1 && column != -1) {
                // Expand any macros in the cell text and display this as the cell's tool tip
                // text
                toolTipText = macroHandler.getMacroToolTipText(getValueAt(row, column).toString());
            }
            return toolTipText;
        }

        /**
         ************************************************************************************
         * Return true if the table data, column order, description, or a data field changes.
         * If the table isn't open in and editor (as when a macro is changed) then the table
         * description and data fields are not applicable
         ************************************************************************************
         */
        @Override
        protected boolean isTableChanged(Object[][] previousData, List<Integer> ignoreColumns) {
            boolean isFieldChanged = false;
            // and/or value change)
            if (editorDialog != null) {
                // Update the field information with the current text field values
                updateCurrentFieldValues(tableInfo.getFieldHandler().getFieldInformation());
                // Set the flag if the number of fields, field attributes, or field contents
                // have changed
                isFieldChanged = CcddFieldHandler.isFieldChanged(tableInfo.getFieldHandler().getFieldInformation(), committedInfo.getFieldHandler().getFieldInformation(), false);
            }
            return super.isTableChanged(previousData, ignoreColumns) || isFieldChanged || !getColumnOrder().equals(committedInfo.getColumnOrder()) || (editorDialog != null && !committedInfo.getDescription().equals(getDescription()));
        }

        /**
         ************************************************************************************
         * Allow multiple line display in all columns
         ************************************************************************************
         */
        @Override
        protected boolean isColumnMultiLine(int column) {
            return true;
        }

        /**
         ************************************************************************************
         * Hide the the specified columns
         ************************************************************************************
         */
        @Override
        protected boolean isColumnHidden(int column) {
            return column == primaryKeyIndex || column == rowIndex;
        }

        /**
         ************************************************************************************
         * Override isCellEditable to determine which cells can be edited
         ************************************************************************************
         */
        @Override
        public boolean isCellEditable(int row, int column) {
            // Initialize the flag to the table edit flag (based on the table edit flag this
            // enables normal editing or disables editing any cell)
            boolean isEditable = isEditEnabled;
            // one row
            if (isEditable && (isDisplayable() || editorDialog == null) && tableModel != null && tableModel.getRowCount() != 0) {
                // Convert the view row and column indices to model coordinates
                int modelRow = convertRowIndexToModel(row);
                int modelColumn = convertColumnIndexToModel(column);
                // Check if the cell is editable
                isEditable = isDataAlterable(((List<?>) tableModel.getDataVector().elementAt(modelRow)).toArray(new String[0]), modelRow, modelColumn);
            }
            return isEditable;
        }

        /**
         ************************************************************************************
         * Override isDataAlterable to determine which table data values can be changed
         *
         * @param rowData
         *            array containing the table row data
         *
         * @param row
         *            table row index in model coordinates
         *
         * @param column
         *            table column index in model coordinates
         *
         * @return true if the data value can be changed
         ************************************************************************************
         */
        @Override
        protected boolean isDataAlterable(Object[] rowData, int row, int column) {
            boolean isAlterable = true;
            // Check if the table data has at least one row
            if (rowData != null && rowData.length != 0) {
                // Copy the row of table data. This prevents the macro expansions for array
                // size and bit length below from changing the cell contents
                Object[] rowCopy = Arrays.copyOf(rowData, rowData.length);
                // Check if the array size column is present in this table
                if (arraySizeIndex != -1) {
                    // Expand any macros in the array size column
                    rowCopy[arraySizeIndex] = newMacroHandler.getMacroExpansion(rowCopy[arraySizeIndex].toString());
                }
                // Check if the array size column is present in this table
                if (bitLengthIndex != -1) {
                    // Expand any macros in the array size column
                    rowCopy[bitLengthIndex] = newMacroHandler.getMacroExpansion(rowCopy[bitLengthIndex].toString());
                }
                // Flag that is true if the row represents an array definition
                boolean isArrayDefinition = arraySizeIndex != -1 && variableNameIndex != -1 && !rowCopy[arraySizeIndex].toString().isEmpty() && !ArrayVariable.isArrayMember(rowCopy[variableNameIndex]);
                // Check if the cell is non-alterable based on the following criteria:
                if (// this is not a prototype table
                ((column == variableNameIndex || column == dataTypeIndex || column == arraySizeIndex || column == bitLengthIndex) && !tableInfo.isPrototype()) || // displays an array member
                ((column == variableNameIndex || column == dataTypeIndex || column == arraySizeIndex) && ArrayVariable.isArrayMember(rowCopy[variableNameIndex])) || // isn't valid for structures
                (dataTypeIndex != -1 && !dataTypeHandler.isPrimitive(rowCopy[dataTypeIndex].toString()) && !typeDefn.isStructureAllowed()[column]) || // This data type is a pointer and the column isn't valid for pointers
                (dataTypeIndex != -1 && dataTypeHandler.isPointer(rowCopy[dataTypeIndex].toString()) && !typeDefn.isPointerAllowed()[column]) || // This is the enumeration or rate cell in a row displaying an array definition
                ((isArrayDefinition && enumerationIndex.contains(column) && rateIndex.contains(column))) || // type is not an integer (signed or unsigned)
                (column == bitLengthIndex && ((arraySizeIndex != -1 && !rowCopy[arraySizeIndex].toString().isEmpty()) || (dataTypeIndex != -1 && !dataTypeHandler.isInteger(rowCopy[dataTypeIndex].toString())))) || // length is present
                (column == arraySizeIndex && ((variableNameIndex != -1 && rowCopy[variableNameIndex].toString().isEmpty()) || (bitLengthIndex != -1 && !rowCopy[bitLengthIndex].toString().isEmpty()))) || // This is a rate cell, and a data type exists that is not a primitive
                (rateIndex.contains(column) && dataTypeIndex != -1 && !rowCopy[dataTypeIndex].toString().isEmpty() && !dataTypeHandler.isPrimitive(rowCopy[dataTypeIndex].toString())) || // first array member
                (variableNameIndex != -1 && dataTypeIndex != -1 && dataTypeHandler.isString(rowCopy[dataTypeIndex].toString()) && ArrayVariable.isArrayMember(rowCopy[variableNameIndex]) && !rowCopy[variableNameIndex].toString().endsWith("[0]")) || // the variable path
                (isArrayDefinition && (typeDefn.getInputTypes()[column].equals(InputDataType.MESSAGE_ID) || column == variablePathIndex)) || // variables in a non-root prototype structure
                (column == variablePathIndex && rowCopy[variablePathIndex].toString().isEmpty())) {
                    // Set the flag to prevent altering the data value
                    isAlterable = false;
                } else // Check the column groupings
                {
                    // Step through each column grouping
                    for (AssociatedColumns colGrp : associatedColumns) {
                        // Check if the cell is non-alterable based on the following criteria:
                        if ((// isn't an integer type (signed or unsigned)
                        column == colGrp.getEnumeration() && !dataTypeHandler.isInteger(rowCopy[colGrp.getDataType()].toString())) || // defined
                        ((column == colGrp.getMinimum() || column == colGrp.getMaximum()) && rowCopy[colGrp.getDataType()].toString().isEmpty())) {
                            // Set the flag to prevent altering the data value and stop
                            // searching
                            isAlterable = false;
                            break;
                        }
                    }
                    // Check if no command argument pairing reset the flag
                    if (isAlterable) {
                        // Step through each non-command argument minimum/maximum pairing
                        for (MinMaxPair minMax : minMaxPair) {
                            // is missing, empty, or isn't a primitive type
                            if (dataTypeIndex != -1 && (rowCopy[dataTypeIndex].toString().isEmpty() || !dataTypeHandler.isPrimitive(rowCopy[dataTypeIndex].toString())) && (column == minMax.getMinimum() || column == minMax.getMaximum())) {
                                // Set the flag to prevent altering the data value and stop
                                // searching
                                isAlterable = false;
                                break;
                            }
                        }
                    }
                }
            }
            return isAlterable;
        }

        /**
         ************************************************************************************
         * Override getCellEditor so that for a data type column cell in a row where the
         * enumeration cell isn't empty the combo box editor that displays only integer data
         * types (signed and unsigned) is returned; for all other cells return the normal cell
         * editor
         *
         * @param row
         *            table view row number
         *
         * @param column
         *            table view column number
         *
         * @return The cell editor for the specified row and column
         ************************************************************************************
         */
        @Override
        public TableCellEditor getCellEditor(int row, int column) {
            // Get the editor for this cell
            TableCellEditor cellEditor = super.getCellEditor(row, column);
            // Convert the row and column indices to the model coordinates
            int modelRow = convertRowIndexToModel(row);
            int modelColumn = convertColumnIndexToModel(column);
            // column and the bit length cell is not empty
            if (modelColumn == dataTypeIndex && bitLengthIndex != -1 && !getExpandedValueAt(modelRow, bitLengthIndex).isEmpty()) {
                // Select the combo box cell editor that displays only integer data types
                // (signed and unsigned)
                cellEditor = enumDataTypeCellEditor;
            } else // Check if this is a data type and enumeration pairing or a command argument
            // column grouping
            {
                // Step through each column grouping
                for (AssociatedColumns colGrp : associatedColumns) {
                    // type column, and that the associated enumeration cell isn't blank
                    if (modelColumn == colGrp.getDataType() && colGrp.getEnumeration() != -1 && !getExpandedValueAt(modelRow, colGrp.getEnumeration()).isEmpty()) {
                        // Select the combo box cell editor that displays only integer data
                        // types (signed and unsigned) and stop searching
                        cellEditor = enumDataTypeCellEditor;
                        break;
                    }
                }
            }
            return cellEditor;
        }

        /**
         ************************************************************************************
         * Validate changes to the editable cells; e.g., verify cell content and, if found
         * invalid, revert to the original value. Update array members if needed
         *
         * @param tableData
         *            list containing the table data row arrays
         *
         * @param row
         *            table model row index
         *
         * @param column
         *            table model column index
         *
         * @param oldValue
         *            original cell contents
         *
         * @param newValue
         *            new cell contents
         *
         * @param showMessage
         *            true to display the invalid input dialog, if applicable
         *
         * @param isMultiple
         *            true if this is one of multiple cells to be entered and checked; false if
         *            only a single input is being entered
         *
         * @return true to indicate that subsequent errors should be displayed; false if
         *         subsequent errors should not be displayed; null if the operation should be
         *         canceled
         ************************************************************************************
         */
        @Override
        protected Boolean validateCellContent(List<Object[]> tableData, int row, int column, Object oldValue, Object newValue, Boolean showMessage, boolean isMultiple) {
            // Reset the flag that indicates the last edited cell's content is invalid
            setLastCellValid(true);
            try {
                // Set the parameters that govern recalculating packed variables to begin with
                // the first row in the table and to use the first variable in the pack to set
                // the rates for other variables in the same pack
                int startRow = 0;
                boolean useRowRate = false;
                // Create a string version of the new value, replacing any macro in the text
                // with its corresponding value
                String newValueS = newMacroHandler.getMacroExpansion(newValue.toString(), validDataTypes);
                // to this structure's prototype or the prototype of one of its children
                if (variableHandler.isInvalidReference()) {
                    throw new CCDDException("Invalid input value in column '</b>" + typeDefn.getColumnNamesUser()[column] + "<b>'; data type invalid or unknown in sizeof() call");
                }
                // Check if the cell is flagged for replacement by the prototype value
                if (newValueS.startsWith(REPLACE_INDICATOR)) {
                    // Remove the flag so that the updated value is stored as a custom value
                    newValueS = newValueS.replaceFirst("^" + REPLACE_INDICATOR, "");
                }
                // Check that the new value isn't blank
                if (!newValueS.isEmpty()) {
                    // Check if the values in this column must not be duplicated
                    if (typeDefn.isRowValueUnique()[column]) {
                        // Step through each row in the table
                        for (int otherRow = 0; otherRow < tableData.size(); otherRow++) {
                            // matches the one being added (case insensitive)
                            if (otherRow != row && newValueS.equalsIgnoreCase(getExpandedValueAt(tableData, otherRow, column))) {
                                throw new CCDDException("Invalid input value for column '</b>" + typeDefn.getColumnNamesUser()[column] + "<b>'; value must be unique");
                            }
                        }
                    }
                    // Step through each column grouping
                    for (AssociatedColumns colGrp : associatedColumns) {
                        // Check if this is a name column
                        if (column == colGrp.getName()) {
                            // Step through the column groupings
                            for (AssociatedColumns otherColGrp : associatedColumns) {
                                // name matches the name of another command argument
                                if (!colGrp.equals(otherColGrp) && newValueS.equals(getExpandedValueAt(tableData, row, otherColGrp.getName()))) {
                                    throw new CCDDException("Invalid input value for column '</b>" + typeDefn.getColumnNamesUser()[column] + "<b>'; command argument names must be unique for a command");
                                }
                            }
                        } else // Check if this is the minimum or maximum value columns
                        if (column == colGrp.getMinimum() || column == colGrp.getMaximum()) {
                            // Verify that the minimum/maximum value is valid for the
                            // argument's data type, and stop searching
                            validateMinMaxContent(tableData, row, column, newValueS, colGrp.getDataType(), colGrp.getMinimum(), colGrp.getMaximum());
                            break;
                        }
                    }
                    // Step through each minimum/maximum pairing
                    for (MinMaxPair minMax : minMaxPair) {
                        // Check if this is the minimum or maximum value columns
                        if (column == minMax.getMinimum() || column == minMax.getMaximum()) {
                            // Verify that the minimum/maximum value is valid for the
                            // argument's data type, and stop searching
                            validateMinMaxContent(tableData, row, column, newValueS, dataTypeIndex, minMax.getMinimum(), minMax.getMaximum());
                            break;
                        }
                    }
                    // Check if the value doesn't match the expected input type
                    if (!newValueS.matches(typeDefn.getInputTypes()[column].getInputMatch())) {
                        throw new CCDDException("Invalid characters in column '</b>" + typeDefn.getColumnNamesUser()[column] + "<b>'; characters consistent with input type '" + typeDefn.getInputTypes()[column].getInputName() + "' expected");
                    }
                    // Check if this is a message ID name column
                    if (msgIDNameIndex.contains(column)) {
                        // The message ID, which is included with the ID name in the combo box
                        // list, doesn't appear when the item is selected from the list, so
                        // remove the ID
                        newValueS = newValueS.replaceFirst(" \\(.*", "");
                    }
                }
                // Flag that indicates that the new cell value contains a macro and/or a
                // sizeof() call
                boolean hasMacroSizeof = CcddMacroHandler.hasMacro(newValue.toString()) || CcddVariableSizeAndConversionHandler.hasSizeof(newValue.toString());
                // prevents the macro reference from being lost
                if (!hasMacroSizeof) {
                    // Store the new value in the table data array after formatting the cell
                    // value per its input type. This is needed primarily to clean up numeric
                    // formatting
                    newValueS = typeDefn.getInputTypes()[column].formatInput(newValueS);
                    newValue = newValueS;
                    tableData.get(row)[column] = newValueS;
                }
                // Replace any macro in the original text with its corresponding value
                String oldValueS = macroHandler.getMacroExpansion(oldValue.toString());
                // original text with its corresponding value
                if (!newValueS.equals(oldValueS)) {
                    String variableName = null;
                    String dataType = null;
                    String arraySize = null;
                    String bitLength = null;
                    // Check if the variable name column exists
                    if (variableNameIndex != -1) {
                        // Get the variable name for the current row, expanding macros in the
                        // name (if present)
                        variableName = getExpandedValueAt(tableData, row, variableNameIndex);
                    }
                    // Check if the data type column exists
                    if (dataTypeIndex != -1) {
                        // Get the data type for the current row
                        dataType = tableData.get(row)[dataTypeIndex].toString();
                    }
                    // Check if the array size column exists
                    if (arraySizeIndex != -1) {
                        // Get the array size for the current row, expanding macros in the
                        // value (if present)
                        arraySize = getExpandedValueAt(tableData, row, arraySizeIndex);
                    }
                    // Check if the bit length column exists
                    if (bitLengthIndex != -1) {
                        // Get the bit length for the current row, expanding macros in the
                        // value (if present)
                        bitLength = getExpandedValueAt(tableData, row, bitLengthIndex);
                    }
                    // Check if the variable name or data type has been changed
                    if (column == variableNameIndex || column == dataTypeIndex) {
                        // if a data type is pasted into the cell
                        if (invalidDataTypes != null && invalidDataTypes.contains(dataType)) {
                            throw new CCDDException("Data type '</b>" + dataType + "<b>' invalid; structure cannot reference itself or an ancestor");
                        }
                        // Check if the variable is an array
                        if (arraySize != null) {
                            // and the bit length exceeds the size of the data type in bits
                            if (column == dataTypeIndex && !newValueS.isEmpty() && bitLength != null && !bitLength.isEmpty() && Integer.valueOf(bitLength) > newDataTypeHandler.getSizeInBits(dataType)) {
                                throw new CCDDException("Bit length exceeds the size of the data type");
                            }
                            // Get the array index values from the array size column and update
                            // array members if this is an array definition
                            int[] arrayDims = ArrayVariable.getArrayIndexFromSize(arraySize);
                            adjustArrayMember(tableData, arrayDims, arrayDims, row, column);
                        }
                        // manually set
                        if (variablePathIndex != -1 && tableData.get(row)[variablePathIndex].toString().equals(getVariablePath((column == variableNameIndex ? oldValueS : variableName), (column == dataTypeIndex ? oldValueS : dataType), true))) {
                            // Update the variable path with the new variable name and/or data
                            // type
                            tableData.get(row)[variablePathIndex] = getVariablePath(variableName, dataType, true);
                        }
                    } else // Check if this is the array size column
                    if (column == arraySizeIndex) {
                        // Get the original and updated array index values
                        int[] arraySizeOld = ArrayVariable.getArrayIndexFromSize(oldValueS);
                        int[] arraySizeNew = ArrayVariable.getArrayIndexFromSize(newValueS);
                        // Set the flag that indicates the array index values changed based on
                        // the number of index values changing
                        boolean isDifferent = arraySizeOld.length != arraySizeNew.length;
                        // individual array index values must be compared
                        if (!isDifferent) {
                            // Step through each index value
                            for (int index = 0; index < arraySizeOld.length; index++) {
                                // Check if the original and updated values differ
                                if (arraySizeOld[index] != arraySizeNew[index]) {
                                    // Set the flag to indicate an index value changed and stop
                                    // searching
                                    isDifferent = true;
                                    break;
                                }
                            }
                        }
                        // Check if the original and updated values differ
                        if (isDifferent) {
                            // Add or remove array members to match the new array size
                            adjustArrayMember(tableData, arraySizeOld, arraySizeNew, row, column);
                        }
                    } else // Check if this is the rate column and the row is an array definition
                    if (rateIndex.contains(column) && arraySize != null && variableName != null && !arraySize.isEmpty() && !ArrayVariable.isArrayMember(variableName)) {
                        // Get the array index value(s)
                        int[] arrayDims = ArrayVariable.getArrayIndexFromSize(arraySize);
                        // Update the array members with the new rate
                        adjustArrayMember(tableData, arrayDims, arrayDims, row, column);
                    } else // Check if this is the rate column and the variable has a bit length value
                    if (rateIndex.contains(column) && bitLength != null && dataType != null && !bitLength.isEmpty()) {
                        // Adjust the rates of any other bit-wise variables that are packed
                        // together with this variable, using this row's rate
                        startRow = row;
                        useRowRate = true;
                    } else // Check if this is the bit length column
                    if (column == bitLengthIndex) {
                        // data type
                        if (bitLength != null && !bitLength.isEmpty() && dataType != null && Integer.valueOf(bitLength) > newDataTypeHandler.getSizeInBits(dataType)) {
                            throw new CCDDException("Bit length exceeds the size of the data type");
                        }
                        // Adjust the rates of any other bit-wise variables that are packed
                        // together with this variable, using the first packed variable's rate
                        startRow = row;
                    } else // Check if this is the variable path column
                    if (column == variablePathIndex && variableName != null && !variableName.isEmpty() && dataType != null && !dataType.isEmpty()) {
                        // entered
                        if (!newValueS.isEmpty()) {
                            // another structure table
                            if (variableHandler.isVariablePathInUse(tableInfo.getTablePath() + "," + dataType + "." + variableName, newValueS)) {
                                throw new CCDDException("Variable path already in use in another structure");
                            }
                        } else // The cell has been blanked
                        {
                            // Build the variable path from the variable name and data type
                            tableData.get(row)[variablePathIndex] = getVariablePath(variableName, dataType, false);
                        }
                    } else // array
                    if (variableName != null && dataType != null && arraySize != null && column != variableNameIndex && column != dataTypeIndex && column != arraySizeIndex && column != variablePathIndex && !arraySize.isEmpty() && (!ArrayVariable.isArrayMember(variableName) || newDataTypeHandler.isString(dataType))) {
                        // Propagate the value to all members of this array/string
                        propagateArrayValues(tableData, row, column);
                    }
                    // Clear the contents of any cells that are no longer valid in this row
                    clearInvalidCells(tableData.get(row), row);
                    // Adjust the rates of the bit-wise variables that are packed together,
                    // beginning at the indicated row
                    setAllPackedVariableRates(tableData, startRow, useRowRate);
                    // Check if the new value contains any macros
                    if (hasMacroSizeof) {
                        // Store the new value, with the macro(s) restored, into the table data
                        // array
                        tableData.get(row)[column] = newValue;
                    }
                } else // vice versa)
                if (!newValue.equals(oldValue)) {
                    // Store the new value in the table data array
                    tableData.get(row)[column] = newValue;
                    // Check if the column is the array size
                    if (column == arraySizeIndex) {
                        // Propagate the value to all members of this array/string
                        propagateArrayValues(tableData, row, column);
                    }
                } else // The cell value didn't change
                {
                    // Pop the edit from the stack
                    table.getUndoManager().undoRemoveEdit();
                }
            } catch (CCDDException ce) {
                // Set the flag that indicates the last edited cell's content is invalid
                setLastCellValid(false);
                // Check if the error message dialog should be displayed
                if (showMessage) {
                    // Check if this is a single cell insert
                    if (!isMultiple) {
                        // Inform the user that the input value is invalid
                        new CcddDialogHandler().showMessageDialog(editorDialog, "<html><b>" + ce.getMessage(), "Invalid Input", JOptionPane.WARNING_MESSAGE, DialogOption.OK_OPTION);
                    } else // This is one of multiple cells being inserted
                    {
                        // Inform the user that the input value is invalid
                        CcddDialogHandler validityDlg = new CcddDialogHandler();
                        int buttonSelected = validityDlg.showIgnoreCancelDialog(editorDialog, "<html><b>" + ce.getMessage(), "Invalid Input", "Ignore this invalid input", "Ignore this and any remaining invalid inputs for this table", "Cease inputting values");
                        // Check if the Ignore All button was pressed
                        if (buttonSelected == IGNORE_BUTTON) {
                            // Set the flag to ignore subsequent input errors
                            showMessage = false;
                        } else // Check if the Cancel button was pressed
                        if (buttonSelected == CANCEL_BUTTON) {
                            // Set the flag to cancel updating the cells
                            showMessage = null;
                        }
                    }
                }
                // Restore the cell contents to its original value and pop the edit from the
                // stack
                tableData.get(row)[column] = oldValue;
                table.getUndoManager().undoRemoveEdit();
            }
            return showMessage;
        }

        /**
         ************************************************************************************
         * Clear the contents of cells in the specified row that are no longer valid due to the
         * contents of other cells
         *
         * @param tableData
         *            list containing the table data row arrays
         *
         * @param row
         *            table model row index
         ************************************************************************************
         */
        private void clearInvalidCells(Object[] rowData, int row) {
            // Step through each visible column
            for (int column = 0; column < getColumnCount(); column++) {
                // Get the column index in model coordinates
                int modelColumn = convertColumnIndexToModel(column);
                if (// rate, or variable path column, and that the cell is not alterable
                (modelColumn != variableNameIndex && modelColumn != dataTypeIndex && modelColumn != arraySizeIndex && modelColumn != bitLengthIndex && modelColumn != variablePathIndex && !rateIndex.contains(modelColumn) && !isDataAlterable(rowData, row, modelColumn)) || // (i.e., it's a structure), and structures are not allowed for this column
                (dataTypeIndex != -1 && !newDataTypeHandler.isPrimitive(rowData[dataTypeIndex].toString()) && !typeDefn.isStructureAllowed()[modelColumn]) || // pointers are not allowed for this column
                (dataTypeIndex != -1 && newDataTypeHandler.isPointer(rowData[dataTypeIndex].toString()) && !typeDefn.isPointerAllowed()[modelColumn]) || // data type isn't a primitive
                (dataTypeIndex != -1 && modelColumn == bitLengthIndex && !newDataTypeHandler.isPrimitive(rowData[dataTypeIndex].toString()))) {
                    // Clear the contents of the cell
                    rowData[modelColumn] = "";
                }
            }
        }

        /**
         ************************************************************************************
         * Load the database values into the table and format the table cells
         ************************************************************************************
         */
        @Override
        protected void loadAndFormatData() {
            // Place the data into the table model along with the column names, set up the
            // editors and renderers for the table cells, set up the table grid lines, and
            // calculate the minimum width required to display the table information
            int totalWidth = setUpdatableCharacteristics(committedInfo.getData(), typeDefn.getColumnNamesUser(), committedInfo.getColumnOrder(), toolTips, true, true, true);
            // editor dialog
            if (editorDialog != null) {
                // Get the minimum width needed to display all columns, but no wider than the
                // display
                int width = Math.min(totalWidth + LAF_SCROLL_BAR_WIDTH, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getWidth());
                // Check if the editor's width is less than the minimum
                if (editorDialog.getTableWidth() < width) {
                    // Set the initial and preferred editor size
                    editorDialog.setTableWidth(width);
                    editorDialog.setPreferredSize(new Dimension(width, editorDialog.getPreferredSize().height));
                }
            }
            // Create the drop-down combo box for the column with the name 'data type' that
            // displays the available data types, including primitive types and the names of
            // tables that represent structures, and add a mouse listener to handle mouse click
            // events. Set up any command argument data type, argument name, enumeration,
            // minimum, and maximum groupings
            setUpDataTypeColumns(null, null);
            // Set up any minimum and maximum pairings (excluding those associated with command
            // argument groupings)
            setUpMinMaxColumns();
            // Create drop-down combo boxes that display the available sample rates for the
            // "Rate" column
            setUpSampleRateColumn();
            // Create drop-down combo boxes that display the available message ID names and
            // values
            setUpMsgNamesAndIDsColumn(null);
            // Create the mouse listener for the data type column
            createDataTypeColumnMouseListener();
        }

        /**
         ************************************************************************************
         * Override prepareRenderer to allow adjusting the background colors of table cells
         ************************************************************************************
         */
        @Override
        public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
            JComponent comp = (JComponent) super.prepareRenderer(renderer, row, column);
            // highlight colors override the invalid highlight color
            if (comp.getBackground() != ModifiableColorInfo.FOCUS_BACK.getColor() && comp.getBackground() != ModifiableColorInfo.SELECTED_BACK.getColor()) {
                // contain an item in the list
                if (!isCellValueFound(row, column)) {
                    // Change the cell's background color
                    comp.setBackground(ModifiableColorInfo.REQUIRED_BACK.getColor());
                } else // Check if this cell is protected from changes
                if (!isCellEditable(row, column)) {
                    // Change the cell's text and background colors
                    comp.setForeground(ModifiableColorInfo.PROTECTED_TEXT.getColor());
                    comp.setBackground(ModifiableColorInfo.PROTECTED_BACK.getColor());
                } else // variable
                if (variableNameIndex != -1 && getExpandedValueAt(table.convertRowIndexToModel(row), variableNameIndex).toString().matches(PAD_VARIABLE + "[0-9]+(?:\\[[0-9]+\\])?$")) {
                    // Change the cell's background color
                    comp.setBackground(ModifiableColorInfo.PADDING_BACK.getColor());
                }
            }
            return comp;
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method to handle right double click events on the
         * array size cells in order to show/hide the array index column and array member rows,
         * and to handle sorting of columns based on their input type
         ************************************************************************************
         */
        @Override
        protected void setTableSortable() {
            super.setTableSortable();
            // Get the table's row sorter
            TableRowSorter<?> sorter = (TableRowSorter<?>) getRowSorter();
            // Create a runnable object to be executed
            SwingUtilities.invokeLater(new Runnable() {

                /**
                 ****************************************************************************
                 * Execute after all pending Swing events are finished. This allows the number
                 * of viewable columns to catch up with the column model when a column is
                 * removed
                 ****************************************************************************
                 */
                @Override
                public void run() {
                    // Issue a table change event so that the new row is displayed properly
                    // when the array view is collapsed. Can't use tableModel here since it
                    // isn't set when the first call to this method is made
                    ((UndoableTableModel) table.getModel()).fireTableStructureChanged();
                }
            });
            // Check if the table has a sorter (i.e., has at least one row)
            if (sorter != null) {
                // filter
                if (sorter.getRowFilter() == null && rowFilter != null) {
                    // Apply the row filter that shows/hides the array members
                    sorter.setRowFilter(rowFilter);
                }
                // Step through each table column
                for (int column = 0; column < table.getModel().getColumnCount(); column++) {
                    // Get the input type format for this column
                    final InputTypeFormat inputFormat = typeDefn.getInputTypes()[column].getInputFormat();
                    // Add a column sort comparator
                    sorter.setComparator(column, new Comparator<String>() {

                        /**
                         ********************************************************************
                         * Override the comparison when sorting columns to account for the
                         * column's input type format. Note that macros aren't expanded when
                         * sorting. Though expansion provides an accurate sort, visually it's
                         * confusing since the macro values aren't readily apparent. For
                         * columns with a numeric input type that contain macros then initial
                         * numeric portion (if any) if used when sorting
                         ********************************************************************
                         */
                        @Override
                        public int compare(String cell1, String cell2) {
                            Integer result = 0;
                            // Check if either cell is empty
                            if (cell1.isEmpty() || cell2.isEmpty()) {
                                // Compare as text (alphabetically)
                                result = cell1.compareTo(cell2);
                            } else // Neither cell is empty
                            {
                                // type
                                switch(inputFormat) {
                                    case TEXT:
                                    case DATA_TYPE:
                                    case ENUMERATION:
                                    case PAGE_FORMAT:
                                    case VARIABLE_PATH:
                                    case BOOLEAN:
                                        // Compare as text (alphabetically)
                                        result = cell1.compareTo(cell2);
                                        break;
                                    default:
                                        // number
                                        if (cell1.matches(InputDataType.INTEGER.getInputMatch() + ".*") && cell2.matches(InputDataType.INTEGER.getInputMatch() + ".*")) {
                                            switch(inputFormat) {
                                                case INTEGER:
                                                    // Compare the two cell values as integers
                                                    result = Integer.compare(Integer.valueOf(cell1.replaceAll("(" + InputDataType.INTEGER.getInputMatch() + ").*", "$1")), Integer.valueOf(cell2.replaceAll("(" + InputDataType.INTEGER.getInputMatch() + ").*", "$1")));
                                                    break;
                                                case HEXADECIMAL:
                                                    // Compare the two cell values as integers
                                                    result = Integer.compare(Integer.decode(cell1.replaceAll("(" + InputDataType.HEXADECIMAL.getInputMatch() + ").*", "$1")), Integer.decode(cell2.replaceAll("(" + InputDataType.HEXADECIMAL.getInputMatch() + ").*", "$1")));
                                                    break;
                                                case FLOAT:
                                                case MINIMUM:
                                                case MAXIMUM:
                                                    // Compare the two cell values as floating
                                                    // points
                                                    result = Double.compare(Double.valueOf(cell1.replaceAll("(" + InputDataType.FLOAT.getInputMatch() + ").*", "$1")), Double.valueOf(cell2.replaceAll("(" + InputDataType.FLOAT.getInputMatch() + ").*", "$1")));
                                                    break;
                                                case RATE:
                                                    // Calculate the value of the cells'
                                                    // expressions, then compare the results as
                                                    // floating point values
                                                    result = Double.compare(CcddMathExpressionHandler.evaluateExpression(cell1), CcddMathExpressionHandler.evaluateExpression(cell2));
                                                    break;
                                                case ARRAY:
                                                    // Array sizes are in the format #<,#<...>.
                                                    // Each cell's array dimensions are first
                                                    // separated, then the first dimension is
                                                    // compared between the two cells, then the
                                                    // second, and so on until a mismatch is
                                                    // found; the sort is performed based on
                                                    // the mismatch (e.g., '1, 2' follows '1'
                                                    // when sorted in ascending order)
                                                    String[] dim1 = cell1.split("\\s*,\\s*");
                                                    String[] dim2 = cell2.split("\\s*,\\s*");
                                                    // same dimensions than the second
                                                    if (dim1.length == dim2.length) {
                                                        // long as there's no mismatch
                                                        for (int index = 0; index < dim1.length && result == 0; index++) {
                                                            // sizeof() call)
                                                            if (dim1[index].matches(InputDataType.INTEGER.getInputMatch()) && dim2[index].matches(InputDataType.INTEGER.getInputMatch())) {
                                                                // Compare the two array
                                                                // dimensions
                                                                result = Integer.compare(Integer.valueOf(dim1[index]), Integer.valueOf(dim2[index]));
                                                            } else // One or both dimension values
                                                            // isn't a number
                                                            {
                                                                // Compare as text
                                                                // (alphabetically)
                                                                result = dim1[index].compareTo(dim2[index]);
                                                            }
                                                        }
                                                    } else // fewer dimensions than the second
                                                    if (dim1.length < dim2.length) {
                                                        // long as there's no mismatch
                                                        for (int index = 0; index < dim1.length && result == 0; index++) {
                                                            // sizeof() call)
                                                            if (dim1[index].matches(InputDataType.INTEGER.getInputMatch()) && dim2[index].matches(InputDataType.INTEGER.getInputMatch())) {
                                                                // Compare the two array
                                                                // dimensions
                                                                result = Integer.compare(Integer.valueOf(dim1[index]), Integer.valueOf(dim2[index]));
                                                            } else // One or both dimension values
                                                            // isn't a number
                                                            {
                                                                // Compare as text
                                                                // (alphabetically)
                                                                result = dim1[index].compareTo(dim2[index]);
                                                            }
                                                        }
                                                        // dimension values are identical
                                                        if (result == 0) {
                                                            // Set the result to indicate the
                                                            // first cell comes before the
                                                            // second since the second has more
                                                            // dimensions
                                                            result = -1;
                                                        }
                                                    } else // The first array size has the more
                                                    // dimensions than the second
                                                    {
                                                        // long as there's no mismatch
                                                        for (int index = 0; index < dim2.length && result == 0; index++) {
                                                            // sizeof() call)
                                                            if (dim1[index].matches(InputDataType.INTEGER.getInputMatch()) && dim2[index].matches(InputDataType.INTEGER.getInputMatch())) {
                                                                // Compare the two array
                                                                // dimensions
                                                                result = Integer.compare(Integer.valueOf(dim1[index]), Integer.valueOf(dim2[index]));
                                                            } else // One or both dimension values
                                                            // isn't a number
                                                            {
                                                                // Compare as text
                                                                // (alphabetically)
                                                                result = dim1[index].compareTo(dim2[index]);
                                                            }
                                                        }
                                                        // dimension values are identical
                                                        if (result == 0) {
                                                            // Set the result to indicate the
                                                            // first cell comes after the
                                                            // second since the second has
                                                            // fewer dimensions
                                                            result = 1;
                                                        }
                                                    }
                                                    break;
                                                default:
                                                    break;
                                            }
                                        } else // One or both cells doesn't begin with a number (this
                                        // is the case if the cell begins with a macro or
                                        // sizeof() call)
                                        {
                                            // Compare as text (alphabetically)
                                            result = cell1.compareTo(cell2);
                                        }
                                }
                            }
                            return result;
                        }
                    });
                }
            }
        }

        /**
         ************************************************************************************
         * Move the selected row(s) in the specified direction if possible. Account for if the
         * selection or target is an array definition or member
         *
         * @param rowDelta
         *            row move direction (-1 for up, +1 for down)
         ************************************************************************************
         */
        private void adjustAndMoveSelectedRows(int rowDelta) {
            int modelStartRow;
            int modelEndRow;
            boolean isCanMove = false;
            // Set the selected start and end rows
            MoveCellSelection selected = new MoveCellSelection();
            // Set the selected start and end rows (model coordinates), and the direction to
            // move
            modelStartRow = selected.getStartRow();
            modelEndRow = selected.getEndRow();
            // Check if the selected row(s) can be moved in the desired direction
            if ((rowDelta < 0 && modelStartRow > 0) || (rowDelta > 0 && modelEndRow < tableModel.getRowCount() - 1)) {
                // Check if the table can display arrays
                if (isCanHaveArrays()) {
                    // While the start row references an array member
                    while (ArrayVariable.isArrayMember(getExpandedValueAt(modelStartRow, variableNameIndex))) {
                        // Decrement the start index to get to the array definition row
                        modelStartRow--;
                    }
                    // Check if the selected ending row references an array definition
                    if (!getExpandedValueAt(modelEndRow, arraySizeIndex).isEmpty() && !ArrayVariable.isArrayMember(getExpandedValueAt(modelEndRow, variableNameIndex))) {
                        // Increment the end row so that the members will be included below
                        modelEndRow++;
                    }
                    boolean isIncludeMember = false;
                    // model hasn't been reached
                    while (modelEndRow < tableModel.getRowCount() && ArrayVariable.isArrayMember(getExpandedValueAt(modelEndRow, variableNameIndex))) {
                        // Increment the end index to get to the end of the array
                        modelEndRow++;
                        isIncludeMember = true;
                    }
                    // Check if the ending row was adjusted to include an array member
                    if (isIncludeMember) {
                        // Decrement the row index since the row selection is inclusive
                        modelEndRow--;
                    }
                    // Check if the selected row(s) can be moved in the desired direction
                    if ((rowDelta < 0 && modelStartRow > 0) || (rowDelta > 0 && modelEndRow < tableModel.getRowCount() - 1)) {
                        // Get the array size column value for the target row
                        String arraySize = getExpandedValueAt((rowDelta < 0 ? modelStartRow : modelEndRow) + rowDelta, arraySizeIndex);
                        // Check if the array size is present on this row
                        if (!arraySize.isEmpty()) {
                            // Get the total number of array members
                            int totalSize = ArrayVariable.getNumMembersFromArraySize(arraySize);
                            // Adjust the number of rows to move based on the number of array
                            // members
                            rowDelta += totalSize * rowDelta;
                        }
                        // Set the flag to indicate the selected row(s) can be moved
                        isCanMove = true;
                    }
                } else // The table can't have an array
                {
                    // Set the flag to indicate the selected row(s) can be moved
                    isCanMove = true;
                }
                // Calculate the row that the selected row(s) will be moved to
                int modelToRow = modelStartRow + rowDelta;
                // Check if the selected row(s) can be moved
                if (isCanMove) {
                    // Move the row(s) in the specified direction and update the cell selection
                    performRowMove(modelStartRow, modelEndRow, modelToRow, selected, rowDelta);
                }
            }
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for moving the selected row(s) up one row in
         * order to prevent moving a row within an array definition and its member rows;
         * instead skip past the array
         ************************************************************************************
         */
        @Override
        protected void moveRowUp() {
            // Move the selected row(s) up if possible
            adjustAndMoveSelectedRows(-1);
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for moving the selected row(s) down one row in
         * order to prevent moving a row within an array definition and its member rows;
         * instead skip past the array
         ************************************************************************************
         */
        @Override
        protected void moveRowDown() {
            // Move the selected row(s) down if possible
            adjustAndMoveSelectedRows(1);
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for moving the selected row(s) so that
         * adjustments can be made to the rates for any packed variables
         *
         * @param startRow
         *            selected starting row, in model coordinates
         *
         * @param endRow
         *            selected ending row, in model coordinates
         *
         * @param toRow
         *            target row to move the selected row(s) to, in model coordinates
         *
         * @param selected
         *            cell selection class
         *
         * @param rowDelta
         *            row move direction and magnitude
         ************************************************************************************
         */
        @Override
        protected void performRowMove(int startRow, int endRow, int toRow, MoveCellSelection selected, int rowDelta) {
            // Move the row(s)
            super.performRowMove(startRow, endRow, toRow, selected, rowDelta);
            // Check if this is a parent structure table
            if (tableInfo.isRootStructure()) {
                // Load the table data into a list
                List<Object[]> tableData = getTableDataList(false);
                // Adjust the rate for any packed variables, beginning with the lowest affected
                // row index
                setAllPackedVariableRates(tableData, Math.min(startRow, toRow), false);
                // Check if a rate value changed
                if (isRateChange) {
                    // Load the array of data into the table
                    loadDataArrayIntoTable(tableData.toArray(new Object[0][0]), true);
                }
            }
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for putting data into a new row inserted below
         * the specified row in order to adjust the insertion index based on the presence of
         * array members
         *
         * @param targetRow
         *            index of the row in model coordinates below which to insert the new row
         *
         * @param data
         *            data to place in the inserted row
         *
         * @return The new row's index, in model coordinates, adjusted as needed to account for
         *         array member visibility
         ************************************************************************************
         */
        @Override
        protected int insertRowData(int targetRow, Object[] data) {
            // Check if table has rows, and has variable name and array size columns
            if (targetRow != -1 && isCanHaveArrays()) {
                // Get the array size value
                String arraySize = getExpandedValueAt(targetRow, arraySizeIndex);
                // (i.e., this is the array definition row)
                if (!arraySize.isEmpty() && !ArrayVariable.isArrayMember(getExpandedValueAt(targetRow, variableNameIndex))) {
                    // Adjust the row index past the array definition and member rows
                    targetRow += ArrayVariable.getNumMembersFromArraySize(arraySize);
                } else // Check if the array members are set to be displayed
                if (isShowArrayMembers) {
                    boolean isIndex = false;
                    // While the selection row is on an array member
                    while (targetRow < tableModel.getRowCount() && ArrayVariable.isArrayMember(getExpandedValueAt(targetRow, variableNameIndex))) {
                        // Skip the array member row
                        targetRow++;
                        isIndex = true;
                    }
                    // Check if an array member was skipped
                    if (isIndex) {
                        // Decrement the row index
                        targetRow--;
                    }
                }
            }
            // Insert the supplied data below the selected row
            return super.insertRowData(targetRow, data);
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for removing a row from the table. Array
         * member rows are ignored unless the array definition row is also deleted; for this
         * case the entire array is removed
         *
         * @param tableData
         *            list containing the table data row arrays
         *
         * @param modelRow
         *            row to remove (model coordinates)
         *
         * @return The index of the row prior to the last deleted row's index
         ************************************************************************************
         */
        @Override
        protected int removeRow(List<Object[]> tableData, int modelRow) {
            boolean isArray = false;
            // Check if the table has array size and variable name columns
            if (isCanHaveArrays()) {
                // Extract the array size cell value
                String arraySize = getExpandedValueAt(modelRow, arraySizeIndex);
                // Check if an array size is present
                if (!arraySize.isEmpty()) {
                    // Set the flag indicating that an array row is being removed
                    isArray = true;
                    // Perform while this row is an array member
                    while (ArrayVariable.isArrayMember(tableData.get(modelRow)[variableNameIndex])) {
                        // Move the row index up
                        modelRow--;
                    }
                    // Get the row index of the last array member
                    int arrayRow = modelRow + ArrayVariable.getNumMembersFromArraySize(arraySize);
                    // Step through each member of the array
                    while (arrayRow >= modelRow) {
                        // Delete the row
                        tableData.remove(modelRow);
                        // Go to the next array member row to remove
                        arrayRow--;
                    }
                }
            }
            // Check if the row does not represent an array definition or member
            if (!isArray) {
                // Delete the row
                super.removeRow(tableData, modelRow);
            }
            // Adjust the rate for any packed variables, beginning with this row
            setAllPackedVariableRates(tableData, convertRowIndexToView(modelRow), false);
            return modelRow - 1;
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for getting the special replacement character
         * when deleting the contents of a cell. Get the corresponding cell value from the
         * table's prototype
         *
         * @param row
         *            cell row index in model coordinates
         *
         * @param column
         *            cell column index in model coordinates
         *
         * @return The corresponding cell value from the tables' prototype
         ************************************************************************************
         */
        @Override
        protected String getSpecialReplacement(int row, int column) {
            return dbTable.queryTableCellValue(tableInfo.getPrototypeName(), committedInfo.getData()[row][primaryKeyIndex], typeDefn.getColumnNamesDatabase()[column], editorDialog);
        }

        /**
         ************************************************************************************
         * Override the CcddJTableHandler method for deleting a cell. Set the special character
         * flag to false if the table is a prototype - prototypes can't have an entry in the
         * custom values table so no special handling is needed for this case
         *
         * @param isReplaceSpecial
         *            false to replace the cell value with a blank; true to replace the cell
         *            contents with the prototype's corresponding cell value
         ************************************************************************************
         */
        @Override
        protected void deleteCell(boolean isReplaceSpecial) {
            super.deleteCell(isReplaceSpecial && !tableInfo.isPrototype());
        }

        /**
         ************************************************************************************
         * Adjust the starting row index to the next row during a paste (insert) operation. If
         * the insertion point falls within an array, skip to the row immediately following the
         * array's members
         *
         * @param startRow
         *            starting row index in view coordinates
         *
         * @return Starting row index, in model coordinates, at which to insert a new row
         ************************************************************************************
         */
        protected int adjustPasteStartRow(int startRow) {
            // Check if the starting row index references a valid row
            if (startRow >= 0 && startRow < getRowCount()) {
                // Convert the row index to model coordinates and adjust the starting row index
                // to the next row
                startRow = convertRowIndexToModel(startRow) + 1;
            } else // The starting index is not a valid row
            {
                // Set the starting row index to the end of the table
                startRow = tableModel.getRowCount();
            }
            // variable size and array name columns, and an array size is present
            if (startRow < tableModel.getRowCount() && isCanHaveArrays() && !getExpandedValueAt(startRow, arraySizeIndex).isEmpty()) {
                // been reached
                while (startRow < tableModel.getRowCount() && ArrayVariable.isArrayMember(getExpandedValueAt(startRow, variableNameIndex))) {
                    // Adjust the row index to the next row
                    startRow++;
                }
            }
            return startRow;
        }

        /**
         ************************************************************************************
         * Determine if a row insertion is required during a paste operation. Array member rows
         * are inserted automatically when an array is defined, so if an array member is being
         * inserted no row needs to be inserted by the paste operation
         *
         * @param index
         *            current index into the cell data array
         *
         * @param cellData
         *            array containing the cell data being inserted
         *
         * @param startColumn
         *            data insertion starting column index
         *
         * @param endColumn
         *            data insertion ending column index
         *
         * @return true if a row should be inserted; false otherwise
         ************************************************************************************
         */
        protected boolean isInsertRowRequired(int index, Object[] cellData, int startColumn, int endColumn) {
            boolean isNotArrayMember = true;
            // Get the variable name column index in view coordinates
            int variableNameIndexView = convertColumnIndexToView(variableNameIndex);
            // Step through the row of data being inserted
            for (int column = startColumn; column <= endColumn; column++, index++) {
                // Check if the column index matches the variable name column
                if (column == variableNameIndexView) {
                    // Check if the variable name cell has a value and is an array member
                    if (cellData[index] == null || ArrayVariable.isArrayMember(cellData[index])) {
                        // Set the flag to indicate a new row doesn't need to be inserted
                        isNotArrayMember = false;
                    }
                    // Stop searching
                    break;
                }
            }
            return isNotArrayMember;
        }

        /**
         ************************************************************************************
         * Override the paste method so that hidden rows (array members) are displayed prior to
         * pasting in new data
         ************************************************************************************
         */
        @Override
        protected boolean pasteData(Object[] cellData, int numColumns, boolean isInsert, boolean isAddIfNeeded, boolean startFirstColumn, boolean combineAsSingleEdit) {
            Boolean showMessage = true;
            // Check if the pasted data should be combined into a single edit operation
            if (combineAsSingleEdit) {
                // End any active edit sequence, then disable auto-ending so that the paste
                // operation can be handled as a single edit for undo/redo purposes
                getUndoManager().endEditSequence();
                getUndoHandler().setAutoEndEditSequence(false);
            }
            // Get the table data array
            List<Object[]> tableData = getTableDataList(false);
            // Calculate the number of rows to be pasted in
            int numRows = cellData.length / numColumns;
            // Initialize the starting row to the first row, which is the default if no row is
            // selected
            int startRow = 0;
            // Check if no row is selected
            if (getSelectedRow() == -1) {
                // Clear the column selection. The column selection can remain in effect after
                // an undo action that clears the row selection. It needs to be cleared if
                // invalid so that the starting column index is correctly calculated below
                getColumnModel().getSelectionModel().clearSelection();
            } else // A row is selected
            {
                // Determine the starting row for pasting the data based on the selected row
                startRow = convertRowIndexToModel(getSelectedRow()) + getSelectedRowCount() - 1;
            }
            // Determine the starting column and ending column for pasting the data. If no
            // column is selected then default to the first column. Data pasted outside of the
            // column range is ignored
            int startColumn = startFirstColumn ? 0 : Math.max(Math.max(getSelectedColumn(), 0), getSelectedColumn() + getSelectedColumnCount() - 1);
            int endColumn = startColumn + numColumns - 1;
            int endColumnSelect = Math.min(endColumn, getColumnCount() - 1);
            // members are hidden
            if (isCanHaveArrays() && !isShowArrayMembers) {
                // Show the array members. All rows must be visible in order for the pasted
                // data to be inserted correctly. The model and view row coordinates are the
                // same after expanding the array members. Note that this clears the row and
                // column selection
                showHideArrayMembers();
            }
            // Check if the data is to be inserted versus overwriting existing cells
            if (isInsert) {
                // Adjust the starting row index to the one after the selected row, and account
                // for hidden rows, if applicable
                startRow = adjustPasteStartRow(startRow);
            } else // contains no rows
            if (startRow == -1) {
                // Set the start row to the first row
                startRow = 0;
            }
            // Determine the ending row for pasting the data
            int endRow = startRow + numRows;
            // Clear the cell selection
            clearSelection();
            // Counters for the number of array member rows added (due to pasting in an array
            // definition) and the number of rows ignored (due to the first pasted row(s) being
            // an array member)
            int arrayRowsAdded = 0;
            int totalAddedRows = 0;
            int skippedRows = 0;
            boolean isIgnoreRow = false;
            // Step through each new row
            for (int index = 0, row = startRow; row < endRow && showMessage != null; row++) {
                boolean skipRow = false;
                // Calculate the row in the table data where the values are to be pasted. This
                // must be adjusted to account for pasting in arrays
                int adjustedRow = row + totalAddedRows - skippedRows;
                // member
                for (int column = startColumn; column <= endColumn && column < getColumnCount() && showMessage != null; column++) {
                    // Get the index into the cell data for this column
                    int tempIndex = index + column - startColumn;
                    // Check if rows were removed due to an array size reduction or removal
                    if (arrayRowsAdded < 0) {
                        // Set the flag indicating that this row of data is to be skipped and
                        // increment the skipped row counter
                        skipRow = true;
                        skippedRows++;
                        // Adjust the row counters so that all array member rows are skipped
                        arrayRowsAdded++;
                        totalAddedRows++;
                    } else // and that the value is an array member
                    if (variableNameIndex == convertColumnIndexToModel(column) && tempIndex < cellData.length && cellData[tempIndex] != null && ArrayVariable.isArrayMember(cellData[tempIndex])) {
                        // the array members
                        if (arrayRowsAdded > 0) {
                            // Move the row index back so that the array member data is pasted
                            // in the proper row
                            adjustedRow -= arrayRowsAdded;
                            arrayRowsAdded--;
                            totalAddedRows--;
                        } else // No rows were added for this array member
                        {
                            // member has no definition
                            if (row == startRow) {
                                // Set the flag indicating that array member rows are ignored
                                isIgnoreRow = true;
                            }
                            // Set the flag indicating that this row of data is to be skipped
                            // and increment the skipped row counter
                            skipRow = true;
                            skippedRows++;
                            // Update the cell data index so that this row is skipped
                            index += numColumns;
                        }
                        break;
                    }
                }
                // Check that this row is not to be ignored
                if (!skipRow) {
                    // Check if inserting is in effect and the cell value is null
                    if (isInsert && index < cellData.length && cellData[index] == null) {
                        // Replace the null with a blank
                        cellData[index] = "";
                    }
                    // Check if a row needs to be inserted to contain the cell data
                    if ((isInsert || (isAddIfNeeded && adjustedRow == tableData.size())) && isInsertRowRequired(index, cellData, startColumn, endColumn)) {
                        // Insert a row at the selection point
                        tableData.add(adjustedRow, getEmptyRow());
                    }
                    // Store the index into the array of data to be pasted
                    int indexSave = index;
                    // are pasted, then the cells that are not empty are pasted
                    for (int pass = 1; pass <= 2; pass++) {
                        // Check if this is the second pass through the row's columns
                        if (pass == 2) {
                            // Reset the index into the array of data to be pasted so that the
                            // non-blank cells can be processed
                            index = indexSave;
                        }
                        // Step through the columns, beginning at the one with the focus
                        for (int column = startColumn; column <= endColumn && showMessage != null; column++) {
                            // outside the bounds or protected then discard the value
                            if (column < getColumnCount()) {
                                // Convert the column coordinate from view to model
                                int columnModel = convertColumnIndexToModel(column);
                                // Get the value to be pasted into the cell, cleaning up the
                                // value if needed. If the number of cells to be filled exceeds
                                // the stored values then insert a blank. A null paste value
                                // indicates that the current cell's value won't be overwritten
                                Object newValue = index < cellData.length ? (cellData[index] != null ? cleanUpCellValue(cellData[index], adjustedRow, columnModel) : (isInsert ? "" : null)) : "";
                                // alterable
                                if (newValue != null && ((pass == 1 && newValue.toString().isEmpty()) || (pass == 2 && !newValue.toString().isEmpty())) && isDataAlterable(tableData.get(adjustedRow), adjustedRow, columnModel)) {
                                    // Get the original cell value
                                    Object oldValue = tableData.get(adjustedRow)[columnModel];
                                    // being inserted, that the value isn't blank
                                    if (!oldValue.equals(newValue) && !(isInsert && newValue.toString().isEmpty())) {
                                        // Insert the value into the cell
                                        tableData.get(adjustedRow)[columnModel] = newValue;
                                        // Get the number of rows in the table prior to
                                        // inserting the new value
                                        int previousRows = tableData.size();
                                        // Validate the new cell contents
                                        showMessage = validateCellContent(tableData, adjustedRow, columnModel, oldValue, newValue, showMessage, cellData.length > 1);
                                        // following an invalid input
                                        if (showMessage == null) {
                                            // Stop pasting data
                                            continue;
                                        }
                                        // Get the number of rows added due to pasting in the
                                        // new value. This is non-zero if an array definition
                                        // is pasted in or if an existing array's size is
                                        // altered
                                        int deltaRows = tableData.size() - previousRows;
                                        // Check if the row count changed
                                        if (deltaRows > 0) {
                                            // Store the number of added/deleted rows and
                                            // update the total number of added/deleted rows
                                            arrayRowsAdded = deltaRows;
                                            totalAddedRows += arrayRowsAdded;
                                        }
                                    }
                                }
                            }
                            // Increment the index to the next value to paste
                            index++;
                        }
                    }
                }
            }
            // Check if the user hasn't selected the Cancel button following an invalid input
            if (showMessage != null) {
                // Load the array of data into the table
                loadDataArrayIntoTable(tableData.toArray(new Object[0][0]), true);
                // Check if automatic edit sequence ending is in effect
                if (getUndoHandler().isAutoEndEditSequence()) {
                    // Flag the end of the editing sequence for undo/redo purposes
                    getUndoManager().endEditSequence();
                }
                // Check if there are rows left to be selected
                if (endRow - 1 - skippedRows > 0) {
                    // Select all of the rows into which the data was pasted
                    setRowSelectionInterval(startRow, endRow - 1 - skippedRows);
                }
                // Select all of the columns into which the data was pasted
                setColumnSelectionInterval(startColumn, endColumnSelect);
                // Select the pasted cells and force the table to be redrawn so that the
                // changes are displayed
                setSelectedCells(startRow, endRow - 1, startColumn, endColumnSelect);
                repaint();
                // Check if any rows were ignored
                if (isIgnoreRow) {
                    // Inform the user how many rows were skipped
                    new CcddDialogHandler().showMessageDialog(editorDialog, "<html><b>" + skippedRows + " array member row(s) ignored due " + "to missing array definition(s)", "Rows Ignored", JOptionPane.WARNING_MESSAGE, DialogOption.OK_OPTION);
                }
            }
            // Set the flag that indicates the last edited cell's content is valid (if an
            // invalid input set the flag to false then it can prevent closing the editor)
            setLastCellValid(true);
            // Check if the pasted data should be combined into a single edit operation
            if (combineAsSingleEdit) {
                // Re-enable auto-ending of the edit sequence and end the sequence. The pasted
                // data can be removed with a single undo if desired
                getUndoHandler().setAutoEndEditSequence(true);
                getUndoManager().endEditSequence();
            }
            return showMessage == null;
        }

        /**
         ************************************************************************************
         * Override the method for cleaning-up of the cell value. The default is to remove any
         * leading and trailing white space characters. This method skips removal of white
         * space characters for cells having input types that allow it
         *
         * @param value
         *            new cell value
         *
         * @param row
         *            table row, model coordinates
         *
         * @param column
         *            table column, model coordinates
         *
         * @return Cell value following clean-up
         ************************************************************************************
         */
        @Override
        protected Object cleanUpCellValue(Object value, int row, int column) {
            // string (i.e., it isn't boolean, etc.)
            if (!table.isEditing() && value instanceof String) {
                // Get the input type for this column
                InputDataType inputType = typeDefn.getInputTypes()[column];
                // space characters
                if (inputType != InputDataType.TEXT_WHT_SPC && inputType != InputDataType.TEXT_MULTI_WHT_SPC) {
                    // Perform the default clean-up (remove leading and trailing white space
                    // characters)
                    value = super.cleanUpCellValue(value, row, column);
                }
            }
            return value;
        }

        /**
         ************************************************************************************
         * Handle a change to the table's content
         ************************************************************************************
         */
        @Override
        protected void processTableContentChange() {
            // and/or value change)
            if (editorDialog != null) {
                // Update the change indicator for the table
                editorDialog.updateChangeIndicator(CcddTableEditorHandler.this);
            }
        }
    };
    // Place the table into a scroll pane
    JScrollPane scrollPane = new JScrollPane(table);
    // Disable storage of edit operations during table creation
    table.getUndoHandler().setAllowUndo(false);
    // Set common table parameters and characteristics
    table.setFixedCharacteristics(scrollPane, tableInfo.isPrototype(), ListSelectionModel.MULTIPLE_INTERVAL_SELECTION, TableSelectionMode.SELECT_BY_CELL, true, ModifiableColorInfo.TABLE_BACK.getColor(), true, true, ModifiableFontInfo.DATA_TABLE_CELL.getFont(), true);
    // Get a reference to the table model to shorten later calls
    tableModel = (UndoableTableModel) table.getModel();
    // Re-enable storage of edit operations
    table.getUndoHandler().setAllowUndo(true);
    // Set the reference to the editor's data field handler in the undo handler so that data
    // field value changes can be undone/redone correctly
    table.getUndoHandler().setFieldHandler(tableInfo.getFieldHandler());
    // Set the undo/redo manager and handler for the description and data field values
    setEditPanelUndo(table.getUndoManager(), table.getUndoHandler());
    // Set the mouse listener to expand and collapse arrays
    setArrayExpansionListener();
    // Get the variable path separators and create the variable path column content, if present
    updateVariablePaths();
    // change)
    if (editorDialog != null) {
        // Create the input field panel to contain the table editor
        createDescAndDataFieldPanel(editorDialog, scrollPane, tableInfo.getProtoVariableName(), tableInfo.getDescription(), tableInfo.getFieldHandler());
        // Set the dialog name so that this dialog can be recognized as being open by the table
        // selection dialog, and the JTable name so that table change events can be identified
        // with this table
        setTableName();
        // Store the current data field information in the event an undo/redo operation occurs
        storeCurrentFieldInformation();
    }
}
Also used : CCDDException(CCDD.CcddClassesDataTable.CCDDException) Matcher(java.util.regex.Matcher) DefaultHighlighter(javax.swing.text.DefaultHighlighter) JTextComponent(javax.swing.text.JTextComponent) InputTypeFormat(CCDD.CcddConstants.InputTypeFormat) Comparator(java.util.Comparator) List(java.util.List) ArrayList(java.util.ArrayList) TableCellEditor(javax.swing.table.TableCellEditor) Component(java.awt.Component) JComponent(javax.swing.JComponent) JTextComponent(javax.swing.text.JTextComponent) DefaultHighlightPainter(javax.swing.text.DefaultHighlighter.DefaultHighlightPainter) TableRowSorter(javax.swing.table.TableRowSorter) InputDataType(CCDD.CcddConstants.InputDataType) JScrollPane(javax.swing.JScrollPane) Pattern(java.util.regex.Pattern) TableCellRenderer(javax.swing.table.TableCellRenderer) MouseEvent(java.awt.event.MouseEvent) JComponent(javax.swing.JComponent) Point(java.awt.Point) Dimension(java.awt.Dimension) Point(java.awt.Point) DefaultHighlightPainter(javax.swing.text.DefaultHighlighter.DefaultHighlightPainter) AssociatedColumns(CCDD.CcddClassesDataTable.AssociatedColumns) UndoableTableModel(CCDD.CcddUndoHandler.UndoableTableModel) MinMaxPair(CCDD.CcddClassesDataTable.MinMaxPair) BadLocationException(javax.swing.text.BadLocationException)

Example 60 with JTextComponent

use of javax.swing.text.JTextComponent in project freeplane by freeplane.

the class EditNodeWYSIWYG method show.

public void show(final RootPaneContainer frame) {
    try {
        HTMLDialog htmlEditorWindow = createHtmlEditor(frame);
        htmlEditorWindow.setBase(this);
        final String titleText;
        titleText = TextUtils.getText(title);
        htmlEditorWindow.getDialog().setTitle(titleText);
        htmlEditorWindow.setSplitEnabled(getEditControl().canSplit());
        final SHTMLPanel htmlEditorPanel = (htmlEditorWindow).getHtmlEditorPanel();
        final StringBuilder ruleBuilder = new StringBuilder(100);
        ruleBuilder.append("body {");
        ruleBuilder.append(new CssRuleBuilder().withCSSFont(font, UITools.FONT_SCALE_FACTOR).withColor(textColor).withBackground(getBackground()).withAlignment(horizontalAlignment));
        ruleBuilder.append("}\n");
        ruleBuilder.append("p {margin-top:0;}\n");
        final HTMLDocument document = htmlEditorPanel.getDocument();
        final JEditorPane editorPane = htmlEditorPanel.getEditorPane();
        if (textColor != null) {
            editorPane.setForeground(textColor);
            editorPane.setCaretColor(textColor);
        }
        final StyleSheet styleSheet = document.getStyleSheet();
        styleSheet.removeStyle("p");
        styleSheet.removeStyle("body");
        styleSheet.addRule(ruleBuilder.toString());
        final URL url = node.getMap().getURL();
        if (url != null) {
            document.setBase(url);
        } else {
            document.setBase(new URL("file: "));
        }
        htmlEditorPanel.setContentPanePreferredSize(preferredSize);
        htmlEditorWindow.getDialog().pack();
        if (ResourceController.getResourceController().getBooleanProperty("el__position_window_below_node")) {
            UITools.setDialogLocationUnder(htmlEditorWindow.getDialog(), node);
        } else {
            UITools.setDialogLocationRelativeTo(htmlEditorWindow.getDialog(), node);
        }
        String content = text;
        if (!HtmlUtils.isHtmlNode(content)) {
            content = HtmlUtils.plainToHTML(content);
        }
        htmlEditorPanel.setCurrentDocumentContent(content);
        final KeyEvent firstKeyEvent = MTextController.getController().getEventQueue().getFirstEvent();
        final JTextComponent currentPane = htmlEditorPanel.getEditorPane();
        if (currentPane == htmlEditorPanel.getMostRecentFocusOwner()) {
            redispatchKeyEvents(currentPane, firstKeyEvent);
            if (firstKeyEvent == null) {
                editorPane.setCaretPosition(htmlEditorPanel.getDocument().getLength());
            }
        } else {
            final EventBuffer keyEventDispatcher = MTextController.getController().getEventQueue();
            keyEventDispatcher.deactivate();
        }
        htmlEditorPanel.getMostRecentFocusOwner().requestFocus();
        htmlEditorWindow.show();
    } catch (final Exception ex) {
        LogUtils.severe("Loading of WYSIWYG HTML editor failed. Use the other editors instead.", ex);
    }
}
Also used : CssRuleBuilder(org.freeplane.core.ui.components.html.CssRuleBuilder) HTMLDocument(javax.swing.text.html.HTMLDocument) JTextComponent(javax.swing.text.JTextComponent) URL(java.net.URL) SHTMLPanel(com.lightdev.app.shtm.SHTMLPanel) KeyEvent(java.awt.event.KeyEvent) StyleSheet(javax.swing.text.html.StyleSheet) JEditorPane(javax.swing.JEditorPane)

Aggregations

JTextComponent (javax.swing.text.JTextComponent)181 Component (java.awt.Component)28 JComponent (javax.swing.JComponent)16 BadLocationException (javax.swing.text.BadLocationException)13 NotNull (org.jetbrains.annotations.NotNull)13 DocumentEvent (javax.swing.event.DocumentEvent)11 DocumentAdapter (com.intellij.ui.DocumentAdapter)8 Caret (javax.swing.text.Caret)8 Document (javax.swing.text.Document)8 Point (java.awt.Point)7 ActionEvent (java.awt.event.ActionEvent)7 ActionListener (java.awt.event.ActionListener)7 ArrayList (java.util.ArrayList)7 ComboBoxEditor (javax.swing.ComboBoxEditor)7 FocusEvent (java.awt.event.FocusEvent)6 Color (java.awt.Color)5 KeyEvent (java.awt.event.KeyEvent)5 MouseEvent (java.awt.event.MouseEvent)5 JButton (javax.swing.JButton)5 JComboBox (javax.swing.JComboBox)5