sbScriptableFilterItems.cpp
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 
28 
29 #include <sbClassInfoUtils.h>
30 
31 #include <nsAutoPtr.h>
32 #include <nsMemory.h>
33 #include <nsIClassInfoImpl.h>
34 #include <nsIStringEnumerator.h>
35 #include <nsStringGlue.h>
36 
37 #include <jsapi.h>
38 
39 #include <sbIFilterableMediaListView.h>
40 #include <sbIMediaListView.h>
41 #include <sbIMediaItem.h>
42 
43 #include "sbRemoteAPIUtils.h"
45 #include "sbRemotePlayer.h"
46 
47 /*
48  * To log this module, set the following environment variable:
49  * NSPR_LOG_MODULES=sbScriptableFilterItems:5
50  */
51 #ifdef PR_LOGGING
52 static PRLogModuleInfo* gScriptableFilterItemsLog = nsnull;
53 #endif
54 
55 #undef LOG
56 #define LOG(args) PR_LOG(gScriptableFilterItemsLog, PR_LOG_WARN, args)
57 #define TRACE(args) PR_LOG(gScriptableFilterItemsLog, PR_LOG_DEBUG, args)
58 
68 
69 // see note in scScriptableFilterItems.h - this is for QI
70 NS_DEFINE_STATIC_IID_ACCESSOR(sbScriptableFilterItems, SB_SCRIPTABLE_FILETER_ITEMS_CID)
71 
72 sbScriptableFilterItems::sbScriptableFilterItems( sbIFilterableMediaListView *aFilterList,
73  sbRemotePlayer *aPlayer )
74  : mListView(aFilterList),
75  mHasItems(PR_FALSE),
76  mPlayer(aPlayer),
77  mEnumerationIndex(0)
78 {
79 #ifdef PR_LOGGING
80  if (!gScriptableFilterItemsLog) {
81  gScriptableFilterItemsLog = PR_NewLogModule( "sbScriptableFilterItems" );
82  }
83 #endif
84  TRACE(("sbScriptableFilterItems::sbScriptableFilterItems()"));
85 }
86 
87 sbScriptableFilterItems::sbScriptableFilterItems( const nsCOMArray<sbIMediaItem>& aItems,
88  sbRemotePlayer *aPlayer )
89  : mItems(aItems),
90  mHasItems(PR_TRUE),
91  mPlayer(aPlayer),
92  mEnumerationIndex(0)
93 {
94 #ifdef PR_LOGGING
95  if (!gScriptableFilterItemsLog) {
96  gScriptableFilterItemsLog = PR_NewLogModule( "sbScriptableFilterItems" );
97  }
98 #endif
99  TRACE(("sbScriptableFilterItems::sbScriptableFilterItems()"));
100 }
101 
102 sbScriptableFilterItems::~sbScriptableFilterItems()
103 {
104 }
105 
106 nsresult
108 {
109  if ( mHasItems ) {
110  // already read
111  return NS_OK;
112  }
113 
114  if (!mListView) {
115  // no enumerator to resolve
116  return NS_ERROR_NOT_INITIALIZED;
117  }
118 
119  nsresult rv;
120 
121  nsCOMPtr<sbIMediaListView> listView = do_QueryInterface( mListView, &rv );
122  NS_ENSURE_SUCCESS( rv, rv );
123 
124  PRUint32 length;
125  rv = listView->GetLength( &length );
126  NS_ENSURE_SUCCESS( rv, rv );
127 
128  for (PRUint32 i = 0; i < length; ++i ) {
129  nsCOMPtr<sbIMediaItem> item;
130  rv = listView->GetItemByIndex( i, getter_AddRefs(item) );
131  NS_ENSURE_SUCCESS( rv, rv );
132  mItems.AppendObject(item);
133  }
134 
135  mHasItems = PR_TRUE;
136  return NS_OK;
137 }
138 
139 // ---------------------------------------------------------------------------
140 //
141 // nsIXPCScriptable
142 //
143 // ---------------------------------------------------------------------------
144 
145 NS_IMETHODIMP sbScriptableFilterItems::GetClassName(char * *aClassName)
146 {
147  NS_ENSURE_ARG_POINTER(aClassName);
148 
149  NS_NAMED_LITERAL_CSTRING( kClassName, "sbScriptableFilterItems" );
150  *aClassName = ToNewCString(kClassName);
151  return aClassName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
152 }
153 
154 /* readonly attribute PRUint32 scriptableFlags; */
155 NS_IMETHODIMP sbScriptableFilterItems::GetScriptableFlags(PRUint32 *aScriptableFlags)
156 {
157  NS_ENSURE_ARG_POINTER(aScriptableFlags);
158  // XXX Mook: USE_JSSTUB_FOR_ADDPROPERTY is needed to define things on the
159  // prototype properly; even with it set scripts cannot add
160  // properties onto the object (because they're not allow to *set*)
161  *aScriptableFlags = USE_JSSTUB_FOR_ADDPROPERTY |
162  DONT_ENUM_STATIC_PROPS |
163  DONT_ENUM_QUERY_INTERFACE |
164  CLASSINFO_INTERFACES_ONLY |
165  WANT_GETPROPERTY |
166  WANT_NEWENUMERATE |
167  WANT_NEWRESOLVE |
168  WANT_EQUALITY |
169  ALLOW_PROP_MODS_DURING_RESOLVE |
170  DONT_REFLECT_INTERFACE_NAMES ;
171  return NS_OK;
172 }
173 
174 NS_IMETHODIMP sbScriptableFilterItems::GetProperty( nsIXPConnectWrappedNative *wrapper,
175  JSContext * cx,
176  JSObject * obj,
177  jsval id,
178  jsval * vp,
179  PRBool *_retval)
180 {
181  TRACE(("sbScriptableFilterItems::GetProperty()"));
182  NS_ENSURE_ARG_POINTER(_retval);
183 
184  JSString* jsstr = JS_ValueToString( cx, id );
185  if (!jsstr) {
186  return NS_OK;
187  }
188 
189  nsresult rv = ReadEnumerator();
190  NS_ENSURE_SUCCESS( rv, rv );
191 
192  *_retval = PR_TRUE;
193 
194  nsDependentString jsid( (PRUnichar *)::JS_GetStringChars(jsstr),
195  ::JS_GetStringLength(jsstr));
196  TRACE(( " getting property %s", NS_LossyConvertUTF16toASCII(jsid).get() ));
197 
198  PRInt32 length = mItems.Count();
199  for (PRInt32 i = 0; i < length; ++i) {
200  nsString guid;
201  rv = mItems[i]->GetGuid(guid);
202  NS_ENSURE_SUCCESS( rv, rv );
203  if ( guid.Equals(jsid) ) {
204  nsCOMPtr<sbIMediaItem> remoteItem;
205  rv = SB_WrapMediaItem( mPlayer, mItems[i], getter_AddRefs(remoteItem) );
206  NS_ENSURE_SUCCESS( rv, rv );
207 
208  nsCOMPtr<nsIXPConnect> xpc;
209  rv = wrapper->GetXPConnect( getter_AddRefs(xpc) );
210  NS_ENSURE_SUCCESS( rv, rv );
211 
212  nsCOMPtr<nsIXPConnectJSObjectHolder> objHolder;
213 
214  rv = xpc->WrapNative( cx,
215  obj,
216  remoteItem,
217  NS_GET_IID(sbIMediaItem),
218  getter_AddRefs(objHolder) );
219  NS_ENSURE_SUCCESS( rv, rv );
220 
221  JSObject* object = nsnull;
222  rv = objHolder->GetJSObject( &object );
223  NS_ENSURE_SUCCESS( rv, rv );
224 
225  *vp = OBJECT_TO_JSVAL(object);
226  return NS_SUCCESS_I_DID_SOMETHING;
227  }
228  }
229 
230  // check for "length"
231  if ( jsid.EqualsLiteral("length") ) {
232  *vp = INT_TO_JSVAL( mItems.Count() );
233  return NS_SUCCESS_I_DID_SOMETHING;
234  }
235 
236  return NS_OK;
237 }
238 
239 NS_IMETHODIMP sbScriptableFilterItems::NewEnumerate( nsIXPConnectWrappedNative *wrapper,
240  JSContext * cx,
241  JSObject * obj,
242  PRUint32 enum_op,
243  jsval * statep,
244  jsid *idp,
245  PRBool *_retval )
246 {
247  TRACE(("sbScriptableFilterItems::NewEnumerate()"));
248 
249  NS_ENSURE_ARG_POINTER(_retval);
250  NS_ENSURE_ARG_POINTER(statep);
251 
252  nsresult rv = ReadEnumerator();
253  NS_ENSURE_SUCCESS( rv, rv );
254 
255  *_retval = PR_TRUE;
256 
257  switch(enum_op) {
258  case JSENUMERATE_INIT: {
259  *statep = INT_TO_JSVAL(0);
260  if (idp) {
261  *idp = INT_TO_JSVAL(mItems.Count());
262  }
263  TRACE((" init: count %i", mItems.Count()));
264  break;
265  }
266  case JSENUMERATE_NEXT: {
267  // prevent GC from confusing us
268  JSAutoRequest ar(cx);
269 
270  PRInt32 i = JSVAL_TO_INT(*statep);
271  if ( i < 0 || i > mItems.Count() ) {
272  TRACE(( " invalid state %i of %i", i, mItems.Count() ));
273  *_retval = PR_FALSE;
274  *statep = JSVAL_NULL;
275  return NS_ERROR_INVALID_ARG;
276  } else if ( i == mItems.Count() ) {
277  TRACE((" finished iteration"));
278  *_retval = PR_TRUE;
279  *statep = JSVAL_NULL;
280  return NS_OK;
281  }
282 
283  nsCOMPtr<sbIMediaItem> item = mItems[i];
284 
285  nsString guid;
286  rv = item->GetGuid(guid);
287  NS_ENSURE_SUCCESS( rv, rv );
288 
289  JSString *jsstr = JS_NewUCStringCopyN( cx,
290  guid.BeginReading(),
291  guid.Length() );
292  if (!jsstr) {
293  TRACE((" failed to alloc string"));
294  *_retval = PR_FALSE;
295  return NS_ERROR_OUT_OF_MEMORY;
296  }
297 
298  // define the property while we're here
299  *_retval = JS_DefineUCProperty( cx,
300  obj,
301  JS_GetStringChars(jsstr),
302  JS_GetStringLength(jsstr),
303  JSVAL_VOID,
304  nsnull,
305  nsnull,
306  JSPROP_ENUMERATE |
307  JSPROP_READONLY |
308  JSPROP_PERMANENT );
309  if (!*_retval) {
310  return NS_ERROR_FAILURE;
311  }
312 
313  *_retval = JS_ValueToId( cx, STRING_TO_JSVAL(jsstr), idp );
314  if (!*_retval) {
315  TRACE((" failed to get id"));
316  return NS_ERROR_FAILURE;
317  }
318 
319  *statep = INT_TO_JSVAL(++i);
320  TRACE((" next: %i", JSVAL_TO_INT(*statep)));
321  break;
322  }
323  case JSENUMERATE_DESTROY: {
324  // nothing to do
325  break;
326  }
327  default:
328  // umm, should not happen
329  *_retval = PR_FALSE;
330  return NS_ERROR_INVALID_ARG;
331  }
332  return NS_OK;
333 }
334 
335 NS_IMETHODIMP sbScriptableFilterItems::NewResolve( nsIXPConnectWrappedNative *wrapper,
336  JSContext * cx,
337  JSObject * obj,
338  jsval id,
339  PRUint32 flags,
340  JSObject * *objp,
341  PRBool *_retval)
342 {
343  TRACE(("sbScriptableFilterItems::NewResolve()"));
344  NS_ENSURE_ARG_POINTER(_retval);
345 
346  nsresult rv = ReadEnumerator();
347  NS_ENSURE_SUCCESS( rv, rv );
348 
349  jsval v;
350  *_retval = JS_IdToValue( cx, id, &v );
351  NS_ENSURE_TRUE( *_retval, NS_ERROR_INVALID_ARG );
352 
353  // we only consider string properties
354  JSString *jsstr = JS_ValueToString( cx, id );
355  if (!jsstr) {
356  if (objp) {
357  *objp = nsnull;
358  }
359  return NS_OK;
360  }
361 
362  nsDependentString prop( JS_GetStringChars(jsstr) );
363  TRACE((" Resolving property %s",
364  NS_LossyConvertUTF16toASCII(prop).BeginReading() ));
365 
366  PRInt32 length = mItems.Count();
367  for (PRInt32 i = 0; i < length; ++i) {
368  nsString guid;
369  rv = mItems[i]->GetGuid(guid);
370  NS_ENSURE_SUCCESS( rv, rv );
371  if ( guid.Equals(prop) ) {
372  *_retval = JS_DefineUCProperty( cx,
373  obj,
374  JS_GetStringChars(jsstr),
375  JS_GetStringLength(jsstr),
376  JSVAL_VOID,
377  nsnull,
378  nsnull,
379  JSPROP_ENUMERATE |
380  JSPROP_READONLY |
381  JSPROP_PERMANENT );
382  if (objp) {
383  *objp = obj;
384  }
385  return NS_OK;
386  }
387  }
388  if (objp) {
389  *objp = nsnull;
390  }
391 
392  return NS_OK;
393 }
394 
395 NS_IMETHODIMP sbScriptableFilterItems::Equality( nsIXPConnectWrappedNative *wrapper,
396  JSContext * cx,
397  JSObject * obj,
398  jsval val,
399  PRBool *_retval )
400 {
401  LOG(("sbScriptableFilterItems::Equality()"));
402  nsresult rv;
403  NS_ENSURE_ARG_POINTER(_retval);
404  NS_ENSURE_ARG_POINTER(obj);
405  NS_ENSURE_ARG_POINTER(wrapper);
406 
407  *_retval = PR_FALSE;
408 
409  if ( !JSVAL_IS_OBJECT(val) ) {
410  return NS_OK;
411  }
412  JSObject* otherObj = JSVAL_TO_OBJECT(val);
413 
414  nsCOMPtr<nsIXPConnect> xpc;
415  rv = wrapper->GetXPConnect( getter_AddRefs(xpc) );
416  NS_ENSURE_SUCCESS( rv, rv );
417 
418  nsCOMPtr<nsIXPConnectWrappedNative> otherWrapper;
419  rv = xpc->GetWrappedNativeOfJSObject( cx, otherObj, getter_AddRefs(otherWrapper) );
420  if ( NS_FAILED(rv) ) {
421  // not a C++ XPCOM object
422  return NS_OK;
423  }
424 
425  nsRefPtr<sbScriptableFilterItems> other;
426  sbScriptableFilterItems* otherPtr;
427  rv = CallQueryInterface( otherWrapper->Native(), &otherPtr );
428  if ( NS_FAILED(rv) ) {
429  // not us
430  return NS_OK;
431  }
432  other = already_AddRefed<sbScriptableFilterItems>(otherPtr);
433 
434  rv = ReadEnumerator();
435  NS_ENSURE_SUCCESS( rv, rv );
436  rv = other->ReadEnumerator();
437  NS_ENSURE_SUCCESS( rv, rv );
438 
439  if ( mItems.Count() != other->mItems.Count() ) {
440  // lengths don't match, not the same
441  return NS_OK;
442  }
443 
444  // XXX Mook: this is pretty sucky. We take all the items in the other set
445  // and compare against all the items in this set.
446 
447  std::multiset<nsString> itemSet;
448  for (PRInt32 i = 0; i < other->mItems.Count(); ++i) {
449  nsString guid;
450  rv = other->mItems[i]->GetGuid(guid);
451  NS_ENSURE_SUCCESS( rv, rv );
452  itemSet.insert(guid);
453  }
454 
455  PRInt32 itemsCount = mItems.Count();
456  for (PRInt32 i = 0; i < itemsCount; ++i) {
457  nsString guid;
458  rv = mItems[i]->GetGuid(guid);
459  NS_ENSURE_SUCCESS( rv, rv );
460  std::multiset<nsString>::iterator found;
461  found = itemSet.find(guid);
462  if ( found == itemSet.end() ) {
463  // not found
464  return NS_OK;
465  }
466  itemSet.erase(found);
467  }
468  if ( itemSet.empty() ) {
469  // no more items left, the two are the same
470  *_retval = PR_TRUE;
471  }
472 
473  return NS_OK;
474 }
475 
476 
477 // ---------------------------------------------------------------------------
478 //
479 // nsISimpleEnumerator
480 //
481 // ---------------------------------------------------------------------------
482 
483 NS_IMETHODIMP sbScriptableFilterItems::HasMoreElements(PRBool *_retval)
484 {
485  NS_ENSURE_ARG_POINTER(_retval);
486  NS_ENSURE_TRUE( mHasItems, NS_ERROR_NOT_INITIALIZED );
487  NS_ENSURE_STATE( mEnumerationIndex >= 0 );
488 
489  *_retval = mEnumerationIndex < (PRUint32)mItems.Count();
490  return NS_OK;
491 }
492 
493 NS_IMETHODIMP sbScriptableFilterItems::GetNext(nsISupports **_retval)
494 {
495  NS_ENSURE_ARG_POINTER(_retval);
496  NS_ENSURE_TRUE( mHasItems, NS_ERROR_NOT_INITIALIZED );
497  NS_ENSURE_STATE( mEnumerationIndex >= 0 );
498  NS_ENSURE_TRUE( mEnumerationIndex < (PRUint32)mItems.Count(), NS_ERROR_FAILURE );
499 
500  nsresult rv;
501  nsCOMPtr<sbIMediaItem> rawItem = mItems[mEnumerationIndex];
502 
503  nsCOMPtr<sbIIndexedMediaItem> item = do_QueryInterface(rawItem, &rv);
504  if (NS_SUCCEEDED(rv)) {
505  // we have an IndexedMediaItem, we're handling a selection enumeration
506  nsRefPtr<sbRemoteIndexedMediaItem> indexedMediaItem =
508  NS_ENSURE_TRUE(indexedMediaItem, NS_ERROR_OUT_OF_MEMORY);
509 
510  rv = indexedMediaItem->Init();
511  NS_ENSURE_SUCCESS(rv, rv);
512  NS_ADDREF( *_retval = NS_ISUPPORTS_CAST(sbIIndexedMediaItem*,
513  indexedMediaItem) );
514  }
515  else {
516  nsCOMPtr<sbIMediaItem> remoteItem;
517  rv = SB_WrapMediaItem(mPlayer, rawItem, getter_AddRefs(remoteItem));
518  NS_ENSURE_SUCCESS(rv, rv);
519  NS_ADDREF( *_retval = NS_ISUPPORTS_CAST(sbIMediaItem*,
520  remoteItem) );
521  }
522 
523  TRACE(( "sbScriptableFilterItems::GetNext(): got %i = %08x",
525  *_retval ));
527  return NS_OK;
528 }
529 
530 // ---------------------------------------------------------------------------
531 //
532 // nsISecurityCheckedComponent
533 //
534 // ---------------------------------------------------------------------------
535 
536 NS_IMETHODIMP sbScriptableFilterItems::CanCreateWrapper( const nsIID * iid,
537  char **_retval)
538 {
539  TRACE(("sbScriptableFilterItems::CanCreateWrapper()"));
540 
541  NS_ENSURE_ARG_POINTER(_retval);
542  *_retval = ToNewCString( NS_LITERAL_CSTRING("AllAccess") );
543  return NS_OK;
544 }
545 
546 NS_IMETHODIMP sbScriptableFilterItems::CanCallMethod( const nsIID * iid,
547  const PRUnichar *methodName,
548  char **_retval)
549 {
550  TRACE(("sbScriptableFilterItems::CanCallMethod() - %s",
551  NS_LossyConvertUTF16toASCII(methodName).BeginReading()));
552 
553  NS_ENSURE_ARG_POINTER(_retval);
554  *_retval = ToNewCString( NS_LITERAL_CSTRING("AllAccess") );
555  return NS_OK;
556 }
557 
558 NS_IMETHODIMP sbScriptableFilterItems::CanGetProperty( const nsIID * iid,
559  const PRUnichar *propertyName,
560  char **_retval)
561 {
562  TRACE(("sbScriptableFilterItems::CanGetProperty() - %s",
563  NS_LossyConvertUTF16toASCII(propertyName).BeginReading()));
564 
565  NS_ENSURE_ARG_POINTER(_retval);
566  *_retval = ToNewCString( NS_LITERAL_CSTRING("AllAccess") );
567  return NS_OK;
568 }
569 
570 NS_IMETHODIMP sbScriptableFilterItems::CanSetProperty( const nsIID * iid,
571  const PRUnichar *propertyName,
572  char **_retval)
573 {
574  TRACE(("sbScriptableFilterItems::CanSetProperty() - %s",
575  NS_LossyConvertUTF16toASCII(propertyName).BeginReading()));
576 
577  NS_ENSURE_ARG_POINTER(_retval);
578  *_retval = ToNewCString( NS_LITERAL_CSTRING("NoAccess") );
579  return NS_OK;
580 }
581 
582 // ---------------------------------------------------------------------------
583 //
584 // nsIClassInfo
585 //
586 // ---------------------------------------------------------------------------
588 
590 
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsval id, jsval *vp, PRBool *_retval)
sbScriptableFilterItems(sbIFilterableMediaListView *aFilterList, sbRemotePlayer *aPlayer)
#define TRACE(args)
return NS_OK
NS_IMPL_CI_INTERFACE_GETTER3(sbMediaListEnumeratorWrapper, sbIMediaListEnumeratorWrapper, nsISimpleEnumerator, nsIClassInfo)
#define SB_SCRIPTABLE_FILETER_ITEMS_CID
sbDeviceFirmwareAutoCheckForUpdate prototype flags
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 enum_op, jsval *statep, jsid *idp, PRBool *_retval)
NS_IMPL_ISUPPORTS4(sbScriptableFilterItems, nsISecurityCheckedComponent, nsIXPCScriptable, nsISimpleEnumerator, sbScriptableFilterItems) NS_IMPL_CI_INTERFACE_GETTER3(sbScriptableFilterItems
NS_IMETHOD Equality(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsval val, PRBool *_retval)
nsRefPtr< sbRemotePlayer > mPlayer
Control the filter settings on a media list.
nsCOMPtr< sbIFilterableMediaListView > mListView
this _dialogInput val(dateText)
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsval id, PRUint32 flags, JSObject **objp, PRBool *_retval)
nsCOMArray< sbIMediaItem > mItems
nsRefPtr< sbRemotePlayer > mPlayer
A container for a media item and its index.
NS_DECL_ISUPPORTS NS_DECL_NSICLASSINFO NS_DECL_NSISECURITYCHECKEDCOMPONENT NS_DECL_NSISIMPLEENUMERATOR NS_IMETHOD GetClassName(char **aClassName)
sbIJobCancelable NS_DECL_CLASSINFO(sbGstreamerMediaInspector)
#define LOG(args)
static nsresult SB_WrapMediaItem(sbRemotePlayer *aRemotePlayer, sbIMediaItem *aMediaItem, sbIMediaItem **aRemoteMediaItem)
nsCOMPtr< sbIFilterableMediaListView > mListView
Interface that defines a single item of media in the system.
#define SB_IMPL_CLASSINFO_INTERFACES_ONLY(_class)
_getSelectedPageStyle s i
nsISecurityCheckedComponent
NS_IMETHOD GetScriptableFlags(PRUint32 *aScriptableFlags)