Prise en charge de l'accès concurrent au plan de travail

Nous avons vu que la structure de l'interface utilisateur JFace permet la prise en charge standard de l'affichage de la progression des tâches dans une boîte de dialogue (pour plus d'informations, reportez-vous à la section Opérations longues). Dans la section Infrastructure d'accès concurrent, nous avons étudié la prise en charge de l'exécution de la plate-forme pour l'accès concurrent et les opérations longues. A présent, nous allons observer comment l'interface utilisateur de la plate-forme améliore cette infrastructure dans le package org.eclipse.ui.progress. Ce package met à disposition l'interface utilisateur pour afficher la progression des tâches dans le plan de travail et définit la prise en charge complémentaire pour les tâches qui s'exécutent sur l'unité d'exécution de l'interface utilisateur.

Regardons d'abord les différentes opérations d'arrière-plan en cours de fonctionnement et comment elles s'affichent sur l'interface utilisateur du plan de travail :


Dans un environnement où plusieurs événements peuvent se produire en même temps, un utilisateur a besoin des éléments suivants :

Service de progression

Le service de progression du plan de travail (IProgressService) est l'interface principale pour la prise en charge de la progression dans le plan de travail. Ce service est disponible à partir du plan de travail et est utilisé pour afficher la progression pour les opérations en tâche de fond et les opérations qui sont exécutées au niveau de l'unité d'exécution de l'interface utilisateur. L'objectif principal de cette classe est de proposer un point unique pour exécuter des opérations, supprimer la nécessité, pour les développeurs de plug-ins, de déterminer le plug-in à utiliser pour afficher la progression dans une situation donnée. Un autre avantage est que la boîte de dialogue de progression affichée avec ces méthodes permet une prise en charge appropriée pour indiquer le blocage d'une opération par une autre opération et donner à l'utilisateur le moyen de contrôler la résolution du conflit. Lorsque cela est possible, les opérations longues doivent être exécutées à l'aide de IProgressService#busyCursorWhile:

   IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
      public void run(IProgressMonitor monitor) {
         // Pour effectuer un travail qui n'est pas associé à l'interface utilisateur
      }
   });

Cette méthode utilise à l'origine un curseur indiquant l'état d'occupation et le remplace par une boîte de dialogue de progression si l'opération dure au-delà d'une durée seuil spécifiée. L'avantage de cette méthode par rapport à une boîte de dialogue de progression est que si l'opération est courte, la boîte de dialogue ne s'affiche pas. Si votre opération doit mettre à jour l'interface utilisateur, vous pouvez toujours utiliser Display.asyncExec ou Display.syncExec pour exécuter le code qui modifie l'interface utilisateur.

Si une opération doit être exécutée dans son intégralité dans l'unité d'exécution de l'interface utilisateur, alors vous devez utiliser IProgressService#runInUI. L'avantage de cette méthode est qu'elle affiche une boîte de dialogue de progression si l'opération est bloquée tout en donnant le contrôle à l'utilisateur.

   progressService.runInUI(
      PlatformUI.getWorkbench().getProgressService(),
      new IRunnableWithProgress() {
         public void run(IProgressMonitor monitor) {
            // Pour effectuer un travail associé à l'interface utilisateur
         }
      },
      Platform.getWorkspace().getRoot());

Le troisième paramètre peut prendre la valeur null ou il peut s'agir d'une règle de planification pour l'opération. En pareil cas, nous spécifions la racine du plan de travail qui va, pour l'essentiel, verrouiller l'espace de travail lorsque l'opération de l'interface utilisateur est exécutée.

Vous pouvez également enregistrer une icône d'une famille de tâches dans le service de progression afin que la vue de progression puisse afficher l'icône en regard de la tâche en cours d'exécution. Voici un exemple qui montre comment une famille de tâches créée automatiquement est associée à une icône :

   IProgressService service = PlatformUI.getWorkbench().getProgressService();
   ImageDescriptor newImage = IDEInternalWorkbenchImages.getImageDescriptor(
      IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC);
   service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_MANUAL_BUILD);
   service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_AUTO_BUILD);

Affichage indiquant qu'un composant est occupé

IWorkbenchSiteProgressService comprend une API pour la planification des tâches qui modifient l'apparence d'un composant du plan de travail lors de l'exécution de la tâche. Si votre plug-in exécute des opérations d'arrière plan qui affectent l'état d'un composant, vous pouvez planifier la tâche via le composant. Ainsi l'utilisateur est averti par un retour que le composant est occupé. Voici un exemple :

   IWorkbenchSiteProgressService siteService =
      (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class);
   siteService.schedule(job, 0 /* now */, true /* use the half-busy cursor in the part */);

Propriétés de progression pour les tâches

Le plan de travail définit les propriétés liées à la progression des tâches dans IProgressConstants . Celles-ci peuvent être utilisées pour contrôler l'affichage d'une tâche dans la vue de progression. Ces propriétés peuvent également être utilisées pour indiquer à la vue de progression de conserver (IProgressConstants#KEEP_PROPERTY) la tâche dans la vue une fois qu'elle est terminée, ou de ne conserver (IProgressConstants#KEEPONE_PROPERTY) qu'une tâche à la fois dans la vue. Vous pouvez également associer une action (IProgressConstants#ACTION_PROPERTY) à une tâche. Lorsqu'une tâche possède une action associée, la vue de progression affiche un lien hypertexte afin que l'utilisateur puisse exécuter l'action. Vous pouvez également savoir si une tâche utilisateur est actuellement affichée dans une boîte de dialogue de progression (IProgressConstants#PROPERTY_IN_DIALOG). Une indication dans la partie inférieure droite de la ligne d'état signale lorsqu'une action est disponible. L'exemple suivant utilise ces propriétés :

   Job job = new Job("Do Work") {
      public IStatus run(IProgressMonitor monitor) {
         // do some work.  
         // Keep the finished job in the progress view only if it is not running in the progress dialog
         Boolean inDialog = (Boolean)getProperty(IProgressConstants.PROPERTY_IN_DIALOG);
         if(!inDialog.booleanValue())
            setProperty(IProgressConstants.KEEP_PROPERTY, Boolean.TRUE);
      }
   };
   job.setProperty(IProgressConstants.ICON_PROPERTY, Plugin.getImageDescriptor(WORK_IMAGE));
   IAction gotoAction = new Action("Results") {
      public void run() {
         // Pour afficher les résultats
      }
   };
   job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction);
   job.setUser(true);
   job.schedule();

Tâches du plan de travail

Lorsque cela est possible, les opérations longues doivent être réalisées en dehors de l'unité d'exécution de l'interface utilisateur. Cependant, il n'est pas toujours possible d'éviter cet état de fait lorsque l'objectif de l'opération est de mettre à jour l'interface utilisateur. La section Problèmes liés aux unités d'exécution SWT explique comment cette opération peut être réalisée à l'aide de l'affichage SWT. Le plan de travail définit une tâche spéciale, UIJob, dont la méthode run est exécutée dans un élément asyncExec SWT. Les sous-classes de UIJob doivent implémenter la méthode runInUIThread au lieu de la méthode run.

WorkbenchJob étend UIJob afin que la tâche ne puisse être planifiée ou exécutée que lorsque le plan de travail est en cours d'exécution. Comme toujours, vous devez éviter le travail en excès au niveau de l'unité d'exécution de l'interface utilisateur car celle-ci n'est pas actualisée pendant la durée de la tâche de l'interface utilisateur.