/* Copyright (c) 2024 PTC Inc. and/or Its Subsidiary Companies. All Rights Reserved. */ #include <ProToolkit.h> #include <ProMdlChk.h> #include <ProParameter.h> #include <ProSolid.h> #include <ProDrawing.h> #include <ProFamtable.h> #include <ProSelection.h> #include <ProScope.h> static wchar_t** s_results_table = NULL; static wchar_t* s_results_url = NULL; #define MISSING_PARAM (int)999 #define INVALID_PARAM_TYPE (int)9999 /*=====================================================================================================*\ FUNCTION: UserCheckMdlParamNameCompare PURPOSE: Compare the model name to the value of the given param. RETURNS: MISSING_PARAM, INVALID_PARAM_TYPE, or the integer results of the string comparison. \*======================================================================================================*/ static int UserCheckMdlParamNameCompare (ProMdl mdl, ProName param_name) { ProError status = PRO_TK_NO_ERROR; ProMdlName mdl_name; ProModelitem modelitem; ProParamvalue param_value; ProParameter param; int compare_result; status = ProMdlMdlnameGet (mdl, mdl_name); status = ProMdlToModelitem(mdl, &modelitem); status = ProParameterInit(&modelitem, param_name, ¶m); /*------------------------------------------------------------------------------------------------------*\ Parameter is missing \*------------------------------------------------------------------------------------------------------*/ if (status != PRO_TK_NO_ERROR) { compare_result = MISSING_PARAM; } else { ProUnititem units; status = ProParameterValueWithUnitsGet(¶m,¶m_value, &units); /*------------------------------------------------------------------------------------------------------*\ Parameter is not a string parameter \*------------------------------------------------------------------------------------------------------*/ if (status != PRO_TK_NO_ERROR || param_value.type != PRO_PARAM_STRING) { compare_result = INVALID_PARAM_TYPE; } else { /*------------------------------------------------------------------------------------------------------*\ Compare the model name to the parameter value. \*------------------------------------------------------------------------------------------------------*/ ProWstringCompare (param_value.value.s_val, mdl_name, PRO_VALUE_UNUSED, &compare_result); } } return (compare_result); } /*======================================================================================================*\ FUNCTION: UserCustCheckMdlParamName PURPOSE: Check function for the ModelCheck check. Outputs details of the comparison as a ModelCheck error. \*======================================================================================================*/ static ProError UserCustCheckMdlParamName (ProCharName name, ProMdl mdl, ProAppData appdata, int* results_count, wchar_t** results_url, wchar_t*** results_table) { ProFileName message_file; ProError status = PRO_TK_NO_ERROR; ProName* param_name_ptr = (ProName*)appdata; ProMdlName mdl_name; int compare_result = UserCheckMdlParamNameCompare (mdl, *param_name_ptr); ProLine error_msg; /*------------------------------------------------------------------------------------------------------*\ Parameter is set correctly. \*------------------------------------------------------------------------------------------------------*/ if (compare_result == 0) { *results_count = 0; *results_url = NULL; *results_table = NULL; return (PRO_TK_NO_ERROR); } /*------------------------------------------------------------------------------------------------------*\ Parameter is not set correctly. Show an appropriate error message. \*------------------------------------------------------------------------------------------------------*/ else { ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); status = ProMdlMdlnameGet (mdl, mdl_name); if (compare_result == MISSING_PARAM) { status = ProMessageToBuffer (error_msg, message_file, "UG CustomCheck: MDL PARAM NOT FOUND", *param_name_ptr, mdl_name); } else if (compare_result == INVALID_PARAM_TYPE) { status = ProMessageToBuffer (error_msg, message_file, "UG CustomCheck: MDL PARAM INV TYPE", *param_name_ptr, mdl_name); } else { status = ProMessageToBuffer (error_msg, message_file, "UG CustomCheck: MDL PARAM INCORRECT", *param_name_ptr, mdl_name); } status = ProArrayAlloc(1, sizeof(ProWstring), 1, (ProArray*)&s_results_table); s_results_table [0] = (wchar_t*) calloc (PRO_LINE_SIZE, sizeof (wchar_t)); ProWstringCopy (error_msg, s_results_table[0], PRO_VALUE_UNUSED); /*------------------------------------------------------------------------------------------------------*\ This URL will be used for the "Check Details" link in the ModelCheck report. \*------------------------------------------------------------------------------------------------------*/ s_results_url = (wchar_t*) calloc (PRO_PATH_SIZE, sizeof (wchar_t)); ProStringToWstring (s_results_url, "http://www.ptc.com/"); *results_table = s_results_table; *results_count = 1; *results_url = s_results_url; return (PRO_TK_NO_ERROR); } } /*======================================================================================================*\ FUNCTION: UserCustCheckMdlAccType PURPOSE: Check function for the ModelCheck check for accuracy type. Outputs the accuracy type. \*======================================================================================================*/ static ProError UserCustCheckMdlAccType (ProCharName name, ProMdl mdl, ProAppData appdata, int* results_count, wchar_t** results_url, wchar_t*** results_table) { ProFileName message_file; ProError status = PRO_TK_NO_ERROR; ProAccuracyType acc_type; double acc_value; ProLine info_msg; ProCharLine message_key; ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); /*------------------------------------------------------------------------------------------------------*\ Output the model accuracy type as an info check. \*------------------------------------------------------------------------------------------------------*/ status = ProSolidAccuracyGet (mdl, &acc_type, &acc_value); switch (acc_type) { case PRO_ACCURACY_ABSOLUTE: strcpy (message_key, "UG CustomCheck: MDL ACC ABS"); break; case PRO_ACCURACY_RELATIVE: strcpy (message_key, "UG CustomCheck: MDL ACC REL"); break; default: return (PRO_TK_UNSUPPORTED); } status = ProMessageToBuffer (info_msg, message_file, message_key); status = ProArrayAlloc(1, sizeof(ProWstring), 1, (ProArray*)&s_results_table); s_results_table [0] = (wchar_t*) calloc (PRO_LINE_SIZE, sizeof (wchar_t)); ProWstringCopy (info_msg, s_results_table[0], PRO_VALUE_UNUSED); *results_table = s_results_table; *results_count = 1; *results_url = NULL; return (PRO_TK_NO_ERROR); } /*======================================================================================================*\ FUNCTION: UserCustCheckRefScope PURPOSE: Check function for the ModelCheck check for reference scope. Outputs the scope permitted for external refs. \*======================================================================================================*/ static ProError UserCustCheckRefScope (ProCharName name, ProMdl mdl, ProAppData appdata, int* results_count, wchar_t** results_url, wchar_t*** results_table) { ProFileName message_file; ProError status = PRO_TK_NO_ERROR; ProExtRefScope scope; ProInvalidRefBehavior behavior; ProLine info_msg; ProCharLine message_key; ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); /*------------------------------------------------------------------------------------------------------*\ Output the model ref control level as an info check. \*------------------------------------------------------------------------------------------------------*/ status = ProRefCtrlSolidGet (mdl, &scope, &behavior); switch (scope) { case PRO_REFCTRL_ALLOW_ALL: strcpy (message_key, "UG CustomCheck: MDL REFC ALL"); break; case PRO_REFCTRL_ALLOW_SUBASSEMBLY: strcpy (message_key, "UG CustomCheck: MDL REFC SUB"); break; case PRO_REFCTRL_ALLOW_SKELETON: strcpy (message_key, "UG CustomCheck: MDL REFC SKEL"); break; case PRO_REFCTRL_ALLOW_NONE: strcpy (message_key, "UG CustomCheck: MDL REFC NONE"); break; default: return (PRO_TK_UNSUPPORTED); } status = ProMessageToBuffer (info_msg, message_file, message_key); status = ProArrayAlloc(1, sizeof(ProWstring), 1, (ProArray*)&s_results_table); s_results_table [0] = (wchar_t*) calloc (PRO_LINE_SIZE, sizeof (wchar_t)); ProWstringCopy (info_msg, s_results_table[0], PRO_VALUE_UNUSED); *results_table = s_results_table; *results_count = 1; *results_url = NULL; return (PRO_TK_NO_ERROR); } /*======================================================================================================*\ FUNCTION: UserCustCheckDwgviewGeneric PURPOSE: Check function for the ModelCheck check for generics in drawing views. Outputs a list of the view names. \*======================================================================================================*/ static ProError UserCustCheckDwgviewGeneric (ProCharName name, ProMdl mdl, ProAppData appdata, int* results_count, wchar_t** results_url, wchar_t*** results_table) { ProFileName message_file; ProError status = PRO_TK_NO_ERROR; ProView* views; int i, size = 0; ProSolid solid; ProFamtable fam_table; wchar_t* table_entry; ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); /*------------------------------------------------------------------------------------------------------*\ Check the model shown by each view \*------------------------------------------------------------------------------------------------------*/ status = ProDrawingViewsCollect ((ProDrawing)mdl, &views); if (status == PRO_TK_NO_ERROR) { status = ProArraySizeGet (views, &size); if (status == PRO_TK_NO_ERROR && size > 0) { status = ProArrayAlloc(0, sizeof(ProWstring), 1, (ProArray*)&s_results_table); for (i = 0; i < size; i ++) { status = ProDrawingViewSolidGet ((ProDrawing)mdl, views[i], &solid); /*------------------------------------------------------------------------------------------------------*\ If ProFamtableCheck() succeeds, this means that the model has a family table with at least one instance or item in it. \*------------------------------------------------------------------------------------------------------*/ status = ProFamtableInit (solid, &fam_table); status = ProFamtableCheck (&fam_table); if (status == PRO_TK_NO_ERROR) { table_entry = (wchar_t*) calloc (PRO_NAME_SIZE, sizeof (wchar_t)); ProDrawingViewNameGet ((ProDrawing)mdl, views [i], table_entry); ProArrayObjectAdd ((ProArray*)&s_results_table, -1, 1, &table_entry); } } /*------------------------------------------------------------------------------------------------------*\ If no items were found... \*------------------------------------------------------------------------------------------------------*/ status = ProArraySizeGet (s_results_table, &size); if (size == 0) { ProArrayFree ((ProArray*)&s_results_table); s_results_table = NULL; } } } *results_table = s_results_table; *results_count = size; *results_url = NULL; return (PRO_TK_NO_ERROR); } /*======================================================================================================*\ FUNCTION: UserCustCheckCleanUtility PURPOSE: Cleanup function for all of the ModelCheck checks. \*======================================================================================================*/ static ProError UserCustCheckCleanUtility (ProCharName name, ProMdl mdl, ProAppData appdata) { int size, i; ProError status = PRO_TK_NO_ERROR; if (s_results_table != NULL) { status = ProArraySizeGet (s_results_table, &size); if (status == PRO_TK_NO_ERROR) { for (i = 0; i < size; i++) free (s_results_table [i]); ProArrayFree ((ProArray*)&s_results_table); } s_results_table = NULL; } if (s_results_url != NULL) { free (s_results_url); s_results_url = NULL; } return (PRO_TK_NO_ERROR); } /*======================================================================================================*\ FUNCTION: UserCustUpdateMdlParamName PURPOSE: Update function for a ModelCheck error due to an invalid or missing model name parameter. \*======================================================================================================*/ static ProError UserCustUpdateMdlParamName (ProCharName name, ProMdl mdl, wchar_t* selected_item, ProAppData appdata) { ProFileName message_file; ProError status = PRO_TK_NO_ERROR; ProName* param_name_ptr = (ProName*)appdata; ProMdlName mdl_name; int compare_result = UserCheckMdlParamNameCompare (mdl, *param_name_ptr); ProModelitem modelitem; ProParamvalue param_value; ProParameter param; if (compare_result == 0) { /* Nothing to do */ return (PRO_TK_NO_ERROR); } else { ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); status = ProMdlMdlnameGet (mdl, mdl_name); param_value.type = PRO_PARAM_STRING; ProWstringCopy (mdl_name, param_value.value.s_val, PRO_VALUE_UNUSED); status = ProMdlToModelitem (mdl, &modelitem); /*------------------------------------------------------------------------------------------------------*\ Create the missing parameter with the correct value. \*------------------------------------------------------------------------------------------------------*/ if (compare_result == MISSING_PARAM) { ProParameterWithUnitsCreate(&modelitem, *param_name_ptr, ¶m_value, NULL, ¶m); status = ProMessageDisplay (message_file, "UG CustomCheck: MDL PARAM UPDATED", *param_name_ptr); } /*------------------------------------------------------------------------------------------------------*\ Since there is no way to change a parameter's type except by deleting and recreating it, the check will not attempt to repair this situation. Instead, show a message to the user. \*------------------------------------------------------------------------------------------------------*/ else if (compare_result == INVALID_PARAM_TYPE) { status = ProMessageDisplay (message_file, "UG CustomCheck: MDL PARAM UPDATE TYPE", *param_name_ptr); } /*------------------------------------------------------------------------------------------------------*\ Change the value of the parameter appropriately. \*------------------------------------------------------------------------------------------------------*/ else { ProParameterInit (&modelitem, *param_name_ptr, ¶m); ProParameterValueWithUnitsSet(¶m, ¶m_value, NULL); status = ProMessageDisplay (message_file, "UG CustomCheck: MDL PARAM UPDATED", *param_name_ptr); } return (PRO_TK_NO_ERROR); } } /*======================================================================================================*\ FUNCTION: UserDwgviewFilterByName PURPOSE: Filter function to find drawing views by matching the input name. \*======================================================================================================*/ static ProError UserDwgviewFilterByName (ProDrawing drawing, ProView view, ProAppData app_data) { ProError status = PRO_TK_NO_ERROR; ProName name; wchar_t* target_name = (wchar_t*)app_data; int compare_result; status = ProDrawingViewNameGet (drawing, view, name); ProWstringCompare (name, target_name, PRO_VALUE_UNUSED, &compare_result); if (compare_result == 0) return (PRO_TK_NO_ERROR); else return (PRO_TK_CONTINUE); } #define DELTA_X 10.0 /* Screen coordinates */ #define DELTA_Y 10.0 /* Screen coordinates */ /*======================================================================================================*\ FUNCTION: UserDwgviewHighlight PURPOSE: Action function to highlight the drawing view. \*======================================================================================================*/ static ProError UserDwgviewHighlight (ProDrawing drawing, ProView view, ProError filter_status, ProAppData app_data) { ProError status = PRO_TK_NO_ERROR; int sheet; int win_id; ProPoint3d outline [2]; ProPoint3d points [5]; ProColor old_color, highlite_color; ProLinestyle old_ls; status = ProDrawingViewSheetGet (drawing, view, &sheet); status = ProDrawingCurrentSheetSet (drawing, sheet); status = ProWindowCurrentGet (&win_id); ProWindowRefresh (win_id); /*------------------------------------------------------------------------------------------------------*\ Draw the outline of the view to highlight it. \*------------------------------------------------------------------------------------------------------*/ status = ProDrawingViewOutlineGet (drawing, view, outline); points[0][0] = outline[0][0] - DELTA_X; points[0][1] = outline[0][1] - DELTA_Y; points[0][2] = 0.0; points[1][0] = outline[0][0] - DELTA_X; points[1][1] = outline[1][1] + DELTA_Y; points[1][2] = 0.0; points[2][0] = outline[1][0] + DELTA_X; points[2][1] = outline[1][1] + DELTA_Y; points[2][2] = 0.0; points[3][0] = outline[1][0] + DELTA_X; points[3][1] = outline[0][1] - DELTA_Y; points[3][2] = 0.0; points[4][0] = outline[0][0] - DELTA_X; points[4][1] = outline[0][1] - DELTA_Y; points[4][2] = 0.0; ProLinestyleSet (PRO_LINESTYLE_PHANTOM, &old_ls); highlite_color.method = PRO_COLOR_METHOD_TYPE; highlite_color.value.type = PRO_COLOR_HIGHLITE; ProGraphicsColorModify (&highlite_color, &old_color); ProGraphicsPolylineDraw(points, 5); ProGraphicsColorModify (&old_color, NULL); ProLinestyleSet (old_ls, NULL); return (PRO_TK_E_FOUND); } /*======================================================================================================*\ FUNCTION: UserCustActionDwgviewGeneric PURPOSE: Action function for the ModelCheck check that locates drawing views using generics. \*======================================================================================================*/ static ProError UserCustActionDwgviewGeneric (ProCharName name, ProMdl mdl, wchar_t* selected_item, ProAppData appdata) { ProFileName message_file; ProError status = PRO_TK_NO_ERROR; ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); ProDrawingViewVisit ((ProDrawing)mdl, UserDwgviewHighlight, UserDwgviewFilterByName, (ProAppData)selected_item); return (PRO_TK_NO_ERROR); } /*======================================================================================================*\ FUNCTION: UserCustomModelChecksDefine PURPOSE: Registers all of the custom Pro/TOOLKIT ModelCheck checks. \*======================================================================================================*/ int UserCustomModelChecksDefine() { ProFileName message_file; ProCharName model_check_name; ProLine check_label, action_label, update_label; static ProName param_name; ProError status; /*--------------------------------------------------------------------*\ Prepare the button labels \*--------------------------------------------------------------------*/ /* Parameter name that should contain the model owner name */ ProStringToWstring (param_name, "MDL_NAME_PARAM"); ProStringToWstring (message_file, "pt_ug_modelcheck.txt"); /* The name of the check. */ strcpy(model_check_name, "CHKTK_UG_MDLPARAM_NAME"); /* The label for the check */ status = ProMessageToBuffer (check_label, message_file, "UG CustomCheck: MDL PARAM NAME", param_name); /* Label for the button used to update the model for an item found by the check */ status = ProMessageToBuffer (update_label, message_file, "UG CustomCheckUpdate: MDL PARAM NAME"); /*--------------------------------------------------------------------*\ Register the custom ModelCheck check. This check allows update of the incorrect situation. \*--------------------------------------------------------------------*/ status = ProModelcheckCheckRegister (model_check_name, check_label, NULL, UserCustCheckMdlParamName, UserCustCheckCleanUtility, NULL, NULL, update_label, UserCustUpdateMdlParamName, (ProAppData) ¶m_name); /*--------------------------------------------------------------------*\ Prepare the button labels \*--------------------------------------------------------------------*/ /* The name of the check. */ strcpy(model_check_name, "CHKTK_UG_MDL_ACC_TYPE"); /* The label for the check */ status = ProMessageToBuffer (check_label, message_file, "UG CustomCheck: MDL ACC TYPE"); /*--------------------------------------------------------------------*\ Register the custom ModelCheck check (an info check, so no action or update is possible). \*--------------------------------------------------------------------*/ status = ProModelcheckCheckRegister (model_check_name, check_label, NULL, UserCustCheckMdlAccType, UserCustCheckCleanUtility, NULL, NULL, NULL, NULL, NULL); /*--------------------------------------------------------------------*\ Prepare the button labels \*--------------------------------------------------------------------*/ /* The name of the check. */ strcpy(model_check_name, "CHKTK_UG_MDL_REFC_SCOPE"); /* The label for the check */ status = ProMessageToBuffer (check_label, message_file, "UG CustomCheck: MDL REFC SCOPE"); /*--------------------------------------------------------------------*\ Register the custom ModelCheck check (an info check, so no action or update is possible). \*--------------------------------------------------------------------*/ status = ProModelcheckCheckRegister (model_check_name, check_label, NULL, UserCustCheckRefScope, UserCustCheckCleanUtility, NULL, NULL, NULL, NULL, NULL); /*--------------------------------------------------------------------*\ Prepare the button labels \*--------------------------------------------------------------------*/ /* The name of the check. */ strcpy(model_check_name, "CHKTK_UG_DWGVIEW_GENERIC"); /* The label for the check */ status = ProMessageToBuffer (check_label, message_file, "UG CustomCheck: DWGVIEW GENERIC", param_name); /* Label for the button used to update the model for an item found by the check */ status = ProMessageToBuffer (action_label, message_file, "UG CustomCheckAction: DWGVIEW GENERIC"); /*--------------------------------------------------------------------*\ Register the custom ModelCheck check; this check has a Highlight action that users can use. \*--------------------------------------------------------------------*/ status = ProModelcheckCheckRegister (model_check_name, check_label, NULL, UserCustCheckDwgviewGeneric, UserCustCheckCleanUtility, action_label, UserCustActionDwgviewGeneric, NULL, NULL, NULL); return (PRO_TK_NO_ERROR); }