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.

Antes de presentar las API nuevas, empecemos por repasar algunos conceptos. En primer lugar, debemos distinguir entre diferentes tipos de operaciones de segundo plano:


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

A continuación, entraremos en detalles acerca de la utilización de las nuevas API.

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 corta ejecución, no se mostrará el diálogo de progreso. Si la operación debe actualizar la UI, siempre puede enviar un Display.asyncExec o Display.syncExec para ejecutar el código que modifica la UI. Si una operación debe ejecutarse totalmente en la hebra de la UI, debe llamar a IProgressService#runInUI. De nuevo, la ventaja de este método es que visualizará un diálogo de progreso si la operación queda bloqueada y otorgará 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 caso, 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 con el servicio de progreso un icono para una familia de trabajos, para que la vista de progreso puede mostrar el icono junto al trabajo en ejecución. A continuación figura un ejemplo de cómo se asocia la 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 añade 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

Existe un conjunto de propiedades predefinidas definidas en IProgressConstants que 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. A continuación figura un ejemplo que utiliza estas propiedades:


   Job job = new Job("Realizar trabajo") {
      public IStatus run(IProgressMonitor monitor) {
         // realizar algún trabajo y conservar sólo el trabajo finalizado en la vista de
         // progreso 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.

Avisos legales.