# 画面設計書 40-アセットインストーラー

## 概要

本ドキュメントは、Godot Engineエディタにおけるアセットインストーラー（EditorAssetInstaller）の画面設計を記述する。このダイアログはアセットライブラリからダウンロードしたアセットパッケージ（ZIPファイル）をプロジェクトにインストールするために使用される。

### 本画面の処理概要

このダイアログ画面では、ZIPアーカイブ内のファイル一覧を表示し、インストールするファイルの選択、インストール先ディレクトリの変更、トップレベルディレクトリのスキップオプションを提供する。競合するファイル（既存ファイル）は自動的に検出され、警告表示される。

**業務上の目的・背景**：Godot Asset Libraryから提供されるアセットパッケージには、プラグイン、テンプレート、サンプルプロジェクトなど様々なリソースが含まれる。このインストーラーにより、必要なファイルのみを選択的にインストールし、既存ファイルとの競合を事前に確認できる。

**画面へのアクセス方法**：アセットライブラリからアセットをダウンロード後、自動的に表示される。または、ダウンロード済みアセットのインストールボタンを押下。

**主要な操作・処理内容**：
1. アセット内容の表示（ソースツリー）
2. インストールファイルの選択/選択解除
3. インストール先ディレクトリの変更
4. トップレベルディレクトリのスキップ
5. インストール先プレビューの表示（デスティネーションツリー）
6. アセットのインストール実行

**画面遷移**：
- 遷移元：アセットライブラリ > ダウンロード完了
- 遷移先（インストール成功）：成功メッセージ表示、ダイアログ閉じる
- 遷移先（キャンセル）：ダイアログ閉じる

**権限による表示制御**：skip_toplevel_checkは、アセットにトップレベルディレクトリがある場合のみ有効化される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| F-090 | アセットインストール | 主機能 | ZIPからのファイル展開とインストール |
| F-091 | ファイル競合検出 | 補助機能 | 既存ファイルとの競合チェック |
| F-092 | ファイルマッピング | 補助機能 | ソースパスからターゲットパスへの変換 |

## 画面種別

インストール・選択（モーダルダイアログ）

## URL/ルーティング

該当なし（デスクトップアプリケーションのモーダルダイアログ）

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| アセットパス | 入力 | String | 必須 | open_asset()で設定されるZIPパス |
| 自動スキップ | 入力 | bool | オプション | トップレベルの自動スキップ |
| インストール先 | 入力 | String | - | デフォルトres:// |
| ファイル選択 | 入力 | bool[] | - | インストールするファイルの選択状態 |
| スキップトップレベル | 入力 | bool | - | トップレベルディレクトリをスキップ |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| Asset | ラベル | アセット名表示 |
| ソースファイルボタン | トグルボタン | ソースツリーの表示/非表示切り替え |
| Change Install Folder | ボタン | インストール先選択ダイアログを開く |
| Ignore asset root | チェックボックス | トップレベルディレクトリのスキップ |
| 競合なしラベル | ラベル | 「No files conflict with your project」 |
| 競合リンク | LinkButton | 競合数を表示、クリックでソースツリー表示 |
| Contents of the asset | Tree | ソースファイル一覧（チェックボックス付き） |
| Installation preview | Tree | インストール先ファイル一覧 |

## イベント仕様

### 1-アセット読み込み

open_asset()が呼び出され、以下の処理が行われる：
1. ZIPファイルをunzOpen2()で開く
2. unzGoToFirstFile()/unzGoToNextFile()で全ファイルを列挙
3. 中間ディレクトリも含めてasset_filesに追加
4. _check_has_toplevel()でトップレベルディレクトリを検出
5. _update_file_mappings()でパスマッピングを作成
6. _rebuild_source_tree()でソースツリーを構築
7. _rebuild_destination_tree()でデスティネーションツリーを構築
8. popup_centered_clamped(Size2(620, 640) * EDSCALE)で表示

### 2-ファイル選択変更

source_treeのitem_editedにより_item_checked_cbk()が呼び出される：
1. item->propagate_check(0)で子要素に伝播
2. _fix_conflicted_indeterminate_state()で競合状態を修正
3. _update_confirm_button()でOKボタン状態更新
4. _rebuild_destination_tree()でプレビュー更新

### 3-トップレベルスキップ

skip_toplevel_checkのtoggledにより_set_skip_toplevel()が呼び出される：
1. skip_toplevelフラグを更新
2. _update_file_mappings()でマッピング再計算
3. _update_source_tree()でステータス更新
4. _rebuild_destination_tree()でプレビュー再構築

