Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Ci = Components.interfaces;
6 const Cc = Components.classes;
7 const Cr = Components.results;
8 const Cu = Components.utils;
10 Cu.import("resource://services-sync/main.js");
11 Cu.import("resource://gre/modules/DownloadUtils.jsm");
13 let gSyncQuota = {
15 init: function init() {
16 this.bundle = document.getElementById("quotaStrings");
17 let caption = document.getElementById("treeCaption");
18 caption.firstChild.nodeValue = this.bundle.getString("quota.treeCaption.label");
20 gUsageTreeView.init();
21 this.tree = document.getElementById("usageTree");
22 this.tree.view = gUsageTreeView;
24 this.loadData();
25 },
27 loadData: function loadData() {
28 this._usage_req = Weave.Service.getStorageInfo(Weave.INFO_COLLECTION_USAGE,
29 function (error, usage) {
30 delete gSyncQuota._usage_req;
31 // displayUsageData handles null values, so no need to check 'error'.
32 gUsageTreeView.displayUsageData(usage);
33 });
35 let usageLabel = document.getElementById("usageLabel");
36 let bundle = this.bundle;
38 this._quota_req = Weave.Service.getStorageInfo(Weave.INFO_QUOTA,
39 function (error, quota) {
40 delete gSyncQuota._quota_req;
42 if (error) {
43 usageLabel.value = bundle.getString("quota.usageError.label");
44 return;
45 }
46 let used = gSyncQuota.convertKB(quota[0]);
47 if (!quota[1]) {
48 // No quota on the server.
49 usageLabel.value = bundle.getFormattedString(
50 "quota.usageNoQuota.label", used);
51 return;
52 }
53 let percent = Math.round(100 * quota[0] / quota[1]);
54 let total = gSyncQuota.convertKB(quota[1]);
55 usageLabel.value = bundle.getFormattedString(
56 "quota.usagePercentage.label", [percent].concat(used).concat(total));
57 });
58 },
60 onCancel: function onCancel() {
61 if (this._usage_req) {
62 this._usage_req.abort();
63 }
64 if (this._quota_req) {
65 this._quota_req.abort();
66 }
67 return true;
68 },
70 onAccept: function onAccept() {
71 let engines = gUsageTreeView.getEnginesToDisable();
72 for each (let engine in engines) {
73 Weave.Service.engineManager.get(engine).enabled = false;
74 }
75 if (engines.length) {
76 // The 'Weave' object will disappear once the window closes.
77 let Service = Weave.Service;
78 Weave.Utils.nextTick(function() { Service.sync(); });
79 }
80 return this.onCancel();
81 },
83 convertKB: function convertKB(value) {
84 return DownloadUtils.convertByteUnits(value * 1024);
85 }
87 };
89 let gUsageTreeView = {
91 _ignored: {keys: true,
92 meta: true,
93 clients: true},
95 /*
96 * Internal data structures underlaying the tree.
97 */
98 _collections: [],
99 _byname: {},
101 init: function init() {
102 let retrievingLabel = gSyncQuota.bundle.getString("quota.retrieving.label");
103 for each (let engine in Weave.Service.engineManager.getEnabled()) {
104 if (this._ignored[engine.name])
105 continue;
107 // Some engines use the same pref, which means they can only be turned on
108 // and off together. We need to combine them here as well.
109 let existing = this._byname[engine.prefName];
110 if (existing) {
111 existing.engines.push(engine.name);
112 continue;
113 }
115 let obj = {name: engine.prefName,
116 title: this._collectionTitle(engine),
117 engines: [engine.name],
118 enabled: true,
119 sizeLabel: retrievingLabel};
120 this._collections.push(obj);
121 this._byname[engine.prefName] = obj;
122 }
123 },
125 _collectionTitle: function _collectionTitle(engine) {
126 try {
127 return gSyncQuota.bundle.getString(
128 "collection." + engine.prefName + ".label");
129 } catch (ex) {
130 return engine.Name;
131 }
132 },
134 /*
135 * Process the quota information as returned by info/collection_usage.
136 */
137 displayUsageData: function displayUsageData(data) {
138 for each (let coll in this._collections) {
139 coll.size = 0;
140 // If we couldn't retrieve any data, just blank out the label.
141 if (!data) {
142 coll.sizeLabel = "";
143 continue;
144 }
146 for each (let engineName in coll.engines)
147 coll.size += data[engineName] || 0;
148 let sizeLabel = "";
149 sizeLabel = gSyncQuota.bundle.getFormattedString(
150 "quota.sizeValueUnit.label", gSyncQuota.convertKB(coll.size));
151 coll.sizeLabel = sizeLabel;
152 }
153 let sizeColumn = this.treeBox.columns.getNamedColumn("size");
154 this.treeBox.invalidateColumn(sizeColumn);
155 },
157 /*
158 * Handle click events on the tree.
159 */
160 onTreeClick: function onTreeClick(event) {
161 if (event.button == 2)
162 return;
164 let row = {}, col = {};
165 this.treeBox.getCellAt(event.clientX, event.clientY, row, col, {});
166 if (col.value && col.value.id == "enabled")
167 this.toggle(row.value);
168 },
170 /*
171 * Toggle enabled state of an engine.
172 */
173 toggle: function toggle(row) {
174 // Update the tree
175 let collection = this._collections[row];
176 collection.enabled = !collection.enabled;
177 this.treeBox.invalidateRow(row);
179 // Display which ones will be removed
180 let freeup = 0;
181 let toremove = [];
182 for each (collection in this._collections) {
183 if (collection.enabled)
184 continue;
185 toremove.push(collection.name);
186 freeup += collection.size;
187 }
189 let caption = document.getElementById("treeCaption");
190 if (!toremove.length) {
191 caption.className = "";
192 caption.firstChild.nodeValue = gSyncQuota.bundle.getString(
193 "quota.treeCaption.label");
194 return;
195 }
197 toremove = [this._byname[coll].title for each (coll in toremove)];
198 toremove = toremove.join(gSyncQuota.bundle.getString("quota.list.separator"));
199 caption.firstChild.nodeValue = gSyncQuota.bundle.getFormattedString(
200 "quota.removal.label", [toremove]);
201 if (freeup)
202 caption.firstChild.nodeValue += gSyncQuota.bundle.getFormattedString(
203 "quota.freeup.label", gSyncQuota.convertKB(freeup));
204 caption.className = "captionWarning";
205 },
207 /*
208 * Return a list of engines (or rather their pref names) that should be
209 * disabled.
210 */
211 getEnginesToDisable: function getEnginesToDisable() {
212 return [coll.name for each (coll in this._collections) if (!coll.enabled)];
213 },
215 // nsITreeView
217 get rowCount() {
218 return this._collections.length;
219 },
221 getRowProperties: function(index) { return ""; },
222 getCellProperties: function(row, col) { return ""; },
223 getColumnProperties: function(col) { return ""; },
224 isContainer: function(index) { return false; },
225 isContainerOpen: function(index) { return false; },
226 isContainerEmpty: function(index) { return false; },
227 isSeparator: function(index) { return false; },
228 isSorted: function() { return false; },
229 canDrop: function(index, orientation, dataTransfer) { return false; },
230 drop: function(row, orientation, dataTransfer) {},
231 getParentIndex: function(rowIndex) {},
232 hasNextSibling: function(rowIndex, afterIndex) { return false; },
233 getLevel: function(index) { return 0; },
234 getImageSrc: function(row, col) {},
236 getCellValue: function(row, col) {
237 return this._collections[row].enabled;
238 },
240 getCellText: function getCellText(row, col) {
241 let collection = this._collections[row];
242 switch (col.id) {
243 case "collection":
244 return collection.title;
245 case "size":
246 return collection.sizeLabel;
247 default:
248 return "";
249 }
250 },
252 setTree: function setTree(tree) {
253 this.treeBox = tree;
254 },
256 toggleOpenState: function(index) {},
257 cycleHeader: function(col) {},
258 selectionChanged: function() {},
259 cycleCell: function(row, col) {},
260 isEditable: function(row, col) { return false; },
261 isSelectable: function (row, col) { return false; },
262 setCellValue: function(row, col, value) {},
263 setCellText: function(row, col, value) {},
264 performAction: function(action) {},
265 performActionOnRow: function(action, row) {},
266 performActionOnCell: function(action, row, col) {}
268 };