Search in sources :

Example 11 with CCDDException

use of CCDD.CcddClassesDataTable.CCDDException in project CCDD by nasa.

the class CcddFileIOHandler method retrieveScriptFromDatabase.

/**
 ********************************************************************************************
 * Retrieve the contents of the specified script from the database and save it to a file
 *
 * @param script
 *            name of the script to retrieve
 *
 * @param file
 *            reference to the script file
 ********************************************************************************************
 */
protected void retrieveScriptFromDatabase(String script, File file) {
    PrintWriter pw = null;
    try {
        // Get the script file contents from the database
        List<String[]> lines = dbTable.retrieveInformationTable(InternalTable.SCRIPT, false, script, ccddMain.getMainFrame());
        boolean cancelRetrieve = false;
        // Check if the data file exists
        if (file.exists()) {
            // Check if the existing file should be overwritten
            if (new CcddDialogHandler().showMessageDialog(ccddMain.getMainFrame(), "<html><b>Overwrite existing script file<br>'</b>" + file.getAbsolutePath() + "<b>'?", "Overwrite File", JOptionPane.QUESTION_MESSAGE, DialogOption.OK_CANCEL_OPTION) == OK_BUTTON) {
                // Check if the existing file can't be deleted
                if (!file.delete()) {
                    throw new CCDDException("Cannot replace");
                }
            } else // File should not be overwritten
            {
                // Cancel retrieving the script
                cancelRetrieve = true;
            }
        }
        // Check that the user didn't cancel the export
        if (!cancelRetrieve) {
            // Check if the script file can't be created
            if (!file.createNewFile()) {
                throw new CCDDException("Cannot create");
            }
            // Output the table data to the selected file
            pw = new PrintWriter(file);
            // Step through each row in the table
            for (String[] line : lines) {
                // Output the line contents (ignore the line number)
                pw.println(line[1]);
            }
        }
    } catch (CCDDException ce) {
        // Inform the user that the script file cannot be created
        new CcddDialogHandler().showMessageDialog(ccddMain.getMainFrame(), "<html><b>" + ce.getMessage() + " script file<br>'</b>" + file.getAbsolutePath() + "<b>'", "File Error", ce.getMessageType(), DialogOption.OK_OPTION);
    } catch (IOException ioe) {
        // Inform the user that the script file cannot be written to
        new CcddDialogHandler().showMessageDialog(ccddMain.getMainFrame(), "<html><b>Cannot write to script file<br>'</b>" + file.getAbsolutePath() + "<b>'", "File Error", JOptionPane.ERROR_MESSAGE, DialogOption.OK_OPTION);
    } finally {
        // Check if the PrintWriter was opened
        if (pw != null) {
            // Close the script file
            pw.close();
        }
    }
}
Also used : CCDDException(CCDD.CcddClassesDataTable.CCDDException) IOException(java.io.IOException) PrintWriter(java.io.PrintWriter)

Example 12 with CCDDException

use of CCDD.CcddClassesDataTable.CCDDException in project CCDD by nasa.

the class CcddEDSHandler method createEnumerationList.

/**
 ********************************************************************************************
 * Build an enumeration list from the supplied enumeration string
 *
 * @param namespace
 *            name space
 *
 * @param enumeration
 *            enumeration in the format <enum value><enum value separator><enum label>[<enum
 *            value separator>...][<enum pair separator>...]
 *
 * @return Enumeration list for the supplied enumeration string
 ********************************************************************************************
 */
