Drag & drop entre 2 NSTableView

UniXUniX Membre
23:06 modifié dans API AppKit #1
Salut.

Bon, j'ai un drag & drop qui fonctionne entre 2 NSTableView.
Le problème, c'est que l'opération duplique l'entité déplacée dans la 2ème NSTableView. C'est à  dire que si je modifie l'élément de ma NSTableView de départ, ce changement n'est pas reflété dans la seconde, vu que les 2 éléments ne sont pas identiques, c'est une copie.

Moi, je voudrais que lors du drag & drop, ce ne soit pas une copie mais l'élément de départ qui soit inséré dans la NSTableView d'arrivée ....

Voilà  mon code pour le drag & drop :
- (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pb<br />{<br />	NSMutableArray *lignesTableau = [NSMutableArray array];<br />	NSData *lignesData;<br /><br />	// remplissage du tableau lignesTableau<br /><br />	lignesData = [NSKeyedArchiver archivedDataWithRootObject:lignesTableau];<br />	[pb declareTypes:[NSArray arrayWithObjects:@&quot;drag&quot;, nil] owner:self];<br />	return [pb setData:lignesData forType:@&quot;drag&quot;];<br />}<br /><br />- (NSDragOperation)tableView: (NSTableView *)aTableView validateDrop:(id &lt;NSDraggingInfo&gt;)item proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op<br /> {	<br />	[listeTable setDropRow:row dropOperation:NSTableViewDropOn];<br />	return NSDragOperationMove;<br /> }<br /><br /> - (BOOL)tableView:(NSTableView*)aTableView acceptDrop:(id &lt;NSDraggingInfo&gt;)item row:(int)row dropOperation:(NSTableViewDropOperation)op<br /> {<br />	 NSPasteboard *pboard = [item draggingPasteboard];<br />	<br />	 if ([pboard availableTypeFromArray:[NSArray arrayWithObject: @&quot;drag&quot;]])<br />	 {<br />		 NSData *lignesData = [pboard dataForType:@&quot;drag&quot;];<br />		 NSMutableArray *lignes = [NSKeyedUnarchiver unarchiveObjectWithData:lignesData];<br />		 <br />		 // ajout des objets dans mon tableau d&#39;arrivée<br />	 }<br />	 return YES;<br /> }

Réponses

  • Eddy58Eddy58 Membre
    23:06 modifié #2
    C'est l'archivage qui fait que tes objets sont deep copied. Je suis pas spécialiste du D&D, mais à  la vue des méthodes dans NSPasteBoard, l'archivage est une étape obligée du processus.
    Il y a un moyen, sans affirmer que c'est la meilleure solution bien sûr : si les objets que tu mets dans ton array sont des dictionarys, ou des objets d'une classe modèle, tu rajoutes lors de la création de tes objets une key (en cas de dictionary) ou une variable d'instance (en cas de classe modèle) du genre "ObjectUniqueID". A cet "ObjectUniqueID" tu te débrouilles bien sûr pour affecter des chaines uniques afin de pouvoir différencier les objets.
    Ensuite, quand tu fais une modif dans une table, il faut aller comparer l'"ObjectUniqueID" de l'objet modifié aux "ObjectUniqueID" de l'autre table, et répercuter les changements en conséquence.
    Par contre, avec cette méthode, il faut veiller à  ne pas D&Dropper plusieurs fois le même objet car il y aura à  ce moment des problèmes de doublon dans les "ObjectUniqueID". Donc soit tu interdis le drop si l'objet est déjà  présent, soit tu lui affectes un nouvel "ObjectUniqueID". 
    En dernier lieu, je ne te cache pas qu'une fois ceci fini tu risques d'avoir très soif, mais c'est un autre problème... :P :p :p
  • UniXUniX Membre
    23:06 modifié #3
    Ouais, j'ai fait un truc dans le style que tu m'as dit .... C'est OK.
    Je trouve bizarre qu'il n'y ai rien de prévu de base dans Cocoa pour faire ça ..... Rien n'est parfait .... :)
  • AliGatorAliGator Membre, Modérateur
    23:06 modifié #4
    Ben c'est justement ce qui est prévu, je pense.
    Si tu penses en terme de MVC, tes données manipulées sont dans le modèle, accessibles par tout le monde. Et ensuite tu demandes à  accéder à  ces données via les accesseurs pour les manipuler (Controller) et les afficher (Vue).
    Ce n'est donc pas l'objet qu'il faut archiver, mais l'identifiant qui te sert à  ... l'identifier.
    Tu as sûrement si tu as un bon MVC un moyen propre de récupérer le bon objet : index dans un tableau, clé unique... pour appeler ton accesseur myObjectWithName: ou un truc dans le genre en lui passant un nom unique, non ? ou myObjectAtIndex: ou dans ce goût là .

    C'est ce que tu utilises pour identifier/récupérer ton objet qu'il faut que tu mettes dans le pasteBoard à  mon avis, qui est la référence/identifiant unique.
    Si tu n'avais pas cette clé unique et que tu l'as créée pour l'occasion comme tu sembles le dire, c'est que c'est pas plus mal parce que c'est toujours bon d'avoir de quoi identifier les objets de façon unique... et ça aurait sans doute dû être le cas dès le début si tu avais fait un modèle comme il faut (mais bon le prend pas mal on peut pas penser à  tout et souvent chze moi aussi la clé unique elle passe à  la trappe :D)

    Tout ça pour dire que c'est prévu dans Cocoa dans le sens où Cocoa part de la base que tu as un beau schéma MVC avec un identifiant unique... et que cette solution vient du coup naturellement à  l'esprit.... enfin quand on suit la logique Cocoa ;)
  • UniXUniX Membre
    23:06 modifié #5
    Tu as raison Ali.
    Mon modèle MVC est fait (je pense ...) correctement. J'ai donc repris mon code, et au lieu d'archiver les données elles-mêmes, j'archive la référence du tableau de départ, ainsi que les numéros de lignes des éléments, tout ça dans un NSDictionary.

    Et à  l'arrivée, je n'ai plus qu'à  faire des copies à  partir des informations contenues dans le NSDictionary.

    Merci pour cet éclaircissement bienvenu ...!

    Allez  :p !
  • VeillardVeillard Membre
    23:06 modifié #6
    Rebonjour tout le monde...

    Je me repenche sur mon appli après quelques mois d'abandon  ???
    J'essaie de reprendre les diverses docs sur le Drag & Drop entre 2 NSTableView mais ça ne fonctionne pas, pourtant j'ai repris la doc Apple :

    - (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard&nbsp; &nbsp;  // Drag &amp; Drop<br />{<br />	// Copy the row numbers to the pasteboard.<br />	NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];<br />	[pboard declareTypes:[NSArray arrayWithObject:@&quot;dives&quot;] owner:self];<br />	[pboard setData:data forType:@&quot;dives&quot;];<br />	<br />	return YES;<br />}<br /><br />- (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id &lt;NSDraggingInfo&gt;)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op<br />{<br />	// Add code here to validate the drop<br />	[_plongeesTableView setDropRow:row dropOperation:NSTableViewDropOn];<br />	<br />	NSLog(@&quot;validate Drop&quot;);<br />	return NSDragOperationEvery;<br />}<br /><br />- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id &lt;NSDraggingInfo&gt;)info row:(int)row dropOperation:(NSTableViewDropOperation)operation<br />{<br />	NSPasteboard* pboard = [info draggingPasteboard];<br />	NSData* rowData = [pboard dataForType:@&quot;dives&quot;];<br />	NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];<br />	int dragRow = [rowIndexes firstIndex];<br />	// Move the specified row to its new location...<br />}<br />
    


    J'ai entendu parler du codage des données avant le drop mais qu'en est-il vraiment ?
    A ce propos ça Drag bien mais ça ne Drop rien du tout  :)
  • schlumschlum Membre
    23:06 modifié #7
    Hello

    Ce code est incomplet... D'un côté tu enregistres dans le presse-papier l'index des lignes sélectionnées du tableau d'origine, de l'autre côté, tu récupères la première ligne de cet index mais tu n'en fais rien ("// Move the specified row to its new location...").
    En plus, s'il y a plusieurs tables permettant le drag, il faudrait aussi enregistrer quelque-chose permettant de retrouver la table d'origine, non ?
  • VeillardVeillard Membre
    mars 2007 modifié #8
    Toujours rien, j'ai rajouté ceci mais j'ai dû manquer quelque chose...

    - (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id &lt;NSDraggingInfo&gt;)info row:(int)row dropOperation:(NSTableViewDropOperation)operation<br />{<br />	NSPasteboard* pboard = [info draggingPasteboard];<br />	NSData* rowData = [pboard dataForType:@&quot;dives&quot;];<br />	NSIndexSet* rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:rowData];<br />	int dragRow = [rowIndexes firstIndex];<br />	<br />	Plongee&nbsp; &nbsp; *dives = [_carnet objectAtIndex: dragRow];<br />&nbsp; &nbsp; [dives retain ];<br /><br />&nbsp; &nbsp; [_carnet insertObject:dives atIndex: row ];<br />&nbsp; &nbsp; [dives release ];<br /><br />&nbsp; &nbsp; return YES;<br />}<br />
    


    Je continue...
  • VeillardVeillard Membre
    23:06 modifié #9
    Pour info, j'arrive à  "Droper" sur la TableView source mais pas sur l'autre. En revanche, j'ai bien le liseré noir qui montre que j'ai sélectionné la zone de destination...
  • schlumschlum Membre
    mars 2007 modifié #10
    T'as essayé en debug ? Il passe dans toutes les fonctions ?
    C'est le meilleur moyen de voir où ça cloche  ;)

    (Enfin pas tout en même temps sinon ça n'ira pas... D'abord un breakpoint dans la fonction de drag et ensuite un autre sur la fonction de drop...)
  • VeillardVeillard Membre
    23:06 modifié #11
    Je maà®trise assez mal le debugger. Je pense plutôt comme tu l'as dit plus haut, à  l'identification des différentes tables. A voir...
  • schlumschlum Membre
    23:06 modifié #12
    dans 1172842408:

    Je maà®trise assez mal le debugger. Je pense plutôt comme tu l'as dit plus haut, à  l'identification des différentes tables. A voir...

    On peut débuguer avec des NSLog quand on maà®trise mal gdb  ;)
    Mets en un peu partout, et regarde ce que ça donne...
  • VeillardVeillard Membre
    23:06 modifié #13
    Bon quand je fais un Drag & Drop d'un tableau source qui contient plis d'éléments que le tableau cible, j'ai :
    [tt]*** -[NSCFArray objectAtIndex:]: index (5) beyond bounds (1)[/tt]
    A l'inverse il y a bien une ligne insérée mais le contenu n'est qu'une ligne recopiée du tableau cible correspondant à  la même position sur le tableau source.

    Il n'y a pas de copie d'un tableau à  l'autre mais bien une copie du tableau sur lui-même...
  • schlumschlum Membre
    23:06 modifié #14
    Tu ne dois pas essayer de récupérer du bon tableau...  ???
  • VeillardVeillard Membre
    mars 2007 modifié #15
    Apparemment oui mais les infos ne sortent pas de la table source.
    Je suis preneur de toute proposition pour en finir avec ce Drag & Drop...  :p
Connectez-vous ou Inscrivez-vous pour répondre.