# 画面設計書 31-NewTabMenu（新規タブメニュー設定）

## 概要

本ドキュメントは、Windows Terminal の設定画面における「新規タブメニュー設定」画面（NewTabMenu）の設計仕様を記述する。新規タブボタン押下時に表示されるメニューの構成を視覚的に管理するための設定ページである。

### 本画面の処理概要

**業務上の目的・背景**：ユーザーが新規タブを作成する際に表示されるドロップダウンメニューの項目構成をカスタマイズするための画面である。デフォルトでは全プロファイルが一覧表示されるが、フォルダによるグルーピング、セパレータの追加、正規表現によるプロファイルマッチング、アクションエントリの追加など、柔軟なメニュー構成が可能となる。これにより、多数のプロファイルを持つユーザーが効率的にメニューを整理できる。

**画面へのアクセス方法**：メイン画面（TerminalPage）から Ctrl+, で設定画面（MainPage）を開き、左側ナビゲーションの「新規タブメニュー」項目を選択して遷移する。

**主要な操作・処理内容**：
1. メニューエントリの一覧表示とドラッグ＆ドロップによる並べ替え
2. プロファイルエントリの追加（ComboBoxで選択し追加ボタン押下）
3. セパレータエントリの追加
4. フォルダエントリの追加（名前を入力して追加）
5. プロファイルマッチャーエントリの追加（正規表現による名前・ソース・コマンドラインマッチング）
6. 残余プロファイルエントリの追加（他のエントリでカバーされないプロファイルを自動追加）
7. エントリの上下移動（ReorderUp/ReorderDown ボタン）
8. エントリの削除（個別削除および複数選択一括削除）
9. エントリのフォルダへの移動（FolderPickerDialog でフォルダを選択）
10. フォルダビューでのフォルダ名編集・インライン設定・空フォルダ許可設定

**画面遷移**：MainPage（設定ナビゲーション）から遷移して表示される。フォルダの編集ボタンをクリックするとフォルダビュー（同一ページ内での表示切替）に遷移する。

**権限による表示制御**：特に権限による表示制御は行われない。ただし、RemainingProfilesエントリが既に存在する場合は追加ボタンが無効化される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 82 | 設定の読み込み・保存 | 主機能 | 新規タブメニューのプロファイル一覧とフォルダ構成の管理 |
| 84 | 設定UI | 主機能 | 新規タブメニュー設定のUI表示 |

## 画面種別

設定（一覧＋編集のハイブリッド画面）

## URL/ルーティング

設定画面内のNavigationViewによるページ遷移。タグ値は `NewTabMenu_Nav`。MainPage の ContentFrame に `NewTabMenu` ページがナビゲートされる。

## 入出力項目

### メニューエントリ一覧（ListView）

| No | 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|----|--------|-----|----------|------|------|
| 1 | エントリ一覧 | ListView | 出力 | - | 現在のメニュー構成を表示。ドラッグ＆ドロップ対応。複数選択可能 |
| 2 | 上へ移動ボタン | Button | 入力 | - | 各エントリの並び順を上に移動 |
| 3 | 下へ移動ボタン | Button | 入力 | - | 各エントリの並び順を下に移動 |
| 4 | 削除ボタン | Button | 入力 | - | 各エントリを削除 |
| 5 | フォルダ編集ボタン | Button | 入力 | - | フォルダエントリの場合に表示。フォルダビューに遷移 |

### 一括操作

| No | 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|----|--------|-----|----------|------|------|
| 6 | フォルダに移動ボタン | Button | 入力 | - | 選択エントリをフォルダに移動。項目選択時に有効化 |
| 7 | 一括削除ボタン | Button | 入力 | - | 選択エントリを一括削除。項目選択時に有効化 |

### フォルダ設定（フォルダビュー時のみ表示）

| No | 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|----|--------|-----|----------|------|------|
| 8 | フォルダ名 | TextBox | 入力 | はい | 現在のフォルダ名。双方向バインド |
| 9 | インライン | ToggleSwitch | 入力 | - | フォルダをインライン表示するか |
| 10 | 空フォルダ許可 | ToggleSwitch | 入力 | - | 空のフォルダを表示するか |

### エントリ追加