private EnumerationListType createEnumerationList(NamespaceType namespace, String enumeration) {
    EnumerationListType enumList = factory.createEnumerationListType();
    try {
        // Get the character that separates the enumeration value from the associated label
        String enumValSep = CcddUtilities.getEnumeratedValueSeparator(enumeration);
        // Check if the value separator couldn't be located
        if (enumValSep == null) {
            throw new CCDDException("separator character between enumeration value and label missing");
        }
        // Get the character that separates the enumerated pairs
        String enumPairSep = CcddUtilities.getEnumerationPairSeparator(enumeration, enumValSep);
        // Check if the enumerated pair separator couldn't be located
        if (enumPairSep == null) {
            throw new CCDDException("separator character between enumerated pairs missing");
        }
        // Divide the enumeration string into the separate enumeration definitions
        String[] enumDefn = enumeration.split(Pattern.quote(enumPairSep));
        // Step through each enumeration definition
        for (int index = 0; index < enumDefn.length; index++) {
            // Split the enumeration definition into the name and label components
            String[] enumParts = enumDefn[index].split(Pattern.quote(enumValSep), 2);
            // Create a new enumeration value type and add the enumerated name and value to the
            // enumeration list
            ValueEnumerationType valueEnum = factory.createValueEnumerationType();
            valueEnum.setLabel(enumParts[1].trim());
            valueEnum.setValue(BigInteger.valueOf(Integer.valueOf(enumParts[0].trim())));
            enumList.getEnumeration().add(valueEnum);
        }
    } catch (CCDDException ce) {
        // Inform the user that the enumeration format is invalid
        new CcddDialogHandler().showMessageDialog(parent, "<html><b>Enumeration '" + enumeration + "' format invalid in table '" + namespace.getName() + "'; " + ce.getMessage(), "Enumeration Error", JOptionPane.WARNING_MESSAGE, DialogOption.OK_OPTION);
    }
    return enumList;
}
Also used : EnumerationListType(org.ccsds.schema.sois.seds.EnumerationListType) ValueEnumerationType(org.ccsds.schema.sois.seds.ValueEnumerationType) CCDDException(CCDD.CcddClassesDataTable.CCDDException)

Example 13 with CCDDException

use of CCDD.CcddClassesDataTable.CCDDException in project CCDD by nasa.

the class CcddCSVHandler method importFromFile.

/**
 ********************************************************************************************
 * Build the information from the table definition(s) in the current file
 *
 * @param importFile
 *            import file reference
 *
 * @param importAll
 *            ImportType.IMPORT_ALL to import the table type, data type, and macro definitions,
 *            and the data from all the table definitions; ImportType.FIRST_DATA_ONLY to load
 *            only the data for the first table defined
 *
 * @throws CCDDException
 *             If a data is missing, extraneous, or in error in the import file
 *
 * @throws IOException
 *             If an import file I/O error occurs
 *
 * @throws Exception
 *             For any unanticipated errors
 ********************************************************************************************
 */
