AutoPercenty3/gui.py

1106 lines
53 KiB
Python

from PySide6.QtWidgets import QInputDialog, QWidget, QMessageBox, QSpinBox, QPushButton, QVBoxLayout, QGridLayout, QTextEdit, QLabel, QLineEdit, QHBoxLayout, QProgressBar, QSizePolicy
from PySide6.QtCore import Qt, Signal, Slot, QRect, QSettings, QTimer
from toggleSwitch import ToggleSwitch
from browser_control import BrowserController
# from whale_translator import WhaleTranslator
# from vertexAI import VertexAITranslator
from locatorManager import LocatorManager
from src.cmb_diag import CMBSettingsDialog
from src.DatabaseManager import DatabaseManager
from loggerModule import Logger # 추가
import logging
import sys
import os, shutil, time
class AutoPercentyGUI(QWidget):
start_stage_signal = Signal(int)
complete_stage_signal = Signal(int)
percentyJob_button_Signal = Signal(bool)
update_detail_progress_signal = Signal(int, int) # (현재 값, 총 값)
set_progress_visible_signal = Signal(bool) # ProgressBar 표시/숨김
def __init__(self, app=None):
super().__init__()
self.start_stage_signal.connect(self.start_stage)
self.complete_stage_signal.connect(self.complete_stage)
self.update_detail_progress_signal.connect(self.update_detail_progress_value) # 연결
self.set_progress_visible_signal.connect(self.set_progress_visibility)
self.percentyJob_button_Signal.connect(self.percentyJob_button_Enable)
self.initUI()
self.logger = Logger(gui_logger=self.log_message, log_file="AutoPercenty3.log", logger_name="AP3_Logger", level=logging.DEBUG)
self.logger.log(f"로그기록이 설정되었습니다.", level=logging.INFO)
self.debug = False
self.settings = QSettings("WhenRideMycar", "AutoPercenty3") # QSettings 초기화
self.locator_manager = LocatorManager()
# self.vertexAI = VertexAITranslator(self.logger)
# DB 파일 경로 설정
self.base_dir = self.get_base_dir()
self.user_db_path = os.path.join(self.base_dir, "userDB.db")
self.initial_db_path = os.path.join(self.base_dir, "src", "initialDB.db")
# userDB.db 생성 (없으면 initialDB.db 복사)
self.create_user_db_if_not_exists()
# 이전에 저장된 설정 불러오기
self.load_settings()
# # DatabaseManager 초기화
self.db_manager = DatabaseManager(db_url=f"sqlite:///{self.user_db_path}", logger=self.logger)
self.cmb_diag = CMBSettingsDialog(parent=self, logger=self.logger, db_manager=self.db_manager, initial_db_path=self.initial_db_path, user_db_path=self.user_db_path, debug=self.debug)
self.browser_controller = BrowserController(self, self.logger, self.locator_manager, self.cmb_diag, self.login_infos, self.toggle_states)
# 브라우저 시작 완료 및 오류 시그널 연결
self.browser_controller.browser_started.connect(self.on_browser_started)
self.browser_controller.browser_error.connect(self.on_browser_error)
# 브라우저 시작 완료 및 오류 시그널 연결
self.browser_controller.translation_started.connect(self.on_PercentyJob_started)
self.browser_controller.translation_completed.connect(self.on_PercentyJob_completed)
self.browser_controller.translation_error.connect(self.on_PercentyJob_error)
# self.clipboardImageManager = ClipboardImageManager(self, logger, self.browser_controller, watermark_font_size=36, debug=self.debug)
# self.optionHandler = OptionHandler(self.locator_manager, self.browser_controller, self.whale_translator, self.clipboardImageManager, self.logger, self.vertexAI, self.debug)
# self.priceHandler = PriceHandler(self.locator_manager, self.browser_controller, self.logger, self.optionHandler, self.vertexAI, self.cmb_diag, self.debug)
# self.titleHandler = TitleHandler(self.locator_manager, self.browser_controller, self.logger)
self.running = False
# 변수 설정
self.start_time = 0
self.finish_time = 0
self.total_product_count = 0
self.current_product_count = 0
self.title_count = 0
self.option_count = 0
self.price_count = 0
self.detail_image_count = 0
self.thumb_image_count = 0
self.current_options_info = {}
self.current_stage_index = 0 # 현재 진행 중인 단계 인덱스
# 프로그래스바 초기화
self.update_total_progress(0,0)
@Slot(str)
def log_message(self, message):
self.log.append(message)
def get_base_dir(self):
"""
실행 환경에 따라 base_dir을 설정하는 메서드.
cx_Freeze로 패키징된 경우 실행 파일의 경로, 일반 Python 환경일 경우 __file__을 기준으로 설정.
"""
if getattr(sys, 'frozen', False): # 패키징된 경우
base_dir = os.path.dirname(sys.executable)
internal_dir = os.path.join(base_dir, '_internal') # _internal 디렉토리 포함
if os.path.exists(internal_dir): # _internal 디렉토리가 존재하면 base_dir로 설정
return internal_dir
else: # 일반 Python 실행 환경
base_dir = os.path.dirname(os.path.abspath(__file__))
return base_dir
def create_user_db_if_not_exists(self):
"""
userDB.db 파일이 없으면 initialDB.db를 복사해서 생성하는 메서드.
"""
try:
if not os.path.exists(self.user_db_path):
self.logger.log(f"userDB.db 파일이 존재하지 않아 initialDB.db를 복사합니다.", level=logging.DEBUG)
if os.path.exists(self.initial_db_path):
shutil.copyfile(self.initial_db_path, self.user_db_path)
self.logger.log("initialDB.db를 userDB.db로 복사했습니다.", level=logging.DEBUG)
else:
raise FileNotFoundError(f"{self.initial_db_path} 파일이 없습니다. 초기 DB 파일이 존재하는지 확인해주세요.")
except FileNotFoundError as e:
self.logger.log(f"DB 초기화 실패: {e}", level=logging.ERROR, exc_info=True)
raise e
except Exception as e:
self.logger.log(f"DB 파일 복사 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
raise e
# def add_text_edit_logger(self):
# """QTextEdit에 로그를 출력하기 위한 핸들러 추가"""
# text_edit_logger = QTextEditLogger()
# text_edit_logger.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
# # text_edit_logger.appendHtml.connect(self.log.appendHtml)
# text_edit_logger.appendHtml.connect(self.log.append) # appendHtml 대신 append로 수정
# text_edit_logger.scrollToBottom.connect(lambda: self.log.verticalScrollBar().setValue(self.log.verticalScrollBar().maximum()))
# self.logger.addHandler(text_edit_logger)
# self.logger.debug('로그기록이 설정되었습니다.')
# def add_text_edit_logger(self):
# """QPlainTextEdit에 로그를 출력하기 위한 핸들러 추가"""
# try:
# # GUI 핸들러 추가
# self.plain_text_edit_logger = QTextEditLogger(self.log)
# self.plain_text_edit_logger.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
# self.logger.addHandler(self.plain_text_edit_logger)
# # self.inspect_logger_handlers(self.logger)
# for handler in self.logger.handlers:
# if isinstance(handler, QTextEditLogger):
# print(f"Handler: {handler}, Type: QTextEditLogger")
# self.logger.debug('로그기록이 설정되었습니다.')
# except Exception as e:
# print(f"Error in add_text_edit_logger: {e}")
@Slot(int)
def start_stage(self, stage_index):
"""지정한 단계에 깜빡임 효과 적용"""
if 0 <= stage_index < len(self.stage_labels):
self.timer = QTimer(self)
self.blink_status = True
self.timer.timeout.connect(lambda: self.blink_stage(stage_index))
self.timer.start(500) # 0.5초 간격으로 깜빡임
def blink_stage(self, stage_index):
"""지정한 단계의 색상을 주기적으로 변경하여 깜빡임 효과를 적용"""
label = self.stage_labels[stage_index]
if self.blink_status:
label.setStyleSheet("background-color: yellow; padding: 5px;")
else:
label.setStyleSheet("background-color: lightgray; padding: 5px;")
self.blink_status = not self.blink_status
def stop_blinking_effect(self):
"""깜빡임 효과 중지"""
self.timer.stop()
@Slot(int)
def complete_stage(self, stage_index):
"""단계 완료 시 깜빡임을 중지하고 완료 상태로 변경"""
if 0 <= stage_index < len(self.stage_labels):
self.stop_blinking_effect()
label = self.stage_labels[stage_index]
label.setStyleSheet("background-color: green; padding: 5px;")
self.current_stage_index += 1
# 다음 단계로 이동하여 깜빡임 시작
if self.current_stage_index < len(self.stages):
self.start_stage(self.current_stage_index)
def init_settings(self):
self.login_infos={
'admin_id' : None,
'admin_pw' : None,
'user_id' : None,
'user_pw' : None,
'is_admin' : False,
}
# 토글 상태를 저장할 딕셔너리 초기화
self.toggle_states = {
'title': False,
'use_API': False,
'clientID': "",
'clientSecret': "",
'optionTrnas': False,
'optionIMGTrans': False,
'optionAutoSelect': False,
'price': False,
'thumb': False,
'tag': False,
'detail_Option': False,
'detail_IMGTrans': False,
'debug_mode': False,
'recovery_mode': False,
'ed_mode': False, # 등록된 상품을 수정할때
'watermark': False, # 워터마크 토글 추가
'watermark_text': "", # 워터마크 텍스트 저장
'opacity_percent': 25, # 워터마크 투명도
'max_option_count': 20, # 최대 선택가능한 옵션 수
}
def initUI(self):
self.init_settings()
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setGeometry(QRect(800, 200, 400, 700))
self.setWindowTitle('AutoPecenty3')
# 로그
self.log = QTextEdit(self)
self.log.setReadOnly(True)
# 전체 프로그레스바
self.total_progress_bar = QProgressBar(self)
self.total_progress_bar.setValue(0)
self.total_progress_bar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
# 스테이지 타임라인
self.stageTimeline_layout = QHBoxLayout()
# self.stages = ["상품명", "옵션", "가격", "썸네일", "상페"]
self.stages = ["상품명", "옵션", "가격", "썸네일", "키워드", "상페"]
self.stage_labels = []
for stage in self.stages:
# self.stage_layout = QHBoxLayout()
label = QLabel(stage)
label.setStyleSheet("background-color: lightgray; padding: 3px;")
self.stage_labels.append(label)
# self.stage_layout.addWidget(label)
# self.stageTimeline_layout.addLayout(self.stage_layout)
self.stageTimeline_layout.addWidget(label) # 수정: QLabel을 추가할 때 addWidget() 사용
# 디테일 프로그레스바
self.detail_progress_bar = QProgressBar(self)
self.detail_progress_bar.setValue(0)
self.detail_progress_bar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.detail_progress_bar.setVisible(False)
# 동작옵션 토글 및 레이블 설정
self.toggle_layout = QGridLayout()
# 상품명 수정 토글
self.title_toggle_label = QLabel("상품명 수정", self)
self.title_toggle = ToggleSwitch(self)
self.title_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('title', checked))
self.toggle_layout.addWidget(self.title_toggle_label, 0, 0)
self.toggle_layout.addWidget(self.title_toggle, 0, 1)
# API 사용 토글
self.use_API_toggle_label = QLabel("API 사용", self)
self.use_API_toggle = ToggleSwitch(self)
self.use_API_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('use_API', checked))
self.toggle_layout.addWidget(self.use_API_toggle_label, 0, 2)
self.toggle_layout.addWidget(self.use_API_toggle, 0, 3)
# API 관련 필드 초기화
self.client_id_label = QLabel("Client ID", self)
self.client_id_input = QLineEdit(self)
self.client_id_input.setPlaceholderText("Client ID 입력")
self.client_id_input.returnPressed.connect(self.update_client_id_input)
self.client_secret_label = QLabel("Client Secret", self)
self.client_secret_input = QLineEdit(self)
self.client_secret_input.setPlaceholderText("Client Secret 입력")
self.client_secret_input.returnPressed.connect(self.update_client_secret_input)
# 초기에는 숨김 상태
self.client_id_label.setVisible(False)
self.client_id_input.setVisible(False)
self.client_secret_label.setVisible(False)
self.client_secret_input.setVisible(False)
# 옵션명 AI번역 토글
self.optionTrnas_toggle_label = QLabel("옵션명 AI번역", self)
self.optionTrnas_toggle = ToggleSwitch(self)
self.optionTrnas_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('optionTrnas', checked))
# 옵션이미지 번역 토글
self.optionIMGTrans_toggle_label = QLabel("옵션이미지 번역", self)
self.optionIMGTrans_toggle = ToggleSwitch(self)
self.optionIMGTrans_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('optionIMGTrans', checked))
# 옵션Auto선택 토글
self.optionAutoSelect_toggle_label = QLabel("옵션 Auto선택", self)
self.optionAutoSelect_toggle = ToggleSwitch(self)
self.optionAutoSelect_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('optionAutoSelect', checked))
# 가격 수정 토글
self.price_toggle_label = QLabel("가격 수정", self)
self.price_toggle = ToggleSwitch(self)
self.price_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('price', checked))
# 태그 수정 토글
self.tag_toggle_label = QLabel("태그 수정", self)
self.tag_toggle = ToggleSwitch(self)
self.tag_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('tag', checked))
# 썸네일 AI수정 토글
self.thumb_toggle_label = QLabel("썸네일 AI수정", self)
self.thumb_toggle = ToggleSwitch(self)
self.thumb_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('thumb', checked))
# 상페 옵션명 삽입 토글
self.detail_Option_toggle_label = QLabel("상세 옵션명 삽입", self)
self.detail_Option_toggle = ToggleSwitch(self)
self.detail_Option_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('detail_Option', checked))
# 상페 이미지 번역 토글
self.detail_IMGTrans_toggle_label = QLabel("상세 이미지 번역", self)
self.detail_IMGTrans_toggle = ToggleSwitch(self)
self.detail_IMGTrans_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('detail_IMGTrans', checked))
# 디버그 모드 토글
self.debug_toggle_label = QLabel("디버그 모드", self)
self.debug_toggle = ToggleSwitch(self)
self.debug_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('debug_mode', checked))
# 수정등록 모드 토글
self.ed_mode_toggle_label = QLabel("수정등록 모드", self)
self.ed_mode_toggle = ToggleSwitch(self)
self.ed_mode_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('ed_mode', checked))
# # VD 모드 토글
# self.vd_mode_toggle_label = QLabel("VD 모드", self)
# self.vd_mode_toggle = ToggleSwitch(self)
# self.vd_mode_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('vd_mode', checked))
# self.toggle_layout.addWidget(self.vd_mode_toggle_label, 5, 2)
# self.toggle_layout.addWidget(self.vd_mode_toggle, 5, 3)
# self.vd_mode_toggle.setVisible(False)
# self.vd_mode_toggle_label.setVisible(False)
# recovery 모드 토글
self.recovery_mode_toggle_label = QLabel("복구 모드", self)
self.recovery_mode_toggle = ToggleSwitch(self)
self.recovery_mode_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('recovery_mode', checked))
# 워터마크 토글 추가
self.watermark_toggle_label = QLabel("워터마크", self)
self.watermark_toggle = ToggleSwitch(self)
self.watermark_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('watermark', checked))
# 워터마크 관련 UI 요소 생성
self.watermark_text_label = QLabel("회사 이름", self)
self.watermark_text_input = QLineEdit(self)
self.watermark_text_input.returnPressed.connect(self.update_watermark_text)
# self.watermark_confirm_button = QPushButton("확인", self)
# # 확인 버튼 클릭 시 watermark_text 업데이트
# self.watermark_confirm_button.clicked.connect(self.update_watermark_text)
# 최대 옵션수
self.max_option_count_label = QLabel("최대옵션수", self)
self.max_option_count_input = QSpinBox(self)
self.max_option_count_input.setMinimum(0) # 최소값 0
self.max_option_count_input.setMaximum(100) # 최대값 100
self.max_option_count_input.setValue(20) # 기본값 0
self.max_option_count_input.setToolTip("0으로 설정시 최대") # 툴팁 설정
self.max_option_count_input.valueChanged.connect(self.update_max_option_count) # 값 변경 시 update_max_option_count 메서드 호출
# 워터마크 투명도 설정
self.opacity_percent_label = QLabel("WM투명도", self)
self.opacity_percent_input = QSpinBox(self)
self.opacity_percent_input.setMinimum(0) # 최소값 0
self.opacity_percent_input.setMaximum(80) # 최대값 100
self.opacity_percent_input.setValue(25) # 기본값 0
self.opacity_percent_input.setToolTip("워터마크 투명도 설정: 낮을수록 투명") # 툴팁 설정
self.opacity_percent_input.valueChanged.connect(self.update_opacity_percent) # 값 변경 시 update_max_option_count 메서드 호출
# 워터마크 관련 요소들을 하나의 QHBoxLayout에 추가 (비율 2:3:1)
self.watermark_layout = QHBoxLayout()
# 초기 위치에서 배치
self.update_widget_positions(use_api_row=1)
# 초기에는 워터마크 입력창과 버튼 숨김
self.toggle_visibility(False, [(self.watermark_text_input, self.watermark_text_label), (self.opacity_percent_input, self.opacity_percent_label)])
# 관리자 토글
self.admin_toggle = ToggleSwitch(self)
self.admin_toggle.clicked.connect(self.on_admin_toggle_clicked)
# 관리자 ID 및 PW
self.admin_id_label = QLabel("관리자 ID:", self)
self.admin_id_input = QLineEdit(self)
# 관리자 PW
self.admin_pw_label = QLabel("관리자 PW:", self)
self.admin_pw_input = QLineEdit(self)
self.admin_pw_input.setEchoMode(QLineEdit.Password)
# 직원 ID 및 PW
self.user_id_label = QLabel("직원 ID:", self)
self.user_id_input = QLineEdit(self)
self.user_pw_label = QLabel("직원 PW:", self)
self.user_pw_input = QLineEdit(self)
self.user_pw_input.setEchoMode(QLineEdit.Password)
# 크롬 실행 버튼 및 번역 버튼
self.start_chrome_button = QPushButton('크롬 실행', self)
self.PercentyJob_button = QPushButton('상품수정 시작', self)
self.PercentyJob_button.setEnabled(False)
self.PercentyJob_button.setStyleSheet("""
QPushButton:disabled {
color: gray;
background-color: lightgray;
border: 1px solid gray;
}
""")
self.pause_button = QPushButton('일시정지', self)
self.pause_button.setEnabled(False)
self.pause_button.setStyleSheet("""
QPushButton:disabled {
color: gray;
background-color: lightgray;
border: 1px solid gray;
}
""")
self.cmb_button = QPushButton('크무비설정', self)
self.cmb_test_button = QPushButton('크무비테스트', self)
# 버튼 크기를 1.5배로 설정
button_height = int(self.start_chrome_button.sizeHint().height() * 1.5)
self.start_chrome_button.setFixedHeight(button_height)
self.PercentyJob_button.setFixedHeight(button_height)
self.pause_button.setFixedHeight(button_height)
self.cmb_button.setFixedHeight(button_height)
# 메인 레이아웃 설정
self.main_layout = QVBoxLayout()
# 관리자 토글 버튼 및 로그인 관련 필드 추가
self.admin_toggle_layout = QHBoxLayout()
self.admin_toggle_layout.addWidget(QLabel("관리자 여부:", self))
self.admin_toggle_layout.addWidget(self.admin_toggle)
self.main_layout.addLayout(self.admin_toggle_layout,1)
# 관리자 ID
self.main_layout.addWidget(self.admin_id_label)
self.main_layout.addWidget(self.admin_id_input)
# 관리자 PW
self.admin_layout = QVBoxLayout()
self.admin_layout.addWidget(self.admin_pw_label)
self.admin_layout.addWidget(self.admin_pw_input)
# 직원 ID/PW
self.user_layout = QVBoxLayout()
self.user_layout.addWidget(self.user_id_label)
self.user_layout.addWidget(self.user_id_input)
self.user_layout.addWidget(self.user_pw_label)
self.user_layout.addWidget(self.user_pw_input)
# 관리자와 직원 레이아웃을 메인 레이아웃에 추가
self.main_layout.addLayout(self.admin_layout,3)
self.main_layout.addLayout(self.user_layout,3)
# 크롬 및 번역 관련 버튼
self.button_layout = QHBoxLayout()
self.button_layout.addWidget(self.start_chrome_button)
self.button_layout.addWidget(self.PercentyJob_button)
self.button_layout.addWidget(self.pause_button)
self.button_layout.addWidget(self.cmb_button)
self.button_layout.addWidget(self.cmb_test_button)
# 로그 및 프로그레스바 레이아웃
self.log_layout = QVBoxLayout()
self.log_layout.addWidget(self.log)
self.log_layout.addWidget(self.total_progress_bar)
self.log_layout.addLayout(self.stageTimeline_layout)
self.log_layout.addWidget(self.detail_progress_bar)
# 메인 레이아웃에 버튼 레이아웃과 로그 레이아웃 추가
self.main_layout.addLayout(self.toggle_layout,2)
self.main_layout.addLayout(self.button_layout,2)
self.main_layout.addLayout(self.log_layout,5)
self.setLayout(self.main_layout)
# 기본 상태 설정
self.on_admin_toggle_clicked(False)
# 버튼 이벤트 연결
self.start_chrome_button.clicked.connect(self.start_browser_thread)
self.PercentyJob_button.clicked.connect(self.on_start_PercentyJob_clicked)
self.cmb_button.clicked.connect(self.on_cmb_button_clicked)
self.cmb_test_button.clicked.connect(self.on_cmb_test_button_clicked)
def load_toggle_settings(self):
"""QSettings에서 토글 상태 불러오기"""
for key, default_value in self.toggle_states.items():
# # opacity_percent와 max_option_count는 처리 제외
# if key in ["opacity_percent", "max_option_count"]:
# continue
# 데이터 타입을 각 항목의 기본값에 따라 결정
if isinstance(default_value, bool):
self.toggle_states[key] = self.settings.value(f"toggle/{key}", default_value, type=bool)
# elif isinstance(default_value, int):
# self.toggle_states[key] = self.settings.value(f"toggle/{key}", default_value, type=int)
# elif isinstance(default_value, str):
# self.toggle_states[key] = self.settings.value(f"toggle/{key}", default_value, type=str)
# else:
# # 기본값이 지정되지 않은 경우 bool로 처리
# self.toggle_states[key] = self.settings.value(f"toggle/{key}", False, type=bool)
self.update_toggle_ui(key)
def save_toggle_settings(self):
"""QSettings에 토글 상태 저장"""
for key, value in self.toggle_states.items():
self.settings.setValue(f"toggle/{key}", value)
# 상태가 변경되었을 때 UI를 업데이트
self.update_toggle_ui(key)
def update_toggle_ui(self, key):
"""토글 상태에 따라 UI 업데이트"""
# if hasattr(self, f"{key}_toggle"):
# toggle_widget = getattr(self, f"{key}_toggle")
toggle_widget = getattr(self, f"{key}_toggle", None)
# bool 타입인 경우
if isinstance(self.toggle_states[key], bool) and toggle_widget:
toggle_widget.setChecked(self.toggle_states[key])
# # int 타입인 경우
# elif isinstance(self.toggle_states[key], int):
# if hasattr(toggle_widget, "setValue"): # setValue 메서드 확인
# toggle_widget.setValue(self.toggle_states[key])
# print(f"int key : {key}")
# # str 타입인 경우
# elif isinstance(self.toggle_states[key], str):
# if key == "clientID":
# print(f"key : {key}, self.toggle_states[key] : {self.toggle_states[key]}")
# self.update_clientID(self.toggle_states[key])
# elif key == "clientSecret":
# # self.client_secret_input.setText(self.toggle_states[key])
# self.update_clientSecret(self.toggle_states[key])
# elif key == 'watermark':
# self.on_watermark_toggle_clicked(self.toggle_states[key])
# print(f"str key : {key}")
# # 워터마크와 관련된 추가 처리
# if key == 'watermark':
# self.on_watermark_toggle_clicked(self.toggle_states[key])
# elif key == 'opacity_percent':
# self.update_opacity_percent(self.toggle_states[key])
# elif key == 'max_option_count':
# self.update_max_option_count(self.toggle_states[key])
# elif key == 'clientID':
# print(f"self.toggle_states[clientID] : {self.toggle_states[key]}")
# self.update_clientID(self.toggle_states[key])
# elif key == 'clientSecret':
# print(f"self.toggle_states[clientSecret] : {self.toggle_states[key]}")
# self.update_clientSecret(self.toggle_states[key])
def on_watermark_toggle_clicked(self, is_checked):
"""워터마크 토글 여부에 따라 회사 이름 입력 필드와 확인 버튼을 표시/숨김"""
if is_checked:
self.watermark_text_label.setVisible(True)
self.watermark_text_input.setVisible(True)
self.opacity_percent_label.setVisible(True)
self.opacity_percent_input.setVisible(True)
# 워터마크 텍스트 입력 필드의 내용을 딕셔너리에 저장
self.toggle_states['watermark_text'] = self.watermark_text_input.text()
else:
self.watermark_text_label.setVisible(False)
self.watermark_text_input.setVisible(False)
self.opacity_percent_label.setVisible(False)
self.opacity_percent_input.setVisible(False)
def show_message(self, title: str, message: str):
"""
공통적으로 메시지 박스를 표시하는 메서드
:param title: 메시지 박스의 제목
:param message: 메시지 박스의 내용
"""
if not hasattr(self, "_message_box"):
self._message_box = QMessageBox(self) # 메시지 박스를 한 번만 생성
self._message_box.setIcon(QMessageBox.Information)
self._message_box.setWindowTitle(title)
self._message_box.setText(message)
self._message_box.setStandardButtons(QMessageBox.Ok)
self._message_box.exec_()
def update_client_id_input(self):
"""QLineEdit에 입력된 텍스트를 toggle_states['clientID']에 저장하고 메시지 표시"""
# clientID 저장
self.toggle_states['clientID'] = self.client_id_input.text()
self.logger.log(f"Updated client ID: {self.toggle_states['clientID']}", level=logging.DEBUG)
# 메시지 박스를 통해 업데이트 알림
self.show_message("클라이언트 ID 업데이트", "클라이언트 ID가 업데이트되었습니다.")
def update_client_secret_input(self):
"""QLineEdit에 입력된 텍스트를 toggle_states['clientSecret']에 저장하고 메시지 표시"""
# clientSecret 저장
self.toggle_states['clientSecret'] = self.client_secret_input.text()
self.logger.log(f"Updated client secret: {self.toggle_states['clientSecret']}", level=logging.DEBUG)
# 메시지 박스를 통해 업데이트 알림
self.show_message("클라이언트 Secret 업데이트", "클라이언트 Secret이 업데이트되었습니다.")
def update_watermark_text(self):
"""QLineEdit에 입력된 텍스트를 toggle_states['watermark_text']에 저장"""
self.toggle_states['watermark_text'] = self.watermark_text_input.text()
self.logger.log(f"Updated watermark text: {self.toggle_states['watermark_text']}", level=logging.DEBUG)
# 메시지 박스를 통해 업데이트 알림 (값 포함)
self.show_message(
"워터마크 텍스트 업데이트",
f"워터마크 텍스트가 업데이트되었습니다: {self.toggle_states['watermark_text']}"
)
def update_max_option_count(self, value):
"""QSpinBox에 입력된 값을 toggle_states['max_option_count']에 저장"""
self.toggle_states['max_option_count'] = value # 변경된 정수 값을 바로 저장
self.logger.log(f"최대 선택 가능 옵션 수 업데이트: {self.toggle_states['max_option_count']}", level=logging.DEBUG)
def update_opacity_percent(self, value):
"""QSpinBox에 입력된 값을 toggle_states['opacity_percent']에 저장"""
self.toggle_states['opacity_percent'] = value # 변경된 정수 값을 바로 저장
self.logger.log(f"워터마크 투명도 업데이트: {self.toggle_states['opacity_percent']}", level=logging.DEBUG)
def update_clientID(self, value):
self.toggle_states['clientID'] = value # 변경된 정수 값을 바로 저장
self.logger.log(f"clientID 업데이트: {self.toggle_states['clientID']}", level=logging.DEBUG)
def update_clientSecret(self, value):
# self.client_id_input.setText(self.toggle_states[value])
self.toggle_states['clientSecret'] = value # 변경된 정수 값을 바로 저장
self.logger.log(f"clientSecret 업데이트: {self.toggle_states['clientSecret']}", level=logging.DEBUG)
def update_watermark_visibility(self):
"""이미지 번역 토글 중 하나라도 켜져 있으면 워터마크 토글을 보이게 하고, visible이 되면 상태에 따라 레이아웃도 제어"""
if self.toggle_states['optionIMGTrans'] or self.toggle_states['detail_IMGTrans'] or self.toggle_states['thumb']:
# 이미지 번역 토글이 하나라도 켜져 있으면 워터마크 토글 보이기
self.toggle_visibility(True, [(self.watermark_toggle, self.watermark_toggle_label)])
# 워터마크 토글이 보이게 될 때 상태 확인
if self.watermark_toggle.isChecked():
# 워터마크 토글이 ON 상태이면 워터마크 레이아웃도 보이게 함
self.toggle_visibility(True, [(self.watermark_text_input, self.watermark_text_label), (self.opacity_percent_input, self.opacity_percent_label)])
else:
# 워터마크 토글이 OFF 상태이면 워터마크 레이아웃 숨김
self.toggle_visibility(False, [(self.watermark_text_input, self.watermark_text_label), (self.opacity_percent_input, self.opacity_percent_label)])
else:
# 모두 꺼져 있으면 워터마크 토글과 레이아웃 숨기기
self.toggle_visibility(False, [(self.watermark_toggle, self.watermark_toggle_label)])
self.toggle_visibility(False, [(self.watermark_text_input, self.watermark_text_label), (self.opacity_percent_input, self.opacity_percent_label)])
def toggle_visibility(self, is_checked, toggle_items):
"""
토글 상태에 따라 여러 필드의 visibility를 제어하는 범용 메서드
:param is_checked: 토글 상태 (True/False)
:param toggle_items: 토글 필드와 레이블 목록 [(필드, 레이블), ...]
"""
for item, label in toggle_items:
item.setVisible(is_checked)
if label:
label.setVisible(is_checked)
# def update_api_fields_visibility(self, is_checked):
# """
# use_API 토글 버튼 상태에 따라 clientID 및 clientSecretKey 필드를 보이거나 숨기는 메서드
# :param is_checked: use_API 토글 상태 (True/False)
# """
# self.toggle_visibility(is_checked, [
# (self.client_id_input, self.client_id_label),
# (self.client_secret_input, self.client_secret_label)
# ])
def update_widget_positions(self, use_api_row):
"""
위젯의 위치를 동적으로 업데이트 (재배치)
:param use_api_row: use_API 토글이 켜졌을 때 clientID와 clientSecret이 위치할 행
"""
current_row = use_api_row
# 1. use_API 관련 필드 위치 업데이트
self.toggle_layout.addWidget(self.client_id_label, current_row, 0)
self.toggle_layout.addWidget(self.client_id_input, current_row, 1, 1, 2)
self.toggle_layout.addWidget(self.client_secret_label, current_row, 3)
self.toggle_layout.addWidget(self.client_secret_input, current_row, 4, 1, 2)
current_row += 1
self.toggle_layout.addWidget(self.optionTrnas_toggle_label, current_row, 0)
self.toggle_layout.addWidget(self.optionTrnas_toggle, current_row, 1)
self.toggle_layout.addWidget(self.optionIMGTrans_toggle_label, current_row, 2)
self.toggle_layout.addWidget(self.optionIMGTrans_toggle, current_row, 3)
self.toggle_layout.addWidget(self.optionAutoSelect_toggle_label, current_row, 4)
self.toggle_layout.addWidget(self.optionAutoSelect_toggle, current_row, 5)
current_row += 1
self.toggle_layout.addWidget(self.price_toggle_label, current_row, 0)
self.toggle_layout.addWidget(self.price_toggle, current_row, 1)
self.toggle_layout.addWidget(self.tag_toggle_label, current_row, 2)
self.toggle_layout.addWidget(self.tag_toggle, current_row, 3)
self.toggle_layout.addWidget(self.thumb_toggle_label, current_row, 4)
self.toggle_layout.addWidget(self.thumb_toggle, current_row, 5)
current_row += 1
self.toggle_layout.addWidget(self.detail_Option_toggle_label, current_row, 0)
self.toggle_layout.addWidget(self.detail_Option_toggle, current_row, 1)
self.toggle_layout.addWidget(self.detail_IMGTrans_toggle_label, current_row, 2)
self.toggle_layout.addWidget(self.detail_IMGTrans_toggle, current_row, 3)
current_row += 1
self.toggle_layout.addWidget(self.debug_toggle_label, current_row, 0)
self.toggle_layout.addWidget(self.debug_toggle, current_row, 1)
self.toggle_layout.addWidget(self.ed_mode_toggle_label, current_row, 2)
self.toggle_layout.addWidget(self.ed_mode_toggle, current_row, 3)
current_row += 1
self.toggle_layout.addWidget(self.recovery_mode_toggle_label, current_row, 0)
self.toggle_layout.addWidget(self.recovery_mode_toggle, current_row, 1)
current_row += 1
self.toggle_layout.addWidget(self.watermark_toggle_label, current_row, 0)
self.toggle_layout.addWidget(self.watermark_toggle, current_row, 1)
self.toggle_layout.addWidget(self.watermark_text_label, current_row, 2)
self.toggle_layout.addWidget(self.watermark_text_input, current_row, 3)
self.toggle_layout.addWidget(self.opacity_percent_label, current_row, 4)
self.toggle_layout.addWidget(self.opacity_percent_input, current_row, 5)
# self.watermark_layout.addWidget(self.watermark_text_label, 2)
# self.watermark_layout.addWidget(self.watermark_text_input, 3)
# self.watermark_layout.addWidget(self.opacity_percent_label, 4)
# self.watermark_layout.addWidget(self.opacity_percent_input, 5)
# self.watermark_layout.addWidget(self.watermark_confirm_button, 1)
# self.toggle_layout.addWidget(self.opacity_percent_label, current_row, 2)
# self.toggle_layout.addWidget(self.opacity_percent_input, current_row, 3)
# self.toggle_layout.addLayout(self.watermark_layout, current_row, 0, 1, 4)
current_row += 1
self.toggle_layout.addWidget(self.max_option_count_label, current_row, 0)
self.toggle_layout.addWidget(self.max_option_count_input, current_row, 1)
def on_toggle_clicked_generic(self, key, is_checked):
"""토글 클릭 시 상태 업데이트 및 저장"""
self.toggle_states[key] = is_checked
if is_checked:
status_text = "활성화"
else:
status_text = "비활성화"
label_text = ""
# key에 따라 라벨 텍스트를 설정
if key == 'title':
label_text = self.title_toggle_label.text()
elif key == 'optionTrnas':
label_text = self.optionTrnas_toggle_label.text()
elif key == 'optionIMGTrans':
label_text = self.optionIMGTrans_toggle_label.text()
elif key == 'optionAutoSelect':
label_text = self.optionAutoSelect_toggle_label.text()
elif key == 'price':
label_text = self.price_toggle_label.text()
elif key == 'thumb':
label_text = self.thumb_toggle_label.text()
elif key == 'tag':
label_text = self.tag_toggle_label.text()
elif key == 'detail_Option':
label_text = self.detail_Option_toggle_label.text()
elif key == 'detail_IMGTrans':
label_text = self.detail_IMGTrans_toggle_label.text()
elif key == 'debug_mode':
label_text = self.debug_toggle_label.text()
# elif key == 'vd_mode':
# label_text = self.vd_mode_toggle_label.text()
elif key == 'recovery_mode':
label_text = self.recovery_mode_toggle_label.text()
elif key == 'ed_mode':
label_text = self.ed_mode_toggle_label.text()
elif key == 'use_API':
label_text = self.use_API_toggle_label.text()
elif key == 'watermark':
label_text = self.watermark_toggle_label.text()
# 이미지 번역 관련 토글이 하나라도 켜져 있으면 워터마크 토글 보이기
if key in ['optionIMGTrans', 'detail_IMGTrans', 'thumb']:
self.update_watermark_visibility()
# 워터마크 토글이 켜져 있으면 watermark_layout 보이기
if key == 'watermark':
self.toggle_visibility(is_checked, [
(self.watermark_text_input, self.watermark_text_label),
(self.opacity_percent_input, self.opacity_percent_label)
])
# key에 따라 라벨 텍스트를 설정
if key == 'use_API':
self.toggle_visibility(is_checked, [(self.client_id_input, self.client_id_label), (self.client_secret_input, self.client_secret_label)])
# label_text = self.use_API_toggle_label.text()
# use_API 토글 상태에 따라 clientID와 clientSecret 표시 여부
# self.client_id_label.setVisible(is_checked)
# self.client_id_input.setVisible(is_checked)
# self.client_secret_label.setVisible(is_checked)
# self.client_secret_input.setVisible(is_checked)
# 위젯 위치 업데이트
base_row = 1 if is_checked else 2
self.update_widget_positions(use_api_row=base_row)
self.logger.log(f"{label_text} 버튼 - {status_text} 선택", level=logging.DEBUG)
self.save_toggle_settings()
def on_admin_toggle_clicked(self, is_checked):
"""관리자 토글 상태에 따라 관리자와 직원 필드를 표시/숨김"""
if is_checked:
# 관리자 모드: 직원 레이아웃을 숨기고, 관리자 PW를 표시
self.set_layout_visibility(self.admin_layout, True)
self.set_layout_visibility(self.user_layout, False)
else:
# 직원 모드: 관리자 PW를 숨기고, 직원 레이아웃을 표시
self.set_layout_visibility(self.admin_layout, False)
self.set_layout_visibility(self.user_layout, True)
# def on_vd_mode_for_detail_imageTrans_clicked(self, is_checked):
# """상페이미지 번역여부에 따라 VD 모드 선택 필드를 표시/숨김"""
# if is_checked:
# self.vd_mode_toggle.setVisible(True)
# self.vd_mode_toggle_label.setVisible(True)
# else:
# self.vd_mode_toggle.setVisible(False)
# self.vd_mode_toggle_label.setVisible(False)
def set_layout_visibility(self, changelayout, visible):
"""레이아웃에 포함된 모든 위젯의 가시성을 설정"""
for i in range(changelayout.count()):
widget = changelayout.itemAt(i).widget()
if widget:
widget.setVisible(visible)
def on_cmb_test_button_clicked(self, test_cat):
"""크무비 설정 실행 버튼 클릭 시 호출"""
self.logger.log('크무비 테스트 버튼 클릭됨', level=logging.DEBUG)
text, ok = QInputDialog.getText(self, "카테고리 입력 테스트", "카테고리를 형식에 맞게 입력하세요:")
if ok and text: # 사용자가 확인 버튼을 누르고 텍스트를 입력한 경우
stage = self.cmb_diag.get_crmobi_stage(text)
self.logger.log(f"{stage}", level=logging.DEBUG)
def on_cmb_button_clicked(self):
"""크무비 설정 실행 버튼 클릭 시 호출"""
self.logger.log('크무비 설정 버튼 클릭됨', level=logging.DEBUG)
self.cmb_diag.show()
def save_settings(self):
"""QSettings에 사용자 정보 저장"""
self.logger.log(f"현재 설정을 저장합니다.", level=logging.DEBUG)
self.settings.setValue("admin/id", self.admin_id_input.text())
self.settings.setValue("admin/pw", self.admin_pw_input.text())
self.settings.setValue("user/id", self.user_id_input.text())
self.settings.setValue("user/pw", self.user_pw_input.text())
self.settings.setValue("admin/toggle", self.admin_toggle.isChecked())
self.settings.setValue("watermark_text", self.watermark_text_input.text())
self.settings.setValue("opacity_percent", self.opacity_percent_input.value())
self.settings.setValue("max_option_count", self.max_option_count_input.value())
self.settings.setValue("api/toggle", self.use_API_toggle.isChecked())
# API 필드 저장
if self.use_API_toggle.isChecked():
self.settings.setValue("api/client_id", self.client_id_input.text())
self.settings.setValue("api/client_secret", self.client_secret_input.text())
def load_settings(self):
"""QSettings에서 사용자 정보 불러오기"""
self.admin_id_input.setText(self.settings.value("admin/id", "", type=str))
self.admin_pw_input.setText(self.settings.value("admin/pw", "", type=str))
self.user_id_input.setText(self.settings.value("user/id", "", type=str))
self.user_pw_input.setText(self.settings.value("user/pw", "", type=str))
admin_toggle_state = self.settings.value("admin/toggle", False, type=bool)
self.admin_toggle.setChecked(admin_toggle_state)
self.on_admin_toggle_clicked(admin_toggle_state)
self.watermark_text_input.setText(self.settings.value("watermark_text", "", type=str))
self.toggle_states['watermark_text'] = self.watermark_text_input.text()
self.opacity_percent_input.setValue(self.settings.value("opacity_percent", 20, type=int))
self.toggle_states['opacity_percent'] = int(self.opacity_percent_input.text())
self.max_option_count_input.setValue(self.settings.value("max_option_count", 20, type=int))
self.toggle_states['max_option_count'] = int(self.max_option_count_input.text())
# self.update_opacity_percent(self.settings.value("opacity_percent", 20, type=int))
# self.update_max_option_count(self.settings.value("max_option_count", 10, type=int))
# use_API 토글 상태 로드
api_toggle_state = self.settings.value("api/toggle", False, type=bool)
self.use_API_toggle.setChecked(api_toggle_state)
# self.on_toggle_clicked_generic('use_API', api_toggle_state)
# API 필드 로드
self.client_id_input.setText(self.settings.value("api/client_id", "", type=str))
self.toggle_states['clientID'] = self.client_id_input.text()
self.client_secret_input.setText(self.settings.value("api/client_secret", "", type=str))
self.toggle_states['clientSecret'] = self.client_secret_input.text()
self.load_toggle_settings()
def get_toggle_states(self):
"""
현재 UI 상태를 기반으로 toggle_states를 업데이트하고 반환
:return: 업데이트된 toggle_states 딕셔너리
"""
# 각 토글 및 입력 필드 상태를 toggle_states에 업데이트
self.toggle_states['title'] = self.title_toggle.isChecked()
self.toggle_states['use_API'] = self.use_API_toggle.isChecked()
self.toggle_states['clientID'] = bool(self.client_id_input.text().strip())
self.toggle_states['clientSecret'] = bool(self.client_secret_input.text().strip())
self.toggle_states['optionTrnas'] = self.optionTrnas_toggle.isChecked()
self.toggle_states['optionIMGTrans'] = self.optionIMGTrans_toggle.isChecked()
self.toggle_states['optionAutoSelect'] = self.optionAutoSelect_toggle.isChecked()
self.toggle_states['price'] = self.price_toggle.isChecked()
self.toggle_states['thumb'] = self.thumb_toggle.isChecked()
self.toggle_states['tag'] = self.tag_toggle.isChecked()
self.toggle_states['detail_Option'] = self.detail_Option_toggle.isChecked()
self.toggle_states['detail_IMGTrans'] = self.detail_IMGTrans_toggle.isChecked()
self.toggle_states['debug_mode'] = self.debug_toggle.isChecked()
self.toggle_states['recovery_mode'] = self.recovery_mode_toggle.isChecked()
self.toggle_states['ed_mode'] = self.ed_mode_toggle.isChecked()
self.toggle_states['watermark'] = self.watermark_toggle.isChecked()
# 워터마크 텍스트, 투명도, 최대 옵션 수 업데이트
self.toggle_states['watermark_text'] = self.watermark_text_input.text()
self.toggle_states['opacity_percent'] = self.opacity_percent_input.value()
self.toggle_states['max_option_count'] = self.max_option_count_input.value()
# 업데이트된 toggle_states 반환
return self.toggle_states
def update_total_progress(self, current_value, total_value):
if current_value == 0:
self.total_progress_bar.setValue(0)
self.total_progress_bar.setFormat("상품 수정 대기") # current_value가 0일 때 표시될 텍스트
else:
# 프로그레스바의 값과 텍스트를 설정
percentage = int((current_value / total_value) * 100)
self.total_progress_bar.setValue(percentage)
self.total_progress_bar.setFormat(f"상품 {current_value}/{total_value}개 완료 [{percentage}%]")
def update_detail_progress(self, current_value, total_value):
if current_value == 0:
self.detail_progress_bar.setValue(0)
self.detail_progress_bar.setFormat("수정 대기") # current_value가 0일 때 표시될 텍스트
else:
# 프로그레스바의 값과 텍스트를 설정
percentage = int((current_value / total_value) * 100)
self.detail_progress_bar.setValue(percentage)
self.detail_progress_bar.setFormat(f"{current_value}/{total_value}개 완료 [{percentage}%]")
@Slot()
def start_browser_thread(self):
"""브라우저 스레드 시작 및 GUI 상태 전달"""
self.browser_controller.start()
time.sleep(1)
if self.browser_controller.isRunning():
# 스레드를 처음 시작하여 이벤트 루프를 실행
# self.browser_controller.start() # QThread의 start() 호출로 run() 실행
self.logger.log("브라우저 스레드가 시작되었습니다.", level=logging.DEBUG)
self.browser_controller.login_infos = {
'admin_id': self.admin_id_input.text(),
'admin_pw': self.admin_pw_input.text(),
'user_id': self.user_id_input.text(),
'user_pw': self.user_pw_input.text(),
'is_admin': self.admin_toggle.isChecked(),
}
# 로그인 정보 저장
self.save_settings()
# 스레드 시작
self.browser_controller.start_browser_task()
else:
self.logger.log("브라우저 스레드가 실행중이지 않습니다.", level=logging.WARNING)
@Slot()
def on_browser_started(self):
"""브라우저 시작 완료 시 처리할 로직"""
self.logger.log("브라우저가 성공적으로 시작되었습니다.", level=logging.INFO)
# 버튼 상태 활성화&비활성화
self.PercentyJob_button.setEnabled(True)
self.pause_button.setEnabled(True)
self.start_chrome_button.setEnabled(False)
@Slot(str)
def on_browser_error(self, error_message):
"""브라우저 오류 발생 시 처리할 로직"""
self.logger.log(f"브라우저 시작 중 오류 발생: {error_message}", level=logging.ERROR)
def closeEvent(self, event):
"""창 닫기 시 스레드 종료"""
self.logger.log('프로그램을 종료합니다...', level=logging.INFO)
self.save_settings()
if self.browser_controller.isRunning():
self.browser_controller.stop() # 리소스 정리
self.browser_controller.wait() # 스레드가 종료될 때까지 대기
event.accept()
# def close(self):
# self.logger.log('프로그램을 종료합니다...', level=logging.INFO)
# self.save_settings()
# asyncio.run(self.browser_controller.close_browser()) # 브라우저 종료
# super().close()
@Slot()
def on_start_PercentyJob_clicked(self):
"""상품수정 스레드 시작 및 상태 전달"""
if self.browser_controller.isRunning():
# 스레드 시작
self.browser_controller.start_PercentyJob_task()
self.logger.log("상품수정 작업 스레드가 시작되었습니다.", level=logging.INFO)
else:
self.logger.log("브라우저 스레드가 없습니다.", level=logging.INFO)
@Slot()
def on_PercentyJob_started(self):
"""상품수정 시작 완료 시 처리할 로직"""
self.logger.log("상품수정 작업이 성공적으로 시작되었습니다.", level=logging.INFO)
self.PercentyJob_button.setEnabled(False)
@Slot()
def on_PercentyJob_completed(self):
"""상품수정 완료 시 처리할 로직"""
self.logger.log("상품수정 작업이 완료되었습니다.", level=logging.INFO)
self.PercentyJob_button.setEnabled(True)
@Slot(str)
def on_PercentyJob_error(self, error_message):
"""상품수정 중 오류 발생 시 처리할 로직"""
self.logger.log(f"상품수정 작업 중 오류 발생: {error_message}", level=logging.ERROR)
self.PercentyJob_button.setEnabled(True)
@Slot(bool)
def set_progress_visibility(self, visible):
self.detail_progress_bar.setVisible(visible)
self.detail_progress_bar.setValue(0)
@Slot(bool)
def update_detail_progress_value(self, current, total):
self.update_detail_progress(current, total)
@Slot(bool)
def percentyJob_button_Enable(self, Enable):
self.PercentyJob_button.setEnabled(Enable)