// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/bookmarks/bookmark_utils.h" #include "base/basictypes.h" #include "base/logging.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" #include "chrome/browser/ui/app_list/app_list_util.h" #include "chrome/browser/ui/bookmarks/bookmark_editor.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/simple_message_box.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "components/user_prefs/user_prefs.h" #include "content/public/browser/web_contents.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "net/base/net_util.h" #include "ui/base/l10n/l10n_util.h" namespace chrome { int num_bookmark_urls_before_prompting = 15; namespace { // Iterator that iterates through a set of BookmarkNodes returning the URLs // for nodes that are urls, or the URLs for the children of non-url urls. // This does not recurse through all descendants, only immediate children. // The following illustrates // typical usage: // OpenURLIterator iterator(nodes); // while (iterator.has_next()) { // const GURL* url = iterator.NextURL(); // // do something with |urll|. // } class OpenURLIterator { public: explicit OpenURLIterator(const std::vector<const BookmarkNode*>& nodes) : child_index_(0), next_(NULL), parent_(nodes.begin()), end_(nodes.end()) { FindNext(); } bool has_next() { return next_ != NULL;} const GURL* NextURL() { if (!has_next()) { NOTREACHED(); return NULL; } const GURL* next = next_; FindNext(); return next; } private: // Seach next node which has URL. void FindNext() { for (; parent_ < end_; ++parent_, child_index_ = 0) { if ((*parent_)->is_url()) { next_ = &(*parent_)->url(); ++parent_; child_index_ = 0; return; } else { for (; child_index_ < (*parent_)->child_count(); ++child_index_) { const BookmarkNode* child = (*parent_)->GetChild(child_index_); if (child->is_url()) { next_ = &child->url(); ++child_index_; return; } } } } next_ = NULL; } int child_index_; const GURL* next_; std::vector<const BookmarkNode*>::const_iterator parent_; const std::vector<const BookmarkNode*>::const_iterator end_; DISALLOW_COPY_AND_ASSIGN(OpenURLIterator); }; bool ShouldOpenAll(gfx::NativeWindow parent, const std::vector<const BookmarkNode*>& nodes) { int child_count = 0; OpenURLIterator iterator(nodes); while (iterator.has_next()) { iterator.NextURL(); child_count++; } if (child_count < num_bookmark_urls_before_prompting) return true; return ShowMessageBox(parent, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), l10n_util::GetStringFUTF16(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL, base::IntToString16(child_count)), MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES; } // Returns the total number of descendants nodes. int ChildURLCountTotal(const BookmarkNode* node) { int result = 0; for (int i = 0; i < node->child_count(); ++i) { const BookmarkNode* child = node->GetChild(i); result++; if (child->is_folder()) result += ChildURLCountTotal(child); } return result; } // Returns in |urls|, the url and title pairs for each open tab in browser. void GetURLsForOpenTabs(Browser* browser, std::vector<std::pair<GURL, base::string16> >* urls) { for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { std::pair<GURL, base::string16> entry; GetURLAndTitleToBookmark(browser->tab_strip_model()->GetWebContentsAt(i), &(entry.first), &(entry.second)); urls->push_back(entry); } } } // namespace void OpenAll(gfx::NativeWindow parent, content::PageNavigator* navigator, const std::vector<const BookmarkNode*>& nodes, WindowOpenDisposition initial_disposition, content::BrowserContext* browser_context) { if (!ShouldOpenAll(parent, nodes)) return; // Opens all |nodes| of type URL and any children of |nodes| that are of type // URL. |navigator| is the PageNavigator used to open URLs. After the first // url is opened |opened_first_url| is set to true and |navigator| is set to // the PageNavigator of the last active tab. This is done to handle a window // disposition of new window, in which case we want subsequent tabs to open in // that window. bool opened_first_url = false; WindowOpenDisposition disposition = initial_disposition; OpenURLIterator iterator(nodes); while (iterator.has_next()) { const GURL* url = iterator.NextURL(); // When |initial_disposition| is OFF_THE_RECORD, a node which can't be // opened in incognito window, it is detected using |browser_context|, is // not opened. if (initial_disposition == OFF_THE_RECORD && !IsURLAllowedInIncognito(*url, browser_context)) continue; content::WebContents* opened_tab = navigator->OpenURL( content::OpenURLParams(*url, content::Referrer(), disposition, content::PAGE_TRANSITION_AUTO_BOOKMARK, false)); if (!opened_first_url) { opened_first_url = true; disposition = NEW_BACKGROUND_TAB; // We opened the first URL which may have opened a new window or clobbered // the current page, reset the navigator just to be sure. |opened_tab| may // be NULL in tests. if (opened_tab) navigator = opened_tab; } } } void OpenAll(gfx::NativeWindow parent, content::PageNavigator* navigator, const BookmarkNode* node, WindowOpenDisposition initial_disposition, content::BrowserContext* browser_context) { std::vector<const BookmarkNode*> nodes; nodes.push_back(node); OpenAll(parent, navigator, nodes, initial_disposition, browser_context); } bool ConfirmDeleteBookmarkNode(const BookmarkNode* node, gfx::NativeWindow window) { DCHECK(node && node->is_folder() && !node->empty()); return ShowMessageBox(window, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), l10n_util::GetStringFUTF16Int(IDS_BOOKMARK_EDITOR_CONFIRM_DELETE, ChildURLCountTotal(node)), MESSAGE_BOX_TYPE_QUESTION) == MESSAGE_BOX_RESULT_YES; } void ShowBookmarkAllTabsDialog(Browser* browser) { Profile* profile = browser->profile(); BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); DCHECK(model && model->loaded()); const BookmarkNode* parent = model->GetParentForNewNodes(); BookmarkEditor::EditDetails details = BookmarkEditor::EditDetails::AddFolder(parent, parent->child_count()); GetURLsForOpenTabs(browser, &(details.urls)); DCHECK(!details.urls.empty()); BookmarkEditor::Show(browser->window()->GetNativeWindow(), profile, details, BookmarkEditor::SHOW_TREE); } bool HasBookmarkURLs(const std::vector<const BookmarkNode*>& selection) { OpenURLIterator iterator(selection); return iterator.has_next(); } bool HasBookmarkURLsAllowedInIncognitoMode( const std::vector<const BookmarkNode*>& selection, content::BrowserContext* browser_context) { OpenURLIterator iterator(selection); while (iterator.has_next()) { const GURL* url = iterator.NextURL(); if (IsURLAllowedInIncognito(*url, browser_context)) return true; } return false; } GURL GetURLToBookmark(content::WebContents* web_contents) { DCHECK(web_contents); return IsInstantNTP(web_contents) ? GURL(kChromeUINewTabURL) : web_contents->GetURL(); } void GetURLAndTitleToBookmark(content::WebContents* web_contents, GURL* url, base::string16* title) { *url = GetURLToBookmark(web_contents); *title = web_contents->GetTitle(); } void ToggleBookmarkBarWhenVisible(content::BrowserContext* browser_context) { PrefService* prefs = user_prefs::UserPrefs::Get(browser_context); const bool always_show = !prefs->GetBoolean(prefs::kShowBookmarkBar); // The user changed when the bookmark bar is shown, update the preferences. prefs->SetBoolean(prefs::kShowBookmarkBar, always_show); } base::string16 FormatBookmarkURLForDisplay(const GURL& url, const PrefService* prefs) { std::string languages; if (prefs) languages = prefs->GetString(prefs::kAcceptLanguages); // Because this gets re-parsed by FixupURL(), it's safe to omit the scheme // and trailing slash, and unescape most characters. However, it's // important not to drop any username/password, or unescape anything that // changes the URL's meaning. return net::FormatUrl( url, languages, net::kFormatUrlOmitAll & ~net::kFormatUrlOmitUsernamePassword, net::UnescapeRule::SPACES, NULL, NULL, NULL); } bool IsAppsShortcutEnabled(Profile* profile, chrome::HostDesktopType host_desktop_type) { // Managed users can not have apps installed currently so there's no need to // show the apps shortcut. if (profile->IsManaged()) return false; // Don't show the apps shortcut in ash since the app launcher is enabled. if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) return false; return chrome::IsInstantExtendedAPIEnabled() && !profile->IsOffTheRecord(); } bool ShouldShowAppsShortcutInBookmarkBar( Profile* profile, chrome::HostDesktopType host_desktop_type) { return IsAppsShortcutEnabled(profile, host_desktop_type) && profile->GetPrefs()->GetBoolean(prefs::kShowAppsShortcutInBookmarkBar); } } // namespace chrome