]> git.sesse.net Git - vlc/commitdiff
* vlc_symbols.h, vlc_playlist.h, view.c : add a function to remove a parent from...
authorBenjamin Pracht <bigben@videolan.org>
Fri, 1 Jul 2005 20:48:48 +0000 (20:48 +0000)
committerBenjamin Pracht <bigben@videolan.org>
Fri, 1 Jul 2005 20:48:48 +0000 (20:48 +0000)
* playlist.m: implements full drag and drop of playlist items. Drop of multiple items and of items and nodes at the same time should be supported. You cannot mode service discovery items. This is a choice and can be changed if wanted.
* Hopes that compiles on current trunk (cannot check since latest comits on net functions broke the built of a half the modules and core of the OSX port...)

include/vlc_playlist.h
include/vlc_symbols.h
modules/gui/macosx/playlist.m
src/playlist/view.c

index b097ae678b4c9cdaeda386de272ed46949e785a3..28b6262514a026c0f78faad6b416f92f924c74cb 100644 (file)
@@ -298,6 +298,7 @@ VLC_EXPORT( playlist_item_t *, playlist_NodeCreate, ( playlist_t *,int,char *, p
 VLC_EXPORT( int, playlist_NodeAppend, (playlist_t *,int,playlist_item_t*,playlist_item_t *) );
 VLC_EXPORT( int, playlist_NodeInsert, (playlist_t *,int,playlist_item_t*,playlist_item_t *, int) );
 VLC_EXPORT( int, playlist_NodeRemoveItem, (playlist_t *,playlist_item_t*,playlist_item_t *) );
+VLC_EXPORT( int, playlist_NodeRemoveParent, (playlist_t *,playlist_item_t*,playlist_item_t *) );
 VLC_EXPORT( int, playlist_NodeChildrenCount, (playlist_t *,playlist_item_t* ) );
 VLC_EXPORT( playlist_item_t *, playlist_ChildSearchName, (playlist_item_t*, const char* ) );
 VLC_EXPORT( int, playlist_NodeDelete, ( playlist_t *, playlist_item_t *, vlc_bool_t , vlc_bool_t ) );
index a5622faa846b99f5c12b821ac7bf11fdf94b67c4..3a898e944cc9f96344ed82680e64f5001bbbe35a 100644 (file)
@@ -376,6 +376,7 @@ struct module_symbols_t
     void (*net_ListenClose_inner) (int *fd);
     void (*DigestMD5_inner) (struct md5_s *, uint32_t *);
     int (*__net_CheckIP_inner) (vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts, int i_hosts);
+    int (*playlist_NodeRemoveParent_inner) (playlist_t *,playlist_item_t*,playlist_item_t *);
 };
 # if defined (__PLUGIN__)
 #  define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner
@@ -737,6 +738,7 @@ struct module_symbols_t
 #  define net_ListenClose (p_symbols)->net_ListenClose_inner
 #  define DigestMD5 (p_symbols)->DigestMD5_inner
 #  define __net_CheckIP (p_symbols)->__net_CheckIP_inner
+#  define playlist_NodeRemoveParent (p_symbols)->playlist_NodeRemoveParent_inner
 # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__)
 /******************************************************************
  * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access.
@@ -1101,6 +1103,7 @@ struct module_symbols_t
     ((p_symbols)->net_ListenClose_inner) = net_ListenClose; \
     ((p_symbols)->DigestMD5_inner) = DigestMD5; \
     ((p_symbols)->__net_CheckIP_inner) = __net_CheckIP; \
+    ((p_symbols)->playlist_NodeRemoveParent_inner) = playlist_NodeRemoveParent; \
     (p_symbols)->net_ConvertIPv4_deprecated = NULL; \
 
 # endif /* __PLUGIN__ */
index 23ffeca18f96f240a7f5f45b75b76a57f3e17946..467d44c59338042e1e3679a72c1cce2d5dec11c8 100644 (file)
@@ -309,9 +309,23 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     vlc_object_release( p_playlist );
 }
 
