Observamos que a estrutura da UI de JFace fornece suporte básico para mostrar
o progresso da tarefa em um diálogo (consulte Operações de
longa execução para obter detalhes). Em Infra-estrutura
de coincidência, revisamos o suporte do tempo execução da plataforma para coincidência
e operações de longa execução. Agora observaremos como a UI da plataforma aprimora essa infra-estrutura no pacote de
org.eclipse.ui.progress. Esse pacote fornece a UI para mostrar o progresso da tarefa no workbench e define suporte adicional para as tarefas que são executadas no encadeamento da UI.
Antes de introduzirmos as novas APIs, vamos começar revisando alguns conceitos. Primeiramente, temos que distinguir entre os diferentes tipos de operações de segundo plano:
Usuário iniciado. Essas tarefas são configuradas para serem tarefas do usuário (Job#setUser). O workbench mostrará automaticamente as tarefas do usuário em um diálogo do progresso com um botão para permitir que o usuário execute a operação no segundo plano e continue trabalhando. Uma preferência global é utilizada para indicar se as tarefas do usuário sempre serão executadas no segundo plano.
Os exemplos de tarefa do usuário incluem construção, registro de saída de um projeto, sincronização com o repositório, exportando um plug-in e procurando.Acionado automaticamente. Essas operações têm um significado para os usuários, mas não foram iniciadas pelo usuário. Essa é a variedade padrão da tarefa. Essas tarefas são mostradas na visualização de progresso e na linha de status, mas o diálogo do progresso não mostrará quando elas são executadas. Os exemplos incluem a autoconstrução e a sincronização planejada.
Operações do sistema. As operações que não são acionadas pelo usuário e podem ser consideradas como um detalhe de implementação. Essas tarefas são criadas pela configuração do sinalizador do sistema (Job#setSystem). Os exemplos das tarefas do sistema incluem tarefas que lentamente ocupam widgets ou computam decorações e anotações para visualizações.
Em um ambiente em que várias coisas podem estar acontecendo ao mesmo tempo, o usuário precisa:
De uma indicação de quando uma operação de longa execução foi iniciada.
As tarefas do usuário são mostradas para o usuário em um diálogo de progresso fornecendo
feedback imediato, enquanto que as tarefas acionadas automaticamente são mostradas na linha de
status e na visualização de progresso. Além disso, as tarefas que afetam uma peça devem ser
planejadas ou registradas com a peça para que o workbench possa fornecer sugestões para o usuário que algo está em execução e afeta a peça.
Indicação de quando uma operação foi concluída
O usuário pode facilmente saber quando as tarefas do usuário terminam porque o diálogo de progresso é fechado. Mas para as tarefas que não são do usuário, há alguns mecanismos de feedback disponíveis. Se a tarefa foiplanejada ou registrada com uma peça, a sugestão do progresso das peças mostrará quando estiver concluída. Se uma tarefa retorna um erro, um indicador de erro aparecerá na parte inferior direita da linha de status, mostrando uma sugestão que um erro ocorreu.
Indicação de novos resultados interessantes ou novas informações sem tirar a ênfase dos diálogos mostrados por uma operação de segundo plano.
Uma tarefa do usuário pode mostrar diretamente os resultados para o usuário quando a operação é
concluída. Para as tarefas que não são do usuário, é recomendável não interromper o
usuário com um diálogo. Em vez disso, se os resultados das tarefas são mostrados em uma visualização, a visualização pode ser aberta quando a tarefa é iniciada e os resultados são mostrados na visualização. Isso não atrapalhará o workflow dos usuários. Além disso, você pode incluir propriedades para a tarefa para indicar se ela deve
ser mantida na visualização de progresso e tem uma ação que mostrará
os resultados. Uma indicação de aviso aparecerá no canto inferior direito da linha
de status quando uma tarefa permanece na visualização de progresso e tem
resultados para mostrar o usuário.
Um sentimento geral de estar no controle do que está em execução, com a habilidade de monitorar e cancelar as operações de segundo plano.
As tarefas do usuário fornecem o melhor controle para o usuário desde que elas sejam
facilmente canceladas e forneçam uma forte indicação de bloqueio ou as operações coincidentes
em execução pela guia Detalhes do diálogo de progresso. Observe que o diálogo de progresso
aprimorado que fornece a área Detalhes é somente mostrado quando os usuários chamam IProgressService#busyCursorWhile
ou IProgressService#runInUI.
Além disso, a visualização de progresso fornece acesso às tarefas que estão em execução.
Todos os plug-ins instalados devem consistentemente mostrar progresso da mesma maneira.
A vantagem de utilizar a API do serviço de progresso é que os usuários obtêm uma experiência de progresso consistente.
A seguir, entraremos em detalhes sobre como as novas APIs podem ser utilizadas.
O serviço de progresso do workbench (IProgressService) é a interface principal do suporte de progresso do workbench. Pode ser obtido a partir do workbench e, em seguida, utilizado para mostrar progresso para as operações de segundo plano e as operações que são executadas no encadeamento da UI. A finalidade principal dessa classe é fornecer um ponto de compras para execução das operações, removendo a necessidade de desenvolvedores de plug-in para decidir qual mecanismo deve ser utilizado para mostrar progresso em uma determinada situação. Outra vantagem é que o diálogo de progresso mostrado com esses métodos fornece um bom suporte para indicar quando uma operação está bloqueada por outra e fornece o controle do usuário para resolver o conflito. Onde possível, as operações de longa execução devem ser executadas utilizando IProgressService#busyCursorWhile:
IProgressService progressService = PlatformUI.getWorkbench().getProgressService(); progressService.busyCursorWhile(new IRunnableWithProgress(){ public void run(IProgressMonitor monitor) { //do non-UI work } });
Este método inicialmente colocará um cursor ocupado e o substitui por um diálogo de progresso se a operação durar mais tempo que um limite de tempo especificado. A vantagem desse método em utilizar um diálogo de progresso é que se a operação for executada em pouco tempo, o diálogo de progresso não será mostrado. Se a sua operação deve atualizar a UI, você sempre pode enviar um Display.asyncExec ou Display.syncExec para executar o código que modifica a UI. Se uma operação deve ser executada na sua totalidade no encadeamento da UI, em seguida, você deve chamar IProgressService#runInUI. Novamente, a vantagem desse método é que um diálogo de progresso será exibido se a operação for bloqueada e der o controle ao usuário.
progressService.runInUI( PlatformUI.getWorkbench().getProgressService(), new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { //do UI work } }, Platform.getWorkspace().getRoot());
O terceiro parâmetro pode ser nulo ou uma regra de planejamento para a
operação. Neste caso, estamos especificando a raiz do espaço de trabalho
que essencialmente travará o espaço de trabalho enquanto esta operação de UI é executada.
Também é possível registrar, com o serviço de progresso, um ícone para uma família de tarefas
para que a visualização de progresso possa mostrar o ícone próximo à tarefa em execução. Aqui está um exemplo de como a autoconstrução está associada ao seu ícone:
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
inclui API para as tarefas de planejamento que alteram a aparência de uma peça do workbench
enquanto a tarefa está em execução. Se o seu plug-in estiver executando operações
em segundo plano que afetam o estado de uma peça, você pode planejar a tarefa via
peça e o usuário obterá feedback de que a peça está ocupada. A seguir encontra-se um exemplo:
IWorkbenchSiteProgressService siteService = (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class); siteService.schedule(job, 0 /* now */, true /* use half-busy cursor in part */);
Há um conjunto de propriedades predefinidas definido em IProgressConstants
que pode ser utilizado para controlar como uma tarefa é mostrada na visualização de progresso. Isso pode ser utilizado para dizer à visualização de progresso para manter IProgressConstants#KEEP_PROPERTY)
sua tarefa na visualização depois de ter sido concluída ou manter uma (IProgressConstants#KEEPONE_PROPERTY)
tarefa de cada vez na visualização. Também é possível associar uma ação (IProgressConstants#ACTION_PROPERTY)
a uma tarefa. Quando uma tarefa tem uma ação associada, a visualização de progresso
mostra um hyperlink para que um usuário possa executar a ação. Também é possível descobrir
se uma tarefa do usuário está sendo mostrada atualmente em um diálogo de progresso IProgressConstants#PROPERTY_IN_DIALOG).
Uma sugestão é fornecida na parte inferior direita da linha de status quando uma ação
está disponível. Aqui está um exemplo que utiliza essas propriedades:
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();
Onde possível, as operações de longa execução devem ser executadas fora do encadeamento da UI. No entanto, isso não pode ser sempre evitado quando a finalidade da operação é atualizar a UI. Problemas de encadeamento SWT explica como isso pode ser feito utilizando SWT Exibir. O workbench define uma tarefa especial, UIJob, cujo método de execução é executado dentro de um asyncExec de SWT. As subclasses de UIJob devem implementar o método runInUIThread em vez do método de execução.
WorkbenchJob estende UIJob para que a tarefa possa ser somente planejada ou executada quando o workbench está em execução. Como sempre, você deve evitar trabalho excessivo no encadeamento UI porque a UI não será atualizado para a duração da Tarefa da UI.