public Impl_MultiModeChannelSelection(MultiModeContext mmc, int[] selCols, int row)
        throws DeviceException {
      channel = IntPool.get(row + 1);
      MultiModeDescriptor mmd = mmc.getMultiModeDescriptor();
      GeneralParameterDescriptor preset_pd = mmd.getPresetParameterDescriptor();
      GeneralParameterDescriptor vol_pd = mmd.getVolumeParameterDescriptor();
      GeneralParameterDescriptor pan_pd = mmd.getPanParameterDescriptor();
      GeneralParameterDescriptor submix_pd = mmd.getSubmixParameterDescriptor();

      MultiModeMap m = mmc.getMultimodeMap();

      for (int i = 0, n = selCols.length; i < n; i++) {
        if (selCols[i] == 0) {
          try {
            values[0] = m.getPreset(channel);
            valueStrings[0] = preset_pd.getStringForValue(values[0]);
          } catch (IllegalMultimodeChannelException e) {
            e.printStackTrace();
          } catch (ParameterValueOutOfRangeException e) {
            e.printStackTrace();
          }
        }

        if (selCols[i] == 1) {
          try {
            values[1] = m.getVolume(channel);
            valueStrings[1] = vol_pd.getStringForValue(values[1]);
          } catch (IllegalMultimodeChannelException e) {
            e.printStackTrace();
          } catch (ParameterValueOutOfRangeException e) {
            e.printStackTrace();
          }
        }
        if (selCols[i] == 2) {
          try {
            values[2] = m.getPan(channel);
            valueStrings[2] = pan_pd.getStringForValue(values[2]);
          } catch (IllegalMultimodeChannelException e) {
            e.printStackTrace();
          } catch (ParameterValueOutOfRangeException e) {
            e.printStackTrace();
          }
        }
        if (selCols[i] == 3) {
          try {
            values[3] = m.getSubmix(channel);
            valueStrings[3] = submix_pd.getStringForValue(values[3]);
          } catch (IllegalMultimodeChannelException e) {
            e.printStackTrace();
          } catch (ParameterValueOutOfRangeException e) {
            e.printStackTrace();
          }
        }
      }
    }
  public MultiModeTableModel(DeviceContext d, boolean just16) throws ZDeviceNotRunningException {
    this.multimodeContext = d.getMultiModeContext();
    this.device = d;
    pmtce = new ParameterModelTableCellEditor(Color.white, Color.black);
    mmptce = new MultiModePresetTableCellEditor(device);
    try {
      readablePresets = d.getDefaultPresetContext().getDatabasePresets();
    } catch (NoSuchContextException e) {
      readablePresets = new ArrayList();
      e.printStackTrace();
    }
    if (multimodeContext.has32Channels()) {
      if (!just16) chnls = 32;
      else chnls = 16;
    } else chnls = 16;

    super.init();

    buildParameterModels();
    multimodeContext.addMultiModeListener(this);
  }
  public void render(MultiModeContext mmc, int targetChannel) {
    MultiModeChannelSelection[] chData = getChannelData();
    Integer val;
    Integer ch;
    int numChnls = (mmc.has32Channels() ? 32 : 16);
    for (int i = 0, n = chData.length; i < n; i++) {
      if (targetChannel + i > numChnls) break;
      ch = IntPool.get(targetChannel + i);
      val = chData[i].getPreset();
      if (val != null)
        try {
          mmc.setPreset(ch, val).post();
        } catch (ResourceUnavailableException e) {
          e.printStackTrace();
        }

      val = chData[i].getVolume();
      if (val != null)
        try {
          mmc.setVolume(ch, val).post();
        } catch (ResourceUnavailableException e) {
          e.printStackTrace();
        }
      val = chData[i].getPan();
      if (val != null)
        try {
          mmc.setPan(ch, val).post();
        } catch (ResourceUnavailableException e) {
          e.printStackTrace();
        }
      val = chData[i].getSubmix();
      if (val != null)
        try {
          mmc.setSubmix(ch, val).post();
        } catch (ResourceUnavailableException e) {
          e.printStackTrace();
        }
    }
  }
  public void zDispose() {
    super.zDispose();
    multimodeContext.removeMultiModeListener(this);
    multimodeContext = null;
    readablePresets.clear();

    int size;
    size = volumeParameterModels.size();
    for (int n = 0; n < size; n++)
      ((EditableParameterModel) volumeParameterModels.get(n)).zDispose();
    size = panParameterModels.size();
    for (int n = 0; n < size; n++) ((EditableParameterModel) panParameterModels.get(n)).zDispose();
    size = submixParameterModels.size();
    for (int n = 0; n < size; n++)
      ((EditableParameterModel) submixParameterModels.get(n)).zDispose();

    size = presetParameterModels.size();
    for (int n = 0; n < size; n++)
      ((EditableParameterModel) presetParameterModels.get(n)).zDispose();

    volumeParameterModels.clear();
    volumeParameterModels = null;

    panParameterModels.clear();
    panParameterModels = null;

    submixParameterModels.clear();
    submixParameterModels = null;

    presetParameterModels.clear();
    presetParameterModels = null;

    device = null;
    readablePresets = null;
    pmtce = null;
    mmptce = null;
  }
  protected Component[] getCustomMenuItems() {
    final int[] selRows = this.getSelectedRows();
    Action dc =
        new AbstractAction("Disable channel") {
          public void actionPerformed(ActionEvent e) {
            MultiModeContext mmc = null;
            try {
              mmc = device.getMultiModeContext();
              for (int i = 0, j = selRows.length; i < j; i++) {
                try {
                  mmc.setPreset(IntPool.get(selRows[i] + 1), IntPool.get(-1)).post();
                } catch (ResourceUnavailableException e1) {
                  e1.printStackTrace();
                }
              }
            } catch (DeviceException e1) {
              e1.printStackTrace();
            }
          }
        };
    JMenuItem pmi = null;
    try {
      ArrayList selPresets = new ArrayList();
      PresetContext dpc = device.getDefaultPresetContext();
      MultiModeContext mmc = device.getMultiModeContext();
      for (int i = 0; i < selRows.length; i++) {
        Integer preset =
            mmc.getPreset(IntPool.get(selRows[i] + 1)); // +1 because midi channels indexed from 1
        if (preset.intValue() >= 0) selPresets.add(dpc.getReadablePreset(preset));
      }
      if (selPresets.size() > 0) {

        Object[] sp = ZUtilities.eliminateDuplicates(selPresets.toArray());
        String name =
            (sp.length > 1
                ? "Presets on selected channels"
                : ((ReadablePreset) sp[0]).getDisplayName());
        pmi = ZCommandFactory.getMenu(sp, name);
      }
    } catch (Exception e) {
    }

    Action stm = null;
    if (this.getSelectedRows().length == 1 && this.getSelectedRow() < 16)
      stm =
          new AbstractAction("Set Ch " + (getSelectedRow() + 1) + " as effects channel") {
            public void actionPerformed(ActionEvent e) {
              try {
                device
                    .getMasterContext()
                    .setMasterParam(IntPool.get(245), IntPool.get(getSelectedRow()))
                    .post();
              } catch (Exception e1) {
                e1.printStackTrace();
              }
            }
          };
    ArrayList comps = new ArrayList();
    // comps.add(new PopupCategoryLabel("Multimode"));
    JMenuItem[] mi;
    Component[] mmi;
    if (pmi != null) mi = new JMenuItem[] {pmi, new JMenuItem(dc)};
    else mi = new JMenuItem[] {new JMenuItem(dc)};

    mmi =
        ZCommandFactory.getMenu(new Object[] {mmtm.getMultimodeContext()}, "Multimode")
            .getMenuComponents();
    comps.addAll(Arrays.asList(mmi));
    comps.addAll(Arrays.asList(mi));
    if (stm != null) comps.add(new JMenuItem(stm));
    return (Component[]) comps.toArray(new Component[comps.size()]);
  }
 // Synthesize some entries using the data values & the row #
 public Object getValueAt(int row, int col) {
   switch (col) {
     case 0:
       return "Ch " + (row + 1);
     case 1:
       /* try {
           Integer p = multimodeContext.getPreset(IntPool.get(row + 1));
           int pv = p.intValue();
           if (pv + 1 > readablePresets.size())
               break;
           if (pv == -1)
               return "Disabled";
           ReadablePreset rop = (ReadablePreset) readablePresets.get(pv);
           if (rop != null && rop.getPresetNumber().equals(p))
               return rop;
           return p.toString();
       } catch (IllegalMidiChannelException e) {
           e.printStackTrace();
       }
       break;
       */
       try {
         if (presetParameterModels.size() >= row + 1) {
           EditableParameterModel p = (EditableParameterModel) presetParameterModels.get(row);
           if (p == null) return multimodeContext.getVolume(IntPool.get(row + 1)).toString();
           else return p;
         } else return "error";
       } catch (IllegalMidiChannelException e) {
         e.printStackTrace();
       }
       break;
     case 2:
       try {
         if (volumeParameterModels.size() >= row + 1) {
           EditableParameterModel p = (EditableParameterModel) volumeParameterModels.get(row);
           if (p == null) return multimodeContext.getVolume(IntPool.get(row + 1)).toString();
           else return p;
         } else return "error";
       } catch (IllegalMidiChannelException e) {
         e.printStackTrace();
       }
       break;
     case 3:
       try {
         if (panParameterModels.size() >= row + 1) {
           EditableParameterModel p = (EditableParameterModel) panParameterModels.get(row);
           if (p == null) return multimodeContext.getPan(IntPool.get(row + 1)).toString();
           else return p;
         } else return "error";
       } catch (IllegalMidiChannelException e) {
         e.printStackTrace();
       }
       break;
     case 4:
       try {
         if (submixParameterModels.size() >= row + 1) {
           EditableParameterModel p = (EditableParameterModel) submixParameterModels.get(row);
           if (p == null) return multimodeContext.getSubmix(IntPool.get(row + 1)).toString();
           else return p;
         } else return "error";
       } catch (IllegalMidiChannelException e) {
         e.printStackTrace();
       }
       break;
   }
   return "";
 }
  private void buildParameterModels() {
    presetParameterModels.clear();
    for (int n = 0; n < chnls; n++) {
      try {
        presetParameterModels.add(
            new ParameterModelEncloser(
                multimodeContext
                    .getMultiModeChannel(IntPool.get(n + 1))
                    .getPresetEditableParameterModel()));
      } catch (Exception e) {
        e.printStackTrace();
        presetParameterModels.clear();
        break;
      }
    }

    volumeParameterModels.clear();
    for (int n = 0; n < chnls; n++) {
      try {
        volumeParameterModels.add(
            new ParameterModelEncloser(
                multimodeContext
                    .getMultiModeChannel(IntPool.get(n + 1))
                    .getVolumeEditableParameterModel()));
      } catch (Exception e) {
        e.printStackTrace();
        volumeParameterModels.clear();
        break;
      }
    }

    panParameterModels.clear();
    for (int n = 0; n < chnls; n++) {
      try {
        panParameterModels.add(
            new ParameterModelEncloser(
                multimodeContext
                    .getMultiModeChannel(IntPool.get(n + 1))
                    .getPanEditableParameterModel()));
      } catch (Exception e) {
        e.printStackTrace();
        panParameterModels.clear();
        break;
      }
    }

    submixParameterModels.clear();
    for (int n = 0; n < chnls; n++) {
      try {
        submixParameterModels.add(
            new ParameterModelEncloser(
                multimodeContext
                    .getMultiModeChannel(IntPool.get(n + 1))
                    .getSubmixEditableParameterModel()));
      } catch (Exception e) {
        e.printStackTrace();
        submixParameterModels.clear();
        break;
      }
    }
  }