# 帳票設計書 8-ウィンドウレイアウトJSON出力

## 概要

本ドキュメントは、Windows Terminal のウィンドウの配置・サイズ・タブ構成等のレイアウト情報をJSON形式でシリアライズする処理の設計を記述する。ウィンドウ復元時に使用される。

### 本帳票の処理概要

WindowLayout オブジェクトが保持するウィンドウレイアウト情報（タブの構成と順序、初期ウィンドウ位置、初期ウィンドウサイズ、起動モード）をJSON形式にシリアライズする。このJSON文字列は ApplicationState の persistedWindowLayouts フィールドの一部として state.json に永続化される。

**業務上の目的・背景**：アプリケーション終了時のウィンドウ状態を保存し、次回起動時に同じレイアウト（ウィンドウ位置・サイズ・タブ構成）を復元するための情報を提供する。マルチウィンドウ環境では各ウィンドウのレイアウトが個別に保存される。

**帳票の利用シーン**：アプリケーション終了時、またはウィンドウの状態永続化が必要な場面で使用される。保存されたレイアウトは次回起動時に復元される。また、WindowLayout::ToJson() は個別のレイアウトをJSON文字列に変換するユーティリティとしても利用可能。

**主要な出力内容**：
1. タブレイアウト（tabLayout）：各タブの再作成に必要なアクションとその引数の配列
2. 初期位置（initialPosition）：ウィンドウの初期配置座標
3. 初期サイズ（initialSize）：ウィンドウの初期サイズ
4. 起動モード（launchMode）：ウィンドウの起動モード（通常/最大化等）

**帳票の出力タイミング**：ApplicationState 経由でウィンドウレイアウトが永続化される際。AppendPersistedWindowLayout() の呼び出しを経て、スロットリング付きで state.json に書き込まれる。

**帳票の利用者**：Windows Terminal アプリケーション自身（ウィンドウ復元機能の内部データ）。

## 帳票種別

状態シリアライズ（JSONデータ構造出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | なし（自動） | - | アプリケーション終了時 / ウィンドウ状態保存時 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（state.json 内の persistedWindowLayouts 配列要素として） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | state.json の一部（直接ファイル出力はしない） |
| 出力方法 | ApplicationState 経由で state.json に含まれる |
| 文字コード | UTF-8 |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

WindowLayout は4つのプロパティを持つJSONオブジェクトとしてシリアライズされる。state.json の persistedWindowLayouts 配列の各要素として格納される。

```
┌─────────────────────────────────────┐
│ {                                   │
│   "tabLayout": [                    │
│     {                               │
│       "action": "...",              │
│       "args": { ... }               │
│     },                              │
│     ...                             │
│   ],                                │
│   "initialPosition": "x,y",        │
│   "initialSize": { ... },          │
│   "launchMode": "..."              │
│ }                                   │
└─────────────────────────────────────┘
```

### ヘッダー部

該当なし

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|------|
| 1 | tabLayout | タブの構成情報（ActionAndArgs の配列） | WindowLayout::TabLayout() | JSON配列 | 可変 |
| 2 | initialPosition | ウィンドウの初期位置座標 | WindowLayout::InitialPosition() | JSON文字列 ("x,y") | 可変 |
| 3 | initialSize | ウィンドウの初期サイズ | WindowLayout::InitialSize() | JSONオブジェクト (Width, Height) | 可変 |
| 4 | launchMode | 起動モード（default/maximized等） | WindowLayout::LaunchMode() | JSON文字列 | 可変 |

### フッター部

該当なし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| WindowLayout オブジェクト | シリアライズ対象のレイアウト情報 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | tabLayout 内のアクション | タブ追加順（登録順） |

### 改ページ条件

該当なし

## データベース参照仕様

### 参照テーブル一覧

該当なし（メモリ上の WindowLayout オブジェクトからデータを取得する）

### テーブル別参照項目詳細

#### WindowLayout（メモリ上レイアウトオブジェクト）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| TabLayout | tabLayout | - | IVector\<ActionAndArgs\>、null可能 |
| InitialPosition | initialPosition | - | IReference\<LaunchPosition\>、null可能 |
| InitialSize | initialSize | - | IReference\<Size\>、null可能 |
| LaunchMode | launchMode | - | IReference\<LaunchMode\>、null可能 |

