sbScriptableFilter.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 
27 #include "sbScriptableFilter.h"
28 
29 #include <sbClassInfoUtils.h>
30 
31 #include <nsAutoPtr.h>
32 #include <nsMemory.h>
33 #include <nsIClassInfoImpl.h>
34 #include <nsIStringEnumerator.h>
35 #include <nsIXPConnect.h>
36 #include <nsStringGlue.h>
37 
38 #include <jsapi.h>
39 
40 #include <sbIFilterableMediaListView.h>
41 #include <sbILibraryConstraints.h>
42 #include <sbIScriptableFilterResult.h>
43 #include <sbIMediaListView.h>
44 #include <sbIPropertyArray.h>
45 
46 #include "sbRemotePlayer.h"
48 
49 /*
50  * To log this module, set the following environment variable:
51  * NSPR_LOG_MODULES=sbScriptableFilter:5
52  */
53 #ifdef PR_LOGGING
54 static PRLogModuleInfo* gScriptableFilterLog = nsnull;
55 #endif
56 
57 #undef LOG
58 #define LOG(args) PR_LOG(gScriptableFilterLog, PR_LOG_WARN, args)
59 #define TRACE(args) PR_LOG(gScriptableFilterLog, PR_LOG_DEBUG, args)
60 
65 
67  const nsAString &aPropertyName,
68  sbRemotePlayer *aPlayer)
69  : mListView(aMediaListView),
70  mPropertyName(aPropertyName),
71  mEnumeratorIndex(-1),
72  mHasProps(PR_FALSE),
73  mPlayer(aPlayer)
74 {
75 #ifdef PR_LOGGING
76  if (!gScriptableFilterLog) {
77  gScriptableFilterLog = PR_NewLogModule( "sbScriptableFilter" );
78  }
79 #endif
80  TRACE(("sbScriptableFilter::sbScriptableFilter()"));
81 }
82 
83 sbScriptableFilter::~sbScriptableFilter()
84 {
85 }
86 
87 nsresult
89 {
90  if ( mEnumeratorIndex != -1 ) {
91  // already read
92  return NS_OK;
93  }
94 
95  if (!mListView) {
96  return NS_ERROR_NOT_INITIALIZED;
97  }
98 
99  nsresult rv;
100 
101  nsCOMPtr<sbIMediaListView> view = do_QueryInterface( mListView, &rv );
102  NS_ENSURE_SUCCESS( rv, rv );
103 
104  nsCOMPtr<nsIStringEnumerator> enumerator;
105  rv = view->GetDistinctValuesForProperty( mPropertyName, getter_AddRefs(enumerator) );
106  NS_ENSURE_SUCCESS( rv, rv );
107 
108  while (true) {
109  PRBool hasMore;
110 
111  rv = enumerator->HasMore(&hasMore);
112  NS_ENSURE_SUCCESS( rv, rv );
113  if (!hasMore) {
114  break;
115  }
116 
117  nsString value;
118  rv = enumerator->GetNext(value);
119  NS_ENSURE_SUCCESS( rv, rv );
120 
121  mStrings.AppendString(value);
122  }
123 
124  // mark that we have finished reading the enumerator, and that the next item
125  // we should enumerate would be the first item.
126  mEnumeratorIndex = 0;
127  return NS_OK;
128 }
129 
130 // ---------------------------------------------------------------------------
131 //
132 // nsIStringEnumerator
133 //
134 // ---------------------------------------------------------------------------
135 
136 
137 /* boolean hasMore (); */
138 NS_IMETHODIMP sbScriptableFilter::HasMore(PRBool *_retval)
139 {
140  TRACE(("sbScriptableFilter::HasMore()"));
141  NS_ENSURE_ARG_POINTER(_retval);
142 
143  nsresult rv = ReadEnumerator();
144  NS_ENSURE_SUCCESS( rv, rv );
145 
146  *_retval = ( mEnumeratorIndex < mStrings.Count() );
147 
148  TRACE(("sbScriptableFilter::HasMore() - got %s",
149  *_retval ? "YES" : "no"));
150 
151  return NS_OK;
152 }
153 
154 /* AString getNext (); */
155 NS_IMETHODIMP sbScriptableFilter::GetNext(nsAString & _retval)
156 {
157  TRACE(("sbScriptableFilter::GetNext()"));
158  nsresult rv = ReadEnumerator();
159  NS_ENSURE_SUCCESS( rv, rv );
160 
161  if ( !( mEnumeratorIndex < mStrings.Count() ) ) {
162  return NS_ERROR_FAILURE;
163  }
164 
165  mStrings.StringAt( mEnumeratorIndex, _retval );
167 
168  TRACE(("sbScriptableFilter::GetNext() - got %s",
169  NS_LossyConvertUTF16toASCII(_retval).BeginReading()));
170 
171  return NS_OK;
172 }
173 
174 
175 // ---------------------------------------------------------------------------
176 //
177 // nsIXPCScriptable
178 //
179 // ---------------------------------------------------------------------------
180 
181 NS_IMETHODIMP sbScriptableFilter::GetClassName(char * *aClassName)
182 {
183  NS_ENSURE_ARG_POINTER(aClassName);
184 
185  NS_NAMED_LITERAL_CSTRING( kClassName, "sbScriptableFilter" );
186  *aClassName = ToNewCString(kClassName);
187  return aClassName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
188 }
189 
190 /* readonly attribute PRUint32 scriptableFlags; */
191 NS_IMETHODIMP sbScriptableFilter::GetScriptableFlags(PRUint32 *aScriptableFlags)
192 {
193  NS_ENSURE_ARG_POINTER(aScriptableFlags);
194  // XXX Mook: USE_JSSTUB_FOR_ADDPROPERTY is needed to define things on the
195  // prototype properly; even with it set scripts cannot add
196  // properties onto the object (because they're not allow to *set*)
197  *aScriptableFlags = USE_JSSTUB_FOR_ADDPROPERTY |
198  DONT_ENUM_STATIC_PROPS |
199  DONT_ENUM_QUERY_INTERFACE |
200  WANT_GETPROPERTY |
201  WANT_NEWENUMERATE |
202  WANT_NEWRESOLVE |
203  ALLOW_PROP_MODS_DURING_RESOLVE |
204  DONT_REFLECT_INTERFACE_NAMES ;
205  return NS_OK;
206 }
207 
208 NS_IMETHODIMP sbScriptableFilter::GetProperty( nsIXPConnectWrappedNative *wrapper,
209  JSContext * cx,
210  JSObject * obj,
211  jsval id,
212  jsval * vp,
213  PRBool *_retval)
214 {
215  TRACE(("sbScriptableFilter::GetProperty()"));
216  NS_ENSURE_ARG_POINTER(_retval);
217 
218  JSString* jsstr = JS_ValueToString( cx, id );
219  if (!jsstr) {
220  return NS_OK;
221  }
222 
223  nsresult rv = ReadEnumerator();
224  NS_ENSURE_SUCCESS( rv, rv );
225 
226  *_retval = PR_TRUE;
227 
228  nsDependentString jsid( (PRUnichar *)::JS_GetStringChars(jsstr),
229  ::JS_GetStringLength(jsstr));
230  TRACE(( " getting property %s", NS_LossyConvertUTF16toASCII(jsid).get() ));
231 
232  PRInt32 length = mStrings.Count();
233  for (PRInt32 i = 0; i < length; ++i) {
234  if ( mStrings[i]->Equals(jsid) ) {
235 
236  // make a clone of the filter view...
237  nsCOMPtr<sbIMediaListView> view = do_QueryInterface( mListView, &rv );
238  NS_ENSURE_SUCCESS( rv, rv );
239  nsCOMPtr<sbIMediaListView> clonedView;
240  rv = view->Clone( getter_AddRefs(clonedView) );
241  NS_ENSURE_SUCCESS( rv, rv );
242  nsCOMPtr<sbIFilterableMediaListView> filterView =
243  do_QueryInterface( clonedView, &rv );
244  NS_ENSURE_SUCCESS( rv, rv );
245 
246  // get the old constraints
247  nsCOMPtr<sbILibraryConstraint> constraint;
248  rv = filterView->GetFilterConstraint( getter_AddRefs(constraint) );
249  NS_ENSURE_SUCCESS( rv, rv );
250 
251  nsCOMPtr<sbILibraryConstraintBuilder> builder =
252  do_CreateInstance( "@songbirdnest.com/Songbird/Library/ConstraintBuilder;1",
253  &rv );
254  NS_ENSURE_SUCCESS( rv, rv );
255 
256  // push the selected property into it if there's an existing one
257  if (constraint) {
258  rv = builder->IncludeConstraint( constraint, nsnull );
259  NS_ENSURE_SUCCESS( rv, rv );
260  rv = builder->Intersect(nsnull);
261  NS_ENSURE_SUCCESS( rv, rv );
262  }
263 
264  rv = builder->Include( mPropertyName, jsid, nsnull );
265  NS_ENSURE_SUCCESS( rv, rv );
266  rv = builder->Get( getter_AddRefs(constraint) );
267  NS_ENSURE_SUCCESS( rv, rv );
268  rv = filterView->SetFilterConstraint( constraint );
269  NS_ENSURE_SUCCESS( rv, rv );
270 
271  // make a filter result
272  nsCOMPtr<sbIScriptableFilterResult> result =
273  new sbScriptableFilterResult( filterView, mPlayer );
274  if (!result) {
275  return NS_ERROR_OUT_OF_MEMORY;
276  }
277 
278  nsCOMPtr<nsIXPConnect> xpc;
279  rv = wrapper->GetXPConnect( getter_AddRefs(xpc) );
280  NS_ENSURE_SUCCESS( rv, rv );
281 
282  nsCOMPtr<nsIXPConnectJSObjectHolder> objHolder;
283 
284  rv = xpc->WrapNative( cx,
285  obj,
286  result,
287  NS_GET_IID(sbIScriptableFilterResult),
288  getter_AddRefs(objHolder) );
289  NS_ENSURE_SUCCESS( rv, rv );
290 
291  JSObject* object = nsnull;
292  rv = objHolder->GetJSObject( &object );
293  NS_ENSURE_SUCCESS( rv, rv );
294 
295  *vp = OBJECT_TO_JSVAL(object);
296  return NS_SUCCESS_I_DID_SOMETHING;
297  }
298  }
299 
300  // check for "length"
301  if ( jsid.EqualsLiteral("length") ) {
302  *vp = INT_TO_JSVAL( mStrings.Count() );
303  return NS_SUCCESS_I_DID_SOMETHING;
304  }
305 
306  return NS_OK;
307 }
308 
309 NS_IMETHODIMP sbScriptableFilter::NewEnumerate( nsIXPConnectWrappedNative *wrapper,
310  JSContext * cx,
311  JSObject * obj,
312  PRUint32 enum_op,
313  jsval * statep,
314  jsid *idp,
315  PRBool *_retval)
316 {
317  TRACE(("sbScriptableFilter::NewEnumerate()"));
318 
319  NS_ENSURE_ARG_POINTER(_retval);
320  NS_ENSURE_ARG_POINTER(statep);
321 
322  nsresult rv = ReadEnumerator();
323  NS_ENSURE_SUCCESS( rv, rv );
324 
325  *_retval = PR_TRUE;
326 
327  switch(enum_op) {
328  case JSENUMERATE_INIT: {
329  *statep = INT_TO_JSVAL(0);
330  if (idp) {
331  *idp = INT_TO_JSVAL(mStrings.Count());
332  }
333  TRACE((" init: count %i", mStrings.Count()));
334  break;
335  }
336  case JSENUMERATE_NEXT: {
337  // prevent GC from confusing us
338  JSAutoRequest ar(cx);
339 
340  PRInt32 i = JSVAL_TO_INT(*statep);
341  if ( i < 0 || i > mStrings.Count() ) {
342  TRACE(( " invalid state %i of %i", i, mStrings.Count() ));
343  *_retval = PR_FALSE;
344  *statep = JSVAL_NULL;
345  return NS_ERROR_INVALID_ARG;
346  } else if ( i == mStrings.Count() ) {
347  TRACE((" finished iteration"));
348  *_retval = PR_TRUE;
349  *statep = JSVAL_NULL;
350  return NS_OK;
351  }
352 
353  nsString *str = mStrings[i];
354 
355  JSString *jsstr = JS_NewUCStringCopyN( cx,
356  str->BeginReading(),
357  str->Length() );
358  if (!jsstr) {
359  TRACE((" failed to alloc string"));
360  *_retval = PR_FALSE;
361  return NS_ERROR_OUT_OF_MEMORY;
362  }
363 
364  // define the property while we're here
365  *_retval = JS_DefineUCProperty( cx,
366  obj,
367  JS_GetStringChars(jsstr),
368  JS_GetStringLength(jsstr),
369  JSVAL_VOID,
370  nsnull,
371  nsnull,
372  JSPROP_ENUMERATE |
373  JSPROP_READONLY |
374  JSPROP_PERMANENT );
375  if (!*_retval) {
376  return NS_ERROR_FAILURE;
377  }
378 
379  *_retval = JS_ValueToId( cx, STRING_TO_JSVAL(jsstr), idp );
380  if (!*_retval) {
381  TRACE((" failed to get id"));
382  return NS_ERROR_FAILURE;
383  }
384 
385  *statep = INT_TO_JSVAL(++i);
386  TRACE((" next: %i", JSVAL_TO_INT(*statep)));
387  break;
388  }
389  case JSENUMERATE_DESTROY: {
390  // nothing to do
391  break;
392  }
393  default:
394  // umm, should not happen
395  *_retval = PR_FALSE;
396  return NS_ERROR_INVALID_ARG;
397  }
398  return NS_OK;
399 }
400 
401 NS_IMETHODIMP sbScriptableFilter::NewResolve( nsIXPConnectWrappedNative *wrapper,
402  JSContext * cx,
403  JSObject * obj,
404  jsval id,
405  PRUint32 flags,
406  JSObject * *objp,
407  PRBool *_retval)
408 {
409  TRACE(("sbScriptableFilter::NewResolve()"));
410  NS_ENSURE_ARG_POINTER(_retval);
411 
412  nsresult rv = ReadEnumerator();
413  NS_ENSURE_SUCCESS( rv, rv );
414 
415  jsval v;
416  *_retval = JS_IdToValue( cx, id, &v );
417  NS_ENSURE_TRUE( *_retval, NS_ERROR_INVALID_ARG );
418 
419  // we only consider string properties
420  JSString *jsstr = JS_ValueToString( cx, id );
421  if (!jsstr) {
422  if (objp) {
423  *objp = nsnull;
424  }
425  return NS_OK;
426  }
427 
428  nsDependentString prop( JS_GetStringChars(jsstr) );
429  TRACE((" Resolving property %s",
430  NS_LossyConvertUTF16toASCII(prop).BeginReading() ));
431 
432  PRInt32 length = mStrings.Count();
433  for (PRInt32 i = 0; i < length; ++i) {
434  if ( mStrings[i]->Equals(prop) ) {
435  *_retval = JS_DefineUCProperty( cx,
436  obj,
437  JS_GetStringChars(jsstr),
438  JS_GetStringLength(jsstr),
439  JSVAL_VOID,
440  nsnull,
441  nsnull,
442  JSPROP_ENUMERATE |
443  JSPROP_READONLY |
444  JSPROP_PERMANENT );
445  if (objp) {
446  *objp = obj;
447  }
448  return NS_OK;
449  }
450  }
451  if (objp) {
452  *objp = nsnull;
453  }
454 
455  return NS_OK;
456 }
457 
458 // ---------------------------------------------------------------------------
459 //
460 // nsISecurityCheckedComponent
461 //
462 // ---------------------------------------------------------------------------
463 
464 NS_IMETHODIMP sbScriptableFilter::CanCreateWrapper( const nsIID * iid,
465  char **_retval)
466 {
467  TRACE(("sbScriptableFilter::CanCreateWrapper()"));
468 
469  NS_ENSURE_ARG_POINTER(_retval);
470  *_retval = ToNewCString( NS_LITERAL_CSTRING("AllAccess") );
471  return NS_OK;
472 }
473 
474 NS_IMETHODIMP sbScriptableFilter::CanCallMethod( const nsIID * iid,
475  const PRUnichar *methodName,
476  char **_retval)
477 {
478  TRACE(("sbScriptableFilter::CanCallMethod() - %s",
479  NS_LossyConvertUTF16toASCII(methodName).BeginReading()));
480 
481  NS_ENSURE_ARG_POINTER(_retval);
482  *_retval = ToNewCString( NS_LITERAL_CSTRING("AllAccess") );
483  return NS_OK;
484 }
485 
486 NS_IMETHODIMP sbScriptableFilter::CanGetProperty( const nsIID * iid,
487  const PRUnichar *propertyName,
488  char **_retval)
489 {
490  TRACE(("sbScriptableFilter::CanGetProperty() - %s",
491  NS_LossyConvertUTF16toASCII(propertyName).BeginReading()));
492 
493  NS_ENSURE_ARG_POINTER(_retval);
494  *_retval = ToNewCString( NS_LITERAL_CSTRING("AllAccess") );
495  return NS_OK;
496 }
497 
498 NS_IMETHODIMP sbScriptableFilter::CanSetProperty( const nsIID * iid,
499  const PRUnichar *propertyName,
500  char **_retval)
501 {
502  TRACE(("sbScriptableFilter::CanSetProperty() - %s",
503  NS_LossyConvertUTF16toASCII(propertyName).BeginReading()));
504 
505  NS_ENSURE_ARG_POINTER(_retval);
506  *_retval = ToNewCString( NS_LITERAL_CSTRING("NoAccess") );
507  return NS_OK;
508 }
509 
510 // ---------------------------------------------------------------------------
511 //
512 // nsIClassInfo
513 //
514 // ---------------------------------------------------------------------------
516 
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 enum_op, jsval *statep, jsid *idp, PRBool *_retval)
return NS_OK
nsCOMPtr< sbIFilterableMediaListView > mListView
sbDeviceFirmwareAutoCheckForUpdate prototype flags
nsRefPtr< sbRemotePlayer > mPlayer
#define TRACE(args)
nsISecurityCheckedComponent
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsval id, jsval *vp, PRBool *_retval)
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsval id, PRUint32 flags, JSObject **objp, PRBool *_retval)
Control the filter settings on a media list.
The result of a filtering expression in a library.
NS_DECL_ISUPPORTS NS_DECL_NSICLASSINFO NS_DECL_NSISECURITYCHECKEDCOMPONENT NS_DECL_NSISTRINGENUMERATOR NS_IMETHOD GetClassName(char **aClassName)
NS_IMPL_ISUPPORTS3_CI(sbScriptableFilter, nsISecurityCheckedComponent, nsIXPCScriptable, nsIStringEnumerator) sbScriptableFilter
StringArrayEnumerator prototype hasMore
countRef value
Definition: FeedWriter.js:1423
sbIJobCancelable NS_DECL_CLASSINFO(sbGstreamerMediaInspector)
NS_IMETHOD GetScriptableFlags(PRUint32 *aScriptableFlags)
#define SB_IMPL_CLASSINFO_INTERFACES_ONLY(_class)
friend class sbScriptableFilterResult
nsStringArray mStrings
_getSelectedPageStyle s i