# 機能設計書 54-ダイアログ

## 概要

本ドキュメントは、VS Codeのダイアログ機能に関する設計書である。モーダルダイアログを通じてユーザーに確認、入力、選択を求める機能を提供する。ファイルダイアログ（開く/保存）やメッセージボックスなど、OSネイティブのダイアログとカスタムダイアログの両方をサポートする。

### 本機能の処理概要

**業務上の目的・背景**：
重要な操作（ファイル削除、設定変更など）の前にユーザーの確認を得ることで、誤操作を防止する。また、ファイルの選択やテキスト入力など、ユーザーからの入力を受け付ける標準的なインターフェースを提供する。OS標準のダイアログとカスタムダイアログを状況に応じて使い分けることで、ネイティブな操作感と柔軟なカスタマイズを両立する。

**機能の利用シーン**：
- 未保存ファイルを閉じる際の保存確認
- ファイルやフォルダの選択（開く/保存ダイアログ）
- 危険な操作の実行確認
- ユーザーへの入力要求（リネーム、パスワード入力など）
- アプリケーション情報の表示（Aboutダイアログ）

**主要な処理内容**：
1. 確認ダイアログの表示（confirm）
2. プロンプトダイアログの表示（prompt）
3. 入力ダイアログの表示（input）
4. ファイル選択ダイアログの表示（pickFile/pickFolder）
5. 保存ダイアログの表示（showSaveDialog）
6. プラットフォーム別のボタン配置最適化
7. Aboutダイアログの表示

**関連システム・外部連携**：
- Electron: ネイティブダイアログAPI
- ファイルシステムサービス（IFileService）: ファイルパスの検証
- 製品サービス（IProductService）: About情報の取得

**権限による制御**：
特になし（ダイアログはユーザー操作に応じて表示）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 46 | ダイアログ | 主機能 | モーダルダイアログによる確認・入力 |

## 機能種別

UI表示 / モーダルダイアログ / ユーザーインタラクション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| message | string | Yes | ダイアログのメッセージ | 空文字列不可 |
| detail | string | No | 詳細メッセージ | - |
| type | Severity/DialogType | No | ダイアログタイプ | none/info/error/question/warning |
| buttons | IPromptButton[] | No | ボタン定義 | 配列 |
| checkbox | ICheckbox | No | チェックボックス | label必須 |
| inputs | IInputElement[] | No | 入力フィールド（input用） | 配列 |

### 入力データソース

- プログラムコードからの直接呼び出し
- メニューアクション
- ファイル操作イベント

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| confirmed | boolean | 確認ダイアログでの確認結果 |
| result | T | プロンプトボタンの戻り値 |
| values | string[] | 入力ダイアログの入力値 |
| checkboxChecked | boolean | チェックボックスの状態 |

### 出力先

- Promiseとして呼び出し元に返却

## 処理フロー

### 処理シーケンス

```
1. ダイアログメソッド呼び出し（confirm/prompt/input）
   └─ オプションを受け取る
2. ボタン配列の構築
   └─ プラットフォーム別にボタン順序を調整
3. ダイアログハンドラーへの委譲
   └─ ネイティブまたはカスタムダイアログを選択
4. ユーザー操作待機
   └─ ボタンクリックまたはキャンセルを待機
5. 結果の構築
   └─ ボタンインデックスを元のインデックスにマッピング
6. コールバック実行（prompt）
   └─ 選択されたボタンのrun()を実行
```

### フローチャート

