import os import sys from PyQt5 import QtWidgets, QtGui, QtCore from datetime import datetime import json import subprocess class MainView(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.version = "1.0.0" # 프로그램 버전 설정 self.default_save_path = os.path.join(os.path.expanduser("~"), "Desktop") # 바탕화면 경로 설정 self.file_paths = [] # 파일 경로 저장 리스트 self.loadSettings() # 설정 로드 self.setupUI() # UI 설정 self.setButtons() # 버튼 설정 self.sortTreeView(0, True) # 기본 파일명 오름차순 정렬 self.channel_options = ["채널 1", "채널 2", "채널 3"] # 채널 옵션 설정 def loadSettings(self): self.settings_file = "settings.json" if os.path.exists(self.settings_file): with open(self.settings_file, "r", encoding="utf-8") as file: self.settings = json.load(file) # 설정 파일 로드 self.default_save_path = self.settings.get("default_save_path", self.default_save_path) self.file_paths = self.settings.get("file_paths", []) else: self.settings = {"theme": "light"} # 기본 설정 def saveSettings(self): settings = { "theme": self.settings.get("theme", "light"), "default_save_path": self.default_save_path, "file_paths": self.file_paths } with open(self.settings_file, "w", encoding="utf-8") as file: json.dump(settings, file, ensure_ascii=False) # 설정 파일 저장 def setupUI(self): self.setWindowTitle("DBC to C Converter") self.setGeometry(100, 100, 1000, 600) # 창 크기 조정 # 메뉴바 추가 self.menu_bar = self.menuBar() file_menu = self.menu_bar.addMenu("파일") edit_menu = self.menu_bar.addMenu("편집") view_menu = self.menu_bar.addMenu("보기") tools_menu = self.menu_bar.addMenu("도구") # 파일 메뉴 항목 추가 file_menu.addAction("파일 추가", self.FilesOpen) file_menu.addSeparator() file_menu.addAction("선택 파일 삭제", self.deleteSelectedFiles) file_menu.addSeparator() file_menu.addAction("모든 파일 삭제", self.deleteAllFiles) # 편집 메뉴 항목 추가 edit_menu.addAction("모두 선택", self.selectAllFiles) edit_menu.addSeparator() edit_menu.addAction("선택 반전", self.invertSelection) # 보기 메뉴 항목 추가 size_menu = view_menu.addMenu("창크기") size_menu.addAction("작게", lambda: self.setWindowSize("small")) size_menu.addSeparator() size_menu.addAction("보통", lambda: self.setWindowSize("medium")) size_menu.addSeparator() size_menu.addAction("크게", lambda: self.setWindowSize("large")) size_menu.addSeparator() size_menu.addAction("자동", lambda: self.setWindowSize("auto")) sort_menu = view_menu.addMenu("정렬") sort_menu.addAction("파일명 오름차순", lambda: self.sortTreeView(0, False)) sort_menu.addSeparator() sort_menu.addAction("파일명 내림차순", lambda: self.sortTreeView(0, True)) sort_menu.addSeparator() sort_menu.addAction("파일경로 오름차순", lambda: self.sortTreeView(1, False)) sort_menu.addSeparator() sort_menu.addAction("파일경로 내림차순", lambda: self.sortTreeView(1, True)) sort_menu.addSeparator() sort_menu.addAction("파일크기 오름차순", lambda: self.sortTreeView(3, False)) sort_menu.addSeparator() sort_menu.addAction("파일크기 내림차순", lambda: self.sortTreeView(3, True)) # 도구 메뉴 항목 추가 tools_menu.addAction("설정", self.openSettings) tools_menu.addSeparator() tools_menu.addAction("프로그램 정보", self.openAbout) # 메인 위젯 설정 main_widget = QtWidgets.QWidget() self.setCentralWidget(main_widget) main_layout = QtWidgets.QVBoxLayout(main_widget) # 파일 리스트 설정 self.tree = QtWidgets.QTreeWidget() self.tree.setColumnCount(4) self.tree.setHeaderLabels(['파일명', '파일경로', '채널', '파일크기']) self.tree.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.tree.header().sectionClicked.connect(self.onHeaderClicked) self.tree.itemDoubleClicked.connect(self.onItemDoubleClicked) main_layout.addWidget(self.tree) # 버튼 프레임 설정 button_frame = QtWidgets.QWidget() button_layout = QtWidgets.QHBoxLayout(button_frame) main_layout.addWidget(button_frame) self.btn_list = QtWidgets.QPushButton("파일 추가") self.btn_list.clicked.connect(self.FilesOpen) button_layout.addWidget(self.btn_list) self.btn_delete = QtWidgets.QPushButton("파일 삭제") self.btn_delete.clicked.connect(self.deleteSelectedFiles) button_layout.addWidget(self.btn_delete) self.btn_delete_all = QtWidgets.QPushButton("모든 파일 삭제") self.btn_delete_all.clicked.connect(self.deleteAllFiles) button_layout.addWidget(self.btn_delete_all) self.btn_convert = QtWidgets.QPushButton("변환") self.btn_convert.clicked.connect(self.convertFiles) button_layout.addWidget(self.btn_convert) self.btn_clear_alerts = QtWidgets.QPushButton("알림창 내용 삭제") self.btn_clear_alerts.clicked.connect(self.clearAlerts) button_layout.addWidget(self.btn_clear_alerts) # 알림창 설정 self.alert_text = QtWidgets.QTextEdit() self.alert_text.setReadOnly(True) main_layout.addWidget(self.alert_text) # 초기 테마 설정 적용 if self.settings["theme"] == "light": self.setLightMode() def setButtons(self): self.btn_list.clicked.disconnect() self.btn_delete.clicked.disconnect() self.btn_delete_all.clicked.disconnect() self.btn_clear_alerts.clicked.disconnect() self.btn_list.clicked.connect(self.FilesOpen) self.btn_delete.clicked.connect(self.deleteSelectedFiles) self.btn_delete_all.clicked.connect(self.deleteAllFiles) self.btn_clear_alerts.clicked.connect(self.clearAlerts) def FilesOpen(self): file_paths, _ = QtWidgets.QFileDialog.getOpenFileNames( self, "파일 열기", "", "DBC 파일 (*.dbc);;모든 파일 (*.*)" ) if file_paths: existing_files = [self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())] duplicate_files = [os.path.split(file_path)[1] for file_path in file_paths if os.path.split(file_path)[1] in existing_files] new_files = [file_path for file_path in file_paths if os.path.split(file_path)[1] not in existing_files] if duplicate_files: self.showDuplicateFilesWarning(duplicate_files, new_files, [os.path.split(file_path)[1] for file_path in new_files]) self.updateAlertText(f"중복 파일 경고", duplicate_files) if new_files: self.populateTreeView(new_files) self.file_paths.extend(new_files) # 파일 경로 저장 self.updateAlertText(f"파일 추가 완료", [os.path.split(file_path)[1] for file_path in new_files]) def deleteSelectedFiles(self): selected_items = self.tree.selectedItems() if not selected_items: self.showWarning("경고", "선택된 파일이 없습니다") self.updateAlertText("파일 삭제 실패", ["선택된 파일이 없습니다"]) return deleted_files = [item.text(0) for item in selected_items] for item in selected_items: index = self.tree.indexOfTopLevelItem(item) self.tree.takeTopLevelItem(index) self.updateAlertText(f"파일 삭제 완료", deleted_files) def deleteAllFiles(self): if self.tree.topLevelItemCount() == 0: self.showWarning("경고", "삭제할 파일이 없습니다") self.updateAlertText("모든 파일 삭제 실패", ["삭제할 파일이 없습니다"]) return deleted_files = [self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())] self.tree.clear() self.updateAlertText(f"모든 파일 삭제 완료", deleted_files) def clearAlerts(self): self.alert_text.clear() def showWarning(self, title, message): warning_box = QtWidgets.QMessageBox(self) warning_box.setIcon(QtWidgets.QMessageBox.Warning) warning_box.setWindowTitle(title) warning_box.setText(message) warning_box.exec_() def showDuplicateFilesWarning(self, duplicate_files, new_files, new_files_names): duplicate_files_str = "\n".join(duplicate_files) new_files_str = "\n".join(new_files_names) if new_files: self.showWarning("중복 파일 경고", f"중복 파일이 존재합니다\n\n{duplicate_files_str}\n\n\n중복 파일을 제외한 신규 파일을 추가합니다\n\n{new_files_str}") else: self.showWarning("중복 파일 경고", f"중복 파일이 존재합니다\n\n{duplicate_files_str}") def sortTreeView(self, col, reverse): items = [] for i in range(self.tree.topLevelItemCount()): item = self.tree.takeTopLevelItem(0) items.append(item) items.sort(key=lambda x: x.text(col), reverse=reverse) for item in items: self.tree.addTopLevelItem(item) def selectAllFiles(self): for i in range(self.tree.topLevelItemCount()): self.tree.topLevelItem(i).setSelected(True) def invertSelection(self): for i in range(self.tree.topLevelItemCount()): item = self.tree.topLevelItem(i) item.setSelected(not item.isSelected()) def setWindowSize(self, size): if size == "small": self.resize(600, 400) elif size == "medium": self.resize(800, 600) elif size == "large": self.resize(1000, 800) elif size == "auto": self.adjustSize() def openSettings(self): settings_window = QtWidgets.QDialog(self) settings_window.setWindowTitle("설정") settings_window.setGeometry(100, 100, 400, 300) layout = QtWidgets.QVBoxLayout(settings_window) label = QtWidgets.QLabel("설정 창입니다.") label.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label) settings_window.exec_() def openAbout(self): about_window = QtWidgets.QDialog(self) about_window.setWindowTitle("프로그램 정보") about_window.setGeometry(100, 100, 400, 300) layout = QtWidgets.QVBoxLayout(about_window) label1 = QtWidgets.QLabel("이 프로그램은 DBC 파일을 C 파일로 변환합니다.") label1.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label1) label2 = QtWidgets.QLabel("프로그램 정보") label2.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label2) label3 = QtWidgets.QLabel(f"버전: {self.version}") label3.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label3) about_window.exec_() def setLightMode(self): self.setStyleSheet("background-color: white; color: black;") self.alert_text.setStyleSheet("background-color: white; color: black;") self.tree.setStyleSheet("background-color: white; color: black;") self.menu_bar.setStyleSheet("background-color: white; color: black;") self.btn_list.setStyleSheet("background-color: white; color: black;") self.btn_delete.setStyleSheet("background-color: white; color: black;") self.btn_delete_all.setStyleSheet("background-color: white; color: black;") self.btn_convert.setStyleSheet("background-color: white; color: black;") self.btn_clear_alerts.setStyleSheet("background-color: white; color: black;") def populateTreeView(self, file_paths): def format_file_size(size_in_bytes): size_in_kb = size_in_bytes / 1024 return f"{size_in_kb:.2f} KB" for file_path in file_paths: directory, file = os.path.split(file_path) fsize = format_file_size(os.path.getsize(file_path)) item = QtWidgets.QTreeWidgetItem([file, directory, self.channel_options[0], fsize]) self.tree.addTopLevelItem(item) def updateAlertText(self, message, file_list): current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.alert_text.append(f"[{current_time}] {message}") for file in file_list: self.alert_text.append(f" - {file}") self.alert_text.setAlignment(QtCore.Qt.AlignLeft) def convertFiles(self): for file_path in self.file_paths: try: subprocess.run(["python", "DBC_to_C_RX.py", file_path], check=True) subprocess.run(["python", "DBC_to_C_TX.py", file_path], check=True) self.updateAlertText(f"변환 성공", [file_path]) except subprocess.CalledProcessError as e: self.updateAlertText(f"변환 실패: {e}", [file_path]) def onHeaderClicked(self, logicalIndex): header = self.tree.headerItem() if header.text(logicalIndex).endswith("▲"): self.sortTreeView(logicalIndex, True) header.setText(logicalIndex, header.text(logicalIndex).replace("▲", "▼")) else: self.sortTreeView(logicalIndex, False) header.setText(logicalIndex, header.text(logicalIndex).replace("▼", "▲")) def onItemDoubleClicked(self, item, column): if column == 0: # 파일명을 더블클릭한 경우 file_path = os.path.join(item.text(1), item.text(0)) os.startfile(file_path) elif column == 1: # 경로를 더블클릭한 경우 os.startfile(item.text(1)) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) main_view = MainView() main_view.show() sys.exit(app.exec_())