using System; using System.Collections.ObjectModel; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using JJServiceManager.Remote; namespace JJServiceManager { /// 설정 화면 (탭: 일반 / 원격 접속 허용 / 관리 대상 PC) public sealed class SettingsWindow : Window { private readonly AppSettings _s; // 일반 private readonly CheckBox _startup, _hotkey, _opLog, _shutdownButtons, _confirmLocal, _confirmRemote; private readonly TextBox _hotkeyBox; private readonly ComboBox _logMode, _esc; private ModifierKeys _mods; private Key _key; // 원격 접속 허용 private readonly CheckBox _server, _activeListen, _allowView, _allowControl, _requireApproval; private readonly ComboBox _serverMode; private readonly TextBox _serverPort; private readonly TextBlock _serverPortHint, _pwState, _serverInfo; private readonly PasswordBox _pwd1, _pwd2; private int _sshPort, _tcpPort; private int _shownMode = -1; // Passive 접속 (대상 PC 쪽) private readonly ListBox _pmList; private readonly TextBox _pmAddr, _pmCode, _pmPort; private readonly ComboBox _pmMode; private readonly TextBlock _pmResult; private readonly ObservableCollection _pms = new ObservableCollection(); // 관리 대상 PC private readonly CheckBox _manage; private readonly ComboBox _passiveMode; private readonly TextBox _passivePort; private int _passiveSshPort, _passiveTcpPort; private int _shownPassiveMode = -1; private readonly ListBox _targets; private readonly TextBox _addr, _hostname, _port, _code; private readonly ComboBox _mode, _direction; private readonly PasswordBox _pwdTarget; private readonly TextBlock _pwTargetState, _test, _lblAddr; private readonly FrameworkElement _lblMode, _lblPort, _lblCode, _pnlCode; private readonly Button _btnTest; private readonly ObservableCollection _items = new ObservableCollection(); /// 목록 표시용 private sealed class TargetItem : ObservableObject { public RemoteTarget T { get; } public TargetItem(RemoteTarget t) => T = t; public string Label => T.Label; public string ModeText => T.Direction == ConnectDirection.Passive ? "Passive · 코드 " + T.AccessCode : "Active · " + (T.Mode == RemoteMode.Ssh ? "SSH" : "지정 포트") + " " + T.Port; public void Changed() { OnPropertyChanged(nameof(Label)); OnPropertyChanged(nameof(ModeText)); } } public SettingsWindow(AppSettings current) { _s = current; Title = "설정" + AppInstance.TitleTag; Width = 800; Height = 720; MinHeight = 560; ResizeMode = ResizeMode.CanResize; FontFamily = new FontFamily("Malgun Gothic"); FontSize = 13; Background = Brushes2.Make("#FAFAFA"); WindowStartupLocation = WindowStartupLocation.CenterOwner; ShowInTaskbar = false; AppIcon.Apply(this); var root = XamlLoader.LoadElement("Settings.xaml"); Content = root; // ───────── 일반 ───────── _startup = root.Find("chkStartup"); _hotkey = root.Find("chkHotkey"); _opLog = root.Find("chkOpLog"); _shutdownButtons = root.Find("chkShutdownButtons"); _confirmLocal = root.Find("chkConfirmLocal"); _confirmRemote = root.Find("chkConfirmRemote"); _hotkeyBox = root.Find("txtHotkey"); _logMode = root.Find("cmbLogMode"); _esc = root.Find("cmbEsc"); root.Find("txtDataPath").Text = "설정 파일: " + SettingsStore.SettingsPath + "\n작업 로그 파일: " + OperationLogFile.Folder; _startup.IsChecked = current.RunAtStartup; _hotkey.IsChecked = current.HotkeyEnabled; _opLog.IsChecked = current.ShowOperationLog; _shutdownButtons.IsChecked = current.ShowShutdownButtons; _confirmLocal.IsChecked = current.ConfirmLocalStartStop; _confirmRemote.IsChecked = current.ConfirmRemoteStartStop; _logMode.SelectedIndex = (int)current.LogWindowMode; _esc.SelectedIndex = (int)current.EscAction; _mods = (ModifierKeys)current.HotkeyModifiers; _key = (Key)current.HotkeyKey; ShowHotkey(); // 단축키: 클릭 후 직접 눌러서 지정 _hotkeyBox.GotKeyboardFocus += (s, e) => _hotkeyBox.Background = Brushes2.Make("#FFF8E1"); _hotkeyBox.LostKeyboardFocus += (s, e) => { _hotkeyBox.Background = Brushes2.Make("#FAFAFA"); ShowHotkey(); }; _hotkeyBox.PreviewKeyDown += OnHotkeyKeyDown; // ───────── 원격 접속 허용 ───────── _server = root.Find("chkServer"); _activeListen = root.Find("chkActiveListen"); _allowView = root.Find("chkAllowView"); _allowControl = root.Find("chkAllowControl"); _requireApproval = root.Find("chkRequireApproval"); _serverMode = root.Find("cmbServerMode"); _serverPort = root.Find("txtServerPort"); _serverPortHint = root.Find("txtServerPortHint"); _pwd1 = root.Find("pwdServer"); _pwd2 = root.Find("pwdServer2"); _pwState = root.Find("txtPwState"); _serverInfo = root.Find("txtServerInfo"); _sshPort = current.RemoteServerSshPort; _tcpPort = current.RemoteServerTcpPort; _server.IsChecked = current.RemoteServerEnabled; _activeListen.IsChecked = current.RemoteServerActiveListen; _allowView.IsChecked = current.RemoteAllowView; _allowControl.IsChecked = current.RemoteAllowControl; _requireApproval.IsChecked = current.RemoteRequireApproval; _serverMode.SelectionChanged += (s, e) => OnServerModeChanged(); _serverMode.SelectedIndex = (int)current.RemoteServerMode; _pwState.Text = string.IsNullOrEmpty(current.RemotePasswordHash) ? "비밀번호가 설정되어 있지 않습니다. 원격 접속을 허용하려면 입력하세요." : "비밀번호가 설정되어 있습니다. 바꿀 때만 입력하세요."; // 제어 허용은 화면 보기가 켜져 있어야 함 _allowView.Checked += (s, e) => _allowControl.IsEnabled = true; _allowView.Unchecked += (s, e) => { _allowControl.IsChecked = false; _allowControl.IsEnabled = false; }; _allowControl.IsEnabled = _allowView.IsChecked == true; UpdateServerInfo(); // Passive 접속 (이 PC → 관리 PC) _pmList = root.Find("lstPassive"); _pmAddr = root.Find("txtPmAddr"); _pmCode = root.Find("txtPmCode"); _pmPort = root.Find("txtPmPort"); _pmMode = root.Find("cmbPmMode"); _pmResult = root.Find("txtPmResult"); foreach (var m in current.PassiveManagers) _pms.Add(m.Clone()); _pmList.ItemsSource = _pms; _pmList.SelectionChanged += (s, e) => ShowPm(_pmList.SelectedItem as PassiveManager); _pmMode.SelectionChanged += (s, e) => { if (_pmPort.Text == "" || _pmPort.Text == "9990" || _pmPort.Text == "2224") _pmPort.Text = _pmMode.SelectedIndex == 0 ? "2224" : "9990"; }; ClearPmForm(); root.Find