| No | 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|----|--------|-----|----------|------|------|
| 11 | プロファイル選択 | ComboBox | 入力 | - | 追加するプロファイルを選択 |
| 12 | プロファイル追加ボタン | Button | 入力 | - | 選択したプロファイルをエントリに追加 |
| 13 | セパレータ追加ボタン | Button | 入力 | - | セパレータエントリを追加 |
| 14 | フォルダ名入力 | TextBox | 入力 | - | 新規フォルダ名を入力 |
| 15 | フォルダ追加ボタン | Button | 入力 | - | 指定名のフォルダエントリを追加。フォルダ名が空の場合無効 |
| 16 | プロファイルマッチャー名 | TextBox | 入力 | - | マッチングルールの名前 |
| 17 | プロファイルマッチャーソース | TextBox | 入力 | - | ソースの正規表現パターン |
| 18 | プロファイルマッチャーコマンドライン | TextBox | 入力 | - | コマンドラインの正規表現パターン |
| 19 | プロファイルマッチャー追加ボタン | Button | 入力 | - | マッチングルールをエントリに追加 |
| 20 | 残余プロファイル追加ボタン | Button | 入力 | - | 残余プロファイルエントリを追加。既存の場合は無効 |

## 表示項目

| No | 項目名 | 表示形式 | 説明 |
|----|--------|----------|------|
| 1 | プロファイルエントリ | アイコン + プロファイル名 | プロファイルのアイコンと名前を表示 |
| 2 | アクションエントリ | アイコン（任意） + 表示テキスト | アクションのアイコンとテキストを表示 |
| 3 | セパレータエントリ | イタリック体テキスト「Separator」 | セパレータを示す |
| 4 | フォルダエントリ | アイコン（任意） + フォルダ名 | フォルダのアイコンと名前を表示 |
| 5 | マッチプロファイルエントリ | イタリック体テキスト | マッチング条件の説明テキスト |
| 6 | 残余プロファイルエントリ | イタリック体テキスト「Remaining profiles」 | 残りのプロファイルを示す |

## イベント仕様

### 1-エントリ追加（プロファイル）

AddProfileButton_Clicked イベントハンドラにより、ViewModel.SelectedProfile で選択されたプロファイルを ViewModel.RequestAddSelectedProfileEntry() で追加し、リストの末尾にスクロールする。

### 2-エントリ追加（セパレータ）

AddSeparatorButton_Clicked イベントハンドラにより、ViewModel.RequestAddSeparatorEntry() でセパレータエントリを追加する。

### 3-エントリ追加（フォルダ）

AddFolderButton_Clicked イベントハンドラにより、ViewModel.RequestAddFolderEntry() でフォルダエントリを追加する。フォルダ名入力が空の場合はボタンが無効化される。Enter キーでも追加可能（AddFolderNameTextBox_KeyDown）。

### 4-エントリ追加（マッチプロファイル）

AddMatchProfilesButton_Clicked イベントハンドラにより、ViewModel.RequestAddProfileMatcherEntry() でプロファイルマッチャーエントリを追加する。名前・ソース・コマンドラインの正規表現パターンがバインドされる。

### 5-エントリ追加（残余プロファイル）

AddRemainingProfilesButton_Clicked イベントハンドラにより、ViewModel.RequestAddRemainingProfilesEntry() で残余プロファイルエントリを追加する。既に存在する場合はボタンが無効化される（IsRemainingProfilesEntryMissing プロパティ）。

### 6-エントリ並べ替え

ReorderEntry_Clicked イベントハンドラにより、ボタンの Tag（"Up" または "Down"）に応じて ViewModel.RequestReorderEntry() でエントリの順序を変更する。

### 7-エントリ削除（個別）

DeleteEntry_Clicked イベントハンドラにより、ViewModel.RequestDeleteEntry() でエントリを削除する。

### 8-エントリ一括削除

DeleteMultiple_Click イベントハンドラにより、ListView の選択項目を取得し、各エントリに対して ViewModel.RequestDeleteEntry() を呼び出す。

### 9-フォルダに移動

MoveMultiple_Click イベントハンドラにより、FolderPickerDialog を表示する。ダイアログでフォルダを選択して OK すると、ViewModel.RequestMoveEntriesToFolder() で選択エントリを指定フォルダに移動する。

### 10-フォルダ編集

EditEntry_Clicked イベントハンドラにより、FolderEntryViewModel を取得し、ViewModel.CurrentFolder() を設定してフォルダビューに遷移する。

### 11-選択状態変更

NewTabMenuListView の SelectionChanged イベントにより、選択項目数に応じて MoveToFolderButton と DeleteMultipleButton の有効/無効を切り替える。

