"""탭2: PC시간 동기화 패널""" import tkinter as tk from tkinter import ttk import threading from datetime import datetime from models.controller import Controller from services.time_sync_service import sync_all class SyncPanel(ttk.Frame): """PC 시간 동기화 패널.""" def __init__(self, parent, shared_controllers: list[Controller]): super().__init__(parent) self._controllers = shared_controllers self._check_vars: list[tk.BooleanVar] = [] self._syncing = False self._build_ui() self._update_clock() def _build_ui(self): # --- 상단: 현재 PC 시간 --- top = ttk.LabelFrame(self, text="현재 PC 시간", padding=10) top.pack(fill=tk.X, padx=5, pady=5) self._clock_label = ttk.Label(top, text="", font=("Consolas", 18)) self._clock_label.pack() # --- 중간: 컨트롤러 체크리스트 --- mid = ttk.LabelFrame(self, text="동기화 대상 컨트롤러", padding=5) mid.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) btn_row = ttk.Frame(mid) btn_row.pack(fill=tk.X) ttk.Button(btn_row, text="전체 선택", command=self._select_all).pack(side=tk.LEFT, padx=2) ttk.Button(btn_row, text="전체 해제", command=self._deselect_all).pack(side=tk.LEFT, padx=2) ttk.Button(btn_row, text="목록 새로고침", command=self.refresh_list).pack(side=tk.LEFT, padx=2) self._check_frame = ttk.Frame(mid) self._check_frame.pack(fill=tk.BOTH, expand=True, pady=5) # --- 하단: 동기화 실행 + 결과 --- bot = ttk.LabelFrame(self, text="동기화", padding=5) bot.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self._btn_sync = ttk.Button(bot, text="동기화 실행", command=self._on_sync) self._btn_sync.pack(pady=5) self._log = tk.Text(bot, height=8, state=tk.DISABLED, wrap=tk.WORD) self._log.pack(fill=tk.BOTH, expand=True) def _update_clock(self): now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self._clock_label.config(text=now) self.after(1000, self._update_clock) def refresh_list(self): """컨트롤러 체크리스트 갱신.""" for w in self._check_frame.winfo_children(): w.destroy() self._check_vars.clear() for ctrl in self._controllers: var = tk.BooleanVar(value=ctrl.selected) self._check_vars.append(var) cb = ttk.Checkbutton( self._check_frame, text=ctrl.display_label, variable=var, command=lambda c=ctrl, v=var: setattr(c, "selected", v.get()), ) cb.pack(anchor=tk.W) def _select_all(self): for var in self._check_vars: var.set(True) for ctrl in self._controllers: ctrl.selected = True def _deselect_all(self): for var in self._check_vars: var.set(False) for ctrl in self._controllers: ctrl.selected = False def _log_message(self, msg: str): self._log.config(state=tk.NORMAL) self._log.insert(tk.END, msg + "\n") self._log.see(tk.END) self._log.config(state=tk.DISABLED) def _on_sync(self): if self._syncing: return selected = [c for c in self._controllers if c.selected] if not selected: self._log_message("동기화할 컨트롤러가 없습니다.") return self._syncing = True self._btn_sync.config(state=tk.DISABLED) self._log_message(f"--- 동기화 시작: {datetime.now().strftime('%H:%M:%S')} ---") threading.Thread(target=self._sync_thread, daemon=True).start() def _sync_thread(self): results = sync_all(self._controllers) self.after(0, self._sync_done, results) def _sync_done(self, results): self._syncing = False self._btn_sync.config(state=tk.NORMAL) ok_count = 0 for ctrl, ok, msg in results: status = "OK" if ok else "FAIL" self._log_message(f" [{status}] {ctrl.display_label}: {msg}") if ok: ok_count += 1 total = len(results) self._log_message(f"--- 완료: {ok_count}/{total} 성공 ---\n")