@Override
public void importFromFile(FileEnvVar importFile, ImportType importType) throws CCDDException, IOException, Exception {
    BufferedReader br = null;
    try {
        List<TableTypeDefinition> tableTypeDefns = new ArrayList<TableTypeDefinition>();
        List<String[]> dataTypeDefns = new ArrayList<String[]>();
        List<String[]> macroDefns = new ArrayList<String[]>();
        List<String[]> reservedMsgIDDefns = new ArrayList<String[]>();
        tableDefinitions = new ArrayList<TableDefinition>();
        // macros, then a second pass to read the table data and fields
        for (int loop = 1; loop <= 2; loop++) {
            int columnNumber = 0;
            // Create a buffered reader to read the file
            br = new BufferedReader(new FileReader(importFile));
            // Flags indicating if importing should continue after an input error is detected
            boolean continueOnTableTypeError = false;
            boolean continueOnDataTypeError = false;
            boolean continueOnMacroError = false;
            boolean continueOnColumnError = false;
            boolean continueOnDataFieldError = false;
            boolean continueOnReservedMsgIDError = false;
            boolean continueOnTableTypeFieldError = false;
            // Initialize the input tag
            CSVTags importTag = null;
            // Read first line in file
            String line = br.readLine();
            // outer while loop accounts for multiple table definitions within a single file
            while (line != null) {
                TableTypeDefinition tableTypeDefn = null;
                // Initialize the table information
                int numColumns = 0;
                String tablePath = "";
                // Create empty table information and table type definition references
                TypeDefinition typeDefn = null;
                // Storage for column indices
                int[] columnIndex = null;
                // Initialize the number of matching columns and the cell data storage
                String[] columnValues = null;
                // Create a table definition to contain the table's information
                TableDefinition tableDefn = new TableDefinition();
                // Flag that indicates if a table type row is the type name and description or
                // a column definition
                boolean isTypeName = false;
                // inner while loop reads the information for a single table in the file
                while (line != null) {
                    // Remove any trailing commas, empty quotes, and leading/trailing white
                    // space characters from the row. If the CSV file is generated from a
                    // spreadsheet application then extra commas are appended to a row if
                    // needed for the number of columns to be equal with the other rows. These
                    // empty trailing columns are ignored
                    line = line.replaceAll("(?:[,\\s*]|\\\"\\s*\\\")*$", "");
                    // character)
                    if (!line.isEmpty() && !line.startsWith("#")) {
                        // Parse the import data. The values are comma- separated; however,
                        // commas within quotes are ignored - this allows commas to be included
                        // in the data values
                        columnValues = CcddUtilities.splitAndRemoveQuotes(line);
                        // Remove any leading/trailing white space characters from the first
                        // column value
                        String firstColumn = columnValues[0].trim();
                        // Check if this is the table name and table type tag
                        if (firstColumn.equalsIgnoreCase(CSVTags.NAME_TYPE.getTag())) {
                            // Set the input type to look for the table name and table type
                            importTag = CSVTags.NAME_TYPE;
                            // information
                            if (loop == 2 && !tablePath.isEmpty()) {
                                // to beginning another one
                                break;
                            }
                        } else // type are defined
                        if (firstColumn.equalsIgnoreCase(CSVTags.COLUMN_NAMES.getTag()) && !tablePath.isEmpty()) {
                            // Set the input type to look for the table column names
                            importTag = CSVTags.COLUMN_NAMES;
                        } else // type are defined
                        if (firstColumn.equalsIgnoreCase(CSVTags.DESCRIPTION.getTag()) && !tablePath.isEmpty()) {
                            // Set the input type to look for the table description
                            importTag = CSVTags.DESCRIPTION;
                        } else // are defined
                        if (firstColumn.equalsIgnoreCase(CSVTags.DATA_FIELD.getTag()) && !tablePath.isEmpty()) {
                            // Set the input type to look for the data field(s)
                            importTag = CSVTags.DATA_FIELD;
                        } else // Check if this is the table type tag
                        if (firstColumn.equalsIgnoreCase(CSVTags.TABLE_TYPE.getTag())) {
                            // Set the input type to look for the table type definition
                            importTag = CSVTags.TABLE_TYPE;
                            // Set the flag so that the next row is treated as the table type
                            // name and description
                            isTypeName = true;
                        } else // is defined
                        if (firstColumn.equalsIgnoreCase(CSVTags.TABLE_TYPE_DATA_FIELD.getTag()) && tableTypeDefn != null) {
                            // Set the input type to look for the table type data field(s)
                            importTag = CSVTags.TABLE_TYPE_DATA_FIELD;
                        } else // Check if this is the data type tag
                        if (firstColumn.equalsIgnoreCase(CSVTags.DATA_TYPE.getTag())) {
                            // Set the input type to look for the data type(s)
                            importTag = CSVTags.DATA_TYPE;
                        } else // Check if this is the macro tag
                        if (firstColumn.equalsIgnoreCase(CSVTags.MACRO.getTag())) {
                            // Set the input type to look for the macro(s)
                            importTag = CSVTags.MACRO;
                        } else // Check if this is the reserved message IDs tag
                        if (firstColumn.equalsIgnoreCase(CSVTags.RESERVED_MSG_IDS.getTag())) {
                            // Set the input type to look for the reserved IDs
                            importTag = CSVTags.RESERVED_MSG_IDS;
                        } else // Not a tag (or no table name and type are defined); read in the
                        // information based on the last tag read
                        {
                            // Check if this is the first pass
                            if (loop == 1) {
                                switch(importTag) {
                                    case TABLE_TYPE:
                                        // Check if this is the table type name and description
                                        if (isTypeName) {
                                            // Reset the flag so that subsequent rows are
                                            // treated as column definitions
                                            isTypeName = false;
                                            columnNumber = NUM_HIDDEN_COLUMNS;
                                            // present
                                            if (columnValues.length == 2 || columnValues.length == 1) {
                                                // Add the table type definition
                                                tableTypeDefn = new TableTypeDefinition(columnValues[0], (columnValues.length == 2 ? columnValues[1] : ""));
                                                tableTypeDefns.add(tableTypeDefn);
                                            } else // The number of inputs is incorrect
                                            {
                                                // Check if the error should be ignored or the
                                                // import canceled
                                                continueOnTableTypeError = getErrorResponse(continueOnTableTypeError, "<html><b>Missing table type name in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Table Type Error", "Ignore this table type", "Ignore this and any remaining invalid table types", "Stop importing", parent);
                                            }
                                        } else // This is a column definition
                                        {
                                            // present
                                            if (columnValues.length == TableTypeEditorColumnInfo.values().length - 1) {
                                                // Add the table type column definition,
                                                // checking for (and if possible, correcting)
                                                // errors
                                                continueOnTableTypeError = addImportedTableTypeDefinition(continueOnTableTypeError, tableTypeDefn, new String[] { String.valueOf(columnNumber), columnValues[TableTypeEditorColumnInfo.NAME.ordinal() - 1], columnValues[TableTypeEditorColumnInfo.DESCRIPTION.ordinal() - 1], columnValues[TableTypeEditorColumnInfo.INPUT_TYPE.ordinal() - 1], columnValues[TableTypeEditorColumnInfo.UNIQUE.ordinal() - 1], columnValues[TableTypeEditorColumnInfo.REQUIRED.ordinal() - 1], columnValues[TableTypeEditorColumnInfo.STRUCTURE_ALLOWED.ordinal() - 1], columnValues[TableTypeEditorColumnInfo.POINTER_ALLOWED.ordinal() - 1] }, importFile.getAbsolutePath(), parent);
                                                // Update the column index number for the next
                                                // column definition
                                                columnNumber++;
                                            } else // The number of inputs is incorrect
                                            {
                                                // Check if the error should be ignored or the
                                                // import canceled
                                                continueOnTableTypeError = getErrorResponse(continueOnTableTypeError, "<html><b>Table type '" + tableTypeDefn.getTypeName() + "' definition has missing or extra " + "input(s) in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Table Type Error", "Ignore this table type", "Ignore this and any remaining invalid table types", "Stop importing", parent);
                                            }
                                        }
                                        break;
                                    case TABLE_TYPE_DATA_FIELD:
                                        // Check if all definitions are to be loaded
                                        if (importType == ImportType.IMPORT_ALL) {
                                            // present
                                            if (columnValues.length == FieldsColumn.values().length - 1 || columnValues.length == FieldsColumn.values().length - 2) {
                                                // Append empty columns as needed to fill out
                                                // the expected number of inputs
                                                columnValues = CcddUtilities.appendArrayColumns(columnValues, FieldsColumn.values().length - 1 - columnValues.length);
                                                // Add the data field definition, checking for
                                                // (and if possible, correcting) errors
                                                continueOnTableTypeFieldError = addImportedDataFieldDefinition(continueOnTableTypeFieldError, tableTypeDefn, new String[] { CcddFieldHandler.getFieldTypeName(tableTypeDefn.getTypeName()), columnValues[FieldsColumn.FIELD_NAME.ordinal() - 1], columnValues[FieldsColumn.FIELD_DESC.ordinal() - 1], columnValues[FieldsColumn.FIELD_SIZE.ordinal() - 1], columnValues[FieldsColumn.FIELD_TYPE.ordinal() - 1], columnValues[FieldsColumn.FIELD_REQUIRED.ordinal() - 1], columnValues[FieldsColumn.FIELD_APPLICABILITY.ordinal() - 1], columnValues[FieldsColumn.FIELD_VALUE.ordinal() - 1] }, importFile.getAbsolutePath(), parent);
                                            } else // The number of inputs is incorrect
                                            {
                                                // Check if the error should be ignored or the
                                                // import canceled
                                                continueOnTableTypeFieldError = getErrorResponse(continueOnTableTypeFieldError, "<html><b>Table type '</b>" + tableTypeDefn.getTypeName() + "<b>' has missing or extra data field " + "input(s) in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Data Field Error", "Ignore this invalid data field", "Ignore this and any remaining invalid data fields", "Stop importing", parent);
                                            }
                                        }
                                        break;
                                    case DATA_TYPE:
                                        // Check if all definitions are to be loaded
                                        if (importType == ImportType.IMPORT_ALL) {
                                            // present
                                            if (columnValues.length == 4) {
                                                // Add the data type definition (add a blank to
                                                // represent the OID)
                                                dataTypeDefns.add(new String[] { columnValues[DataTypesColumn.USER_NAME.ordinal()], columnValues[DataTypesColumn.C_NAME.ordinal()], columnValues[DataTypesColumn.SIZE.ordinal()], columnValues[DataTypesColumn.BASE_TYPE.ordinal()], "" });
                                            } else // The number of inputs is incorrect
                                            {
                                                // Check if the error should be ignored or the
                                                // import canceled
                                                continueOnDataTypeError = getErrorResponse(continueOnDataTypeError, "<html><b>Missing or extra data type definition " + "input(s) in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Data Type Error", "Ignore this data type", "Ignore this and any remaining invalid data types", "Stop importing", parent);
                                            }
                                        }
                                        break;
                                    case MACRO:
                                        // Check if all definitions are to be loaded
                                        if (importType == ImportType.IMPORT_ALL) {
                                            // present
                                            if (columnValues.length == 2 || columnValues.length == 1) {
                                                // Add the macro definition (add a blank to
                                                // represent the OID)
                                                macroDefns.add(new String[] { columnValues[0], (columnValues.length == 2 ? columnValues[1] : ""), "" });
                                            } else // The number of inputs is incorrect
                                            {
                                                // Check if the error should be ignored or the
                                                // import canceled
                                                continueOnMacroError = getErrorResponse(continueOnMacroError, "<html><b>Missing or extra macro definition " + "input(s) in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Macro Error", "Ignore this macro", "Ignore this and any remaining invalid macros", "Stop importing", parent);
                                            }
                                        }
                                        break;
                                    case RESERVED_MSG_IDS:
                                        // Check if all definitions are to be loaded
                                        if (importType == ImportType.IMPORT_ALL) {
                                            // present
                                            if (columnValues.length == 2 || columnValues.length == 1) {
                                                // Append empty columns as needed to fill out
                                                // the expected number of inputs
                                                columnValues = CcddUtilities.appendArrayColumns(columnValues, 2 - columnValues.length);
                                                // Add the reserved message ID definition (add
                                                // a blank to represent the OID)
                                                reservedMsgIDDefns.add(new String[] { columnValues[ReservedMsgIDsColumn.MSG_ID.ordinal()], columnValues[ReservedMsgIDsColumn.DESCRIPTION.ordinal()], "" });
                                            } else // The number of inputs is incorrect
                                            {
                                                // Check if the error should be ignored or the
                                                // import canceled
                                                continueOnReservedMsgIDError = getErrorResponse(continueOnReservedMsgIDError, "<html><b>Missing or extra reserved message ID " + "definition input(s) in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Reserved Message ID Error", "Ignore this data type", "Ignore this and any remaining invalid reserved message IDs", "Stop importing", parent);
                                            }
                                        }
                                        break;
                                    case CELL_DATA:
                                    case COLUMN_NAMES:
                                    case DATA_FIELD:
                                    case DESCRIPTION:
                                    case NAME_TYPE:
                                        break;
                                    default:
                                        // before other data
                                        throw new CCDDException("Import file '</b>" + importFile.getAbsolutePath() + "<b>' information missing");
                                }
                            } else // This is the second pass
                            {
                                switch(importTag) {
                                    case NAME_TYPE:
                                        // not used)
                                        if (columnValues.length == 2 || columnValues.length == 3) {
                                            // Use the table name (with path, if applicable)
                                            // and type to build the parent, path, and type for
                                            // the table information class
                                            tablePath = columnValues[0];
                                            tableDefn.setName(tablePath);
                                            tableDefn.setTypeName(columnValues[1]);
                                            // Get the table's type definition
                                            typeDefn = tableTypeHandler.getTypeDefinition(tableDefn.getTypeName());
                                            // Check if the table type doesn't exist
                                            if (typeDefn == null) {
                                                throw new CCDDException("Unknown table type '" + tableDefn.getTypeName() + "'");
                                            }
                                            // Get the number of expected columns (the hidden
                                            // columns, primary key and row index, should not
                                            // be included in the CSV file)
                                            numColumns = typeDefn.getColumnCountVisible();
                                        } else // Incorrect number of inputs
                                        {
                                            throw new CCDDException("Too many/few table name and type inputs");
                                        }
                                        break;
                                    case DESCRIPTION:
                                        // Store the table description
                                        tableDefn.setDescription(columnValues[0]);
                                        break;
                                    case COLUMN_NAMES:
                                        // Check if any column names exist
                                        if (columnValues.length != 0) {
                                            // Number of columns in an import file that match
                                            // the target table
                                            int numValidColumns = 0;
                                            // Create storage for the column indices
                                            columnIndex = new int[columnValues.length];
                                            // Step through each column name
                                            for (int index = 0; index < columnValues.length; index++) {
                                                // Get the index for this column name
                                                columnIndex[index] = typeDefn.getVisibleColumnIndexByUserName(columnValues[index]);
                                                // that of a column in the table
                                                if (columnIndex[index] != -1) {
                                                    // Increment the counter that tracks the
                                                    // number of matched columns
                                                    numValidColumns++;
                                                } else // The number of inputs is incorrect
                                                {
                                                    // Check if the error should be ignored or
                                                    // the import canceled
                                                    continueOnColumnError = getErrorResponse(continueOnColumnError, "<html><b>Table '</b>" + tableDefn.getName() + "<b>' column name '</b>" + columnValues[index] + "<b>' unrecognized in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Column Error", "Ignore this invalid column name", "Ignore this and any remaining invalid column names", "Stop importing", parent);
                                                }
                                            }
                                            // in the table
                                            if (numValidColumns == 0) {
                                                throw new CCDDException("No columns in import file '</b>" + importFile.getAbsolutePath() + "<b>' match those in the target table", JOptionPane.WARNING_MESSAGE);
                                            }
                                        } else // The file contains no column data
                                        {
                                            throw new CCDDException("Format invalid for import file '</b>" + importFile.getAbsolutePath() + "<b>'");
                                        }
                                        // Set the input type to look for cell data
                                        importTag = CSVTags.CELL_DATA;
                                        break;
                                    case CELL_DATA:
                                        // Create storage for the row of cell data and
                                        // initialize the values to nulls (a null indicates
                                        // that the pasted cell value won't overwrite the
                                        // current table value if overwriting; if inserting the
                                        // pasted value is changed to a space)
                                        String[] rowData = new String[numColumns];
                                        Arrays.fill(rowData, null);
                                        // Step through each column in the row
                                        for (int index = 0; index < columnValues.length; index++) {
                                            // Check if the column exists
                                            if (index < columnIndex.length && columnIndex[index] != -1) {
                                                // Store the cell data in the column matching
                                                // the one in the target table
                                                rowData[columnIndex[index]] = columnValues[index];
                                            }
                                        }
                                        // Add the row of data read in from the file to the
                                        // cell data list
                                        tableDefn.addData(rowData);
                                        break;
                                    case DATA_FIELD:
                                        // Check if the expected number of inputs is present
                                        if (columnValues.length == FieldsColumn.values().length - 1 || columnValues.length == FieldsColumn.values().length - 2) {
                                            // Append empty columns as needed to fill out the
                                            // expected number of inputs
                                            columnValues = CcddUtilities.appendArrayColumns(columnValues, FieldsColumn.values().length - 1 - columnValues.length);
                                            // Add the data field definition, checking for (and
                                            // if possible, correcting) errors
                                            continueOnDataFieldError = addImportedDataFieldDefinition(continueOnDataFieldError, tableDefn, new String[] { tableDefn.getName(), columnValues[FieldsColumn.FIELD_NAME.ordinal() - 1], columnValues[FieldsColumn.FIELD_DESC.ordinal() - 1], columnValues[FieldsColumn.FIELD_SIZE.ordinal() - 1], columnValues[FieldsColumn.FIELD_TYPE.ordinal() - 1], columnValues[FieldsColumn.FIELD_REQUIRED.ordinal() - 1], columnValues[FieldsColumn.FIELD_APPLICABILITY.ordinal() - 1], columnValues[FieldsColumn.FIELD_VALUE.ordinal() - 1] }, importFile.getAbsolutePath(), parent);
                                        } else // The number of inputs is incorrect
                                        {
                                            // Check if the error should be ignored or the
                                            // import canceled
                                            continueOnDataFieldError = getErrorResponse(continueOnDataFieldError, "<html><b>Table '</b>" + tableDefn.getName() + "<b>' has missing or extra data field " + "input(s) in import file '</b>" + importFile.getAbsolutePath() + "<b>'; continue?", "Data Field Error", "Ignore this invalid data field", "Ignore this and any remaining invalid data fields", "Stop importing", parent);
                                        }
                                        break;
                                    case DATA_TYPE:
                                    case MACRO:
                                    case TABLE_TYPE:
                                    case TABLE_TYPE_DATA_FIELD:
                                    case RESERVED_MSG_IDS:
                                        break;
                                    default:
                                        // before other data
                                        throw new CCDDException("Import file '</b>" + importFile.getAbsolutePath() + "<b>' information missing");
                                }
                            }
                        }
                    }
                    // Read next line in file
                    line = br.readLine();
                }
                // Check if this is the second pass
                if (loop == 2) {
                    // Add the table's definition to the list
                    tableDefinitions.add(tableDefn);
                    // Check if only the data from the first table is to be read
                    if (importType == ImportType.FIRST_DATA_ONLY) {
                        // Stop reading table definitions
                        break;
                    }
                }
            }
            // Check if this is the first pass
            if (loop == 1) {
                // Add the table type if it's new or match it to an existing one with the same
                // name if the type definitions are the same
                String badDefn = tableTypeHandler.updateTableTypes(tableTypeDefns, fieldHandler);
                // same name
                if (badDefn != null) {
                    throw new CCDDException("Imported table type '" + badDefn + "' doesn't match the existing definition");
                }
                // Check if all definitions are to be loaded
                if (importType == ImportType.IMPORT_ALL) {
                    // Add the data type if it's new or match it to an existing one with the
                    // same name if the type definitions are the same
                    badDefn = dataTypeHandler.updateDataTypes(dataTypeDefns);
                    // the same name
                    if (badDefn != null) {
                        throw new CCDDException("Imported data type '" + badDefn + "' doesn't match the existing definition");
                    }
                    // Add the macro if it's new or match it to an existing one with the same
                    // name if the values are the same
                    badDefn = macroHandler.updateMacros(macroDefns);
                    // same name
                    if (badDefn != null) {
                        throw new CCDDException("Imported macro '" + badDefn + "' doesn't match the existing definition");
                    }
                    // Add the reserved message ID if it's new
                    rsvMsgIDHandler.updateReservedMsgIDs(reservedMsgIDDefns);
                }
            }
        }
    } finally {
        try {
            // Check that the buffered reader exists
            if (br != null) {
                // Close the file
                br.close();
            }
        } catch (IOException ioe) {
            // Inform the user that the file cannot be closed
            new CcddDialogHandler().showMessageDialog(parent, "<html><b>Cannot close import file '</b>" + importFile.getAbsolutePath() + "<b>'", "File Warning", JOptionPane.WARNING_MESSAGE, DialogOption.OK_OPTION);
        }
    }
}
Also used : CCDDException(CCDD.CcddClassesDataTable.CCDDException) ArrayList(java.util.ArrayList) TableTypeDefinition(CCDD.CcddClassesDataTable.TableTypeDefinition) IOException(java.io.IOException) TableTypeDefinition(CCDD.CcddClassesDataTable.TableTypeDefinition) TypeDefinition(CCDD.CcddTableTypeHandler.TypeDefinition) BufferedReader(java.io.BufferedReader) TableDefinition(CCDD.CcddClassesDataTable.TableDefinition) FileReader(java.io.FileReader)