## データベース更新仕様

### 操作別データベース影響一覧

本画面はデータベースを使用しない。設定は settings.json ファイルに保存される。

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| エントリ追加 | settings.json (newTabMenu) | UPDATE | メニューエントリを追加 |
| エントリ削除 | settings.json (newTabMenu) | UPDATE | メニューエントリを削除 |
| エントリ並べ替え | settings.json (newTabMenu) | UPDATE | メニューエントリの順序を変更 |
| フォルダ設定変更 | settings.json (newTabMenu) | UPDATE | フォルダの名前・インライン・空許可設定を変更 |

## メッセージ仕様

| No | メッセージID | 種別 | メッセージ内容 | 表示条件 |
|----|-------------|------|---------------|----------|
| 1 | N/A | 情報 | 正規表現ヘルプリンク | マッチプロファイル追加セクションに常時表示 |

## 例外処理

- フォルダ名が空の場合、フォルダ追加ボタンが無効化される（AddFolderNameTextBox_TextChanged で制御）
- 残余プロファイルエントリが既に存在する場合、追加ボタンが無効化される（IsRemainingProfilesEntryMissing バインド）
- 選択項目が0件の場合、フォルダへ移動ボタンと一括削除ボタンが無効化される

## 備考

- エントリの種別は NewTabMenuEntryType 列挙型で管理される（Profile, Action, Separator, Folder, MatchProfiles, RemainingProfiles, Invalid）
- NewTabMenuEntryTemplateSelector により、エントリの種別に応じたデータテンプレートが自動選択される
- フォルダビューは同一ページ内での表示切替であり、ViewModel.IsFolderView プロパティで制御される
- ListView は AllowDrop=True, CanDragItems=True, CanReorderItems=True でドラッグ＆ドロップによる並べ替えに対応
- FolderPickerDialog は遅延読み込み（x:Load="False"）で、MoveMultiple_Click 時に動的に読み込まれる

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

メニューエントリの種別とビューモデルの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | NewTabMenuViewModel.idl | `src/cascadia/TerminalSettingsEditor/NewTabMenuViewModel.idl` | NewTabMenuViewModel と各エントリビューモデル（ProfileEntryViewModel, ActionEntryViewModel, SeparatorEntryViewModel, FolderEntryViewModel, MatchProfilesEntryViewModel, RemainingProfilesEntryViewModel）のインターフェース定義を確認する |
| 1-2 | NewTabMenu.idl | `src/cascadia/TerminalSettingsEditor/NewTabMenu.idl` | ページクラスとテンプレートセレクタのインターフェースを確認する |

**読解のコツ**: IDL ファイルで定義されたプロパティやイベントが、XAML のバインディングやコードビハインドのイベントハンドラに対応している。

#### Step 2: エントリーポイントを理解する

MainPage からの遷移と NewTabMenu ページの初期化を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MainPage.cpp | `src/cascadia/TerminalSettingsEditor/MainPage.cpp` | 47行目: newTabMenuTag 定数定義。68行目: NewTabMenuViewModel の生成。ナビゲーション時に NewTabMenuViewModel をパラメータとして渡す |
| 2-2 | NewTabMenu.cpp | `src/cascadia/TerminalSettingsEditor/NewTabMenu.cpp` | 19-40行目: コンストラクタで ListView の SelectionChanged イベント登録とアクセシビリティ名設定。42-53行目: OnNavigatedTo で ViewModel を受け取る |

**主要処理フロー**:
1. **19行目**: InitializeComponent() で XAML を初期化
2. **26-30行目**: SelectionChanged イベントで複数選択ボタンの有効/無効を制御
3. **42-53行目**: OnNavigatedTo で ViewModel を受け取り、テレメトリを送信

#### Step 3: XAML レイアウトを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NewTabMenu.xaml | `src/cascadia/TerminalSettingsEditor/NewTabMenu.xaml` | 16-227行目: DataTemplate 定義（6種類のエントリテンプレート）。230-490行目: ページレイアウト（エントリ一覧、フォルダ設定、エントリ追加セクション） |

#### Step 4: イベントハンドラを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | NewTabMenu.cpp | `src/cascadia/TerminalSettingsEditor/NewTabMenu.cpp` | 78-173行目: 各種イベントハンドラの実装。EditEntry_Clicked, ReorderEntry_Clicked, DeleteEntry_Clicked, AddXxx_Clicked 等 |
| 4-2 | NewTabMenu.cpp | `src/cascadia/TerminalSettingsEditor/NewTabMenu.cpp` | 175-206行目: NewTabMenuEntryTemplateSelector の実装。エントリ種別に応じたテンプレート選択ロジック |

