Supporto di simultaneità del workbench

È stato illustrato come il framework dell'UI JFace fornisca il supporto di base per la visualizzazione dell'avanzamento delle attività in una finestra di dialogo (per i dettagli, fare riferimento alla sezione Operazioni di lunga durata. Nella sezione Infrastruttura di simultaneità, è stato esaminato il supporto runtime della piattaforma per operazioni simultanee e di lunga durata. Viene ora esaminato come l'UI della piattaforma migliori questa infrastruttura nel pacchetto org.eclipse.ui.progress. Questo pacchetto fornisce l'UI per la visualizzazione dell'avanzamento del lavoro nel workbench e definisce un supporto supplementare per i lavori che vengono eseguiti nel thread UI.

Prima, vengono analizzati i diversi tipi di operazioni in background che possono essere in esecuzione e le relative modalità di visualizzazione nell'UI del workbench:


In un ambiente in cui possono essere eseguite diverse operazioni nello stesso tempo, l'utente ha bisogno dei seguenti elementi:

Servizio di avanzamento

Il servizio di avanzamento del workbench (IProgressService) è l'interfaccia principale del supporto di avanzamento del workbench. Può essere richiamato dal workbench e utilizzato per mostrare l'avanzamento per le operazioni in background e le operazioni che vengono eseguite nel thread dell'UI. Lo scopo principale di questa classe è fornire un'interfaccia unica per le operazioni in esecuzione, facendo in modo che gli sviluppatori di plugin non debbano stabilire i meccanismi da utilizzare per visualizzare l'avanzamento in una determinata situazione. Un altro vantaggio sta nel fatto che la finestra di dialogo di avanzamento visualizzata con questi metodi fornisce un ottimo supporto per indicare quando un'operazione è bloccata e fornisce all'utente il controllo per risolvere il conflitto. Quando possibile, le operazioni di lunga durata devono essere eseguite utilizzando IProgressService#busyCursorWhile:

   IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
   progressService.busyCursorWhile(new IRunnableWithProgress(){
      public void run(IProgressMonitor monitor) {
         //do non-UI work
      }
   });

Questo metodo supporta inizialmente un cursore e lo sostituisce con una finestra di dialogo di avanzamento se l'operazione dura più a lungo della soglia di tempo specificata. Il vantaggio di questo metodo rispetto all'utilizzo di una finestra di dialogo di avanzamento sta nel fatto che se l'operazione è di breve durata, la finestra di dialogo di avanzamento non viene visualizzata. Se l'operazione deve aggiornare l'UI, è possibile sempre utilizzare Display.asyncExec o Display.syncExec per eseguire il codice che modifica l'UI.

Se un'operazione deve essere eseguita completamente nel thread dell'UI, deve essere utilizzato IProgressService#runInUI. Questo metodo visualizza una finestra di dialogo di avanzamento anche se l'operazione è bloccata e fornisce il controllo all'utente.

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

Il terzo parametro può essere null o una regola di pianificazione per l'operazione. In questo esempio, viene specificato l'elemento principale dello spazio di lavoro, che praticamente blocca lo spazio di lavoro durante l'esecuzione dell'operazione dell'UI.

È anche possibile registrare con il servizio di avanzamento un'icona per una famiglia di lavori, in modo che la vista di avanzamento possa visualizzare l'icona accanto al lavoro in esecuzione. Di seguito viene riportato un esempio del modo in cui la famiglia di lavori generata automaticamente è associata alla relativa icona:

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

Visualizzazione di una parte occupata

IWorkbenchSiteProgressService include l'API per la pianificazione dei lavori che modificano l'aspetto della parte di un workbench durante l'esecuzione del lavoro. Se il plugin esegue operazioni in background che influiscono sullo stato di una parte, è possibile pianificare il lavoro mediante la parte, in modo che l'utente visualizzi il feedback che mostra che la parte è occupata. Di seguito viene riportato un esempio:

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

Proprietà di avanzamento per i lavori

Il workbench definisce le proprietà relative allo stato di avanzamento per i lavori in IProgressConstants. Queste possono essere utilizzate per controllare le modalità di visualizzazione della vista di avanzamento. Le proprietà possono essere utilizzate per indicare alla vista di avanzamento di mantenere (IProgressConstants#KEEP_PROPERTY) nella vista il lavoro una volta completato o di mantenere un solo lavoro (IProgressConstants#KEEPONE_PROPERTY) alla volta nella vista. È possibile anche associare un'azione (IProgressConstants#ACTION_PROPERTY) ad un lavoro. Quando ad un lavoro è associata un'azione, la vista di avanzamento mostra un collegamento ipertestuale in modo che l'utente possa eseguire l'azione. È possibile anche rilevare se il lavoro di un utente viene attualmente visualizzato in una finestra di dialogo di avanzamento (IProgressConstants#PROPERTY_IN_DIALOG). Un suggerimento viene visualizzato a destra della riga di stato quando è disponibile un'azione. Di seguito viene riportato un esempio di uso di queste proprietà:

   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() {
         // show the results
      }
   };
   job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction);
   job.setUser(true);
   job.schedule();

Lavori del workbench

Quando possibile, le operazioni di lunga durata devono essere eseguite al di fuori del thread dell'UI. Tuttavia, ciò non può sempre essere evitato quando lo scopo dell'operazione è quello di aggiornare l'UI. La sezione Problemi relativi ai thread SWT illustra come eseguire questa operazione utilizzando la Visualizzazione SWT. Il workbench definisce un lavoro speciale, UIJob, il cui metodo di esecuzione viene eseguito all'interno di un SWT asyncExec. Le sottoclassi di UIJob devono implementare il metodo runInUIThread anziché il metodo run.

WorkbenchJob estende UIJob in modo che il lavoro possa essere pianificato o eseguito solo quando il workbench è in esecuzione. Come sempre, è necessario evitare operazioni onerose nel thread dell'UI, perché l'UI non verrà aggiornata per tutta la durata del lavoro.