Bindings, reordering des rows et flag de modification
Bonjour à tous !
Je suis en train de faire un petit outils sous MacOSX qui utilise quasiment uniquement les bindings. En effet c'est pour de la gestion d'un petit catalogue et sans une seule ligne de code j'ai déjà pu faire fonctionner le tout, ça m'impressionne toujours autant ces bindings
Du coup l'utilisateur peut naviguer dans les données via mon interface, mais aussi les modifier.
Oui mais voilà j'ai deux petites questions :
PS : Pour info la structure de mes données est la suivante : un NSMutableArray "catalog", qui contient un tableau de NSDictionary représentant des catégories. Une catégorie = un nom + un tableau d'éléments, donc un autre NSMutableArray contenant à son tout des NSDictionaries. Pour gérer tout ça j'utilise deux NSArrayControllers dans mon XIB, un pour le tableau de catégories (dont le contentArray est bindé à mon catalogue) et un pour le tableau des éléments de la catégorie sélectionnée (dont le contentArray est bindé sur le model key path "selection.items" du premier ArrayController)
Je suis en train de faire un petit outils sous MacOSX qui utilise quasiment uniquement les bindings. En effet c'est pour de la gestion d'un petit catalogue et sans une seule ligne de code j'ai déjà pu faire fonctionner le tout, ça m'impressionne toujours autant ces bindings

