• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2024 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {Disposable} from '../base/disposable';
16import {DetailsPanel, LegacyDetailsPanel, TabDescriptor} from '../public';
17
18export interface ResolvedTab {
19  uri: string;
20  tab?: TabDescriptor;
21}
22
23/**
24 * Stores tab & current selection section registries.
25 * Keeps track of tab lifecycles.
26 */
27export class TabManager implements Disposable {
28  private _registry = new Map<string, TabDescriptor>();
29  private _defaultTabs = new Set<string>();
30  private _legacyDetailsPanelRegistry = new Set<LegacyDetailsPanel>();
31  private _detailsPanelRegistry = new Set<DetailsPanel>();
32  private _currentTabs = new Map<string, TabDescriptor>();
33
34  dispose(): void {
35    // Dispose of all tabs that are currently alive
36    for (const tab of this._currentTabs.values()) {
37      this.disposeTab(tab);
38    }
39    this._currentTabs.clear();
40  }
41
42  registerTab(desc: TabDescriptor): Disposable {
43    this._registry.set(desc.uri, desc);
44    return {
45      dispose: () => this._registry.delete(desc.uri),
46    };
47  }
48
49  addDefaultTab(uri: string): Disposable {
50    this._defaultTabs.add(uri);
51    return {
52      dispose: () => this._defaultTabs.delete(uri),
53    };
54  }
55
56  registerLegacyDetailsPanel(section: LegacyDetailsPanel): Disposable {
57    this._legacyDetailsPanelRegistry.add(section);
58    return {
59      dispose: () => this._legacyDetailsPanelRegistry.delete(section),
60    };
61  }
62
63  registerDetailsPanel(section: DetailsPanel): Disposable {
64    this._detailsPanelRegistry.add(section);
65    return {
66      dispose: () => this._detailsPanelRegistry.delete(section),
67    };
68  }
69
70  resolveTab(uri: string): TabDescriptor | undefined {
71    return this._registry.get(uri);
72  }
73
74  get tabs(): TabDescriptor[] {
75    return Array.from(this._registry.values());
76  }
77
78  get defaultTabs(): string[] {
79    return Array.from(this._defaultTabs);
80  }
81
82  get legacyDetailsPanels(): LegacyDetailsPanel[] {
83    return Array.from(this._legacyDetailsPanelRegistry);
84  }
85
86  get detailsPanels(): DetailsPanel[] {
87    return Array.from(this._detailsPanelRegistry);
88  }
89
90  /**
91   * Resolves a list of URIs to tabs and manages tab lifecycles.
92   * @param tabUris List of tabs.
93   * @return List of resolved tabs.
94   */
95  resolveTabs(tabUris: string[]): ResolvedTab[] {
96    // Refresh the list of old tabs
97    const newTabs = new Map<string, TabDescriptor>();
98    const tabs: ResolvedTab[] = [];
99
100    tabUris.forEach((uri) => {
101      const newTab = this._registry.get(uri);
102      tabs.push({uri, tab: newTab});
103
104      if (newTab) {
105        newTabs.set(uri, newTab);
106      }
107    });
108
109    // Call onShow() on any new tabs.
110    for (const [uri, tab] of newTabs) {
111      const oldTab = this._currentTabs.get(uri);
112      if (!oldTab) {
113        this.initTab(tab);
114      }
115    }
116
117    // Call onHide() on any tabs that have been removed.
118    for (const [uri, tab] of this._currentTabs) {
119      const newTab = newTabs.get(uri);
120      if (!newTab) {
121        this.disposeTab(tab);
122      }
123    }
124
125    this._currentTabs = newTabs;
126
127    return tabs;
128  }
129
130  /**
131   * Call onShow() on this tab.
132   * @param tab The tab to initialize.
133   */
134  private initTab(tab: TabDescriptor): void {
135    tab.onShow?.();
136  }
137
138  /**
139   * Call onHide() and maybe remove from registry if tab is ephemeral.
140   * @param tab The tab to dispose.
141   */
142  private disposeTab(tab: TabDescriptor): void {
143    // Attempt to call onHide
144    tab.onHide?.();
145
146    // If ephemeral, also unregister the tab
147    if (tab.isEphemeral) {
148      this._registry.delete(tab.uri);
149    }
150  }
151}
152