/** @return A Box for selecting an asset type, the old asset and its replacement asset. */
  private Box assetChoiceBox() {
    TreeSet<String> types = new TreeSet<String>();

    types.add(AssetType.CHARACTER.toString());
    types.add(AssetType.PROP.toString());
    types.add(AssetType.SET.toString());

    // JDrawer toReturn;
    Box hbox = new Box(BoxLayout.X_AXIS);
    {
      JCollectionField assetType = UIFactory.createCollectionField(types, diag, sTSize);
      assetType.setActionCommand("type");
      assetType.addActionListener(this);

      JCollectionField oldAsset = UIFactory.createCollectionField(charList.keySet(), diag, sVSize);
      JCollectionField newAsset = UIFactory.createCollectionField(charList.keySet(), diag, sVSize);
      hbox.add(assetType);
      hbox.add(Box.createHorizontalStrut(10));
      hbox.add(oldAsset);
      hbox.add(Box.createHorizontalStrut(5));
      hbox.add(newAsset);

      // pPotentials.put(oldAsset, newAsset);
    }
    list.add(Box.createVerticalStrut(5));

    return hbox; // toReturn;
  } // return assetChoiceBox
  /**
   * Initialize the common user interface components.
   *
   * <p>
   */
  protected JButton[] initUI(
      String title, JComponent extraComps, String confirm, String[][] extra, String cancel) {
    JButton[] extraBtns = null;

    /* create dialog body components */
    {
      JPanel body = new JPanel();
      body.setName("MainDialogPanel");

      body.setLayout(new BoxLayout(body, BoxLayout.Y_AXIS));

      body.add(UIFactory.createPanelLabel("Existing Layouts:"));

      body.add(Box.createRigidArea(new Dimension(0, 4)));

      {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(new TreeData(), true);
        DefaultTreeModel model = new DefaultTreeModel(root, true);

        JTree tree = new JFancyTree(model);
        pTree = tree;
        tree.setName("DarkTree");

        tree.setCellRenderer(new JLayoutTreeCellRenderer());
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        {
          JScrollPane scroll =
              UIFactory.createScrollPane(
                  pTree,
                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED,
                  ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                  new Dimension(230, 120),
                  new Dimension(230, 150),
                  null);

          body.add(scroll);
        }
      }

      if (extraComps != null) body.add(extraComps);

      extraBtns = super.initUI(title, body, confirm, null, extra, cancel);
    }

    return extraBtns;
  }
  /**
   * Draws the GUI that allows a user to select assets to be updated.
   *
   * @return true if the user made a valid choice of assets to replace.
   * @throws PipelineException
   */
  private boolean buildUpdateGUI() throws PipelineException {
    Box finalBox = new Box(BoxLayout.Y_AXIS);
    top = new Box(BoxLayout.Y_AXIS);

    JScrollPane scroll;

    {
      scroll = new JScrollPane(finalBox);

      scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
      scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

      Dimension size = new Dimension(sVSize + sVSize + sTSize + 52, 500);
      scroll.setMinimumSize(size);
      scroll.setPreferredSize(size);
      scroll.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
    }

    /* query the user */
    diag = new JToolDialog("Propagate Asset", scroll, "Continue");

    areas = mclient.getWorkingAreas();
    {
      Box hbox = new Box(BoxLayout.X_AXIS);
      Component comps[] = UIFactory.createTitledPanels();
      JPanel tpanel = (JPanel) comps[0];
      JPanel vpanel = (JPanel) comps[1];
      {
        userField =
            UIFactory.createTitledCollectionField(
                tpanel,
                "User:"******"The user whose area the node is being created in.");
        userField.setActionCommand("user");
        userField.setSelected(PackageInfo.sUser);
        userField.addActionListener(this);
      }
      UIFactory.addVerticalSpacer(tpanel, vpanel, 3);
      {
        viewField =
            UIFactory.createTitledCollectionField(
                tpanel,
                "View:",
                sTSize,
                vpanel,
                areas.get(PackageInfo.sUser),
                diag,
                sVSize,
                "The working area to create the nodes in.");
        viewField.setActionCommand("wrap");
        viewField.addActionListener(this);
      }
      UIFactory.addVerticalSpacer(tpanel, vpanel, 3);
      {
        toolsetField =
            UIFactory.createTitledCollectionField(
                tpanel,
                "Toolset:",
                sTSize,
                vpanel,
                mclient.getActiveToolsetNames(),
                diag,
                sVSize,
                "The toolset to set on all the nodes.");
        toolsetField.setSelected(mclient.getDefaultToolsetName());
        toolsetField.setActionCommand("wrap");
        toolsetField.addActionListener(this);
      }
      UIFactory.addVerticalSpacer(tpanel, vpanel, 3);

      w =
          new Wrapper(
              userField.getSelected(),
              viewField.getSelected(),
              toolsetField.getSelected(),
              mclient);

      charList = SonyConstants.getAssetList(w, project, AssetType.CHARACTER);
      setsList = SonyConstants.getAssetList(w, project, AssetType.SET);
      propsList = SonyConstants.getAssetList(w, project, AssetType.PROP);

      {
        projectField =
            UIFactory.createTitledCollectionField(
                tpanel,
                "Project:",
                sTSize,
                vpanel,
                Globals.getChildrenDirs(w, "/projects"),
                diag,
                sVSize,
                "All the projects in pipeline.");
        projectField.setActionCommand("proj");
        projectField.addActionListener(this);
      }
      hbox.add(comps[2]);
      top.add(hbox);
    }

    {
      Box vbox = new Box(BoxLayout.Y_AXIS);
      Box hbox = new Box(BoxLayout.X_AXIS);
      JButton button = new JButton("Propagate Additional Asset");
      button.setName("ValuePanelButton");
      button.setRolloverEnabled(false);
      button.setFocusable(false);
      Dimension d = new Dimension(sVSize, 25);
      button.setPreferredSize(d);
      button.setMinimumSize(d);
      button.setMaximumSize(new Dimension(Integer.MAX_VALUE, 25));

      vbox.add(Box.createRigidArea(new Dimension(0, 5)));
      hbox.add(button);
      hbox.add(Box.createRigidArea(new Dimension(4, 0)));
      vbox.add(hbox);
      vbox.add(Box.createRigidArea(new Dimension(0, 5)));

      button.setActionCommand("add");
      button.addActionListener(this);

      top.add(vbox);
    }

    list = new Box(BoxLayout.Y_AXIS);
    test = new JDrawer("Propagate Additional Asset", list, false);

    top.add(test);
    list.add(assetChoiceBox());

    finalBox.add(top);

    {
      JPanel spanel = new JPanel();
      spanel.setName("Spacer");
      spanel.setMinimumSize(new Dimension(sTSize + sVSize, 7));
      spanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
      spanel.setPreferredSize(new Dimension(sTSize + sVSize, 7));
      finalBox.add(spanel);
    }

    diag.setVisible(true);
    if (diag.wasConfirmed()) {
      // get list of things to change.
      for (Component comp : list.getComponents()) {
        if (comp instanceof Box) {
          Box can = (Box) comp;
          JCollectionField oldOne = (JCollectionField) can.getComponent(2);
          JCollectionField newOne = (JCollectionField) can.getComponent(4);

          TreeMap<String, String> assetList = new TreeMap<String, String>();
          assetList.putAll(charList);
          assetList.putAll(propsList);
          assetList.putAll(setsList);

          String key = assetList.get(oldOne.getSelected()) + lr;
          String value = assetList.get(newOne.getSelected()) + lr;
          if (!key.equals(value)) {
            potentialUpdates.add(key);
            pAssetManager.put(key, new AssetInfo(key, value));
          }
          // System.err.println("bUG: "+pAssetManager.get(key).getHiLoResShots());
        }
      }

      if (!pAssetManager.isEmpty()) return true;
    }
    return false;
  } // end buildReplacementGUI
  /**
   * Present a GUI allowing the user to select shots in which each previously selected asset should
   * be updated.
   *
   * @return
   * @throws PipelineException
   */
  private String confirmShotsToUpdate() throws PipelineException {

    /* DO GUI DRAWING STUFF*/
    JScrollPane scroll = null;
    {
      Box ibox = new Box(BoxLayout.Y_AXIS);
      if (pAssetManager.isEmpty()) {
        Component comps[] = UIFactory.createTitledPanels();
        JPanel tpanel = (JPanel) comps[0];
        JPanel vpanel = (JPanel) comps[1];

        tpanel.add(Box.createRigidArea(new Dimension(sTSize - 7, 0)));
        vpanel.add(Box.createHorizontalGlue());

        ibox.add(comps[2]);
      } else {

        for (String assetName : pAssetManager.keySet()) {
          String name = getShortName(assetName);
          AssetInfo info = pAssetManager.get(assetName);

          Component comps[] = UIFactory.createTitledPanels();
          JPanel tpanel = (JPanel) comps[0];
          JPanel vpanel = (JPanel) comps[1];
          String title = "Replace " + name + " with ";
          title += getShortName(info.getNewAsset());

          JDrawer shotList = new JDrawer(title, (JComponent) comps[2], true);
          ibox.add(shotList);

          for (String shot : info.getLoHiResShots().keySet()) {

            String shortShot = getShortName(shot);
            JBooleanField field =
                UIFactory.createTitledBooleanField(
                    tpanel,
                    shortShot,
                    sVSize,
                    vpanel,
                    sTSize,
                    "Whether to replace this asset source for the node.");
            field.setName(shot);
            field.setValue(true);

            if (!pSubstituteFields.containsKey(assetName))
              pSubstituteFields.put(assetName, new LinkedList<JBooleanField>());

            pSubstituteFields.get(assetName).add(field);
            UIFactory.addVerticalSpacer(tpanel, vpanel, 3);
          }
        }
      }

      {
        JPanel spanel = new JPanel();
        spanel.setName("Spacer");

        spanel.setMinimumSize(new Dimension(sTSize + sVSize, 7));
        spanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
        spanel.setPreferredSize(new Dimension(sTSize + sVSize, 7));

        ibox.add(spanel);
      }

      {
        scroll = new JScrollPane(ibox);
        scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        Dimension size = new Dimension(sTSize + sVSize + 52, 300);
        scroll.setMinimumSize(size);
        scroll.setPreferredSize(size);

        scroll.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
      }
    }

    /* query the user */
    JToolDialog diag = new JToolDialog("Update Assets Per Shot", scroll, "Confirm");
    diag.setVisible(true);

    /* Process User Input */
    if (diag.wasConfirmed()) {

      for (String asset : pSubstituteFields.keySet()) {
        for (JBooleanField field : pSubstituteFields.get(asset)) {
          Boolean bUpdate = field.getValue();
          if ((bUpdate == null) || !bUpdate) {
            pAssetManager.get(asset).getLoHiResShots().remove(field.getName());

            // logLine("\tRemoving: "+ getShortName(field.getName())
            // TODO		+" from list for "+ getShortName(asset));
          }
        }
      }
      return ": Modifying Nodes...";
    }
    return null;
  } // end confirmShotsToUpdate
  /** Initialize the common user interface components. */
  private void initUI() {
    /* initialize fields */
    {
      pFileSeqPanels = new TreeMap<FileSeq, JFileSeqPanel>();
    }

    /* initialize the popup menus */
    {
      initBasicMenus(true, false);
      updateMenuToolTips();
    }

    /* initialize the panel components */
    {
      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

      /* header */
      {
        pApplyToolTipText = "Replace the working area files with the selected checked-in files.";
        pUnApplyToolTipText = "There are no unsaved changes to Apply at this time.";

        JPanel panel = initHeader(true);
        add(panel);
      }

      add(Box.createRigidArea(new Dimension(0, 4)));

      /* full node name */
      {
        LinkedList<Component> extra = new LinkedList<Component>();
        extra.add(Box.createRigidArea(new Dimension(4, 0)));
        {
          JButton btn = new JButton();
          pSeqLayoutButton = btn;
          btn.setName(pIsListLayout ? "ListLayoutButton" : "TabbedLayoutButton");

          Dimension size = new Dimension(19, 19);
          btn.setMinimumSize(size);
          btn.setMaximumSize(size);
          btn.setPreferredSize(size);

          btn.setActionCommand("seq-layout-changed");
          btn.addActionListener(this);

          extra.add(btn);
        }

        initNameField(this, extra);

        pNodeNameField.setFocusable(true);
        pNodeNameField.addKeyListener(this);
        pNodeNameField.addMouseListener(this);
      }

      add(Box.createRigidArea(new Dimension(0, 4)));

      {
        JTabbedPane tab = new JTabbedPane();
        pFileSeqsTab = tab;
        tab.setVisible(!pIsListLayout);
        add(tab);
      }

      {
        Box vbox = new Box(BoxLayout.Y_AXIS);
        pFileSeqsBox = vbox;

        {
          JScrollPane scroll = UIFactory.createVertScrollPane(vbox);
          pFileSeqsScroll = scroll;
          scroll.setVisible(!pIsListLayout);

          add(scroll);
        }
      }

      Dimension size = new Dimension(sSize + 22, 120);
      setMinimumSize(size);
      setPreferredSize(size);

      setFocusable(true);
      addKeyListener(this);
      addMouseListener(this);
    }

    updateNodeStatus(null, null, null);
  }
  /**
   * Update the UI components to reflect the current per-file status.
   *
   * @param status The current node status.
   * @param novelty The per-file novelty flags.
   * @param offline The revision numbers of the offline checked-in versions.
   */
  protected synchronized void updateNodeStatus(
      NodeStatus status,
      TreeMap<VersionID, TreeMap<FileSeq, boolean[]>> novelty,
      TreeSet<VersionID> offline) {
    super.updateNodeStatus(status, false);

    pNovelty = novelty;
    pOffline = offline;

    NodeDetailsLight details = null;
    if (pStatus != null) details = pStatus.getLightDetails();

    /* files */
    {
      pFileSeqsTab.removeAll();
      pFileSeqsBox.removeAll();
      pFileSeqPanels.clear();

      if ((pNovelty != null) && (details != null)) {
        NodeMod mod = details.getWorkingVersion();
        NodeVersion vsn = details.getLatestVersion();

        NodeCommon com = null;
        if (mod != null) com = mod;
        else if (vsn != null) com = vsn;
        else assert (false);

        /* get the primary and unique secondary file sequences */
        FileSeq primary = com.getPrimarySequence();
        TreeSet<FileSeq> secondary = new TreeSet<FileSeq>();
        {
          secondary.addAll(com.getSecondarySequences());

          TreeSet<FileSeq> unique = new TreeSet<FileSeq>();
          for (TreeMap<FileSeq, boolean[]> table : pNovelty.values()) unique.addAll(table.keySet());

          for (FileSeq ufseq : unique) {
            boolean found = false;

            if (ufseq.similarTo(primary)) found = true;
            else {
              for (FileSeq fseq : secondary) {
                if (ufseq.similarTo(fseq)) {
                  found = true;
                  break;
                }
              }
            }

            if (!found) secondary.add(ufseq);
          }
        }

        /* add the file sequence UI components */
        addFileSeqPanel(primary);
        for (FileSeq fseq : secondary) addFileSeqPanel(fseq);

        if (pIsListLayout) pFileSeqsBox.add(UIFactory.createFiller(sSize));
      }
    }

    pFileSeqsTab.setVisible(!pIsListLayout);
    pFileSeqsScroll.setVisible(pIsListLayout);

    if (pIsListLayout) pFileSeqsScroll.revalidate();
    else pFileSeqsTab.revalidate();
  }