Table des matière du kit d'application      Index du kit d'application

Scripts

Les scripts fournissent un moyen de contrôler par programme une autre application en lui envoyant ses commandes de scripts spécifiques. Ces commandes sont définies par l'application "scriptée" elle-même. Par exemple, si vous voulez qu'une autre application soit capable de dire à votre application d'effectuer l'opération "Retournement", vous devez publier le format de la commande "Retournement". L'ensemble des opérations que vous souhaitez rendre public est appelée une "suite."

BeOS définit un certain nombre de suites correspondant à des classes spécifiques. Par exemple, tous les objets BApplication répondent aux commandes définies dans la suite "vnd.Be-application". Une des commandes de la suite vous donne accès aux fenêtres de l'application. Une fois localisée la fenêtre désirée, vous pouvez la déplacer, la fermer, la redimensionner, et ainsi de suite, en fonction des commandes de la suite "vnd.Be-window".


Notions de base

Le cadre de travail des scripts définit les notions suivantes : commandes, propriétés, et spécifieurs. Si AppleScript vous est familier, ells sont équivalentes aux verbes, nouns, et adjectifs. Les commandes agissent sur l'instance spécifique d'une propriété, déterminée par les spécifieurs.


Commandes

Une commande transmet l'action d'un script de commande et est stockée dans le champ what du BMessage de script. Il existe six commandes standard (définies dans be/app/Message.h) :

Chacune de ces commandes agit sur une "propriété," qui n'est rien d'autre que la fonction "scriptable" d'un objet. A titre d'exemple réel, les fenêtres appartenant à une application sont des propriétés, de même que le titre de chaque fenêtre. L'interprétation spécifique de la commande dépend de la propriété sur laquelle elle agit. Par exemple, B_DELETE_PROPERTY, agissant sur la propriété "Entry" d'une fenêtre du Tracker, provoque la mise à la corbeille d'un fichier. Toutefois, la même commande, agissant sur la propriété "Selection" de la même fenêtre, ôte des fichiers de la liste des éléments sélectionnés.

Les objets scriptables devraient se limiter à cet ensemble de commandes. Si un objet utilise une commande non standard, il encours le risque de ne pas pouvoir être utilisé par les outils de scripts généraux.


Propriétés et Spécifieurs

Une propriété représente une fonction scriptable d'un objet. Les propriétés sont nommées ; ces noms sont des chaînes de caractères, uniques pour une classe. Par exemple, un BWindow définit des propriétés comme "Cadre", "Titre," et "Vue." Le type de données de la propriété et ses valeurs permises sont déterminés par la propriété. Par exemple, le "Cadre" d'une fenêtre accepte des valeurs B_RECT_TYPE alors que le "Titre" est une B_STRING_TYPE.

Parfois une propriété est représentée par un autre objet. Par exemple, "Vue" de BWindow désigne un BView, un objet ayant un ensemble de propriétés distinctes de celles de BWindow.

Un objet peut avoir plus d'une instance d'une propriété donnée. Par exemple, la propriété "Window" de BApplication, a autant d'instances qu'il y a de fenêtres dans l'application. Il en résulte qu'il existe une ambiguïté lorsque vous demandez la Fenêtre d'une application. A la place, il vaut mieux demander la première Fenêtre, ou la Fenêtre nommée "Snyder." Autrement dit, une propriété est insuffisante pour identifier une fonction ; une instance spécifique doit aussi être sélectionnée.

Les spécifieurs sont utilisés pour cibler ("spécifier") des instances spécifiques de propriétés. Un spécifieur est un BMessage contenant les éléments suivants :

Il existe sept constantes standard de spécifieurs (définies dans <be/app/Message.h>) :

Comme pour tous les messages, la signification précise d'un spécifieur donné dépend du contexte. De plus, il peut exister des spécifieurs définis (ou plus exactement des objets définis) par l'utilisateur. Les constantes des spécifieurs définis par l'utilisateur doivent être supérieures à B_SPECIFIERS_END pour éviter les conflits avec les spécifieurs Be.

Les spécifieurs sont ajoutés au champ "spécifieur" d'un message de script en utilisant BMessage::AddSpecifier(). Il existe plusieurs variantes à cette méthode, comprenant des raccourcis pour ajouter les spécifieurs B_DIRECT_SPECIFIER, B_INDEX_SPECIFIER, B_RANGE_SPECIFIER, et B_NAME_SPECIFIER. Pour tous les autres spécifieurs, vous devez construire manuellement le spécifieur et l'ajouter au message de script avec AddSpecifier(). Par exemple, pour ajouter un B_ID_SPECIFIER :

   BMessage specifier(B_ID_SPECIFIER); // crée un nouveau spécifieur
   specifier.AddInt32("id", 2827);    // ajoute l'identifiant au spécifieur
   message.AddSpecifier(&specifier); // ajoute le spécifieur au message
 
