Soporte de simultaneidad del entorno de trabajo

Hemos visto que la infraestructura de UI de JFace proporciona soporte básico para mostrar el progreso de las tareas en un diálogo (consulte la sección Operaciones de larga ejecución para obtener detalles). En la sección Infraestructura de simultaneidad, hemos examinado el soporte de ejecución de la plataforma para la simultaneidad y las operaciones de larga ejecución. Ahora veremos cómo la UI de la plataforma mejora esta infraestructura en el paquete org.eclipse.ui.progress. Este paquete suministra la UI para visualizar el progreso de los trabajos en el entorno de trabajo y define soporte adicional para los trabajos que se ejecutan en la hebra de UI.

En primer lugar, veamos las distintas clases de operaciones de fondo que pueden ejecutarse y cómo se muestran en la UI del entorno de trabajo:


Dado un entorno en el que pueden estar ocurriendo varias cosas simultáneamente, el usuario necesita lo siguiente:

Servicio de progreso

El servicio de progreso del entorno de trabajo (IProgressService) es la interfaz primaria del soporte de progreso del entorno de trabajo. Puede obtenerse del entorno de trabajo y, a continuación, utilizarse para mostrar el progreso de las operaciones de segundo plano y de las operaciones ejecutadas en la hebra de la UI. La finalidad de esta clase consiste en suministrar un solo punto de visualización para las operaciones en ejecución, eliminando la necesidad de que los desarrolladores de conectores decidan el mecanismo que debe utilizarse para mostrar el progreso en una situación determinada. Otra ventaja consiste en que el diálogo de progreso mostrado con estos métodos proporciona un buen soporte para indicar cuándo una operación queda bloqueada por otra y otorga al usuario el control para resolver el conflicto. Cuando sea posible, las operaciones de larga ejecución deben ejecutarse mediante IProgressService#busyCursorWhile:

   IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
         public void run(IProgressMonitor monitor) {
         //realizar trabajo no de UI
      }
   });

Este método colocará inicialmente un cursor ocupado y lo sustituirá por un diálogo de progreso si la duración de la operación es superior al umbral de tiempo especificado. La ventaja de este método con respecto a la utilización de un diálogo de progreso consiste en que, si la operación es de ejecución breve, no se mostrará el diálogo de progreso. Si la operación debe actualizar la UI, siempre puede utilizar un Display.asyncExec o Display.syncExec para ejecutar el código que modifica la UI.

Si una operación debe ejecutarse en su totalidad en la hebra de la UI, debe utilizarse IProgressService#runInUI. Este método también mostrará un diálogo de progreso si la operación queda bloqueada y dará el control al usuario.

   progressService.runInUI(
      PlatformUI.getWorkbench().getProgressService(),
      new IRunnableWithProgress() {
         public void run(IProgressMonitor monitor) {
         //realizar trabajo de UI
         }
      },
      Platform.getWorkspace().getRoot());

El tercer parámetro puede ser nulo o una norma de planificación para la operación. En este ejemplo, se especifica el directorio raíz del área de trabajo que esencialmente bloqueará el área de trabajo mientras se ejecuta esta operación de UI.

También puede registrar un icono para una familia de trabajos con el servicio de progreso, para que la vista de progreso pueda mostrar el icono junto al trabajo en ejecución. A continuación se muestra un ejemplo de cómo se asocia la familia de trabajos de construcción automática con su icono:

   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);

Mostrar que un componente está ocupado

IWorkbenchSiteProgressService incluye una API destinada a planificar los trabajos que cambian el aspecto de un componente del entorno de trabajo durante la ejecución del trabajo. Si el conector está ejecutando operaciones en segundo plano que afectan al estado de un componente, puede planificar el trabajo por medio del componente para que el usuario obtenga información acerca de que el componente está ocupado. A continuación se ofrece un ejemplo:

   IWorkbenchSiteProgressService siteService =
      (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class);
   siteService.schedule(job, 0 /* now */, true /* utilizar cursor medio ocupado en componente */);

Propiedades de progreso de los trabajos

El entorno de trabajo define las propiedades relacionadas con el progreso para trabajos en IProgressConstants . Pueden utilizarse para controlar cómo se muestra un trabajo en la vista de progreso. Estas propiedades pueden utilizarse para indicar a la vista de progreso que conserve (IProgressConstants#KEEP_PROPERTY) el trabajo en la vista una vez finalizado o que sólo conserve un trabajo (IProgressConstants#KEEPONE_PROPERTY) a la vez en la vista. También puede asociar una acción (IProgressConstants#ACTION_PROPERTY) con un trabajo. Si un trabajo tiene ninguna acción asociada, la vista de progreso muestra un hiperenlace para que el usuario pueda ejecutar la acción. También puede averiguar si un trabajo de usuario se está mostrando actualmente en un diálogo de progreso (IProgressConstants#PROPERTY_IN_DIALOG). En la esquina inferior derecha de la línea de estado se suministra una indicación cuando una acción está disponible. El siguiente ejemplo utiliza estas propiedades:

   Job job = new Job("Realizar trabajo") {
      public IStatus run(IProgressMonitor monitor) {
         // realizar un trabajo.  
         // Mantener el trabajo finalizado en la vista de progreso sólo si no se ejecuta en el diálogo de progreso
         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() {
         // mostrar los resultados
      }
   };
   job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction);
   job.setUser(true);
   job.schedule();

Trabajos del entorno de trabajo

Cuando sea posible, las operaciones de larga ejecución deben ejecutarse fuera de la hebra de la UI. Sin embargo, esto no siempre puede evitarse si el propósito de la operación es actualizar la UI. La sección Elementos de las hebras SWT describe cómo puede realizarse esta operación mediante la operación Display de SWT. El entorno de trabajo define un trabajo especial, UIJob, cuyo método run se ejecuta dentro de un asyncExec SWT. Las subclases de UIJob deben implementar el método runInUIThread en lugar del método run.

WorkbenchJob amplía UIJob para que el trabajo sólo pueda planificarse o ejecutarse cuando el entorno de trabajo está en ejecución. Como siempre, debe evitar un trabajo excesivo en la hebra de la UI, ya que ésta no se renovará durante el tiempo que dure el trabajo de UI.