```mermaid
flowchart TD
    A[ダイアログ呼び出し] --> B[ボタン配列構築]
    B --> C{カスタムダイアログ強制?}
    C -->|Yes| D[カスタムダイアログ表示]
    C -->|No| E{プラットフォーム}
    E -->|Electron| F[ネイティブダイアログ表示]
    E -->|Browser| D
    D --> G[ユーザー操作待機]
    F --> G
    G --> H{ボタン押下}
    H -->|キャンセル| I[キャンセル結果返却]
    H -->|確認/選択| J[ボタンインデックスマッピング]
    J --> K{prompt?}
    K -->|Yes| L[button.run実行]
    K -->|No| M[結果返却]
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | Linux/macOSボタン順序 | キャンセルボタンを先頭に配置 | Linux/macOS |
| BR-54-02 | Windowsボタン順序 | キャンセルボタンを末尾に配置 | Windows |
| BR-54-03 | デフォルトボタン | 最初のボタンをデフォルトボタンとして扱う | 常時 |
| BR-54-04 | キャンセルボタン | 最後のボタンをキャンセルボタンとして扱う | 常時 |
| BR-54-05 | 保存確認上限 | 最大10ファイルまでファイル名を表示 | showSaveConfirm |

### 計算ロジック

```typescript
// プラットフォーム別ボタン配置
function massageMessageBoxOptions(options: MessageBoxOptions, productService: IProductService) {
  // Linux/macOS: キャンセルを先頭付近に移動し、ボタン配列を反転
  if (isLinux || isMacintosh) {
    if (cancelButton && buttons.length > 1 && cancelId !== 1) {
      buttons.splice(cancelId, 1);
      buttons.splice(1, 0, cancelButton);
      cancelId = 1;
    }
    if (isLinux && buttons.length > 1) {
      buttons = buttons.reverse();
      defaultId = buttons.length - 1;
    }
  }
  // Windows: キャンセルを末尾に移動
  else if (isWindows) {
    if (cancelButton && cancelId !== buttons.length - 1) {
      buttons.splice(cancelId, 1);
      buttons.push(cancelButton);
      cancelId = buttons.length - 1;
    }
  }
}

// ファイル名メッセージ構築（最大10件）
const MAX_CONFIRM_FILES = 10;
function getFileNamesMessage(files: (string | URI)[]): string {
  const message = files.slice(0, MAX_CONFIRM_FILES).map(f => basename(f));
  if (files.length > MAX_CONFIRM_FILES) {
    message.push(`...${files.length - MAX_CONFIRM_FILES} additional files not shown`);
  }
  return message.join('\n');
}
```

## データベース操作仕様

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 入力検証エラー | input で検証失敗 | エラーメッセージ表示、再入力要求 |

### リトライ仕様

入力検証エラー時は、ユーザーが入力を修正するまでダイアログを閉じない。

## トランザクション仕様

該当なし

## パフォーマンス要件

- ダイアログ表示は即座に行う
- ネイティブダイアログはOSに依存

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

- パスワード入力フィールドはマスク表示
- カスタムダイアログ内のMarkdownリンクは安全な形式のみ許可

## 備考

- 非モーダルな確認にはINotificationService.promptを使用
- カスタムダイアログはWebコンテキストでも動作

---

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

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

### 推奨読解順序

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

ダイアログのインターフェースと型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dialogs.ts | `src/vs/platform/dialogs/common/dialogs.ts` | IDialogService、IFileDialogService、関連型定義 |

**読解のコツ**:
- IConfirmation/IInput/IPromptの3つのダイアログタイプを区別する
- DialogTypeはSeverityまたは文字列（'none'/'info'/'error'/'question'/'warning'）

**主要処理フロー**:
1. **21-25行目**: IDialogArgs - ダイアログ引数の共通型
2. **27-40行目**: IBaseDialogOptions - 基本オプション（type, title, message, detail, checkbox, custom）
3. **46-57行目**: IConfirmation - 確認ダイアログ型
4. **59-65行目**: IConfirmationResult - 確認結果型
5. **71-78行目**: IInput - 入力ダイアログ型
6. **120-133行目**: IPrompt - プロンプトダイアログ型
7. **273行目**: IDialogServiceのdecorator登録
8. **452-509行目**: IDialogService - サービスインターフェース

#### Step 2: ファイルダイアログを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dialogs.ts | `src/vs/platform/dialogs/common/dialogs.ts` | IFileDialogService、ISaveDialogOptions、IOpenDialogOptions |

**主要処理フロー**:
- **198-226行目**: ISaveDialogOptions - 保存ダイアログオプション
- **228-271行目**: IOpenDialogOptions - 開くダイアログオプション
- **511-587行目**: IFileDialogService - ファイルダイアログサービス

#### Step 3: ダイアログハンドラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dialogs.ts | `src/vs/platform/dialogs/common/dialogs.ts` | IDialogHandler、AbstractDialogHandler |

**主要処理フロー**:
- **293-314行目**: IDialogHandler - ハンドラーインターフェース
- **322-444行目**: AbstractDialogHandler - ボタン構築、タイプ変換の共通実装

#### Step 4: プラットフォーム別の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | dialogs.ts | `src/vs/platform/dialogs/common/dialogs.ts` | massageMessageBoxOptions関数 |

**主要処理フロー**:
- **641-730行目**: massageMessageBoxOptions - プラットフォーム別ボタン配置の最適化

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

```
IDialogService (サービスインターフェース)
    │
    ├─ confirm() - 確認ダイアログ
    │      │
    │      ├─ IConfirmation (入力)
    │      │      ├─ message
    │      │      ├─ primaryButton
    │      │      └─ cancelButton
    │      │
    │      └─ IConfirmationResult (出力)
    │             ├─ confirmed
    │             └─ checkboxChecked
    │
    ├─ prompt() - プロンプトダイアログ
    │      │
    │      ├─ IPrompt<T> (入力)
    │      │      ├─ buttons[]
    │      │      │      └─ run() → T
    │      │      └─ cancelButton
    │      │
    │      └─ IPromptResult<T> (出力)
    │             ├─ result (T)
    │             └─ checkboxChecked
    │
    ├─ input() - 入力ダイアログ
    │      │
    │      ├─ IInput (入力)
    │      │      └─ inputs[]
    │      │             ├─ type (text/password)
    │      │             └─ placeholder
    │      │
    │      └─ IInputResult (出力)
    │             ├─ confirmed
    │             └─ values[]
    │
    ├─ info() / warn() / error() - 簡易メッセージ
    │
    └─ about() - Aboutダイアログ