Vous devez utiliser AddSpecifier() pour ajouter des spécifieurs à un BMessage ; elle effetue une tâche additionnelle de complément de scripts que AddMessage() ne fait pas.


La pile des spécifieurs

En général, une application ne pourra pas obtenir un BMessenger de l'objet cible ; à la place, elle devra accepter un BMessenger ciblant la BApplication du programme contenant l'objet désiré. Dans ce cas, un spécifieur unique peut être insuffisant pour cibler un message de script. Le vrai pouvoir des spécifieurs tient dans leur habileté à être chaînés ensemble dans la pile des spécifieurs.

Un exemple illustre mieux les opérations sur la pile des spécifieurs. L'échantillon de code suivant crée un message qui vise le cadre de la seconde vue de la fenêtre nommée "egg" dans l'application cible :

   message.AddSpecifier("Label");
   message.AddSpecifier("MenuBar");
   message.AddSpecifier("Window", 1);

Des appels répétés à AddSpecifier() construisent la pile des spécifieurs. L'ordre des appels est très important ; les spécifieurs sont évalués dans l'ordre inverse de leur addition. Quand ce message est reçu par l'application cible, elle retire en premier le troisième spécifieur et dirige le message vers la seconde fenêtre de l'application. Le BWindow retire ensuite le second spécifieur et dirige le message vers la barre de menu de la fenêtre. Le premier spécifieur ("Label") est alors traité par BMenuBar. Ce processus est détaillé plus loin dans "ResolveSpecifier()".


Réponses

Une réponse est générée pour chaque demande de script. Le message de réponse contient les champs suivants :

Tout objet scriptable que vous créez devrait aussi obéir au protocole décrit plus haut. Bien sur, des objets individuels sont libres de définir leurs propres protocoles de transmission d'information additionnelle dans la réponse ; dans ce cas, consultez la documentation de la classe concernée.


Créer et Envoyer des Messages de Script

Les possibilités de scripts d'une application peuvent être invoquées en trois étapes aisées :


Exemple

Supposez que nous voulions aller chercher le cadre rectangle de la seconde vue de la fenêtre intitulée "egg" dans une application portant la signature "application/x-fish". Le code :

   BMessage message, reply;
   BRect result;
   
   // positionne la constante de commande
   message.what = B_GET_PROPERTY;
   
   // construit la pile des spécifieurs
   message.AddSpecifier("Frame"); // B_DIRECT_SPECIFIER
   message.AddSpecifier("View", 1); // B_INDEX_SPECIFIER
   message.AddSpecifier("Window", "egg"); // B_NAME_SPECIFIER
   
   // envoie le message et va chercher le résultat
   BMessenger("application/x-fish").SendMessage(&message, &reply);
   reply.FindRect("result", &result)

est concis et élégant.


Suites

Un élément du système de script est manquant, c'est nommément la possibilité d'interroger un objet sur ses capacités de scripts. C'est utile quand l'application de contrôle ne connait pas le type précis de l'objet auquel elle envoie des scripts. Posséder une méthode pour découvrir les possibilités de scripts d'un objet permet un usage plus dynamique des scripts.

Les capacités de scripts d'un objet sont organisées en une ou plusieurs "suites" de scripts, un ensemble de messages supportés et des spécifieurs associés. Une suite est identifiée par une chaîne de caractères pseudo MIME de supertype "suite". Par exemple, BControl implémente la suite de scripts "suite/vnd.Be-control". Rien n'empêche deux objets de mettre en oeuvre la même suite ; deux éditeurs de son, par exemple, peuvent avoir des implémentations différentes d'une suite de scripts commune pour filtrer des données audio.

Pour interroger un objet sur ses suites de scripts, envoyez un message de script standard avec une demande B_GET_PROPERTY pour la propriété "Suites" :

   message.what = B_GET_PROPERTY;
   message.AddSpecifier("Suites");
   
   ... ajoutez les autres spécifieurs ici ...
   
   messenger.SendMessage(&message, &reply);

L'objet cible répond par un BMessage B_REPLY avec les champs suivants :

D'une utilité plus faible, vous pouvez envoyer un BMessage B_GET_SUPPORTED_SUITES directement à un objet et obtenir ses suites dans une réponse de format identique.

Chaque objet scriptable supporte la suite "suite/vnd.Be-handler" par le biais de son héritage de BHandler. Cette suite est parfois appelée la "suite universelle". Elle accomplit les fonctions suivantes :


Construire des Objets Scriptables

Comme les messages de script sont passés via des BMessengers, les objets acceptant les messages de script doivent hériter de BHandler. Typiquement, ajouter des aménagements pour les scripts n'implique rien de plus que de surcharger un peu les méthodes suivantes :


