È 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 di introdurre le nuove API, è necessario rivedere alcuni argomenti. È necessario prima distinguere tra diversi tipi di operazioni di sfondo:
Utente inizializzato. Questi lavori vengono impostati in modo da essere lavori dell'utente (Job#setUser). Il workbench mostra automaticamente i lavori dell'utente in una finestra di dialogo di avanzamento modale con un pulsante che consente all'utente di eseguire l'operazione sullo sfondo e di continuare a lavorare. Una preferenza globale viene utilizzata per indicare se i lavori dell'utente devono essere sempre eseguiti sullo sfondo.
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.Attivato automaticamente. Queste operazioni hanno un significato per gli utenti ma non sono inizializzate dall'utente. Si tratta della varietà predefinita di un lavoro. Questi lavori vengono visualizzati nella vista di avanzamento e nella riga di stato ma nella finestra di dialogo di avanzamento modale non vengono visualizzati quando sono eseguiti. Gli esempi includono la generazione automatica e la sincronizzazione pianificata.
Operazioni di sistema. Le operazioni che non sono attivate dall'utente e possono essere considerate come un dettaglio dell'implementazione. Questi lavori vengono creati impostando l'indicatore del sistema (Job#setSystem). Esempi di lavori di sistema includono i lavori che vengono inseriti nei widget o decorazioni e annotazioni di calcolo per le viste.
Dato un ambiente in cui possono accadere varie cose 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.
Inoltre, 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 terminano i lavori dell'utente, in quanto la finestra di dialogo di avanzamento viene chiusa.
Ciò ad eccezione dei lavori che non sono dell'utente, che rappresentano una coppia di meccanismi di feedback disponibili.
Se il lavoro è stato pianificato o registrato con una parte, il suggerimento relativo all'avanzamento delle parti viene visualizzato quando il lavoro è completo.
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 prestare attenzione alle finestre di dialogo visualizzate da un'operazione di sfondo.
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.
Al contrario, se i risultati dei lavori vengono visualizzati in una vista, la vista può essere aperta quando il lavoro viene avviato e i risultati visualizzati nella vista.
Ciò non interferisce sul flusso di lavoro degli utenti. È possibile inoltre aggiungere proprietà al 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.
L'indicazione di un'avvertenza viene visualizzata nell'angolo destro della riga di stato quando un lavoro resta nella vista di avanzamento e ha risultati che devono essere visualizzati dall'utente.
La sensazione generale di avere il controllo dell'elemento in esecuzione, con la possibilità di controllare e annullare le operazioni di sfondo.
I lavori dell'utente forniscono il controllo migliore all'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 gli utenti richiamano IProgressService#busyCursorWhile
o IProgressService#runInUI.
Inoltre, la vista di avanzamento fornisce l'accesso ai lavori in esecuzione.
Tutti i plugin installati devono visualizzare l'avanzamento allo stesso modo.
Il vantaggio dell'utilizzo dell'API del servizio di avanzamento sta nel fatto che gli utenti visualizzano un avanzamento coerente.
Vengono ora esaminati i dettagli ed il modo in cui possono essere utilizzate le nuove API.
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 di sfondo e le operazioni che vengono eseguite nel thread dell'UI. Lo scopo principale di questa classe è fornire la possibilità di scegliere rapidamente 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 inviare un Display.asyncExec o Display.syncExec per eseguire il codice che modifica l'UI. Se un'operazione deve essere eseguita completamente nel thread dell'UI, è necessario richiamare IProgressService#runInUI. Inoltre, il vantaggio di questo metodo sta nel fatto che visualizza una finestra di dialogo di avanzamento 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 caso, si specifica l'elemento principale dello spazio di lavoro che 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 generazione automatica è 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
aggiunge 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 di sfondo 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 half-busy cursor in part */);
Un insieme di proprietà predefinite è specificato in IProgressConstants
, che può essere utilizzato per controllare il modo in cui un lavoro viene visualizzato nella vista di avanzamento.
Le proprietà possono essere utilizzate per indicare la vista di avanzamento in cui inserire (IProgressConstants#KEEP_PROPERTY)
il lavoro una volta completato o per indicare di inserire un 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 in cui vengono utilizzate queste proprietà:
Job job = new Job("Do Work") { public IStatus run(IProgressMonitor monitor) { // do some work then only keep the finished job in the progress view if // 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 solo pianificato o eseguito quando il workbench è in esecuzione. Come sempre, è necessario evitare il lavoro eccessivo nel thread dell'UI, perché l'UI non viene aggiornata per tutta la durata del lavoro.