### 4-インストール先変更

Change Install Folderボタンのpressedにより_open_target_dir_dialog()が呼び出される：
1. EditorFileDialogでディレクトリ選択
2. _target_dir_selected()で選択パスを設定
3. _update_file_mappings()でマッピング再計算
4. ソースツリーとデスティネーションツリーを更新

### 5-ソースツリー表示切り替え

show_source_files_buttonのtoggledにより_toggle_source_tree()が呼び出される：
1. source_tree_vbの表示/非表示を切り替え
2. ボタンアイコンをBack/Forwardに変更
3. destination_treeのテーマバリエーションを調整
4. p_scroll_to_errorがtrueの場合、最初の競合にスクロール

### 6-インストール実行

OKボタン押下でok_pressed()→_install_asset()が呼び出される：
1. ZIPファイルを再度開く
2. ProgressDialogで進捗表示
3. 各ファイルを展開：
   - チェック済みファイルのみ処理
   - ディレクトリの場合：make_dir_recursive()
   - ファイルの場合：unzReadCurrentFile()でデータ読み込み、FileAccess::WRITE保存
4. 失敗ファイルがある場合は警告表示
5. 成功時は成功メッセージ表示
6. EditorFileSystem::scan_changes()でファイルシステム更新

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| インストール | プロジェクトファイルシステム | CREATE | アセットファイルの展開 |

### テーブル別更新項目詳細

#### プロジェクトファイルシステム

| 操作 | 項目 | 更新値・取得条件 | 備考 |
|-----|------|-----------------|------|
| CREATE | ディレクトリ | DirAccess::make_dir_recursive() | 必要に応じて作成 |
| CREATE | ファイル | FileAccess::store_buffer() | ZIPから展開したデータ |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------:|
| - | タイトル | Configure Asset Before Installing | ダイアログタイトル |
| - | ラベル | Asset: | アセット名ラベル |
| - | ボタン | Change Install Folder | インストール先変更ボタン |
| - | チェック | Ignore asset root | トップレベルスキップ |
| - | ラベル | No files conflict with your project | 競合なし時 |
| - | リンク | %d file conflicts with your project... | 競合あり時（単数） |
| - | リンク | %d files conflict with your project... | 競合あり時（複数） |
| - | ラベル | Contents of the asset: | ソースツリータイトル |
| - | ラベル | Installation preview: | デスティネーションツリータイトル |
| - | ボタン | Install | OKボタンテキスト |
| - | エラー | Error opening asset file... (not in ZIP format). | ZIP読み込みエラー |
| - | 成功 | Asset "%s" installed successfully! | インストール成功 |
| - | 警告 | The following files failed extraction... | 展開失敗時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ZIPファイルオープン失敗 | EditorToasterでエラーメッセージ表示 |
| ファイル展開失敗 | failed_filesに追加、後でまとめて警告表示 |
| 既存ファイル競合 | 赤色で表示、チェック解除、ツールチップに「(already exists)」 |

## 備考

- ConfirmationDialogを継承
- set_hide_on_ok(true)で確定時に自動的に閉じる
- 拡張子ごとにアイコンを設定（画像、音声、シーン、スクリプト等）
- C#サポートがない場合、.csファイルにImportFailアイコン表示
- first_file_conflictで最初の競合ファイルを追跡（スクロール用）
- TreeSecondaryテーマバリエーションをソースツリーに適用
- 中間ディレクトリもasset_filesに追加（ZIPが報告しない場合のため）
- toplevel_prefixで共通プレフィックスを検出

---

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

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

### 推奨読解順序

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

クラス定義とメンバ変数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | editor_asset_installer.h | `editor/asset_library/editor_asset_installer.h` | UI要素（44-54行目）、データ構造（56-70行目） |

**読解のコツ**: source_tree（選択用）とdestination_tree（プレビュー用）の2つのツリーが主要UI。mapped_filesがソースパス→ターゲットパスのマッピング、file_item_mapがパス→TreeItemのマッピング。

#### Step 2: アセット読み込みを理解する

open_asset()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | open_asset()（109-167行目） |

**主要処理フロー**:
1. **116-120行目**: ZIPファイルオープン、エラー時はtoast表示
2. **122-149行目**: ファイル列挙と中間ディレクトリ追加
3. **155-160行目**: トップレベルチェックとスキップ設定
4. **162-166行目**: マッピング作成、ツリー構築、ダイアログ表示

#### Step 3: ツリー構築を理解する

