use std::collections::HashMap;
use crate::webview::{WebView, prompt::PromptDialog};
use base::id::WebViewId;
use serde::{Deserialize, Serialize};
use servo_url::ServoUrl;
use webrender_api::units::DeviceRect;
pub struct Tab {
id: WebViewId,
webview: WebView,
history: TabHistory,
prompt: Option<PromptDialog>,
title: String,
}
impl Tab {
pub fn new(webview: WebView) -> Self {
Self {
id: webview.webview_id,
webview,
history: TabHistory {
list: Vec::new(),
current_idx: 0,
},
prompt: None,
title: "null".to_string(),
}
}
pub fn id(&self) -> WebViewId {
self.id
}
pub fn webview(&self) -> &WebView {
&self.webview
}
pub fn set_webview_size(&mut self, rect: DeviceRect) {
self.webview.set_size(rect);
}
pub fn history(&self) -> &TabHistory {
&self.history
}
pub fn set_history(&mut self, list: Vec<ServoUrl>, current_idx: usize) {
self.history = TabHistory { list, current_idx };
}
pub fn prompt(&self) -> Option<&PromptDialog> {
self.prompt.as_ref()
}
pub fn prompt_id(&self) -> Option<WebViewId> {
self.prompt.as_ref().map(|p| p.id())
}
pub fn set_prompt(&mut self, prompt: PromptDialog) {
self.prompt = Some(prompt);
}
pub fn remove_prompt(&mut self) -> Option<PromptDialog> {
self.prompt.take()
}
pub fn has_prompt(&self) -> bool {
self.prompt.is_some()
}
pub fn set_prompt_size(&mut self, rect: DeviceRect) {
if let Some(prompt) = self.prompt.as_mut() {
prompt.set_size(rect);
}
}
pub fn set_title(&mut self, title: String) {
self.title = title;
}
pub fn title(&self) -> String {
self.title.clone()
}
}
pub struct TabManager {
active_tab_id: Option<WebViewId>,
tab_map: HashMap<WebViewId, Tab>,
prompt_tab_map: HashMap<WebViewId, WebViewId>,
}
impl TabManager {
pub fn new() -> Self {
Self {
active_tab_id: None,
tab_map: HashMap::new(),
prompt_tab_map: HashMap::new(),
}
}
pub fn count(&self) -> usize {
self.tab_map.len()
}
pub fn current_tab_id(&self) -> Option<WebViewId> {
self.active_tab_id
}
pub fn current_tab(&self) -> Option<&Tab> {
if let Some(tab_id) = self.active_tab_id {
self.tab_map.get(&tab_id)
} else {
None
}
}
pub fn current_tab_mut(&mut self) -> Option<&mut Tab> {
if let Some(tab_id) = self.active_tab_id {
self.tab_map.get_mut(&tab_id)
} else {
None
}
}
pub fn tab_ids(&self) -> Vec<WebViewId> {
self.tab_map.keys().cloned().collect()
}
pub fn activate_tab(&mut self, tab_id: WebViewId) -> Option<&Tab> {
if let Some(tab) = self.tab_map.get(&tab_id) {
self.active_tab_id = Some(tab_id);
Some(tab)
} else {
self.active_tab_id = None;
None
}
}
pub fn tab(&self, id: WebViewId) -> Option<&Tab> {
self.tab_map.get(&id)
}
pub fn append_tab(&mut self, webview: WebView, active: bool) {
let id = webview.webview_id;
let tab = Tab::new(webview);
self.tab_map.insert(id, tab);
if active {
self.active_tab_id = Some(id);
}
}
pub fn close_tab(&mut self, id: WebViewId) -> Result<Tab, TabManagerErr> {
match self.tab_map.remove(&id) {
Some(tab) => Ok(tab),
None => Err(TabManagerErr::WebViewIdNotFound),
}
}
pub fn set_size(
&mut self,
tab_id: WebViewId,
rect: DeviceRect,
) -> (Option<WebViewId>, Option<WebViewId>) {
if let Some(tab) = self.tab_map.get_mut(&tab_id) {
tab.set_webview_size(rect);
if let Some(prompt_id) = tab.prompt_id() {
tab.set_prompt_size(rect);
(Some(tab_id), Some(prompt_id))
} else {
(Some(tab_id), None)
}
} else {
(None, None)
}
}
pub fn history(&self, tab_id: WebViewId) -> Option<&TabHistory> {
self.tab_map.get(&tab_id).map(|tab| tab.history())
}
pub fn set_history(&mut self, tab_id: WebViewId, list: Vec<ServoUrl>, current_idx: usize) {
if let Some(tab) = self.tab_map.get_mut(&tab_id) {
tab.set_history(list, current_idx);
};
}
pub fn prompt_by_tab_id(&self, tab_id: WebViewId) -> Option<&PromptDialog> {
self.tab_map.get(&tab_id).and_then(|tab| tab.prompt())
}
pub fn prompt_by_prompt_id(&self, prompt_id: WebViewId) -> Option<&PromptDialog> {
if let Some(tab_id) = self.prompt_tab_map.get(&prompt_id) {
self.prompt_by_tab_id(*tab_id)
} else {
None
}
}
pub fn current_prompt(&self) -> Option<&PromptDialog> {
if let Some(tab_id) = self.active_tab_id {
self.prompt_by_tab_id(tab_id)
} else {
None
}
}
pub fn set_prompt(&mut self, tab_id: WebViewId, prompt: PromptDialog) {
if let Some(tab) = self.tab_map.get_mut(&tab_id) {
self.prompt_tab_map.insert(prompt.id(), tab_id);
tab.set_prompt(prompt);
}
}
pub fn remove_prompt_by_tab_id(&mut self, tab_id: WebViewId) -> Option<PromptDialog> {
if let Some(tab) = self.tab_map.get_mut(&tab_id) {
if let Some(prompt) = tab.remove_prompt() {
self.prompt_tab_map.remove(&prompt.id());
return Some(prompt);
}
}
None
}
pub fn remove_prompt_by_prompt_id(&mut self, prompt_id: WebViewId) -> Option<PromptDialog> {
if let Some(tab_id) = self.prompt_tab_map.remove(&prompt_id) {
self.remove_prompt_by_tab_id(tab_id)
} else {
None
}
}
pub fn has_prompt(&self, prompt_id: WebViewId) -> bool {
self.prompt_tab_map.contains_key(&prompt_id)
}
}
impl Default for TabManager {
fn default() -> Self {
Self::new()
}
}
pub struct TabHistory {
pub list: Vec<ServoUrl>,
pub current_idx: usize,
}
pub enum TabManagerErr {
IndexOutOfBounds,
WebViewIdNotFound,
RemoveLastWebView,
}
#[derive(Debug, Clone, Serialize)]
pub struct TabCreateResponse {
pub success: bool,
pub id: WebViewId,
}
impl TabCreateResponse {
pub fn to_json(&self) -> String {
serde_json::to_string(self).unwrap()
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct TabActivateRequest {
pub id: WebViewId,
}
#[derive(Debug, Clone, Deserialize)]
pub struct TabCloseRequest {
pub id: WebViewId,
}