Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / picasa_data_provider.cc
blob0633362b5299a477a06274333f5930bf56e35d0c
1 // Copyright 2013 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.
5 #include "chrome/browser/media_galleries/fileapi/picasa_data_provider.h"
7 #include <utility>
9 #include "base/basictypes.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/file_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "chrome/browser/media_galleries/fileapi/file_path_watcher_util.h"
15 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
16 #include "chrome/browser/media_galleries/fileapi/safe_picasa_album_table_reader.h"
17 #include "chrome/browser/media_galleries/fileapi/safe_picasa_albums_indexer.h"
18 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
19 #include "webkit/browser/fileapi/file_system_operation_context.h"
20 #include "webkit/browser/fileapi/file_system_url.h"
22 namespace picasa {
24 namespace {
26 void RunAllCallbacks(
27 std::vector<PicasaDataProvider::ReadyCallback>* ready_callbacks,
28 bool success) {
29 for (std::vector<PicasaDataProvider::ReadyCallback>::const_iterator it =
30 ready_callbacks->begin();
31 it != ready_callbacks->end();
32 ++it) {
33 it->Run(success);
35 ready_callbacks->clear();
38 } // namespace
40 PicasaDataProvider::PicasaDataProvider(const base::FilePath& database_path)
41 : database_path_(database_path),
42 state_(STALE_DATA_STATE),
43 weak_factory_(this) {
44 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
46 StartFilePathWatchOnMediaTaskRunner(
47 database_path_.DirName().AppendASCII(kPicasaTempDirName),
48 base::Bind(&PicasaDataProvider::OnTempDirWatchStarted,
49 weak_factory_.GetWeakPtr()),
50 base::Bind(&PicasaDataProvider::OnTempDirChanged,
51 weak_factory_.GetWeakPtr()));
54 PicasaDataProvider::~PicasaDataProvider() {}
56 void PicasaDataProvider::RefreshData(DataType needed_data,
57 const ReadyCallback& ready_callback) {
58 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
59 // TODO(tommycli): Need to watch the database_path_ folder and handle
60 // rereading the data when it changes.
62 if (state_ == INVALID_DATA_STATE) {
63 ready_callback.Run(false /* success */);
64 return;
67 if (needed_data == LIST_OF_ALBUMS_AND_FOLDERS_DATA) {
68 if (state_ == LIST_OF_ALBUMS_AND_FOLDERS_FRESH_STATE ||
69 state_ == ALBUMS_IMAGES_FRESH_STATE) {
70 ready_callback.Run(true /* success */);
71 return;
73 album_list_ready_callbacks_.push_back(ready_callback);
74 } else {
75 if (state_ == ALBUMS_IMAGES_FRESH_STATE) {
76 ready_callback.Run(true /* success */);
77 return;
79 albums_index_ready_callbacks_.push_back(ready_callback);
81 DoRefreshIfNecessary();
84 scoped_ptr<AlbumMap> PicasaDataProvider::GetFolders() {
85 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
86 DCHECK(state_ == LIST_OF_ALBUMS_AND_FOLDERS_FRESH_STATE ||
87 state_ == ALBUMS_IMAGES_FRESH_STATE);
88 return make_scoped_ptr(new AlbumMap(folder_map_));
91 scoped_ptr<AlbumMap> PicasaDataProvider::GetAlbums() {
92 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
93 DCHECK(state_ == LIST_OF_ALBUMS_AND_FOLDERS_FRESH_STATE ||
94 state_ == ALBUMS_IMAGES_FRESH_STATE);
95 return make_scoped_ptr(new AlbumMap(album_map_));
98 scoped_ptr<AlbumImages> PicasaDataProvider::FindAlbumImages(
99 const std::string& key,
100 base::PlatformFileError* error) {
101 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
102 DCHECK(state_ == ALBUMS_IMAGES_FRESH_STATE);
103 DCHECK(error);
105 AlbumImagesMap::const_iterator it = albums_images_.find(key);
107 if (it == albums_images_.end()) {
108 *error = base::PLATFORM_FILE_ERROR_NOT_FOUND;
109 return scoped_ptr<AlbumImages>();
112 *error = base::PLATFORM_FILE_OK;
113 return make_scoped_ptr(new AlbumImages(it->second));
116 void PicasaDataProvider::InvalidateData() {
117 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
119 // Set data state to stale and ignore responses from any in-flight processes.
120 // TODO(tommycli): Implement and call Cancel function for these
121 // UtilityProcessHostClients to actually kill the in-flight processes.
122 state_ = STALE_DATA_STATE;
123 album_table_reader_ = NULL;
124 albums_indexer_ = NULL;
126 DoRefreshIfNecessary();
129 void PicasaDataProvider::OnTempDirWatchStarted(
130 scoped_ptr<base::FilePathWatcher> temp_dir_watcher) {
131 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
132 temp_dir_watcher_.reset(temp_dir_watcher.release());
135 void PicasaDataProvider::OnTempDirChanged(const base::FilePath& temp_dir_path,
136 bool error) {
137 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
138 if (base::IsDirectoryEmpty(temp_dir_path))
139 InvalidateData();
142 void PicasaDataProvider::DoRefreshIfNecessary() {
143 DCHECK(state_ != INVALID_DATA_STATE);
144 DCHECK(state_ != ALBUMS_IMAGES_FRESH_STATE);
145 DCHECK(!(album_table_reader_ && albums_indexer_));
147 if (album_list_ready_callbacks_.empty() &&
148 albums_index_ready_callbacks_.empty()) {
149 return;
152 if (state_ == STALE_DATA_STATE) {
153 if (album_table_reader_)
154 return;
155 album_table_reader_ =
156 new SafePicasaAlbumTableReader(AlbumTableFiles(database_path_));
157 album_table_reader_->Start(
158 base::Bind(&PicasaDataProvider::OnAlbumTableReaderDone,
159 weak_factory_.GetWeakPtr(),
160 album_table_reader_));
161 } else {
162 DCHECK(state_ == LIST_OF_ALBUMS_AND_FOLDERS_FRESH_STATE);
163 if (albums_indexer_)
164 return;
165 albums_indexer_ = new SafePicasaAlbumsIndexer(album_map_, folder_map_);
166 albums_indexer_->Start(base::Bind(&PicasaDataProvider::OnAlbumsIndexerDone,
167 weak_factory_.GetWeakPtr(),
168 albums_indexer_));
172 void PicasaDataProvider::OnAlbumTableReaderDone(
173 scoped_refptr<SafePicasaAlbumTableReader> reader,
174 bool parse_success,
175 const std::vector<AlbumInfo>& albums,
176 const std::vector<AlbumInfo>& folders) {
177 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
178 // If the reader has already been deemed stale, ignore the result.
179 if (reader != album_table_reader_)
180 return;
181 album_table_reader_ = NULL;
183 DCHECK(state_ == STALE_DATA_STATE);
185 if (!parse_success) {
186 // If we didn't get the list successfully, fail all those waiting for
187 // the albums indexer also.
188 state_ = INVALID_DATA_STATE;
189 RunAllCallbacks(&album_list_ready_callbacks_, false /* success */);
190 RunAllCallbacks(&albums_index_ready_callbacks_, false /* success */);
191 return;
194 album_map_.clear();
195 folder_map_.clear();
196 UniquifyNames(albums, &album_map_);
197 UniquifyNames(folders, &folder_map_);
199 state_ = LIST_OF_ALBUMS_AND_FOLDERS_FRESH_STATE;
200 RunAllCallbacks(&album_list_ready_callbacks_, parse_success);
202 // Chain from this process onto refreshing the albums images if necessary.
203 DoRefreshIfNecessary();
206 void PicasaDataProvider::OnAlbumsIndexerDone(
207 scoped_refptr<SafePicasaAlbumsIndexer> indexer,
208 bool success,
209 const picasa::AlbumImagesMap& albums_images) {
210 DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
211 // If the indexer has already been deemed stale, ignore the result.
212 if (indexer != albums_indexer_)
213 return;
214 albums_indexer_ = NULL;
216 DCHECK(state_ == LIST_OF_ALBUMS_AND_FOLDERS_FRESH_STATE);
218 if (success) {
219 state_ = ALBUMS_IMAGES_FRESH_STATE;
221 albums_images_ = albums_images;
224 RunAllCallbacks(&albums_index_ready_callbacks_, success);
227 // static
228 std::string PicasaDataProvider::DateToPathString(const base::Time& time) {
229 base::Time::Exploded exploded_time;
230 time.LocalExplode(&exploded_time);
232 // TODO(tommycli): Investigate better localization and persisting which locale
233 // we use to generate these unique names.
234 return base::StringPrintf("%04d-%02d-%02d", exploded_time.year,
235 exploded_time.month, exploded_time.day_of_month);
238 // static
239 void PicasaDataProvider::UniquifyNames(const std::vector<AlbumInfo>& info_list,
240 AlbumMap* result_map) {
241 // TODO(tommycli): We should persist the uniquified names.
242 std::vector<std::string> desired_names;
244 std::map<std::string, int> total_counts;
245 std::map<std::string, int> current_counts;
247 for (std::vector<AlbumInfo>::const_iterator it = info_list.begin();
248 it != info_list.end(); ++it) {
249 std::string desired_name =
250 it->name + " " + DateToPathString(it->timestamp);
251 desired_names.push_back(desired_name);
252 ++total_counts[desired_name];
255 for (unsigned int i = 0; i < info_list.size(); i++) {
256 std::string name = desired_names[i];
258 if (total_counts[name] != 1) {
259 name = base::StringPrintf("%s (%d)", name.c_str(),
260 ++current_counts[name]);
263 result_map->insert(std::pair<std::string, AlbumInfo>(name, info_list[i]));
267 } // namespace picasa