## 計算仕様

### 計算項目一覧

該当なし（プロパティの値をそのままJSONに変換する）

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[ウィンドウ状態保存要求] --> B[ApplicationState::AppendPersistedWindowLayout]
    B --> C[persistedWindowLayouts に追加]
    C --> D[_throttler 起動 1秒デバウンス]
    D --> E[_write 呼び出し]
    E --> F[ToJson FileSource::Local]
    F --> G[JsonUtils::SetValueForKey persistedWindowLayouts]
    G --> H[ConversionTrait WindowLayout::ToJson 呼び出し]
    H --> I[各プロパティを JSON キーに設定]
    I --> J[state.json に書き込み]
    J --> K[終了]
```

### WindowLayout::ToJson 単独呼び出しフロー

```mermaid
flowchart TD
    A[WindowLayout::ToJson 静的メソッド呼び出し] --> B[ConversionTrait ToJson 呼び出し]
    B --> C[tabLayout を SetValueForKey]
    C --> D[initialPosition を SetValueForKey]
    D --> E[initialSize を SetValueForKey]
    E --> F[launchMode を SetValueForKey]
    F --> G[Json::writeString でJSON文字列化]
    G --> H[til::u8u16 で UTF-16 変換]
    H --> I[hstring として返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| JSONパースエラー | FromJson での不正なJSON入力 | なし | WEB_E_INVALID_JSON_STRING 例外をスロー |
| 書き込みエラー | state.json への書き込み失敗 | なし | CATCH_LOG() でログ記録 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ウィンドウ数 x タブ数（通常10件以下） |
| 目標出力時間 | 即座（ApplicationState のスロットリング経由） |
| 同時出力数上限 | 1（ApplicationState のスロットリングにより制御） |

## セキュリティ考慮事項

- WindowLayout データはアプリケーション内部で生成されるため、外部入力由来のリスクは低い
- FromJson での復元時にはJSON構造の検証が行われる（isObject() チェック）
- persistedWindowLayouts は Local ソースであり、昇格時は elevated-state.json に保存される

## 備考

- WindowLayout::ToJson() には2種類のオーバーロードがある:
  1. 静的メソッド `WindowLayout::ToJson(const Model::WindowLayout& layout)` - JSON文字列（hstring）を返す
  2. ConversionTrait の `ToJson(const WindowLayout& val)` - Json::Value を返す
- 静的メソッドは内部で ConversionTrait を使用し、さらに Json::writeString で文字列化してUTF-16に変換する
- tabLayout は ActionAndArgs の配列で、各要素はタブの作成に必要なアクション（newTab, splitPane等）とその引数を保持する
- 各プロパティは IReference（null可能）で管理されており、未設定のプロパティはJSONに出力されない
- ConversionTrait\<WindowLayout\> はJsonUtils名前空間で定義されており、JsonUtilsの汎用的なシリアライズ機構を活用する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ApplicationState.h | `src/cascadia/TerminalSettingsModel/ApplicationState.h` | WindowLayout 構造体（47-58行目）。TabLayout, InitialPosition, InitialSize, LaunchMode の4プロパティ |
| 1-2 | ApplicationState.cpp | `src/cascadia/TerminalSettingsModel/ApplicationState.cpp` | 19-23行目のJSONキー定数定義（TabLayoutKey, InitialPositionKey, InitialSizeKey, LaunchModeKey） |

**読解のコツ**: WindowLayout はWINRT_PROPERTYマクロで4つのプロパティを定義している。各プロパティはnull可能（nullptr デフォルト）で、IReference型のラッパーを使用している。

#### Step 2: ConversionTrait を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ApplicationState.cpp | `src/cascadia/TerminalSettingsModel/ApplicationState.cpp` | ConversionTrait\<WindowLayout\>（24-65行目）。FromJson, CanConvert, ToJson の実装。JsonUtils の GetValueForKey/SetValueForKey を使用 |

**主要処理フロー**:
- **31-41行目**: FromJson - 各キーから値を読み取り WindowLayout を構築
- **48-58行目**: ToJson - 各プロパティをJSONキーに設定

#### Step 3: 静的ToJsonメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ApplicationState.cpp | `src/cascadia/TerminalSettingsModel/ApplicationState.cpp` | WindowLayout::ToJson 静的メソッド（71-79行目）。ConversionTrait を使って Json::Value を取得し、writeString で文字列化 |

**主要処理フロー**:
- **73行目**: ConversionTrait\<Model::WindowLayout\> のインスタンス作成
- **74行目**: trait.ToJson(layout) で Json::Value 取得
- **77行目**: Json::writeString でJSON文字列化
- **78行目**: til::u8u16 で UTF-16 変換して hstring として返却

#### Step 4: ApplicationState への統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ApplicationState.cpp | `src/cascadia/TerminalSettingsModel/ApplicationState.cpp` | AppendPersistedWindowLayout メソッド（305-317行目）。PersistedWindowLayouts への追加とスロットリングトリガー |
| 4-2 | ApplicationState.h | `src/cascadia/TerminalSettingsModel/ApplicationState.h` | MTSM_APPLICATION_STATE_FIELDS の40行目。PersistedWindowLayouts が Local ソースであることを確認 |

**主要処理フロー**:
- **308行目**: state ロック取得
- **309-312行目**: PersistedWindowLayouts が未初期化なら空のベクターを作成
- **313行目**: レイアウトを追加
- **316行目**: _throttler() でスロットリング書き込みをトリガー

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

```
ApplicationState::AppendPersistedWindowLayout (ApplicationState.cpp:305)
    |
    +-- state->PersistedWindowLayouts->Append(layout)
    |
    +-- _throttler() (1秒デバウンス)
            |
            +-- ApplicationState::_write() (ApplicationState.cpp:198)
                    |
                    +-- ApplicationState::ToJson(FileSource::Local) (ApplicationState.cpp:281)
                    |       |
                    |       +-- JsonUtils::SetValueForKey("persistedWindowLayouts", ...)
                    |               |
                    |               +-- ConversionTrait<WindowLayout>::ToJson (ApplicationState.cpp:48)
                    |                       |
                    |                       +-- SetValueForKey(json, "tabLayout", ...)
                    |                       +-- SetValueForKey(json, "initialPosition", ...)
                    |                       +-- SetValueForKey(json, "initialSize", ...)
                    |                       +-- SetValueForKey(json, "launchMode", ...)
                    |
                    +-- _writeLocalContents() (state.json / elevated-state.json)

WindowLayout::ToJson(layout) [静的メソッド] (ApplicationState.cpp:71)
    |
    +-- ConversionTrait<WindowLayout>::ToJson()
    +-- Json::writeString()
    +-- til::u8u16()
```

### データフロー図

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

WindowLayout (メモリ)         ---> ConversionTrait::ToJson() ---> Json::Value
  |                                  |                              |
  +-- TabLayout                    +-- SetValueForKey             +-- [ApplicationState経由]
  |    (IVector<ActionAndArgs>)    |    "tabLayout"               |      |
  +-- InitialPosition             +-- SetValueForKey             |      +-- state.json
  |    (IReference<LaunchPosition>)|    "initialPosition"         |         persistedWindowLayouts[]
  +-- InitialSize                  +-- SetValueForKey             |
  |    (IReference<Size>)          |    "initialSize"             +-- [静的メソッド経由]
  +-- LaunchMode                   +-- SetValueForKey                    |
       (IReference<LaunchMode>)    |    "launchMode"                    +-- hstring (JSON文字列)
                                   +-- Json::writeString
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ApplicationState.h | `src/cascadia/TerminalSettingsModel/ApplicationState.h` | ヘッダー | WindowLayout 構造体定義 |
| ApplicationState.cpp | `src/cascadia/TerminalSettingsModel/ApplicationState.cpp` | ソース | WindowLayout::ToJson, ConversionTrait, AppendPersistedWindowLayout の実装 |
| ApplicationState.idl | `src/cascadia/TerminalSettingsModel/ApplicationState.idl` | IDL | WindowLayout の WinRT インターフェース定義 |
| WindowLayout.g.h | (生成ファイル) | ヘッダー | WindowLayout の WinRT コード生成 |
| JsonUtils.h | `src/cascadia/TerminalSettingsModel/JsonUtils.h` | ヘッダー | GetValueForKey, SetValueForKey テンプレート関数 |
| ActionAndArgs.h | `src/cascadia/TerminalSettingsModel/ActionAndArgs.h` | ヘッダー | タブレイアウトの各アクション定義 |
