pinned_tab_codec.cc revision f2477e01787aa58f445919b809d89e252beef54f
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) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_iterator.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationEntry; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Key used in dictionaries for the app id. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kAppID[] = "app_id"; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Key used in dictionaries for the url. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kURL[] = "url"; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if |browser| has any pinned tabs. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool HasPinnedTabs(Browser* browser) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStripModel* tab_model = browser->tab_strip_model(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_model->count(); ++i) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_model->IsTabPinned(i)) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adds a DictionaryValue to |values| representing |tab|. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EncodeTab(const StartupTab& tab, ListValue* values) { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> value(new DictionaryValue); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kURL, tab.url.spec()); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab.is_app) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kAppID, tab.app_id); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Append(value.release()); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adds a DictionaryValue to |values| representing the pinned tab at the 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specified index. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EncodePinnedTab(TabStripModel* model, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue* values) { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DictionaryValue> value(new DictionaryValue()); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* web_contents = model->GetWebContentsAt(index); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model->IsAppTab(index)) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const extensions::Extension* extension = 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::TabHelper::FromWebContents(web_contents)->extension_app(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(extension); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kAppID, extension->id()); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For apps we use the launch url. We do this because the user is 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // effectively restarting the app, so returning them to the app's launch 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // page seems closest to what they expect. 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) value->SetString( 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kURL, extensions::AppLaunchInfo::GetFullLaunchURL(extension).spec()); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Append(value.release()); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NavigationEntry* entry = web_contents->GetController().GetActiveEntry(); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!entry && web_contents->GetController().GetEntryCount()) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) entry = web_contents->GetController().GetEntryAtIndex(0); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->SetString(kURL, entry->GetURL().spec()); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Append(value.release()); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Invokes EncodePinnedTab for each pinned tab in browser. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EncodePinnedTabs(Browser* browser, ListValue* values) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TabStripModel* tab_model = browser->tab_strip_model(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < tab_model->count() && tab_model->IsTabPinned(i); ++i) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodePinnedTab(tab_model, i, values); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Decodes the previously written values in |value| to |tab|, returning true 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on success. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool DecodeTab(const DictionaryValue& value, StartupTab* tab) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->is_app = false; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_string; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.GetString(kURL, &url_string)) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->url = GURL(url_string); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value.GetString(kAppID, &(tab->app_id))) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tab->is_app = true; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PinnedTabCodec::RegisterProfilePrefs( 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_prefs::PrefRegistrySyncable* registry) { 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterListPref(prefs::kPinnedTabs, 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PinnedTabCodec::WritePinnedTabs(Profile* profile) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = profile->GetPrefs(); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!prefs) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue values; 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (chrome::BrowserIterator it; !it.done(); it.Next()) { 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Browser* browser = *it; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (browser->is_type_tabbed() && 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser->profile() == profile && HasPinnedTabs(browser)) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodePinnedTabs(browser, &values); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs->Set(prefs::kPinnedTabs, values); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PinnedTabCodec::WritePinnedTabs(Profile* profile, 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const StartupTabs& tabs) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = profile->GetPrefs(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!prefs) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListPrefUpdate update(prefs, prefs::kPinnedTabs); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListValue* values = update.Get(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values->Clear(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (StartupTabs::const_iterator i = tabs.begin(); i != tabs.end(); ++i) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodeTab(*i, values); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTabs PinnedTabCodec::ReadPinnedTabs(Profile* profile) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrefService* prefs = profile->GetPrefs(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!prefs) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return StartupTabs(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ReadPinnedTabs(prefs->GetList(prefs::kPinnedTabs)); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupTabs PinnedTabCodec::ReadPinnedTabs(const base::Value* value) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartupTabs results; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::ListValue* tabs_list = NULL; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value->GetAsList(&tabs_list)) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return results; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0, max = tabs_list->GetSize(); i < max; ++i) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::DictionaryValue* tab_values = NULL; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tabs_list->GetDictionary(i, &tab_values)) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartupTab tab; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (DecodeTab(*tab_values, &tab)) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results.push_back(tab); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return results; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 167