Example 14 with CCDDException

use of CCDD.CcddClassesDataTable.CCDDException in project CCDD by nasa.

the class CcddScriptManagerDialog method addAssociation.

/**
 ********************************************************************************************
 * Add an association to the script associations list based on the script and table selections
 *
 * @param insertPoint
 *            insertion point for the added row into the associations table:
 *            TableInsertionPoint.START to insert as the first row in the table,
 *            TableInsertionPoint.SELECTION to insert below the currently selected row, or
 *            TableInsertionPoint.END to insert as the last row in the table
 *
 * @return true if the association inputs are valid and the association is successfully added
 ********************************************************************************************
 */
private boolean addAssociation(TableInsertionPoint insertPoint) {
    boolean isAdded = false;
    try {
        List<String> members = new ArrayList<>();
        // Check if the tree is filtered by group
        if (tableTree.isFilteredByGroup()) {
            // Step through each selected group
            for (String group : tableTree.getSelectedGroups()) {
                // Add the group to the list. Any table belonging to the group is deselected
                members.add(GROUP_DATA_FIELD_IDENT + group);
            }
        }
        // Remove any excess white space
        nameFld.setText(nameFld.getText().trim());
        descriptionFld.setText(descriptionFld.getText().trim());
        // Check if the name field isn't blank
        if (!nameFld.getText().isEmpty()) {
            // Check if the association name does not match the alphanumeric input type
            if (!nameFld.getText().matches(InputDataType.ALPHANUMERIC.getInputMatch())) {
                throw new CCDDException("Illegal character(s) in association name");
            }
            // creating a duplicate
            for (int row = 0; row < assnsTable.getRowCount(); row++) {
                // matches the one being added (case insensitive)
                if (nameFld.getText().equalsIgnoreCase(assnsTable.getValueAt(row, AssociationsTableColumnInfo.NAME.ordinal()).toString())) {
                    throw new CCDDException("Association name already in use");
                }
            }
        }
        // Add the selected table names, skipping child tables if an ancestor of the table is
        // selected
        members.addAll(tableTree.getSelectedTablesWithoutChildren());
        // Get a file descriptor for the script file name
        FileEnvVar scriptFile = new FileEnvVar(scriptFld.getText());
        // Check that the script association already exists in the list
        if (isAssociationExists(scriptFile.getAbsolutePathWithEnvVars(), members.toArray(new String[0]))) {
            throw new CCDDException("An association with this script and table(s) " + "already exists in the script associations table");
        }
        // Create the script association strings
        String assn = "";
        // Step through each selected table/group in the tree
        for (String member : members) {
            // Add the table/group name to the script association
            assn += member + ASSN_TABLE_SEPARATOR;
        }
        // Remove the trailing table separator
        assn = CcddUtilities.removeTrailer(assn, ASSN_TABLE_SEPARATOR);
        // Insert the new script association at the end of the associations table, then select
        // it and scroll to it
        assnsTable.insertRow(true, insertPoint, new Object[] { nameFld.getText(), descriptionFld.getText(), scriptFile.getAbsolutePathWithEnvVars(), CcddUtilities.highlightDataType(assn), (scriptFile.exists() ? AvailabilityType.AVAILABLE : AvailabilityType.SCRIPT_MISSING) });
        isAdded = true;
    } catch (CCDDException ce) {
        // Inform the user that an input value is invalid
        new CcddDialogHandler().showMessageDialog(ccddMain.getMainFrame(), "<html><b>" + ce.getMessage(), "Invalid Input", JOptionPane.WARNING_MESSAGE, DialogOption.OK_OPTION);
    }
    return isAdded;
}
Also used : CCDDException(CCDD.CcddClassesDataTable.CCDDException) ArrayList(java.util.ArrayList) FileEnvVar(CCDD.CcddClassesComponent.FileEnvVar) TableInsertionPoint(CCDD.CcddConstants.TableInsertionPoint)

