1 // Copyright (c) 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 #include "chrome/browser/ui/bookmarks/bookmark_utils.h" 6 7 #include "base/basictypes.h" 8 #include "base/logging.h" 9 #include "base/prefs/pref_service.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "chrome/browser/bookmarks/bookmark_model.h" 12 #include "chrome/browser/bookmarks/bookmark_model_factory.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/search/search.h" 15 #include "chrome/browser/ui/app_list/app_list_util.h" 16 #include "chrome/browser/ui/bookmarks/bookmark_editor.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser_navigator.h" 19 #include "chrome/browser/ui/browser_window.h" 20 #include "chrome/browser/ui/simple_message_box.h" 21 #include "chrome/browser/ui/tabs/tab_strip_model.h" 22 #include "chrome/common/pref_names.h" 23 #include "chrome/common/url_constants.h" 24 #include "components/user_prefs/user_prefs.h" 25 #include "content/public/browser/web_contents.h" 26 #include "grit/chromium_strings.h" 27 #include "grit/generated_resources.h" 28 #include "net/base/net_util.h" 29 #include "ui/base/l10n/l10n_util.h" 30 31 namespace chrome { 32 33 int num_bookmark_urls_before_prompting = 15; 34 35 namespace { 36 37 // Iterator that iterates through a set of BookmarkNodes returning the URLs 38 // for nodes that are urls, or the URLs for the children of non-url urls. 39 // This does not recurse through all descendants, only immediate children. 40 // The following illustrates 41 // typical usage: 42 // OpenURLIterator iterator(nodes); 43 // while (iterator.has_next()) { 44 // const GURL* url = iterator.NextURL(); 45 // // do something with |urll|. 46 // } 47 class OpenURLIterator { 48 public: 49 explicit OpenURLIterator(const std::vector<const BookmarkNode*>& nodes) 50 : child_index_(0), 51 next_(NULL), 52 parent_(nodes.begin()), 53 end_(nodes.end()) { 54 FindNext(); 55 } 56 57 bool has_next() { return next_ != NULL;} 58 59 const GURL* NextURL() { 60 if (!has_next()) { 61 NOTREACHED(); 62 return NULL; 63 } 64 65 const GURL* next = next_; 66 FindNext(); 67 return next; 68 } 69 70 private: 71 // Seach next node which has URL. 72 void FindNext() { 73 for (; parent_ < end_; ++parent_, child_index_ = 0) { 74 if ((*parent_)->is_url()) { 75 next_ = &(*parent_)->url(); 76 ++parent_; 77 child_index_ = 0; 78 return; 79 } else { 80 for (; child_index_ < (*parent_)->child_count(); ++child_index_) { 81 const BookmarkNode* child = (*parent_)->GetChild(child_index_); 82 if (child->is_url()) { 83 next_ = &child->url(); 84 ++child_index_; 85 return; 86 } 87 } 88 } 89 } 90 next_ = NULL; 91 } 92 93 int child_index_; 94 const GURL* next_; 95 std::vector<const BookmarkNode*>::const_iterator parent_; 96 const std::vector<const BookmarkNode*>::const_iterator end_; 97 98 DISALLOW_COPY_AND_ASSIGN(OpenURLIterator); 99 }; 100 101 bool ShouldOpenAll(gfx::NativeWindow parent, 102 const std::vector<const BookmarkNode*>& nodes) { 103 int child_count = 0; 104 OpenURLIterator iterator(nodes); 105 while (iterator.has_next()) { 106 iterator.NextURL(); 107 child_count++; 108 } 109 110 if (child_count < num_bookmark_urls_before_prompting) 111 return true; 112 113 return ShowMessageBox(parent, 114 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 115 l10n_util::GetStringFUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL, 116 base::IntToString16(child_count)), 117 MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES; 118 } 119 120 // Returns the total number of descendants nodes. 121 int ChildURLCountTotal(const BookmarkNode* node) { 122 int result = 0; 123 for (int i = 0; i < node->child_count(); ++i) { 124 const BookmarkNode* child = node->GetChild(i); 125 result++; 126 if (child->is_folder()) 127 result += ChildURLCountTotal(child); 128 } 129 return result; 130 } 131 132 // Returns in |urls|, the url and title pairs for each open tab in browser. 133 void GetURLsForOpenTabs(Browser* browser, 134 std::vector<std::pair<GURL, base::string16> >* urls) { 135 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { 136 std::pair<GURL, base::string16> entry; 137 GetURLAndTitleToBookmark(browser->tab_strip_model()->GetWebContentsAt(i), 138 &(entry.first), &(entry.second)); 139 urls->push_back(entry); 140 } 141 } 142 143 } // namespace 144 145 void OpenAll(gfx::NativeWindow parent, 146 content::PageNavigator* navigator, 147 const std::vector<const BookmarkNode*>& nodes, 148 WindowOpenDisposition initial_disposition, 149 content::BrowserContext* browser_context) { 150 if (!ShouldOpenAll(parent, nodes)) 151 return; 152 153 // Opens all |nodes| of type URL and any children of |nodes| that are of type 154 // URL. |navigator| is the PageNavigator used to open URLs. After the first 155 // url is opened |opened_first_url| is set to true and |navigator| is set to 156 // the PageNavigator of the last active tab. This is done to handle a window 157 // disposition of new window, in which case we want subsequent tabs to open in 158 // that window. 159 bool opened_first_url = false; 160 WindowOpenDisposition disposition = initial_disposition; 161 OpenURLIterator iterator(nodes); 162 while (iterator.has_next()) { 163 const GURL* url = iterator.NextURL(); 164 // When |initial_disposition| is OFF_THE_RECORD, a node which can't be 165 // opened in incognito window, it is detected using |browser_context|, is 166 // not opened. 167 if (initial_disposition == OFF_THE_RECORD && 168 !IsURLAllowedInIncognito(*url, browser_context)) 169 continue; 170 171 content::WebContents* opened_tab = navigator->OpenURL( 172 content::OpenURLParams(*url, content::Referrer(), disposition, 173 content::PAGE_TRANSITION_AUTO_BOOKMARK, false)); 174 175 if (!opened_first_url) { 176 opened_first_url = true; 177 disposition = NEW_BACKGROUND_TAB; 178 // We opened the first URL which may have opened a new window or clobbered 179 // the current page, reset the navigator just to be sure. |opened_tab| may 180 // be NULL in tests. 181 if (opened_tab) 182 navigator = opened_tab; 183 } 184 } 185 } 186 187 void OpenAll(gfx::NativeWindow parent, 188 content::PageNavigator* navigator, 189 const BookmarkNode* node, 190 WindowOpenDisposition initial_disposition, 191 content::BrowserContext* browser_context) { 192 std::vector<const BookmarkNode*> nodes; 193 nodes.push_back(node); 194 OpenAll(parent, navigator, nodes, initial_disposition, browser_context); 195 } 196 197 bool ConfirmDeleteBookmarkNode(const BookmarkNode* node, 198 gfx::NativeWindow window) { 199 DCHECK(node && node->is_folder() && !node->empty()); 200 return ShowMessageBox(window, 201 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), 202 l10n_util::GetStringFUTF16Int(IDS_BOOKMARK_EDITOR_CONFIRM_DELETE, 203 ChildURLCountTotal(node)), 204 MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES; 205 } 206 207 void ShowBookmarkAllTabsDialog(Browser* browser) { 208 Profile* profile = browser->profile(); 209 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); 210 DCHECK(model && model->loaded()); 211 212 const BookmarkNode* parent = model->GetParentForNewNodes(); 213 BookmarkEditor::EditDetails details = 214 BookmarkEditor::EditDetails::AddFolder(parent, parent->child_count()); 215 GetURLsForOpenTabs(browser, &(details.urls)); 216 DCHECK(!details.urls.empty()); 217 218 BookmarkEditor::Show(browser->window()->GetNativeWindow(), profile, details, 219 BookmarkEditor::SHOW_TREE); 220 } 221 222 bool HasBookmarkURLs(const std::vector<const BookmarkNode*>& selection) { 223 OpenURLIterator iterator(selection); 224 return iterator.has_next(); 225 } 226 227 bool HasBookmarkURLsAllowedInIncognitoMode( 228 const std::vector<const BookmarkNode*>& selection, 229 content::BrowserContext* browser_context) { 230 OpenURLIterator iterator(selection); 231 while (iterator.has_next()) { 232 const GURL* url = iterator.NextURL(); 233 if (IsURLAllowedInIncognito(*url, browser_context)) 234 return true; 235 } 236 return false; 237 } 238 239 GURL GetURLToBookmark(content::WebContents* web_contents) { 240 DCHECK(web_contents); 241 return IsInstantNTP(web_contents) ? 242 GURL(kChromeUINewTabURL) : web_contents->GetURL(); 243 } 244 245 void GetURLAndTitleToBookmark(content::WebContents* web_contents, 246 GURL* url, 247 base::string16* title) { 248 *url = GetURLToBookmark(web_contents); 249 *title = web_contents->GetTitle(); 250 } 251 252 void ToggleBookmarkBarWhenVisible(content::BrowserContext* browser_context) { 253 PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); 254 const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar); 255 256 // The user changed when the bookmark bar is shown, update the preferences. 257 prefs->SetBoolean(prefs::kShowBookmarkBar, always_show); 258 } 259 260 base::string16 FormatBookmarkURLForDisplay(const GURL& url, 261 const PrefService* prefs) { 262 std::string languages; 263 if (prefs) 264 languages = prefs->GetString(prefs::kAcceptLanguages); 265 266 // Because this gets re-parsed by FixupURL(), it's safe to omit the scheme 267 // and trailing slash, and unescape most characters. However, it's 268 // important not to drop any username/password, or unescape anything that 269 // changes the URL's meaning. 270 return net::FormatUrl( 271 url, languages, 272 net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword, 273 net::UnescapeRule::SPACES, NULL, NULL, NULL); 274 } 275 276 bool IsAppsShortcutEnabled(Profile* profile, 277 chrome::HostDesktopType host_desktop_type) { 278 // Managed users can not have apps installed currently so there's no need to 279 // show the apps shortcut. 280 if (profile->IsManaged()) 281 return false; 282 283 // Don't show the apps shortcut in ash since the app launcher is enabled. 284 if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) 285 return false; 286 287 return chrome::IsInstantExtendedAPIEnabled() && !profile->IsOffTheRecord(); 288 } 289 290 bool ShouldShowAppsShortcutInBookmarkBar( 291 Profile* profile, 292 chrome::HostDesktopType host_desktop_type) { 293 return IsAppsShortcutEnabled(profile, host_desktop_type) && 294 profile->GetPrefs()->GetBoolean(prefs::kShowAppsShortcutInBookmarkBar); 295 } 296 297 } // namespace chrome 298