Oui mais voilà j'ai deux petites questions :
- y a-t-il un moyen de savoir quand mes ArrayControllers et mes bindings modifient les données, de sorte que je puisse mettre un flag shouldSave à YES, pour ne proposer ensuite de sauver le catalogue quand on quitte que s'il a été modifié ?
- comment peut-on (directement avec les bindings sans code ou avec code ?) permettre de réarranger les lignes d'un NSArrayController ? De sorte que l'utilisateur puisse faire passer un élément qui est en 3e position en 5e ou 1ère position par exemple, avec un simple drag & drop de la row de la tableView ?
PS : Pour info la structure de mes données est la suivante : un NSMutableArray "catalog", qui contient un tableau de NSDictionary représentant des catégories. Une catégorie = un nom + un tableau d'éléments, donc un autre NSMutableArray contenant à son tout des NSDictionaries. Pour gérer tout ça j'utilise deux NSArrayControllers dans mon XIB, un pour le tableau de catégories (dont le contentArray est bindé à mon catalogue) et un pour le tableau des éléments de la catégorie sélectionnée (dont le contentArray est bindé sur le model key path "selection.items" du premier ArrayController)
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
1) Les controllers adoptent tous les protocoles NSEditor et NSEditorRegistration, tu devrais donc pouvoir suivre les modifications
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html#//apple_ref/doc/uid/20002373-200965
Pour le 2) je suis preneur d'une solution simple. Pour l'instant je ne connais que ce qu'Apple propose http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/DragandDrop/UsingDragAndDrop.html%23//apple_ref/doc/uid/20000726-BABFIDAB
Pour le Drag & Drop merci pour le lien c'est nickel je vais essayer ça... Bon ça veut donc dire qu'il faut le coder, que les NSArrayControllers ne savent à priori pas le gérer tout seul... dommage mais bon, c'est sans doute qu'on prend vite l'habitude de ne pas écrire une seule ligne de code quand on a commencé à utiliser les bindings que du coup on est choqué d'avoir à en écrire 10
?
Pour en être certain j'ai fait un projet rapidement avec un tableau qui contient un dictionnaire, mis dans IB une vue tableau avec une colonne liée à la valeur du dico via un NSArrayController et ajouté dans le AppDelegate
Une fois lancée l'appli si je clique dans la vue tableau et que je change la valeur j'obtiens bien
Pas de besoin de sous-classer ??
Pour ce genre de choses, la méthode classique est quand même d'utiliser l'undo manager.
Je sais bien que tu bidouilles un truc vite fait, mais on en revient toujours au même principe: Cocoa est facile à utiliser tant que l'on fait des choses standard.
Donc d'après la doc c'est NSArrayController qui implémente objectDidEndEditing (et qu'il faudrait donc sous-classer pour implémenter son propre comportement là -dedans), c'est pas un message envoyé à un delegate du NSArrayController et encore moins au AppController (qu'est ce qu'il vient faire là -dedans, le delegate de l'application, qui n'est à priori pas le delegate du NSArrayController ?)
J'ai dû louper un truc dans la doc moi... car ton test marche d'après ce que tu dis et tant mieux ça m'arrange... mais j'aimerais bien comprendre pourquoi :P
Si tu veux le test je te l'envoie :-)
Si tu double-cliques sur objectDidEndEditing: en tenant la touche commande enfoncée tu peux remonter jusqu'à la définition de la méthode. Sauf dans le cas où elle est définie dans plusieurs endroits auquel cas tu as un pop-up pour choisir.
objectDidEndEditing est donc définie pour NSObject via NSKeyValueBinding.h en plus des NSObjectController
Etant définie elle est appelée, et il me semble que c'était voulu au départ par Apple..
Cela veut dire que n'importe quel NSObject a le droit d'être un delegate d'un objet B donné. Ce n'est pas pour autant que les méthodes sont appellées dans tout et n'importe quoi et dans n'importe quel type d'objet : ce n'est pas parce que la méthode est déclarée qu'elle est appellée sur tous les NSObjects par tous les NSControllers.
(Exemple type, pour NSURLConnection, -- qui est encore une des rares classes usuelles à utiliser des protocoles informels depuis que les protocoles formels ont la possibilité de déclarer les méthodes @optional et que tout est maintenant migré du coup vers les protocoles formels -- tu as les méthodes [tt]connection:didFailWithError:[/tt] ou [tt]connectionDidFinishLoading:[/tt] qui sont des méthodes de delegate mais déclarées comme un protocole informel, donc comme catégorie de NSObject. Mais c'est pas pour autant que ces méthodes sont appellées sur tous les objets dans lesquels tu les déclares, et que par exemple si tu implémentes ces méthodes dans ton AppDelegate elles seront appellées par tous les NSURLConnection que tu vas utiliser dans ton appli ! (et encore heureux que ça ne se passe pas comme ça !). Elles ne sont appellées que sur l'objet qui est déclaré comme "delegate" de ton NSURLConnection, ce delegate pouvant être n'importe quel NSObject mais encore faut-il indiquer à NSURLConnection quel est cet objet qui servira de delegate.
Or pour NS(Array)Controller on ne le fait pas, il n'y a pas de notion de delegate d'indiquée dans la doc nous permettant d'indiquer l'objet qui servira de delegate (qui pourrait si on le choisissait être notre AppDelegate, soit l'objet servant de delegate également à ta NSApplication, mais là on peut même pas le choisir). Au contraire l'application dit que ce protocole informel NSEditorRegistration est implémenté par NSController, ce qui veut dire que c'est NSController lui-même qui est conforme au protocole NSEditorRegistration, c'est lui qui implémente les méthodes [tt]objectDidEndEditing:[/tt] & co, c'est pas un autre objet (comme par exemple ton AppDelegate) qui sert de delegate et qui se devrait pour cela d'être conforme au protocle NSEditorRegistration...
Donc il manque toujours un maillon dans l'explication, c'est pas cohérent en tout cas avec la doc....
je testerai ce soir en faisant comme toi, en implémentant les méthodes dans mon AppDelegate et en mettant un breakpoint dedans pour comprendre la callstack, mais même si ça marche je persiste à dire que c'est louche, soit ils ont pas tout dit dans la doc (le plus probable à mon avis vu ce que tu décris) soit c'est un effet de bord bizarre...
En tout cas c'est comme ça que je le vis mais je ne demande qu'à être éclairé :-)
Bon bah c'est donc qu'ils avaient oublié de précisé que la notification était aussi envoyée à l'objet bindé au NSArrayController alors.
J'attaque le reordering des rows (pour l'instant j'ai suivi la doc Apple, ça marche pas j'ai beau cliquer sur une ligne et essayer de la changer de place il ne fait que sélectionner la suivante... mais bon je creuse j'ai dû zapper un truc)
[EDIT] C'est bon ça marche (l'erreur conne, j'avais oublié de relier un IBOutlet) pour le reordering aussi !
Merci bien en tout cas maintenant tout marche nickel. Un peu "déçu" que le reordering soit pas automatique avec les bindings, mais bon :P
Probablement pas autant que moi quand j'en ai eu besoin !
Je suis très content d'avoir pu t'aider !
ça s'arrose
Dur dur le réveil, le Picon bière c'est plutôt traitre comme breuvage, Perrier pour le restant de la journée ;-)
Mais la nuit portant quand même conseil, ce matin en me remettant dans ma machine je me suis souvenu d'un projet exemple d'Apple pour le drag 'n drop qui s'appelait Bookmarks (la mémoire humaine est supérieure à l'informatique en ce sens qu'elle fonctionne même quand le système est au repos
Par contre pas moyen de remettre la main dessus depuis la documentation Xcode, en fait c'est un projet récupéré depuis le site http://homepage.mac.com/mmalc/CocoaExamples/controllers.html il y a juste à changer le SDK d'origine (10.4) pour le faire tourner.
Il n'est pas impossible que ma mémoire ait défailli parce qu'il utilise une sous-classe de NSArrayController et que j'ai souvent lu qu'il ne fallait pas faire ça. Pourtant le copyright des fichiers semble être d'Apple ...
Dommage parce que du coup tu n'aurais pas eu de difficulté pour implémenter en plus didEndEditing ..
Je le mets en pièce jointe, au cas où il intéresserait quelqu'un d'autre, avec un DNDArrayController il n'y a besoin de rien s'occuper pour ajouter le Drag 'N Drop à une vueTableau ..
Mais merci quand même ça pourra servir pour d'autres de toute façon