gt:         panelDefaultOutputs = new javax.swing.JPanel();
context: /*
   * To change this template, choose Tools | Templates
   * and open the template in the editor.
   */
  
  /*
   * OutputPanel.java
   *
   * Created on 15-Apr-2012, 1:28:32 AM
   */
  package webcamstudio.components;
  
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.datatransfer.DataFlavor;
  import java.awt.datatransfer.UnsupportedFlavorException;
  import java.awt.dnd.DnDConstants;
  import java.awt.dnd.DropTarget;
  import java.awt.dnd.DropTargetDropEvent;
  import java.awt.event.ActionEvent;
  import java.awt.event.MouseEvent;
  import java.awt.image.BufferedImage;
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.Reader;
  import java.net.URISyntaxException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.TreeMap;
  import java.util.logging.Level;
  import java.util.logging.Logger;
  import java.util.prefs.BackingStoreException;
  import java.util.prefs.Preferences;
  import javax.swing.*;
  import javax.swing.filechooser.FileNameExtensionFilter;
  import webcamstudio.WebcamStudio;
  import static webcamstudio.WebcamStudio.theme;
  import webcamstudio.channels.MasterChannels;
  import static webcamstudio.components.ChannelPanel.lblOnAir;
  import webcamstudio.exporter.vloopback.VideoDevice;
  import webcamstudio.externals.FME;
  import webcamstudio.media.renderer.Exporter;
  import webcamstudio.mixers.MasterMixer;
  import webcamstudio.streams.SinkAudio;
  import webcamstudio.streams.SinkBroadcast;
  import webcamstudio.streams.SinkFile;
  import webcamstudio.streams.SinkLinuxDevice;
  import webcamstudio.streams.SinkUDP;
  import webcamstudio.streams.Stream;
  import webcamstudio.util.GridLayout2;
  import webcamstudio.util.Tools;
  import webcamstudio.util.Tools.OS;
  
  /**
   *
   * @author patrick (modified by karl)
   */
  public class OutputPanel extends javax.swing.JPanel implements Stream.Listener, WebcamStudio.Listener, ChannelPanel.Listener, Exporter.Listener {
  
      TreeMap<String, SinkFile> files = new TreeMap<>();
      TreeMap<String, SinkBroadcast> broadcasts = new TreeMap<>();
      ArrayList<String> broadcastsOut = new ArrayList<>();
      TreeMap<String, SinkLinuxDevice> devices = new TreeMap<>();
      ArrayList<String> devicesOut = new ArrayList<>();
      TreeMap<String, SinkUDP> udpOut = new TreeMap<>();
      TreeMap<String, SinkAudio> audioOut = new TreeMap<>();
      TreeMap<String, FME> fmes = new TreeMap<>();
      private final static String userHomeDir = Tools.getUserHome();
      boolean skyCamMode = false;
      int camCount = 0;
      int fmeCount = 0;
      String virtualDevice = "webcamstudio";
      TreeMap<String, ResourceMonitorLabel> labels = new TreeMap<>();
      JPanel wDFrame;
      FME currFME;
      JPopupMenu fmePopup = new JPopupMenu();
      JPopupMenu sinkFilePopup = new JPopupMenu();
      JPopupMenu sinkUDPPopup = new JPopupMenu();
      File f;
      SinkFile fileStream;
      SinkUDP udpStream;
      SinkAudio audioStream;
      private boolean audioOutState = false;
      private boolean udpOutState = false;
      private boolean audioOutSwitch = false;
      private boolean udpOutSwitch = false;
      private boolean fmeOutState = false;
      private boolean fmeOutSwitch = false;
      private boolean camOutState = false;
      private boolean camOutSwitch = false;
      private final ArrayList<String> idWSOuts = new ArrayList<>();
      private String idWSAD;
      private String idDef;
      private String idWSOut;
      private final String[] v4l2PixelFormats = { "RGB24", "UYUV", "BGR24" };
  
  
      @SuppressWarnings("unchecked")
      /** Creates new form OutputPanel
       * @param aFrame */
      public OutputPanel(JPanel aFrame) {
          initComponents();
          GridLayout2 columLayout = new GridLayout2(0,1);
          this.setLayout(columLayout);
          panelPixelFormat.setLayout(columLayout);
          panelDefaultOutputs.setLayout(columLayout);
          panelVirtualAudio.setLayout(columLayout);
          panelVirtualC.setLayout(columLayout);
          panelVirtualA.setLayout(columLayout); 
          panelDefault.setLayout(columLayout);
          panelFME.setLayout(columLayout);
          comboPixelFormat.setModel(new javax.swing.DefaultComboBoxModel(v4l2PixelFormats));
          f = new File(userHomeDir + "/.webcamstudio/Record To File");
          udpStream = new SinkUDP();
          fileStream = new SinkFile(f);
          audioStream = new SinkAudio();
  //        System.out.println("SinkAudio"+audioStream);
  
          tglRecordToFile.addMouseListener(new java.awt.event.MouseAdapter() {
              @Override
              public void mousePressed(java.awt.event.MouseEvent evt) {
                  JToggleButton button = ((JToggleButton) evt.getSource());
                  if (!button.isSelected()) {
                      sinkFileRightMousePressed(evt);
                  }
              }
          });
  
          tglUDP.addMouseListener(new java.awt.event.MouseAdapter() {
              @Override
              public void mousePressed(java.awt.event.MouseEvent evt) {
                  JToggleButton button = ((JToggleButton) evt.getSource());
                  if (!button.isSelected()) {
                      sinkUDPRightMousePressed(evt);
                  }
              }
          });
  
          wDFrame = aFrame;
          fmeInitPopUp();
          sinkFileInitPopUp();
          sinkUDPInitPopUp();
          final OutputPanel instanceSinkOP = this;
          WebcamStudio.setListenerOP(instanceSinkOP);
          ChannelPanel.setListenerCPOPanel(instanceSinkOP);
          Exporter.setListenerEx(instanceSinkOP);
          if (Tools.getOS() == OS.LINUX) {
              paintWSCamButtons ();
          }
  
          fileStream.setWidth(MasterMixer.getInstance().getWidth());
          fileStream.setHeight(MasterMixer.getInstance().getHeight());
          fileStream.setRate(MasterMixer.getInstance().getRate());
  
          udpStream.setWidth(MasterMixer.getInstance().getWidth());
          udpStream.setHeight(MasterMixer.getInstance().getHeight());
          udpStream.setRate(MasterMixer.getInstance().getRate());
  
          this.setDropTarget(new DropTarget() {
  
              @Override
              public synchronized void drop(DropTargetDropEvent evt) {
                  try {
                      String fileName = "";
                      evt.acceptDrop(DnDConstants.ACTION_REFERENCE);
                      boolean success = false;
                      DataFlavor dataFlavor = null;
                      if (evt.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                          dataFlavor = DataFlavor.javaFileListFlavor;
                      } else if (evt.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                          dataFlavor = DataFlavor.stringFlavor;
                      } else {
                          for (DataFlavor d : evt.getTransferable().getTransferDataFlavors()) {
                              if (evt.getTransferable().isDataFlavorSupported(d)) {
                                  System.out.println("Supported: " + d.getDefaultRepresentationClassAsString());
                                  dataFlavor = d;
                                  break;
                              }
                          }
                      }
                      Object data = evt.getTransferable().getTransferData(dataFlavor);
                      String files = "";
                      if (data instanceof Reader) {
                          char[] text = new char[65536];
                          files = new String(text).trim();
                      } else if (data instanceof InputStream) {
                          char[] text = new char[65536];
                          files = new String(text).trim();
                      } else if (data instanceof String) {
                          files = data.toString().trim();
                      } else {
                          List list = (List) data;
                          for (Object o : list) {
                              files += new File(o.toString()).toURI().toURL().toString() + "\n";
                          }
                      }
                      if (files.length() > 0) {
                          String[] lines = files.split("\n");
                          for (String line : lines) {
                              File file = new File(new URL(line.trim()).toURI());
                              fileName = file.getName();
                              if (file.exists() && file.getName().toLowerCase().endsWith("xml")) {
                                  success = true;
                                  FME fme = new FME(file);
                                  fmes.put(fme.getName(), fme);
                                  addButtonBroadcast(fme);
                              }
                          }
                      }
                      evt.dropComplete(success);
                      if (!success) {
                          ResourceMonitorLabel label = new ResourceMonitorLabel(System.currentTimeMillis() + 5000, "Unsupported file: " + fileName);
                          ResourceMonitor.getInstance().addMessage(label);
                      }
                  } catch (UnsupportedFlavorException | IOException | URISyntaxException ex) {
                      ex.printStackTrace();
                  }
              }
  
          });
      }
  
      public void loadPrefs(Preferences prefs) {
          Preferences fmePrefs = prefs.node("fme");
          Preferences filePrefs = prefs.node("filerec");
          Preferences udpPrefs = prefs.node("udp");
          try {
              String[] services = fmePrefs.childrenNames();
              String[] servicesF = filePrefs.childrenNames();
              String[] servicesU = udpPrefs.childrenNames();
  
              for (String s : servicesF){
                  Preferences serviceF = filePrefs.node(s);
                  fileStream.setVbitrate(serviceF.get("vbitrate", "1200"));
                  fileStream.setAbitrate(serviceF.get("abitrate", "128"));
              }
  
              for (String s : servicesU){
                  Preferences serviceU = udpPrefs.node(s);
                  udpStream.setVbitrate(serviceU.get("vbitrate", "1200"));
                  udpStream.setAbitrate(serviceU.get("abitrate", "128"));
                  udpStream.setStandard(serviceU.get("standard", "STD"));
              }
  
              for (String s : services) {
                  Preferences service = fmePrefs.node(s);
                  String url = service.get("url", "");
                  String name = service.get("name", "");
                  String abitrate = service.get("abitrate", "512000");
                  String vbitrate = service.get("vbitrate", "96000");
                  String vcodec = service.get("vcodec", "");
                  String acodec = service.get("acodec", "");
                  String width = service.get("width", "");
                  String height = service.get("height", "");
                  String stream = service.get("stream", "");
                  String mount = service.get("mount", "");
                  String password = service.get("password", "");
                  String port = service.get("port", "");
                  String keyInt = service.get("keyint", "");
                  String standard = service.get("standard", "STD");
                  // for compatibility before KeyInt
                  if ("".equals(keyInt)) {
                      keyInt = "125";
                  }
  
  //                System.out.println("Loaded KeyInt: "+keyInt+"###");
                  FME fme = new FME(url, stream, name, abitrate, vbitrate, vcodec, acodec, width, height, mount, password, port, keyInt);
                  fme.setStandard(standard);
                  fmes.put(fme.getName(), fme);
                  addButtonBroadcast(fme);
              }
          } catch (BackingStoreException ex) {
              Logger.getLogger(OutputPanel.class.getName()).log(Level.SEVERE, null, ex);
          }
  
      }
  
      public void savePrefs(Preferences prefs) {
          Preferences fmePrefs = prefs.node("fme");
          Preferences filePrefs = prefs.node("filerec");
          Preferences udpPrefs = prefs.node("udp");
          try {
              fmePrefs.removeNode();
              fmePrefs.flush();
              fmePrefs = prefs.node("fme");
              filePrefs.removeNode();
              filePrefs.flush();
              filePrefs = prefs.node("filerec");
              udpPrefs.removeNode();
              udpPrefs.flush();
              udpPrefs = prefs.node("udp");
          } catch (BackingStoreException ex) {
              Logger.getLogger(OutputPanel.class.getName()).log(Level.SEVERE, null, ex);
          }
          for (FME fme : fmes.values()) {
              Preferences service = fmePrefs.node(fme.getName());
              service.put("url", fme.getUrl());
              service.put("name", fme.getName());
              service.put("abitrate", fme.getAbitrate());
              service.put("vbitrate", fme.getVbitrate());
              service.put("vcodec", fme.getVcodec());
              service.put("acodec", fme.getAcodec());
              service.put("width", fme.getWidth());
              service.put("height", fme.getHeight());
              service.put("stream", fme.getStream());
              service.put("mount", fme.getMount());
              service.put("password", fme.getPassword());
              service.put("port", fme.getPort());
              service.put("keyint", fme.getKeyInt());
              service.put("standard", fme.getStandard());
          }
          Preferences serviceF = filePrefs.node("frecordset");
          serviceF.put("abitrate", fileStream.getAbitrate());
          serviceF.put("vbitrate", fileStream.getVbitrate());
          Preferences serviceU = udpPrefs.node("uoutset");
          serviceU.put("abitrate", udpStream.getAbitrate());
          serviceU.put("vbitrate", udpStream.getVbitrate());
          serviceU.put("standard", udpStream.getStandard());
      }
  
      private String checkDoubleBroad(String s) {
          String res = s;
          for (String broName : broadcastsOut) {
              if (s.equals(broName)){
                  res = "";
              }
          }
          return res;
      }
  
      private String checkDoubleCam(String s) {
          String res = s;
          for (String camName : devicesOut) {
              if (s.equals(camName)){
                  res = "";
              }
          }
          return res;
      }
  
      private void addButtonBroadcast(final FME fme) {
          final OutputPanel instanceSinkFME = this;
          JToggleButton button = new JToggleButton();
  //        Dimension d = new Dimension(139,22);
  //        button.setPreferredSize(d);
          button.setText(fme.getName());
          button.setActionCommand(fme.getUrl()+"/"+fme.getStream());
          button.setIcon(tglRecordToFile.getIcon());
          button.setSelectedIcon(tglRecordToFile.getSelectedIcon());
          button.setRolloverEnabled(false);
          button.setToolTipText("Drag to the right to Remove... - Right Click for Settings");
          button.addActionListener(new java.awt.event.ActionListener() {
  
              @Override
              public void actionPerformed(ActionEvent evt) {
                  JToggleButton button = ((JToggleButton) evt.getSource());
                  FME fme = fmes.get(button.getText());
                  if (button.isSelected()) {
                      if (fme != null){
                          fmeOutState = true;
                          String cleanBroad = checkDoubleBroad(button.getText());
                          if (!"".equals(cleanBroad)) {
                              broadcastsOut.add(cleanBroad);
  //                            System.out.println("broadcastsOut: "+broadcastsOut);
                          }
                          fmeCount ++;
                          SinkBroadcast broadcast = new SinkBroadcast(fme);
                          broadcast.setStandard(fme.getStandard());
                          broadcast.setRate(MasterMixer.getInstance().getRate());
                          broadcast.setWidth(MasterMixer.getInstance().getWidth());
                          fme.setWidth(Integer.toString(MasterMixer.getInstance().getWidth()));
                          broadcast.setHeight(MasterMixer.getInstance().getHeight());
                          fme.setHeight(Integer.toString(MasterMixer.getInstance().getHeight()));
                          broadcast.setListener(instanceSinkFME);
                          broadcast.read();
                          broadcasts.put(button.getText(), broadcast);
                          ResourceMonitorLabel label = new ResourceMonitorLabel(System.currentTimeMillis()+10000, "Broadcasting to " + fme.getName());
                          labels.put(fme.getName(), label);
                          ResourceMonitor.getInstance().addMessage(label);
                          lblOnAir.setForeground(Color.RED);
                      } else {
                          fmeCount --;
                          button.setSelected(false);
                      }
                  } else {
                      fmeOutState = fmeCount > 0;
                      broadcastsOut.remove(button.getText());
                      SinkBroadcast broadcast = broadcasts.get(button.getText());
                      if (broadcast != null) {
                          fmeCount --;
                          broadcast.stop();
                          broadcast.destroy();
                          broadcasts.remove(fme.getName());
                          ResourceMonitorLabel label = labels.get(fme.getName());
                          labels.remove(fme.getName());
                          ResourceMonitor.getInstance().removeMessage(label);
                          if (fmeCount == 0 && !udpOutState) {
                              if (theme.equals("Dark")) {
                                  lblOnAir.setForeground(Color.WHITE);
                              } else {
                                  lblOnAir.setForeground(Color.BLACK);
                              }
                          }
                      }
                  }
              }
          });
          button.addMouseMotionListener(new java.awt.event.MouseMotionListener() {
  
              @Override
              public void mouseDragged(MouseEvent e) {
                  if (e.getX() > getWidth()) {
                      JToggleButton button = ((JToggleButton) e.getSource());
                      if (!button.isSelected() && e.getX() > getWidth()) {
                          System.out.println(button.getText()+" removed ...");
                          SinkBroadcast broadcast = broadcasts.remove(button.getText());
                          if (broadcast != null) {
                              MasterChannels.getInstance().unregister(broadcast);
                          }
                          fmes.remove(button.getText());
                          labels.remove(fme.getName());
                          remove(button);
                          revalidate();
                      }
                  }
              }
  
              @Override
              public void mouseMoved(MouseEvent e) {
              }
          });
          button.addMouseListener(new java.awt.event.MouseAdapter() {
              @Override
              public void mousePressed(MouseEvent evt) {
                  JToggleButton button = ((JToggleButton) evt.getSource());
                  if (!button.isSelected()) {
                      fmeRightMousePressed(evt, fme);
                  }
              }
          });
          this.add(button);
          this.revalidate();
      }
  
      private void fmeRightMousePressed(java.awt.event.MouseEvent evt, FME fme) {
          if (evt.isPopupTrigger()) {
              fmePopup.show(evt.getComponent(), evt.getX(), evt.getY());
              currFME = fme;
          }
      }
  
      private void sinkFileRightMousePressed(java.awt.event.MouseEvent evt) { // , SinkFile sinkfile
          if (evt.isPopupTrigger()) {
              sinkFilePopup.show(evt.getComponent(), evt.getX(), evt.getY());
          }
      }
  
      private void sinkUDPRightMousePressed(java.awt.event.MouseEvent evt) {
          if (evt.isPopupTrigger()) {
              sinkUDPPopup.show(evt.getComponent(), evt.getX(), evt.getY());
          }
      }
  
      private void fmeInitPopUp(){
          JMenuItem fmeSettings = new JMenuItem (new AbstractAction("FME Settings") {
              @Override
              public void actionPerformed(ActionEvent e) {
                  FMESettings fmeSet = new FMESettings(currFME);
                  fmeSet.setLocationRelativeTo(WebcamStudio.cboAnimations);
                  fmeSet.setAlwaysOnTop(true);
                  fmeSet.setVisible(true);
              }
          });
          fmeSettings.setIcon(new ImageIcon(getClass().getResource("/webcamstudio/resources/tango/working-4.png"))); // NOI18N
          fmePopup.add(fmeSettings);
      }
  
      private void sinkFileInitPopUp(){
          JMenuItem sinkSettings = new JMenuItem (new AbstractAction("Record Settings") {
              @Override
              public void actionPerformed(ActionEvent e) {
                  SinkSettings sinkSet = new SinkSettings(fileStream, null);
                  sinkSet.setLocationRelativeTo(WebcamStudio.cboAnimations);
                  sinkSet.setAlwaysOnTop(true);
                  sinkSet.setVisible(true);
              }
          });
          sinkSettings.setIcon(new ImageIcon(getClass().getResource("/webcamstudio/resources/tango/working-4.png"))); // NOI18N
          sinkFilePopup.add(sinkSettings);
      }
  
      private void sinkUDPInitPopUp(){
          JMenuItem sinkSettings = new JMenuItem (new AbstractAction("UDP Settings") {
              @Override
              public void actionPerformed(ActionEvent e) {
                  SinkSettings sinkSet = new SinkSettings(null, udpStream);
                  sinkSet.setLocationRelativeTo(WebcamStudio.cboAnimations);
                  sinkSet.setAlwaysOnTop(true);
                  sinkSet.setVisible(true);
              }
          });
          sinkSettings.setIcon(new ImageIcon(getClass().getResource("/webcamstudio/resources/tango/working-4.png"))); // NOI18N
          sinkUDPPopup.add(sinkSettings);
      }
  
      /** This method is called from within the constructor to
       * initialize the form.
       * WARNING: Do NOT modify this code. The content of this method is
       * always regenerated by the Form Editor.
       */
      @SuppressWarnings("unchecked")
      // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
      private void initComponents() {
  
          outputTabs = new javax.swing.JTabbedPane();
          panelVirtualC = new javax.swing.JPanel();
          panelPixelFormat = new javax.swing.JPanel();
          labelPixelFormat = new javax.swing.JLabel();
          comboPixelFormat = new javax.swing.JComboBox();
          panelVirtualA = new javax.swing.JPanel();
          panelVirtualAudio = new javax.swing.JPanel();
          tglWSAudioDev = new javax.swing.JCheckBox();
          tglAudioOut = new javax.swing.JToggleButton();
          panelDefault = new javax.swing.JPanel();
  