private void addViewerSelectionListener() {
   tv.setSelection(new StructuredSelection(Arrays.asList(mixedSelection.getValue().toArray())));
   tv.addSelectionChangedListener(
       new ISelectionChangedListener() {
         public void selectionChanged(SelectionChangedEvent event) {
           mixedSelection.getElements().refresh();
         }
       });
 }
 private void hookContextMenu() {
   MenuManager menuMgr = new MenuManager("#PopupMenu");
   menuMgr.setRemoveAllWhenShown(true);
   menuMgr.addMenuListener(
       new IMenuListener() {
         public void menuAboutToShow(IMenuManager manager) {
           fillContextMenu(manager);
         }
       });
   Menu menu = menuMgr.createContextMenu(tv.getControl());
   tv.getControl().setMenu(menu);
 }
 public void gotValue(
     LiveExpression<Filter<BootDashElement>> exp, Filter<BootDashElement> value) {
   tv.refresh();
   final Tree t = tv.getTree();
   t.getDisplay()
       .asyncExec(
           new Runnable() {
             public void run() {
               Composite parent = t.getParent();
               parent.layout();
             }
           });
 }
 protected void uiGotValue(
     LiveExpression<ImmutableSet<BootDashElement>> exp,
     ImmutableSet<BootDashElement> value) {
   if (tv != null && !tv.getControl().isDisposed()) {
     // TODO: refreshing the whole table is overkill, but is a bit tricky to figure out which
     // BDM
     // this set of elements belong to. If we did know then we could just refresh the node
     // representing its section
     // only.
     tv.refresh();
   } else {
     // This listener can't easily be removed because of the intermediary adapter that adds
     // it to a numner of different
     // things. So at least remove it when model remains chatty after view got disposed.
     exp.removeListener(this);
   }
 }
  @Override
  public void createContents(Composite page) {
    tv = new CustomTreeViewer(page, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
    tv.setExpandPreCheckFilters(true);
    tv.setContentProvider(new BootDashTreeContentProvider());
    tv.setSorter(new BootModelViewerSorter(this.model));
    tv.setInput(model);
    tv.getTree().setLinesVisible(true);

    stylers = new Stylers(tv.getTree().getFont());
    tv.setLabelProvider(new BootDashTreeLabelProvider(stylers, tv));

    ColumnViewerToolTipSupport.enableFor(tv);

    GridDataFactory.fillDefaults().grab(true, true).applyTo(tv.getTree());

    new HiddenElementsLabel(page, tv.hiddenElementCount);

    tv.getControl()
        .addControlListener(
            new ControlListener() {
              public void controlResized(ControlEvent e) {
                ReflowUtil.reflow(owner, tv.getControl());
              }

              public void controlMoved(ControlEvent e) {}
            });

    actions = new BootDashActions(model, getSelection(), getSectionSelection(), ui);
    hookContextMenu();

    // Careful, either selection or tableviewer might be created first.
    // in either case we must make sure the listener is added when *both*
    // have been created.
    if (selection != null) {
      addViewerSelectionListener();
    }

    tv.addDoubleClickListener(
        new IDoubleClickListener() {
          public void doubleClick(DoubleClickEvent event) {
            if (selection != null) {
              BootDashElement selected = selection.getSingle();
              if (selected != null) {
                String url =
                    BootDashElementUtil.getUrl(selected, selected.getDefaultRequestMappingPath());
                if (url != null) {
                  UiUtil.openUrl(url);
                }
              } else if (sectionSelection.getValue() != null) {
                IAction openCloudAdminConsoleAction = actions.getOpenCloudAdminConsoleAction();
                if (openCloudAdminConsoleAction != null) {
                  openCloudAdminConsoleAction.run();
                }
              }
            }
          }
        });

    model.getRunTargets().addListener(RUN_TARGET_LISTENER);
    model.getSectionModels().addListener(ELEMENTS_SET_LISTENER_ADAPTER);

    model.addElementStateListener(ELEMENT_STATE_LISTENER);

    if (searchFilterModel != null) {
      searchFilterModel.addListener(FILTER_LISTENER);
      tv.addFilter(
          new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
              if (searchFilterModel.getValue() != null && element instanceof BootDashElement) {
                return searchFilterModel.getValue().accept((BootDashElement) element);
              }
              return true;
            }
          });
    }

    tv.getTree()
        .addDisposeListener(
            new DisposeListener() {
              @Override
              public void widgetDisposed(DisposeEvent e) {
                model.removeElementStateListener(ELEMENT_STATE_LISTENER);
                model.getRunTargets().removeListener(RUN_TARGET_LISTENER);
                model.getSectionModels().removeListener(ELEMENTS_SET_LISTENER_ADAPTER);
                for (BootDashModel m : model.getSectionModels().getValue()) {
                  m.removeModelStateListener(MODEL_STATE_LISTENER);
                }

                if (searchFilterModel != null) {
                  searchFilterModel.removeListener(FILTER_LISTENER);
                }

                if (actions != null) {
                  actions.dispose();
                  actions = null;
                }
                if (stylers != null) {
                  stylers.dispose();
                  stylers = null;
                }
              }
            });

    addDragSupport(tv);
    addDropSupport(tv);
  }
 protected void uiGotValue(LiveExpression<Set<RunTarget>> exp, Set<RunTarget> value) {
   if (tv != null && !tv.getControl().isDisposed()) {
     tv.refresh();
   }
 }