sbPlayQueueExternalLibraryListener.cpp
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2010 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
31 
32 #include <nsIArray.h>
33 #include <nsISimpleEnumerator.h>
34 #include <nsServiceManagerUtils.h>
35 
36 #include <sbILibraryManager.h>
37 #include <sbStandardProperties.h>
38 
39 #include <prlog.h>
40 
41 #include <algorithm>
42 
47 #ifdef PR_LOGGING
48  static PRLogModuleInfo* gPlayQueueExternalLibraryListenerLog = nsnull;
49 #define TRACE(args) PR_LOG(gPlayQueueExternalLibraryListenerLog, PR_LOG_DEBUG, args)
50 #define LOG(args) PR_LOG(gPlayQueueExternalLibraryListenerLog, PR_LOG_WARN, args)
51 # ifdef __GNUC__
52 #define __FUNCTION__ __PRETTY_FUNCTION__
53 #endif /* __GNUC__ */
54 #else
55 #define TRACE(args) /* nothing */
56 #define LOG(args) /* nothing */
57 #endif
58 
59 //------------------------------------------------------------------------------
60 //
61 // Implementation of sbPropertyUpdate
62 //
63 //------------------------------------------------------------------------------
64 
65 bool
67 {
68  if (mItem != rhs.mItem) {
69  return false;
70  }
71 
72  nsresult rv;
73  PRUint32 lhLength;
74  rv = mUpdate->GetLength(&lhLength);
75  NS_ENSURE_SUCCESS(rv, false);
76  PRUint32 rhLength;
77  rv = rhs.mUpdate->GetLength(&rhLength);
78  NS_ENSURE_SUCCESS(rv, false);
79  if (lhLength != rhLength) {
80  return false;
81  }
82 
83  for (PRUint32 i = 0; i < lhLength; i++) {
84  nsCOMPtr<sbIProperty> lhProp;
85  rv = mUpdate->GetPropertyAt(i, getter_AddRefs(lhProp));
86  NS_ENSURE_SUCCESS(rv, false);
87  nsAutoString id;
88  lhProp->GetId(id);
89  nsAutoString lhValue;
90  lhProp->GetValue(lhValue);
91  nsAutoString rhValue;
92  rv = rhs.mUpdate->GetPropertyValue(id, rhValue);
93  NS_ENSURE_SUCCESS(rv, false);
94  if (!lhValue.Equals(rhValue)) {
95  return false;
96  }
97  }
98 
99  return true;
100 }
101 
102 //------------------------------------------------------------------------------
103 //
104 // Implementation of sbPlayQueueExternalLibraryListener
105 //
106 //------------------------------------------------------------------------------
107 
110 
112  : mUpdateLock(nsnull)
113 {
114  #if PR_LOGGING
115  if (!gPlayQueueExternalLibraryListenerLog) {
116  gPlayQueueExternalLibraryListenerLog =
117  PR_NewLogModule("sbPlayQueueExternalLibraryListener");
118  }
119  #endif /* PR_LOGGING */
120 
121  TRACE(("%s[%p]", __FUNCTION__, this));
122 
123  mUpdateLock = nsAutoLock::NewLock("sbPlayQueueExternalLibraryListener::mUpdateLock");
124  NS_ASSERTION(mUpdateLock, "failed to create lock!");
125 }
126 
127 sbPlayQueueExternalLibraryListener::~sbPlayQueueExternalLibraryListener()
128 {
129  TRACE(("%s[%p]", __FUNCTION__, this));
130 
131  if (mUpdateLock) {
132  nsAutoLock::DestroyLock(mUpdateLock);
133  }
134 }
135 
136 nsresult
138 {
139  nsresult rv;
140  rv = mMasterLibrary->RemoveListener(this);
141  NS_ENSURE_SUCCESS(rv, rv);
142 
143  PRUint32 length = mExternalLibraries.Count();
144  for (PRUint32 i = 0; i < length; i++) {
145  nsCOMPtr<sbILibrary> library = mExternalLibraries.ObjectAt(i);
146  NS_ENSURE_STATE(library);
147 
148  rv = library->RemoveListener(this);
149  NS_ENSURE_SUCCESS(rv, rv);
150  }
151 
152  return NS_OK;
153 }
154 
155 nsresult
157 {
158  TRACE(("%s[%p]", __FUNCTION__, this));
159  nsresult rv;
160 
161  mMasterLibrary = aLibrary;
162  rv = mMasterLibrary->AddListener(this,
163  PR_FALSE,
165  nsnull);
166  NS_ENSURE_SUCCESS(rv, rv);
167 
168  return NS_OK;
169 }
170 
171 nsresult
173 {
174  TRACE(("%s[%p]", __FUNCTION__, this));
175  nsresult rv;
176 
177  PRBool added = mExternalLibraries.AppendObject(aLibrary);
178  NS_ENSURE_TRUE(added, NS_ERROR_FAILURE);
179 
180  rv = aLibrary->AddListener(this,
181  PR_FALSE,
183  nsnull);
184  NS_ENSURE_SUCCESS(rv, rv);
185 
186  return NS_OK;
187 }
188 
189 nsresult
191  sbIMediaItem* aMediaItem,
192  sbIPropertyArray* aProperties)
193 {
194  TRACE(("%s[%p]", __FUNCTION__, this));
195  nsresult rv;
196 
197  // OnItemUpdated will get called with the old values, so push the
198  // current values onto mUpdates here.
199  nsCOMPtr<sbIPropertyArray> props;
200  rv = aMediaItem->GetProperties(aProperties, getter_AddRefs(props));
201  NS_ENSURE_SUCCESS(rv, rv);
202 
203  sbPropertyUpdate update(aMediaItem, props);
204  {
205  nsAutoLock lock(mUpdateLock);
206  mUpdates.push_back(update);
207  }
208 
209  rv = aMediaItem->SetProperties(aProperties);
210  NS_ENSURE_SUCCESS(rv, rv);
211 
212  {
213  nsAutoLock lock(mUpdateLock);
214  mUpdates.remove(update);
215  }
216 
217  return NS_OK;
218 }
219 
220 nsresult
221 sbPlayQueueExternalLibraryListener::GenerateUpdates(
222  sbIMediaItem* aMediaItem,
223  sbIPropertyArray* aProperties,
224  Updates& updates)
225 {
226  TRACE(("%s[%p]", __FUNCTION__, this));
227  nsresult rv;
228 
229  nsCOMPtr<sbILibrary> lib;
230  rv = aMediaItem->GetLibrary(getter_AddRefs(lib));
231  NS_ENSURE_SUCCESS(rv, rv);
232 
233  // This ensures that we have an item that is either in our master library or
234  // is duplicated in the master library.
235  nsCOMPtr<sbIMediaItem> internalMediaItem;
236  if (lib == mMasterLibrary) {
237  internalMediaItem = aMediaItem;
238  } else {
239  rv = mMasterLibrary->GetDuplicate(aMediaItem,
240  getter_AddRefs(internalMediaItem));
241  NS_ENSURE_SUCCESS(rv, rv);
242  if (internalMediaItem) {
243  sbPropertyUpdate internalUpdate(internalMediaItem, aProperties);
244  updates.push_back(internalUpdate);
245  } else {
246  // If we can't find a duplicate in our master library, just return.
247  return NS_OK;
248  }
249  }
250 
251  // We found an item in our master library - go find duplicates in our external
252  // libraries to update.
253  for (PRInt32 i = 0; i < mExternalLibraries.Count(); i++)
254  {
255  if (mExternalLibraries[i] != lib) {
256  nsCOMPtr<sbIMediaItem> externalMediaItem;
257  rv = mExternalLibraries[i]->GetDuplicate(internalMediaItem,
258  getter_AddRefs(externalMediaItem));
259  if (NS_SUCCEEDED(rv) && externalMediaItem) {
260  sbPropertyUpdate externalUpdate(externalMediaItem, aProperties);
261  updates.push_back(externalUpdate);
262  }
263  }
264  }
265  return NS_OK;
266 }
267 
268 //------------------------------------------------------------------------------
269 //
270 // Implementation of sbIMediaListListener
271 //
272 //------------------------------------------------------------------------------
273 
274 // We only care about OnItemUpdated.
275 NS_IMETHODIMP
276 sbPlayQueueExternalLibraryListener::OnBeforeListCleared(
277  sbIMediaList* aMediaList,
278  PRBool aExcludeLists,
279  PRBool *aNoMoreForBatch)
280 {
281  TRACE(("%s[%p]", __FUNCTION__, this));
282  if (aNoMoreForBatch) {
283  *aNoMoreForBatch = PR_TRUE;
284  }
285  return NS_OK;
286 }
287 
288 NS_IMETHODIMP
289 sbPlayQueueExternalLibraryListener::OnListCleared(sbIMediaList* aMediaList,
290  PRBool aExcludeLists,
291  PRBool* aNoMoreForBatch)
292 {
293  TRACE(("%s[%p]", __FUNCTION__, this));
294  if (aNoMoreForBatch) {
295  *aNoMoreForBatch = PR_TRUE;
296  }
297  return NS_OK;
298 }
299 
300 
301 NS_IMETHODIMP
302 sbPlayQueueExternalLibraryListener::OnBatchBegin(sbIMediaList* aMediaList)
303 {
304  TRACE(("%s[%p]", __FUNCTION__, this));
305  return NS_OK;
306 }
307 
308 NS_IMETHODIMP
309 sbPlayQueueExternalLibraryListener::OnBatchEnd(sbIMediaList* aMediaList)
310 {
311  TRACE(("%s[%p]", __FUNCTION__, this));
312  return NS_OK;
313 }
314 
315 NS_IMETHODIMP
316 sbPlayQueueExternalLibraryListener::OnItemAdded(sbIMediaList* aMediaList,
317  sbIMediaItem* aMediaItem,
318  PRUint32 aIndex,
319  PRBool* aNoMoreForBatch)
320 {
321  TRACE(("%s[%p]", __FUNCTION__, this));
322  if (aNoMoreForBatch) {
323  *aNoMoreForBatch = PR_TRUE;
324  }
325  return NS_OK;
326 }
327 
328 NS_IMETHODIMP
329 sbPlayQueueExternalLibraryListener::OnBeforeItemRemoved(
330  sbIMediaList* aMediaList,
331  sbIMediaItem* aMediaItem,
332  PRUint32 aIndex,
333  PRBool* aNoMoreForBatch)
334 {
335  TRACE(("%s[%p]", __FUNCTION__, this));
336  if (aNoMoreForBatch) {
337  *aNoMoreForBatch = PR_TRUE;
338  }
339  return NS_OK;
340 }
341 
342 NS_IMETHODIMP
343 sbPlayQueueExternalLibraryListener::OnAfterItemRemoved(sbIMediaList* aMediaList,
344  sbIMediaItem* aMediaItem,
345  PRUint32 aIndex,
346  PRBool* aNoMoreForBatch)
347 {
348  TRACE(("%s[%p]", __FUNCTION__, this));
349  if (aNoMoreForBatch) {
350  *aNoMoreForBatch = PR_TRUE;
351  }
352  return NS_OK;
353 }
354 
355 NS_IMETHODIMP
356 sbPlayQueueExternalLibraryListener::OnItemUpdated(sbIMediaList* aMediaList,
357  sbIMediaItem* aMediaItem,
358  sbIPropertyArray* aProperties,
359  PRBool* aNoMoreForBatch)
360 {
361  TRACE(("%s[%p]", __FUNCTION__, this));
362 
363  nsresult rv;
364 
365  Updates updates;
366  sbPropertyUpdate update(aMediaItem, aProperties);
367  {
368  nsAutoLock lock(mUpdateLock);
369 
370  UpdateIter it;
371  it = std::find(mUpdates.begin(), mUpdates.end(), update);
372  if (it != mUpdates.end()) {
373  // This update is already being handled.
374  return NS_OK;
375  }
376 
377  rv = GenerateUpdates(aMediaItem, aProperties, updates);
378  NS_ENSURE_SUCCESS(rv, rv);
379  if (updates.size() == 0) {
380  // No duplicates to update.
381  return NS_OK;
382  }
383 
384  for (it = updates.begin(); it != updates.end(); it++) {
385  mUpdates.push_back(*it);
386  }
387  }
388 
389  // Get the updated properties from the item and apply them to the items we
390  // need to update.
391  nsCOMPtr<sbIPropertyArray> props;
392  rv = aMediaItem->GetProperties(aProperties, getter_AddRefs(props));
393  NS_ENSURE_SUCCESS(rv, rv);
394 
395  for (UpdateIter it = updates.begin(); it != updates.end(); it++) {
396  rv = it->mItem->SetProperties(props);
397  NS_ENSURE_SUCCESS(rv, rv);
398  }
399 
400  {
401  nsAutoLock lock(mUpdateLock);
402 
403  for (UpdateIter it = updates.begin(); it != updates.end(); it++) {
404  mUpdates.remove(*it);
405  }
406  }
407 
408  return NS_OK;
409 }
410 
411 NS_IMETHODIMP
412 sbPlayQueueExternalLibraryListener::OnItemMoved(sbIMediaList* aMediaList,
413  PRUint32 aFromIndex,
414  PRUint32 aToIndex,
415  PRBool* aNoMoreForBatch)
416 {
417  TRACE(("%s[%p]", __FUNCTION__, this));
418  if (aNoMoreForBatch) {
419  *aNoMoreForBatch = PR_TRUE;
420  }
421  return NS_OK;
422 }
return NS_OK
nsresult AddExternalLibrary(sbILibrary *aLibrary)
Add an external library to listen to.
menuItem id
Definition: FeedWriter.js:971
Class to allow items in a "master" internal library to stay in sync with duplicates in other librarie...
A brief description of the contents of this interface.
Helper class to listen to external libraries and sync properties.
Interface used to listen to changes to a media list.
#define TRACE(args)
NS_IMPL_THREADSAFE_ISUPPORTS1(sbPlayQueueExternalLibraryListener, sbIMediaListListener)
nsresult SetPropertiesNoSync(sbIMediaItem *aMediaItem, sbIPropertyArray *aProperties)
Set properties on an item, but don't synchronize to duplicates in other libraries.
bool operator==(sbPropertyUpdate rhs)
NS_DECL_ISUPPORTS NS_DECL_SBIMEDIALISTLISTENER sbPlayQueueExternalLibraryListener()
Media library abstraction.
Definition: sbILibrary.idl:82
nsresult RemoveListeners()
Removes all listeners so the libraries can shut down.
nsresult SetMasterLibrary(sbILibrary *aLibrary)
Set the master library. Items that are in this library with duplicates in external libraries...
Interface that defines a single item of media in the system.
const unsigned long LISTENER_FLAGS_ITEMUPDATED
Class to hold onto property updates to make sure we're not applying them more than once...
nsCOMPtr< sbIPropertyArray > mUpdate
nsCOMPtr< sbIMediaItem > mItem
An interface to carry around arrays of nsIProperty instances. Users of this interface should only QI ...
_getSelectedPageStyle s i