ResolveSpecifier()

                                                         
  

virtual BHandler *ResolveSpecifier( BMessage *message, int32 index, BMessage *specifier, int32 what, const char *property)


Implémentée par des classes héritées pour déterminer le handler concerné par un message de script. Le message a pour cible le BHandler, mais les spécifieurs peuvent indiquer qu'il doit être assigné à un autre objet. La tâche de ResolveSpecifier() est d'examiner le spécifieur en cours (ou plus, le cas échéant) et de renvoyer l'objet qui devra soit prendre en charge le message soit regarder le spécifieur suivant. Cette fonction est appelée avant que le message soit distribué et avant qu'aucune fonction de filtre ne soient appelée.

Le premier paramètre, message, pointe sur le message de script pris en compte. Le spécifieur courant est passé dans specifier ; il se trouve à l'index index dans le tableau des spécifieurs de message. Enfin, what contient le membre de données what de specifier tandis que property contient le nom de la propriété visée.

ResolveSpecifier() renvoie un pointeur sur le BHandler suivant qui est censé s'occuper du message. Elle dispose ici de quatre options :

      if ( (strcmp(property, "Proxy") == 0)
 
Dans la mesure ou cette fonction a résolu le spécifieur à index, elle appelle PopSpecifier() pour décrémenter l'index avant de faire suivre le message. Sinon, le gestionnaire suivant essaierait de résoudre le même spécifieur.

      if ( proxy ) {
          message->PopSpecifier();
 
En effet, ceci place l'objet renvoyé à la place du BHandler en tant que gestionnaire désigné pour le message. Le BLooper donnera au gestionnaire renvoyé une chance de répondre au message ou de résoudre le spécifieur suivant.

      if ( (strcmp(property, "Value") == 0)
 
Ceci confirme que le BHandler est la cible du message. ResolveSpecifier() ne sera pas appelée de nouveau, il n'est donc pas nécessaire d'appeller PopSpecifier() avant le retour.

L'objet BApplication effectue la première étape en résolvant un spécifieur pour une propriété "Window" ; il envoie le message au BWindow spécifié et renvoie NULL. Un BWindow accomplit la seconde étape en résolvant un spécifieur pour une propriété "View" ; il renvoie le BView spécifié. Ainsi, un message qui ciblait initialement l'objet BApplication peut faire son chemin jusqu'à un BView.

La version BHandler de ResolveSpecifier() reconnait un message B_GET_PROPERTY avec un specifier direct demandant une "Suite" parmi les suites supportées, un "Messenger" pour le BHandler, ou le "InternalName" du BHandler (le même nom que sa fonction Name() renvoie). Dans les trois cas, elle assigne le BHandler (this) en tant qu'objet responsable du message.

Pour tous les autres spécifieurs et messages, elle envoie une réponse B_MESSAGE_NOT_UNDERSTOOD et renvoie NULL. Le message de réponse possède un champ "error" contenant l'erreur B_SCRIPT_SYNTAX et un champ "message" qui contient un texte explicatif de l'erreur plus developpé.


MessageReceived()

                                                         
  

virtual status_t MessageReceived( BMessage *message)


MessageReceived() est appelée pour traiter tout message de script arrivant. Les messages de script sont traités à cet égard comme tout autre BMessage. MessageReceived() doit être implémentée pour effectuer les actions demandées par les commandes de script.


GetSupportedSuites()

                                                         
  

virtual status_t GetSupportedSuites( BMessage *message)


Implémentée par les classes héritées pour rendre compte des suites de messages et des spécifieurs qu'elles interprètent. Cette fonction est appelée en réponse soit à un message de script B_GET_PROPERTY pour la propriété "Suites" soit un message B_GET_SUPPORTED_SUITES.

Chaque classe héritée doit ajouter le nom des suites qu'elle implémente au tableau des "suites" de message. Chaque élément du tableau est une chaîne de caractères pseudo MIME de supertype "suite". De plus, les classes doivent ajouter les objets correspondants mis à plat BPropertyInfo dans le tableau "messages". Une mise en oeuvre typique de GetSupportedSuites() ressemble à :

   status_t MyHandler::GetSupportedSuites(BMessage *message)
   {
      message->AddString("suites", "suite/vnd.Me-my_handler"));
      BPropertyInfo prop_info(prop_list);
      message->AddFlat("messages", &prop_info);
      return BHandler::GetSupportedSuites(message);
   }

La valeur renvoyée par GetSupportedSuites() est ajoutée à message dans le champ int32 "error". La version BHandler de cette fonction ajoute la suite universelle "suite/vnd.Be-handler" à message et renvoie ensuite B_OK.


Table des matières du kit d'application      Index du kit d'application


The Be Book,
...in lovely HTML...
for BeOS Release 5.

Copyright © 2000 Be, Inc. All rights reserved..