+- (playlist_item_t *)parentOfItem:(playlist_item_t *)p_item
+{
+    int i;
+    for( i = 0 ; i < p_item->i_parents; i++ )
+    {
+        if( p_item->pp_parents[i]->i_view == i_current_view )
+        {
+            return p_item->pp_parents[i]->p_parent;
+        }
+    }
+    return NULL;
+}
+
 - (void)updateRowSelection
 {
-    int i,i_row;
+//    int i;
+    int i_row;
     unsigned int j;
 
     playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
@@ -323,20 +337,26 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
         return;
 
     p_item = p_playlist->status.p_item;
-    if( p_item == NULL ) return;
+    if( p_item == NULL )
+    {
+        vlc_object_release(p_playlist);
+        return;
+    }
 
     p_temp_item = p_item;
     while( p_temp_item->i_parents > 0 )
     {
         [o_array insertObject: [NSValue valueWithPointer: p_temp_item] atIndex: 0];
-        for (i = 0 ; i < p_temp_item->i_parents ; i++)
+
+        p_temp_item = [self parentOfItem: p_temp_item];
+        /*for (i = 0 ; i < p_temp_item->i_parents ; i++)
         {
             if( p_temp_item->pp_parents[i]->i_view == i_current_view )
             {
                 p_temp_item = p_temp_item->pp_parents[i]->p_parent;
                 break;
             }
-        }
+        }*/
     }
 
     for (j = 0 ; j < [o_array count] - 1 ; j++)
@@ -369,11 +389,21 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
         return NO;
     }
 
-    if( p_node == p_item ) return YES;
+    if( p_node == p_item )
+    {
+        vlc_object_release(p_playlist);
+        return YES;
+    }
+
+    if( p_node->i_children < 1)
+    {
+        vlc_object_release(p_playlist);
+        return NO;
+    }
 
     if ( p_temp_item )
     {
-        int i;
+//        int i;
         vlc_mutex_lock( &p_playlist->object_lock );
 
 // Let's check if we can do without that
@@ -395,7 +425,15 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 #endif
         while( p_temp_item->i_parents > 0 )
         {
-            for( i = 0; i < p_temp_item->i_parents ; i++ )
+            p_temp_item = [self parentOfItem: p_temp_item];
+            if( p_temp_item == p_node )
+            {
+                 vlc_mutex_unlock( &p_playlist->object_lock );
+                 vlc_object_release( p_playlist );
+                 return YES;
+            }
+
+/*            for( i = 0; i < p_temp_item->i_parents ; i++ )
             {
                 if( p_temp_item->pp_parents[i]->i_view == i_current_view )
                 {
@@ -411,15 +449,42 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
                         break;
                     }
                 }
-            }
-            vlc_mutex_unlock( &p_playlist->object_lock );
+            }*/
         }
+        vlc_mutex_unlock( &p_playlist->object_lock );
     }
 
     vlc_object_release( p_playlist );
     return NO;
 }
 