IFileDialogService (ファイルダイアログ)
    │
    ├─ pickFileAndOpen() - ファイル選択して開く
    ├─ pickFolderAndOpen() - フォルダ選択して開く
    ├─ showSaveDialog() - 保存ダイアログ
    ├─ showOpenDialog() - 開くダイアログ
    └─ showSaveConfirm() - 保存確認ダイアログ
```

### データフロー図

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

confirm()
    │
    ↓
┌───────────────┐
│IConfirmation  │
│  - message    │
│  - buttons    │
└───────────────┘
    │
    ↓
┌───────────────┐
│ボタン配列構築  │
│(getButtons)   │
└───────────────┘
    │
    ↓
┌───────────────┐
│プラットフォーム│
│別調整         │
│(massageOptions)│
└───────────────┘
    │
    ├──────────────────┐
    ↓                  ↓
┌──────────┐    ┌──────────┐
│ネイティブ │    │カスタム   │
│ダイアログ │    │ダイアログ │
│(Electron) │    │(HTML)    │
└──────────┘    └──────────┘
    │                │
    └────────────────┘
           │
           ↓
    ┌──────────────┐
    │ボタンIndex   │
    │マッピング    │
    └──────────────┘
           │
           ↓
    ┌──────────────┐
    │IConfirmation │
    │Result        │
    └──────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dialogs.ts | `src/vs/platform/dialogs/common/dialogs.ts` | ソース | インターフェース・共通ロジック |
| dialog.ts | `src/vs/platform/dialogs/browser/dialog.ts` | ソース | ブラウザ実装 |
| dialog.ts | `src/vs/platform/dialogs/electron-browser/dialog.ts` | ソース | Electronブラウザ側実装 |
| dialogMainService.ts | `src/vs/platform/dialogs/electron-main/dialogMainService.ts` | ソース | Electronメイン側実装 |
| testDialogService.ts | `src/vs/platform/dialogs/test/common/testDialogService.ts` | テスト | テスト用モック実装 |
