Files
time_manager/gui/sync_panel.py
insulee 3c14e1e401 Initial commit: Dabit Time Manager project
Python-based time management application with UDP discovery,
TCP protocol communication, time sync, and drift monitoring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 11:10:55 +09:00

125 lines
4.3 KiB
Python

"""탭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")