]> git.sesse.net Git - vlc/blob - modules/gui/beos/ListViews.cpp
macosx: added missing pl locks
[vlc] / modules / gui / beos / ListViews.cpp
1 /*****************************************************************************
2  * ListViews.h: BeOS interface list view class implementation
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Stephan Aßmus <stippi@yellowbites.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #if 0
25
26 #include <malloc.h>
27
28 #include <Bitmap.h>
29 #include <Entry.h>
30 #include <String.h>
31
32 /* VLC headers */
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc_common.h>
38 #include <vlc_interface.h>
39
40 #include "InterfaceWindow.h"
41 #include "ListViews.h"
42 #include "MsgVals.h"
43
44 #define MAX_DRAG_HEIGHT        200.0
45 #define ALPHA                170
46 #define TEXT_OFFSET            20.0
47
48 /*****************************************************************************
49  * PlaylistItem class
50  *****************************************************************************/
51 PlaylistItem::PlaylistItem( const char *name )
52     : BStringItem( name ),
53       fName( "" )
54 {
55     entry_ref ref;
56     if ( get_ref_for_path( name, &ref) == B_OK )
57         fName.SetTo( ref.name );
58 }
59
60 PlaylistItem::~PlaylistItem()
61 {
62 }
63
64 /*****************************************************************************
65  * PlaylistItem::DrawItem
66  *****************************************************************************/
67 void
68 PlaylistItem::Draw( BView *owner, BRect frame, bool tintedLine,
69                     uint32 mode, bool active, bool playing )
70 {
71     rgb_color color = (rgb_color){ 255, 255, 255, 255 };
72     if ( tintedLine )
73         color = tint_color( color, 1.04 );
74     // background
75     if ( IsSelected() )
76         color = tint_color( color, B_DARKEN_2_TINT );
77     owner->SetLowColor( color );
78     owner->FillRect( frame, B_SOLID_LOW );
79     // label
80     owner->SetHighColor( 0, 0, 0, 255 );
81     font_height fh;
82     owner->GetFontHeight( &fh );
83     const char* text = Text();
84     switch ( mode )
85     {
86         case DISPLAY_NAME:
87             if ( fName.CountChars() > 0 )
88                 text = fName.String();
89             break;
90         case DISPLAY_PATH:
91         default:
92             break;
93     }
94     BString truncatedString( text );
95     owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE,
96                            frame.Width() - TEXT_OFFSET - 4.0 );
97     owner->DrawString( truncatedString.String(),
98                        BPoint( frame.left + TEXT_OFFSET,
99                                frame.top + fh.ascent + 1.0 ) );
100     // playmark
101     if ( active )
102     {
103         rgb_color black = (rgb_color){ 0, 0, 0, 255 };
104         rgb_color green = (rgb_color){ 0, 255, 0, 255 };
105         BRect r( 0.0, 0.0, 10.0, 10.0 );
106         r.OffsetTo( frame.left + 4.0,
107                     ceilf( ( frame.top + frame.bottom ) / 2.0 ) - 5.0 );
108         if ( !playing )
109             green = tint_color( color, B_DARKEN_1_TINT );
110         rgb_color lightGreen = tint_color( green, B_LIGHTEN_2_TINT );
111         rgb_color darkGreen = tint_color( green, B_DARKEN_2_TINT );
112         BPoint arrow[3];
113         arrow[0] = r.LeftTop();
114         arrow[1] = r.LeftBottom();
115         arrow[2].x = r.right;
116         arrow[2].y = ( r.top + r.bottom ) / 2.0;
117         owner->BeginLineArray( 6 );
118             // black outline
119             owner->AddLine( arrow[0], arrow[1], black );
120             owner->AddLine( BPoint( arrow[1].x + 1.0, arrow[1].y - 1.0 ),
121                             arrow[2], black );
122             owner->AddLine( arrow[0], arrow[2], black );
123             // inset arrow
124             arrow[0].x += 1.0;
125             arrow[0].y += 2.0;
126             arrow[1].x += 1.0;
127             arrow[1].y -= 2.0;
128             arrow[2].x -= 2.0;
129             // highlights and shadow
130             owner->AddLine( arrow[1], arrow[2], darkGreen );
131             owner->AddLine( arrow[0], arrow[2], lightGreen );
132             owner->AddLine( arrow[0], arrow[1], lightGreen );
133         owner->EndLineArray();
134         // fill green
135         arrow[0].x += 1.0;
136         arrow[0].y += 1.0;
137         arrow[1].x += 1.0;
138         arrow[1].y -= 1.0;
139         arrow[2].x -= 2.0;
140         owner->SetHighColor( green );
141         owner->FillPolygon( arrow, 3 );
142     }
143 }
144
145 /*****************************************************************************
146  * DragSortableListView class
147  *****************************************************************************/
148 DragSortableListView::DragSortableListView( BRect frame, const char* name,
149                                             list_view_type type, uint32 resizingMode,
150                                             uint32 flags )
151     : BListView( frame, name, type, resizingMode, flags ),
152       fDropRect( 0.0, 0.0, -1.0, -1.0 ),
153       fDropIndex( -1 )
154 {
155     SetViewColor( B_TRANSPARENT_32_BIT );
156 }
157
158 DragSortableListView::~DragSortableListView()
159 {
160 }
161
162 /*****************************************************************************
163  * DragSortableListView::Draw
164  *****************************************************************************/
165 void
166 DragSortableListView::Draw( BRect updateRect )
167 {
168     int32 firstIndex = IndexOf( updateRect.LeftTop() );
169     int32 lastIndex = IndexOf( updateRect.RightBottom() );
170     if ( firstIndex >= 0 )
171     {
172         if ( lastIndex < firstIndex )
173             lastIndex = CountItems() - 1;
174         // update rect contains items
175         BRect r( updateRect );
176         for ( int32 i = firstIndex; i <= lastIndex; i++)
177         {
178             r = ItemFrame( i );
179             DrawListItem( this, i, r );
180         }
181         updateRect.top = r.bottom + 1.0;
182         if ( updateRect.IsValid() )
183         {
184             SetLowColor( 255, 255, 255, 255 );
185             FillRect( updateRect, B_SOLID_LOW );
186         }
187     }
188     else
189     {
190         SetLowColor( 255, 255, 255, 255 );
191         FillRect( updateRect, B_SOLID_LOW );
192     }
193     // drop anticipation indication
194     if ( fDropRect.IsValid() )
195     {
196         SetHighColor( 255, 0, 0, 255 );
197         StrokeRect( fDropRect );
198     }
199 }
200
201 /*****************************************************************************
202  * DragSortableListView::InitiateDrag
203  *****************************************************************************/
204 bool
205 DragSortableListView::InitiateDrag( BPoint point, int32 index, bool )
206 {
207     bool success = false;
208     BListItem* item = ItemAt( CurrentSelection( 0 ) );
209     if ( !item )
210     {
211         // workarround a timing problem
212         Select( index );
213         item = ItemAt( index );
214     }
215     if ( item )
216     {
217         // create drag message
218         BMessage msg( B_SIMPLE_DATA );
219         MakeDragMessage( &msg );
220         // figure out drag rect
221         float width = Bounds().Width();
222         BRect dragRect(0.0, 0.0, width, -1.0);
223         // figure out, how many items fit into our bitmap
224         int32 numItems;
225         bool fade = false;
226         for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) {
227             dragRect.bottom += ceilf( item->Height() ) + 1.0;
228             if ( dragRect.Height() > MAX_DRAG_HEIGHT ) {
229                 fade = true;
230                 dragRect.bottom = MAX_DRAG_HEIGHT;
231                 numItems++;
232                 break;
233             }
234         }
235         BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true );
236         if ( dragBitmap && dragBitmap->IsValid() ) {
237             if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) {
238                 dragBitmap->AddChild( v );
239                 dragBitmap->Lock();
240                 BRect itemBounds( dragRect) ;
241                 itemBounds.bottom = 0.0;
242                 // let all selected items, that fit into our drag_bitmap, draw
243                 for ( int32 i = 0; i < numItems; i++ ) {
244                     int32 index = CurrentSelection( i );
245                     BListItem* item = ItemAt( index );
246                     itemBounds.bottom = itemBounds.top + ceilf( item->Height() );
247                     if ( itemBounds.bottom > dragRect.bottom )
248                         itemBounds.bottom = dragRect.bottom;
249                     DrawListItem( v, index, itemBounds );
250                     itemBounds.top = itemBounds.bottom + 1.0;
251                 }
252                 // make a black frame arround the edge
253                 v->SetHighColor( 0, 0, 0, 255 );
254                 v->StrokeRect( v->Bounds() );
255                 v->Sync();
256  
257                 uint8 *bits = (uint8 *)dragBitmap->Bits();
258                 int32 height = (int32)dragBitmap->Bounds().Height() + 1;
259                 int32 width = (int32)dragBitmap->Bounds().Width() + 1;
260                 int32 bpr = dragBitmap->BytesPerRow();
261  
262                 if (fade) {
263                     for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) {
264                         uint8 *line = bits + 3;
265                         for (uint8 *end = line + 4 * width; line < end; line += 4)
266                             *line = ALPHA;
267                     }
268                     for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) {
269                         uint8 *line = bits + 3;
270                         for (uint8 *end = line + 4 * width; line < end; line += 4)
271                             *line = (height - y) << 1;
272                     }
273                 } else {
274                     for ( int32 y = 0; y < height; y++, bits += bpr ) {
275                         uint8 *line = bits + 3;
276                         for (uint8 *end = line + 4 * width; line < end; line += 4)
277                             *line = ALPHA;
278                     }
279                 }
280                 dragBitmap->Unlock();
281                 success = true;
282             }
283         }
284         if (success)
285             DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) );
286         else {
287             delete dragBitmap;
288             DragMessage( &msg, dragRect.OffsetToCopy( point ), this );
289         }
290     }
291     return success;
292 }
293
294 /*****************************************************************************
295  * DragSortableListView::WindowActivated
296  *****************************************************************************/
297 void
298 DragSortableListView::WindowActivated( bool active )
299 {
300     // workarround for buggy focus indication of BScrollView
301     if ( BView* view = Parent() )
302         view->Invalidate();
303 }
304
305 /*****************************************************************************
306  * DragSortableListView::MessageReceived
307  *****************************************************************************/
308 void
309 DragSortableListView::MessageReceived(BMessage* message)
310 {
311     switch ( message->what )
312     {
313         case B_MODIFIERS_CHANGED:
314             ModifiersChanged();
315             break;
316         case B_SIMPLE_DATA:
317         {
318             DragSortableListView *list = NULL;
319             if ( message->FindPointer( "list", (void **)&list ) == B_OK
320                  && list == this )
321             {
322                 int32 count = CountItems();
323                 if ( fDropIndex < 0 || fDropIndex > count )
324                     fDropIndex = count;
325                 BList items;
326                 int32 index;
327                 for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ )
328                     if ( BListItem* item = ItemAt(index) )
329                         items.AddItem( (void*)item );
330                 if ( items.CountItems() > 0 )
331                 {
332                     if ( modifiers() & B_SHIFT_KEY )
333                         CopyItems( items, fDropIndex );
334                     else
335                         MoveItems( items, fDropIndex );
336                 }
337                 fDropIndex = -1;
338             }
339             break;
340         }
341         default:
342             BListView::MessageReceived( message );
343             break;
344     }
345 }
346
347 /*****************************************************************************
348  * DragSortableListView::MouseMoved
349  *****************************************************************************/
350 void
351 DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
352 {
353     if ( msg && ( msg->what == B_SIMPLE_DATA || msg->what == MSG_SOUNDPLAY ) )
354     {
355         bool replaceAll = !msg->HasPointer("list") && !(modifiers() & B_SHIFT_KEY);
356         switch ( transit )
357         {
358             case B_ENTERED_VIEW:
359                 // remember drag message
360                 // this is needed to react on modifier changes
361                 fDragMessageCopy = *msg;
362             case B_INSIDE_VIEW:
363             {
364                 if ( replaceAll )
365                 {
366                     BRect r( Bounds() );
367                     r.bottom--;    // compensate for scrollbar offset
368                     _SetDropAnticipationRect( r );
369                     fDropIndex = -1;
370                 }
371                 else
372                 {
373                     // offset where by half of item height
374                     BRect r( ItemFrame( 0 ) );
375                     where.y += r.Height() / 2.0;
376  
377                     int32 index = IndexOf( where );
378                     if ( index < 0 )
379                         index = CountItems();
380                     _SetDropIndex( index );
381                 }
382                 break;
383             }
384             case B_EXITED_VIEW:
385                 // forget drag message
386                 fDragMessageCopy.what = 0;
387             case B_OUTSIDE_VIEW:
388                 _RemoveDropAnticipationRect();
389                 break;
390         }
391     }
392     else
393     {
394         _RemoveDropAnticipationRect();
395         BListView::MouseMoved(where, transit, msg);
396         fDragMessageCopy.what = 0;
397     }
398 }
399
400 /*****************************************************************************
401  * DragSortableListView::MouseUp
402  *****************************************************************************/
403 void
404 DragSortableListView::MouseUp( BPoint where )
405 {
406     // remove drop mark
407     _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
408     // be sure to forget drag message
409     fDragMessageCopy.what = 0;
410     BListView::MouseUp( where );
411 }
412
413 /*****************************************************************************
414  * DragSortableListView::DrawItem
415  *****************************************************************************/
416 void
417 DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete )
418 {
419     DrawListItem( this, IndexOf( item ), itemFrame );
420 }
421
422 /*****************************************************************************
423  * DragSortableListView::ModifiersChaned
424  *****************************************************************************/
425 void
426 DragSortableListView::ModifiersChanged()
427 {
428     BPoint where;
429     uint32 buttons;
430     GetMouse( &where, &buttons, false );
431     uint32 transit = Bounds().Contains( where ) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
432     MouseMoved( where, transit, &fDragMessageCopy );
433 }
434
435 /*****************************************************************************
436  * DragSortableListView::MoveItems
437  *****************************************************************************/
438 void
439 DragSortableListView::MoveItems( BList& items, int32 index )
440 {
441     DeselectAll();
442     // we remove the items while we look at them, the insertion index is decreased
443     // when the items index is lower, so that we insert at the right spot after
444     // removal
445     BList removedItems;
446     int32 count = items.CountItems();
447     for ( int32 i = 0; i < count; i++ )
448     {
449         BListItem* item = (BListItem*)items.ItemAt( i );
450         int32 removeIndex = IndexOf( item );
451         if ( RemoveItem( item ) && removedItems.AddItem( (void*)item ) )
452         {
453             if ( removeIndex < index )
454                 index--;
455         }
456         // else ??? -> blow up
457     }
458     for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ )
459     {
460         if ( AddItem( item, index ) )
461         {
462             // after we're done, the newly inserted items will be selected
463             Select( index, true );
464             // next items will be inserted after this one
465             index++;
466         }
467         else
468             delete item;
469     }
470 }
471
472 /*****************************************************************************
473  * DragSortableListView::CopyItems
474  *****************************************************************************/
475 void
476 DragSortableListView::CopyItems( BList& items, int32 index )
477 {
478     DeselectAll();
479     // by inserting the items after we copied all items first, we avoid
480     // cloning an item we already inserted and messing everything up
481     // in other words, don't touch the list before we know which items
482     // need to be cloned
483     BList clonedItems;
484     int32 count = items.CountItems();
485     for ( int32 i = 0; i < count; i++ )
486     {
487         BListItem* item = CloneItem( IndexOf( (BListItem*)items.ItemAt( i ) ) );
488         if ( item && !clonedItems.AddItem( (void*)item ) )
489             delete item;
490     }
491     for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ )
492     {
493         if ( AddItem( item, index ) )
494         {
495             // after we're done, the newly inserted items will be selected
496             Select( index, true );
497             // next items will be inserted after this one
498             index++;
499         }
500         else
501             delete item;
502     }
503 }
504
505 /*****************************************************************************
506  * DragSortableListView::RemoveItemList
507  *****************************************************************************/
508 void
509 DragSortableListView::RemoveItemList( BList& items )
510 {
511     int32 count = items.CountItems();
512     for ( int32 i = 0; i < count; i++ )
513     {
514         BListItem* item = (BListItem*)items.ItemAt( i );
515         if ( RemoveItem( item ) )
516             delete item;
517     }
518 }
519
520 /*****************************************************************************
521  * DragSortableListView::RemoveSelected
522  *****************************************************************************/
523 void
524 DragSortableListView::RemoveSelected()
525 {
526     BList items;
527     for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
528         items.AddItem( (void*)item );
529     RemoveItemList( items );
530 }
531
532 /*****************************************************************************
533  * DragSortableListView::CountSelectedItems
534  *****************************************************************************/
535 int32
536 DragSortableListView::CountSelectedItems() const
537 {
538     int32 count = 0;
539     while ( CurrentSelection( count ) >= 0 )
540         count++;
541     return count;
542 }
543
544 /*****************************************************************************
545  * DragSortableListView::_SetDropAnticipationRect
546  *****************************************************************************/
547 void
548 DragSortableListView::_SetDropAnticipationRect( BRect r )
549 {
550     if ( fDropRect != r )
551     {
552         if ( fDropRect.IsValid() )
553             Invalidate( fDropRect );
554         fDropRect = r;
555         if ( fDropRect.IsValid() )
556             Invalidate( fDropRect );
557     }
558 }
559
560 /*****************************************************************************
561  * DragSortableListView::_SetDropAnticipationRect
562  *****************************************************************************/
563 void
564 DragSortableListView::_SetDropIndex( int32 index )
565 {
566     if ( fDropIndex != index )
567     {
568         fDropIndex = index;
569         if ( fDropIndex == -1 )
570             _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
571         else
572         {
573             int32 count = CountItems();
574             if ( fDropIndex == count )
575             {
576                 BRect r;
577                 if ( BListItem* item = ItemAt( count - 1 ) )
578                 {
579                     r = ItemFrame( count - 1 );
580                     r.top = r.bottom + 1.0;
581                     r.bottom = r.top + 1.0;
582                 }
583                 else
584                 {
585                     r = Bounds();
586                     r.bottom--;    // compensate for scrollbars moved slightly out of window
587                 }
588                 _SetDropAnticipationRect( r );
589             }
590             else
591             {
592                 BRect r = ItemFrame( fDropIndex );
593                 r.bottom = r.top + 1.0;
594                 _SetDropAnticipationRect( r );
595             }
596         }
597     }
598 }
599
600 /*****************************************************************************
601  * DragSortableListView::_RemoveDropAnticipationRect
602  *****************************************************************************/
603 void
604 DragSortableListView::_RemoveDropAnticipationRect()
605 {
606     _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
607     _SetDropIndex( -1 );
608 }
609
610
611 /*****************************************************************************
612  * PlaylistView class
613  *****************************************************************************/
614 PlaylistView::PlaylistView( intf_thread_t * _p_intf,
615                             BRect frame, InterfaceWindow* mainWindow,
616                             BMessage* selectionChangeMessage )
617     : DragSortableListView( frame, "playlist listview",
618                             B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES,
619                             B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED
620                             | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ),
621       p_intf( _p_intf ),
622       fCurrentIndex( -1 ),
623       fPlaying( false ),
624       fDisplayMode( DISPLAY_PATH ),
625       fMainWindow( mainWindow ),
626       fSelectionChangeMessage( selectionChangeMessage ),
627       fLastClickedItem( NULL )
628 {
629 }
630
631 PlaylistView::~PlaylistView()
632 {
633     delete fSelectionChangeMessage;
634 }
635
636 /*****************************************************************************
637  * PlaylistView::AttachedToWindow
638  *****************************************************************************/
639 void
640 PlaylistView::AttachedToWindow()
641 {
642     // get pulse message every two frames
643     Window()->SetPulseRate( 80000 );
644 }
645
646 /*****************************************************************************
647  * PlaylistView::MessageReceived
648  *****************************************************************************/
649 void
650 PlaylistView::MessageReceived( BMessage* message)
651 {
652     switch ( message->what )
653     {
654         case MSG_SOUNDPLAY:
655         case B_SIMPLE_DATA:
656             if ( message->HasPointer( "list" ) )
657             {
658                 // message comes from ourself
659                 DragSortableListView::MessageReceived( message );
660             }
661             else
662             {
663                 // message comes from another app (for example Tracker)
664                 message->AddInt32( "drop index", fDropIndex );
665                 fMainWindow->PostMessage( message, fMainWindow );
666             }
667             break;
668         default:
669             DragSortableListView::MessageReceived( message );
670             break;
671     }
672 }
673
674 /*****************************************************************************
675  * PlaylistView::MouseDown
676  *****************************************************************************/
677 void
678 PlaylistView::MouseDown( BPoint where )
679 {
680     int32 clicks = 1;
681     Window()->CurrentMessage()->FindInt32( "clicks", &clicks );
682     bool handled = false;
683     for ( int32 i = 0; PlaylistItem* item = (PlaylistItem*)ItemAt( i ); i++ )
684     {
685         BRect r = ItemFrame( i );
686         if ( r.Contains( where ) )
687         {
688             if ( clicks == 2 )
689             {
690                 // only do something if user clicked the same item twice
691                 if ( fLastClickedItem == item )
692                 {
693                     playlist_t * p_playlist = pl_Hold( p_intf );
694                     if( p_playlist )
695                     {
696                         playlist_Goto( p_playlist, i );
697                         pl_Release( p_intf );
698                     }
699                     handled = true;
700                 }
701             }
702             else
703             {
704                 // remember last clicked item
705                 fLastClickedItem = item;
706                 if ( i == fCurrentIndex )
707                 {
708                     r.right = r.left + TEXT_OFFSET;
709                     if ( r.Contains ( where ) )
710                     {
711                         fMainWindow->PostMessage( PAUSE_PLAYBACK );
712                         InvalidateItem( i );
713                         handled = true;
714                     }
715                 }
716             }
717             break;
718         }
719     }
720     if ( !handled )
721         DragSortableListView::MouseDown(where);
722 }
723
724 /*****************************************************************************
725  * PlaylistView::KeyDown
726  *****************************************************************************/
727 void
728 PlaylistView::KeyDown( const char* bytes, int32 numBytes )
729 {
730     if ( numBytes < 1 )
731         return;
732  
733     if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) )
734     {
735         RemoveSelected();
736     }
737     DragSortableListView::KeyDown( bytes, numBytes );
738 }
739
740 /*****************************************************************************
741  * PlaylistView::Pulse
742  *****************************************************************************/
743 void
744 PlaylistView::Pulse()
745 {
746     if ( fMainWindow->IsStopped() )
747         SetPlaying( false );
748 }
749
750 /*****************************************************************************
751  * PlaylistView::SelectionChanged
752  *****************************************************************************/
753 void
754 PlaylistView::SelectionChanged()
755 {
756     BLooper* looper = Looper();
757     if ( fSelectionChangeMessage && looper )
758     {
759         BMessage message( *fSelectionChangeMessage );
760         looper->PostMessage( &message );
761     }
762 }
763
764
765 /*****************************************************************************
766  * PlaylistView::MoveItems
767  *****************************************************************************/
768 void
769 PlaylistView::MoveItems( BList& items, int32 index )
770 {
771 #if 0
772     DeselectAll();
773     // we remove the items while we look at them, the insertion index is decreased
774     // when the items index is lower, so that we insert at the right spot after
775     // removal
776     if ( fVlcWrapper->PlaylistLock() )
777     {
778         BList removedItems;
779         BList removeItems;
780         int32 count = items.CountItems();
781         int32 indexOriginal = index;
782         // remember currently playing item
783         BListItem* playingItem = _PlayingItem();
784         // collect item pointers for removal by index
785         for ( int32 i = 0; i < count; i++ )
786         {
787             int32 removeIndex = IndexOf( (BListItem*)items.ItemAt( i ) );
788             void* item = fVlcWrapper->PlaylistItemAt( removeIndex );
789             if ( item && removeItems.AddItem( item ) )
790             {
791                 if ( removeIndex < index )
792                     index--;
793             }
794             // else ??? -> blow up
795         }
796         // actually remove items using pointers
797         for ( int32 i = 0; i < count; i++ )
798         {
799             void* item = fVlcWrapper->PlaylistRemoveItem( removeItems.ItemAt( i ) );
800             if ( item && !removedItems.AddItem( item ) )
801                 free( item );
802         }
803         // add items at index
804         for ( int32 i = 0; void* item = removedItems.ItemAt( i ); i++ )
805         {
806             if ( fVlcWrapper->PlaylistAddItem( item, index ) )
807                 // next items will be inserted after this one
808                 index++;
809             else
810                 free( item );
811         }
812         // update GUI
813         DragSortableListView::MoveItems( items, indexOriginal );
814         // restore currently playing item
815         _SetPlayingIndex( playingItem );
816         // update interface (in case it isn't playing,
817         // there is a chance that it needs to update)
818         fMainWindow->PostMessage( MSG_UPDATE );
819         fVlcWrapper->PlaylistUnlock();
820     }
821 #endif
822 }
823
824 /*****************************************************************************
825  * PlaylistView::CopyItems
826  *****************************************************************************/
827 void
828 PlaylistView::CopyItems( BList& items, int32 toIndex )
829 {
830 #if 0
831     DeselectAll();
832     // we remove the items while we look at them, the insertion index is decreased
833     // when the items index is lower, so that we insert at the right spot after
834     // removal
835     if ( fVlcWrapper->PlaylistLock() )
836     {
837         BList clonedItems;
838         int32 count = items.CountItems();
839         // remember currently playing item
840         BListItem* playingItem = _PlayingItem();
841         // collect cloned item pointers
842         for ( int32 i = 0; i < count; i++ )
843         {
844             int32 index = IndexOf( (BListItem*)items.ItemAt( i ) );
845             void* item = fVlcWrapper->PlaylistItemAt( index );
846             void* cloned = fVlcWrapper->PlaylistCloneItem( item );
847             if ( cloned && !clonedItems.AddItem( cloned ) )
848                 free( cloned );
849  
850         }
851         // add cloned items at index
852         int32 index = toIndex;
853         for ( int32 i = 0; void* item = clonedItems.ItemAt( i ); i++ )
854         {
855             if ( fVlcWrapper->PlaylistAddItem( item, index ) )
856                 // next items will be inserted after this one
857                 index++;
858             else
859                 free( item );
860         }
861         // update GUI
862         DragSortableListView::CopyItems( items, toIndex );
863         // restore currently playing item
864         _SetPlayingIndex( playingItem );
865         // update interface (in case it isn't playing,
866         // there is a chance that it needs to update)
867         fMainWindow->PostMessage( MSG_UPDATE );
868         fVlcWrapper->PlaylistUnlock();
869     }
870 #endif
871 }
872
873 /*****************************************************************************
874  * PlaylistView::RemoveItemList
875  *****************************************************************************/
876 void
877 PlaylistView::RemoveItemList( BList& items )
878 {
879 #if 0
880     if ( fVlcWrapper->PlaylistLock() )
881     {
882         // remember currently playing item
883         BListItem* playingItem = _PlayingItem();
884         // collect item pointers for removal
885         BList removeItems;
886         int32 count = items.CountItems();
887         for ( int32 i = 0; i < count; i++ )
888         {
889             int32 index = IndexOf( (BListItem*)items.ItemAt( i ) );
890             void* item = fVlcWrapper->PlaylistItemAt( index );
891             if ( item && !removeItems.AddItem( item ) )
892                 free( item );
893         }
894         // remove items from playlist
895         count = removeItems.CountItems();
896         for ( int32 i = 0; void* item = removeItems.ItemAt( i ); i++ )
897         {
898             fVlcWrapper->PlaylistRemoveItem( item );
899         }
900         // update GUI
901         DragSortableListView::RemoveItemList( items );
902         // restore currently playing item
903         _SetPlayingIndex( playingItem );
904         // update interface (in case it isn't playing,
905         // there is a chance that it needs to update)
906         fMainWindow->PostMessage( MSG_UPDATE );
907         fVlcWrapper->PlaylistUnlock();
908     }
909 #endif
910 }
911
912 /*****************************************************************************
913  * PlaylistView::CloneItem
914  *****************************************************************************/
915 BListItem*
916 PlaylistView::CloneItem( int32 atIndex ) const
917 {
918     BListItem* clone = NULL;
919     if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( atIndex ) ) )
920         clone = new PlaylistItem( item->Text() );
921     return clone;
922 }
923
924 /*****************************************************************************
925  * PlaylistView::DrawListItem
926  *****************************************************************************/
927 void
928 PlaylistView::DrawListItem( BView* owner, int32 index, BRect frame ) const
929 {
930     if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( index ) ) )
931         item->Draw( owner,  frame, index % 2,
932                     fDisplayMode, index == fCurrentIndex, fPlaying );
933 }
934
935 /*****************************************************************************
936  * PlaylistView::MakeDragMessage
937  *****************************************************************************/
938 void
939 PlaylistView::MakeDragMessage( BMessage* message ) const
940 {
941     if ( message )
942     {
943         message->AddPointer( "list", (void*)this );
944         int32 index;
945         for ( int32 i = 0; ( index = CurrentSelection( i ) ) >= 0; i++ )
946         {
947             message->AddInt32( "index", index );
948             // add refs to message (inter application communication)
949             if ( BStringItem* item = dynamic_cast<BStringItem*>( ItemAt( index ) ) )
950             {
951                 entry_ref ref;
952                 if ( get_ref_for_path( item->Text(), &ref ) == B_OK )
953                     message->AddRef( "refs", &ref );
954             }
955         }
956     }
957 }
958
959 /*****************************************************************************
960  * PlaylistView::SetCurrent
961  *****************************************************************************/
962 void
963 PlaylistView::SetCurrent( int32 index )
964 {
965     if ( fCurrentIndex != index )
966     {
967         InvalidateItem( fCurrentIndex );
968         fCurrentIndex = index;
969         InvalidateItem( fCurrentIndex );
970     }
971 }
972
973 /*****************************************************************************
974  * PlaylistView::SetPlaying
975  *****************************************************************************/
976 void
977 PlaylistView::SetPlaying( bool playing )
978 {
979     if ( fPlaying != playing )
980     {
981         fPlaying = playing;
982         InvalidateItem( fCurrentIndex );
983     }
984 }
985
986 /*****************************************************************************
987  * PlaylistView::SetPlaying
988  *****************************************************************************/
989 void
990 PlaylistView::RebuildList()
991 {
992     playlist_t * p_playlist = pl_Hold( p_intf );
993
994     // remove all items
995     BListItem * item;
996     int32 count = CountItems();
997     while( ( item = RemoveItem( --count ) ) )
998         delete item;
999
1000     // rebuild listview from VLC's playlist
1001     PL_LOCK;
1002     FOREACH_ARRAY( playlist_item_t *p_item, p_playlist->items )
1003         AddItem( new PlaylistItem( p_item->p_input->psz_name ) );
1004     FOREACH_END();
1005     PL_UNLOCK;
1006
1007     vlc_object_release( p_playlist );
1008 }
1009
1010
1011 /*****************************************************************************
1012  * PlaylistView::SortReverse
1013  *****************************************************************************/
1014 void
1015 PlaylistView::SortReverse()
1016 {
1017 #if 0
1018     if ( int32 count = CountSelectedItems() )
1019     {
1020         int32 last  = count - 1;
1021         // remember currently playing item
1022         BListItem* playingItem = _PlayingItem();
1023         for ( int32 first = 0; first < count / 2; first++, last-- )
1024         {
1025             int32 index1 = CurrentSelection( first);
1026             int32 index2 = CurrentSelection( last);
1027             if ( SwapItems( index1, index2 ) )
1028             {
1029                 // index2 > index1, so the list won't get messed up
1030                 // if we remove the items in that order
1031                 // TODO: Error checking + handling!
1032                 void* item2 = fVlcWrapper->PlaylistRemoveItem( index2 );
1033                 void* item1 = fVlcWrapper->PlaylistRemoveItem( index1 );
1034                 fVlcWrapper->PlaylistAddItem( item2, index1 );
1035                 fVlcWrapper->PlaylistAddItem( item1, index2 );
1036             }
1037         }
1038         // restore currently playing item
1039         _SetPlayingIndex( playingItem );
1040     }
1041 #endif
1042 }
1043
1044 /*****************************************************************************
1045  * PlaylistView::SortByPath
1046  *****************************************************************************/
1047 void
1048 PlaylistView::SortByPath()
1049 {
1050  
1051 }
1052
1053 /*****************************************************************************
1054  * PlaylistView::SortByName
1055  *****************************************************************************/
1056 void
1057 PlaylistView::SortByName()
1058 {
1059 }
1060
1061 /*****************************************************************************
1062  * PlaylistView::SetDisplayMode
1063  *****************************************************************************/
1064 void
1065 PlaylistView::SetDisplayMode( uint32 mode )
1066 {
1067     if ( mode != fDisplayMode )
1068     {
1069         fDisplayMode = mode;
1070         Invalidate();
1071     }
1072 }
1073
1074 /*****************************************************************************
1075  * PlaylistView::_PlayingItem
1076  *****************************************************************************/
1077 BListItem*
1078 PlaylistView::_PlayingItem() const
1079 {
1080     playlist_t * p_playlist = pl_Hold( p_intf );
1081
1082     if( !p_playlist )
1083     {
1084         return NULL;
1085     }
1086
1087     BListItem * item = ItemAt( p_playlist->i_index );
1088     pl_Release( p_intf );
1089     return item;
1090 }
1091
1092 /*****************************************************************************
1093  * PlaylistView::_SetPlayingIndex
1094  *****************************************************************************/
1095 void
1096 PlaylistView::_SetPlayingIndex( BListItem* playingItem )
1097 {
1098     for ( int32 i = 0; BListItem* item = ItemAt( i ); i++ )
1099     {
1100         if ( item == playingItem )
1101         {
1102             playlist_t * p_playlist = pl_Hold( p_intf );
1103  
1104             if( !p_playlist )
1105             {
1106                 return;
1107             }
1108
1109             playlist_Goto( p_playlist, i );
1110             SetCurrent( i );
1111
1112             pl_Release( p_intf );
1113             break;
1114         }
1115     }
1116 }
1117
1118 #endif