feat: add automatic file renaming for shrinkwrap exports to avoid overwrites

- Add FileExists() function to check if file already exists in filesystem
- Add GenerateUniqueFilePath() function to generate unique file names with _1, _2, etc. suffixes
- Modify ExecuteOTKShrinkwrap() to check for existing files before saving
- Rename Creo model internally if file name needs to be changed
- Use timestamp as fallback when maximum attempts (999) are exhausted
- Ensure proper .prt extension handling

This prevents accidental overwriting of existing shrinkwrap export files by automatically appending incremental suffixes to duplicate file names.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sladro 2025-09-20 12:55:01 +08:00
parent 8e037ea486
commit 83cf963b9d
2 changed files with 88 additions and 1 deletions

View File

@ -14,6 +14,7 @@
#endif
#include <functional>
#include <numeric>
#include <io.h> // For _access on Windows
ShrinkwrapManager* ShrinkwrapManager::instance = nullptr;
@ -250,6 +251,46 @@ double ShrinkwrapManager::CalculateModelVolume(pfcModel_ptr model) {
return 0.0;
}
bool ShrinkwrapManager::FileExists(const std::string& filepath) {
// Use _access for Windows platform
return (_access(filepath.c_str(), 0) == 0);
}
std::string ShrinkwrapManager::GenerateUniqueFilePath(const std::string& base_path, const std::string& file_name) {
// Construct full path
std::string full_path = base_path + "\\" + file_name;
// Return original path if file doesn't exist
if (!FileExists(full_path)) {
return full_path;
}
// Extract name and extension
size_t dot_pos = file_name.find_last_of('.');
std::string name_without_ext = (dot_pos != std::string::npos) ? file_name.substr(0, dot_pos) : file_name;
std::string extension = (dot_pos != std::string::npos) ? file_name.substr(dot_pos) : "";
// Try different suffixes
int counter = 1;
const int max_attempts = 999; // Limit maximum attempts
while (counter <= max_attempts) {
std::string new_file_name = name_without_ext + "_" + std::to_string(counter) + extension;
full_path = base_path + "\\" + new_file_name;
if (!FileExists(full_path)) {
return full_path;
}
counter++;
}
// Use timestamp as fallback if all attempts exhausted
auto now = std::chrono::system_clock::now();
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
std::string timestamp_file_name = name_without_ext + "_" + std::to_string(timestamp) + extension;
return base_path + "\\" + timestamp_file_name;
}
pfcModel_ptr ShrinkwrapManager::ExecuteOTKShrinkwrap(pfcModel_ptr source_model, const ShrinkwrapShellRequest& request) {
if (!source_model) return nullptr;
@ -315,11 +356,53 @@ pfcModel_ptr ShrinkwrapManager::ExecuteOTKShrinkwrap(pfcModel_ptr source_model,
try {
if (output_model) {
// 直接保存模型到当前工作目录
// Get current working directory
xstring current_dir_xstr = session_info.session->GetCurrentDirectory();
std::string save_path = StringToStdString(current_dir_xstr);
// Get model file name with extension
xstring model_name_xstr = output_model->GetFileName();
std::string file_name = StringToStdString(model_name_xstr);
// Add .prt extension if not present
if (file_name.find(".prt") == std::string::npos &&
file_name.find(".PRT") == std::string::npos) {
file_name += ".prt";
}
// Check for existing file and generate unique path
std::string unique_file_path = GenerateUniqueFilePath(save_path, file_name);
// Extract new file name if path was modified
size_t last_slash = unique_file_path.find_last_of('\\');
if (last_slash != std::string::npos) {
std::string new_file_name = unique_file_path.substr(last_slash + 1);
// Remove extension to get model name
size_t dot_pos = new_file_name.find_last_of('.');
if (dot_pos != std::string::npos) {
new_file_name = new_file_name.substr(0, dot_pos);
}
// Rename model if name changed
std::string original_name = StringToStdString(model_name_xstr);
size_t orig_dot_pos = original_name.find_last_of('.');
if (orig_dot_pos != std::string::npos) {
original_name = original_name.substr(0, orig_dot_pos);
}
if (new_file_name != original_name) {
xstring new_name_xstr = StringToXString(new_file_name);
output_model->Rename(new_name_xstr);
}
}
// Save model to disk
output_model->Save();
}
} catch (...) {
// Save failed but return model anyway
// Model exists in session even if save failed
}
return pfcModel::cast(output_part);

View File

@ -90,6 +90,10 @@ private:
// 质量属性计算
double CalculateModelVolume(pfcModel_ptr model);
// File system operations
bool FileExists(const std::string& filepath);
std::string GenerateUniqueFilePath(const std::string& base_path, const std::string& file_name);
public:
// 单例模式
static ShrinkwrapManager& Instance();