sbLocalDatabaseMediaListViewSelection.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 
27 
28 #include <sbStandardProperties.h>
29 #include <sbStringUtils.h>
30 
31 #include <nsComponentManagerUtils.h>
32 #include <nsIClassInfoImpl.h>
33 #include <nsIObjectInputStream.h>
34 #include <nsIObjectOutputStream.h>
35 #include <nsIProgrammingLanguage.h>
36 #include <nsMemory.h>
37 
38 // Uncomment this to log the selection list whenever it changes. This is
39 // normally ifdef'd out because it can be really slow
40 //#define LOG_SELECTION
41 
44 
45 #define NOTIFY_LISTENERS_INDIRECT(_obj, _method, _params) \
46  PR_BEGIN_MACRO \
47  if (!_obj->mSelectionNotificationsSuppressed) { \
48  sbObserverArray::ForwardIterator iter(_obj->mObservers); \
49  while (iter.HasMore()) { \
50  iter.GetNext()->_method _params; \
51  } \
52  } \
53  PR_END_MACRO
54 #define NOTIFY_LISTENERS(_method, _params) \
55  NOTIFY_LISTENERS_INDIRECT(this, _method, _params)
56 
57 /*
58  * To log this module, set the following environment variable:
59  * NSPR_LOG_MODULES=sbLocalDatabaseMediaListViewSelection:5
60  */
61 #ifdef PR_LOGGING
62 static PRLogModuleInfo* gLocalDatabaseMediaListViewSelectionLog = nsnull;
63 #define TRACE(args) PR_LOG(gLocalDatabaseMediaListViewSelectionLog, PR_LOG_DEBUG, args)
64 #define LOG(args) PR_LOG(gLocalDatabaseMediaListViewSelectionLog, PR_LOG_WARN, args)
65 #else
66 #define TRACE(args) /* nothing */
67 #define LOG(args) /* nothing */
68 #endif
69 
71  : mSelectionIsAll(PR_FALSE),
72  mCurrentIndex(-1),
73  mArray(nsnull),
74  mIsLibrary(PR_FALSE),
75  mLength(0),
76  mSelectionNotificationsSuppressed(PR_FALSE)
77 {
78 #ifdef PR_LOGGING
79  if (!gLocalDatabaseMediaListViewSelectionLog) {
80  gLocalDatabaseMediaListViewSelectionLog =
81  PR_NewLogModule("sbLocalDatabaseMediaListViewSelection");
82  }
83 #endif
84 }
85 
86 nsresult
88  const nsAString& aListGUID,
90  PRBool aIsLibrary,
92 {
93  NS_ASSERTION(aArray, "aArray is null");
94 
95  nsresult rv;
96 
97  mLibrary = aLibrary;
98  mListGUID = aListGUID;
99  mArray = aArray;
100  mIsLibrary = aIsLibrary;
101 
102  PRBool success = mSelection.Init();
103  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
104 
105  if (aState) {
106  mCurrentIndex = aState->mCurrentIndex;
107  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
108  NS_ENSURE_SUCCESS(rv, rv);
109  mSelectionIsAll = aState->mSelectionIsAll;
110 
111  if (!mSelectionIsAll) {
112  aState->mSelectionList.EnumerateRead(SB_CopySelectionListCallback,
113  &mSelection);
114  }
115  }
116 
117  return NS_OK;
118 }
119 
120 nsresult
122 {
123  nsresult rv = mArray->GetLength(&mLength);
124  NS_ENSURE_SUCCESS(rv, rv);
125 
126  // Get the new current index from the current unique ID.
127  if (!mCurrentUID.IsEmpty()) {
128  PRUint32 index;
129  rv = GetIndexForUniqueId(mCurrentUID, &index);
130  if (NS_SUCCEEDED(rv)) {
131  mCurrentIndex = index;
132  } else if (rv == NS_ERROR_NOT_AVAILABLE) {
133  mCurrentIndex = -1;
134  } else {
135  NS_ENSURE_SUCCESS(rv, rv);
136  }
137  } else {
138  mCurrentIndex = -1;
139  }
140 
141  return NS_OK;
142 }
143 
144 nsresult
146 {
147  NS_ENSURE_ARG_POINTER(aState);
148 
149  nsRefPtr<sbLocalDatabaseMediaListViewSelectionState> state =
151  NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
152 
153  nsresult rv = state->Init();
154  NS_ENSURE_SUCCESS(rv, rv);
155 
156  state->mCurrentIndex = mCurrentIndex;
157  state->mSelectionIsAll = mSelectionIsAll;
158 
159  if (!mSelectionIsAll) {
160  mSelection.EnumerateRead(SB_CopySelectionListCallback,
161  &state->mSelectionList);
162  }
163 
164  NS_ADDREF(*aState = state);
165  return NS_OK;
166 }
167 
168 NS_IMETHODIMP
169 sbLocalDatabaseMediaListViewSelection::GetCount(PRInt32* aCount)
170 {
171  NS_ENSURE_ARG_POINTER(aCount);
172 
173  if (mSelectionIsAll) {
174  *aCount = (PRInt32) mLength;
175  }
176  else {
177  *aCount = (PRInt32) mSelection.Count();
178  }
179 
180  return NS_OK;
181 }
182 
183 NS_IMETHODIMP
184 sbLocalDatabaseMediaListViewSelection::GetCurrentIndex(PRInt32* aCurrentIndex)
185 {
186  NS_ENSURE_ARG_POINTER(aCurrentIndex);
187  *aCurrentIndex = mCurrentIndex;
188  return NS_OK;
189 }
190 
191 NS_IMETHODIMP
192 sbLocalDatabaseMediaListViewSelection::SetCurrentIndex(PRInt32 aCurrentIndex)
193 {
194  NS_ENSURE_ARG_RANGE(aCurrentIndex, -1, (PRInt32) mLength - 1);
195  nsresult rv;
196  mCurrentIndex = aCurrentIndex;
197  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
198  NS_ENSURE_SUCCESS(rv, rv);
199  NOTIFY_LISTENERS(OnCurrentIndexChanged, ());
200  return NS_OK;
201 }
202 
203 NS_IMETHODIMP
204 sbLocalDatabaseMediaListViewSelection::GetCurrentMediaItem(sbIMediaItem** aCurrentMediaItem)
205 {
206  NS_ENSURE_ARG_POINTER(aCurrentMediaItem);
207  nsresult rv;
208 
209  if (mCurrentIndex >= 0) {
210  nsString guid;
211  rv = mArray->GetGuidByIndex(mCurrentIndex, guid);
212  NS_ENSURE_SUCCESS(rv, rv);
213 
214  rv = mLibrary->GetMediaItem(guid, aCurrentMediaItem);
215  NS_ENSURE_SUCCESS(rv, rv);
216  }
217  else {
218  *aCurrentMediaItem = nsnull;
219  }
220 
221  return NS_OK;
222 }
223 
224 NS_IMETHODIMP
225 sbLocalDatabaseMediaListViewSelection::IsIndexSelected(PRInt32 aIndex,
226  PRBool* _retval)
227 {
228  NS_ENSURE_ARG_POINTER(_retval);
229  nsresult rv;
230 
231  // An invalid row is always not selected
232  if (aIndex < 0 || aIndex > (PRInt32) mLength - 1) {
233  *_retval = PR_FALSE;
234  return NS_OK;
235  }
236 
237  if (mSelectionIsAll) {
238  *_retval = PR_TRUE;
239  return NS_OK;
240  }
241 
242  nsString uid;
243  rv = GetUniqueIdForIndex((PRUint32) aIndex, uid);
244  NS_ENSURE_SUCCESS(rv, rv);
245 
246  *_retval = mSelection.Get(uid, nsnull);
247 
248  return NS_OK;
249 }
250 
251 static nsresult IsContentTypeEqual(nsAString &aGuid,
252  sbILibrary* aLibrary,
253  const nsAString &aContentType,
254  PRBool* aIsSame)
255 {
256  NS_ENSURE_ARG_POINTER(aLibrary);
257  NS_ENSURE_ARG_POINTER(aIsSame);
258  nsresult rv;
259 
260  nsCOMPtr<sbIMediaItem> item;
261  rv = aLibrary->GetItemByGuid(aGuid, getter_AddRefs(item));
262  NS_ENSURE_SUCCESS(rv, rv);
263 
264  nsString contentType;
265  rv = item->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTTYPE),
266  contentType);
267  NS_ENSURE_SUCCESS(rv, rv);
268 
269  *aIsSame = aContentType.Equals(contentType);
270  return NS_OK;
271 }
272 
273 
274 NS_IMETHODIMP
275 sbLocalDatabaseMediaListViewSelection::IsContentTypeSelected(
276  const nsAString &aContentType,
277  PRBool* _retval)
278 {
279  NS_ENSURE_ARG_POINTER(_retval);
280  nsresult rv;
281 
282  // If everything is selected, check our array
283  if (mSelectionIsAll) {
284  for (PRUint32 i = 0; i < mLength; i++) {
285  nsAutoString guid;
286  rv = mArray->GetGuidByIndex(i, guid);
287  NS_ENSURE_SUCCESS(rv, rv);
288 
289  PRBool isSame;
290  rv = IsContentTypeEqual(guid, mLibrary, aContentType, &isSame);
291  NS_ENSURE_SUCCESS(rv, rv);
292 
293  if (isSame) {
294  *_retval = PR_TRUE;
295  return NS_OK;
296  }
297  }
298  }
299  else {
300  PRUint32 selectionCount = mSelection.Count();
301 
302  PRUint32 found = 0;
303  for (PRUint32 i = 0; i < mLength && found < selectionCount; i++) {
304  PRBool isIndexCached;
305  rv = mArray->IsIndexCached(i, &isIndexCached);
306  NS_ENSURE_SUCCESS(rv, rv);
307 
308  if (isIndexCached) {
309  nsString uid;
310  rv = GetUniqueIdForIndex(i, uid);
311  NS_ENSURE_SUCCESS(rv, rv);
312 
313  nsString guid;
314  if (mSelection.Get(uid, &guid)) {
315  PRBool isSame;
316  rv = IsContentTypeEqual(guid, mLibrary, aContentType, &isSame);
317  NS_ENSURE_SUCCESS(rv, rv);
318 
319  if (isSame) {
320  *_retval = PR_TRUE;
321  return NS_OK;
322  }
323 
324  found++;
325  }
326  }
327  }
328 
329  // If we searched everything and no match, return
330  if (found == selectionCount) {
331  *_retval = PR_FALSE;
332  return NS_OK;
333  }
334 
335  // If we didn't find everything in the first pass of cached indexes,
336  // do it again ignoring the cache (will cause database queries)
337  for (PRUint32 i = 0; i < mLength; i++) {
338  nsString uid;
339  rv = GetUniqueIdForIndex(i, uid);
340  NS_ENSURE_SUCCESS(rv, rv);
341 
342  nsString guid;
343  if (mSelection.Get(uid, &guid)) {
344  PRBool isSame;
345  rv = IsContentTypeEqual(guid, mLibrary, aContentType, &isSame);
346  NS_ENSURE_SUCCESS(rv, rv);
347 
348  if (isSame) {
349  *_retval = PR_TRUE;
350  return NS_OK;
351  }
352  }
353  }
354  }
355 
356  *_retval = PR_FALSE;
357  return NS_OK;
358 }
359 
360 NS_IMETHODIMP
361 sbLocalDatabaseMediaListViewSelection::GetSelectedIndexedMediaItems(nsISimpleEnumerator** aSelectedMediaItems)
362 {
363  NS_ENSURE_ARG_POINTER(aSelectedMediaItems);
364  nsresult rv;
365 
366  // If everything is selected, simply return an enumerator over our array
367  if (mSelectionIsAll) {
368  *aSelectedMediaItems = new sbIndexedGUIDArrayEnumerator(mLibrary, mArray);
369  NS_ENSURE_TRUE(*aSelectedMediaItems, NS_ERROR_OUT_OF_MEMORY);
370 
371  NS_ADDREF(*aSelectedMediaItems);
372  return NS_OK;
373  }
374 
375  // There is no way to determine the index of the items in the selection
376  // list, so first walk through the cached indexes of the array and locate
377  // the selected items
378  nsRefPtr<sbGUIDArrayToIndexedMediaItemEnumerator>
379  enumerator(new sbGUIDArrayToIndexedMediaItemEnumerator(mLibrary));
380  NS_ENSURE_TRUE(enumerator, NS_ERROR_OUT_OF_MEMORY);
381 
382  PRUint32 selectionCount = mSelection.Count();
383 
384  PRUint32 found = 0;
385  for (PRUint32 i = 0; i < mLength && found < selectionCount; i++) {
386  PRBool isIndexCached;
387  rv = mArray->IsIndexCached(i, &isIndexCached);
388  NS_ENSURE_SUCCESS(rv, rv);
389 
390  if (isIndexCached) {
391  nsString uid;
392  rv = GetUniqueIdForIndex(i, uid);
393  NS_ENSURE_SUCCESS(rv, rv);
394 
395  nsString guid;
396  if (mSelection.Get(uid, &guid)) {
397  rv = enumerator->AddGuid(guid, i);
398  NS_ENSURE_SUCCESS(rv, rv);
399  found++;
400  }
401  }
402  }
403 
404  // If we found everything, return
405  if (found == selectionCount) {
406  NS_ADDREF(*aSelectedMediaItems = enumerator);
407  return NS_OK;
408  }
409 
410  // If we didn't find everything in the first pass of cached indexes,
411  // do it again ignoring the cache (will cause database queries)
412  enumerator = new sbGUIDArrayToIndexedMediaItemEnumerator(mLibrary);
413  NS_ENSURE_TRUE(enumerator, NS_ERROR_OUT_OF_MEMORY);
414 
415  for (PRUint32 i = 0; i < mLength; i++) {
416  nsString uid;
417  rv = GetUniqueIdForIndex(i, uid);
418  NS_ENSURE_SUCCESS(rv, rv);
419 
420  nsString guid;
421  if (mSelection.Get(uid, &guid)) {
422  rv = enumerator->AddGuid(guid, i);
423  NS_ENSURE_SUCCESS(rv, rv);
424  }
425  }
426 
427  NS_ADDREF(*aSelectedMediaItems = enumerator);
428  return NS_OK;
429 }
430 
431 NS_IMETHODIMP
432 sbLocalDatabaseMediaListViewSelection::GetSelectedMediaItems(nsISimpleEnumerator * *aSelectedMediaItems)
433 {
434  NS_ENSURE_ARG_POINTER(aSelectedMediaItems);
435  nsresult rv;
436 
437  // just create an indexed enumerator and wrap it; this makes sure we reuse
438  // the code and the two enumerator implementations are kept in sync.
439  nsCOMPtr<nsISimpleEnumerator> indexedEnumerator;
440  rv = GetSelectedIndexedMediaItems(getter_AddRefs(indexedEnumerator));
441  NS_ENSURE_SUCCESS(rv, rv);
442 
443  nsRefPtr<sbIndexedToUnindexedMediaItemEnumerator> unwrapper =
444  new sbIndexedToUnindexedMediaItemEnumerator(indexedEnumerator);
445  NS_ENSURE_TRUE(unwrapper, NS_ERROR_OUT_OF_MEMORY);
446 
447  return CallQueryInterface(unwrapper.get(), aSelectedMediaItems);
448 }
449 
450 NS_IMETHODIMP
452 {
453  NS_ENSURE_ARG_RANGE(aIndex, 0, (PRInt32) mLength - 1);
454  nsresult rv;
455 
456  mCurrentIndex = aIndex;
457  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
458  NS_ENSURE_SUCCESS(rv, rv);
459 
460  rv = AddToSelection(aIndex);
461  NS_ENSURE_SUCCESS(rv, rv);
462 
463  CheckSelectAll();
464 
465  NOTIFY_LISTENERS(OnSelectionChanged, ());
466 
467 #ifdef DEBUG
468  LogSelection();
469 #endif
470 
471  return NS_OK;
472 }
473 
474 NS_IMETHODIMP
475 sbLocalDatabaseMediaListViewSelection::SelectOnly(PRInt32 aIndex)
476 {
477  NS_ENSURE_ARG_RANGE(aIndex, 0, (PRInt32) mLength - 1);
478  nsresult rv;
479 
480  mCurrentIndex = aIndex;
481  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
482  NS_ENSURE_SUCCESS(rv, rv);
483 
484  mSelection.Clear();
485  mSelectionIsAll = PR_FALSE;
486 
487  rv = AddToSelection(aIndex);
488  NS_ENSURE_SUCCESS(rv, rv);
489 
490  CheckSelectAll();
491 
492  NOTIFY_LISTENERS(OnSelectionChanged, ());
493 
494 #ifdef DEBUG
495  LogSelection();
496 #endif
497 
498  return NS_OK;
499 }
500 
501 NS_IMETHODIMP
502 sbLocalDatabaseMediaListViewSelection::TimedSelectOnly(PRInt32 aIndex, PRInt32 aDelay)
503 {
504  PRBool suppressed = mSelectionNotificationsSuppressed;
505  if (aDelay != -1)
506  mSelectionNotificationsSuppressed = PR_TRUE;
507  nsresult rv = SelectOnly(aIndex);
508  mSelectionNotificationsSuppressed = suppressed;
509  NS_ENSURE_SUCCESS(rv, rv);
510 
511  if (aDelay != -1 && !mSelectionNotificationsSuppressed) {
512  if (mSelectTimer)
513  mSelectTimer->Cancel();
514 
515  mSelectTimer = do_CreateInstance("@mozilla.org/timer;1");
516  mSelectTimer->InitWithFuncCallback(DelayedSelectNotification, this, aDelay,
517  nsITimer::TYPE_ONE_SHOT);
518  }
519 
520  return NS_OK;
521 }
522 
523 void
524 sbLocalDatabaseMediaListViewSelection::DelayedSelectNotification(nsITimer* aTimer, void* aClosure)
525 {
526  nsRefPtr<sbLocalDatabaseMediaListViewSelection> self =
528  if (self) {
529  NOTIFY_LISTENERS_INDIRECT(self, OnSelectionChanged, ());
530  aTimer->Cancel();
531  self->mSelectTimer = nsnull;
532  }
533 }
534 
535 NS_IMETHODIMP
536 sbLocalDatabaseMediaListViewSelection::Toggle(PRInt32 aIndex)
537 {
538  NS_ENSURE_ARG_RANGE((PRInt32) aIndex, 0, (PRInt32) mLength - 1);
539  nsresult rv;
540 
541  mCurrentIndex = aIndex;
542  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
543  NS_ENSURE_SUCCESS(rv, rv);
544 
545  // If have an all selection, fill the selection with everything but the
546  // toggled index
547  if (mSelectionIsAll) {
548  mSelectionIsAll = PR_FALSE;
549  for (PRUint32 i = 0; i < mLength; i++) {
550  if (i != (PRUint32) aIndex) {
551  rv = AddToSelection(i);
552  NS_ENSURE_SUCCESS(rv, rv);
553  }
554  }
555  return NS_OK;
556  }
557 
558  // Otherwise, simply do the toggle
559  PRBool isSelected;
560  rv = IsIndexSelected(aIndex, &isSelected);
561  NS_ENSURE_SUCCESS(rv, rv);
562 
563  if (isSelected) {
564  rv = RemoveFromSelection(aIndex);
565  NS_ENSURE_SUCCESS(rv, rv);
566  }
567  else {
568  rv = AddToSelection(aIndex);
569  NS_ENSURE_SUCCESS(rv, rv);
570  }
571 
572  CheckSelectAll();
573 
574  NOTIFY_LISTENERS(OnSelectionChanged, ());
575 
576 #ifdef DEBUG
577  LogSelection();
578 #endif
579 
580  return NS_OK;
581 }
582 
583 NS_IMETHODIMP
584 sbLocalDatabaseMediaListViewSelection::Clear(PRInt32 aIndex)
585 {
586  NS_ENSURE_ARG_RANGE(aIndex, 0, (PRInt32) mLength - 1);
587 
588  nsresult rv;
589 
590  mCurrentIndex = aIndex;
591  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
592  NS_ENSURE_SUCCESS(rv, rv);
593 
594  // If have an all selection, fill the selection with everything but the
595  // range we're clearing
596  if (mSelectionIsAll) {
597  mSelectionIsAll = PR_FALSE;
598  for (PRUint32 i = 0; i < mLength; i++) {
599  if (i != (PRUint32) aIndex) {
600  rv = AddToSelection(i);
601  NS_ENSURE_SUCCESS(rv, rv);
602  }
603  }
604 
605  NOTIFY_LISTENERS(OnSelectionChanged, ());
606 
607  return NS_OK;
608  }
609 
610  rv = RemoveFromSelection((PRUint32) aIndex);
611  NS_ENSURE_SUCCESS(rv, rv);
612 
613  NOTIFY_LISTENERS(OnSelectionChanged, ());
614 
615 #ifdef DEBUG
616  LogSelection();
617 #endif
618 
619  return NS_OK;
620 }
621 
622 
623 NS_IMETHODIMP
624 sbLocalDatabaseMediaListViewSelection::SelectRange(PRInt32 aStartIndex,
625  PRInt32 aEndIndex)
626 {
627  TRACE(("sbLocalDatabaseMediaListViewSelection[0x%.8x] - SelectRange(%d, %d)",
628  this, aStartIndex, aEndIndex));
629 
630  NS_ENSURE_ARG_RANGE(aStartIndex, 0, (PRInt32) mLength - 1);
631  NS_ENSURE_ARG_RANGE(aEndIndex, 0, (PRInt32) mLength - 1);
632 
633  nsresult rv;
634 
635  if (mSelectionIsAll) {
636  return NS_OK;
637  }
638 
639  mCurrentIndex = aEndIndex;
640  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
641  NS_ENSURE_SUCCESS(rv, rv);
642 
643  PRInt32 start = PR_MIN(aStartIndex, aEndIndex);
644  PRInt32 end = PR_MAX(aStartIndex, aEndIndex);
645 
646  for (PRInt32 i = start; i <= end; i++) {
647  rv = AddToSelection((PRUint32) i);
648  NS_ENSURE_SUCCESS(rv, rv);
649  }
650 
651  CheckSelectAll();
652 
653  NOTIFY_LISTENERS(OnSelectionChanged, ());
654 
655 #ifdef DEBUG
656  LogSelection();
657 #endif
658 
659  return NS_OK;
660 }
661 
662 NS_IMETHODIMP
663 sbLocalDatabaseMediaListViewSelection::ClearRange(PRInt32 aStartIndex,
664  PRInt32 aEndIndex)
665 {
666  NS_ENSURE_ARG_RANGE(aStartIndex, 0, (PRInt32) mLength - 1);
667  NS_ENSURE_ARG_RANGE(aEndIndex, 0, (PRInt32) mLength - 1);
668 
669  nsresult rv;
670 
671  mCurrentIndex = aEndIndex;
672  rv = GetUniqueIdForIndex(mCurrentIndex, mCurrentUID);
673  NS_ENSURE_SUCCESS(rv, rv);
674 
675  // If have an all selection, fill the selection with everything but the
676  // range we're clearing
677  if (mSelectionIsAll) {
678  mSelectionIsAll = PR_FALSE;
679  for (PRUint32 i = 0; i < mLength; i++) {
680  if (i < (PRUint32) aStartIndex || i > (PRUint32) aEndIndex) {
681  rv = AddToSelection(i);
682  NS_ENSURE_SUCCESS(rv, rv);
683  }
684  }
685 
686  NOTIFY_LISTENERS(OnSelectionChanged, ());
687 
688  return NS_OK;
689  }
690 
691  for (PRInt32 i = aStartIndex; i <= aEndIndex; i++) {
692  rv = RemoveFromSelection((PRUint32) i);
693  NS_ENSURE_SUCCESS(rv, rv);
694  }
695 
696  NOTIFY_LISTENERS(OnSelectionChanged, ());
697 
698 #ifdef DEBUG
699  LogSelection();
700 #endif
701 
702  return NS_OK;
703 }
704 
705 NS_IMETHODIMP
706 sbLocalDatabaseMediaListViewSelection::SelectNone()
707 {
708  mSelection.Clear();
709  mSelectionIsAll = PR_FALSE;
710  mCurrentIndex = -1;
711  mCurrentUID.Truncate();
712 
713  NOTIFY_LISTENERS(OnSelectionChanged, ());
714 
715 #ifdef DEBUG
716  LogSelection();
717 #endif
718 
719  return NS_OK;
720 }
721 
722 NS_IMETHODIMP
723 sbLocalDatabaseMediaListViewSelection::SelectAll()
724 {
725  mSelection.Clear();
726  mSelectionIsAll = PR_TRUE;
727 
728  NOTIFY_LISTENERS(OnSelectionChanged, ());
729 
730 #ifdef DEBUG
731  LogSelection();
732 #endif
733 
734  return NS_OK;
735 }
736 
737 NS_IMETHODIMP
738 sbLocalDatabaseMediaListViewSelection::AddListener(sbIMediaListViewSelectionListener* aListener)
739 {
740  NS_ENSURE_ARG_POINTER(aListener);
741 
742  PRBool success = mObservers.AppendElementUnlessExists(aListener);
743  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
744  return NS_OK;
745 }
746 
747 NS_IMETHODIMP
748 sbLocalDatabaseMediaListViewSelection::RemoveListener(sbIMediaListViewSelectionListener* aListener)
749 {
750  NS_ENSURE_ARG_POINTER(aListener);
751  mObservers.RemoveElement(aListener);
752  return NS_OK;
753 }
754 
755 NS_IMETHODIMP
756 sbLocalDatabaseMediaListViewSelection::SetSelectionNotificationsSuppressed(PRBool aSelectionEventsSuppressed)
757 {
758  mSelectionNotificationsSuppressed = aSelectionEventsSuppressed;
759 
760  // If this is being set to false, notify
761  if (!mSelectionNotificationsSuppressed) {
762  NOTIFY_LISTENERS(OnSelectionChanged, ());
763  }
764 
765  return NS_OK;
766 }
767 
768 NS_IMETHODIMP
769 sbLocalDatabaseMediaListViewSelection::GetSelectionNotificationsSuppressed(PRBool *aSelectionEventsSuppressed)
770 {
771  NS_ENSURE_ARG_POINTER(aSelectionEventsSuppressed);
772  *aSelectionEventsSuppressed = mSelectionNotificationsSuppressed;
773  return NS_OK;
774 }
775 
776 nsresult
777 sbLocalDatabaseMediaListViewSelection::AddToSelection(PRUint32 aIndex)
778 {
779  nsresult rv;
780 
781  nsString uid;
782  rv = GetUniqueIdForIndex(aIndex, uid);
783  NS_ENSURE_SUCCESS(rv, rv);
784 
785  if (mSelection.Get(uid, nsnull)) {
786  return NS_OK;
787  }
788 
789  nsString guid;
790  rv = mArray->GetGuidByIndex(aIndex, guid);
791  NS_ENSURE_SUCCESS(rv, rv);
792 
793  PRBool success = mSelection.Put(uid, guid);
794  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
795 
796  return NS_OK;
797 }
798 
799 nsresult
800 sbLocalDatabaseMediaListViewSelection::RemoveFromSelection(PRUint32 aIndex)
801 {
802  nsresult rv;
803 
804  nsString uid;
805  rv = GetUniqueIdForIndex(aIndex, uid);
806  NS_ENSURE_SUCCESS(rv, rv);
807 
808  mSelection.Remove(uid);
809 
810  return NS_OK;
811 }
812 
813 nsresult
814 sbLocalDatabaseMediaListViewSelection::GetUniqueIdForIndex(PRUint32 aIndex,
815  nsAString& aId)
816 {
817  nsresult rv;
818 
819  /* For regular lists, the unique identifer is composed of the lists' guid
820  * appended to the item's guid and viewItemUID (rowid-mediaitemid)
821  * Thus the UniqueId is of the form:
822  * "listGUID|itemGUID|rowid-mediaitemid" */
823  aId.Assign(mListGUID);
824  aId.Append('|');
825 
826  nsString guid;
827  rv = mArray->GetGuidByIndex(aIndex, guid);
828  NS_ENSURE_SUCCESS(rv, rv);
829  aId.Append(guid);
830  aId.Append('|');
831 
832  // get the viewItemUID which is "rowid-mediaitemid" and append to the UniqueId
833  nsString viewItemUID;
834  rv = mArray->GetViewItemUIDByIndex(aIndex, viewItemUID);
835  NS_ENSURE_SUCCESS(rv, rv);
836  aId.Append(viewItemUID);
837 
838  return NS_OK;
839 }
840 
841 nsresult
842 sbLocalDatabaseMediaListViewSelection::GetUniqueIdForIndex(PRInt32 aIndex,
843  nsAString& aId)
844 {
845  if (aIndex < 0) {
846  aId.Truncate();
847  return NS_OK;
848  }
849  return GetUniqueIdForIndex(static_cast<PRUint32>(aIndex), aId);
850 }
851 
852 nsresult
853 sbLocalDatabaseMediaListViewSelection::GetIndexForUniqueId
854  (const nsAString& aId,
855  PRUint32* aIndex)
856 {
857  nsresult rv;
858 
859  // Split the unique ID into its components.
860  nsTArray<nsString> idComponentList;
861  nsString_Split(aId, NS_LITERAL_STRING("|"), idComponentList);
862  if (idComponentList.Length() < 3)
863  return NS_ERROR_NOT_AVAILABLE;
864 
865  /* use the unique id to get the viewItemUID which can help us get
866  * the index of the item */
867  nsString viewItemUID = idComponentList[2];
868 
869  // Get the index from the rowid and mediaitemid.
870  rv = mArray->GetIndexByViewItemUID(viewItemUID, aIndex);
871  if (rv == NS_ERROR_NOT_AVAILABLE)
872  return NS_ERROR_NOT_AVAILABLE;
873  NS_ENSURE_SUCCESS(rv, rv);
874 
875  return NS_OK;
876 }
877 
878 #ifdef DEBUG
879 void
880 sbLocalDatabaseMediaListViewSelection::LogSelection()
881 {
882 #ifdef LOG_SELECTION
883  nsString list;
884 
885  if (mSelectionIsAll) {
886  list.AssignLiteral("all");
887  }
888  else {
889  PRUint32 oldFetchSize;
890  nsresult rv = mArray->GetFetchSize(&oldFetchSize);
891  NS_ENSURE_SUCCESS(rv, /* void */);
892 
893  rv = mArray->SetFetchSize(0);
894  NS_ENSURE_SUCCESS(rv, /* void */);
895 
896  for (PRUint32 i = 0; i < mLength; i++) {
897  nsString uid;
898  GetUniqueIdForIndex(i, uid);
899 
900  nsString guid;
901  if (mSelection.Get(uid, nsnull)) {
902  list.AppendInt(i);
903  list.Append(' ');
904  }
905  }
906 
907  rv = mArray->SetFetchSize(oldFetchSize);
908  NS_ENSURE_SUCCESS(rv, /* void */);
909  }
910 
911  TRACE(("sbLocalDatabaseMediaListViewSelection[0x%.8x] - LogSelection() "
912  "length: %d, selection: %s",
913  this, mLength, NS_LossyConvertUTF16toASCII(list).get()));
914 #endif
915 }
916 #endif
917 
920 
922  mCurrentIndex(-1),
923  mSelectionIsAll(PR_FALSE)
924 {
925 }
926 
927 NS_IMETHODIMP
928 sbLocalDatabaseMediaListViewSelectionState::Read(nsIObjectInputStream* aStream)
929 {
930  NS_ENSURE_ARG_POINTER(aStream);
931 
932  nsresult rv;
933 
934  rv = aStream->Read32((PRUint32*) &mCurrentIndex);
935  NS_ENSURE_SUCCESS(rv, rv);
936 
937  PRUint32 selectionCount;
938  rv = aStream->Read32(&selectionCount);
939  NS_ENSURE_SUCCESS(rv, rv);
940 
941  for (PRUint32 i = 0; i < selectionCount; i++) {
942  nsString key;
943  nsString entry;
944 
945  rv = aStream->ReadString(key);
946  NS_ENSURE_SUCCESS(rv, rv);
947 
948  rv = aStream->ReadString(entry);
949  NS_ENSURE_SUCCESS(rv, rv);
950 
951  PRBool success = mSelectionList.Put(key, entry);
952  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
953  }
954 
955  PRBool selectionIsAll;
956  rv = aStream->ReadBoolean(&selectionIsAll);
957  NS_ENSURE_SUCCESS(rv, rv);
958  mSelectionIsAll = selectionIsAll;
959 
960  return NS_OK;
961 }
962 
963 NS_IMETHODIMP
964 sbLocalDatabaseMediaListViewSelectionState::Write(nsIObjectOutputStream* aStream)
965 {
966  NS_ENSURE_ARG_POINTER(aStream);
967 
968  nsresult rv;
969 
970  rv = aStream->Write32((PRUint32) mCurrentIndex);
971  NS_ENSURE_SUCCESS(rv, rv);
972 
973  rv = aStream->Write32(mSelectionList.Count());
974  NS_ENSURE_SUCCESS(rv, rv);
975 
976  mSelectionList.EnumerateRead(SB_SerializeSelectionListCallback, aStream);
977 
978  rv = aStream->WriteBoolean(mSelectionIsAll);
979  NS_ENSURE_SUCCESS(rv, rv);
980 
981  return NS_OK;
982 }
983 
984 nsresult
986 {
987  PRBool success = mSelectionList.Init();
988  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
989 
990  return NS_OK;
991 }
992 
993 nsresult
995 {
996  nsString buff;
997 
998  buff.AppendLiteral(" currentIndex ");
999  buff.AppendInt(mCurrentIndex);
1000 
1001  buff.AppendLiteral(" selection ");
1002  if (mSelectionIsAll) {
1003  buff.AppendLiteral("is all");
1004  }
1005  else {
1006  buff.AppendInt(mSelectionList.Count());
1007  buff.AppendLiteral(" items");
1008  }
1009 
1010  aStr = buff;
1011 
1012  return NS_OK;
1013 }
1014 
1015 
1018  nsIClassInfo)
1021  nsIClassInfo)
1022 
1023 NS_DECL_CLASSINFO(sbGUIDArrayToIndexedMediaItemEnumerator)
1024 NS_IMPL_THREADSAFE_CI(sbGUIDArrayToIndexedMediaItemEnumerator)
1025 
1032 sbGUIDArrayToIndexedMediaItemEnumerator::sbGUIDArrayToIndexedMediaItemEnumerator(sbILibrary* aLibrary) :
1033  mInitalized(PR_FALSE),
1034  mLibrary(aLibrary),
1035  mNextIndex(0),
1036  mNextItemIndex(0)
1037 {
1038 }
1039 
1040 nsresult
1042  PRUint32 aIndex)
1043 {
1044  Item* item = mItems.AppendElement();
1045  NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
1046 
1047  item->index = aIndex;
1048  item->guid = aGuid;
1049 
1050  return NS_OK;
1051 }
1052 
1053 nsresult
1054 sbGUIDArrayToIndexedMediaItemEnumerator::GetNextItem()
1055 {
1056  if (!mInitalized) {
1057  mInitalized = PR_TRUE;
1058  }
1059 
1060  mNextItem = nsnull;
1061  PRUint32 length = mItems.Length();
1062 
1063  while (mNextIndex < length) {
1064  nsresult rv = mLibrary->GetMediaItem(mItems[mNextIndex].guid,
1065  getter_AddRefs(mNextItem));
1066  mNextItemIndex = mItems[mNextIndex].index;
1067  mNextIndex++;
1068  if (NS_SUCCEEDED(rv)) {
1069  return NS_OK;
1070  }
1071  }
1072 
1073  return NS_ERROR_NOT_AVAILABLE;
1074 }
1075 
1076 NS_IMETHODIMP
1077 sbGUIDArrayToIndexedMediaItemEnumerator::HasMoreElements(PRBool *_retval)
1078 {
1079  if (!mInitalized) {
1080  GetNextItem();
1081  }
1082 
1083  *_retval = mNextItem != nsnull;
1084 
1085  return NS_OK;
1086 }
1087 
1088 NS_IMETHODIMP
1089 sbGUIDArrayToIndexedMediaItemEnumerator::GetNext(nsISupports **_retval)
1090 {
1091  if (!mInitalized) {
1092  GetNextItem();
1093  }
1094 
1095  if (!mNextItem) {
1096  return NS_ERROR_FAILURE;
1097  }
1098 
1099  nsRefPtr<sbLocalDatabaseIndexedMediaItem> indexedItem
1100  (new sbLocalDatabaseIndexedMediaItem(mNextItemIndex, mNextItem));
1101  NS_ENSURE_TRUE(indexedItem, NS_ERROR_OUT_OF_MEMORY);
1102 
1103  NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(sbIIndexedMediaItem*,
1104  indexedItem.get()));
1105 
1106  GetNextItem();
1107 
1108  return NS_OK;
1109 }
1110 
1113  nsIClassInfo)
1116  nsIClassInfo)
1117 
1118 NS_DECL_CLASSINFO(sbIndexedGUIDArrayEnumerator)
1119 NS_IMPL_THREADSAFE_CI(sbIndexedGUIDArrayEnumerator)
1120 
1121 sbIndexedGUIDArrayEnumerator::sbIndexedGUIDArrayEnumerator(sbILibrary* aLibrary,
1122  sbILocalDatabaseGUIDArray* aArray) :
1123  mLibrary(aLibrary),
1124  mArray(aArray),
1125  mNextIndex(0),
1126  mInitalized(PR_FALSE)
1127 {
1128  NS_ASSERTION(aLibrary, "aLibrary is null");
1129  NS_ASSERTION(aArray, "aArray is null");
1130 }
1131 
1132 nsresult
1133 sbIndexedGUIDArrayEnumerator::Init()
1134 {
1135  PRUint32 length;
1136  nsresult rv = mArray->GetLength(&length);
1137  NS_ENSURE_SUCCESS(rv, rv);
1138 
1139  for (PRUint32 i = 0; i < length; i++) {
1140  nsAutoString guid;
1141  rv = mArray->GetGuidByIndex(i, guid);
1142  NS_ENSURE_SUCCESS(rv, rv);
1143 
1144  nsString* added = mGUIDArray.AppendElement(guid);
1145  NS_ENSURE_TRUE(added, NS_ERROR_OUT_OF_MEMORY);
1146  }
1147 
1148  mInitalized = PR_TRUE;
1149 
1150  return NS_OK;
1151 }
1152 
1153 NS_IMETHODIMP
1154 sbIndexedGUIDArrayEnumerator::HasMoreElements(PRBool *_retval)
1155 {
1156  if (!mInitalized) {
1157  nsresult rv = Init();
1158  NS_ENSURE_SUCCESS(rv, rv);
1159  }
1160 
1161  *_retval = mNextIndex < mGUIDArray.Length();
1162  return NS_OK;
1163 }
1164 
1165 NS_IMETHODIMP
1166 sbIndexedGUIDArrayEnumerator::GetNext(nsISupports **_retval)
1167 {
1168  nsresult rv;
1169 
1170  if (!mInitalized) {
1171  rv = Init();
1172  NS_ENSURE_SUCCESS(rv, rv);
1173  }
1174 
1175  if (!(mNextIndex < mGUIDArray.Length())) {
1176  return NS_ERROR_FAILURE;
1177  }
1178 
1179  nsCOMPtr<sbIMediaItem> item;
1180  rv = mLibrary->GetMediaItem(mGUIDArray[mNextIndex], getter_AddRefs(item));
1181  NS_ENSURE_SUCCESS(rv, rv);
1182 
1183  nsRefPtr<sbLocalDatabaseIndexedMediaItem> indexedItem
1184  (new sbLocalDatabaseIndexedMediaItem(mNextIndex, item));
1185  NS_ENSURE_TRUE(indexedItem, NS_ERROR_OUT_OF_MEMORY);
1186 
1187  NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(sbIIndexedMediaItem*,
1188  indexedItem.get()));
1189 
1190  mNextIndex++;
1191  return NS_OK;
1192 }
1193 
1196  nsIClassInfo)
1199  nsIClassInfo)
1200 
1201 NS_DECL_CLASSINFO(sbIndexedToUnindexedMediaItemEnumerator)
1202 NS_IMPL_THREADSAFE_CI(sbIndexedToUnindexedMediaItemEnumerator)
1203 
1210 sbIndexedToUnindexedMediaItemEnumerator::sbIndexedToUnindexedMediaItemEnumerator(nsISimpleEnumerator* aEnumerator) :
1211  mIndexedEnumerator(aEnumerator)
1212 {
1213 }
1214 
1215 NS_IMETHODIMP
1216 sbIndexedToUnindexedMediaItemEnumerator::HasMoreElements(PRBool *_retval)
1217 {
1218  NS_ENSURE_TRUE(mIndexedEnumerator, NS_ERROR_NOT_INITIALIZED);
1219  return mIndexedEnumerator->HasMoreElements(_retval);
1220 }
1221 
1222 NS_IMETHODIMP
1223 sbIndexedToUnindexedMediaItemEnumerator::GetNext(nsISupports **_retval)
1224 {
1225  NS_ENSURE_ARG_POINTER(_retval);
1226  NS_ENSURE_TRUE(mIndexedEnumerator, NS_ERROR_NOT_INITIALIZED);
1227 
1228  nsresult rv;
1229 
1230  nsCOMPtr<sbIIndexedMediaItem> indexedItem;
1231  rv = mIndexedEnumerator->GetNext(getter_AddRefs(indexedItem));
1232  NS_ENSURE_SUCCESS(rv, rv);
1233 
1234  nsCOMPtr<sbIMediaItem> item;
1235  rv = indexedItem->GetMediaItem(getter_AddRefs(item));
1236  NS_ENSURE_SUCCESS(rv, rv);
1237 
1238  return CallQueryInterface(item, _retval);
1239 }
function start(ch)
classDescription entry
Definition: FeedWriter.js:1427
nsresult GetState(sbLocalDatabaseMediaListViewSelectionState **aState)
return NS_OK
Manage the selection of items within a view. This interface is a subset of nsITreeViewSelection. Note that if you are part of the user interface, you probably want to be calling nsITreeView.selection instead - otherwise things can get subtly out of sync.
NS_DECL_ISUPPORTS NS_DECL_NSISERIALIZABLE nsresult Init()
saveStateDelayed aDelay
[USER CODE SHOULD NOT REFERENCE THIS CLASS]
NS_IMPL_THREADSAFE_CI(sbMediaListEnumeratorWrapper)
NS_DECL_ISUPPORTS NS_DECL_SBIMEDIALISTVIEWSELECTION sbLocalDatabaseMediaListViewSelection()
nsresult Init(sbILibrary *aLibrary, const nsAString &aListGUID, sbILocalDatabaseGUIDArray *aArray, PRBool aIsLibrary, sbLocalDatabaseMediaListViewSelectionState *aState)
#define TRACE(args)
static nsresult IsContentTypeEqual(nsAString &aGuid, sbILibrary *aLibrary, const nsAString &aContentType, PRBool *aIsSame)
An unwrapper for sbGUIDArrayToIndexedMediaItemEnumerator to return unwrapped sbIMediaItems with no in...
#define SB_PROPERTY_CONTENTTYPE
NS_IMPL_ISUPPORTS1(sbLocalDatabaseMediaListViewSelection, sbIMediaListViewSelection) sbLocalDatabaseMediaListViewSelection
void nsString_Split(const nsAString &aString, const nsAString &aDelimiter, nsTArray< nsString > &aSubStringArray)
NS_IMPL_THREADSAFE_ISUPPORTS2(sbGUIDArrayToIndexedMediaItemEnumerator, nsISimpleEnumerator, nsIClassInfo) NS_IMPL_CI_INTERFACE_GETTER2(sbGUIDArrayToIndexedMediaItemEnumerator
void * aClosure
Definition: sbArray.cpp:52
nsISerializable
A container for a media item and its index.
Media library abstraction.
Definition: sbILibrary.idl:82
nsresult AddGuid(const nsAString &aGuid, PRUint32 aIndex)
PLDHashOperator PR_CALLBACK SB_CopySelectionListCallback(nsStringHashKey::KeyType aKey, nsString aEntry, void *aUserData)
#define NOTIFY_LISTENERS(_method, _params)
Listener interface that gets notified on selection changes.
sbIJobCancelable NS_DECL_CLASSINFO(sbGstreamerMediaInspector)
#define NOTIFY_LISTENERS_INDIRECT(_obj, _method, _params)
Interface that defines a single item of media in the system.
restoreHistoryPrecursor aCount
NS_IMPL_CI_INTERFACE_GETTER2(sbDataRemoteWrapper, sbIDataRemote, nsIClassInfo) sbDataRemoteWrapper
restoreWindow aState
_getSelectedPageStyle s i
Autocompleter Select
PLDHashOperator PR_CALLBACK SB_SerializeSelectionListCallback(nsStringHashKey::KeyType aKey, nsString aEntry, void *aUserData)