deviceProgress.js
Go to the documentation of this file.
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4  *=BEGIN SONGBIRD GPL
5  *
6  * This file is part of the Songbird web player.
7  *
8  * Copyright(c) 2005-2011 POTI, Inc.
9  * http://www.songbirdnest.com
10  *
11  * This file may be licensed under the terms of of the
12  * GNU General Public License Version 2 (the ``GPL'').
13  *
14  * Software distributed under the License is distributed
15  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
16  * express or implied. See the GPL for the specific language
17  * governing rights and limitations.
18  *
19  * You should have received a copy of the GPL along with this
20  * program. If not, go to http://www.gnu.org/licenses/gpl.html
21  * or write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  *=END SONGBIRD GPL
25  */
26 
32 //------------------------------------------------------------------------------
33 //------------------------------------------------------------------------------
34 //
35 // Device progress widget.
36 //
37 //------------------------------------------------------------------------------
38 //------------------------------------------------------------------------------
39 
40 //------------------------------------------------------------------------------
41 //
42 // Device progress defs.
43 //
44 //------------------------------------------------------------------------------
45 
46 // Component manager defs.
47 if (typeof(Cc) == "undefined")
48  var Cc = Components.classes;
49 if (typeof(Ci) == "undefined")
50  var Ci = Components.interfaces;
51 if (typeof(Cr) == "undefined")
52  var Cr = Components.results;
53 if (typeof(Cu) == "undefined")
54  var Cu = Components.utils;
55 
56 Cu.import("resource://app/jsmodules/sbProperties.jsm");
57 Cu.import("resource://app/jsmodules/WindowUtils.jsm");
58 Cu.import("resource://app/jsmodules/sbTimeFormatter.jsm");
59 
60 //------------------------------------------------------------------------------
61 //
62 // Device progress configuration.
63 //
64 //------------------------------------------------------------------------------
65 
66 /*
67  * operationInfoList List of device operation information records.
68  * state Operation state value.
69  * localeSuffix Locale string key suffix for operation.
70  * progressMeterUndetermined If true, display undetermined progress meter for
71  * operation.
72  * progressMeterDetermined If true, display determined progress meter for
73  * operation.
74  * canBeCompleted If true, operation can be completed and should
75  * be set for last completed operation.
76  * showIdleMessage If true, and this was the last completed
77  * operation, then reflect that in the idle msg.
78  * showProgress If true, progress should be displayed for
79  * operation.
80  * updateIdle If true, update UI for an idle operation.
81  * updateBusy If true, update UI for a busy operation.
82  * operationCanceled If true, remember that the current operation
83  * was canceled
84  */
85 
86 var DPWCfg = {
87  operationInfoList: [
88  /* Idle. */
89  {
90  state: Ci.sbIDevice.STATE_IDLE,
91  localeSuffix: "idle",
92  updateIdle: true
93  },
94 
95  /* Sync. */
96  {
97  state: Ci.sbIDevice.STATE_SYNCING,
98  localeSuffix: "syncing",
99  progressMeterDetermined: true,
100  canBeCompleted: true,
101  showIdleMessage: true,
102  showProgress: true,
103  updateBusy: true,
104  preparingOnIdle: true,
105  operationCanceled: false
106  },
107 
108  /* Sync preparation. */
109  {
110  state: Ci.sbIDevice.STATE_SYNC_PREPARING,
111  localeSuffix: "sync_preparing",
112  progressMeterUndetermined: true,
113  canBeCompleted: true,
114  showIdleMessage: true,
115  showProgress: true,
116  updateBusy: true,
117  operationCanceled: false
118  },
119 
120  /* Sync preparation. */
121  {
122  state: Ci.sbIDevice.STATE_IMAGESYNC_PREPARING,
123  localeSuffix: "imagesync_preparing",
124  progressMeterUndetermined: true,
125  canBeCompleted: true,
126  showIdleMessage: true,
127  showProgress: true,
128  updateBusy: true,
129  operationCanceled: false
130  },
131 
132  /* Copy. */
133  {
134  state: Ci.sbIDevice.STATE_COPYING,
135  localeSuffix: "copying",
136  progressMeterDetermined: true,
137  canBeCompleted: true,
138  showIdleMessage: true,
139  showProgress: true,
140  updateBusy: true,
141  operationCanceled: false
142  },
143 
144  /* Delete. */
145  {
146  state: Ci.sbIDevice.STATE_DELETING,
147  localeSuffix: "deleting",
148  progressMeterDetermined: true,
149  canBeCompleted: true,
150  showIdleMessage: true,
151  showProgress: true,
152  updateBusy: true,
153  operationCanceled: false
154  },
155 
156  /* Update. */
157  {
158  state: Ci.sbIDevice.STATE_UPDATING,
159  localeSuffix: "updating",
160  progressMeterDetermined: true,
161  canBeCompleted: true,
162  showIdleMessage: true,
163  showProgress: true,
164  updateBusy: true,
165  operationCanceled: false
166  },
167 
168  /* Mount. */
169  {
170  state: Ci.sbIDevice.STATE_MOUNTING,
171  localeSuffix: "mounting",
172  progressMeterUndetermined: true,
173  canBeCompleted: true,
174  showIdleMessage: false, // no message after mount, just hide progress
175  showProgress: true,
176  updateBusy: true,
177  operationCanceled: false
178  },
179 
180  /* Download */
181  {
182  state: Ci.sbIDevice.STATE_DOWNLOADING,
183  localeSuffix: "downloading",
184  progressMeterDetermined: true,
185  canBeCompleted: true,
186  showIdleMessage: true,
187  showProgress: true,
188  updateBusy: true,
189  operationCanceled: false
190  },
191 
192  /* Cancel. */
193  {
194  state: Ci.sbIDevice.STATE_CANCEL,
195  localeSuffix: "cancelling",
196  progressMeterUndetermined: true,
197  canBeCompleted: true,
198  showIdleMessage: true,
199  showProgress: true,
200  updateBusy: true,
201  operationCanceled: true
202  },
203 
204  /* Transcode */
205  {
206  state: Ci.sbIDevice.STATE_TRANSCODE,
207  localeSuffix: "transcoding",
208  progressMeterDetermined: true,
209  canBeCompleted: true,
210  showIdleMessage: true,
211  showProgress: true,
212  updateBusy: true,
213  operationCanceled: false
214  },
215 
216  /* Format. */
217  {
218  state: Ci.sbIDevice.STATE_FORMATTING,
219  localeSuffix: "formatting",
220  progressMeterUndetermined: true,
221  canBeCompleted: true,
222  showIdleMessage: true,
223  showProgress: true,
224  updateBusy: true,
225  operationCanceled: false
226  }
227  ]
228 };
229 
230 
231 //------------------------------------------------------------------------------
232 //
233 // Device progress services.
234 //
235 //------------------------------------------------------------------------------
236 
237 var DPW = {
238  //
239  // Device progress object fields.
240  //
241  // _cfg Configuration.
242  // _widget Device info widget.
243  // _device Device bound to device control widget.
244  // _deviceID Device ID.
245  // _deviceLibrary Device library we are working with.
246  // _deviceSyncSettings Device sync settings we are working with.
247  // _deviceErrorMonitor Error monitor for the device
248  // _curItemIndex Current index in the batch of items to process
249  // _totalItems Total items in the batch
250  // _operationInfoTable Table mapping operation state values to
251  // operation information records.
252  // _lastEventOperation Operation of last state changed event.
253  // _lastCompletedEventOperation
254  // Last completed operation of last state changed
255  // event.
256  // _lastIsTranscoding True if the locale suffix of previous operation
257  // is transcoding.
258  // _operationCanceled If true, last operation was canceled
259  // _showProgress If true, progress status should be displayed.
260  //
261  // _progressInfoBox Device progress info.
262  // _syncButton Sync button element.
263  // _idleBox Idle message & spacer.
264  // _cancelButtonBox Cancel button box element.
265  // _finishButton Finish button element.
266  // _progressMeter Progress meter element.
267  // _progressTextLabel Progress text label element.
268  // _idleLabel Idle text label element.
269  // _idleBox Idle box holding idle text.
270  //
271  // _lastProgress Saved last item progress number.
272  // _ratio The ratio for transcoding : transferring.
273  // _firstCopying True for the first copying after transcoding
274  //
275  // _transcodingStart Time stamp when transcoding starts.
276  // _transcodingEnd Time stamp when transcoding ends.
277  // _copyingStart Time stamp when copying starts.
278  // _copyingEnd Time stamp when copying ends.
279  //
280 
281  _cfg: DPWCfg,
282  _widget: null,
283  _device: null,
284  _deviceErrorMonitor : null,
285  _deviceID: null,
286  _deviceLibrary: null,
287  _curItemIndex: null,
288  _totalItems: null,
289  _operationInfoTable: null,
290  _lastIsTranscoding: false,
291  _lastEventOperation: Ci.sbIDevice.STATE_IDLE,
292  _lastCompletedEventOperation: Ci.sbIDevice.STATE_IDLE,
293  _operationCanceled: false,
294  _showProgress: false,
295 
296  _progressInfoBox: null,
297  _syncButton: null,
298  _cancelButtonBox: null,
299  _finishButton: null,
300  _progressMeter: null,
301  _progressTextLabel: null,
302  _idleLabel: null,
303  _idleErrorsLabel: null,
304  _idleBox: null,
305 
306  _lastProgress: 0,
307  _ratio: 1,
308  _firstCopying: false,
309 
310  _transcodingStart: 0,
311  _transcodingEnd: 0,
312  _copyingStart: 0,
313  _copyingEnd: 0,
314 
322  initialize: function DPW__initialize(aWidget) {
323  // Get the device widget.
324  this._widget = aWidget;
325 
326  this._deviceErrorMonitor =
327  Cc["@songbirdnest.com/device/error-monitor-service;1"]
328  .getService(Ci.sbIDeviceErrorMonitor);
329 
330  // Initialize the operation info table.
331  this._operationInfoTable = {};
332  for (var i = 0; i < this._cfg.operationInfoList.length; i++) {
333  var operationInfo = this._cfg.operationInfoList[i];
334  this._operationInfoTable[operationInfo.state] = operationInfo;
335  }
336 
337  // Get some widget elements.
338  this._progressInfoBox = this._getElement("progress_information_box");
339  this._syncButton = this._getElement("sync_operation_button");
340  this._cancelButtonBox = this._getElement("cancel_operation_box");
341  this._finishButton = this._getElement("finish_progress_button");
342  this._progressMeter = this._getElement("progress_meter");
343  this._progressTextLabel = this._getElement("progress_text_label");
344  this._subProgressTextLabel = this._getElement("sub_progress_text_label")
345  this._idleBox = this._getElement("progress_idle_box");
346 
347  this._finishButton.addEventListener("click", this._onButtonEvent, false);
348  this._finishButton.addEventListener("keypress", this._onButtonEvent, false);
349 
350  // Initialize object fields.
351  this._deviceID = this._widget.deviceID;
352  this._device = this._widget.device;
353  this._deviceLibrary = this._widget.devLib;
354 
355  /* If we have a deviceLibrary initialize the things we can.
356  * If not disable the syncButton. */
357  if (this._deviceLibrary) {
358  this._deviceLibrary.addDeviceLibraryListener(this);
359  this._deviceSyncSettings = this._deviceLibrary.syncSettings;
360  }
361  else {
362  this._syncButton.setAttribute("disabled", "true");
363  }
364 
365  // Initialize the device services.
366  this._deviceInitialize();
367 
368  // Get the device operation total items and current item index data remotes.
369  var createDataRemote = new Components.Constructor(
370  "@songbirdnest.com/Songbird/DataRemote;1",
371  Ci.sbIDataRemote,
372  "init");
373  this._totalItems = createDataRemote(
374  this._deviceID + ".status.totalcount", null);
375  this._curItemIndex = createDataRemote(
376  this._deviceID + ".status.workcount", null);
377  this._itemProgress = createDataRemote(
378  this._deviceID + ".status.progress", null);
379  this._itemType = createDataRemote(
380  this._deviceID + ".status.type", null);
381 
382  // Update the last completed operation
383  this._lastCompletedEventOperation = this._device.previousState;
384 
385  // Read the ratio value from preference.
386  var prefService = Cc['@mozilla.org/preferences-service;1']
387  .getService(Ci.nsIPrefBranch);
388  if (!this._device.isDirectTranscoding) {
389  try {
390  let key = "device.transcoding.transfer.ratio";
391  this._ratio = prefService.getIntPref(key);
392  } catch (err) {}
393  }
394 
395  // Simulate a device state changed event to initialize the operation state
396  // and update the UI.
397  this._handleStateChanged({ data: this._device.state });
398  this._update();
399  },
400 
401 
406  finalize: function DPW_finalize() {
407  // Finalize the device services.
408  this._deviceFinalize();
409 
410  // Remove our settings listener
411  if (this._deviceLibrary)
412  this._deviceLibrary.removeDeviceLibraryListener(this);
413 
414 
415  // Clear object fields.
416  this._widget = null;
417  this._device = null;
418  this._deviceErrorMonitor = null;
419  this._deviceID = null;
420  this._deviceLibrary = null;
421  this._operationInfoTable = null;
422  this._progressInfoBox = null;
423  this._idleBox = null;
424  this._syncButton = null;
425  this._cancelButtonBox = null;
426  this._finishButton = null;
427  this._progressMeter = null;
428  this._progressTextLabel = null;
429  this._idleLabel = null;
430  this._idleErrorLabel = null;
431  },
432 
433 
434  //----------------------------------------------------------------------------
435  //
436  // Device progress UI update services.
437  //
438  //----------------------------------------------------------------------------
439 
444  _update: function DPW__update() {
445  // Get the current device state.
446  var deviceState = this._device.state;
447 
448  // Dispatch progress update processing based upon the current device state.
449  var deviceStateOperationInfo = this._getOperationInfo(deviceState);
450  if (deviceStateOperationInfo.updateBusy)
451  this._updateProgressBusy();
452  else if (deviceStateOperationInfo.updateIdle)
453  this._updateProgressIdle();
454 
455  // Show cancel button while busy and finish button while idle.
456  var cancelButtonHidden;
457  var finishButtonHidden;
458  if (deviceState == Ci.sbIDevice.STATE_CANCEL) {
459  // There's no way to escape close the cancel state
460  cancelButtonHidden = true;
461  finishButtonHidden = true;
462  }
463  else if (deviceState == Ci.sbIDevice.STATE_IDLE) {
464  cancelButtonHidden = true;
465  finishButtonHidden = false;
466  } else {
467  cancelButtonHidden = false;
468  finishButtonHidden = true;
469  }
470 
471  // Hide or show progress.
472  var hideProgress = !this._showProgress;
473  this._progressInfoBox.hidden = hideProgress;
474  this._idleBox.hidden = !hideProgress;
475  if (hideProgress) {
476  cancelButtonHidden = true;
477  finishButtonHidden = true;
478  }
479 
480  // Set cancel and hide button hidden property. The device cancel command
481  // widget automatically hides/shows itself depending upon the device state.
482  // Thus, the cancel button is hidden by hiding an enclosing box so as not to
483  // interfere with the internal cancel hiding logic.
484  this._cancelButtonBox.hidden = cancelButtonHidden;
485  this._finishButton.hidden = finishButtonHidden;
486 
487  // Only show sync button if not showing progress.
488  this._syncButton.hidden = this._showProgress;
489 
490  // Disable sync button if the device doesn't contain any storage
491  // This must be checked first because if the library is null
492  // this._deviceSyncSettings will be null as well.
493  if (!this._device.defaultLibrary) {
494  this._syncButton.setAttribute("disabled", "true");
495  return;
496  }
497 
498  /* Check if any mediaType is set to be imported or to sync to the device.
499  * If at least one is, we do not disable the sync button. */
500  var disableSyncButton = true;
501  for (var currMediaType = Ci.sbIDeviceLibrary.MEDIATYPE_AUDIO;
502  currMediaType < Ci.sbIDeviceLibrary.MEDIATYPE_COUNT;
503  currMediaType++) {
504  var currMediaSettings = this._deviceSyncSettings
505  .getMediaSettings(currMediaType);
506 
507  /* Check if this mediatype is set to be imported or have content
508  * synced to it from the main library */
509  if (currMediaSettings.import ||
510  (currMediaSettings.mgmtType !=
511  Ci.sbIDeviceLibraryMediaSyncSettings.SYNC_MGMT_NONE)) {
512  disableSyncButton = false;
513  break;
514  }
515  }
516 
517  if (disableSyncButton) {
518  this._syncButton.setAttribute("disabled", "true");
519  }
520  else {
521  this._syncButton.removeAttribute("disabled");
522  }
523  },
524 
525 
530  _updateProgressIdle: function DPW__updateProgressIdle() {
531  this._lastProgress = 0;
532  this._lastIsTranscoding = false;
533 
534  // Write back the ratio so this can be used in the future.
535  var prefService = Cc['@mozilla.org/preferences-service;1']
536  .getService(Ci.nsIPrefBranch);
537  if (!this._device.isDirectTranscoding) {
538  let key = "device.transcoding.transfer.ratio";
539  prefService.setIntPref(key, this._ratio);
540  }
541 
542  var oInfo = this._getOperationInfo(this._lastCompletedEventOperation);
543 
544  /* If the lastCompletedEvent is one for which a message should be displayed,
545  * display that message. If no message is to be displayed (and it's not the
546  * idle state) set the state to idle, finish, and clear the progress bar.
547  * We explicitly check for idle so that, in the event this code gets called
548  * more then once, we won't finish() twice.*/
549  if (oInfo.showIdleMessage) {
550  // Per bug 20294, don't bother showing different idle messages for each
551  // operation type.
552  var key = "device.status.progress_completed";
553 
554  // Check for errors, notify of errors, cancel takes precedence
555  var hasErrors = this._checkForDeviceErrors("");
556  if (this._operationCanceled) {
557  key = "device.status.progress_aborted";
558  }
559  else if (hasErrors) {
560  key += "_errors";
561  }
562  else {
563  key += "_ok";
564  }
565  this._progressTextLabel.value = SBString(key, "");
566  }
567  else if (this._lastCompletedEventOperation != Ci.sbIDevice.STATE_IDLE) {
568  // notably, this is what happens when the lastCompletedEvent was mounting
569  this._lastCompletedEventOperation = Ci.sbIDevice.STATE_IDLE;
570  this._finish();
571  }
572 
573  this._progressMeter.hidden = true;
574  this._subProgressTextLabel.hidden = true;
575 
576  this._startTimestamp = null;
577  this._lastTimeLeft = Infinity;
578  },
579 
580 
585  _getItemType: function DPW__getItemType() {
586  if (this._itemType.intValue == 1)
587  return "audio";
588  else if (this._itemType.intValue == 2)
589  return "video";
590  else if (this._itemType.intValue == 4)
591  return "image";
592  else
593  return null;
594  },
595 
596 
601  _updateProgressBusy: function DPW__updateProgressBusy() {
602  var localeKey, subLocaleKey;
603 
604  // Get the device status.
605  var deviceStatus = this._device.currentStatus;
606  var operation = deviceStatus.currentState;
607  var substate = deviceStatus.currentSubState;
608  var curItemIndex = this._curItemIndex.intValue;
609  var totalItems = this._totalItems.intValue;
610  var duration = deviceStatus.elapsedTime;
611 
612  // Get the operation info.
613  var operationInfo = this._getOperationInfo(operation);
614  var operationLocaleSuffix = operationInfo.localeSuffix;
615 
616  // Show progress meter if it was previously hidden
617  this._progressMeter.hidden = false;
618  this._subProgressTextLabel.hidden = false;
619 
620  if (!this._startTimestamp) {
621  this._startTimestamp = new Date();
622  this._lastTimeLeft = Infinity;
623  }
624 
625  if (deviceStatus.isNewBatch)
626  {
627 // dump("==> New Batch!\n");
628  deviceStatus.isNewBatch = false;
629  }
630 
631  var eta, etaString;
632 
633  // Update the operation progress meter.
634  if (operationInfo.progressMeterDetermined) {
635  // Compute the progress from 0-1.
636  var progress = 0;
637  if ((totalItems > 0) &&
638  (curItemIndex > 0) &&
639  (curItemIndex <= totalItems))
640  {
641  progress = (curItemIndex - 1) / totalItems;
642  }
643 
644  // We are often incorrectly told that 100% of the zeroth file
645  // has been completed. This will be fixed by bug 20363.
646  if (curItemIndex != 0) {
647  let increase = (this._itemProgress.intValue / 100) / totalItems;
648 
649  // Some device has two phases for transcoding (MTP): transcode to
650  // temporary file, then copy to the device.
651  if (!this._device.isDirectTranscoding) {
652  // Calculate the transcoding and copying progress based on ratio.
653  //
654  // Make sure the progress bar moves forwards in a continuous way
655  // for transcoding/copying.
656  if (operation == Ci.sbIDevice.STATE_TRANSCODE ||
657  substate == Ci.sbIDevice.STATE_TRANSCODE) {
658  if (this._itemProgress.intValue == 0) {
659  this._lastIsTranscoding = true;
660  this._firstCopying = true;
661 
662  // Calculate the ratio based on the processing time of
663  // previous items.
664  if (curItemIndex > 1) {
665  this._copyingEnd = duration;
666  let transcodingDuration =
667  this._transcodingEnd - this._transcodingStart;
668  let copyingDuration =
669  this._copyingEnd - this._copyingStart;
670 
671  // Replace the saved ratio with the first calculated one.
672  if (curItemIndex == 2) {
673  this._ratio = transcodingDuration / copyingDuration + 0.5;
674  if (!this._ratio) this._ratio = 1;
675  }
676  // Calculate the avarage ratio.
677  else {
678  this._ratio = this._ratio * (curItemIndex - 2) + 0.5 +
679  transcodingDuration / copyingDuration;
680  this._ratio /= (curItemIndex - 1);
681  if (!this._ratio) this._ratio = 1;
682  }
683  }
684  this._transcodingStart = duration;
685  }
686 
687  let divisor = totalItems * (1 / this._ratio + 1);
688  increase = (this._itemProgress.intValue / 100) / divisor;
689  }
690  else if (this._lastIsTranscoding &&
691  (operation == Ci.sbIDevice.STATE_COPYING ||
692  substate == Ci.sbIDevice.STATE_COPYING)) {
693  if (this._itemProgress.intValue == 0) {
694  this._copyingStart = duration;
695  this._transcodingEnd = duration;
696  }
697 
698  let divisor = totalItems * (this._ratio + 1);
699 
700  // XXX Hack: the item progress of first copying after transcoding
701  // is still the one from transcoding. Due to asynchronous
702  // update?
703  // Ignore the first copying so that the progress bar works
704  if (this._firstCopying) {
705  this._firstCopying = false;
706  increase = this._ratio / divisor;
707  }
708  else {
709  increase =
710  (this._itemProgress.intValue / 100 + this._ratio) / divisor;
711  }
712  }
713  }
714 
715  progress += increase;
716  }
717 
718  // Show the time remaining detail starting from 5%. The value could
719  // change dramatically before 5%.
720  if (progress > 0.05)
721  {
722  if (progress > this._lastProgress)
723  this._lastProgress = progress;
724  else
725  progress = this._lastProgress;
726 
727  eta = (duration / progress) - duration;
728  etaString = TimeFormatter.formatHMS(eta / 1000);
729  }
730  else
731  this._lastProgress = progress;
732 
733  // Set the progress meter to determined.
734  this._progressMeter.setAttribute("mode", "determined");
735  // convert from 0-1 to 0-100, and round
736  this._progressMeter.value = Math.round(progress * 100);
737  } else if (operationInfo.progressMeterUndetermined) {
738  this._progressMeter.setAttribute("mode", "undetermined");
739  this._progressMeter.value = 0;
740  } else {
741  this._progressMeter.setAttribute("mode", "determined");
742  this._progressMeter.value = 0;
743  }
744 
745 // var now = new Date().valueOf();
746 // dump("==> "+ now +": "+
747 // operationInfo.localeSuffix +"+"+
748 // this._getOperationInfo(substate).localeSuffix +" "+
749 // curItemIndex +"/"+ totalItems +". "+
750 // this._itemProgress.intValue +"% of this item, "+
751 // Math.round(progress * 10000) / 100 +"% in total. "+
752 // duration +"ms spent so far, "+
753 // Math.round(eta) +"ms left until "+
754 // (new Date(now + eta)).valueOf() +"\n");
755 
756  var itemType = this._getItemType();
757  // Determine if this is a playlist
758  var isPlaylist = deviceStatus.mediaItem instanceof Ci.sbIMediaList;
759 
760  // If we're preparing to sync (indicated by an idle sub)
761  // then show the preparing label
762  if (operationInfo.preparingOnIdle && (substate == Ci.sbIDevice.STATE_IDLE))
763  {
764  localeKey = "device.status.progress_header_" + operationLocaleSuffix;
765  if (itemType)
766  localeKey = localeKey + "." + itemType;
767  subLocaleKey = "device.status.progress_preparing_" + operationLocaleSuffix;
768  } else if (operation == Ci.sbIDevice.STATE_TRANSCODE ||
769  substate == Ci.sbIDevice.STATE_TRANSCODE) {
770  localeKey = "device.status.progress_header_transcoding";
771  if (itemType)
772  localeKey = localeKey + "." + itemType;
773  } else if (operation == Ci.sbIDevice.STATE_SYNCING &&
774  substate == Ci.sbIDevice.STATE_DELETING) {
775  // we don't want to show deleting playlists counts during sync
776  if (!isPlaylist) {
777  localeKey = "device.status.progress_header_deleting";
778  }
779  else {
780  localeKey = "device.status.progress_header_syncing";
781  subLocaleKey = "device.status.progress_footer_syncing_finishing";
782  }
783  } else if (operation == Ci.sbIDevice.STATE_CANCEL) {
784  localeKey = "device.status.progress_header_cancelling";
785  } else if (operation == Ci.sbIDevice.STATE_SYNCING &&
786  substate == Ci.sbIDevice.STATE_SYNC_PLAYLIST) {
787  localeKey = "device.status.progress_header_" + operationLocaleSuffix;
788  subLocaleKey = "device.status.progress_footer_syncing_finishing";
789  this._progressMeter.setAttribute("mode", "undetermined");
790  } else if (operation == Ci.sbIDevice.STATE_COPYING ||
791  substate == Ci.sbIDevice.STATE_COPYING) {
792  localeKey = "device.status.progress_header_copying";
793  if (itemType)
794  localeKey = localeKey + "." + itemType;
795  } else {
796  localeKey = "device.status.progress_header_" + operationLocaleSuffix;
797  }
798 
799  if (!subLocaleKey) {
800  subLocaleKey = etaString ? "device.status.progress_detail"
801  : "device.status.progress_item_index";
802  }
803 
804  // Update the operation progress text.
805  this._progressTextLabel.value = SBString(localeKey, "");
806  if (curItemIndex > 0 && curItemIndex <= totalItems &&
807  operation != Ci.sbIDevice.STATE_MOUNTING &&
808  operation != Ci.sbIDevice.STATE_CANCEL &&
809  substate != Ci.sbIDevice.STATE_SYNCING &&
810  substate != Ci.sbIDevice.STATE_COPY_PREPARING &&
811  substate != Ci.sbIDevice.STATE_UPDATING &&
812  substate != Ci.sbIDevice.STATE_SYNCING_TYPE) {
813  let params = [curItemIndex, totalItems, etaString];
814  this._subProgressTextLabel.value =
815  SBFormattedString(subLocaleKey, params, "");
816  } else {
817  this._subProgressTextLabel.value = null;
818  }
819  },
820 
821  //----------------------------------------------------------------------------
822  //
823  // Device progress event handler services.
824  //
825  //----------------------------------------------------------------------------
826 
834  onAction: function DPW_onAction(aEvent) {
835  // Dispatch processing of action.
836  switch (aEvent.target.getAttribute("action")) {
837  case "finish" :
838  this._finish();
839  break;
840 
841  default :
842  break;
843  }
844  },
845 
846 
854  _onButtonEvent: function DPW__onButtonEvent(aEvent) {
855  //Create a new event for mouse click and key press
856  if ((aEvent.type == "click" && aEvent.button == 0) ||
857  (aEvent.type == "keypress" &&
858  (aEvent.keyCode == KeyEvent.DOM_VK_ENTER ||
859  aEvent.keyCode == KeyEvent.DOM_VK_RETURN))) {
860  var newEvent = document.createEvent("Events");
861  newEvent.initEvent("sbDeviceProgress-ok-button-enter", false, true);
862  document.dispatchEvent(newEvent);
863  }
864  },
865 
866 
871  // We don't do anything with these functions, but they need to be here.
872  onBatchBegin: function DeviceSyncWidget_onBatchBegin(aMediaList) {},
873  onBatchEnd: function DeviceSyncWidget_onBatchEnd(aMediaList) {},
874  onItemAdded: function DeviceSyncWidget_onItemAdded(aMediaList, aMediaItem, aIndex) { return true; },
875  onBeforeItemRemoved: function DeviceSyncWidget_onBeforeItemRemoved(aMediaList, aMediaItem, aIndex) { return true; },
876  onAfterItemRemoved: function DeviceSyncWidget_onAfterItemRemoved(aMediaList, aMediaItem, aIndex) { return true; },
877  onBeforeListCleared: function DeviceSyncWidget_onBeforeListCleared(aMediaList, aExcludeLists) { return true; },
878  onListCleared: function DeviceSyncWidget_onListCleared(aMediaList, aExcludeLists) { return true; },
879  onItemUpdated: function DeviceSyncWidget_onItemUpdated(aMediaList, aMediaItem, aProperties) { return true; },
880  onItemMoved: function DeviceSyncWidget_onItemMoved(aMediaList, aFromIndex, aToIndex) { return true; },
881  onItemCopied: function DeviceSyncWidget_onItemCopied(aSourceItem, aDestItem) { return true; },
882  onBeforeCreateMediaItem: function DeviceSyncWidget_onBeforeCreateMediaItem(aContentUri, aProperties, aAllowDuplicates) { return true; },
883  onBeforeCreateMediaList: function DeviceSyncWidget_onBeforeCreateMediaList(aType, aProperties) { return true; },
884  onBeforeAdd: function DeviceSyncWidget_onBeforeAdd(aMediaItem) { return true; },
885  onBeforeAddAll: function DeviceSyncWidget_onBeforeAddAll(aMediaList) { return true; },
886  onBeforeAddSome: function DeviceSyncWidget_onBeforeAddSome(aMediaItems) { return true; },
887  onBeforeClear: function DeviceSyncWidget_onBeforeClear() { return true; },
888 
902  _handleStateChanged: function DPW__handleStateChanged(aEvent) {
903  // Update the last event operation.
904  var prevLastEventOperation = this._lastEventOperation;
905  this._lastEventOperation = aEvent.data;
906 
907  // Get the last and previous last event operation info.
908  var lastEventOperationInfo = this._getOperationInfo
909  (this._lastEventOperation);
910  var prevLastEventOperationInfo = this._getOperationInfo
911  (prevLastEventOperation);
912 
913  // Set to show progress if busy.
914  if (lastEventOperationInfo.showProgress)
915  this._showProgress = true;
916 
917  // Remember canceled operations.
918  if ("operationCanceled" in lastEventOperationInfo)
919  this._operationCanceled = lastEventOperationInfo.operationCanceled;
920 
921  // Update the last completed event operation.
922  if (prevLastEventOperationInfo.canBeCompleted)
923  this._lastCompletedEventOperation = prevLastEventOperation;
924 
925  // Update the widget.
926  this._update();
927  },
928 
929 
930  //----------------------------------------------------------------------------
931  //
932  // Device progress XUL services.
933  //
934  //----------------------------------------------------------------------------
935 
945  _getElement: function DIW__getElement(aElementID) {
946  return document.getAnonymousElementByAttribute(this._widget,
947  "sbid",
948  aElementID);
949  },
950 
951 
952  //----------------------------------------------------------------------------
953  //
954  // Internal device info services.
955  //
956  //----------------------------------------------------------------------------
957 
962  _finish: function DPW__finish() {
963  // Set to no longer show progress.
964  this._showProgress = false;
965 
966  // Update the UI.
967  this._update();
968  },
969 
979  _getOperationInfo: function DPW__getOperationInfo(aOperation) {
980  var operationInfo = this._operationInfoTable[aOperation];
981  if (!operationInfo)
982  operationInfo = {};
983  return operationInfo;
984  },
985 
986 
987  //----------------------------------------------------------------------------
988  //
989  // Device progress device services.
990  //
991  // These services provide an interface to the device object.
992  // These services register for any pertinent device notifications and call
993  // _update to update the UI accordingly. In particular, these services
994  // register to receive notifications when the device state changes.
995  //
996  //----------------------------------------------------------------------------
997 
1002  _deviceInitialize: function DPW__deviceInitialize() {
1003  // Add a listener for status operations
1004  if (this._device) {
1005  var deviceEventTarget = this._device;
1006  deviceEventTarget.QueryInterface(Ci.sbIDeviceEventTarget);
1007  deviceEventTarget.addEventListener(this);
1008  }
1009  },
1010 
1015  _deviceFinalize: function DPW__deviceFinalize() {
1016  // Clear object fields.
1017  if (this._device) {
1018  var currentState = this._device.currentStatus.currentState;
1019 
1020  var deviceEventTarget = this._device;
1021  deviceEventTarget.QueryInterface(Ci.sbIDeviceEventTarget);
1022  deviceEventTarget.removeEventListener(this);
1023  }
1024  this._device = null;
1025  },
1026 
1036  _getPrefValue : function DPW__getPrefValue(aPrefID, aDefaultValue) {
1037  var prefService = Cc['@mozilla.org/preferences-service;1']
1038  .getService(Ci.nsIPrefBranch);
1039  try {
1040  return prefService.getCharPref(aPrefID);
1041  } catch (err) {
1042  return aDefaultValue;
1043  }
1044  },
1045 
1052  onDeviceEvent : function DPW_onDeviceEvent(aEvent) {
1053  switch (aEvent.type) {
1054  case Ci.sbIDeviceEvent.EVENT_DEVICE_STATE_CHANGED:
1055  this._handleStateChanged(aEvent);
1056  break;
1057 
1058  case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSFER_START:
1059  case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSFER_PROGRESS:
1060  case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSFER_END:
1061  case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_START:
1062  case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_PROGRESS:
1063  case Ci.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_END:
1064  case Ci.sbIDeviceEvent.EVENT_DEVICE_PREFS_CHANGED:
1065  case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_START:
1066  case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_PROGRESS:
1067  case Ci.sbIDeviceEvent.EVENT_DEVICE_TRANSCODE_END:
1068  case Ci.sbIDeviceEvent.EVENT_DEVICE_FORMATTING_START:
1069  case Ci.sbIDeviceEvent.EVENT_DEVICE_FORMATTING_PROGRESS:
1070  case Ci.sbIDeviceEvent.EVENT_DEVICE_FORMATTING_END:
1071  case Ci.sbIDeviceEvent.EVENT_DEVICE_DOWNLOAD_START:
1072  case Ci.sbIDeviceEvent.EVENT_DEVICE_DOWNLOAD_PROGRESS:
1073  case Ci.sbIDeviceEvent.EVENT_DEVICE_DOWNLOAD_END:
1074  this._update();
1075  break;
1076  }
1077  },
1078 
1079 
1086  _deviceGetStatusDRPrefix: function DPW__deviceGetStatusDRPrefix() {
1087  return "device." + this._deviceID + ".status";
1088  },
1089 
1090 
1097  _deviceIsIdle: function DPW__deviceIsIdle() {
1098  return this._isIdle;
1099  },
1100 
1104  _deviceIsSyncing: function DPW__deviceIsSyncing() {
1105  return this._isSyncing;
1106  },
1107 
1111  _checkForDeviceErrors: function DIPW__checkForDeviceErrors() {
1112  var hasErrors = false;
1113  try {
1114  hasErrors = this._deviceErrorMonitor.deviceHasErrors(this._device,
1115  "",
1116  0);
1117  } catch (err) {
1118  Cu.reportError(err);
1119  }
1120  return hasErrors;
1121  },
1122 };
const Cu
function Fx prototype initialize
const Cc
function SBFormattedString(aKey, aParams, aDefault, aStringBundle)
var DPWCfg
function SBString(aKey, aDefault, aStringBundle)
Definition: StringUtils.jsm:93
_hideDatepicker duration
var createDataRemote
return null
Definition: FeedWriter.js:1143
const Cr
const Ci
var DPW
observe data
Definition: FeedWriter.js:1329
_getSelectedPageStyle s i