• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/custom_home_pages_table_model.h"
6 
7 #include "base/i18n/rtl.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/prefs/pref_service.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_list.h"
13 #include "chrome/common/pref_names.h"
14 #include "chrome/common/url_constants.h"
15 #include "content/browser/tab_contents/tab_contents.h"
16 #include "googleurl/src/gurl.h"
17 #include "grit/app_resources.h"
18 #include "grit/generated_resources.h"
19 #include "net/base/net_util.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/models/table_model_observer.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/gfx/codec/png_codec.h"
25 
26 struct CustomHomePagesTableModel::Entry {
EntryCustomHomePagesTableModel::Entry27   Entry() : title_handle(0), favicon_handle(0) {}
28 
29   // URL of the page.
30   GURL url;
31 
32   // Page title.  If this is empty, we'll display the URL as the entry.
33   string16 title;
34 
35   // Icon for the page.
36   SkBitmap icon;
37 
38   // If non-zero, indicates we're loading the title for the page.
39   HistoryService::Handle title_handle;
40 
41   // If non-zero, indicates we're loading the favicon for the page.
42   FaviconService::Handle favicon_handle;
43 };
44 
CustomHomePagesTableModel(Profile * profile)45 CustomHomePagesTableModel::CustomHomePagesTableModel(Profile* profile)
46     : default_favicon_(NULL),
47       profile_(profile),
48       observer_(NULL) {
49   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
50   default_favicon_ = rb.GetBitmapNamed(IDR_DEFAULT_FAVICON);
51 }
52 
~CustomHomePagesTableModel()53 CustomHomePagesTableModel::~CustomHomePagesTableModel() {
54 }
55 
SetURLs(const std::vector<GURL> & urls)56 void CustomHomePagesTableModel::SetURLs(const std::vector<GURL>& urls) {
57   entries_.resize(urls.size());
58   for (size_t i = 0; i < urls.size(); ++i) {
59     entries_[i].url = urls[i];
60     entries_[i].title.erase();
61     entries_[i].icon.reset();
62     LoadTitleAndFavicon(&(entries_[i]));
63   }
64   // Complete change, so tell the view to just rebuild itself.
65   if (observer_)
66     observer_->OnModelChanged();
67 }
68 
Add(int index,const GURL & url)69 void CustomHomePagesTableModel::Add(int index, const GURL& url) {
70   DCHECK(index >= 0 && index <= RowCount());
71   entries_.insert(entries_.begin() + static_cast<size_t>(index), Entry());
72   entries_[index].url = url;
73   LoadTitleAndFavicon(&(entries_[index]));
74   if (observer_)
75     observer_->OnItemsAdded(index, 1);
76 }
77 
Remove(int index)78 void CustomHomePagesTableModel::Remove(int index) {
79   DCHECK(index >= 0 && index < RowCount());
80   Entry* entry = &(entries_[index]);
81   // Cancel any pending load requests now so we don't deref a bogus pointer when
82   // we get the loaded notification.
83   if (entry->title_handle) {
84     HistoryService* history_service =
85         profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
86     if (history_service)
87       history_service->CancelRequest(entry->title_handle);
88   }
89   if (entry->favicon_handle) {
90     FaviconService* favicon_service =
91         profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
92     if (favicon_service)
93       favicon_service->CancelRequest(entry->favicon_handle);
94   }
95   entries_.erase(entries_.begin() + static_cast<size_t>(index));
96   if (observer_)
97     observer_->OnItemsRemoved(index, 1);
98 }
99 
SetToCurrentlyOpenPages()100 void CustomHomePagesTableModel::SetToCurrentlyOpenPages() {
101   // Remove the current entries.
102   while (RowCount())
103     Remove(0);
104 
105   // And add all tabs for all open browsers with our profile.
106   int add_index = 0;
107   for (BrowserList::const_iterator browser_i = BrowserList::begin();
108        browser_i != BrowserList::end(); ++browser_i) {
109     Browser* browser = *browser_i;
110     if (browser->profile() != profile_)
111       continue;  // Skip incognito browsers.
112 
113     for (int tab_index = 0; tab_index < browser->tab_count(); ++tab_index) {
114       const GURL url = browser->GetTabContentsAt(tab_index)->GetURL();
115       if (!url.is_empty() &&
116           !(url.SchemeIs(chrome::kChromeUIScheme) &&
117             url.host() == chrome::kChromeUISettingsHost))
118         Add(add_index++, url);
119     }
120   }
121 }
122 
GetURLs()123 std::vector<GURL> CustomHomePagesTableModel::GetURLs() {
124   std::vector<GURL> urls(entries_.size());
125   for (size_t i = 0; i < entries_.size(); ++i)
126     urls[i] = entries_[i].url;
127   return urls;
128 }
129 
RowCount()130 int CustomHomePagesTableModel::RowCount() {
131   return static_cast<int>(entries_.size());
132 }
133 
GetText(int row,int column_id)134 string16 CustomHomePagesTableModel::GetText(int row, int column_id) {
135   DCHECK(column_id == 0);
136   DCHECK(row >= 0 && row < RowCount());
137   return entries_[row].title.empty() ? FormattedURL(row) : entries_[row].title;
138 }
139 
GetIcon(int row)140 SkBitmap CustomHomePagesTableModel::GetIcon(int row) {
141   DCHECK(row >= 0 && row < RowCount());
142   return entries_[row].icon.isNull() ? *default_favicon_ : entries_[row].icon;
143 }
144 
GetTooltip(int row)145 string16 CustomHomePagesTableModel::GetTooltip(int row) {
146   return entries_[row].title.empty() ? string16() :
147       l10n_util::GetStringFUTF16(IDS_OPTIONS_STARTUP_PAGE_TOOLTIP,
148                                  entries_[row].title, FormattedURL(row));
149 }
150 
SetObserver(ui::TableModelObserver * observer)151 void CustomHomePagesTableModel::SetObserver(ui::TableModelObserver* observer) {
152   observer_ = observer;
153 }
154 
LoadTitleAndFavicon(Entry * entry)155 void CustomHomePagesTableModel::LoadTitleAndFavicon(Entry* entry) {
156   HistoryService* history_service =
157       profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
158   if (history_service) {
159     entry->title_handle = history_service->QueryURL(entry->url, false,
160         &query_consumer_,
161         NewCallback(this, &CustomHomePagesTableModel::OnGotTitle));
162   }
163   FaviconService* favicon_service =
164       profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
165   if (favicon_service) {
166     entry->favicon_handle = favicon_service->GetFaviconForURL(entry->url,
167         history::FAVICON, &query_consumer_,
168         NewCallback(this, &CustomHomePagesTableModel::OnGotFavicon));
169   }
170 }
171 
OnGotTitle(HistoryService::Handle handle,bool found_url,const history::URLRow * row,history::VisitVector * visits)172 void CustomHomePagesTableModel::OnGotTitle(HistoryService::Handle handle,
173                                            bool found_url,
174                                            const history::URLRow* row,
175                                            history::VisitVector* visits) {
176   int entry_index;
177   Entry* entry =
178       GetEntryByLoadHandle(&Entry::title_handle, handle, &entry_index);
179   if (!entry) {
180     // The URLs changed before we were called back.
181     return;
182   }
183   entry->title_handle = 0;
184   if (found_url && !row->title().empty()) {
185     entry->title = row->title();
186     if (observer_)
187       observer_->OnItemsChanged(static_cast<int>(entry_index), 1);
188   }
189 }
190 
OnGotFavicon(FaviconService::Handle handle,history::FaviconData favicon)191 void CustomHomePagesTableModel::OnGotFavicon(
192     FaviconService::Handle handle,
193     history::FaviconData favicon) {
194   int entry_index;
195   Entry* entry =
196       GetEntryByLoadHandle(&Entry::favicon_handle, handle, &entry_index);
197   if (!entry) {
198     // The URLs changed before we were called back.
199     return;
200   }
201   entry->favicon_handle = 0;
202   if (favicon.is_valid()) {
203     int width, height;
204     std::vector<unsigned char> decoded_data;
205     if (gfx::PNGCodec::Decode(favicon.image_data->front(),
206                               favicon.image_data->size(),
207                               gfx::PNGCodec::FORMAT_BGRA, &decoded_data,
208                               &width, &height)) {
209       entry->icon.setConfig(SkBitmap::kARGB_8888_Config, width, height);
210       entry->icon.allocPixels();
211       memcpy(entry->icon.getPixels(), &decoded_data.front(),
212              width * height * 4);
213       if (observer_)
214         observer_->OnItemsChanged(static_cast<int>(entry_index), 1);
215     }
216   }
217 }
218 
219 CustomHomePagesTableModel::Entry*
GetEntryByLoadHandle(CancelableRequestProvider::Handle Entry::* member,CancelableRequestProvider::Handle handle,int * index)220     CustomHomePagesTableModel::GetEntryByLoadHandle(
221     CancelableRequestProvider::Handle Entry::* member,
222     CancelableRequestProvider::Handle handle,
223     int* index) {
224   for (size_t i = 0; i < entries_.size(); ++i) {
225     if (entries_[i].*member == handle) {
226       *index = static_cast<int>(i);
227       return &entries_[i];
228     }
229   }
230   return NULL;
231 }
232 
FormattedURL(int row) const233 string16 CustomHomePagesTableModel::FormattedURL(int row) const {
234   std::string languages =
235       profile_->GetPrefs()->GetString(prefs::kAcceptLanguages);
236   string16 url = net::FormatUrl(entries_[row].url, languages);
237   url = base::i18n::GetDisplayStringInLTRDirectionality(url);
238   return url;
239 }
240