1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_UI_TOOLBAR_RECENT_TABS_SUB_MENU_MODEL_H_
6#define CHROME_BROWSER_UI_TOOLBAR_RECENT_TABS_SUB_MENU_MODEL_H_
7
8#include <set>
9
10#include "base/memory/weak_ptr.h"
11#include "base/task/cancelable_task_tracker.h"
12#include "chrome/browser/favicon/favicon_service.h"
13#include "chrome/browser/sessions/tab_restore_service.h"
14#include "chrome/browser/sessions/tab_restore_service_observer.h"
15#include "chrome/browser/sync/glue/synced_session.h"
16#include "ui/base/accelerators/accelerator.h"
17#include "ui/base/models/simple_menu_model.h"
18
19class Browser;
20struct SessionTab;
21
22namespace browser_sync {
23class OpenTabsUIDelegate;
24}
25
26namespace favicon_base {
27struct FaviconImageResult;
28}
29
30namespace gfx {
31class Image;
32}
33
34namespace ui {
35class AcceleratorProvider;
36}
37
38// A menu model that builds the contents of "Recent tabs" submenu, which include
39// the recently closed tabs/windows of current device i.e. local entries, and
40// opened tabs of other devices.
41class RecentTabsSubMenuModel : public ui::SimpleMenuModel,
42                               public ui::SimpleMenuModel::Delegate,
43                               public TabRestoreServiceObserver {
44 public:
45  // Command Id for recently closed items header or disabled item to which the
46  // accelerator string will be appended.
47  static const int kRecentlyClosedHeaderCommandId;
48  static const int kDisabledRecentlyClosedHeaderCommandId;
49
50  // Exposed for tests only: return the Command Id for the first entry in the
51  // recently closed window items list.
52  static int GetFirstRecentTabsCommandId();
53
54  // If |open_tabs_delegate| is NULL, the default delegate for |browser|'s
55  // profile will be used. Testing may require a specific |open_tabs_delegate|.
56  RecentTabsSubMenuModel(ui::AcceleratorProvider* accelerator_provider,
57                         Browser* browser,
58                         browser_sync::OpenTabsUIDelegate* open_tabs_delegate);
59  virtual ~RecentTabsSubMenuModel();
60
61  // Overridden from ui::SimpleMenuModel::Delegate:
62  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
63  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
64  virtual bool GetAcceleratorForCommandId(
65      int command_id,
66      ui::Accelerator* accelerator) OVERRIDE;
67  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
68  virtual const gfx::FontList* GetLabelFontListAt(int index) const OVERRIDE;
69
70  int GetMaxWidthForItemAtIndex(int item_index) const;
71  bool GetURLAndTitleForItemAtIndex(int index,
72                                    std::string* url,
73                                    base::string16* title);
74
75 private:
76  struct TabNavigationItem;
77  typedef std::vector<TabNavigationItem> TabNavigationItems;
78
79  typedef std::vector<SessionID::id_type> WindowItems;
80
81  // Build the menu items by populating the menumodel.
82  void Build();
83
84  // Build the recently closed tabs and windows items.
85  void BuildLocalEntries();
86
87  // Build the tabs items from other devices.
88  void BuildTabsFromOtherDevices();
89
90  // Build a recently closed tab item with parameters needed to restore it, and
91  // add it to the menumodel at |curr_model_index|.
92  void BuildLocalTabItem(int seesion_id,
93                         const base::string16& title,
94                         const GURL& url,
95                         int curr_model_index);
96
97  // Build the recently closed window item with parameters needed to restore it,
98  // and add it to the menumodel at |curr_model_index|.
99  void BuildLocalWindowItem(const SessionID::id_type& window_id,
100                            int num_tabs,
101                            int curr_model_index);
102
103  // Build the tab item for other devices with parameters needed to restore it.
104  void BuildOtherDevicesTabItem(const std::string& session_tag,
105                                const SessionTab& tab);
106
107  // Add the favicon for the device section header.
108  void AddDeviceFavicon(int index_in_menu,
109                        browser_sync::SyncedSession::DeviceType device_type);
110
111  // Add the favicon for a local or other devices' tab asynchronously,
112  // OnFaviconDataAvailable() will be invoked when the favicon is ready.
113  void AddTabFavicon(int command_id, const GURL& url);
114  void OnFaviconDataAvailable(
115      int command_id,
116      const favicon_base::FaviconImageResult& image_result);
117
118  // Clear all recently closed tabs and windows.
119  void ClearLocalEntries();
120
121  // Converts |command_id| of menu item to index in local or other devices'
122  // TabNavigationItems, and returns the corresponding local or other devices'
123  // TabNavigationItems in |tab_items|.
124  int CommandIdToTabVectorIndex(int command_id, TabNavigationItems** tab_items);
125
126  // Used to access (and lazily initialize) open_tabs_delegate_.
127  // TODO(tim): This lazy-init for member variables is error prone because you
128  // can always skip going through the function and access the field directly.
129  // Consider instead having code just deal with potentially NULL open_tabs_
130  // and have it initialized by an event / callback.
131  browser_sync::OpenTabsUIDelegate* GetOpenTabsUIDelegate();
132
133  // Overridden from TabRestoreServiceObserver:
134  virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE;
135  virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE;
136
137  Browser* browser_;  // Weak.
138
139  browser_sync::OpenTabsUIDelegate* open_tabs_delegate_;  // Weak.
140
141  // Accelerator for reopening last closed tab.
142  ui::Accelerator reopen_closed_tab_accelerator_;
143
144  // Navigation items for local recently closed tabs.  The |command_id| for
145  // these is set to |kFirstLocalTabCommandId| plus the index into the vector.
146  // Upon invocation of the menu, the navigation information is retrieved from
147  // |local_tab_navigation_items_| and used to navigate to the item specified.
148  TabNavigationItems local_tab_navigation_items_;
149
150  // Similar to |local_tab_navigation_items_| except the tabs are opened tabs
151  // from other devices, and the first |command_id| is
152  // |kFirstOtherDevicesTabCommandId|.
153  TabNavigationItems other_devices_tab_navigation_items_;
154
155  // Window items for local recently closed windows.  The |command_id| for
156  // these is set to |kFirstLocalWindowCommandId| plus the index into the
157  // vector.  Upon invocation of the menu, information is retrieved from
158  // |local_window_items_| and used to create the specified window.
159  WindowItems local_window_items_;
160
161  // Index of the last local entry (recently closed tab or window) in the
162  // menumodel.
163  int last_local_model_index_;
164
165  gfx::Image default_favicon_;
166
167  base::CancelableTaskTracker local_tab_cancelable_task_tracker_;
168  base::CancelableTaskTracker other_devices_tab_cancelable_task_tracker_;
169
170  base::WeakPtrFactory<RecentTabsSubMenuModel> weak_ptr_factory_;
171
172  DISALLOW_COPY_AND_ASSIGN(RecentTabsSubMenuModel);
173};
174
175#endif  // CHROME_BROWSER_UI_TOOLBAR_RECENT_TABS_SUB_MENU_MODEL_H_
176