teigha 오류 수정
This commit is contained in:
@@ -153,6 +153,23 @@
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button x:Name="btnAuto"
|
||||
Content="🤖 자동" Width="150" Height="45"
|
||||
Margin="5,0"
|
||||
Click="BtnAuto_Click" FontSize="14" FontWeight="Bold"
|
||||
Background="#4CAF50" Foreground="White"
|
||||
BorderThickness="0">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#45A049"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
@@ -20,20 +20,40 @@ namespace DwgExtractorManual
|
||||
private DispatcherTimer _timer;
|
||||
private ExportExcel? _exportExcel;
|
||||
private SqlDatas? _sqlDatas;
|
||||
// 자동 처리 모드 플래그
|
||||
private bool isAutoProcessing = false;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeDefaultPaths();
|
||||
InitializeTimer();
|
||||
|
||||
// 앱 종료 시 Teigha 리소스 정리
|
||||
this.Closed += MainWindow_Closed;
|
||||
|
||||
LogMessage("🚀 DWG 정보 추출기가 시작되었습니다.");
|
||||
}
|
||||
|
||||
private void MainWindow_Closed(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogMessage("🔄 애플리케이션 종료 시 Teigha 리소스 정리 중...");
|
||||
TeighaServicesManager.Instance.ForceDisposeServices();
|
||||
LogMessage("✅ Teigha 리소스 정리 완료");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"⚠️ 앱 종료 시 Teigha 정리 중 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeDefaultPaths()
|
||||
{
|
||||
// 기본 경로 설정 - 실제 환경에 맞게 수정
|
||||
txtSourceFolder.Text = @"D:\dwgpdfcompare\test2";
|
||||
txtResultFolder.Text = @"D:\dwgpdfcompare\result";
|
||||
txtSourceFolder.Text = @"C:\WorkProjects\dwfpdfCompare";
|
||||
txtResultFolder.Text = @"C:\WorkProjects\dwfpdfCompare";
|
||||
|
||||
// 경로가 존재하지 않으면 기본값으로 설정
|
||||
if (!Directory.Exists(txtSourceFolder.Text))
|
||||
@@ -159,15 +179,13 @@ namespace DwgExtractorManual
|
||||
// 입력 유효성 검사
|
||||
if (string.IsNullOrEmpty(txtSourceFolder.Text) || !Directory.Exists(txtSourceFolder.Text))
|
||||
{
|
||||
System.Windows.MessageBox.Show("유효한 변환할 폴더를 선택하세요.", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
ShowMessageBox("유효한 변환할 폴더를 선택하세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(txtResultFolder.Text) || !Directory.Exists(txtResultFolder.Text))
|
||||
{
|
||||
System.Windows.MessageBox.Show("유효한 결과 저장 폴더를 선택하세요.", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
ShowMessageBox("유효한 결과 저장 폴더를 선택하세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -181,7 +199,7 @@ namespace DwgExtractorManual
|
||||
{
|
||||
if (!testSql.TestConnection())
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
"PostgreSQL 데이터베이스에 연결할 수 없습니다.\n\n" +
|
||||
"연결 설정을 확인하고 데이터베이스 서버가 실행 중인지 확인하세요.",
|
||||
"데이터베이스 연결 오류",
|
||||
@@ -194,7 +212,7 @@ namespace DwgExtractorManual
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
$"데이터베이스 연결 테스트 중 오류가 발생했습니다:\n\n{ex.Message}",
|
||||
"오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
LogMessage($"❌ 데이터베이스 연결 오류: {ex.Message}");
|
||||
@@ -206,6 +224,7 @@ namespace DwgExtractorManual
|
||||
btnExtract.IsEnabled = false;
|
||||
btnPdfExtract.IsEnabled = false;
|
||||
btnMerge.IsEnabled = false;
|
||||
btnAuto.IsEnabled = false;
|
||||
btnBrowseSource.IsEnabled = false;
|
||||
btnBrowseResult.IsEnabled = false;
|
||||
rbExcel.IsEnabled = false;
|
||||
@@ -225,8 +244,7 @@ namespace DwgExtractorManual
|
||||
{
|
||||
LogMessage($"❌ 치명적 오류 발생: {ex.Message}");
|
||||
UpdateStatus("오류가 발생했습니다.");
|
||||
System.Windows.MessageBox.Show($"작업 중 오류가 발생했습니다:\n\n{ex.Message}",
|
||||
"오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
ShowMessageBox($"작업 중 오류가 발생했습니다:\n\n{ex.Message}", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -234,6 +252,7 @@ namespace DwgExtractorManual
|
||||
btnExtract.IsEnabled = true;
|
||||
btnPdfExtract.IsEnabled = true;
|
||||
btnMerge.IsEnabled = true;
|
||||
btnAuto.IsEnabled = true;
|
||||
btnBrowseSource.IsEnabled = true;
|
||||
btnBrowseResult.IsEnabled = true;
|
||||
rbExcel.IsChecked = true;
|
||||
@@ -242,9 +261,280 @@ namespace DwgExtractorManual
|
||||
LogMessage(new string('=', 50));
|
||||
LogMessage("🏁 작업 완료");
|
||||
LogMessage(new string('=', 50)); // ✅ 정상 작동
|
||||
|
||||
// 자동 처리 모드 비활성화
|
||||
isAutoProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MessageBox 표시 (자동 모드에서는 로그만 출력)
|
||||
/// </summary>
|
||||
private void ShowMessageBox(string message, string title, MessageBoxButton button = MessageBoxButton.OK, MessageBoxImage image = MessageBoxImage.Information)
|
||||
{
|
||||
if (isAutoProcessing)
|
||||
{
|
||||
LogMessage($"📢 {title}: {message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Windows.MessageBox.Show(message, title, button, image);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 확인 대화상자 표시 (자동 모드에서는 자동으로 Yes 반환)
|
||||
/// </summary>
|
||||
private MessageBoxResult ShowConfirmationDialog(string message, string title)
|
||||
{
|
||||
if (isAutoProcessing)
|
||||
{
|
||||
LogMessage($"📢 {title}: {message} - 자동 승인됨");
|
||||
return MessageBoxResult.Yes;
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Windows.MessageBox.Show(message, title, MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG 파일 처리 - 자동 모드용 (폴더 경로 직접 지정)
|
||||
/// </summary>
|
||||
/// <param name="sourceFolderPath">처리할 폴더 경로</param>
|
||||
private async Task ProcessFiles(string sourceFolderPath)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var targetDir = new DirectoryInfo(sourceFolderPath);
|
||||
var files = targetDir.GetFiles("*.dwg", SearchOption.AllDirectories);
|
||||
|
||||
if (files.Length == 0)
|
||||
{
|
||||
UpdateStatus("선택한 폴더에 DWG 파일이 없습니다.");
|
||||
ShowMessageBox("선택한 폴더에 DWG 파일이 없습니다.", "정보", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
// 결과 저장 폴더는 UI에서 가져옴 (변경하지 않음)
|
||||
string resultDir = txtResultFolder.Text;
|
||||
|
||||
LogMessage($"📊 처리할 파일 수: {files.Length}개");
|
||||
LogMessage($"📋 출력 모드: {(rbExcel.IsChecked == true ? "Excel" : "Database")}");
|
||||
LogMessage($"📂 소스 폴더: {sourceFolderPath}");
|
||||
LogMessage($"💾 결과 폴더: {resultDir}");
|
||||
|
||||
try
|
||||
{
|
||||
if (rbExcel.IsChecked == true)
|
||||
{
|
||||
LogMessage("📊 Excel 내보내기 모드로 시작합니다...");
|
||||
|
||||
ExportExcel? _exportExcel = null;
|
||||
var successCount = 0;
|
||||
var failureCount = 0;
|
||||
var totalProcessingTime = 0.0;
|
||||
|
||||
try
|
||||
{
|
||||
_exportExcel = new ExportExcel();
|
||||
LogMessage("📝 Excel 애플리케이션 초기화 중...");
|
||||
LogMessage("✅ Excel 애플리케이션 초기화 완료");
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
var fileStopwatch = Stopwatch.StartNew();
|
||||
|
||||
UpdateStatus($"처리 중: {file.Name} ({i + 1}/{files.Length})");
|
||||
LogMessage($"🔄 [{i + 1}/{files.Length}] 처리 중: {file.Name}");
|
||||
|
||||
try
|
||||
{
|
||||
// 실제 DWG 처리 로직
|
||||
var progress = new Progress<double>(value =>
|
||||
{
|
||||
// 파일별 진행률을 전체 진행률에 반영
|
||||
var overallProgress = ((i * 100.0 + value) / files.Length);
|
||||
progressBar.Value = overallProgress;
|
||||
});
|
||||
|
||||
bool success = _exportExcel.ExportDwgToExcel(file.FullName, progress);
|
||||
|
||||
fileStopwatch.Stop();
|
||||
|
||||
if (success)
|
||||
{
|
||||
successCount++;
|
||||
totalProcessingTime += fileStopwatch.ElapsedMilliseconds;
|
||||
LogMessage($"✅ {file.Name} 처리 완료 ({fileStopwatch.ElapsedMilliseconds}ms)");
|
||||
}
|
||||
else
|
||||
{
|
||||
failureCount++;
|
||||
LogMessage($"❌ {file.Name} 처리 실패 ({fileStopwatch.ElapsedMilliseconds}ms)");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
failureCount++;
|
||||
fileStopwatch.Stop();
|
||||
LogMessage($"💥 {file.Name} 처리 중 예외 발생: {ex.Message}");
|
||||
}
|
||||
|
||||
// 진행률 업데이트
|
||||
progressBar.Value = ((i + 1) * 100.0) / files.Length;
|
||||
|
||||
// UI 응답성을 위한 짧은 지연
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
// Excel 파일 및 매핑 데이터 저장
|
||||
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
var excelFileName = Path.Combine(resultDir, $"{timestamp}_DwgToExcel.xlsx");
|
||||
var mappingDataFile = Path.Combine(resultDir, $"{timestamp}_mapping_data.json");
|
||||
|
||||
LogMessage("💾 Excel 파일과 매핑 데이터를 저장합니다...");
|
||||
|
||||
// 매핑 딕셔너리를 JSON 파일로 저장 (PDF 데이터 병합용)
|
||||
_exportExcel.SaveMappingDictionary(mappingDataFile);
|
||||
LogMessage($"✅ 매핑 데이터 저장 완료: {Path.GetFileName(mappingDataFile)}");
|
||||
|
||||
// Excel 파일 저장
|
||||
_exportExcel.SaveAndCloseExcel(excelFileName);
|
||||
LogMessage($"✅ Excel 파일 저장 완료: {Path.GetFileName(excelFileName)}");
|
||||
|
||||
var elapsed = stopwatch.Elapsed;
|
||||
LogMessage($"✅ Excel 내보내기 완료! 소요시간: {elapsed.TotalSeconds:F1}초");
|
||||
UpdateStatus($"✅ {files.Length}개 파일 처리 완료");
|
||||
LogMessage($"📈 성공: {successCount}개, 실패: {failureCount}개");
|
||||
LogMessage($"⏱️ 평균 처리 시간: {(successCount > 0 ? totalProcessingTime / successCount : 0):F1}ms");
|
||||
|
||||
if (!isAutoProcessing)
|
||||
{
|
||||
ShowMessageBox($"Excel 내보내기가 완료되었습니다!\n\n" +
|
||||
$"✅ 성공: {successCount}개\n" +
|
||||
$"❌ 실패: {failureCount}개\n" +
|
||||
$"⏱️ 총 소요시간: {elapsed:mm\\:ss}\n\n" +
|
||||
$"📄 결과 파일이 저장 폴더에 생성되었습니다.",
|
||||
"완료", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ Excel 처리 중 치명적 오류: {ex.Message}");
|
||||
UpdateStatus("❌ Excel 처리 실패");
|
||||
if (!isAutoProcessing)
|
||||
{
|
||||
ShowMessageBox("Excel 처리 중 오류가 발생했습니다. 로그를 확인해주세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_exportExcel?.Dispose();
|
||||
_exportExcel = null;
|
||||
}
|
||||
}
|
||||
else if (rbDatabase.IsChecked == true)
|
||||
{
|
||||
LogMessage("🗄️ 데이터베이스 모드로 시작합니다...");
|
||||
LogMessage("🔗 데이터베이스 연결을 초기화합니다...");
|
||||
|
||||
SqlDatas? _sqlDatas = null;
|
||||
var successCount = 0;
|
||||
var failureCount = 0;
|
||||
var totalProcessingTime = 0.0;
|
||||
|
||||
try
|
||||
{
|
||||
_sqlDatas = new SqlDatas();
|
||||
LogMessage("✅ 데이터베이스 연결 초기화 완료");
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
var fileStopwatch = Stopwatch.StartNew();
|
||||
|
||||
UpdateStatus($"처리 중: {file.Name} ({i + 1}/{files.Length})");
|
||||
LogMessage($"🔄 [{i + 1}/{files.Length}] 처리 중: {file.Name}");
|
||||
|
||||
try
|
||||
{
|
||||
// 실제 DWG 처리 로직 (DwgToDB는 실패시 true 반환)
|
||||
bool failed = _sqlDatas.DwgToDB(file.FullName);
|
||||
bool success = !failed;
|
||||
|
||||
fileStopwatch.Stop();
|
||||
|
||||
if (success)
|
||||
{
|
||||
successCount++;
|
||||
totalProcessingTime += fileStopwatch.ElapsedMilliseconds;
|
||||
LogMessage($"✅ {file.Name} DB 저장 완료 ({fileStopwatch.ElapsedMilliseconds}ms)");
|
||||
}
|
||||
else
|
||||
{
|
||||
failureCount++;
|
||||
LogMessage($"❌ {file.Name} DB 저장 실패 ({fileStopwatch.ElapsedMilliseconds}ms)");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
failureCount++;
|
||||
fileStopwatch.Stop();
|
||||
LogMessage($"💥 {file.Name} 처리 중 예외 발생: {ex.Message}");
|
||||
}
|
||||
|
||||
// 진행률 업데이트
|
||||
progressBar.Value = ((i + 1) * 100.0) / files.Length;
|
||||
|
||||
// UI 응답성을 위한 짧은 지연
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
var elapsed = stopwatch.Elapsed;
|
||||
LogMessage($"✅ 데이터베이스 저장 완료! 소요시간: {elapsed.TotalSeconds:F1}초");
|
||||
UpdateStatus($"✅ {files.Length}개 파일 처리 완료");
|
||||
LogMessage($"📈 성공: {successCount}개, 실패: {failureCount}개");
|
||||
LogMessage($"⏱️ 평균 처리 시간: {(successCount > 0 ? totalProcessingTime / successCount : 0):F1}ms");
|
||||
|
||||
if (!isAutoProcessing)
|
||||
{
|
||||
ShowMessageBox($"데이터베이스 저장이 완료되었습니다!\n\n" +
|
||||
$"✅ 성공: {successCount}개\n" +
|
||||
$"❌ 실패: {failureCount}개\n" +
|
||||
$"⏱️ 총 소요시간: {elapsed:mm\\:ss}",
|
||||
"완료", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ 데이터베이스 처리 중 치명적 오류: {ex.Message}");
|
||||
UpdateStatus("❌ 데이터베이스 처리 실패");
|
||||
if (!isAutoProcessing)
|
||||
{
|
||||
ShowMessageBox("데이터베이스 처리 중 오류가 발생했습니다. 로그를 확인해주세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sqlDatas?.Dispose();
|
||||
_sqlDatas = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ 처리 중 오류 발생: {ex.Message}");
|
||||
UpdateStatus("❌ 처리 실패");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG 파일 처리 - 기존 메서드
|
||||
/// </summary>
|
||||
private async Task ProcessFiles()
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
@@ -254,8 +544,7 @@ namespace DwgExtractorManual
|
||||
if (files.Length == 0)
|
||||
{
|
||||
UpdateStatus("선택한 폴더에 DWG 파일이 없습니다.");
|
||||
System.Windows.MessageBox.Show("선택한 폴더에 DWG 파일이 없습니다.",
|
||||
"정보", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
ShowMessageBox("선택한 폴더에 DWG 파일이 없습니다.", "정보", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -356,6 +645,22 @@ namespace DwgExtractorManual
|
||||
// Excel 파일 저장
|
||||
_exportExcel.SaveAndCloseExcel(excelFileName);
|
||||
LogMessage($"✅ Excel 파일 저장 완료: {Path.GetFileName(excelFileName)}");
|
||||
|
||||
|
||||
LogMessage($"✅ Excel 내보내기 완료!");
|
||||
UpdateStatus($"✅ {files.Length}개 파일 처리 완료");
|
||||
LogMessage($"📈 성공: {successCount}개, 실패: {failureCount}개");
|
||||
LogMessage($"⏱️ 평균 처리 시간: {(successCount > 0 ? totalProcessingTime / successCount : 0):F1}ms");
|
||||
|
||||
if (!isAutoProcessing)
|
||||
{
|
||||
ShowMessageBox($"Excel 내보내기가 완료되었습니다!\n\n" +
|
||||
$"✅ 성공: {successCount}개\n" +
|
||||
$"❌ 실패: {failureCount}개\n" +
|
||||
$"✅ Excel 내보내기 완료!" +
|
||||
$"📄 결과 파일이 저장 폴더에 생성되었습니다.",
|
||||
"완료", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -376,7 +681,7 @@ namespace DwgExtractorManual
|
||||
LogMessage($"⏱️ 평균 처리 시간: {(successCount > 0 ? totalProcessingTime / successCount : 0):F1}ms");
|
||||
LogMessage($"🕐 총 소요 시간: {totalStopwatch.ElapsedMilliseconds}ms");
|
||||
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
$"Excel 내보내기가 완료되었습니다!\n\n" +
|
||||
$"✅ 성공: {successCount}개\n" +
|
||||
$"❌ 실패: {failureCount}개\n" +
|
||||
@@ -461,7 +766,7 @@ namespace DwgExtractorManual
|
||||
LogMessage($"⏱️ 평균 처리 시간: {(successCount > 0 ? totalProcessingTime / successCount : 0):F1}ms");
|
||||
LogMessage($"🕐 총 소요 시간: {totalStopwatch.ElapsedMilliseconds}ms");
|
||||
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
$"데이터베이스 내보내기가 완료되었습니다!\n\n" +
|
||||
$"✅ 성공: {successCount}개\n" +
|
||||
$"❌ 실패: {failureCount}개\n" +
|
||||
@@ -475,15 +780,13 @@ namespace DwgExtractorManual
|
||||
// 입력 유효성 검사
|
||||
if (string.IsNullOrEmpty(txtSourceFolder.Text) || !Directory.Exists(txtSourceFolder.Text))
|
||||
{
|
||||
System.Windows.MessageBox.Show("유효한 변환할 폴더를 선택하세요.", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
ShowMessageBox("유효한 변환할 폴더를 선택하세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(txtResultFolder.Text) || !Directory.Exists(txtResultFolder.Text))
|
||||
{
|
||||
System.Windows.MessageBox.Show("유효한 결과 저장 폴더를 선택하세요.", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
ShowMessageBox("유효한 결과 저장 폴더를 선택하세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -493,8 +796,7 @@ namespace DwgExtractorManual
|
||||
|
||||
if (pdfFiles.Length == 0)
|
||||
{
|
||||
System.Windows.MessageBox.Show("선택한 폴더에 PDF 파일이 없습니다.", "정보",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
ShowMessageBox("선택한 폴더에 PDF 파일이 없습니다.", "정보", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -502,6 +804,7 @@ namespace DwgExtractorManual
|
||||
btnExtract.IsEnabled = false;
|
||||
btnPdfExtract.IsEnabled = false;
|
||||
btnMerge.IsEnabled = false;
|
||||
btnAuto.IsEnabled = false;
|
||||
btnBrowseSource.IsEnabled = false;
|
||||
btnBrowseResult.IsEnabled = false;
|
||||
rbExcel.IsEnabled = false;
|
||||
@@ -521,8 +824,7 @@ namespace DwgExtractorManual
|
||||
{
|
||||
LogMessage($"❌ PDF 추출 중 치명적 오류 발생: {ex.Message}");
|
||||
UpdateStatus("PDF 추출 중 오류가 발생했습니다.");
|
||||
System.Windows.MessageBox.Show($"PDF 추출 중 오류가 발생했습니다:\n\n{ex.Message}",
|
||||
"오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
ShowMessageBox($"PDF 추출 중 오류가 발생했습니다:\n\n{ex.Message}", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -530,6 +832,7 @@ namespace DwgExtractorManual
|
||||
btnExtract.IsEnabled = true;
|
||||
btnPdfExtract.IsEnabled = true;
|
||||
btnMerge.IsEnabled = true;
|
||||
btnAuto.IsEnabled = true;
|
||||
btnBrowseSource.IsEnabled = true;
|
||||
btnBrowseResult.IsEnabled = true;
|
||||
rbExcel.IsEnabled = true;
|
||||
@@ -579,7 +882,7 @@ namespace DwgExtractorManual
|
||||
$"--include-errors {includeErrors.ToString().ToLower()} " +
|
||||
$"--output \"{outputPath}\"";
|
||||
|
||||
LogMessage($"🐍 Python 스크립트 실행 준비...");
|
||||
LogMessage("🐍 Python 스크립트 실행 준비...");
|
||||
LogMessage($"📁 Python 경로: {pythonPath}");
|
||||
LogMessage($"📁 스크립트 경로: {scriptPath}");
|
||||
LogMessage($"📄 파일 리스트: {Path.GetFileName(tempFileList)}");
|
||||
@@ -648,7 +951,7 @@ namespace DwgExtractorManual
|
||||
// 자동 Excel 매핑 업데이트 (새로운 효율적 방식)
|
||||
await AutoUpdateExcelMappingWithPdfResults(outputPath);
|
||||
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
$"PDF 추출이 완료되었습니다!\n\n" +
|
||||
$"📄 처리된 파일: {pdfFiles.Length}개\n" +
|
||||
$"⏱️ 총 소요시간: {stopwatch.Elapsed:mm\\:ss}\n\n" +
|
||||
@@ -996,8 +1299,7 @@ namespace DwgExtractorManual
|
||||
// 입력 유효성 검사
|
||||
if (string.IsNullOrEmpty(txtResultFolder.Text) || !Directory.Exists(txtResultFolder.Text))
|
||||
{
|
||||
System.Windows.MessageBox.Show("유효한 결과 저장 폴더를 선택하세요.", "오류",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
ShowMessageBox("유효한 결과 저장 폴더를 선택하세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1005,6 +1307,7 @@ namespace DwgExtractorManual
|
||||
btnExtract.IsEnabled = false;
|
||||
btnPdfExtract.IsEnabled = false;
|
||||
btnMerge.IsEnabled = false;
|
||||
btnAuto.IsEnabled = false;
|
||||
btnBrowseSource.IsEnabled = false;
|
||||
btnBrowseResult.IsEnabled = false;
|
||||
rbExcel.IsEnabled = false;
|
||||
@@ -1024,8 +1327,7 @@ namespace DwgExtractorManual
|
||||
{
|
||||
LogMessage($"❌ 매핑 병합 중 치명적 오류 발생: {ex.Message}");
|
||||
UpdateStatus("매핑 병합 중 오류가 발생했습니다.");
|
||||
System.Windows.MessageBox.Show($"매핑 병합 중 오류가 발생했습니다:\n\n{ex.Message}",
|
||||
"오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
ShowMessageBox($"매핑 병합 중 오류가 발생했습니다:\n\n{ex.Message}", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -1033,6 +1335,7 @@ namespace DwgExtractorManual
|
||||
btnExtract.IsEnabled = true;
|
||||
btnPdfExtract.IsEnabled = true;
|
||||
btnMerge.IsEnabled = true;
|
||||
btnAuto.IsEnabled = true;
|
||||
btnBrowseSource.IsEnabled = true;
|
||||
btnBrowseResult.IsEnabled = true;
|
||||
rbExcel.IsEnabled = true;
|
||||
@@ -1065,7 +1368,7 @@ namespace DwgExtractorManual
|
||||
LogMessage("❌ PDF 추출 JSON 파일을 찾을 수 없습니다.");
|
||||
LogMessage("💡 먼저 'PDF 추출' 버튼을 실행하여 JSON 파일을 생성하세요.");
|
||||
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
"PDF 추출 JSON 파일을 찾을 수 없습니다.\n\n" +
|
||||
"먼저 'PDF 추출' 버튼을 실행하여 JSON 파일을 생성하세요.",
|
||||
"파일 없음", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
@@ -1082,7 +1385,7 @@ namespace DwgExtractorManual
|
||||
LogMessage("❌ 매핑 데이터 파일을 찾을 수 없습니다.");
|
||||
LogMessage("💡 먼저 'DWG 정보 추출' 버튼을 실행하여 매핑 데이터를 생성하세요.");
|
||||
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
"매핑 데이터 파일을 찾을 수 없습니다.\n\n" +
|
||||
"먼저 'DWG 정보 추출' 버튼을 실행하여 매핑 데이터를 생성하세요.",
|
||||
"파일 없음", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
@@ -1100,15 +1403,13 @@ namespace DwgExtractorManual
|
||||
await ShowJsonPreview(latestJsonFile);
|
||||
|
||||
// 사용자 확인
|
||||
var result = System.Windows.MessageBox.Show(
|
||||
var result = ShowConfirmationDialog(
|
||||
$"다음 파일들로 Excel 매핑을 업데이트하시겠습니까?\n\n" +
|
||||
$"📄 PDF JSON: {Path.GetFileName(latestJsonFile)}\n" +
|
||||
$"📊 매핑 데이터: {Path.GetFileName(latestMappingDataFile)}\n" +
|
||||
$"📅 생성: {File.GetCreationTime(latestJsonFile):yyyy-MM-dd HH:mm:ss}\n" +
|
||||
$"📏 크기: {new FileInfo(latestJsonFile).Length / 1024:N0} KB",
|
||||
"매핑 업데이트 확인",
|
||||
MessageBoxButton.YesNo,
|
||||
MessageBoxImage.Question);
|
||||
"매핑 업데이트 확인");
|
||||
|
||||
if (result != MessageBoxResult.Yes)
|
||||
{
|
||||
@@ -1165,7 +1466,7 @@ namespace DwgExtractorManual
|
||||
LogMessage($"✅ Excel 매핑 병합 완료: {Path.GetFileName(completeExcelPath)}");
|
||||
LogMessage("📊 DWG 값과 PDF 값이 모두 포함된 통합 Excel 파일이 생성되었습니다.");
|
||||
|
||||
System.Windows.MessageBox.Show(
|
||||
ShowMessageBox(
|
||||
$"Excel 매핑 병합이 완료되었습니다!\n\n" +
|
||||
$"📄 사용된 JSON: {Path.GetFileName(latestJsonFile)}\n" +
|
||||
$"📊 생성된 파일: {Path.GetFileName(completeExcelPath)}\n" +
|
||||
@@ -1254,6 +1555,302 @@ namespace DwgExtractorManual
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 자동 처리 버튼 클릭 이벤트
|
||||
/// </summary>
|
||||
private async void BtnAuto_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 입력 검증
|
||||
if (string.IsNullOrEmpty(txtSourceFolder.Text))
|
||||
{
|
||||
ShowMessageBox("소스 폴더를 선택해주세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(txtResultFolder.Text))
|
||||
{
|
||||
ShowMessageBox("결과 저장 폴더를 선택해주세요.", "오류", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
string rootFolder = txtSourceFolder.Text;
|
||||
string resultFolder = txtResultFolder.Text;
|
||||
|
||||
if (!Directory.Exists(rootFolder))
|
||||
{
|
||||
ShowMessageBox("소스 폴더가 존재하지 않습니다.", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(resultFolder))
|
||||
{
|
||||
ShowMessageBox("결과 저장 폴더가 존재하지 않습니다.", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 리프 폴더들 찾기
|
||||
LogMessage("🔍 리프 폴더 검색 중...");
|
||||
var leafFolders = FindLeafFolders(rootFolder);
|
||||
|
||||
if (leafFolders.Count == 0)
|
||||
{
|
||||
ShowMessageBox("처리할 리프 폴더가 없습니다.", "정보", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
LogMessage($"📁 발견된 리프 폴더: {leafFolders.Count}개");
|
||||
foreach (var folder in leafFolders)
|
||||
{
|
||||
LogMessage($" └─ {folder}");
|
||||
}
|
||||
|
||||
// 사용자 확인
|
||||
var result = ShowConfirmationDialog(
|
||||
$"총 {leafFolders.Count}개의 리프 폴더를 자동 처리하시겠습니까?\n\n" +
|
||||
"각 폴더마다 DWG 추출 → PDF 추출 → 합치기가 순차적으로 실행됩니다.",
|
||||
"자동 처리 확인");
|
||||
|
||||
if (result != MessageBoxResult.Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// UI 상태 변경
|
||||
SetButtonsEnabled(false);
|
||||
progressBar.Value = 0;
|
||||
UpdateStatus("🤖 자동 처리 시작...");
|
||||
|
||||
// 자동 처리 모드 활성화
|
||||
isAutoProcessing = true;
|
||||
|
||||
await ProcessLeafFoldersAutomatically(leafFolders, resultFolder);
|
||||
|
||||
ShowMessageBox(
|
||||
$"자동 처리가 완료되었습니다!\n\n" +
|
||||
$"처리된 폴더: {leafFolders.Count}개\n" +
|
||||
$"결과 저장 위치: {resultFolder}",
|
||||
"완료",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ 자동 처리 중 오류: {ex.Message}");
|
||||
ShowMessageBox($"자동 처리 중 오류가 발생했습니다:\n{ex.Message}", "오류", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetButtonsEnabled(true);
|
||||
progressBar.Value = 0;
|
||||
UpdateStatus("✅ 준비");
|
||||
|
||||
// 자동 처리 모드 비활성화
|
||||
isAutoProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 폴더에서 리프 폴더들(하위 폴더가 없는 폴더)을 재귀적으로 찾습니다.
|
||||
/// </summary>
|
||||
/// <param name="rootPath">루트 폴더 경로</param>
|
||||
/// <returns>리프 폴더 경로 목록</returns>
|
||||
private List<string> FindLeafFolders(string rootPath)
|
||||
{
|
||||
var leafFolders = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
FindLeafFoldersRecursive(rootPath, leafFolders);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ 리프 폴더 검색 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
return leafFolders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 재귀적으로 리프 폴더를 찾는 헬퍼 메서드
|
||||
/// </summary>
|
||||
/// <param name="currentPath">현재 폴더 경로</param>
|
||||
/// <param name="leafFolders">리프 폴더 목록</param>
|
||||
private void FindLeafFoldersRecursive(string currentPath, List<string> leafFolders)
|
||||
{
|
||||
try
|
||||
{
|
||||
var subDirectories = Directory.GetDirectories(currentPath);
|
||||
|
||||
if (subDirectories.Length == 0)
|
||||
{
|
||||
// 하위 폴더가 없으면 리프 폴더
|
||||
leafFolders.Add(currentPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 하위 폴더가 있으면 재귀 호출
|
||||
foreach (var subDir in subDirectories)
|
||||
{
|
||||
FindLeafFoldersRecursive(subDir, leafFolders);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
LogMessage($"⚠️ 접근 권한 없음: {currentPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ 폴더 처리 중 오류 ({currentPath}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 리프 폴더들을 자동으로 처리합니다.
|
||||
/// </summary>
|
||||
/// <param name="leafFolders">처리할 리프 폴더 목록</param>
|
||||
/// <param name="resultBaseFolder">결과 저장 기본 폴더</param>
|
||||
private async Task ProcessLeafFoldersAutomatically(List<string> leafFolders, string resultBaseFolder)
|
||||
{
|
||||
int totalFolders = leafFolders.Count;
|
||||
int currentFolderIndex = 0;
|
||||
|
||||
foreach (var leafFolder in leafFolders)
|
||||
{
|
||||
currentFolderIndex++;
|
||||
try
|
||||
{
|
||||
LogMessage($"📁 [{currentFolderIndex}/{totalFolders}] 처리 시작: {leafFolder}");
|
||||
|
||||
// 폴더 경로를 파일명으로 변환 (경로 구분자를 '_'로 변경)
|
||||
string rootFolderPath = txtSourceFolder.Text.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
string relativePath = Path.GetRelativePath(rootFolderPath, leafFolder);
|
||||
string excelFileName = relativePath.Replace(Path.DirectorySeparatorChar, '_').Replace(Path.AltDirectorySeparatorChar, '_') + ".xlsx";
|
||||
string excelFilePath = Path.Combine(resultBaseFolder, excelFileName);
|
||||
|
||||
// 진행률 업데이트
|
||||
double baseProgress = ((double)(currentFolderIndex - 1) / totalFolders) * 100;
|
||||
progressBar.Value = baseProgress;
|
||||
|
||||
// 1. DWG 추출
|
||||
LogMessage($"🔧 [{currentFolderIndex}/{totalFolders}] DWG 추출 시작...");
|
||||
UpdateStatus($"🔧 DWG 추출 중... ({currentFolderIndex}/{totalFolders})");
|
||||
|
||||
await ProcessFiles(leafFolder);
|
||||
|
||||
progressBar.Value = baseProgress + (100.0 / totalFolders) * 0.33;
|
||||
LogMessage($"✅ [{currentFolderIndex}/{totalFolders}] DWG 추출 완료");
|
||||
|
||||
// 2초 대기 (원래 타이밍 복원 - 싱글톤 Services로 충돌 해결됨)
|
||||
await Task.Delay(2000);
|
||||
|
||||
// 2. PDF 추출
|
||||
LogMessage($"📄 [{currentFolderIndex}/{totalFolders}] PDF 추출 시작...");
|
||||
UpdateStatus($"📄 PDF 추출 중... ({currentFolderIndex}/{totalFolders})");
|
||||
|
||||
// 현재 폴더에서 PDF 파일 찾기
|
||||
var pdfFiles = new DirectoryInfo(leafFolder)
|
||||
.GetFiles("*.pdf", SearchOption.AllDirectories)
|
||||
.ToArray();
|
||||
|
||||
if (pdfFiles.Length == 0)
|
||||
{
|
||||
LogMessage($"⚠️ [{currentFolderIndex}/{totalFolders}] PDF 파일이 없음 - PDF 추출 건너뜀");
|
||||
}
|
||||
else
|
||||
{
|
||||
await ProcessPdfFiles(pdfFiles);
|
||||
}
|
||||
|
||||
progressBar.Value = baseProgress + (100.0 / totalFolders) * 0.66;
|
||||
LogMessage($"✅ [{currentFolderIndex}/{totalFolders}] PDF 추출 완료");
|
||||
|
||||
// 3초 대기
|
||||
await Task.Delay(3000);
|
||||
|
||||
// 3. 합치기 및 Excel 파일 이름 변경
|
||||
LogMessage($"🔗 [{currentFolderIndex}/{totalFolders}] 합치기 시작...");
|
||||
UpdateStatus($"🔗 합치기 중... ({currentFolderIndex}/{totalFolders})");
|
||||
|
||||
await MergeLatestPdfResults();
|
||||
|
||||
// 생성된 Excel 파일을 목표 이름으로 변경
|
||||
await RenameLatestExcelFile(resultBaseFolder, excelFilePath);
|
||||
|
||||
progressBar.Value = baseProgress + (100.0 / totalFolders);
|
||||
LogMessage($"✅ [{currentFolderIndex}/{totalFolders}] 처리 완료: {excelFileName}");
|
||||
|
||||
// 2초 대기 후 다음 폴더 처리
|
||||
if (currentFolderIndex < totalFolders)
|
||||
{
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"❌ [{currentFolderIndex}/{totalFolders}] 폴더 처리 실패 ({leafFolder}): {ex.Message}");
|
||||
LogMessage($"⏭️ [{currentFolderIndex}/{totalFolders}] 다음 폴더로 계속 진행");
|
||||
|
||||
// 오류 발생 시 잠시 대기 후 다음 폴더 처리
|
||||
await Task.Delay(2000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LogMessage($"🎉 자동 처리 완료! 총 {totalFolders}개 폴더 처리됨");
|
||||
UpdateStatus("✅ 자동 처리 완료");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 최신 Excel 파일을 목표 경로로 이름 변경
|
||||
/// </summary>
|
||||
/// <param name="resultFolder">결과 폴더</param>
|
||||
/// <param name="targetPath">목표 파일 경로</param>
|
||||
private async Task RenameLatestExcelFile(string resultFolder, string targetPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 최신 *_Complete_Mapping_Merged.xlsx 파일 찾기
|
||||
var excelFiles = Directory.GetFiles(resultFolder, "*_Complete_Mapping_Merged.xlsx")
|
||||
.Where(f => !Path.GetFileName(f).StartsWith("~$"))
|
||||
.OrderByDescending(f => File.GetCreationTime(f))
|
||||
.ToList();
|
||||
|
||||
if (excelFiles.Any())
|
||||
{
|
||||
string latestFile = excelFiles.First();
|
||||
|
||||
// 목표 파일이 이미 존재하면 삭제
|
||||
if (File.Exists(targetPath))
|
||||
{
|
||||
File.Delete(targetPath);
|
||||
}
|
||||
|
||||
// 파일 이름 변경
|
||||
File.Move(latestFile, targetPath);
|
||||
LogMessage($"📋 Excel 파일 이름 변경됨: {Path.GetFileName(targetPath)}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"⚠️ Excel 파일 이름 변경 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 버튼들의 활성화 상태를 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="enabled">활성화 여부</param>
|
||||
private void SetButtonsEnabled(bool enabled)
|
||||
{
|
||||
btnExtract.IsEnabled = enabled;
|
||||
btnPdfExtract.IsEnabled = enabled;
|
||||
btnMerge.IsEnabled = enabled;
|
||||
btnAuto.IsEnabled = enabled;
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
_timer?.Stop();
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace DwgExtractorManual.Models
|
||||
/// </summary>
|
||||
internal class ExportExcel : IDisposable
|
||||
{
|
||||
// ODA 서비스 객체
|
||||
// ODA 서비스 객체 (managed by singleton)
|
||||
private Services appServices;
|
||||
|
||||
// Excel COM 객체들
|
||||
@@ -72,7 +72,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
Debug.WriteLine("🔄 ODA 초기화 중...");
|
||||
ActivateAndInitializeODA();
|
||||
InitializeTeighaServices();
|
||||
Debug.WriteLine("🔄 Excel 초기화 중...");
|
||||
InitializeExcel();
|
||||
}
|
||||
@@ -93,13 +93,20 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
}
|
||||
|
||||
// ODA 제품 활성화 및 초기화
|
||||
private void ActivateAndInitializeODA()
|
||||
// Teigha 서비스 초기화 (싱글톤 사용)
|
||||
private void InitializeTeighaServices()
|
||||
{
|
||||
var userInfo = "c2FtYW4gZW5naW5lZXJpbmc=";
|
||||
var userSignature = "F0kuQTmtVpHtvl/TgaFVGE92/YqGmYR9SLoXckEjnOk8NoAQh7Sg6GQruVC04JqD4C/IipxJYqpqvMfMc2auRMG+cAJCKqKUE2djIMdkUdb+C5IVx2c97fcK5ba3n8DDvB54Upokajl+6j12yD8h8MKGOR3Z3zysObeXD62bFpQgp00GCYTqlxEZtTIRjHIPAfJfix8Y0jtXWWYyVJ3LYOu86as5xtx+hY1aakpYIJiQk/6pGd84qSn/9K1w8nxR7UrFzieDeQ/xM58BHSD4u/ZxVJwvv6Uy10tsdBFBTvfJMAFp05Y7yeyeCNr100tA3iOfmWoXAVRHfxnkPfiYR54aK04QI+R6OGkI+yd1oR5BtmN6BdDt3z8KYK5EpFGJGiJIGoUy5PvkYdJ2VV6xe9JWBiIJuI/tDn1Y+uyTQFA9qaDHnOURriXsRGfy8reDPf1eejybSJxWKkpilG6RXhq3xHlCkjZzh1Q45S+xYXNGatcWMm9nkn20M8Ke5JEVaI9w/p2GE36CHRtRQbt8kfPmsbWNXJCFr4svHW2MPbCKWoyn5XEyMWBnuAKi74zvczB13DKjf29SqSIgF5k/hwy2QrgvnaKzY1k8bw8w2/k0vJXcS3GKOB/ZYDle1tf/lkAD1HtnF9zE18TiXhVnqwAVjwg4ui1RPLn/LMs6b5Y=";
|
||||
Services.odActivate(userInfo, userSignature);
|
||||
appServices = new Services();
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[DEBUG] TeighaServicesManager를 통한 Services 획득 중...");
|
||||
appServices = TeighaServicesManager.Instance.AcquireServices();
|
||||
Debug.WriteLine($"[DEBUG] Services 획득 성공. Reference Count: {TeighaServicesManager.Instance.ReferenceCount}");
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Teigha Services 초기화 실패: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Excel 애플리케이션 및 워크시트 초기화
|
||||
@@ -603,14 +610,31 @@ namespace DwgExtractorManual.Models
|
||||
return false;
|
||||
}
|
||||
|
||||
// JSON 파일 읽기
|
||||
string jsonContent = File.ReadAllText(jsonFilePath);
|
||||
JObject jsonData = JObject.Parse(jsonContent);
|
||||
// JSON 파일 읽기 및 정리
|
||||
string jsonContent = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
|
||||
Debug.WriteLine($"[DEBUG] JSON 파일 크기: {jsonContent.Length} bytes");
|
||||
|
||||
// JSON 내용 정리 (주석 제거 등)
|
||||
jsonContent = CleanJsonContent(jsonContent);
|
||||
|
||||
JObject jsonData;
|
||||
try
|
||||
{
|
||||
jsonData = JObject.Parse(jsonContent);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonReaderException jsonEx)
|
||||
{
|
||||
Debug.WriteLine($"❌ JSON 파싱 오류: {jsonEx.Message}");
|
||||
Debug.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
|
||||
Debug.WriteLine(jsonContent.Length > 500 ? jsonContent.Substring(0, 500) + "..." : jsonContent);
|
||||
throw new System.Exception($"PDF 분석 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {jsonFilePath}");
|
||||
}
|
||||
|
||||
var results = jsonData["results"] as JArray;
|
||||
if (results == null)
|
||||
{
|
||||
Debug.WriteLine("❌ JSON에서 'results' 배열을 찾을 수 없습니다.");
|
||||
Debug.WriteLine($"❌ JSON 루트 키들: {string.Join(", ", jsonData.Properties().Select(p => p.Name))}");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1032,7 +1056,21 @@ namespace DwgExtractorManual.Models
|
||||
string jsonContent = File.ReadAllText(filePath, System.Text.Encoding.UTF8);
|
||||
Debug.WriteLine($"[DEBUG] JSON 내용 길이: {jsonContent.Length}");
|
||||
|
||||
var deserializedData = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, JObject>>>(jsonContent);
|
||||
// JSON 내용 정리 (주석 제거 등)
|
||||
jsonContent = CleanJsonContent(jsonContent);
|
||||
|
||||
Dictionary<string, Dictionary<string, JObject>> deserializedData;
|
||||
try
|
||||
{
|
||||
deserializedData = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, JObject>>>(jsonContent);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonReaderException jsonEx)
|
||||
{
|
||||
Debug.WriteLine($"❌ JSON 파싱 오류: {jsonEx.Message}");
|
||||
Debug.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
|
||||
Debug.WriteLine(jsonContent.Length > 500 ? jsonContent.Substring(0, 500) + "..." : jsonContent);
|
||||
throw new System.Exception($"매핑 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {filePath}");
|
||||
}
|
||||
|
||||
// 새로운 딕셔너리 초기화
|
||||
FileToMapkeyToLabelTagValuePdf.Clear();
|
||||
@@ -1146,14 +1184,31 @@ namespace DwgExtractorManual.Models
|
||||
return;
|
||||
}
|
||||
|
||||
// JSON 파일 읽기
|
||||
string jsonContent = File.ReadAllText(jsonFilePath);
|
||||
JObject jsonData = JObject.Parse(jsonContent);
|
||||
// JSON 파일 읽기 및 정리
|
||||
string jsonContent = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
|
||||
Debug.WriteLine($"[DEBUG] JSON 파일 크기: {jsonContent.Length} bytes");
|
||||
|
||||
// JSON 내용 정리 (주석 제거 등)
|
||||
jsonContent = CleanJsonContent(jsonContent);
|
||||
|
||||
JObject jsonData;
|
||||
try
|
||||
{
|
||||
jsonData = JObject.Parse(jsonContent);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonReaderException jsonEx)
|
||||
{
|
||||
Debug.WriteLine($"❌ JSON 파싱 오류: {jsonEx.Message}");
|
||||
Debug.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
|
||||
Debug.WriteLine(jsonContent.Length > 500 ? jsonContent.Substring(0, 500) + "..." : jsonContent);
|
||||
throw new System.Exception($"PDF 분석 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {jsonFilePath}");
|
||||
}
|
||||
|
||||
var results = jsonData["results"] as JArray;
|
||||
if (results == null)
|
||||
{
|
||||
Debug.WriteLine("❌ JSON에서 'results' 배열을 찾을 수 없습니다.");
|
||||
Debug.WriteLine($"❌ JSON 루트 키들: {string.Join(", ", jsonData.Properties().Select(p => p.Name))}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1229,18 +1284,159 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JSON 내용을 정리하여 파싱 가능한 상태로 만듭니다.
|
||||
/// 주석 제거 및 기타 무효한 문자 처리
|
||||
/// </summary>
|
||||
/// <param name="jsonContent">원본 JSON 내용</param>
|
||||
/// <returns>정리된 JSON 내용</returns>
|
||||
private string CleanJsonContent(string jsonContent)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonContent))
|
||||
return jsonContent;
|
||||
|
||||
try
|
||||
{
|
||||
// 줄별로 처리하여 주석 제거
|
||||
var lines = jsonContent.Split('\n');
|
||||
var cleanedLines = new List<string>();
|
||||
|
||||
bool inMultiLineComment = false;
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string processedLine = line;
|
||||
|
||||
// 멀티라인 주석 처리 (/* */)
|
||||
if (inMultiLineComment)
|
||||
{
|
||||
int endIndex = processedLine.IndexOf("*/");
|
||||
if (endIndex >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(endIndex + 2);
|
||||
inMultiLineComment = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // 전체 라인이 주석
|
||||
}
|
||||
}
|
||||
|
||||
// 멀티라인 주석 시작 확인
|
||||
int multiLineStart = processedLine.IndexOf("/*");
|
||||
if (multiLineStart >= 0)
|
||||
{
|
||||
int multiLineEnd = processedLine.IndexOf("*/", multiLineStart + 2);
|
||||
if (multiLineEnd >= 0)
|
||||
{
|
||||
// 같은 라인에서 시작하고 끝나는 주석
|
||||
processedLine = processedLine.Substring(0, multiLineStart) +
|
||||
processedLine.Substring(multiLineEnd + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 멀티라인 주석 시작
|
||||
processedLine = processedLine.Substring(0, multiLineStart);
|
||||
inMultiLineComment = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 싱글라인 주석 제거 (//) - 문자열 내부의 //는 제외
|
||||
bool inString = false;
|
||||
bool escaped = false;
|
||||
int commentIndex = -1;
|
||||
|
||||
for (int i = 0; i < processedLine.Length - 1; i++)
|
||||
{
|
||||
char current = processedLine[i];
|
||||
char next = processedLine[i + 1];
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == '\\')
|
||||
{
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == '"')
|
||||
{
|
||||
inString = !inString;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inString && current == '/' && next == '/')
|
||||
{
|
||||
commentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (commentIndex >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(0, commentIndex);
|
||||
}
|
||||
|
||||
// 빈 라인이 아니면 추가
|
||||
if (!string.IsNullOrWhiteSpace(processedLine))
|
||||
{
|
||||
cleanedLines.Add(processedLine);
|
||||
}
|
||||
}
|
||||
|
||||
string result = string.Join("\n", cleanedLines);
|
||||
Debug.WriteLine($"[DEBUG] JSON 정리 완료: {jsonContent.Length} -> {result.Length} bytes");
|
||||
return result;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"❌ JSON 정리 중 오류: {ex.Message}");
|
||||
// 정리 실패시 원본 반환
|
||||
return jsonContent;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[DEBUG] ExportExcel Dispose 시작");
|
||||
|
||||
if (excelApplication != null)
|
||||
{
|
||||
Debug.WriteLine("[DEBUG] Excel 객체 정리 중...");
|
||||
CloseExcelObjects();
|
||||
}
|
||||
|
||||
if (appServices != null)
|
||||
{
|
||||
appServices.Dispose();
|
||||
Debug.WriteLine("[DEBUG] Teigha Services 해제 중...");
|
||||
try
|
||||
{
|
||||
TeighaServicesManager.Instance.ReleaseServices();
|
||||
Debug.WriteLine($"[DEBUG] Teigha Services 해제 완료. Remaining ref count: {TeighaServicesManager.Instance.ReferenceCount}");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Teigha Services 해제 중 오류 (무시됨): {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
appServices = null;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine("[DEBUG] ExportExcel Dispose 완료");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] ExportExcel Dispose 중 전역 오류: {ex.Message}");
|
||||
// Disposal 오류는 로그만 남기고 계속 진행
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,22 @@ namespace DwgExtractorManual.Models
|
||||
/// </summary>
|
||||
internal sealed class SqlDatas : IDisposable
|
||||
{
|
||||
Services appServices; // ODA 제품 활성화용
|
||||
Services appServices; // ODA 제품 활성화용 (managed by singleton)
|
||||
readonly string connectionString = "Host=localhost;Database=postgres;Username=postgres;Password=Qwer1234";
|
||||
|
||||
void ActivateAndInitializeODA()
|
||||
void InitializeTeighaServices()
|
||||
{
|
||||
var userInfo = "c2FtYW4gZW5naW5lZXJpbmc=";
|
||||
var userSignature = "F0kuQTmtVpHtvl/TgaFVGE92/YqGmYR9SLoXckEjnOk8NoAQh7Sg6GQruVC04JqD4C/IipxJYqpqvMfMc2auRMG+cAJCKqKUE2djIMdkUdb+C5IVx2c97fcK5ba3n8DDvB54Upokajl+6j12yD8h8MKGOR3Z3zysObeXD62bFpQgp00GCYTqlxEZtTIRjHIPAfJfix8Y0jtXWWYyVJ3LYOu86as5xtx+hY1aakpYIJiQk/6pGd84qSn/9K1w8nxR7UrFzieDeQ/xM58BHSD4u/ZxVJwvv6Uy10tsdBFBTvfJMAFp05Y7yeyeCNr100tA3iOfmWoXAVRHfxnkPfiYR54aK04QI+R6OGkI+yd1oR5BtmN6BdDt3z8KYK5EpFGJGiJIGoUy5PvkYdJ2VV6xe9JWBiIJuI/tDn1Y+uyTQFA9qaDHnOURriXsRGfy8reDPf1eejybSJxWKkpilG6RXhq3xHlCkjZzh1Q45S+xYXNGatcWMm9nkn20M8Ke5JEVaI9w/p2GE36CHRtRQbt8kfPmsbWNXJCFr4svHW2MPbCKWoyn5XEyMWBnuAKi74zvczB13DKjf29SqSIgF5k/hwy2QrgvnaKzY1k8bw8w2/k0vJXcS3GKOB/ZYDle1tf/lkAD1HtnF9zE18TiXhVnqwAVjwg4ui1RPLn/LMs6b5Y=";
|
||||
Services.odActivate(userInfo, userSignature);
|
||||
appServices = new Services();
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[SqlDatas] TeighaServicesManager를 통한 Services 획득 중...");
|
||||
appServices = TeighaServicesManager.Instance.AcquireServices();
|
||||
Debug.WriteLine($"[SqlDatas] Services 획득 성공. Reference Count: {TeighaServicesManager.Instance.ReferenceCount}");
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[SqlDatas] Teigha Services 초기화 실패: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateTables()
|
||||
@@ -78,7 +85,7 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
public SqlDatas()
|
||||
{
|
||||
ActivateAndInitializeODA();
|
||||
InitializeTeighaServices();
|
||||
CreateTables();
|
||||
}
|
||||
|
||||
@@ -301,9 +308,21 @@ namespace DwgExtractorManual.Models
|
||||
{
|
||||
if (appServices != null)
|
||||
{
|
||||
appServices.Dispose();
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[SqlDatas] Teigha Services 해제 중...");
|
||||
TeighaServicesManager.Instance.ReleaseServices();
|
||||
Debug.WriteLine($"[SqlDatas] Teigha Services 해제 완료. Remaining ref count: {TeighaServicesManager.Instance.ReferenceCount}");
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[SqlDatas] Teigha Services 해제 중 오류 (무시됨): {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
appServices = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
192
Models/TeighaServicesManager.cs
Normal file
192
Models/TeighaServicesManager.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Teigha.Runtime;
|
||||
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton class to manage Teigha Services lifecycle and prevent disposal conflicts
|
||||
/// </summary>
|
||||
public sealed class TeighaServicesManager
|
||||
{
|
||||
private static readonly object _lock = new object();
|
||||
private static TeighaServicesManager _instance = null;
|
||||
private static Services _services = null;
|
||||
private static int _referenceCount = 0;
|
||||
private static bool _isActivated = false;
|
||||
|
||||
private TeighaServicesManager()
|
||||
{
|
||||
// Private constructor for singleton
|
||||
}
|
||||
|
||||
public static TeighaServicesManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new TeighaServicesManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Acquires Teigha Services (creates if needed, increments reference count)
|
||||
/// </summary>
|
||||
/// <returns>The Services instance</returns>
|
||||
public Services AcquireServices()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"[TeighaManager] AcquireServices - Current ref count: {_referenceCount}");
|
||||
|
||||
if (!_isActivated)
|
||||
{
|
||||
Debug.WriteLine("[TeighaManager] Activating ODA for first time...");
|
||||
ActivateODA();
|
||||
_isActivated = true;
|
||||
}
|
||||
|
||||
if (_services == null)
|
||||
{
|
||||
Debug.WriteLine("[TeighaManager] Creating new Services instance...");
|
||||
_services = new Services();
|
||||
Debug.WriteLine("[TeighaManager] Services instance created successfully");
|
||||
}
|
||||
|
||||
_referenceCount++;
|
||||
Debug.WriteLine($"[TeighaManager] Services acquired - New ref count: {_referenceCount}");
|
||||
return _services;
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TeighaManager] Error acquiring services: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases Teigha Services (decrements reference count, disposes when count reaches 0)
|
||||
/// </summary>
|
||||
public void ReleaseServices()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine($"[TeighaManager] ReleaseServices - Current ref count: {_referenceCount}");
|
||||
|
||||
if (_referenceCount > 0)
|
||||
{
|
||||
_referenceCount--;
|
||||
Debug.WriteLine($"[TeighaManager] Services released - New ref count: {_referenceCount}");
|
||||
}
|
||||
|
||||
// Don't dispose Services until app shutdown to prevent conflicts
|
||||
// Just track reference count for debugging
|
||||
if (_referenceCount == 0)
|
||||
{
|
||||
Debug.WriteLine("[TeighaManager] All references released (Services kept alive for app lifetime)");
|
||||
}
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TeighaManager] Error releasing services: {ex.Message}");
|
||||
// Don't throw on release to prevent cascade failures
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force dispose Services (only call on application shutdown)
|
||||
/// </summary>
|
||||
public void ForceDisposeServices()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[TeighaManager] Force disposing Services...");
|
||||
|
||||
if (_services != null)
|
||||
{
|
||||
_services.Dispose();
|
||||
Debug.WriteLine("[TeighaManager] Services disposed successfully");
|
||||
}
|
||||
|
||||
_services = null;
|
||||
_referenceCount = 0;
|
||||
_isActivated = false;
|
||||
|
||||
Debug.WriteLine("[TeighaManager] Force dispose completed");
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TeighaManager] Error during force dispose: {ex.Message}");
|
||||
// Reset state even if disposal fails
|
||||
_services = null;
|
||||
_referenceCount = 0;
|
||||
_isActivated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current reference count (for debugging)
|
||||
/// </summary>
|
||||
public int ReferenceCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _referenceCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if Services is active and valid
|
||||
/// </summary>
|
||||
public bool IsServicesActive
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _services != null && _isActivated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ActivateODA()
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.WriteLine("[TeighaManager] Activating ODA...");
|
||||
|
||||
var userInfo = "c2FtYW4gZW5naW5lZXJpbmc=";
|
||||
var userSignature = "F0kuQTmtVpHtvl/TgaFVGE92/YqGmYR9SLoXckEjnOk8NoAQh7Sg6GQruVC04JqD4C/IipxJYqpqvMfMc2auRMG+cAJCKqKUE2djIMdkUdb+C5IVx2c97fcK5ba3n8DDvB54Upokajl+6j12yD8h8MKGOR3Z3zysObeXD62bFpQgp00GCYTqlxEZtTIRjHIPAfJfix8Y0jtXWWYyVJ3LYOu86as5xtx+hY1aakpYIJiQk/6pGd84qSn/9K1w8nxR7UrFzieDeQ/xM58BHSD4u/ZxVJwvv6Uy10tsdBFBTvfJMAFp05Y7yeyeCNr100tA3iOfmWoXAVRHfxnkPfiYR54aK04QI+R6OGkI+yd1oR5BtmN6BdDt3z8KYK5EpFGJGiJIGoUy5PvkYdJ2VV6xe9JWBiIJuI/tDn1Y+uyTQFA9qaDHnOURriXsRGfy8reDPf1eejybSJxWKkpilG6RXhq3xHlCkjZzh1Q45S+xYXNGatcWMm9nkn20M8Ke5JEVaI9w/p2GE36CHRtRQbt8kfPmsbWNXJCFr4svHW2MPbCKWoyn5XEyMWBnuAKi74zvczB13DKjf29SqSIgF5k/hwy2QrgvnaKzY1k8bw8w2/k0vJXcS3GKOB/ZYDle1tf/lkAD1HtnF9zE18TiXhVnqwAVjwg4ui1RPLn/LMs6b5Y=";
|
||||
|
||||
Services.odActivate(userInfo, userSignature);
|
||||
Debug.WriteLine("[TeighaManager] ODA activation successful");
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TeighaManager] ODA activation failed: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,16 +56,159 @@ public class FieldMapper
|
||||
/// </summary>
|
||||
public static FieldMapper LoadFromFile(string jsonFilePath)
|
||||
{
|
||||
string jsonContent = File.ReadAllText(jsonFilePath);
|
||||
try
|
||||
{
|
||||
string jsonContent = File.ReadAllText(jsonFilePath, System.Text.Encoding.UTF8);
|
||||
Console.WriteLine($"[DEBUG] 매핑 테이블 JSON 파일 크기: {jsonContent.Length} bytes");
|
||||
|
||||
// JSON 내용 정리 (주석 제거 등)
|
||||
jsonContent = CleanJsonContent(jsonContent);
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
AllowTrailingCommas = true
|
||||
};
|
||||
|
||||
var mappingData = JsonSerializer.Deserialize<MappingTableData>(jsonContent, options);
|
||||
Console.WriteLine($"[DEBUG] 매핑 테이블 로드 성공: {mappingData?.MappingTable?.AilabelToSystems?.Count ?? 0}개 항목");
|
||||
return new FieldMapper(mappingData);
|
||||
}
|
||||
catch (JsonException jsonEx)
|
||||
{
|
||||
Console.WriteLine($"❌ 매핑 테이블 JSON 파싱 오류: {jsonEx.Message}");
|
||||
Console.WriteLine($"❌ 파일: {jsonFilePath}");
|
||||
if (File.Exists(jsonFilePath))
|
||||
{
|
||||
string content = File.ReadAllText(jsonFilePath);
|
||||
Console.WriteLine($"❌ JSON 내용 미리보기 (첫 500자):");
|
||||
Console.WriteLine(content.Length > 500 ? content.Substring(0, 500) + "..." : content);
|
||||
}
|
||||
throw new Exception($"매핑 테이블 JSON 파일 파싱 실패: {jsonEx.Message}\n파일: {jsonFilePath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"❌ 매핑 테이블 로드 중 오류: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JSON 내용을 정리하여 파싱 가능한 상태로 만듭니다.
|
||||
/// 주석 제거 및 기타 무효한 문자 처리
|
||||
/// </summary>
|
||||
/// <param name="jsonContent">원본 JSON 내용</param>
|
||||
/// <returns>정리된 JSON 내용</returns>
|
||||
private static string CleanJsonContent(string jsonContent)
|
||||
{
|
||||
if (string.IsNullOrEmpty(jsonContent))
|
||||
return jsonContent;
|
||||
|
||||
try
|
||||
{
|
||||
// 줄별로 처리하여 주석 제거
|
||||
var lines = jsonContent.Split('\n');
|
||||
var cleanedLines = new List<string>();
|
||||
|
||||
bool inMultiLineComment = false;
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string processedLine = line;
|
||||
|
||||
// 멀티라인 주석 처리 (/* */)
|
||||
if (inMultiLineComment)
|
||||
{
|
||||
int endIndex = processedLine.IndexOf("*/");
|
||||
if (endIndex >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(endIndex + 2);
|
||||
inMultiLineComment = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // 전체 라인이 주석
|
||||
}
|
||||
}
|
||||
|
||||
// 멀티라인 주석 시작 확인
|
||||
int multiLineStart = processedLine.IndexOf("/*");
|
||||
if (multiLineStart >= 0)
|
||||
{
|
||||
int multiLineEnd = processedLine.IndexOf("*/", multiLineStart + 2);
|
||||
if (multiLineEnd >= 0)
|
||||
{
|
||||
// 같은 라인에서 시작하고 끝나는 주석
|
||||
processedLine = processedLine.Substring(0, multiLineStart) +
|
||||
processedLine.Substring(multiLineEnd + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 멀티라인 주석 시작
|
||||
processedLine = processedLine.Substring(0, multiLineStart);
|
||||
inMultiLineComment = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 싱글라인 주석 제거 (//) - 문자열 내부의 //는 제외
|
||||
bool inString = false;
|
||||
bool escaped = false;
|
||||
int commentIndex = -1;
|
||||
|
||||
for (int i = 0; i < processedLine.Length - 1; i++)
|
||||
{
|
||||
char current = processedLine[i];
|
||||
char next = processedLine[i + 1];
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == '\\')
|
||||
{
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == '"')
|
||||
{
|
||||
inString = !inString;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inString && current == '/' && next == '/')
|
||||
{
|
||||
commentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (commentIndex >= 0)
|
||||
{
|
||||
processedLine = processedLine.Substring(0, commentIndex);
|
||||
}
|
||||
|
||||
// 빈 라인이 아니면 추가
|
||||
if (!string.IsNullOrWhiteSpace(processedLine))
|
||||
{
|
||||
cleanedLines.Add(processedLine);
|
||||
}
|
||||
}
|
||||
|
||||
string result = string.Join("\n", cleanedLines);
|
||||
Console.WriteLine($"[DEBUG] 매핑 테이블 JSON 정리 완료: {jsonContent.Length} -> {result.Length} bytes");
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"❌ 매핑 테이블 JSON 정리 중 오류: {ex.Message}");
|
||||
// 정리 실패시 원본 반환
|
||||
return jsonContent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AI 라벨을 고속도로공사 필드명으로 변환
|
||||
|
||||
@@ -73,12 +73,6 @@
|
||||
"railway": "",
|
||||
"docaikey": "CSCOP"
|
||||
},
|
||||
//"사업명_bot": {
|
||||
// "molit": "",
|
||||
// "expressway": "TD_CNAME",
|
||||
// "railway": "TD_CNAME",
|
||||
// "docaikey": "TDCNAME"
|
||||
//},
|
||||
"설계공구_공구명": {
|
||||
"molit": "",
|
||||
"expressway": "TD_DSECT",
|
||||
|
||||
Reference in New Issue
Block a user