2013-02-18 10 views
6

私は、CMSからファイル構造を表示するために使用するGWTセルツリーを持っています。私は作成したカスタムRPCクラスからデータをロードするAsyncDataProviderを使用しています。私はまた、システム内で働いている他のクライアントからイベント(ファイルの作成、名前の変更、移動、削除など)をブロードキャストするWebソケットシステムを持っています。イベントバス経由でGWTセルウィジェットのデータが変更されたことを教えてください。

私はこれらのイベントの1つを受け取ったとき、私は自分のセルツリーを正しく更新するのですか?

この問題は、ページ上に同じサーバーサイドデータを提示し、ユーザーが1つ更新したときにもう1つ更新されることを確実にしたいという、 EventBusを使用して

私はこれがかなりシンプルであるべきだと感じましたが、今は6時間を費やしていません。私のコードは以下に含まれています:

注:カスタムRPCフレームワークのように見えるかもしれませんが、私はRequestFactoryを使用していません。また、FileEntityは、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()); 
      } 
     } 
    } 

答えて

2

現在のところ、最新のgwtバージョンであっても個々のツリーアイテムの更新を直接サポートしていません。

しかし、これには回避策があります。各ツリー項目は値に関連付けられています。この値を使用すると、対応するツリー項目を取得できます。

あなたのケースでは、どのアイテムが更新/更新されるかを知っています。つまり、どのファイルエンティティが変更されたかを知っています。このファイルエンティティを使用して、対応するツリー項目を検索します。ツリーアイテムを取得したら、親アイテムを展開、折りたたんだり、折りたたんだり展開したりするだけです。これにより、親アイテムはその子を再レンダリングします。あなたの変更されたファイルエンティティは子供の中の1つです。だからそれはリフレッシュされます。

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

私が探していたものではないが、これはうまくいく。ルックアップ時間を改善するために、インデックスFileEntity-> TreeNodeを維持することについてどう思いますか?ありがとう! –

+0

はい、いつもインデックスを使う方が良いです... – Adarsha

0

セルラーツリーを更新するためにdataproviderを使用できます。あなただけの特別なセルを更新したい場合は、データプロバイダからlistwrapperを取得し、唯一の要素を設定することができます

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

: あなたはとの完全な細胞ツリーを更新することができます。

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

これは、新しいデータがサーバーから送信されるAsyncDataProviderで動作する必要があります。私はこのアプローチがうまくいくとは思わない... –