Example 15 with CCDDException

use of CCDD.CcddClassesDataTable.CCDDException 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)

Aggregations

CCDDException (CCDD.CcddClassesDataTable.CCDDException)44 ArrayList (java.util.ArrayList)17 TypeDefinition (CCDD.CcddTableTypeHandler.TypeDefinition)13 JSONObject (org.json.simple.JSONObject)12 FileEnvVar (CCDD.CcddClassesComponent.FileEnvVar)11 JSONArray (org.json.simple.JSONArray)11 JScrollPane (javax.swing.JScrollPane)10 JComponent (javax.swing.JComponent)9 Component (java.awt.Component)8 ParseException (org.json.simple.parser.ParseException)8 IOException (java.io.IOException)7 TableCellRenderer (javax.swing.table.TableCellRenderer)7 JSONParser (org.json.simple.parser.JSONParser)7 GroupInformation (CCDD.CcddClassesDataTable.GroupInformation)6 GridBagConstraints (java.awt.GridBagConstraints)6 GridBagLayout (java.awt.GridBagLayout)6 Insets (java.awt.Insets)6 JPanel (javax.swing.JPanel)6 TableDefinition (CCDD.CcddClassesDataTable.TableDefinition)5 TableInformation (CCDD.CcddClassesDataTable.TableInformation)5