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 sectionOpé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.
Avant de présenter les nouvelles API, commençons par passer en revue quelques concepts. Il convient tout d'abord d'opérer une distinction entre les différents types d'opérations en tâche de fond :
Tâches déclenchées par l'utilisateur. Ces tâches sont définies pour être des tâches utilisateur (Job#setUser). Le plan de travail affiche automatiquement les tâches utilisateur dans une boîte de dialogue modale, indiquant la progression, contenant un bouton pour permettre à l'utilisateur d'exécuter l'opération en tâche de fond et de continuer à travailler. Une préférence globale est utilisée pour indiquer si les tâches utilisateur doivent toujours être exécutées en tâche de fond.
Les exemples de tâches utilisateur incluent la création, la réservation d'un projet, la synchronisation avec le référentiel, l'exportation d'un plug-in et la recherche.Tâches déclenchées automatiquement. Ces opérations ont un sens pour les utilisateurs mais ne sont pas déclenchées à son initiative. C'est le type de tâche par défaut. Ces tâches sont indiquées dans la vue de progression et dans la ligne de statut, mais la boîte de dialogue modale de progression n'affiche pas le moment auquel elles sont exécutées. La création automatique et la synchronisation planifiée en sont des exemples.
Les opérations système. Il s'agit d'opérations qui ne sont pas déclenchées par l'utilisateur et qui peuvent être considérées comme un détail d'implémentation. Ces tâches sont créées en définissant l'indicateur système (Job#setSystem). Les tâches qui peuplent lentement les widgets ou calculent les décorations et les annotations des vues en sont des exemples.
Dans un environnement dans lequel plusieurs éléments peuvent se produire en même temps, l'utilisateur doit :
Savoir quand une opération longue a commencé.
Les tâches utilisateur sont affichées à l'attention de l'utilisateur dans une boîte de dialogue de progression indiquant un retour immédiat, tandis que les tâches déclenchées automatiquement sont affichées dans la ligne de statut et dans la vue de progression. De même, les tâches qui affectent une partie doivent être planifiées ou enregistrées avec la partie afin que le plan de travail puisse signaler à l'utilisateur qu'une opération est en cours d'exécution et qu'elle a un impact sur la partie.
Savoir quand une opération est terminée.
L'utilisateur peut facilement savoir quand des tâches utilisateur prennent fin car la boîte de dialogue de progression se ferme. Pour les tâches autres que les tâches utilisateur, il existe quelques mécanismes de retour. Si la tâche a été planifiée ou enregistrée avec une partie, l'indication de progression des parties s'affiche à la fin. Si une tâche renvoie une erreur, un indicateur d'erreur s'affiche dans la partie inférieure droite de la ligne de statut et signale qu'une erreur s'est produite.
Connaître les nouveaux résultats intéressants ou les nouvelles informations, sans entraver l'affichage des boîtes de dialogue par une opération en tâche de fond.
Une tâche utilisateur peut afficher directement les résultats à l'attention de l'utilisateur lorsque l'opération est terminée. Pour les tâches autres que les tâches utilisateur, il est recommandé de ne pas interrompre l'utilisateur avec une boîte de dialogue. Au lieu de cela, si les résultats des tâches sont affichés dans une vue, la vue peut être ouverte lorsque la tâche commence et que les résultats sont affichés dans la vue. Cela n'a pas pour effet de gêner le flux de travail des utilisateurs. Par ailleurs, vous pouvez ajouter des propriétés à la tâche pour indiquer que cet élément doit être conservé dans la vue de progression et être associée à une action qui affiche les résultats. Une indication d'avertissement s'affiche dans le coin inférieur droit de la ligne de statut lorsqu'une tâche reste dans la vue de progression et a des résultats à afficher à l'attention de l'utilisateur.
Un sentiment général de contrôle de ce qui est exécuté avec la possibilité de surveiller et d'annuler les opérations en tâche de fond.
Les tâches utilisateur offrent le meilleur contrôle à l'utilisateur car elles sont faciles à annuler et affichent des indications évidentes de blocages ou d'opérations exécutées simultanément via l'onglet Détails de la boîte de dialogue de progression. Notez que la boîte de dialogue de progression améliorée qui affiche la zone Détails n'est affichée que lorsque les utilisateurs appellent IProgressService#busyCursorWhile
ou IProgressService#runInUI.
En outre, la vue de progression permet d'accéder aux tâches qui sont en cours d'exécution.
Tous les plug-ins installés doivent afficher la progression de manière cohérente.
L'avantage d'utiliser l'API de service de progression est que les utilisateurs bénéficient d'une progression cohérente.
Ensuite, nous allons découvrir en détail l'utilisation des nouvelles API.
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 de progression ne s'affiche pas. Si l'opération doit mettre à jour l'interface utilisateur, vous pouvez toujours transmettre 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é au niveau de l'unité d'exécution de l'interface utilisateur, vous devez appeler IProgressService#runInUI. Là encore, l'avantage de cette méthode est qu'elle affiche une boîte de dialogue de progression si l'opération est bloquée et donne 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 affiche l'icône en regard de la tâche en cours d'exécution. Voici un exemple d'association d'une icône à la création automatique :
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);
IWorkbenchSiteProgressService
ajoute une API pour planifier les tâches qui modifient l'apparence d'une partie du plan de travail lorsque la tâche est en cours d'exécution. Si le plug-in exécute des opérations en tâche de fond qui affectent l'état d'une partie, vous pouvez planifier la tâche via la partie et l'utilisateur est averti que la partie est occupée. Voici un exemple :
IWorkbenchSiteProgressService siteService = (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class); siteService.schedule(job, 0 /* now */, true /* use half-busy cursor in part */);
Il existe un ensemble de propriétés prédéfinies dans IProgressConstants, qui peuvent être utilisées pour contrôler l'affichage d'une tâche dans la vue de progression. Ces propriétés peuvent ê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 de statut signale lorsqu'une action est disponible. Voici un exemple qui utilise ces propriétés :
Job job = new Job("Do Work") { public IStatus run(IProgressMonitor monitor) { // Pour réaliser un travail et ne conserver que la tâche terminée dans la vue de progression si // elle n'est pas exécutée dans la boîte de dialogue de progression 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();
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.