Mountain/Environment/
TreeViewProvider.rs

1// File: Mountain/Source/Environment/TreeViewProvider.rs
2
3//! # TreeViewProvider Implementation
4//!
5//! Implements the `TreeViewProvider` trait for the `MountainEnvironment`. This
6//! provider manages the lifecycle of custom tree views and orchestrates the
7//! data flow between the extension host (`Cocoon`) and the UI (`Sky`).
8
9#![allow(non_snake_case, non_camel_case_types)]
10
11use std::sync::Arc;
12
13use Common::{
14	Environment::Requires::Requires,
15	Error::CommonError::CommonError,
16	IPC::{DTO::ProxyTarget::ProxyTarget, IPCProvider::IPCProvider},
17	TreeView::{DTO::TreeViewOptionsDTO::TreeViewOptionsDTO, TreeViewProvider::TreeViewProvider},
18};
19use async_trait::async_trait;
20use log::{info, warn};
21use serde_json::{Value, json};
22use tauri::Emitter;
23
24use super::{MountainEnvironment::MountainEnvironment, Utility};
25use crate::ApplicationState::DTO::TreeViewStateDTO::TreeViewStateDTO;
26
27#[async_trait]
28impl TreeViewProvider for MountainEnvironment {
29	/// Registers a new tree data provider from an extension (e.g., Cocoon).
30	async fn RegisterTreeDataProvider(&self, ViewIdentifier:String, Options:Value) -> Result<(), CommonError> {
31		info!("[TreeViewProvider] Registering data provider for view: {}", ViewIdentifier);
32
33		let OptionsDTO:TreeViewOptionsDTO = serde_json::from_value(Options.clone()).map_err(|Error| {
34			CommonError::InvalidArgument { ArgumentName:"Options".into(), Reason:Error.to_string() }
35		})?;
36
37		// For now, assume all extension providers come from the main sidecar.
38		let SideCarIdentifier = "cocoon-main".to_string();
39
40		let NewState = TreeViewStateDTO {
41			ViewIdentifier:ViewIdentifier.clone(),
42
43			// This is a proxied provider, not native.
44			Provider:None,
45
46			SideCarIdentifier:Some(SideCarIdentifier),
47
48			CanSelectMany:OptionsDTO.CanSelectMany,
49
50			HasHandleDrag:OptionsDTO.HasHandleDrag,
51
52			HasHandleDrop:OptionsDTO.HasHandleDrop,
53
54			Message:None,
55
56			Title:None,
57
58			Description:None,
59		};
60
61		self.ApplicationState
62			.ActiveTreeViews
63			.lock()
64			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
65			.insert(ViewIdentifier.clone(), NewState);
66
67		self.ApplicationHandle
68			.emit(
69				"sky://tree-view/create",
70				json!({ "ViewIdentifier": ViewIdentifier, "Options": Options }),
71			)
72			.map_err(|Error| CommonError::UserInterfaceInteraction { Reason:Error.to_string() })?;
73
74		Ok(())
75	}
76
77	/// Unregisters a tree data provider.
78	async fn UnregisterTreeDataProvider(&self, ViewIdentifier:String) -> Result<(), CommonError> {
79		info!("[TreeViewProvider] Unregistering data provider for view: {}", ViewIdentifier);
80
81		self.ApplicationState
82			.ActiveTreeViews
83			.lock()
84			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
85			.remove(&ViewIdentifier);
86
87		self.ApplicationHandle
88			.emit("sky://tree-view/dispose", json!({ "ViewIdentifier": ViewIdentifier }))
89			.map_err(|Error| CommonError::UserInterfaceInteraction { Reason:Error.to_string() })
90	}
91
92	/// Reveals a specific item in the tree view by notifying the UI.
93	async fn RevealTreeItem(&self, ViewIdentifier:String, ItemHandle:String, Options:Value) -> Result<(), CommonError> {
94		info!(
95			"[TreeViewProvider] Revealing item '{}' in view '{}'",
96			ItemHandle, ViewIdentifier
97		);
98
99		self.ApplicationHandle
100			.emit(
101				"sky://tree-view/reveal",
102				json!({ "viewId": ViewIdentifier, "itemHandle": ItemHandle, "options": Options }),
103			)
104			.map_err(|Error| CommonError::UserInterfaceInteraction { Reason:Error.to_string() })
105	}
106
107	/// Refreshes the tree view by notifying the UI.
108	async fn RefreshTreeView(&self, ViewIdentifier:String, ItemsToRefresh:Option<Value>) -> Result<(), CommonError> {
109		info!("[TreeViewProvider] Refreshing view '{}'", ViewIdentifier);
110
111		self.ApplicationHandle
112			.emit(
113				"sky://tree-view/refresh",
114				json!({ "viewId": ViewIdentifier, "itemsToRefresh": ItemsToRefresh }),
115			)
116			.map_err(|Error| CommonError::UserInterfaceInteraction { Reason:Error.to_string() })
117	}
118
119	/// Gets the children for a given element. This method acts as a dispatcher.
120	async fn GetChildren(
121		&self,
122
123		ViewIdentifier:String,
124
125		ElementHandle:Option<String>,
126	) -> Result<Vec<Value>, CommonError> {
127		let ProviderInfo = self
128			.ApplicationState
129			.ActiveTreeViews
130			.lock()
131			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
132			.get(&ViewIdentifier)
133			.cloned();
134
135		if let Some(Info) = ProviderInfo {
136			if let Some(NativeProvider) = Info.Provider {
137				// Case 1: Native Rust provider (e.g., File Explorer)
138				return NativeProvider.GetChildren(ViewIdentifier, ElementHandle).await;
139			} else if let Some(SideCarId) = Info.SideCarIdentifier {
140				// Case 2: Proxied extension provider
141				let IPCProvider:Arc<dyn IPCProvider> = self.Require();
142
143				let RPCMethod = format!("{}$getChildren", ProxyTarget::ExtHostTreeView.GetTargetPrefix());
144
145				let RPCParams = json!([ViewIdentifier, ElementHandle]);
146
147				let Response = IPCProvider.SendRequestToSideCar(SideCarId, RPCMethod, RPCParams, 10000).await?;
148
149				return serde_json::from_value::<Vec<Value>>(Response).map_err(CommonError::from);
150			}
151		}
152		Err(CommonError::TreeViewProviderNotFound { ViewIdentifier })
153	}
154
155	/// Gets the TreeItem for a given element. This method acts as a dispatcher.
156	async fn GetTreeItem(&self, ViewIdentifier:String, ElementHandle:String) -> Result<Value, CommonError> {
157		let ProviderInfo = self
158			.ApplicationState
159			.ActiveTreeViews
160			.lock()
161			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
162			.get(&ViewIdentifier)
163			.cloned();
164
165		if let Some(Info) = ProviderInfo {
166			if let Some(NativeProvider) = Info.Provider {
167				return NativeProvider.GetTreeItem(ViewIdentifier, ElementHandle).await;
168			} else if let Some(SideCarId) = Info.SideCarIdentifier {
169				let IPCProvider:Arc<dyn IPCProvider> = self.Require();
170
171				let RPCMethod = format!("{}$getTreeItem", ProxyTarget::ExtHostTreeView.GetTargetPrefix());
172
173				let RPCParams = json!([ViewIdentifier, ElementHandle]);
174
175				return IPCProvider.SendRequestToSideCar(SideCarId, RPCMethod, RPCParams, 5000).await;
176			}
177		}
178		Err(CommonError::TreeViewProviderNotFound { ViewIdentifier })
179	}
180
181	// --- Other stubbed methods ---
182	async fn SetTreeViewMessage(&self, _ViewIdentifier:String, _Message:Option<String>) -> Result<(), CommonError> {
183		warn!("[TreeViewProvider] SetTreeViewMessage is not implemented.");
184
185		Ok(())
186	}
187
188	async fn SetTreeViewTitle(
189		&self,
190
191		_ViewIdentifier:String,
192
193		_Title:Option<String>,
194
195		_Description:Option<String>,
196	) -> Result<(), CommonError> {
197		warn!("[TreeViewProvider] SetTreeViewTitle is not implemented.");
198
199		Ok(())
200	}
201
202	async fn SetTreeViewBadge(&self, _ViewIdentifier:String, _Badge:Option<Value>) -> Result<(), CommonError> {
203		warn!("[TreeViewProvider] SetTreeViewBadge is not implemented.");
204
205		Ok(())
206	}
207}