Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / file_manager / foreground / js / photo / gallery_item.js
1 // Copyright (c) 2012 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 'use strict';
6
7 /**
8  * Object representing an image item (a photo or a video).
9  *
10  * @param {FileEntry} entry Image entry.
11  * @constructor
12  */
13 Gallery.Item = function(entry) {
14   this.entry_ = entry;
15   this.original_ = true;
16 };
17
18 /**
19  * @return {FileEntry} Image entry.
20  */
21 Gallery.Item.prototype.getEntry = function() { return this.entry_ };
22
23 /**
24  * @return {string} File name.
25  */
26 Gallery.Item.prototype.getFileName = function() {
27   return this.entry_.name;
28 };
29
30 /**
31  * @return {boolean} True if this image has not been created in this session.
32  */
33 Gallery.Item.prototype.isOriginal = function() { return this.original_ };
34
35 // TODO: Localize?
36 /**
37  * @type {string} Suffix for a edited copy file name.
38  */
39 Gallery.Item.COPY_SIGNATURE = ' - Edited';
40
41 /**
42  * Regular expression to match '... - Edited'.
43  * @type {RegExp}
44  */
45 Gallery.Item.REGEXP_COPY_0 =
46     new RegExp('^(.+)' + Gallery.Item.COPY_SIGNATURE + '$');
47
48 /**
49  * Regular expression to match '... - Edited (N)'.
50  * @type {RegExp}
51  */
52 Gallery.Item.REGEXP_COPY_N =
53     new RegExp('^(.+)' + Gallery.Item.COPY_SIGNATURE + ' \\((\\d+)\\)$');
54
55 /**
56  * Creates a name for an edited copy of the file.
57  *
58  * @param {Entry} dirEntry Entry.
59  * @param {function} callback Callback.
60  * @private
61  */
62 Gallery.Item.prototype.createCopyName_ = function(dirEntry, callback) {
63   var name = this.getFileName();
64
65   // If the item represents a file created during the current Gallery session
66   // we reuse it for subsequent saves instead of creating multiple copies.
67   if (!this.original_) {
68     callback(name);
69     return;
70   }
71
72   var ext = '';
73   var index = name.lastIndexOf('.');
74   if (index != -1) {
75     ext = name.substr(index);
76     name = name.substr(0, index);
77   }
78
79   if (!ext.match(/jpe?g/i)) {
80     // Chrome can natively encode only two formats: JPEG and PNG.
81     // All non-JPEG images are saved in PNG, hence forcing the file extension.
82     ext = '.png';
83   }
84
85   function tryNext(tries) {
86     // All the names are used. Let's overwrite the last one.
87     if (tries == 0) {
88       setTimeout(callback, 0, name + ext);
89       return;
90     }
91
92     // If the file name contains the copy signature add/advance the sequential
93     // number.
94     var matchN = Gallery.Item.REGEXP_COPY_N.exec(name);
95     var match0 = Gallery.Item.REGEXP_COPY_0.exec(name);
96     if (matchN && matchN[1] && matchN[2]) {
97       var copyNumber = parseInt(matchN[2], 10) + 1;
98       name = matchN[1] + Gallery.Item.COPY_SIGNATURE + ' (' + copyNumber + ')';
99     } else if (match0 && match0[1]) {
100       name = match0[1] + Gallery.Item.COPY_SIGNATURE + ' (1)';
101     } else {
102       name += Gallery.Item.COPY_SIGNATURE;
103     }
104
105     dirEntry.getFile(name + ext, {create: false, exclusive: false},
106         tryNext.bind(null, tries - 1),
107         callback.bind(null, name + ext));
108   }
109
110   tryNext(10);
111 };
112
113 /**
114  * Writes the new item content to the file.
115  *
116  * @param {Entry} overrideDir Directory to save to. If null, save to the same
117  *   directory as the original.
118  * @param {boolean} overwrite True if overwrite, false if copy.
119  * @param {HTMLCanvasElement} canvas Source canvas.
120  * @param {ImageEncoder.MetadataEncoder} metadataEncoder MetadataEncoder.
121  * @param {function(boolean)=} opt_callback Callback accepting true for success.
122  */
123 Gallery.Item.prototype.saveToFile = function(
124     overrideDir, overwrite, canvas, metadataEncoder, opt_callback) {
125   ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime'));
126
127   var name = this.getFileName();
128
129   var onSuccess = function(entry) {
130     ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 1, 2);
131     ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime'));
132     this.entry_ = entry;
133     if (opt_callback) opt_callback(true);
134   }.bind(this);
135
136   function onError(error) {
137     console.error('Error saving from gallery', name, error);
138     ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('SaveResult'), 0, 2);
139     if (opt_callback) opt_callback(false);
140   }
141
142   function doSave(newFile, fileEntry) {
143     fileEntry.createWriter(function(fileWriter) {
144       function writeContent() {
145         fileWriter.onwriteend = onSuccess.bind(null, fileEntry);
146         fileWriter.write(ImageEncoder.getBlob(canvas, metadataEncoder));
147       }
148       fileWriter.onerror = function(error) {
149         onError(error);
150         // Disable all callbacks on the first error.
151         fileWriter.onerror = null;
152         fileWriter.onwriteend = null;
153       };
154       if (newFile) {
155         writeContent();
156       } else {
157         fileWriter.onwriteend = writeContent;
158         fileWriter.truncate(0);
159       }
160     }, onError);
161   }
162
163   function getFile(dir, newFile) {
164     dir.getFile(name, {create: newFile, exclusive: newFile},
165         doSave.bind(null, newFile), onError);
166   }
167
168   function checkExistence(dir) {
169     dir.getFile(name, {create: false, exclusive: false},
170         getFile.bind(null, dir, false /* existing file */),
171         getFile.bind(null, dir, true /* create new file */));
172   }
173
174   var saveToDir = function(dir) {
175     if (overwrite) {
176       checkExistence(dir);
177     } else {
178       this.createCopyName_(dir, function(copyName) {
179         this.original_ = false;
180         name = copyName;
181         checkExistence(dir);
182       }.bind(this));
183     }
184   }.bind(this);
185
186   if (overrideDir) {
187     saveToDir(overrideDir);
188   } else {
189     this.entry_.getParent(saveToDir, onError);
190   }
191 };
192
193 /**
194  * Renames the file.
195  *
196  * @param {string} displayName New display name (without the extension).
197  * @param {function()} onSuccess Success callback.
198  * @param {function()} onExists Called if the file with the new name exists.
199  */
200 Gallery.Item.prototype.rename = function(displayName, onSuccess, onExists) {
201   var newFileName = this.entry_.name.replace(
202       ImageUtil.getDisplayNameFromName(this.entry_.name), displayName);
203
204   if (newFileName === this.entry_.name)
205     return;
206
207   var onRenamed = function(entry) {
208     this.entry_ = entry;
209     onSuccess();
210   }.bind(this);
211
212   var onError = function() {
213     console.error(
214         'Rename error: "' + this.entry_.name + '" to "' + newFileName + '"');
215   };
216
217   var moveIfDoesNotExist = function(parentDir) {
218     parentDir.getFile(
219         newFileName,
220         {create: false, exclusive: false},
221         onExists,
222         function() {
223           this.entry_.moveTo(parentDir, newFileName, onRenamed, onError);
224         }.bind(this));
225   }.bind(this);
226
227   this.entry_.getParent(moveIfDoesNotExist, onError);
228 };