_rebuild_source_tree()と_rebuild_destination_tree()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | _rebuild_source_tree()（191-241行目） |
| 3-2 | editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | _rebuild_destination_tree()（293-334行目） |

**主要処理フロー**:
- **195-200行目**: ルートアイテム作成（チェックボックス付き）
- **207-235行目**: ファイル/ディレクトリの追加、競合チェック
- **296-298行目**: デスティネーションルート作成
- **302-333行目**: チェック済みアイテムのみプレビューに追加

#### Step 4: 競合処理を理解する

_update_source_item_status()と_fix_conflicted_indeterminate_state()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | _update_source_item_status()（273-291行目） |
| 4-2 | editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | _fix_conflicted_indeterminate_state()（65-103行目） |

**主要処理フロー**:
- **277-286行目**: 既存ファイルチェック、赤色設定、チェック解除
- **69-89行目**: 子要素の競合状態に基づく親の状態決定
- **90-96行目**: 不確定状態の設定

#### Step 5: インストール処理を理解する

_install_asset()の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | _install_asset()（505-593行目） |

**主要処理フロー**:
- **506-513行目**: ZIPファイル再オープン
- **518行目**: ProgressDialog表示
- **521-569行目**: ファイル展開ループ
- **543-548行目**: ディレクトリ作成
- **550-565行目**: ファイル展開と保存
- **574-590行目**: 結果メッセージ表示
- **592行目**: ファイルシステムスキャン

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

```
EditorAssetInstaller (ConfirmationDialog)
    │
    ├─ open_asset(p_path, p_autoskip)     [初期化]
    │      ├─ unzOpen2()
    │      ├─ unzGoToFirstFile()/Next()
    │      ├─ _check_has_toplevel()
    │      ├─ _update_file_mappings()
    │      ├─ _rebuild_source_tree()
    │      └─ _rebuild_destination_tree()
    │
    ├─ _rebuild_source_tree()             [ソースツリー構築]
    │      ├─ _create_dir_item()
    │      ├─ _create_file_item()
    │      └─ _update_conflict_status()
    │
    ├─ _item_checked_cbk()                [選択変更]
    │      ├─ propagate_check()
    │      ├─ _fix_conflicted_indeterminate_state()
    │      ├─ _update_confirm_button()
    │      └─ _rebuild_destination_tree()
    │
    ├─ _toggle_source_tree()              [表示切替]
    │      └─ scroll_to_item()            [競合へスクロール]
    │
    └─ _install_asset()                   [インストール実行]
           ├─ unzOpen2()
           ├─ ProgressDialog::add_task()
           ├─ DirAccess::make_dir_recursive()
           ├─ FileAccess::store_buffer()
           └─ EditorFileSystem::scan_changes()
```

### データフロー図

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

open_asset(path) ───────▶ unzOpen2() ─────────────────▶ asset_files
ZIPパス                       │                          (ファイル一覧)
                              └─ unzGoToFirstFile()

asset_files ────────────▶ _check_has_toplevel() ──────▶ toplevel_prefix
                              │
                              └─ _update_file_mappings()
                                      │
                                      ▼
                              mapped_files ────────────▶ ツリー表示

チェック変更 ───────────▶ _item_checked_cbk() ────────▶ destination_tree
source_tree                   │                          更新
                              └─ propagate_check()

インストール先変更 ─────▶ _target_dir_selected() ─────▶ ツリー再構築
EditorFileDialog              │
                              └─ _update_file_mappings()

OKボタン ──────────────▶ _install_asset() ────────────▶ ファイル展開
                              │                          成功/失敗メッセージ
                              ├─ unzReadCurrentFile()
                              └─ FileAccess::store_buffer()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| editor_asset_installer.cpp | `editor/asset_library/editor_asset_installer.cpp` | ソース | ダイアログの実装 |
| editor_asset_installer.h | `editor/asset_library/editor_asset_installer.h` | ヘッダ | クラス定義 |
| zip_io.h | `core/io/zip_io.h` | ヘッダ | ZIPファイルI/O |
| editor_file_dialog.h | `editor/gui/editor_file_dialog.h` | ヘッダ | ディレクトリ選択 |
| editor_toaster.h | `editor/gui/editor_toaster.h` | ヘッダ | トースト通知 |
| progress_dialog.h | `editor/gui/progress_dialog.h` | ヘッダ | 進捗表示 |
| tree.h | `scene/gui/tree.h` | ヘッダ | ツリーUI |
| link_button.h | `scene/gui/link_button.h` | ヘッダ | 競合リンク |
