2013-02-18 16 views
6

Ho una cella GWT che utilizzo per visualizzare una struttura di file da un CMS. Sto usando un AsyncDataProvider che carica i dati da una classe RPC personalizzata che ho creato. Ho anche un sistema Web Socket che trasmetterà eventi (File create, rinominato, spostato, cancellato, ecc.) Da altri client che funzionano anche nel sistema.Come si comunica a un GWT che i dati del widget della cella sono stati modificati tramite il bus eventi?

Quello che sto cercando di comprendere è quando ricevo uno di questi eventi, come aggiorno correttamente il mio albero cellulare?

Suppongo che questo problema sia analogo a due istanze del mio albero cellulare nella pagina, che presentano gli stessi dati lato server e che vogliono garantire che quando l'utente ne ha aggiornato uno, che anche l'altro sia aggiornato, via usando il EventBus.

Ritengo che questo dovrebbe essere piuttosto semplice, ma ho trascorso circa 6 ore su di esso ora senza alcun progresso. Il mio codice è incluso di seguito:

NOTA: Non sto utilizzando RequestFactory anche se potrebbe sembrare come se fosse il mio framework RPC personalizzato. Inoltre, FileEntity è solo una semplice rappresentazione di un file che ha un nome accessibile da getName().

private void drawTree() { 

     // fileService is injected earlier on and is my own custom rpc service 
     TreeViewModel model = new CustomTreeModel(new FileDataProvider(fileService)); 
     CellTree tree = new CellTree(model, "Root"); 

     tree.setAnimationEnabled(true); 

     getView().getWorkspace().add(tree); 

    } 

    private static class CustomTreeModel implements TreeViewModel { 

     // I am trying to use a single AsyncDataProvider so I have a single point of loading data which I can manipulate (Not sure if this is the correct way to go) 
     public CustomTreeModel(FileDataProvider dataProvider) { 
      this.provider = provider; 
     } 


     public <T> NodeInfo<?> getNodeInfo(final T value) { 

      if (!(value instanceof FileEntity)) { 

           // I already have the root File loaded in my presenter, if we are at the root of the tree, I just add it via a list here 
       ListDataProvider<FileEntity> dataProvider = new ListDataProvider<FileEntity>(); 

       dataProvider.getList().add(TreeWorkspacePresenter.rootFolder); 

       return new DefaultNodeInfo<FileEntity>(dataProvider, 
         new FileCell()); 
      } else { 

           // Otherwise I know that we are loading some tree child data, and I invoke the AsyncProvider to load it from the server 
       provider.setFocusFile(value); 

       return new DefaultNodeInfo<FileEntity>(provider, 
         new FileCell()); 
      } 
     } 

     public boolean isLeaf(Object value) { 

      if(value == null || value instanceof Folder) 
       return false; 
      return true; 
     } 

    } 

    public class FileDataProvider extends AsyncDataProvider<FileEntity> { 

     private FileEntity focusFile; 
     private FileService service; 

     @Inject 
     public FileDataProvider(FileService service){ 
      this.service = service; 
     } 

     public void setFocusFile(FileEntity focusFile){ 
      this.focusFile = focusFile; 
     } 

     @Override 
     protected void onRangeChanged(HasData<FileEntity> display) { 


       service.getChildren(((Folder) focusFile), 
         new Reciever<List<FileEntity>>() { 

          @Override 
          public void onSuccess(List<FileEntity> files) { 

           updateRowData(0, files); 

          } 

          @Override 
          public void onFailure(Throwable error) { 

           Window.alert(error.toString()); 
          } 

         }); 

      } 
     } 



    /** 
    * The cell used to render Files. 
    */ 
    public static class FileCell extends AbstractCell<FileEntity> { 

     private FileEntity file; 

     public FileEntity getFile() { 
      return file; 

     } 

     @Override 
     public void render(Context context, FileEntity file, SafeHtmlBuilder sb) { 
      if (file != null) { 
       this.file = file; 
       sb.appendEscaped(file.getName()); 
      } 
     } 
    } 

risposta

2

Attualmente non esiste un supporto diretto per il singolo aggiornamento della struttura ad albero anche nell'ultima versione di gwt.

Ma c'è una soluzione per questo. Ogni elemento dell'albero è associato a un valore. Usando questo valore puoi ottenere la voce dell'albero corrispondente.

Nel tuo caso, suppongo, non si sa quale elemento di aggiornare/aggiornare cioè sapere quale entità file è stato modificato. Utilizzare questa entità file per cercare l'elemento dell'albero corrispondente. Una volta ottenuto l'elemento dell'albero, è sufficiente espandere, comprimere o comprimere ed espandere l'elemento principale. Questo rende l'elemento principale per re-renderizzare i suoi figli. L'entità del file modificato è uno tra i bambini. Quindi viene aggiornato.

public void refreshFileEntity(FileEntity fileEntity) 
{ 
     TreeNode fileEntityNode = getFileEntityNode(fileEntity, cellTree.getRootTreeNode() 

     // For expnad and collapse run this for loop 

     for (int i = 0; i < fileEntityNode.getParent().getChildCount(); i++) 
    { 
     if (!fileEntityNode.getParent().isChildLeaf(i)) 
     { 
      fileEntityNode.getParent().setChildOpen(i, true); 
     } 
    } 

} 

public TreeNode getFileEntityNode(FileEntity fileEntity, TreeNode treeNode) 
{ 
     if(treeNode.getChildren == null) 
     { 
      return null; 
     } 
     for(TreeNode node : treeNode.getChildren()) 
     { 
      if(fileEntity.getId().equals(node.getValue.getId())) 
      { 
       return node; 
      } 
      getEntityNode(fileEntity, node); 
     } 
} 
+0

Non esattamente quello che stavo cercando, ma questo funziona. Cosa ne pensi di mantenere un indice FileEntity-> TreeNode per migliorare i tempi di ricerca? Grazie! –

+0

Sì, è sempre meglio usare l'indicizzazione ... – Adarsha

0

È possibile utilizzare il dataprovider per aggiornare la cella. È possibile aggiornare l'albero delle cellule completo di:

provider.setList(pList); 
provider.refresh(); 

Se si desidera aggiornare solo una cella speciale è possibile ottenere il ListWrapper dal dataprovider e impostare un solo elemento.

provider.getList().set(12, element); 
+0

Questo deve funzionare con un AsyncDataProvider, in cui nuovi dati provengono dal server. Non credo che questo approccio funzionerà ... –

Problemi correlati