SBJobUtils.jsm
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25  */
26 
27 EXPORTED_SYMBOLS = [ "SBJobUtils" ];
28 
29 // Amount of time to wait before launching a progress dialog
31 
32 const Cc = Components.classes;
33 const Ci = Components.interfaces;
34 const Cr = Components.results;
35 const Ce = Components.Exception;
36 const Cu = Components.utils;
37 
38 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
39 Cu.import("resource://app/jsmodules/ArrayConverter.jsm");
40 Cu.import("resource://app/jsmodules/WindowUtils.jsm");
41 Cu.import("resource://app/jsmodules/SBTimer.jsm");
42 
43 /******************************************************************************
44  * A collection of functions for manipulating sbIJob* interfaces
45  *****************************************************************************/
46 var SBJobUtils = {
47 
61  showProgressDialog: function(aJobProgress, aWindow, aTimeout, aNonModal) {
62  if (!(aJobProgress instanceof Ci.sbIJobProgress)) {
63  throw new Error("showProgressDialog requires an object implementing sbIJobProgress");
64  }
65 
66  function showDialog() {
67  if (timer) {
68  timer.cancel();
69  timer = null;
70  }
71 
72  // If the job is already complete, skip the dialog
73  if (aJobProgress.status == Ci.sbIJobProgress.STATUS_SUCCEEDED) {
74  return;
75  }
76 
77  // If the job is blocked and the dialog is modal, skip the dialog to avoid
78  // blocking the UI
79  if (!aNonModal && aJobProgress.blocked) {
80  return;
81  }
82 
83  // Parent to the main window by default
84  if (!aWindow || aWindow.closed) {
85  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
86  .getService(Components.interfaces.nsIWindowMediator);
87  aWindow = wm.getMostRecentWindow("Songbird:Main");
88  }
89  WindowUtils.openDialog(
90  aWindow,
91  "chrome://songbird/content/xul/jobProgress.xul",
92  "job_progress_dialog",
93  "chrome,centerscreen",
94  !aNonModal,
95  [ aJobProgress ],
96  null,
97  null);
98  }
99 
100  if (aTimeout == null) {
102  }
103 
104  var timer;
105  if (aTimeout) {
106  // Wait a bit before launching the dialog. If the job is already
107  // complete don't bother launching it.
108  // The timer will maintain a ref to this closure during the delay, and vice versa.
109  timer = new SBTimer(showDialog, aTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
110  } else {
111  // If 0 just show immediately
112  showDialog();
113  }
114  }
115 
116 }
117 
118 
119 /******************************************************************************
120  * A base implementation of sbIJobProgress, to be extended
121  * when creating a JavaScript sbIJobProgress object.
122  *
123  * Supports forwarding progress information to a child sbIJobProgress,
124  * for cases where a main job needs to aggregate a number of sub-jobs.
125  *
126  * See DirectoryImportJob for an example.
127  *****************************************************************************/
128 SBJobUtils.JobBase = function() {
129  this._errorMessages = [];
130  this._listeners = [];
131 }
132 SBJobUtils.JobBase.prototype = {
133  QueryInterface : XPCOMUtils.generateQI(
134  [Ci.sbIJobProgress, Ci.sbIJobCancelable,
135  Ci.sbIJobProgressListener, Ci.nsIClassInfo]),
136 
139  classDescription : 'Songbird Job Progress Implementation',
140  classID : null,
141  contractID : null,
142  flags : Ci.nsIClassInfo.MAIN_THREAD_ONLY,
143  implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
144  getHelperForLanguage : function(aLanguage) { return null; },
145  getInterfaces : function(count) {
146  var interfaces = [Ci.sbIJobProgress,
147  Ci.sbIJobCancelable,
148  Ci.sbIJobProgressListener,
149  Ci.nsIClassInfo,
150  Ci.nsISupports
151  ];
152  count.value = interfaces.length;
153  return interfaces;
154  },
155 
156 
157  _status : Ci.sbIJobProgress.STATUS_RUNNING,
158  _blocked : false,
159  _statusText : "",
160  _titleText : "",
161  _progress : 0,
162  _total : 0,
163 
164  // Array of error strings
165  _errorMessages : null,
166 
167  // Array of listeners
168  _listeners : null,
169 
170  // Another sbIJobProgress. If set, all sbIJobProgress calls other than
171  // status and listeners will be forwarded through to the other job.
172  // This can be used to provide a single interface that aggregates
173  // several sub-jobs.
174  _jobProgressDelegate : null,
175 
176 
179  get status() {
180  // Note that status is not delegated, as the main job only completes
181  // when all sub-jobs are finished.
182  return this._status;
183  },
184 
185  get blocked() {
186  return (this._jobProgressDelegate) ?
187  this._jobProgressDelegate.blocked : this._blocked;
188  },
189 
190  get statusText() {
191  return (this._jobProgressDelegate) ?
192  this._jobProgressDelegate.statusText : this._statusText;
193  },
194 
195  get titleText() {
196  return (this._jobProgressDelegate) ?
197  this._jobProgressDelegate.titleText : this._titleText;
198  },
199 
200  get progress() {
201  return (this._jobProgressDelegate) ?
202  this._jobProgressDelegate.progress : this._progress;
203  },
204 
205  get total() {
206  return (this._jobProgressDelegate) ?
207  this._jobProgressDelegate.total : this._total;
208  },
209 
210  get errorCount() {
211  return (this._jobProgressDelegate) ?
212  this._jobProgressDelegate.errorCount : this._errorMessages.length;
213  },
214 
215  getErrorMessages: function Job_getErrorMessages() {
216  return (this._jobProgressDelegate) ?
217  this._jobProgressDelegate.getErrorMessages() :
218  ArrayConverter.enumerator(this._errorMessages);
219  },
220 
221  addJobProgressListener: function Job_addJobProgressListener(aListener) {
222  aListener.QueryInterface(Ci.sbIJobProgressListener);
223  this._listeners.push(aListener);
224  },
225 
226  removeJobProgressListener: function Job_removeJobProgressListener(aListener){
227  var index = this._listeners.indexOf(aListener);
228  if (index > -1) {
229  this._listeners.splice(index,1);
230  }
231  },
232 
233 
236  _canCancel: false,
237  get canCancel() {
238  return (this._jobProgressDelegate &&
239  this._jobProgressDelegate instanceof Ci.sbIJobCancelable) ?
240  this._jobProgressDelegate.canCancel : this._canCancel;
241  },
242 
243  cancel: function Job_cancel() {
244  // Override this method
245  throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
246  },
247 
248 
256  delegateJobProgress: function Job_delegateJobProgress(aJob) {
257  if (aJob != null && !(aJob.QueryInterface(Ci.sbIJobProgress))) {
258  throw Components.results.NS_ERROR_INVALID_ARG;
259  }
260 
261  if (this._jobProgressDelegate) {
262  this._jobProgressDelegate.removeJobProgressListener(this);
263  }
264 
265  this._jobProgressDelegate = aJob;
266 
267  if (this._jobProgressDelegate) {
268  this._jobProgressDelegate.addJobProgressListener(this);
269  }
270  },
271 
272 
277  onJobProgress: function Job_onJobProgress(aJob) {
278  try {
279  if ((!this._jobProgressDelegate) || this._jobProgressDelegate != aJob) {
280  // Just report the error. Don't throw, as that would just go to the
281  // sub-job, and wouldn't help.
282  Cu.reportError("Job_onJobProgress called with invalid _jobProgressDelegate state!");
283  }
284 
285  // Forward the progress notification on to all our listeners
286  this.notifyJobProgressListeners();
287 
288  // If the delegate is done, allow the main job to move on
289  if (this._jobProgressDelegate.status != Ci.sbIJobProgress.STATUS_RUNNING) {
290  this.onJobDelegateCompleted();
291  }
292  }
293  catch (e) {
294  Cu.reportError(e);
295  }
296  },
297 
298 
303  onJobDelegateCompleted: function Job_onJobDelegateCompleted() {
304  // Base behaviour is to just throw away the delegated job
305  this.delegateJobProgress(null);
306  },
307 
308 
312  notifyJobProgressListeners: function Job_notifyJobProgressListeners() {
313  var thisJob = this;
314  // need to clone the array, otherwise removing one in the middle gets
315  // things confused
316  var listeners = [].concat(this._listeners);
317  listeners.forEach( function (listener) {
318  try {
319  listener.onJobProgress(thisJob);
320  } catch (e) {
321  Cu.reportError(e);
322  }
323  });
324  }
325 }
326 
327 
const Cu
Definition: SBJobUtils.jsm:36
var total
const Ce
Definition: SBJobUtils.jsm:35
const Ci
Definition: SBJobUtils.jsm:33
sbDeviceFirmwareAutoCheckForUpdate prototype flags
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
sbOSDControlService prototype QueryInterface
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
sbDeviceFirmwareAutoCheckForUpdate prototype getHelperForLanguage
var count
Definition: test_bug7406.js:32
const Cc
Definition: SBJobUtils.jsm:32
const PROGRESS_DEFAULT_DIALOG_DELAY
Definition: SBJobUtils.jsm:30
return null
Definition: FeedWriter.js:1143
EXPORTED_SYMBOLS
Definition: SBJobUtils.jsm:27
const Cr
Definition: SBJobUtils.jsm:34
sbDeviceFirmwareAutoCheckForUpdate prototype classID
sbDeviceFirmwareAutoCheckForUpdate prototype getInterfaces
sbDeviceFirmwareAutoCheckForUpdate prototype interfaces
classDescription implementationLanguage
Definition: FeedWriter.js:1427