È 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:
I lavori inizializzati dall'utente sono quelli attivati dall'utente. Il workbench mostra automaticamente i lavori dell'utente in una finestra di dialogo di avanzamento con un pulsante che consente all'utente di eseguire l'operazione in background e di continuare a lavorare. Una preferenza globale viene utilizzata per indicare se i lavori dell'utente devono essere sempre eseguiti in background. I lavori dell'utente sono distinti nell'API del lavoro mediante (Job#setUser). Esempi di lavori dell'utente includono la generazione, l'estrazione di un progetto, la sincronizzazione con il repository, l'esportazione di un plugin e la ricerca.
I lavori con attivazione automatica sono significativi per gli utenti, ma non sono inizializzati dagli utenti. Questi lavori vengono visualizzati nella vista di avanzamento e nella riga di stato, ma non viene visualizzata una finestra di dialogo di avanzamento quando sono eseguiti. Gli esempi includono la generazione automatica e la sincronizzazione pianificata.
Le operazioni di sistema non sono attivate dall'utente e possono essere considerate come un dettaglio dell'implementazione della piattaforma. Questi lavori sono creati impostando l'indicatore di sistema mediante (Job#setSystem). Esempi di lavori di sistema includono i lavori che inseriscono dati nei widget o calcolano le decorazioni e le annotazioni per le viste.
In un ambiente in cui possono essere eseguite diverse operazioni nello stesso tempo, l'utente ha bisogno dei seguenti elementi:
Indicazione dell'inizio di un'operazione di lunga durata.
I lavori dell'utente vengono visualizzati all'utente in una finestra di dialogo di avanzamento fornendo un feedback immediato, mentre i lavori attivati automaticamente vengono visualizzati nella riga di stato e nella vista di avanzamento. I lavori che influiscono su una parte, devono essere pianificati o registrati con la parte, in modo
che il workbench possa indicare all'utente che un elemento in esecuzione influisce sulla parte stessa.
Indicazione della fine di un'operazione.
L'utente può facilmente comprendere quando termina un lavoro dell'utente, in quanto la finestra di dialogo di avanzamento viene chiusa. Per
i lavori che non sono dell'utente, esistono un paio di meccanismi di feedback disponibili. Se il lavoro è
pianificato o registrato con una parte, lo stato di avanzamento della parte mostrerà quando il lavoro è
stato completato. Se il lavoro restituisce un errore, un indicatore di errore viene visualizzato a destra della riga di stato.
Indicazione di nuovi risultati di interesse, o di nuove informazioni, senza attivazione di una finestra di dialogo.
Un lavoro dell'utente può visualizzare direttamente i risultati all'utente quando l'operazione viene completata. Per i lavori che non sono
dell'utente, si consiglia di non interrompere l'utente con una finestra di dialogo. Ad esempio, si può aprire una vista quando si avvia
il lavoro e mostrare i risultati in questa vista senza interrompere il flusso di lavoro dell'utente. È possibile inoltre aggiungere
proprietà del lavoro per indicare che il lavoro deve essere mantenuto nella vista di avanzamento e che dispone
di un'azione che consente di visualizzare i risultati. In questo caso, l'indicazione di un avviso viene visualizzata nell'angolo destro
della riga di stato quando un lavoro resta nella vista di avanzamento e dispone di risultati da visualizzare all'utente.
Capacità di avere il controllo delle operazioni in esecuzione, con la possibilità di controllare e annullare le operazioni in background.
I lavori dell'utente forniscono il controllo migliore per l'utente, poiché sono facilmente annullati e forniscono una chiara indicazione di
blocco o di esecuzione di operazioni simultanee, mediante la scheda Dettagli della finestra di dialogo di avanzamento. La finestra
di dialogo di avanzamento che fornisce l'area Dettagli viene visualizzata solo quando i plugin utilizzano IProgressService#busyCursorWhile
o IProgressService#runInUI.
Inoltre, la vista di avanzamento fornisce l'accesso ai lavori in esecuzione.
Prospetti di avanzamento congruenti per tutti i plugin installati.
Il vantaggio dell'utilizzo dell'API del servizio di avanzamento sta nel fatto che gli utenti visualizzano uno stato di avanzamento
congruente.
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);
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 */);
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();
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.