/** check for flow mappings; does not allow flow mapping through CoordinateSystem */
 private String findFlow(
     ShadowTupleType shadow,
     DisplayImpl display,
     DisplayTupleType[] tuples,
     int[] flowToComponent) {
   ShadowRealType[] components = shadow.getRealComponents();
   for (int i = 0; i < components.length; i++) {
     int num_flow_per_real = 0;
     Enumeration maps = components[i].getSelectedMapVector().elements();
     while (maps.hasMoreElements()) {
       ScalarMap map = (ScalarMap) maps.nextElement();
       DisplayRealType dreal = map.getDisplayScalar();
       DisplayTupleType tuple = dreal.getTuple();
       if (Display.DisplayFlow1Tuple.equals(tuple) || Display.DisplayFlow2Tuple.equals(tuple)) {
         if (tuples[0] != null) {
           if (!tuples[0].equals(tuple)) {
             return multipleFlowTuples;
           }
         } else {
           tuples[0] = tuple;
         }
         num_flow_per_real++;
         if (num_flow_per_real > 1) {
           return multipleFlowMapping;
         }
         int index = dreal.getTupleIndex();
         flowToComponent[index] = i;
         directMap[index] = map;
       } else if (Display.DisplayFlow1SphericalTuple.equals(tuple)
           || Display.DisplayFlow2SphericalTuple.equals(tuple)) {
         if (tuples[0] != null) {
           if (!tuples[0].equals(tuple)) {
             return multipleFlowTuples;
           }
         } else {
           tuples[0] = tuple;
           coord = tuple.getCoordinateSystem();
         }
         num_flow_per_real++;
         if (num_flow_per_real > 1) {
           return multipleFlowMapping;
         }
         int index = dreal.getTupleIndex();
         flowToComponent[index] = i;
         directMap[index] = map;
       }
     } // while (maps.hasMoreElements())
   }
   return null;
 }
  public void checkDirect() throws VisADException, RemoteException {
    // realCheckDirect();
    //
    // must customize
    setIsDirectManipulation(false);

    DisplayImpl display = getDisplay();
    link = getLinks()[0];
    ref = link.getDataReference();
    type = link.getType();
    if (!(type instanceof TupleType) || !((TupleType) type).getFlat()) {
      whyNotDirect = notFlatTupleType;
      return;
    }
    flowToComponent = new int[] {-1, -1, -1};
    directMap = new ScalarMap[] {null, null, null};
    shadow = (ShadowTupleType) link.getShadow().getAdaptedShadowType();
    DisplayTupleType[] tuples = {null};
    whyNotDirect = findFlow(shadow, display, tuples, flowToComponent);
    if (whyNotDirect != null) return;
    if (coord == null) {
      if (tuples[0] == null || flowToComponent[0] < 0 || flowToComponent[1] < 0) {
        whyNotDirect = noFlow;
        return;
      }
    } else {
      if (tuples[0] == null || flowToComponent[1] < 0 || flowToComponent[2] < 0) {
        whyNotDirect = noFlow;
        return;
      }
    }

    ShadowRealType[] components = shadow.getRealComponents();
    for (int i = 0; i < components.length; i++) {
      DisplayTupleType spatial_tuple = components[i].getDisplaySpatialTuple();
      if (spatial_tuple != null && !Display.DisplaySpatialCartesianTuple.equals(spatial_tuple)) {
        whyNotDirect = nonCartesian;
        return;
      }
    }

    // needs more, will find out when we write drag_direct
    setIsDirectManipulation(true);
  }