NSUndoManager & NSDocument " Quelle architecture adopter ?
Hello à tous
Toujours pour ma Document Based Application, j'aurais besoin de vos conseils sur l'architecture et l'organisation à adopter.
Je sais bien qu'il n'y a pas forcément de vérité absolue dans ce domaine, mais j'aimerais bien tenir compte de vos conseils/expériences.
En gros, j'ai mon NSDocument, un NSWindowManager, et un NSViewController.
Mon NSViewController gère une outline view (c'en est le delegate et le datasource).
Mon outline view gère des objets "Item" qui comportent des méthodes pour gérer l'arborescence.
Le NSViewController fait appel à ces méthodes quand il reçoit des actions.
Le truc c'est que le NSUndoManager est dans mon NSDocument, mais le meilleur endroit pour déterminer l'action "undo" à appeller, c'est à l'intérieur des méthodes de ma classe model "Item.
D'ailleurs j'ai vu dans le programming guide qu'Apple recommande de placer les appels à l'undo manager dans les classes modèles quand cela est possible.
Du coup j'aimerais savoir comment accéder à l'undo manager de mes classes modèles ? je le fait passer par une property à chaque fois que je créé une instance de cette classe ?
Je voulais utiliser la responder chain (en faisant hériter mes classes modèle de NSResponder) afin d'utiliser la feature décrite ici, mais le undoManager récupéré est nil.
Du coup voilà je sais pas trop.
J'hésitais même à déplacer mes méthodes permettant de manipuler mes objets "Item" directement dans le NSDocument, mais du coup elle deviendront trop dépendante de ce NSDocument, alors que j'aimerais pouvoir les réutiliser dans une future application.
Bref, j'ai écris beaucoup pour pas dire grand chose, mais bon, j'espère que vous saurez m'aider
Réponses
J'ai déjà rencontré le problème. Il me semble que je l'ai résolu très simplement: sachant que l'undo manager est maintenu par le NSDocument, et que les modèles aussi, j'ajoutais une propriété undoManager à chaque objet du modèle.
Ah voilà , en fait j'avais une seconde question dans le cas où je fais tout dans les classes modèles : comment vous faite pour rafraichir l'UI afin de prendre en compte les modifs ? Vous envoyez une notif ?
Ben non, les bindings sont là pour ça!
Si tu utilises un data source pour l'outline view, tu peux toujours te rabattre sur le KVO.
Non j'utilise pas les bindings. J'ai trouvé ça trop complexe pour faire avec les bindings. Après c'est ptet juste que je connais pas assez.
Mais sinon en fait j'ai vu que y'avait ces deux notifs qui sont automatiquement envoyées, c'est parfait pour moi : NSUndoManagerDidUndoChangeNotification & NSUndoManagerDidRedoChangeNotification
Et du coup dans une classe modèle, si vous avez un méthode genre setName: vous géré comment le fait que dans certains cas il faudra appeler le undo manager mais pas dans d'autre ?
Par exemple si le setName: est appelé en interne par un init, il faut pas ajouter un élément à l'undo stack. Mais si le rename est fait par l'user alors là oui.
Perso j'ai fait un truc du type setUndoableName: en plus du setName: mais je veux bien connaitre votre façon de faire.
Je faisais comme toi, j'avais un deuxième setter, du genre -setPrimaryName: en plus de -setName:.
Sinon pourquoi vous ne placez pas une référence au NSDocument plutôt qu'au undo manager dans chaque item. Ainsi l'item signale au document qu'une action a eu lieu, et c'est le document qui décide de reporter ou non l'action au undo manager en fonction du contexte (relecture de fichier, première initialisation, etc).
L'idée étant que l'item n'a pas à connaitre le contexte mais juste à faire son job toujours de la même manière, le fait que l'action soit enregistrée ou non, c'est pas son problème.
Cela fait une indirection en plus mais cela vous permet d'accéder éventuellement à d'autres ressources maintenues par le document.
C'est le même principe lorsqu'un objet se dessine sur un context graphique. Il n'a pas à savoir s'il s'agit de l'écran ou de l'imprimante derrière le contexte.
Là c'est pareil mais avec un contexte d'action plutôt qu'avec un contexte de dessin.
Au fond je préfère avoir juste une référence à mon undo manager avec des méthodes undoable.
Pourquoi ? car le lier au document est trop fort à mon goût. Je prévois de peut-être réutiliser ces classes modèle dans une future application. Et pas sûr que je me base sur un NSDocument par contre, mais il y aura probablement un Undo Manager.
Et puis même sans ça, je trouve que passer par le NSDocument au lieu du NSUndoManager est inutile. Comme tu dis, "l'idée étant que l'item n'a pas a connaitre le contexte mais juste à faire son job", or, en le liant au document, on lui donne un contexte. Je préfère la solution setter + setter undoable.
L'idee, en fait, ce n'est pas forcement d'utiliser le NSDocument mais d'ajouter une indirection entre ton item et le undomanager.
Ainsi tu pourras aiguiller ton objet soit sur le undomanager, soit sur rien, sans qu'il ait le besoin de le savoir.
Le fait de vouloir reutiliser est un autre probleme, si tu veux réutiliser, passe par un protocol pour implementer ton contexte.
Quand tu fais setUndoableName, tu ajoutes un deuxieme couplage au moment où l'action est effectuee. Ce couplage est inutile et risque de te gener plus tard.
(...)
Apres avoir regardé la doc, je vois qu'il existe déjà un mécanisme pour desactiver l'undomanager :
disableUndoRegistration / enableUndoRegistration.
Pourquoi ne pas l'utiliser ?