pinned_tab_codec.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/pinned_tab_codec.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/pref_service.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/scoped_user_pref_update.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tab_contents/tab_contents.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationEntry; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Key used in dictionaries for the app id. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kAppID[] = "app_id"; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Key used in dictionaries for the url. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kURL[] = "url"; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |browser| has any pinned tabs. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool HasPinnedTabs(Browser* browser) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStripModel* tab_model = browser->tab_strip_model(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_model->count(); ++i) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_model->IsTabPinned(i)) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adds a DictionaryValue to |values| representing |tab|. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EncodeTab(const StartupTab& tab, ListValue* values) { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> value(new DictionaryValue); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kURL, tab.url.spec()); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab.is_app) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kAppID, tab.app_id); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Append(value.release()); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adds a DictionaryValue to |values| representing the pinned tab at the 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specified index. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EncodePinnedTab(TabStripModel* model, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue* values) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> value(new DictionaryValue()); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::WebContents* web_contents = 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->GetTabContentsAt(index)->web_contents(); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model->IsAppTab(index)) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Extension* extension = 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::TabHelper::FromWebContents(web_contents)->extension_app(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(extension); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kAppID, extension->id()); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For apps we use the launch url. We do this because the user is 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // effectively restarting the app, so returning them to the app's launch 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // page seems closest to what they expect. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kURL, extension->GetFullLaunchURL().spec()); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Append(value.release()); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NavigationEntry* entry = web_contents->GetController().GetActiveEntry(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry && web_contents->GetController().GetEntryCount()) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry = web_contents->GetController().GetEntryAtIndex(0); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kURL, entry->GetURL().spec()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Append(value.release()); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Invokes EncodePinnedTab for each pinned tab in browser. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EncodePinnedTabs(Browser* browser, ListValue* values) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStripModel* tab_model = browser->tab_strip_model(); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_model->count() && tab_model->IsTabPinned(i); ++i) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodePinnedTab(tab_model, i, values); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Decodes the previously written values in |value| to |tab|, returning true 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on success. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool DecodeTab(const DictionaryValue& value, StartupTab* tab) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->is_app = false; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_string; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.GetString(kURL, &url_string)) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->url = GURL(url_string); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value.GetString(kAppID, &(tab->app_id))) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->is_app = true; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PinnedTabCodec::RegisterUserPrefs(PrefService* prefs) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs->RegisterListPref(prefs::kPinnedTabs, PrefService::UNSYNCABLE_PREF); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PinnedTabCodec::WritePinnedTabs(Profile* profile) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = profile->GetPrefs(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!prefs) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue values; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (BrowserList::const_iterator i = BrowserList::begin(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != BrowserList::end(); ++i) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Browser* browser = *i; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (browser->is_type_tabbed() && 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser->profile() == profile && HasPinnedTabs(browser)) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodePinnedTabs(browser, &values); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs->Set(prefs::kPinnedTabs, values); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PinnedTabCodec::WritePinnedTabs(Profile* profile, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const StartupTabs& tabs) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = profile->GetPrefs(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!prefs) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListPrefUpdate update(prefs, prefs::kPinnedTabs); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue* values = update.Get(); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Clear(); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (StartupTabs::const_iterator i = tabs.begin(); i != tabs.end(); ++i) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodeTab(*i, values); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTabs PinnedTabCodec::ReadPinnedTabs(Profile* profile) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = profile->GetPrefs(); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!prefs) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return StartupTabs(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ReadPinnedTabs(prefs->GetList(prefs::kPinnedTabs)); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTabs PinnedTabCodec::ReadPinnedTabs(const base::Value* value) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartupTabs results; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::ListValue* tabs_list = NULL; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value->GetAsList(&tabs_list)) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return results; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0, max = tabs_list->GetSize(); i < max; ++i) { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::DictionaryValue* tab_values = NULL; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabs_list->GetDictionary(i, &tab_values)) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartupTab tab; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (DecodeTab(*tab_values, &tab)) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results.push_back(tab); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return results; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 164