Coller de l'Excel ou du Numbers dans une NSTableView?
Bonjour,
Je butte sur une façon (relativement) sûre de coller des données en provenance d'un tableur dans une NSTableView.
Les données arrivent en principe sous forme RTF. Pour le moment j'essaie la méthode barbare "et largement insatisfaisante" de passer par un collage dans une NSTextView temporaire et je récupère ensuite sa NSString que je redécoupe laborieusement pour en faire des "cellules" que je crée ensuite dans la TableView. Mais comme je vous l'ai dit, c'est moche et assez aléatoire. Je n'aimerais pas mettre des barrières à l'utilisateur ou l'obliger à coller/recopier via une autre application.
Dès lors comment faire? On ne peut pas dire que la doc abonde. J'ai lu en diagonale celle sur NSTextTable etc. mais je ne vois pas comment poursuivre de ce côté-là .
Mon but est de détecter si le contenu du presse-papiers est recevable, puis de le traduire en un contenu utilisable par le contrôleur de ma NSTableView (les données sont Core Data, mais c'est un détail).
Toute aide, suggestion ou documentation est la bienvenue. D'avance merci.
Réponses
Pour simplifier, disons que les données proviennent d'un fichier texte, dans lequel les tabulations délimitent les colonnes, et les retours à la ligne délimitent les lignes. Je pense que tu vois comment on ferait: on créerait une NSString à partir du fichier, on découperait cette NSString (avec -componentsSeparatedByString:), et enfin on pourrait nourrir notre modèle.
Pour le presse-papiers, c'est pareil, sauf qu'on récupère une NSData. Par exemple, si tu déclares que ton appli accepte le type "texte", alors la NSData correspondra à un chaà®ne, et tu pourras instancier une NSString avec -initWithData:encoding:.
Maintenant, tout la question est de savoir ce que Numbers ou Excel mettent dans le presse-papiers, et comment tu vas le parser. Normalement, une appli déclare plusieurs types qu'elle est capable d'exporter. Par exemple, si elles sont capables d'exporter en HTML, ça peut-être intéressant pour toi, parce que tu n'auras qu'à trouver une balise <table>.
Il faut décomposer le problème, et tu verras que le fait de faire intervenir une vue est la dernière chose à faire.
Tu sais récupérer des données du pasteboard et notamment la liste des formats disponibles ?
Tu sais transformer ces données (NSData) en texte ?
Tu sais parser du RTF ?
Tu sais découper une chaine selon des séparateurs ?
Tu sais mettre des données dans Core Data ?
Tu sais mettre du texte issu d'un modèle dans une NSTableView ?
Si tu sais répondre oui à toutes ces questions alors tu sais comment faire.
Si tu poses la question, c'est sans doute qu'il y a une chose qui te parait obscure dans toutes ces étapes. Il n'y a qu'en décomposant que tu trouveras où se trouve la partie qui te gêne.
En l'occurrence, s'il s'agit de décoder le RTF (ce qui n'est peut-être pas la seule solution puisque le clipboard peut contenir plusieurs formats), regarde peut-être la fonction suivante :
@Céroce : Je ne pars pas de la partie vue, j'utilise par paresse le "paste" de NSTextView pour récupérer le contenu du pasteboard. Mais je ne vais certainement pas partir de la couche Modèle non plus: la commande "coller" aboutit au contrôleur de la NSTableView, et ce sera à lui de créer les entités Core Data qui correspondent au contenu du pasteboard.
Maintenant, c'est affaire de parsing, à n'en pas douter. Je parse actuellement une NSString, en y repérant les TAB et les RETURN et en découpant ma chaà®ne. Mais ça ne fonctionne pas terriblement bien. Excel, dans sa partie RTF, semble tout séparer par des sauts de lignes.
Mon problème est donc : récupération et parsing.
Non, ce n'est pas le bon endroit.
Le contrôleur doit interagir avec le pasteboard, en extraire les données brutes et ensuite passer ces données sous formes de NSData ou de NSString à une classe du modèle (ou à une classe utilitaire ou factory, tu l'appelleras comme tu veux) qui va créer les objets dans Core Data.
Imagine toi, que ton outil gagne une fonction importer qui utilise le même format de donnée, ou qu'ils doivent traiter les mêmes données en batch par la ligne de commande ou même que tu décides de faire des tests unitaires. Bref, y'a t-il une bonne raison de coupler ce code avec le contrôleur ?
Ca ne coute pas grand chose de créer une classe ou même une méthode de classe dans les modèles qui va faire ce travail. Ca te permettra de bien séparer les traitements et de commencer à construire quelque chose plutôt que de commencer à rendre ton contrôleur moins lisible.
Le contrôleur ne doit pas être un fourre-tout mais un lieu de passage.
Je repose la question de Céroce, es-tu certain que le RTF est un bon choix pour la récupération et le parsing ?
N'y a t-il pas un format mieux structuré dans ton pasteboard ? (html, csv, ou autre ?)
FKDEV,
Comment récupérer les types stockés dans le pasteboard? il y a pas mal d'exemples pour y coller des données, et d'autres qui montrent son fonctionnement interne à l'application (genre drag&drop) mais pas grand-chose sur la récupération de données externes.
Je devrais pouvoir vérifier si des données compatibles existent, par exemple pour valider la commande "Coller" dans le menu Edition, puis à l'exécution de cette commande, parser le contenu et créer les objets (d'accord avec une classe dédiée à cette création, d'ayant plus que cette création est différée par Core Data après l'exécution de la boucle d'événement et qu'un view controller n'est pas le meilleur endroit pour bidouiller le managed context)...
- (NSArray *)types de NSPasteBoard.
Tu devrais lire le NSPasteBoard programming guide. Il y a des exemples.
Je crois qu'il y a aussi une méthode pour vérifier la présence de types spécifiques.
La liste des types standard est définis quelque part dans la doc de NSPasteBoard.
Le petit souci que je rencontre lors du parsing c'est la fin de ligne. Toutes les applications ne sont pas d'accord pour le code de fin de ligne.
Excel : \r
Numbers : \n
Avant de parser les lignes (au moins tout le monde est d'accord pour séparer les champs pas \t) je suis donc obligé de vérifier la présence de l'un des deux. Puis selon le cas je fais
ou "\r" pour le désopilant Excel.
ça n'a pas "l'élégance" des solutions à 200 lignes faisant appel à NSScanner (genre "là je crois que j'ai pensé à tout") mais ça fonctionne. Après ça, si mon utilisateur colle du texte folklorique, il pourra toujours taper commande-Z face à la bouillie que ça donnera...
Merci FKDEV, le type du csv est représenté par NSAttributedString, je n'ai rien déniché de mieux...
Bonjour,
Juste pour info,il existe une library payante pour lire / écrire des fichier Excel
Voir ici http://www.libxl.com/
Merci devulder, mais j'aime autant en arriver à ça:
Et en plus c'est gratuit