use of CCDD.CcddClassesDataTable.TableModification in project CCDD by nasa.
the class CcddTableEditorDialog method doTableModificationComplete.
/**
********************************************************************************************
* Perform the steps needed following execution of a table modification. This includes closing
* child table editors that are no longer valid and modifying child tables when a prototype
* table is changed
*
* @param main
* reference to CcddMain
*
* @param dbTblCmdHndlr
* reference to CcddDbTableCommandHandler
*
* @param tableInfo
* table information
*
* @param modifications
* list of row update information
*
* @param deletions
* list of row deletion information
*
* @param forceUpdate
* true to make the changes to other tables; false to only make changes to tables
* other than the one in which the changes originally took place
********************************************************************************************
*/
protected static void doTableModificationComplete(CcddMain main, TableInformation tableInfo, List<TableModification> modifications, List<TableModification> deletions, boolean forceUpdate) {
CcddDataTypeHandler dtHandler = main.getDataTypeHandler();
CcddDbTableCommandHandler dbTblCmdHndlr = main.getDbTableCommandHandler();
// Create a list to store the names of tables that are no longer valid
List<String[]> invalidatedEditors = new ArrayList<String[]>();
// Step through each row modification
for (TableModification mod : modifications) {
// type has been changed
if (mod.getVariableColumn() != -1 && mod.getDataTypeColumn() != -1 && !dtHandler.isPrimitive(mod.getOriginalRowData()[mod.getDataTypeColumn()].toString()) && ((mod.getArraySizeColumn() != -1 && mod.getOriginalRowData()[mod.getArraySizeColumn()].toString().isEmpty() && !mod.getRowData()[mod.getArraySizeColumn()].toString().isEmpty()) || !mod.getOriginalRowData()[mod.getDataTypeColumn()].toString().equals(mod.getRowData()[mod.getDataTypeColumn()].toString()))) {
// Add the pattern that matches the table editor tab names for the modified
// structure. The pattern is [parent structure].__,[original structure data
// type].[original structure variable name][,__]
invalidatedEditors.add(new String[] { tableInfo.getPrototypeName(), mod.getOriginalRowData()[mod.getDataTypeColumn()].toString() + "." + mod.getOriginalRowData()[mod.getVariableColumn()].toString() });
}
}
// Step through each row deletion
for (TableModification del : deletions) {
// Check if the original data type was for a structure
if (del.getVariableColumn() != -1 && del.getDataTypeColumn() != -1 && !dtHandler.isPrimitive(del.getRowData()[del.getDataTypeColumn()].toString())) {
// Add the pattern that matches the table editor tab names for the deleted
// structure. The pattern is [parent structure].__,[structure data type].[structure
// variable name][,__]
invalidatedEditors.add(new String[] { tableInfo.getPrototypeName(), del.getRowData()[del.getDataTypeColumn()].toString() + "." + del.getRowData()[del.getVariableColumn()].toString() });
}
}
// Close the invalid table editors
dbTblCmdHndlr.closeDeletedTableEditors(invalidatedEditors, main.getMainFrame());
// Update the tables with message names & IDs columns
dbTblCmdHndlr.updateMessageIDNamesColumns(main.getMainFrame());
// Step through the open editor dialogs
for (CcddTableEditorDialog editorDialog : main.getTableEditorDialogs()) {
// Step through each individual editor
for (CcddTableEditorHandler editor : editorDialog.getTableEditors()) {
// updated
if (editor.getTableInformation().getPrototypeName().equals(tableInfo.getPrototypeName())) {
// Flag that indicates true if a forced update is set (such as when a macro
// name or value is changed), or if the updated table is a prototype and the
// editor is for an instance table of the updated table
boolean applyToChild = forceUpdate || (tableInfo.isPrototype() && !tableInfo.getTablePath().equals(editor.getTableInformation().getTablePath()));
// Load the table from the database
TableInformation updateInfo = main.getDbTableCommandHandler().loadTableData(editor.getTableInformation().getTablePath(), true, true, true, editorDialog);
// Store the updates as the committed changes in the table (so that other
// changes are recognized)
editor.doTableUpdatesComplete(updateInfo, applyToChild);
}
// Check if the table's root structure status changed
if (editor.getTableInformation().isRootStructure() != dbTblCmdHndlr.getRootStructures().contains(editor.getTableInformation().getTablePath())) {
// Update the table's root structure status
editor.getTableInformation().setRootStructure(!editor.getTableInformation().isRootStructure());
// Rebuild the table's data fields based on the updated field information
editor.createDataFieldPanel(false);
}
// Step through each row modification
for (TableModification mod : modifications) {
// this implies it could be a structure table reference
if (mod.getVariableColumn() != -1 && mod.getDataTypeColumn() != -1) {
// Update the table names in the open editors
updateTableNames(main, mod.getOriginalRowData()[mod.getDataTypeColumn()].toString(), mod.getRowData()[mod.getDataTypeColumn()].toString(), mod.getOriginalRowData()[mod.getVariableColumn()].toString(), mod.getRowData()[mod.getVariableColumn()].toString(), editorDialog, editor);
}
}
}
}
// Check if the data field editor table dialog is open
if (main.getFieldTableEditor() != null && main.getFieldTableEditor().isShowing()) {
// Update the data field editor table
main.getFieldTableEditor().reloadDataFieldTable();
}
}
use of CCDD.CcddClassesDataTable.TableModification in project CCDD by nasa.
the class CcddDbTableCommandHandler method buildDeletionCommand.
/**
********************************************************************************************
* Build the command to delete a table row. Only prototype tables can have a row deleted
*
* @param tableInfo
* table information
*
* @param deletions
* list of row deletion information
*
* @param dbTableName
* name of the table to which to delete rows
*
* @param typeDefn
* table type definition
*
* @param skipInternalTables
* true to not build and execute the commands to update the internal tables. This is
* used during a data type update where only the data type name has changed in order
* to speed up the operation
*
* @return Table row deletion command
********************************************************************************************
*/
private String buildDeletionCommand(TableInformation tableInfo, List<TableModification> deletions, String dbTableName, TypeDefinition typeDefn, boolean skipInternalTables) {
StringBuilder delCmd = new StringBuilder("");
// Check if there are any table deletions
if (!deletions.isEmpty()) {
StringBuilder valuesDelCmd = new StringBuilder("");
StringBuilder groupsDelCmd = new StringBuilder("");
StringBuilder fieldsDelCmd = new StringBuilder("");
StringBuilder ordersDelCmd = new StringBuilder("");
StringBuilder assnsDelCmd = new StringBuilder("");
StringBuilder linksDelCmd = new StringBuilder("");
StringBuilder tlmDelCmd = new StringBuilder("");
// Step through each deletion
for (TableModification del : deletions) {
// Add the table row deletion command
delCmd.append("DELETE FROM " + dbTableName + " WHERE " + typeDefn.getColumnNamesDatabase()[DefaultColumn.PRIMARY_KEY.ordinal()] + " = " + del.getRowData()[DefaultColumn.PRIMARY_KEY.ordinal()] + "; ");
// structure
if (!skipInternalTables && typeDefn.isStructure()) {
// Since a variable has been deleted set the flag to force the variable paths
// and offsets lists to be rebuilt
isPathUpdate = true;
// Get the variable name, data type, and bit length
String variableName = del.getRowData()[del.getVariableColumn()].toString();
String dataType = del.getRowData()[del.getDataTypeColumn()].toString();
// Build the variable path
String variablePath = tableInfo.getPrototypeName() + "," + dataType + "." + variableName;
// Build the regular expression that matches the variable path in the table's
// prototype
String protoVarPathEsc = CcddUtilities.escapePostgreSQLReservedChars(variablePath);
// Build the regular expression that matches the variable path in any instance
// of the table's prototype
String instanceVarPathEsc = ".+," + tableInfo.getPrototypeName() + "\\\\.[^,]*," + dataType + "\\\\." + CcddUtilities.escapePostgreSQLReservedChars(variableName);
// Append the command to delete any instance of the variable from the custom
// values table
valuesDelCmd.append("DELETE FROM " + InternalTable.VALUES.getTableName() + " WHERE " + ValuesColumn.TABLE_PATH.getColumnName() + " ~ E'^" + protoVarPathEsc + "(?:,|:|$)' OR " + ValuesColumn.TABLE_PATH.getColumnName() + " ~ E'^" + instanceVarPathEsc + "(?:,|:|$)'; ");
// Append the command to delete the variable from the link and telemetry
// scheduler tables for references to the variable in the prototype table
deleteLinkAndTlmPathRef(del.getRowData()[del.getArraySizeColumn()].toString(), variableName, variablePath, protoVarPathEsc, linksDelCmd, tlmDelCmd);
// Append the command to delete the variable from the link and telemetry
// scheduler tables for all references to the variable in instances of the
// prototype table
deleteLinkAndTlmPathRef(del.getRowData()[del.getArraySizeColumn()].toString(), variableName, variablePath, instanceVarPathEsc, linksDelCmd, tlmDelCmd);
// Check if the data type represents a structure
if (!dataTypeHandler.isPrimitive(dataType)) {
// Append the commands to update the internal tables for references to the
// variable in the prototype table and all references to the variable in
// instances of the prototype table
groupsDelCmd.append("DELETE FROM " + InternalTable.GROUPS.getTableName() + " WHERE " + GroupsColumn.MEMBERS.getColumnName() + " ~ E'^" + protoVarPathEsc + "(?:,|$)' OR " + GroupsColumn.MEMBERS.getColumnName() + " ~ E'^" + instanceVarPathEsc + "(?:,|$)'; ");
fieldsDelCmd.append("DELETE FROM " + InternalTable.FIELDS.getTableName() + " WHERE " + FieldsColumn.OWNER_NAME.getColumnName() + " ~ E'^" + protoVarPathEsc + "(?:,|$)' OR " + FieldsColumn.OWNER_NAME.getColumnName() + " ~ E'^" + instanceVarPathEsc + "(?:,|$)'; ");
ordersDelCmd.append("DELETE FROM " + InternalTable.ORDERS.getTableName() + " WHERE " + OrdersColumn.TABLE_PATH.getColumnName() + " ~ E'^" + protoVarPathEsc + "(?:,|$)' OR " + OrdersColumn.TABLE_PATH.getColumnName() + " ~ E'^" + instanceVarPathEsc + "(?:,|$)'; ");
String protoPathWithChildren = protoVarPathEsc + "(?:," + PATH_IDENT + ")?";
String instancePathWithChildren = instanceVarPathEsc + "(?:," + PATH_IDENT + ")?";
assnsDelCmd.append("UPDATE " + InternalTable.ASSOCIATIONS.getTableName() + " SET " + AssociationsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + AssociationsColumn.MEMBERS.getColumnName() + ", E'^" + protoPathWithChildren + "', E'', 'ng'); UPDATE " + InternalTable.ASSOCIATIONS.getTableName() + " SET " + AssociationsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + AssociationsColumn.MEMBERS.getColumnName() + ", E'^" + instancePathWithChildren + "', E'', 'ng'); ");
}
}
}
// Check is a command was created to change the associations table
if (assnsDelCmd.length() != 0) {
// Clean up any associations that no longer have a table referenced
assnsDelCmd.append("UPDATE " + InternalTable.ASSOCIATIONS.getTableName() + " SET " + AssociationsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + AssociationsColumn.MEMBERS.getColumnName() + ", E'^" + assnsSeparator + "', E'', 'ng'); UPDATE " + InternalTable.ASSOCIATIONS.getTableName() + " SET " + AssociationsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + AssociationsColumn.MEMBERS.getColumnName() + ", E'" + assnsSeparator + "$', E'', 'ng'); ");
}
// Append the command's closing semi-colon and add the commands to update the internal
// tables to the delete command
delCmd.append(valuesDelCmd.toString() + groupsDelCmd.toString() + fieldsDelCmd.toString() + ordersDelCmd.toString() + assnsDelCmd.toString() + linksDelCmd.toString() + tlmDelCmd.toString());
}
return delCmd.toString();
}
use of CCDD.CcddClassesDataTable.TableModification in project CCDD by nasa.
the class CcddDbTableCommandHandler method buildAdditionCommand.
/**
********************************************************************************************
* Build the command to add table rows. Only prototype tables can have a row added
*
* @param tableInfo
* table information
*
* @param additions
* list of row addition information
*
* @param dbTableName
* name of the table to which to add rows
*
* @param typeDefn
* table type definition
*
* @param skipInternalTables
* true to not build and execute the commands to update the internal tables. This is
* used during a data type update where only the data type name has changed in order
* to speed up the operation
*
* @return Table row addition command
********************************************************************************************
*/
private String buildAdditionCommand(TableInformation tableInfo, List<TableModification> additions, String dbTableName, TypeDefinition typeDefn, boolean skipInternalTables) {
StringBuilder addCmd = new StringBuilder("");
// Check if there are any table additions
if (!additions.isEmpty()) {
List<String> stringArrays = new ArrayList<String>();
StringBuilder valuesAddCmd = new StringBuilder("");
StringBuilder groupsAddCmd = new StringBuilder("");
StringBuilder fieldsAddCmd = new StringBuilder("");
StringBuilder ordersAddCmd = new StringBuilder("");
StringBuilder assnsAddCmd = new StringBuilder("");
StringBuilder linksDelCmd = new StringBuilder("");
StringBuilder tlmDelCmd = new StringBuilder("");
// Create the insert table data command. The array of column names is converted to a
// string
addCmd.append("INSERT INTO " + dbTableName + " (" + CcddUtilities.convertArrayToString(typeDefn.getColumnNamesDatabase()) + ") VALUES ");
// Step through each addition
for (TableModification add : additions) {
addCmd.append("(DEFAULT, ");
// For each column in the matching row
for (int column = 0; column < add.getRowData().length; column++) {
// Check that this isn't the primary key column
if (column != DefaultColumn.PRIMARY_KEY.ordinal()) {
// Append the column value
addCmd.append(delimitText(add.getRowData()[column]) + ", ");
}
}
// Remove the ending comma and space, append the closing parenthesis, and add the
// command to add this row
addCmd = CcddUtilities.removeTrailer(addCmd, ", ");
addCmd.append("), ");
// Check if internal tables are to be updated and the parent table is a structure
if (!skipInternalTables && typeDefn.isStructure()) {
// Since a variable has been added set the flag to force the variable paths and
// offsets lists to be rebuilt
isPathUpdate = true;
// Get the variable name and data type for the variable in the new row
String variableName = add.getRowData()[add.getVariableColumn()].toString();
String dataType = add.getRowData()[add.getDataTypeColumn()].toString();
// Get the variable path
String newVariablePath = tableInfo.getTablePath() + "," + dataType + "." + variableName;
// table) and this structure is a root table
if (!dataTypeHandler.isPrimitive(dataType) && rootStructures.contains(dataType)) {
// If the structure chosen as the variable's data type is a root structure,
// then any custom values for this the root structure (which becomes a
// child structure) are transferred to its new parent structure. References
// in the other internal tables are also changed to the structure's new
// path as a child
valuesAddCmd.append("UPDATE " + InternalTable.VALUES.getTableName() + " SET " + ValuesColumn.TABLE_PATH.getColumnName() + " = regexp_replace(" + ValuesColumn.TABLE_PATH.getColumnName() + ", E'^" + dataType + ",', E'" + newVariablePath + ",'); ");
groupsAddCmd.append("UPDATE " + InternalTable.GROUPS.getTableName() + " SET " + GroupsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + GroupsColumn.MEMBERS.getColumnName() + ", E'^" + dataType + "(,|$)', E'" + newVariablePath + "\\\\1'); ");
fieldsAddCmd.append("UPDATE " + InternalTable.FIELDS.getTableName() + " SET " + FieldsColumn.OWNER_NAME.getColumnName() + " = regexp_replace(" + FieldsColumn.OWNER_NAME.getColumnName() + ", E'^" + dataType + ",', E'" + newVariablePath + ",'); INSERT INTO " + InternalTable.FIELDS.getTableName() + " SELECT regexp_replace(" + FieldsColumn.OWNER_NAME.getColumnName() + ", E'^" + dataType + "', E'" + newVariablePath + "'), " + FieldsColumn.FIELD_NAME.getColumnName() + ", " + FieldsColumn.FIELD_DESC.getColumnName() + ", " + FieldsColumn.FIELD_SIZE.getColumnName() + ", " + FieldsColumn.FIELD_TYPE.getColumnName() + ", " + FieldsColumn.FIELD_REQUIRED.getColumnName() + ", " + FieldsColumn.FIELD_APPLICABILITY.getColumnName() + ", " + FieldsColumn.FIELD_VALUE.getColumnName() + " FROM " + InternalTable.FIELDS.getTableName() + " WHERE " + FieldsColumn.OWNER_NAME.getColumnName() + " = '" + dataType + "' AND " + FieldsColumn.FIELD_APPLICABILITY.getColumnName() + " != '" + ApplicabilityType.ROOT_ONLY.getApplicabilityName() + "'; ");
ordersAddCmd.append("UPDATE " + InternalTable.ORDERS.getTableName() + " SET " + OrdersColumn.TABLE_PATH.getColumnName() + " = regexp_replace(" + OrdersColumn.TABLE_PATH.getColumnName() + ", E'^" + dataType + ",', E'" + newVariablePath + ",'); INSERT INTO " + InternalTable.ORDERS.getTableName() + " SELECT " + OrdersColumn.USER_NAME.getColumnName() + ", regexp_replace(" + OrdersColumn.TABLE_PATH.getColumnName() + ", E'^" + dataType + "', E'" + newVariablePath + "'), " + OrdersColumn.COLUMN_ORDER.getColumnName() + " FROM " + InternalTable.ORDERS.getTableName() + " WHERE " + OrdersColumn.TABLE_PATH.getColumnName() + " = '" + dataType + "'; ");
String orgPathWithChildren = dataType + "(," + PATH_IDENT + ")?";
assnsAddCmd.append("UPDATE " + InternalTable.ASSOCIATIONS.getTableName() + " SET " + AssociationsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + AssociationsColumn.MEMBERS.getColumnName() + ", E'(?:^" + orgPathWithChildren + "|(" + assnsSeparator + ")" + orgPathWithChildren + ")', E'\\\\2" + newVariablePath + "\\\\1\\\\3', 'g'); ");
// References in the links and telemetry scheduler to the root structure
// and its children are not automatically amended to include the new parent
// structure path, but are instead removed
deleteLinkPathRef("^" + dataType + "(?:,|\\\\.|$)", linksDelCmd);
deleteTlmPathRef(dataType + "(?:,|\\\\.|$)", tlmDelCmd);
}
// Check if the added variable is a string array member
if (dataTypeHandler.isString(dataType) && ArrayVariable.isArrayMember(variableName)) {
// Get the string array definition
String stringArrayDefn = ArrayVariable.removeStringSize(newVariablePath);
// Check if this string array hasn't already been processed
if (!stringArrays.contains(stringArrayDefn)) {
// Add the string array definition to the list so that it's only
// processed once (in the event multiple members of the array are
// added)
stringArrays.add(stringArrayDefn);
// Update the links definitions, if needed, with the new string array
// member
updateLinksForStringMemberAddition(tableInfo.getTablePath(), dataType, variableName);
// Remove all references to the string array from the telemetry
// scheduler table
deleteTlmPathRef(stringArrayDefn + "(?:,|:|$)", tlmDelCmd);
}
}
}
}
// Remove the ending comma and space, and append the command's closing semi-colon
addCmd = CcddUtilities.removeTrailer(addCmd, ", ");
addCmd.append("; " + valuesAddCmd.toString() + groupsAddCmd.toString() + fieldsAddCmd.toString() + ordersAddCmd.toString() + assnsAddCmd.toString() + linksDelCmd.toString() + tlmDelCmd.toString());
}
return addCmd.toString();
}
use of CCDD.CcddClassesDataTable.TableModification in project CCDD by nasa.
the class CcddDataTypeEditorDialog method buildUpdates.
/**
********************************************************************************************
* Compare the current data type table data to the committed data and create lists of the
* changed values necessary to update the table in the database to match the current values
********************************************************************************************
*/
private void buildUpdates() {
// Remove change information from a previous commit, if any
modifications.clear();
// Get the number of rows that have been committed to the database
int numCommitted = committedData.length;
// Get the data type table cell values
Object[][] tableData = dataTypeTable.getTableData(true);
// Step through each row in the data type table
for (int tblRow = 0; tblRow < tableData.length; tblRow++) {
boolean matchFound = false;
// Step through each row in the committed version of the data type table data
for (int comRow = 0; comRow < numCommitted && !matchFound; comRow++) {
// Check if the index values match for these rows
if (tableData[tblRow][DataTypesColumn.OID.ordinal()].equals(committedData[comRow][DataTypesColumn.OID.ordinal()])) {
// Set the flags indicating this row has a match
matchFound = true;
boolean isChangedColumn = false;
// Step through each column in the row
for (int column = 0; column < tableData[tblRow].length; column++) {
// Check if the current and committed values don't match
if (!tableData[tblRow][column].equals(committedData[comRow][column])) {
// Set the flag to indicate a column value changed and stop searching
isChangedColumn = true;
break;
}
}
// Check if any columns were changed
if (isChangedColumn) {
// Store the row modification information
modifications.add(new TableModification(tableData[tblRow], committedData[comRow]));
}
}
}
}
}
use of CCDD.CcddClassesDataTable.TableModification in project CCDD by nasa.
the class CcddDbTableCommandHandler method modifyTablePerDataTypeOrMacroChanges.
/**
********************************************************************************************
* Modify all tables affected by changes to the user-defined data type names, or macro names
* and/or macro values. This command is executed in a separate thread since it can take a
* noticeable amount time to complete, and by using a separate thread the GUI is allowed to
* continue to update. The GUI menu commands, however, are disabled until the database command
* completes execution
*
* @param modifications
* list of data type (macro) definition modifications
*
* @param updates
* list of string arrays reflecting the content of the data types (macros) after
* being changed in the data type (macro) editor
*
* @param dialog
* reference to the data type or macro editor dialog
********************************************************************************************
*/
protected void modifyTablePerDataTypeOrMacroChanges(final List<TableModification> modifications, final List<String[]> updates, final CcddDialogHandler dialog) {
final CcddDataTypeHandler newDataTypeHandler;
final CcddMacroHandler newMacroHandler;
final String changeName;
// Set to true if the change is to a data type, and false if the change is to a macro
final boolean isDataType = dialog instanceof CcddDataTypeEditorDialog;
// Check if this is a data type change
if (isDataType) {
// Create new data type, macro, and variable size handlers using the updates from the
// data type editor
newDataTypeHandler = new CcddDataTypeHandler(updates);
newMacroHandler = new CcddMacroHandler(ccddMain, ccddMain.getMacroHandler().getMacroData());
changeName = "Data types";
} else // This is a macro change
{
// Create new macro and variable size handlers using the updates from the macro editor
newDataTypeHandler = dataTypeHandler;
newMacroHandler = new CcddMacroHandler(ccddMain, updates);
changeName = "Macros";
}
// Create a variable size handler accounting for the updates, then build the variable paths
// and offsets lists
final CcddVariableSizeAndConversionHandler newVariableHandler = new CcddVariableSizeAndConversionHandler(ccddMain, newDataTypeHandler, newMacroHandler);
newMacroHandler.setHandlers(newVariableHandler);
newVariableHandler.buildPathAndOffsetLists();
/**
****************************************************************************************
* Class for table information for those tables modified due to changes in a data type
* (macro) definition
****************************************************************************************
*/
class ModifiedTable {
private final TableInformation tableInformation;
private final CcddTableEditorHandler editor;
/**
************************************************************************************
* Class constructor for table information for those tables modified due to changes in
* a data type (macro) definition
*
* @param tablePath
* table path (if applicable) and name
************************************************************************************
*/
ModifiedTable(String tablePath) {
// Load the table's information from the project database
tableInformation = loadTableData(tablePath, false, true, false, dialog);
// Create a table editor handler using the updated data types and/or macros, but
// without displaying the editor itself
editor = new CcddTableEditorHandler(ccddMain, tableInformation, newDataTypeHandler, newMacroHandler);
}
/**
************************************************************************************
* Get the reference to the table information
*
* @return Reference to the table information
************************************************************************************
*/
protected TableInformation getTableInformation() {
return tableInformation;
}
/**
************************************************************************************
* Get the reference to the table editor
*
* @return Reference to the table editor
************************************************************************************
*/
protected CcddTableEditorHandler getEditor() {
return editor;
}
}
// Execute the command in the background
CcddBackgroundCommand.executeInBackground(ccddMain, dialog, new BackgroundCommand() {
boolean errorFlag = false;
List<ModifiedTable> modifiedTables = new ArrayList<ModifiedTable>();
/**
************************************************************************************
* Modify data types (macros) command
************************************************************************************
*/
@Override
protected void execute() {
TypeDefinition typeDefn = null;
// Flag that indicates that only a data type (macro) name has been altered, or a
// data type size where the new size is not larger than the old size. If this
// remains true for all data type (macro) updates then the project database
// internal table update process is streamlined, making it much faster in cases
// where the internal tables reference a large number of variables and tables
boolean nameChangeOnly = true;
// Storage for the table's data. This is the table data as it exists in the project
// database
List<Object[]> tableData;
// Step through each modification
for (TableModification mod : modifications) {
String oldName;
String newName;
String oldNameDelim = null;
String newNameDelim = null;
String[] references;
// Check if this is a data type change
if (isDataType) {
// Get the original and updated user-defined data type names
oldName = CcddDataTypeHandler.getDataTypeName(mod.getOriginalRowData()[DataTypesColumn.USER_NAME.ordinal()].toString(), mod.getOriginalRowData()[DataTypesColumn.C_NAME.ordinal()].toString());
newName = CcddDataTypeHandler.getDataTypeName(mod.getRowData()[DataTypesColumn.USER_NAME.ordinal()].toString(), mod.getRowData()[DataTypesColumn.C_NAME.ordinal()].toString());
// Get the references to the updated data type
references = dataTypeHandler.getDataTypeReferences(oldName, dialog);
// the initial pass)
if (nameChangeOnly) {
// Set to false if the size increased or the base type changed; keep
// equal to true if only the data type name has changed and the size is
// no larger
nameChangeOnly = Integer.valueOf(mod.getOriginalRowData()[DataTypesColumn.SIZE.ordinal()].toString()) >= Integer.valueOf(mod.getRowData()[DataTypesColumn.SIZE.ordinal()].toString()) && mod.getOriginalRowData()[DataTypesColumn.BASE_TYPE.ordinal()].toString().equals(mod.getRowData()[DataTypesColumn.BASE_TYPE.ordinal()].toString());
}
} else // This is a macro change
{
// Get the original and updated user-defined macro names
oldName = mod.getOriginalRowData()[MacrosColumn.MACRO_NAME.ordinal()].toString();
newName = mod.getRowData()[MacrosColumn.MACRO_NAME.ordinal()].toString();
// Get the original and updated macro names with the macro delimiters
oldNameDelim = CcddMacroHandler.getFullMacroName(mod.getOriginalRowData()[MacrosColumn.MACRO_NAME.ordinal()].toString());
newNameDelim = CcddMacroHandler.getFullMacroName(mod.getRowData()[MacrosColumn.MACRO_NAME.ordinal()].toString());
// Get the references to the updated macro
references = macroHandler.getMacroReferences(oldNameDelim, dialog);
// initial pass)
if (nameChangeOnly) {
// Set to false if the macro value changes; keep equal to true if only
// the macro name has changed
nameChangeOnly = macroHandler.getMacroExpansion(mod.getOriginalRowData()[MacrosColumn.VALUE.ordinal()].toString()).equals(newMacroHandler.getMacroExpansion(mod.getRowData()[MacrosColumn.VALUE.ordinal()].toString()));
}
}
// Step through each table/column containing the modification
for (String ref : references) {
String tableName = null;
String changeColumn = null;
String matchColumn = null;
ModifiedTable modifiedTable = null;
// Split the reference into table name, column name, table type, and
// context
String[] tblColDescAndCntxt = ref.split(TABLE_DESCRIPTION_SEPARATOR, 4);
// Create a reference to the search result's database table name and row
// data to shorten comparisons below
String refTableName = tblColDescAndCntxt[SearchResultsQueryColumn.TABLE.ordinal()];
String[] refContext = CcddUtilities.splitAndRemoveQuotes(tblColDescAndCntxt[SearchResultsQueryColumn.CONTEXT.ordinal()]);
// Set to true if the referenced table is a prototype table and false if
// the reference is to the internal custom values table
boolean isPrototype = !refTableName.startsWith(INTERNAL_TABLE_PREFIX);
// Check if the referenced table is a prototype table
if (isPrototype) {
// Set the viewable table name (with capitalization intact) and get the
// column name containing the data type (macro) reference. Use the
// primary key as the matching column criteria
tableName = tblColDescAndCntxt[SearchResultsQueryColumn.COMMENT.ordinal()].split(",", 2)[0];
changeColumn = tblColDescAndCntxt[SearchResultsQueryColumn.COLUMN.ordinal()];
matchColumn = refContext[DefaultColumn.PRIMARY_KEY.ordinal()];
} else // change
if (!isDataType) {
// Get the table name from the variable path in the custom values table
// and get the column name containing the macro reference. Use the
// variable name as the matching column criteria
tableName = refContext[ValuesColumn.TABLE_PATH.ordinal()].replaceAll("(\"|\\s|,[^\\.]*\\.[^,]*$)", "");
changeColumn = refContext[ValuesColumn.COLUMN_NAME.ordinal()];
matchColumn = refContext[ValuesColumn.TABLE_PATH.ordinal()].replaceAll("(.*\\.|\")", "");
} else // This is a data type change and the reference is in the custom values
// table
{
// process
continue;
}
// Step through each table already loaded for modifications
for (ModifiedTable modTbl : modifiedTables) {
// Check if the table has already been loaded
if (modTbl.getTableInformation().getProtoVariableName().equals(tableName)) {
// Store the reference to the modified table and stop searching
modifiedTable = modTbl;
break;
}
}
// Check if the table isn't already loaded
if (modifiedTable == null) {
// Load the table and add it to the list
modifiedTable = new ModifiedTable(tableName);
modifiedTables.add(modifiedTable);
// Check if the table arrays aren't expanded
if (!modifiedTable.getEditor().isExpanded()) {
// Expand the table arrays
modifiedTable.getEditor().showHideArrayMembers();
}
}
// Get the reference to the table to shorten subsequent calls
CcddJTableHandler table = modifiedTable.getEditor().getTable();
// Use the table's type to get the index for the table column containing
// the data type (macro) reference
typeDefn = modifiedTable.getEditor().getTableTypeDefinition();
int changeColumnIndex = isPrototype ? typeDefn.getColumnIndexByDbName(changeColumn) : typeDefn.getColumnIndexByUserName(changeColumn);
String macroValue = null;
// Check is a change was made to a macro
if (!isDataType) {
// Get the original value of the macro
macroValue = macroHandler.getMacroValue(oldName);
}
// Set the flags that indicate if a name or value changed
boolean isNameChange = !oldName.equals(newName);
boolean isValueChange = (isDataType && (dataTypeHandler.getSizeInBytes(oldName) != newDataTypeHandler.getSizeInBytes(newName) || !dataTypeHandler.getBaseDataType(oldName).equals(newDataTypeHandler.getBaseDataType(newName)))) || (!isDataType && macroValue != null && !macroValue.equals(newMacroHandler.getMacroValue(newName)));
// base type, or macro value, changed
if (isNameChange || isValueChange) {
// Get the table's data (again if a name change occurred since changes
// were made)
tableData = table.getTableDataList(false);
// Step through each row
for (int row = 0; row < tableData.size(); row++) {
// column index for the variable name
if (isPrototype ? matchColumn.equals(tableData.get(row)[DefaultColumn.PRIMARY_KEY.ordinal()]) : matchColumn.equals(tableData.get(row)[typeDefn.getColumnIndexByInputType(InputDataType.VARIABLE)].toString())) {
// key and row index columns
for (int column = NUM_HIDDEN_COLUMNS; column < tableData.get(row).length; column++) {
// macro
if (column == changeColumnIndex) {
// Check if the cell value is editable
if (table.isCellEditable(table.convertRowIndexToView(row), table.convertColumnIndexToView(column))) {
// Get the contents of the cell containing the data
// type or macro reference
String oldValue = tableData.get(row)[column].toString();
String newValue = oldValue;
// Check if the data type or macro name changed
if (isNameChange) {
// Check if this is a data type change
if (isDataType) {
// the data type name
if (!oldValue.equals(oldName)) {
// sizeof() call for the data type
if (!CcddVariableSizeAndConversionHandler.hasSizeof(oldValue, oldName)) {
// type match is coincidental
continue;
}
// replacing each sizeof() instance
while (CcddVariableSizeAndConversionHandler.hasSizeof(newValue, oldName)) {
// Replace the data type in the
// sizeof() call with the new name
newValue = newValue.replaceFirst(CcddVariableSizeAndConversionHandler.getSizeofDataTypeMatch(oldName), "sizeof(" + newName + ")");
}
} else // The cell contains only the data type
// name
{
// Set the new cell value to the new
// data type name
newValue = newName;
}
} else // This is a macro change
{
// Replace all instances of the old macro
// name in the table cell with the new name
newValue = macroHandler.replaceMacroName(oldNameDelim, newNameDelim, oldValue);
}
}
// size or base type
if (isDataType && isValueChange) {
// sizeof() call)
if (!newValue.equals(newName) && !CcddVariableSizeAndConversionHandler.hasSizeof(newValue) && !CcddMacroHandler.hasMacro(newValue)) {
// match is coincidental
continue;
}
}
// Store the change in the table data
tableData.get(row)[column] = newValue;
// Make the change to the cell, including any
// updates to changes in array size
table.validateCellContent(tableData, row, column, oldValue, newValue, false, true);
// Load the updated array of data into the table
table.loadDataArrayIntoTable(tableData.toArray(new Object[0][0]), false);
}
// located and processed
break;
}
}
// processed
break;
}
}
}
}
}
try {
// Enable creation of a save point in case an error occurs while modifying a
// table. This prevents committing the changes to the database until after all
// tables are modified
dbCommand.setSavePointEnable(true);
// simplified in order to speed it up
if (nameChangeOnly) {
// references in the internal tables
for (TableModification mod : modifications) {
// Check if this is a data type change
if (isDataType) {
// Get the old and new data type name
String oldName = CcddDataTypeHandler.getDataTypeName(mod.getOriginalRowData()[DataTypesColumn.USER_NAME.ordinal()].toString(), mod.getOriginalRowData()[DataTypesColumn.C_NAME.ordinal()].toString());
String newName = CcddDataTypeHandler.getDataTypeName(mod.getRowData()[DataTypesColumn.USER_NAME.ordinal()].toString(), mod.getRowData()[DataTypesColumn.C_NAME.ordinal()].toString());
// Execute the command to update the internal tables that reference
// variable paths
dbCommand.executeDbUpdate("UPDATE " + InternalTable.LINKS.getTableName() + " SET " + LinksColumn.MEMBER.getColumnName() + " = regexp_replace(" + LinksColumn.MEMBER.getColumnName() + ", E'(.*,)" + oldName + "(\\..*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.TLM_SCHEDULER.getTableName() + " SET " + TlmSchedulerColumn.MEMBER.getColumnName() + " = regexp_replace(" + TlmSchedulerColumn.MEMBER.getColumnName() + ", E'(.*,)" + oldName + "(\\..*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.VALUES.getTableName() + " SET " + ValuesColumn.TABLE_PATH.getColumnName() + " = regexp_replace(" + ValuesColumn.TABLE_PATH.getColumnName() + ", E'(.*,)" + oldName + "(\\..*)'" + ", E'\\\\1" + newName + "\\\\2'); ", dialog);
} else // This is a macro change
{
// Get the original and updated user-defined macro names (with the
// delimiters)
String oldName = CcddMacroHandler.getFullMacroName(mod.getOriginalRowData()[MacrosColumn.MACRO_NAME.ordinal()].toString());
String newName = CcddMacroHandler.getFullMacroName(mod.getRowData()[MacrosColumn.MACRO_NAME.ordinal()].toString());
// Execute the command to update the internal tables that reference
// variable and table paths
dbCommand.executeDbUpdate("UPDATE " + InternalTable.ASSOCIATIONS.getTableName() + " SET " + AssociationsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + AssociationsColumn.MEMBERS.getColumnName() + ", E'(.*)" + oldName + "(.*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.FIELDS.getTableName() + " SET " + FieldsColumn.OWNER_NAME.getColumnName() + " = regexp_replace(" + FieldsColumn.OWNER_NAME.getColumnName() + ", E'(.*)" + oldName + "(.*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.GROUPS.getTableName() + " SET " + GroupsColumn.MEMBERS.getColumnName() + " = regexp_replace(" + GroupsColumn.MEMBERS.getColumnName() + ", E'(.*)" + oldName + "(.*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.LINKS.getTableName() + " SET " + LinksColumn.MEMBER.getColumnName() + " = regexp_replace(" + LinksColumn.MEMBER.getColumnName() + ", E'(.*)" + oldName + "(.*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.TLM_SCHEDULER.getTableName() + " SET " + TlmSchedulerColumn.MEMBER.getColumnName() + " = regexp_replace(" + TlmSchedulerColumn.MEMBER.getColumnName() + ", E'(.*)" + oldName + "(.*)'" + ", E'\\\\1" + newName + "\\\\2'); UPDATE " + InternalTable.VALUES.getTableName() + " SET " + ValuesColumn.TABLE_PATH.getColumnName() + " = regexp_replace(" + ValuesColumn.TABLE_PATH.getColumnName() + ", E'(.*)" + oldName + "(.*)'" + ", E'\\\\1" + newName + "\\\\2'); ", dialog);
}
}
}
// Step through each modified table
for (ModifiedTable modTbl : modifiedTables) {
// Build the additions, modifications, and deletions to the table
modTbl.getEditor().buildUpdates();
// table editors that contain the data type (macro) reference(s)
if (modifyTableData(modTbl.getTableInformation(), modTbl.getEditor().getAdditions(), modTbl.getEditor().getModifications(), modTbl.getEditor().getDeletions(), true, nameChangeOnly, false, false, false, newDataTypeHandler, dialog)) {
throw new SQLException("table modification error");
}
}
// Store the data type or macro table
dbCommand.executeDbUpdate(storeNonTableTypesInfoTableCommand((isDataType ? InternalTable.DATA_TYPES : InternalTable.MACROS), CcddUtilities.removeArrayListColumn(updates, (isDataType ? DataTypesColumn.OID.ordinal() : MacrosColumn.OID.ordinal())), null, dialog), dialog);
// Commit the change(s) to the database
dbCommand.getConnection().commit();
// Inform the user that the update succeeded
eventLog.logEvent(SUCCESS_MSG, changeName + " and all affected tables updated");
} catch (SQLException se) {
try {
// Inform the user that updating the macros failed
eventLog.logFailEvent(dialog, "Cannot update " + changeName.toLowerCase() + "; cause '" + se.getMessage() + "'", "<html><b>Cannot update " + changeName.toLowerCase());
// Revert the changes to the tables that were successfully updated prior
// the current table
dbCommand.executeDbCommand("ROLLBACK TO SAVEPOINT " + DB_SAVE_POINT_NAME + ";", dialog);
} catch (SQLException se2) {
// Inform the user that the reversion to the save point failed
eventLog.logFailEvent(dialog, "Cannot revert changes to table(s); cause '" + se.getMessage() + "'", "<html><b>Cannot revert changes to table(s)");
}
errorFlag = true;
} catch (Exception e) {
// Display a dialog providing details on the unanticipated error
CcddUtilities.displayException(e, dialog);
} finally {
// Reset the flag for creating a save point
dbCommand.setSavePointEnable(false);
}
}
/**
************************************************************************************
* Modify data types or macros command complete
************************************************************************************
*/
@Override
protected void complete() {
// Rebuild the variable paths and offsets
variableHandler.buildPathAndOffsetLists();
// Check if this is a data type change
if (isDataType) {
((CcddDataTypeEditorDialog) dialog).doDataTypeUpdatesComplete(errorFlag);
} else // This is a macro change
{
((CcddMacroEditorDialog) dialog).doMacroUpdatesComplete(errorFlag);
}
}
});
}
Aggregations