+/* This method is usefull for instance to remove the selected children of an
+   already selected node, for instance */
+- (void)removeItemsFrom:(id)o_items ifChildrenOf:(id)o_nodes
+{
+    unsigned int i, j;
+    for( i = 0 ; i < [o_items count] ; i++ )
+    {
+        for ( j = 0 ; j < [o_nodes count] ; j++ )
+        {
+            if( o_items == o_nodes)
+            {
+                if( j == i ) continue;
+            }
+            if( [self isItem: [[o_items objectAtIndex:i] pointerValue]
+                    inNode: [[o_nodes objectAtIndex:j] pointerValue]] )
+            {
+                [o_nodes removeObjectAtIndex:i];
+                /* We need to execute the next iteration with the same index
+                   since the current item has been deleted */
+                i--;
+                break;
+            }
+        }
+    }
+
+}
+
 - (BOOL)isValueItem: (id)o_item inNode: (id)o_node
 {
     int i;
@@ -473,7 +538,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     {
         playlist_item_t *p_item;
         playlist_item_t *p_node = NULL;
-        int i;
+//        int i;
 
         p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue];
 
@@ -481,13 +546,15 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
         {
             if( p_item->i_children == -1 )
             {
-                for( i = 0 ; i < p_item->i_parents ; i++ )
+                p_node = [self parentOfItem: p_item];
+
+/*                for( i = 0 ; i < p_item->i_parents ; i++ )
                 {
                     if( p_item->pp_parents[i]->i_view == i_current_view )
                     {
                         p_node = p_item->pp_parents[i]->p_parent;
                     }
-                }
+                }*/
             }
             else
             {
@@ -1360,6 +1427,8 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
                                                FIND_ANYWHERE );
 
+    /* First remove the items that were moved during the last drag & drop
+       operation */
     [o_items_array removeAllObjects];
     [o_nodes_array removeAllObjects];
 
@@ -1369,12 +1438,15 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     {
         id o_item = [items objectAtIndex: i];
 
+        /* Refuse to move items that are not in the General Node
+           (Service Discovery) */
         if( ![self isItem: [o_item pointerValue] inNode:
                                         p_playlist->p_general] )
         {
             vlc_object_release(p_playlist);
             return NO;
         }
+        /* Fill the items and nodes to move in 2 different arrays */
         if( ((playlist_item_t *)[o_item pointerValue])->i_children > 0 )
             [o_nodes_array addObject: o_item];
         else
@@ -1383,6 +1455,10 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
     /* Now we need to check if there are selected items that are in already
        selected nodes. In that case, we only want to move the nodes */
+    [self removeItemsFrom: o_nodes_array ifChildrenOf: o_nodes_array];
+    [self removeItemsFrom: o_items_array ifChildrenOf: o_nodes_array];
+
+#if 0
     for( i = 0 ; i < [o_nodes_array count] ; i++ )
     {
         for ( j = 0 ; j < [o_nodes_array count] ; j++ )
@@ -1413,6 +1489,11 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
             }
         }
     }
+#endif
+    /* We add the "VLCPlaylistItemPboardType" type to be able to recognize
+       a Drop operation comçing from the playlist.
+       We need to add NSFilenamesPboardType otherwise the outlineview refuses
+       to the drop. */
 
     [pboard declareTypes: [NSArray arrayWithObjects:
         @"VLCPlaylistItemPboardType",NSFilenamesPboardType, nil] owner: self];
@@ -1431,8 +1512,15 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
     if( !p_playlist ) return NSDragOperationNone;
 
-    if( ![self isItem: [item pointerValue] inNode: p_playlist->p_general] )
-    return NSDragOperationNone;
+    /* We refuse to drop an item in anything else than a child of the General
+       Node. We still accept items that would be root nodes of the outlineview
+       however, to allow drop in an empty playlist.*/
+    if( !([self isItem: [item pointerValue] inNode: p_playlist->p_general] ||
+          item == nil) )
+    {
+        vlc_object_release(p_playlist);
+        return NSDragOperationNone;
+    }
 
     /* Drop from the Playlist */
     if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
@@ -1440,6 +1528,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
         unsigned int i;
         for( i = 0 ; i < [o_nodes_array count] ; i++ )
         {
+            /* We refuse to Drop in a child of an item we are moving */
             if( [self isItem: [item pointerValue] inNode:
                             [[o_nodes_array objectAtIndex: i] pointerValue]]  )
             {
@@ -1469,7 +1558,127 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
     if( !p_playlist ) return NO;
 
-    if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
+    /* Drag & Drop inside the playlist */
+    if( [[o_pasteboard types] containsObject: @"VLCPlaylistItemPboardType"] )
+    {
+        int i_row;
+        unsigned int i;
+        playlist_item_t *p_new_parent, *p_item = NULL;
+        NSArray *o_all_items = [o_nodes_array arrayByAddingObjectsFromArray:
+                                                                o_items_array];
+        /* If the item is to be dropped as root item of the outline, make it a
+           child of the General node.
+           Else, choose the proposed parent as parent. */
+        if( item == nil )
+        p_new_parent = p_playlist->p_general;
+        else
+        p_new_parent = [item pointerValue];
+
+        /* If the proposed parent is not a node, then use the parent node of
+           this item. */
+        if( p_new_parent->i_children <= 0 )
+        {
+            int j;
+            playlist_item_t *p_temp_item = p_new_parent;
+            p_new_parent = [self parentOfItem: p_new_parent];
+            if( !p_new_parent )
+            {
+                vlc_object_release(p_playlist);
+                return NO;
+            }
+            /* Calculate the position of the dropped item in this new parent:
+               following the first proposed parent. */
+            for( j = 0; j < p_new_parent->i_children; j++ )
+            {
+                if( p_new_parent->pp_children[j] == p_temp_item )
+                {
+                    index = j;
+                    break;
+                }
+                else if( j == p_new_parent->i_children - 1 )
+                index = -1;
+            }
+        }
+
+        for( i = 0; i < [o_all_items count]; i++ )
+        {
+            playlist_item_t *p_old_parent = NULL;
+            int i_old_index = 0;
+
+            p_item = [[o_all_items objectAtIndex:i] pointerValue];
+            p_old_parent = [self parentOfItem: p_item];
+            if( !p_old_parent )
+            continue;
+            /* We may need the old index later */
+            if( p_new_parent == p_old_parent )
+            {
+                int j;
+                for( j = 0; j < p_old_parent->i_children; j++ )
+                {
+                    if( p_old_parent->pp_children[j] == p_item )
+                    {
+                        i_old_index = j;
+                        break;
+                    }
+                }
+            }
+
+
+            /* If we move the playing item in a different node or we move the
+               node containing the playing item in a different node, then stop
+               playback, or the playlist refuses to detach the item. */
+/*            if( p_playlist->status.i_status != PLAYLIST_STOPPED &&
+                (( p_item == p_playlist->status.p_item &&
+                p_new_parent != p_old_parent) ||
+                ( p_item->i_children > 0 &&
+                [self isItem: p_playlist->status.p_item inNode:p_item] == YES))
+            {
+                playlist_Stop( p_playlist );
+            }*/
+            vlc_mutex_lock( &p_playlist->object_lock );
+            // Acually detach the item from the old position
+            if( playlist_NodeRemoveItem( p_playlist, p_item, p_old_parent ) ==
+                VLC_SUCCESS  &&
+                playlist_NodeRemoveParent( p_playlist, p_item, p_old_parent ) ==
+                VLC_SUCCESS )
+            {
+                int i_new_index;
+                /* Calculate the new index */
+                if( index == -1 )
+                i_new_index = -1;
+                /* If we move the item in the same node, we need to take into
+                   account that one item will be deleted */
+                else if((p_new_parent == p_old_parent &&
+                                                i_old_index < index + (int)i)
+                       || p_new_parent == p_playlist->p_general || index == 0 )
+                i_new_index = index + i;
+                else
+                i_new_index = index + i + 1;
+                // Reattach the item to the new position
+                playlist_NodeInsert( p_playlist, i_current_view, p_item,
+                                                    p_new_parent, i_new_index );
+            }
+            vlc_mutex_unlock( &p_playlist->object_lock );
+        }
+        [self playlistUpdated];
+        i_row = [o_outline_view rowForItem:[o_outline_dict
+            objectForKey:[NSString stringWithFormat: @"%p", p_item]]];
+
+        if( i_row == -1 )
+        {
+            i_row = [o_outline_view rowForItem:[o_outline_dict
+            objectForKey:[NSString stringWithFormat: @"%p", p_new_parent]]];
+        }
+
+        [o_outline_view deselectAll: self];
+        [o_outline_view selectRow: i_row byExtendingSelection: NO];
+        [o_outline_view scrollRowToVisible: i_row];
+
+        vlc_object_release(p_playlist);
+        return YES;
+    }
+
+    else if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
     {
         int i;
         playlist_item_t *p_node = [item pointerValue];
@@ -1506,6 +1715,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
                 }
                 if( i_counter == p_node->i_parents )
                 {
+                    vlc_object_release(p_playlist);
                     return NO;
                 }
             }
index 1521c3fa545414661c103486abd0430d2b05bd24..7f3eb82c7bf0ea2aaa7e62b72fafe27eefb6b9a8 100644 (file)
@@ -496,14 +496,14 @@ int playlist_NodeInsert( playlist_t *p_playlist,
 }
 
 /**
- * Deletes an item from the children of a node
+ * Deletes a parent from the parent list of a node
  *
  * \param p_playlist the playlist
  * \param p_item the item to remove
  * \param p_parent the parent node
  * \return VLC_SUCCESS or an error
  */
-int playlist_NodeRemoveItem( playlist_t *p_playlist,
+int playlist_NodeRemoveParent( playlist_t *p_playlist,
                         playlist_item_t *p_item,
                         playlist_item_t *p_parent )
 {
@@ -513,6 +513,34 @@ int playlist_NodeRemoveItem( playlist_t *p_playlist,
         msg_Err( p_playlist, "invalid node" );
    }
 
+   for( i = 0; i < p_item->i_parents; i++ )
+   {
+       if( p_item->pp_parents[i]->p_parent == p_parent )
+       {
+           if( p_item->pp_parents[i] )
+           {
+               free( p_item->pp_parents[i] );
+           }
+           REMOVE_ELEM( p_item->pp_parents, p_item->i_parents, i );
+       }
+   }
+   p_item->i_serial++;
+   return VLC_SUCCESS;
+}
+
+/**
+ * Deletes an item from the children of a node
+ *
+ * \param p_playlist the playlist
+ * \param p_item the item to remove
+ * \param p_parent the parent node
+ * \return VLC_SUCCESS or an error
+ */
+int playlist_NodeRemoveItem( playlist_t *p_playlist,
+                        playlist_item_t *p_item,
+                        playlist_item_t *p_parent )
+{
+   int i;
    for( i= 0; i< p_parent->i_children ; i++ )
    {
        if( p_parent->pp_children[i] == p_item )