#### Step 5: ビューモデルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | NewTabMenuViewModel.h | `src/cascadia/TerminalSettingsEditor/NewTabMenuViewModel.h` | ViewModel の構造体定義。CurrentView, AvailableProfiles, FolderTree 等のプロパティと RequestXxx メソッドを確認する |
| 5-2 | NewTabMenuViewModel.cpp | `src/cascadia/TerminalSettingsEditor/NewTabMenuViewModel.cpp` | ViewModel のロジック実装。エントリの追加・削除・並べ替え・フォルダ移動の詳細処理を確認する |

### プログラム呼び出し階層図

```
MainPage (設定ナビゲーション)
    |
    +-- NewTabMenu (ページ)
    |       |
    |       +-- NewTabMenuViewModel (ビューモデル)
    |       |       |
    |       |       +-- RequestAddSelectedProfileEntry()
    |       |       +-- RequestAddSeparatorEntry()
    |       |       +-- RequestAddFolderEntry()
    |       |       +-- RequestAddProfileMatcherEntry()
    |       |       +-- RequestAddRemainingProfilesEntry()
    |       |       +-- RequestReorderEntry()
    |       |       +-- RequestDeleteEntry()
    |       |       +-- RequestMoveEntriesToFolder()
    |       |       +-- GenerateFolderTree()
    |       |
    |       +-- NewTabMenuEntryTemplateSelector
    |               |
    |               +-- SelectTemplateCore()
    |                       +-- ProfileEntryTemplate
    |                       +-- ActionEntryTemplate
    |                       +-- SeparatorEntryTemplate
    |                       +-- FolderEntryTemplate
    |                       +-- MatchProfilesEntryTemplate
    |                       +-- RemainingProfilesEntryTemplate
    |
    +-- settings.json (保存先)
```

### データフロー図

```
[入力]                          [処理]                              [出力]

ユーザー操作               NewTabMenu.cpp                   NewTabMenuViewModel
(ボタン押下/              (イベントハンドラ)                (設定モデル更新)
 ドラッグ&ドロップ)
                                |                                |
プロファイル選択 --------> AddProfileButton_Clicked ------> RequestAddSelectedProfileEntry()
フォルダ名入力 ----------> AddFolderButton_Clicked -------> RequestAddFolderEntry()
エントリ選択 ------------> ReorderEntry_Clicked ----------> RequestReorderEntry()
                           DeleteEntry_Clicked -----------> RequestDeleteEntry()
                           MoveMultiple_Click ------------> FolderPickerDialog
                                                             |
                                                   FolderPickerDialog_PrimaryButtonClick
                                                             |
                                                   RequestMoveEntriesToFolder()
                                                             |
                                                        settings.json に反映
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NewTabMenu.xaml | `src/cascadia/TerminalSettingsEditor/NewTabMenu.xaml` | ソース | ページのXAMLレイアウト定義 |
| NewTabMenu.cpp | `src/cascadia/TerminalSettingsEditor/NewTabMenu.cpp` | ソース | ページのコードビハインド（イベントハンドラ） |
| NewTabMenu.h | `src/cascadia/TerminalSettingsEditor/NewTabMenu.h` | ソース | ページのヘッダー定義 |
| NewTabMenu.idl | `src/cascadia/TerminalSettingsEditor/NewTabMenu.idl` | ソース | WinRT インターフェース定義 |
| NewTabMenuViewModel.cpp | `src/cascadia/TerminalSettingsEditor/NewTabMenuViewModel.cpp` | ソース | ビューモデルの実装 |
| NewTabMenuViewModel.h | `src/cascadia/TerminalSettingsEditor/NewTabMenuViewModel.h` | ソース | ビューモデルのヘッダー定義 |
| NewTabMenuViewModel.idl | `src/cascadia/TerminalSettingsEditor/NewTabMenuViewModel.idl` | ソース | ビューモデルのWinRTインターフェース定義 |
| MainPage.cpp | `src/cascadia/TerminalSettingsEditor/MainPage.cpp` | ソース | 設定画面のメインページ（ナビゲーション管理） |
| CommonResources.xaml | `src/cascadia/TerminalSettingsEditor/CommonResources.xaml` | リソース | 共通スタイル・テンプレートリソース |
