public BufrMessageViewer(final PreferencesExt prefs, JPanel buttPanel) {
    this.prefs = prefs;

    AbstractAction useReaderAction =
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            Boolean state = (Boolean) getValue(BAMutil.STATE);
            doRead = state.booleanValue();
          }
        };
    BAMutil.setActionProperties(useReaderAction, "addCoords", "read data", true, 'C', -1);
    useReaderAction.putValue(BAMutil.STATE, new Boolean(doRead));
    BAMutil.addActionToContainer(buttPanel, useReaderAction);

    AbstractAction seperateWindowAction =
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            Boolean state = (Boolean) getValue(BAMutil.STATE);
            seperateWindow = state.booleanValue();
          }
        };
    BAMutil.setActionProperties(
        seperateWindowAction, "addCoords", "seperate DDS window", true, 'C', -1);
    seperateWindowAction.putValue(BAMutil.STATE, new Boolean(seperateWindow));
    BAMutil.addActionToContainer(buttPanel, seperateWindowAction);

    messageTable =
        new BeanTableSorted(
            MessageBean.class, (PreferencesExt) prefs.node("GridRecordBean"), false);
    messageTable.addListSelectionListener(
        new ListSelectionListener() {
          public void valueChanged(ListSelectionEvent e) {
            ddsTable.setBeans(new ArrayList());
            obsTable.setBeans(new ArrayList());

            MessageBean mb = (MessageBean) messageTable.getSelectedBean();
            java.util.List<DdsBean> beanList = new ArrayList<DdsBean>();
            try {
              setDataDescriptors(beanList, mb.m.getRootDataDescriptor(), 0);
              setObs(mb.m);
            } catch (IOException e1) {
              JOptionPane.showMessageDialog(BufrMessageViewer.this, e1.getMessage());
              e1
                  .printStackTrace(); // To change body of catch statement use File | Settings |
                                      // File Templates.
            }
            ddsTable.setBeans(beanList);
          }
        });

    obsTable = new BeanTableSorted(ObsBean.class, (PreferencesExt) prefs.node("ObsBean"), false);
    obsTable.addListSelectionListener(
        new ListSelectionListener() {
          public void valueChanged(ListSelectionEvent e) {
            ObsBean csb = (ObsBean) obsTable.getSelectedBean();
          }
        });

    ddsTable = new BeanTableSorted(DdsBean.class, (PreferencesExt) prefs.node("DdsBean"), false);
    ddsTable.addListSelectionListener(
        new ListSelectionListener() {
          public void valueChanged(ListSelectionEvent e) {
            DdsBean csb = (DdsBean) ddsTable.getSelectedBean();
          }
        });

    thredds.ui.PopupMenu varPopup = new thredds.ui.PopupMenu(messageTable.getJTable(), "Options");
    varPopup.addAction(
        "Show DDS",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            MessageBean vb = (MessageBean) messageTable.getSelectedBean();
            if (!seperateWindow) infoTA.clear();
            Formatter f = new Formatter();
            try {
              if (!vb.m.isTablesComplete()) {
                f.format(" MISSING DATA DESCRIPTORS= ");
                vb.m.showMissingFields(f);
                f.format("%n%n");
              }

              vb.m.dump(f);
            } catch (IOException e1) {
              JOptionPane.showMessageDialog(BufrMessageViewer.this, e1.getMessage());
              e1
                  .printStackTrace(); // To change body of catch statement use File | Settings |
                                      // File Templates.
            }
            if (seperateWindow) {
              TextHistoryPane ta = new TextHistoryPane();
              IndependentWindow info =
                  new IndependentWindow("Extra Information", BAMutil.getImage("netcdfUI"), ta);
              info.setBounds(
                  (Rectangle) prefs.getBean("InfoWindowBounds", new Rectangle(300, 300, 500, 300)));
              ta.appendLine(f.toString());
              ta.gotoTop();
              info.show();

            } else {
              infoTA.appendLine(f.toString());
              infoTA.gotoTop();
              infoWindow.show();
            }
          }
        });
    varPopup.addAction(
        "Data Table",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            MessageBean mb = (MessageBean) messageTable.getSelectedBean();
            try {
              NetcdfDataset ncd = getBufrMessageAsDataset(mb.m);
              Variable v = ncd.findVariable(BufrIosp.obsRecord);
              if ((v != null) && (v instanceof Structure)) {
                if (dataTable == null) makeDataTable();
                dataTable.setStructure((Structure) v);
                dataWindow.show();
              }
            } catch (Exception ex) {
              JOptionPane.showMessageDialog(BufrMessageViewer.this, ex.getMessage());
              ex.printStackTrace();
            }
          }
        });

    varPopup.addAction(
        "Bit Count",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            MessageBean mb = (MessageBean) messageTable.getSelectedBean();
            Message m = mb.m;

            Formatter out = new Formatter();
            try {
              infoTA2.clear();
              if (!m.dds.isCompressed()) {
                MessageUncompressedDataReader reader = new MessageUncompressedDataReader();
                reader.readData(null, m, raf, null, false, out);
              } else {
                MessageCompressedDataReader reader = new MessageCompressedDataReader();
                reader.readData(null, m, raf, null, out);
              }
              int nbitsGiven = 8 * (m.dataSection.getDataLength() - 4);
              DataDescriptor root = m.getRootDataDescriptor();
              out.format(
                  "Message nobs=%d compressed=%s vlen=%s countBits= %d givenBits=%d %n",
                  m.getNumberDatasets(),
                  m.dds.isCompressed(),
                  root.isVarLength(),
                  m.getCountedDataBits(),
                  nbitsGiven);
              out.format(" countBits= %d givenBits=%d %n", m.getCountedDataBits(), nbitsGiven);
              out.format(
                  " countBytes= %d dataSize=%d %n",
                  m.getCountedDataBytes(), m.dataSection.getDataLength());
              out.format("%n");
              infoTA2.appendLine(out.toString());

            } catch (Exception ex) {
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              ex.printStackTrace(new PrintStream(bos));
              infoTA2.appendLine(out.toString());
              infoTA2.appendLine(bos.toString());
            }

            infoTA2.gotoTop();
            infoWindow2.show();
          }
        });

    varPopup.addAction(
        "Write Message",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            MessageBean mb = (MessageBean) messageTable.getSelectedBean();
            try {
              String defloc;
              String header = mb.m.getHeader();
              if (header != null) {
                header = header.split(" ")[0];
              }
              if (header == null) {
                defloc = (raf.getLocation() == null) ? "." : raf.getLocation();
                int pos = defloc.lastIndexOf(".");
                if (pos > 0) defloc = defloc.substring(0, pos);
              } else defloc = header;

              if (fileChooser == null)
                fileChooser =
                    new FileManager(null, null, null, (PreferencesExt) prefs.node("FileManager"));

              String filename = fileChooser.chooseFilenameToSave(defloc + ".bufr");
              if (filename == null) return;

              File file = new File(filename);
              FileOutputStream fos = new FileOutputStream(file);
              WritableByteChannel wbc = fos.getChannel();
              wbc.write(ByteBuffer.wrap(mb.m.getHeader().getBytes()));

              byte[] raw = scan.getMessageBytes(mb.m);
              wbc.write(ByteBuffer.wrap(raw));
              wbc.close();
              JOptionPane.showMessageDialog(
                  BufrMessageViewer.this, filename + " successfully written");

            } catch (Exception ex) {
              JOptionPane.showMessageDialog(BufrMessageViewer.this, "ERROR: " + ex.getMessage());
              ex.printStackTrace();
            }
          }
        });

    varPopup.addAction(
        "Dump distinct DDS",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            dumpDDS();
          }
        });

    varPopup.addAction(
        "Write all distinct messages",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            writeAll();
          }
        });

    varPopup.addAction(
        "Show XML",
        new AbstractAction() {
          public void actionPerformed(ActionEvent e) {
            MessageBean mb = (MessageBean) messageTable.getSelectedBean();
            Message m = mb.m;

            ByteArrayOutputStream out = new ByteArrayOutputStream(1000 * 100);
            try {
              infoTA.clear();

              NetcdfDataset ncd = getBufrMessageAsDataset(mb.m);
              new Bufr2Xml(m, ncd, out, true);
              infoTA.setText(out.toString());

            } catch (Exception ex) {
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              ex.printStackTrace(new PrintStream(bos));
              infoTA.appendLine(out.toString());
              infoTA.appendLine(bos.toString());
            }

            infoTA.gotoTop();
            infoWindow.show();
          }
        });

    // the info window
    infoTA = new TextHistoryPane();
    infoWindow = new IndependentWindow("Extra Information", BAMutil.getImage("netcdfUI"), infoTA);
    infoWindow.setBounds(
        (Rectangle) prefs.getBean("InfoWindowBounds", new Rectangle(300, 300, 500, 300)));

    // the info window 2
    infoTA2 = new TextHistoryPane();
    infoWindow2 =
        new IndependentWindow("Extra Information-2", BAMutil.getImage("netcdfUI"), infoTA2);
    infoWindow2.setBounds(
        (Rectangle) prefs.getBean("InfoWindowBounds2", new Rectangle(300, 300, 500, 300)));

    split2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, ddsTable, obsTable);
    split2.setDividerLocation(prefs.getInt("splitPos2", 800));

    split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, messageTable, split2);
    split.setDividerLocation(prefs.getInt("splitPos", 500));

    setLayout(new BorderLayout());
    add(split, BorderLayout.CENTER);
  }