blob: 08cb2c7768f5110b6cdece9581e39f286f85baa7 [file] [log] [blame]
// 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