/**
   * Handles registration of a new configuration form.
   *
   * @param event the <tt>ServiceEvent</tt> that notified us
   */
  public void serviceChanged(ServiceEvent event) {
    Object sService = AdvancedConfigActivator.bundleContext.getService(event.getServiceReference());

    // we don't care if the source service is not a configuration form
    if (!(sService instanceof ConfigurationForm)) return;

    ConfigurationForm configForm = (ConfigurationForm) sService;

    /*
     * This AdvancedConfigurationPanel is an advanced ConfigurationForm so
     * don't try to add it to itself.
     */
    if ((configForm == this) || !configForm.isAdvanced()) return;

    switch (event.getType()) {
      case ServiceEvent.REGISTERED:
        if (logger.isInfoEnabled())
          logger.info("Handling registration of a new Configuration Form.");

        this.addConfigForm(configForm);
        break;

      case ServiceEvent.UNREGISTERING:
        this.removeConfigForm(configForm);
        break;
    }
  }
Exemple #2
0
  /**
   * Sets the current device controller to the given value.
   *
   * @param aDeviceName the name of the device controller to set, cannot be <code>null</code>.
   */
  public synchronized void setDeviceController(final String aDeviceName) {
    if (LOG.isLoggable(Level.INFO)) {
      final String name = (aDeviceName == null) ? "no device" : aDeviceName;
      LOG.log(Level.INFO, "Setting current device controller to: \"{0}\" ...", name);
    }

    final Collection<DeviceController> devices = getDevices();
    for (DeviceController device : devices) {
      if (aDeviceName.equals(device.getName())) {
        this.currentDevCtrl = device;
      }
    }

    updateActions();
  }
Exemple #3
0
  /**
   * Runs the tool denoted by the given name.
   *
   * @param aToolName the name of the tool to run, cannot be <code>null</code>;
   * @param aParent the parent window to use, can be <code>null</code>.
   */
  public void runTool(final String aToolName, final Window aParent) {
    if (LOG.isLoggable(Level.INFO)) {
      LOG.log(Level.INFO, "Running tool: \"{0}\" ...", aToolName);
    }

    final Tool tool = findToolByName(aToolName);
    if (tool == null) {
      JOptionPane.showMessageDialog(
          aParent, "No such tool found: " + aToolName, "Error ...", JOptionPane.ERROR_MESSAGE);
    } else {
      final ToolContext context = createToolContext();
      tool.process(aParent, this.dataContainer, context, this);
    }

    updateActions();
  }
  public void scrollToAttribute(Attribute a) {
    if (!a.getDescriptor().getConfig().equals(getConfig())) {
      logger.fine("Cannot scroll to attribute that isn't attached to this type of descriptor");
      return;
    }
    int rowIndex = getCurrentModel().getRowForDescriptor(a.getDescriptor());
    int colIndex = getCurrentModel().getColumnForAttribute(a);
    JScrollPane scrollPane = (JScrollPane) this.getComponent(0);
    JViewport viewport = (JViewport) scrollPane.getViewport();
    EnhancedTable table = (EnhancedTable) viewport.getView();

    // This rectangle is relative to the table where the
    // northwest corner of cell (0,0) is always (0,0).
    Rectangle rect = table.getCellRect(rowIndex, colIndex, true);

    // The location of the viewport relative to the table
    Point pt = viewport.getViewPosition();

    // Translate the cell location so that it is relative
    // to the view, assuming the northwest corner of the
    // view is (0,0)
    rect.setLocation(rect.x - pt.x, rect.y - pt.y);

    // Scroll the area into view
    viewport.scrollRectToVisible(rect);
  }
Exemple #5
0
 public void actionPerformed(ActionEvent e) {
   try {
     undo.redo();
   } catch (CannotRedoException ex) {
     Logger.getLogger(RedoAction.class.getName()).log(Level.SEVERE, "Unable to redo", ex);
   }
   update();
   undoAction.update();
 }
Exemple #6
0
    @Override
    @SuppressWarnings("SleepWhileHoldingLock")
    public void run() {
      try {
        // initialize the statusbar
        status.removeAll();
        JProgressBar progress = new JProgressBar();
        progress.setMinimum(0);
        progress.setMaximum(doc.getLength());
        status.add(progress);
        status.revalidate();

        // start writing
        Writer out = new FileWriter(f);
        Segment text = new Segment();
        text.setPartialReturn(true);
        int charsLeft = doc.getLength();
        int offset = 0;
        while (charsLeft > 0) {
          doc.getText(offset, Math.min(4096, charsLeft), text);
          out.write(text.array, text.offset, text.count);
          charsLeft -= text.count;
          offset += text.count;
          progress.setValue(offset);
          try {
            Thread.sleep(10);
          } catch (InterruptedException e) {
            Logger.getLogger(FileSaver.class.getName()).log(Level.SEVERE, null, e);
          }
        }
        out.flush();
        out.close();
      } catch (IOException e) {
        final String msg = e.getMessage();
        SwingUtilities.invokeLater(
            new Runnable() {

              public void run() {
                JOptionPane.showMessageDialog(
                    getFrame(),
                    "Could not save file: " + msg,
                    "Error saving file",
                    JOptionPane.ERROR_MESSAGE);
              }
            });
      } catch (BadLocationException e) {
        System.err.println(e.getMessage());
      }
      // we are done... get rid of progressbar
      status.removeAll();
      status.revalidate();
    }
  public PrintfEditor(Frame frame, String title) {
    super(frame, title, false);

    originalTemplate = new PrintfTemplate();
    editableTemplate = new PrintfTemplate();
    try {
      jbInit();
      pack();
      initMatches();
    } catch (Exception exc) {
      String logMessage = "Could not set up the printf editor";
      logger.critical(logMessage, exc);
      JOptionPane.showMessageDialog(frame, logMessage, "Printf Editor", JOptionPane.ERROR_MESSAGE);
    }
  }
Exemple #8
0
  /**
   * Create preview component.
   *
   * @param type type
   * @param comboBox the options.
   * @param prefSize the preferred size
   * @return the component.
   */
  private static Component createPreview(int type, final JComboBox comboBox, Dimension prefSize) {
    JComponent preview = null;

    if (type == DeviceConfigurationComboBoxModel.AUDIO) {
      Object selectedItem = comboBox.getSelectedItem();

      if (selectedItem instanceof AudioSystem) {
        AudioSystem audioSystem = (AudioSystem) selectedItem;

        if (!NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase(audioSystem.getLocatorProtocol())) {
          preview = new TransparentPanel(new GridBagLayout());
          createAudioSystemControls(audioSystem, preview);
        }
      }
    } else if (type == DeviceConfigurationComboBoxModel.VIDEO) {
      JLabel noPreview =
          new JLabel(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.NO_PREVIEW"));

      noPreview.setHorizontalAlignment(SwingConstants.CENTER);
      noPreview.setVerticalAlignment(SwingConstants.CENTER);

      preview = createVideoContainer(noPreview);
      preview.setPreferredSize(prefSize);

      Object selectedItem = comboBox.getSelectedItem();
      CaptureDeviceInfo device = null;
      if (selectedItem instanceof DeviceConfigurationComboBoxModel.CaptureDevice)
        device = ((DeviceConfigurationComboBoxModel.CaptureDevice) selectedItem).info;

      Exception exception;
      try {
        createVideoPreview(device, preview);
        exception = null;
      } catch (IOException ex) {
        exception = ex;
      } catch (MediaException ex) {
        exception = ex;
      }
      if (exception != null) {
        logger.error("Failed to create preview for device " + device, exception);
        device = null;
      }
    }

    return preview;
  }
public class MyFileListTable extends MyDefaultTable {
  private static Logger log = Logger.getLogger(MyFileListTable.class.getName());

  public MyFileListTable() {
    super();
  }

  public MyFileListTable(TableModel dm) {
    super(dm);
  }

  protected void init() {
    super.init();
    setRowHeight(16);
    setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    enableAutoPack(true);
  }

  public TableCellRenderer getCellRenderer(int row, int column) {
    // log.info(row+", "+column);
    return super.getCellRenderer(row, column);
  }

  protected void resizeTable() {
    if (getColumnCount() > 1) {
      packColumn(this, 0);
      packColumn(this, 1);
    }
  }

  /** Overrides <code>JComponent</code>'s <code>getToolTipText</code> */
  public String getToolTipText(MouseEvent e) {
    String tip = null;
    java.awt.Point p = e.getPoint();
    int rowIndex = rowAtPoint(p);
    // int colIndex = columnAtPoint(p);
    // int realColumnIndex = convertColumnIndexToModel(colIndex);
    TableModel model = getModel();
    tip = (String) model.getValueAt(rowIndex, 1);
    return tip;
  }
}
Exemple #10
0
 // /home/jean/Área de Trabalho/Link para Dropbox/workspace/GSPAnalyzer/grails app
 // examples/rgms-master/grails-app/views/bookChapter/show.gsp
 private void process(String uri) {
   try {
     URL url;
     try {
       url = new URL(uri);
     } catch (java.net.MalformedURLException mfu) {
       int idx = uri.indexOf(':');
       if (idx == -1 || idx == 1) {
         // try file
         url = new URL("file:" + uri);
       } else {
         throw mfu;
       }
     }
     // Call SimpleHtmlRendererContext.navigate()
     // which implements incremental rendering.
     this.rcontext.navigate(url, null);
   } catch (Exception err) {
     logger.log(Level.SEVERE, "Error trying to load URI=[" + uri + "].", err);
   }
 }
/**
 * QSAdminGUI - Control Panel for QuickServer Admin GUI - QSAdminGUI
 *
 * @author Akshathkumar Shetty
 * @since 1.3
 */
public class QSAdminGUI extends JPanel /*JFrame*/ {
  private static Logger logger = Logger.getLogger(QSAdminGUI.class.getName());

  private static QSAdminMain qsadminMain = null;
  private static String pluginDir = "./../plugin";

  private ClassLoader classLoader = getClass().getClassLoader();
  public ImageIcon logo = new ImageIcon(classLoader.getResource("icons/logo.gif"));
  public ImageIcon logoAbout = new ImageIcon(classLoader.getResource("icons/logo.png"));
  public ImageIcon ball = new ImageIcon(classLoader.getResource("icons/ball.gif"));

  private HeaderPanel headerPanel;
  private MainCommandPanel mainCommandPanel;
  private CmdConsole cmdConsole;
  private PropertiePanel propertiePanel;
  // private StatsPanel statsPanel;

  private JTabbedPane tabbedPane;
  private JFrame parentFrame;

  final HashMap pluginPanelMap = new HashMap();

  // --v1.3.2
  private ArrayList plugins = new ArrayList();

  private JMenu mainMenu, helpMenu;
  private JMenuBar jMenuBar;
  private JMenuItem loginMenuItem, exitMenuItem, aboutMenuItem;

  /** Logs the interaction, Type can be S - Server Sent C - Client Sent */
  public void logComand(String command, char type) {
    logger.info("For[" + type + "] " + command);
  }

  /** Displays the QSAdminGUi with in a JFrame. */
  public static void showGUI(String args[], final SplashScreen splash) {
    java.awt.EventQueue.invokeLater(
        new Runnable() {
          public void run() {
            try {
              UIManager.setLookAndFeel("net.sourceforge.mlf.metouia.MetouiaLookAndFeel");
            } catch (Exception e) {
              try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
              } catch (Exception ee) {
              }
            }

            qsadminMain = new QSAdminMain();

            JFrame frame = new JFrame("QSAdmin GUI");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            QSAdminGUI qsAdminGUI = new QSAdminGUI(qsadminMain, frame);
            qsAdminGUI.updateConnectionStatus(false);
            frame.getContentPane().add(qsAdminGUI);
            frame.pack();
            frame.setSize(700, 450);
            frame.setIconImage(qsAdminGUI.logo.getImage());
            JFrameUtilities.centerWindow(frame);
            frame.setVisible(true);
            if (splash != null) splash.kill();
          }
        });
  }

  public QSAdminGUI(QSAdminMain qsadminMain, JFrame parentFrame) {
    this.parentFrame = parentFrame;
    Container cp = this;
    qsadminMain.setGUI(this);
    cp.setLayout(new BorderLayout(5, 5));
    headerPanel = new HeaderPanel(qsadminMain, parentFrame);
    mainCommandPanel = new MainCommandPanel(qsadminMain);
    cmdConsole = new CmdConsole(qsadminMain);
    propertiePanel = new PropertiePanel(qsadminMain);

    if (headerPanel == null
        || mainCommandPanel == null
        || cmdConsole == null
        || propertiePanel == null) {
      throw new RuntimeException("Loading of one of gui component failed.");
    }

    headerPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
    cp.add(headerPanel, BorderLayout.NORTH);
    JScrollPane propertieScrollPane = new JScrollPane(propertiePanel);
    // JScrollPane commandScrollPane = new JScrollPane(mainCommandPanel);
    JSplitPane splitPane =
        new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, mainCommandPanel, cmdConsole);
    splitPane.setOneTouchExpandable(false);
    splitPane.setDividerLocation(250);
    // splitPane.setDividerLocation(0.70);

    tabbedPane = new JTabbedPane(JTabbedPane.TOP);
    tabbedPane.addTab("Main", ball, splitPane, "Main Commands");
    tabbedPane.addTab("Get/Set", ball, propertieScrollPane, "Properties Panel");

    QSAdminPluginConfig qsAdminPluginConfig = null;
    PluginPanel pluginPanel = null;
    // -- start of loadPlugins
    try {
      File xmlFile = null;
      ClassLoader classLoader = null;
      Class mainClass = null;

      File file = new File(pluginDir);
      File dirs[] = null;

      if (file.canRead()) dirs = file.listFiles(new DirFileList());

      for (int i = 0; dirs != null && i < dirs.length; i++) {
        xmlFile = new File(dirs[i].getAbsolutePath() + File.separator + "plugin.xml");
        if (xmlFile.canRead()) {
          qsAdminPluginConfig = PluginConfigReader.read(xmlFile);
          if (qsAdminPluginConfig.getActive().equals("yes")
              && qsAdminPluginConfig.getType().equals("javax.swing.JPanel")) {
            classLoader = ClassUtil.getClassLoaderFromJars(dirs[i].getAbsolutePath());
            mainClass = classLoader.loadClass(qsAdminPluginConfig.getMainClass());
            logger.fine("Got PluginMainClass " + mainClass);
            pluginPanel = (PluginPanel) mainClass.newInstance();
            if (JPanel.class.isInstance(pluginPanel) == true) {
              logger.info("Loading plugin : " + qsAdminPluginConfig.getName());
              pluginPanelMap.put("" + (2 + i), pluginPanel);
              plugins.add(pluginPanel);
              tabbedPane.addTab(
                  qsAdminPluginConfig.getName(),
                  ball,
                  (JPanel) pluginPanel,
                  qsAdminPluginConfig.getDesc());
              pluginPanel.setQSAdminMain(qsadminMain);
              pluginPanel.init();
            }
          } else {
            logger.info(
                "Plugin "
                    + dirs[i]
                    + " is disabled so skipping "
                    + qsAdminPluginConfig.getActive()
                    + ":"
                    + qsAdminPluginConfig.getType());
          }
        } else {
          logger.info("No plugin configuration found in " + xmlFile + " so skipping");
        }
      }
    } catch (Exception e) {
      logger.warning("Error loading plugin : " + e);
      logger.fine("StackTrace:\n" + MyString.getStackTrace(e));
    }
    // -- end of loadPlugins

    tabbedPane.addChangeListener(
        new ChangeListener() {
          int selected = -1;
          int oldSelected = -1;

          public void stateChanged(ChangeEvent e) {
            // if plugin
            selected = tabbedPane.getSelectedIndex();
            if (selected >= 2) {
              ((PluginPanel) pluginPanelMap.get("" + selected)).activated();
            }
            if (oldSelected >= 2) {
              ((PluginPanel) pluginPanelMap.get("" + oldSelected)).deactivated();
            }
            oldSelected = selected;
          }
        });

    // tabbedPane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    cp.add(tabbedPane, BorderLayout.CENTER);

    buildMenu();
  }

  public void setStatus(String msg) {
    headerPanel.setStatus(msg);
  }

  public void setResponse(String res) {
    int msgType = JOptionPane.PLAIN_MESSAGE;
    if (res.startsWith("+OK")) msgType = JOptionPane.INFORMATION_MESSAGE;
    if (res.startsWith("-ERR")) msgType = JOptionPane.ERROR_MESSAGE;
    JOptionPane.showMessageDialog(
        QSAdminGUI.this, res.substring(res.indexOf(" ") + 1), "Response", msgType);
  }

  public void appendToConsole(String msg) {
    cmdConsole.append(msg);
  }

  public void setConsoleSend(boolean flag) {
    cmdConsole.setSendEdit(flag);
  }

  public void updateConnectionStatus(boolean connected) {
    if (connected == true) {
      headerPanel.setLogoutText();
      loginMenuItem.setText("Logout");
    } else {
      headerPanel.setLoginText();
      loginMenuItem.setText("Login...");
    }
    mainCommandPanel.updateConnectionStatus(connected);
    propertiePanel.updateConnectionStatus(connected);
    cmdConsole.updateConnectionStatus(connected);
    Iterator iterator = plugins.iterator();
    PluginPanel updatePluginPanel = null;
    while (iterator.hasNext()) {
      updatePluginPanel = (PluginPanel) iterator.next();
      updatePluginPanel.updateConnectionStatus(connected);
    }

    if (connected == true) {
      int selected = tabbedPane.getSelectedIndex();
      if (selected >= 2) {
        ((PluginPanel) pluginPanelMap.get("" + selected)).activated();
      }
    }
  }

  // --v1.3.2
  public static void setPluginDir(String dir) {
    pluginDir = dir;
  }

  public static String getPluginDir() {
    return pluginDir;
  }

  private void buildMenu() {
    jMenuBar = new javax.swing.JMenuBar();
    mainMenu = new javax.swing.JMenu();
    mainMenu.setText("Main");

    loginMenuItem = new JMenuItem("Login...");
    loginMenuItem.addActionListener(
        new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
            headerPanel.handleLoginLogout();
          }
        });

    mainMenu.add(loginMenuItem);

    exitMenuItem = new JMenuItem("Exit");
    exitMenuItem.addActionListener(
        new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
            if (qsadminMain.isConnected() == true) {
              headerPanel.handleLoginLogout();
            }
            System.exit(0);
          }
        });
    mainMenu.add(exitMenuItem);

    helpMenu = new javax.swing.JMenu();
    helpMenu.setText("Help");

    aboutMenuItem = new JMenuItem("About...");
    aboutMenuItem.setEnabled(true);
    aboutMenuItem.addActionListener(
        new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
            about();
          }
        });
    helpMenu.add(aboutMenuItem);

    jMenuBar.add(mainMenu);
    jMenuBar.add(helpMenu);

    parentFrame.setJMenuBar(jMenuBar);
  }

  private void about() {
    JOptionPane.showMessageDialog(
        this,
        "QSAdminGUI\n\n"
            + "GUI Client for QSAdminServer of QuickServer.\n"
            + "This is compliant with QuickServer v"
            + QSAdminMain.VERSION_OF_SERVER
            + " release.\n\n"
            + "Copyright (C) QuickServer.org\n"
            + "http://www.quickserver.org",
        "About QSAdminGUI",
        JOptionPane.INFORMATION_MESSAGE,
        logoAbout);
  }
}
Exemple #12
0
/**
 * The ConfigEditor presents a JTree view of a viperdata configuration, presented within a
 * JScrollPane. The view is pretty straightforward, and can have a property sheet attached to it,
 * which displays the value for the currently selected node.
 *
 * @author David Mihalcik
 */
public class ConfigEditor extends JScrollPane {
  public static Logger logger = Logger.getLogger("edu.umd.cfar.lamp.viper.gui.config");

  private class ConfigEditPopup extends JPopupMenu {
    private JMenuItem newDescriptor;
    private JMenuItem newAttribute;
    private JMenuItem duplicate;
    private JMenuItem delete;

    private Node node;

    private class NewAttributeAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        createAttrConfigForNode(node);
      }
    }

    private class DeleteAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        node.getParent().removeChild(node);
      }
    }

    private class DuplicateAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {}
    }

    public ConfigEditPopup() {
      super("Config Properties");

      newDescriptor = new JMenuItem("New Descriptor Type");
      newDescriptor.addActionListener(newConfigListener);

      newAttribute = new JMenuItem("New Attribute Type");
      newAttribute.addActionListener(new NewAttributeAction());

      delete = new JMenuItem("Delete");
      delete.addActionListener(new DeleteAction());

      duplicate = new JMenuItem("Duplicate");
      duplicate.addActionListener(new DuplicateAction());

      add(newDescriptor);
      add(newAttribute);
      // add(duplicate);
      add(new JSeparator());
      add(delete);
    }

    public void show(Component invoker, int x, int y) {
      Object o = getTree().getClosestPathForLocation(x, y).getLastPathComponent();
      if (null != o) {
        node = (Node) o;
        if ((node instanceof AttrConfig) || (node instanceof Config)) {
          newAttribute.setEnabled(true);
          duplicate.setEnabled(true);
          delete.setEnabled(true);
        } else {
          newAttribute.setEnabled(false);
          duplicate.setEnabled(false);
          delete.setEnabled(false);
        }
        super.show(invoker, x, y);
      }
    }
  }

  private class MySelectionChangeListener implements TreeSelectionListener {
    public void valueChanged(TreeSelectionEvent e) {
      Node node = (Node) getTree().getLastSelectedPathComponent();
      if (getSheet() == null) return;
      if (node == null) {
        node = (Node) getTree().getPathForRow(0).getLastPathComponent();
      }
      nextToSetTo = node;
      if (getSheet().getObject() != nextToSetTo) {
        SwingUtilities.invokeLater(setSheetObject);
      }
    }
  }

  private Runnable setSheetObject =
      new Runnable() {
        public void run() {
          getSheet().setObject(nextToSetTo);
          nextToSetTo = null;
        }
      };
  private Object nextToSetTo = null;

  /**
   * Checks to see if a path to a Config node is expanded. It adds/removes the node from the
   * expandedNodes set as appropriate.
   */
  private class CheckIfExpanded implements Runnable {
    private TreePath t;
    /**
     * Creates a new check for the Config in the path.
     *
     * @param t The path to the descriptor config to check.
     */
    public CheckIfExpanded(TreePath t) {
      assert t.getLastPathComponent() instanceof Config;
      this.t = t;
    }

    public void run() {
      if (getTree().isExpanded(t)) {
        expandedNodes.add(t.getLastPathComponent());
      } else {
        expandedNodes.remove(t.getLastPathComponent());
      }
    }
  }

  private JPopupMenu popup;
  private ViperTreeModel model;
  private Set expandedNodes;

  /** Create a new config editor that isn't attached to any ViperData. */
  public ConfigEditor() {
    super(new JTree());
    popup = new ConfigEditPopup();
    getTree()
        .addMouseListener(
            new MouseAdapter() {
              public void mousePressed(MouseEvent e) {
                maybeShowPopup(e);
                TreePath p = getTree().getClosestPathForLocation(e.getX(), e.getY());
                Object end = p.getLastPathComponent();
                if (end instanceof Config) {
                  EventQueue.invokeLater(new CheckIfExpanded(p));
                }
              }

              public void mouseReleased(MouseEvent e) {
                maybeShowPopup(e);
              }

              private void maybeShowPopup(MouseEvent e) {
                if (e.isPopupTrigger()) {
                  popup.show(e.getComponent(), e.getX(), e.getY());
                }
              }
            });
    model = new ViperTreeModel(this);
    model.addTreeToSelect(getTree());
    // getTree().setRootVisible(false);
    expandedNodes = new HashSet();
    getTree().setModel(model);
    getTree().getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

    // Listen for when the selection changes.
    getTree().addTreeSelectionListener(new MySelectionChangeListener());
  }

  public void resetListOfExpandedNodes() {
    expandedNodes.clear();
    for (int i = 1; i < getTree().getRowCount(); i++) {
      if (getTree().isExpanded(i)) {
        Object o = getTree().getPathForRow(i).getLastPathComponent();
        if (o instanceof Config) {
          expandedNodes.add(o);
        }
      }
    }
  }

  Iterator getExpandedNodes() {
    return expandedNodes.iterator();
  }

  Config[] getCopyOfExpandedNodes() {
    return (Config[]) expandedNodes.toArray(new Config[0]);
  }

  /**
   * Call when an expanded node has gone missing
   *
   * @param c The config that is gone
   */
  void nodeRemoved(Config c) {
    expandedNodes.remove(c);
  }

  JTree getTree() {
    return (JTree) this.getViewport().getComponent(0);
  }

  /**
   * Get the viper view mediator.
   *
   * @return The mediator that the view is listening to.
   */
  public ViperViewMediator getMediator() {
    return model.getMediator();
  }

  /**
   * Sets the view mediator.
   *
   * @param mediator The mediator
   */
  public void setMediator(ViperViewMediator mediator) {
    model.setMediator(mediator);
  }

  private PropertySheet sheet;
  /**
   * Gets the current property sheet that is used to display the details about the selected node.
   *
   * @return a PropertySheet that displays (and allows the user to edit) the properties of the
   *     selected node
   */
  public PropertySheet getSheet() {
    return sheet;
  }
  /**
   * Sets the property sheet to keep updated.
   *
   * @param sheet A PropertySheet to reflect the value of the selected node.
   */
  public void setSheet(PropertySheet sheet) {
    this.sheet = sheet;
  }

  /**
   * An ActionListener for a 'Create New Descriptor Type' action.
   *
   * @return an ActionListener that creates a new descriptor.
   */
  public ActionListener getNewConfigActionListener() {
    return newConfigListener;
  }

  private ActionListener newConfigListener = new NewConfigActionListener();

  private class NewConfigActionListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      ViperData v = model.getMediator().getViperData();
      String newName = unusedName("Desc", new DescNameIter());
      Config c = v.createConfig(Config.OBJECT, newName);
      select(c);
    }
  }

  /** Iterates over the names of all the descriptors. */
  private class DescNameIter implements Iterator {
    private Iterator descs;

    public DescNameIter() {
      descs = model.getMediator().getViperData().getConfigs();
    }

    public void remove() {
      throw new UnsupportedOperationException();
    }

    public boolean hasNext() {
      return descs.hasNext();
    }

    public Object next() {
      return ((Config) descs.next()).getDescName();
    }
  }
  /** Iterates over the names of all the attributes for the given descriptor type. */
  private class AttrNameIter implements Iterator {
    private Iterator attrs;

    public AttrNameIter(Config c) {
      attrs = c.getChildren();
    }

    public void remove() {
      throw new UnsupportedOperationException();
    }

    public boolean hasNext() {
      return attrs.hasNext();
    }

    public Object next() {
      return ((AttrConfig) attrs.next()).getAttrName();
    }
  }

  /**
   * Returns an action listener that creates a new attribute for the currently selected descriptor
   * type. It doesn't do anything if no descriptor type is selected.
   *
   * @return An ActionListener that creates a new attribute field on the current descriptor type.
   */
  public ActionListener getNewAttrConfigActionListener() {
    return newAttrConfigListener;
  }

  private ActionListener newAttrConfigListener = new NewAttrConfigActionListener();

  private class NewAttrConfigActionListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      JTree tree = getTree();
      TreePath path = tree.getSelectionPath();
      if (path == null) {
        sheet.getLogger().warning("Warning: User must select a node to attach a new config to");
        // XXX add a message telling users to select a node
      } else {
        createAttrConfigForNode((Node) path.getLastPathComponent());
      }
    }
  }

  private void duplicateNode(Node selected) {
    if (selected instanceof AttrConfig) {
      duplicateAttrConfig((AttrConfig) selected);
    } else if (selected instanceof Config) {
      duplicateConfig((Config) selected);
    }
  }

  private void duplicateAttrConfig(AttrConfig selected) {}

  private void duplicateConfig(Config selected) {}

  private void createAttrConfigForNode(Node selected) {
    Config parent = null;
    if (selected instanceof Config) {
      parent = (Config) selected;
    } else if (selected instanceof AttrConfig) {
      parent = (Config) ((AttrConfig) selected).getParent();
    }
    if (parent != null) {
      String newName = unusedName("Attr", new AttrNameIter(parent));
      String type = ViperData.ViPER_DATA_URI + "svalue";
      AttrValueWrapper params = model.getMediator().getDataFactory().getAttribute(type);
      Node n = parent.createAttrConfig(newName, type, false, null, params);
      select(n);
    }
  }

  /**
   * Gets an action listener for events that delete the currently selected attriubute or descriptor
   * config.
   *
   * @return An ActionListener that will delete the current selection
   */
  public ActionListener getDeleteActionListener() {
    return deleteActionListener;
  }

  private void select(Node n) {
    model.enqueueNodeSelection(n);
  }

  private ActionListener deleteActionListener = new DeleteActionListener();

  private class DeleteActionListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
      JTree tree = getTree();
      TreePath path = tree.getSelectionPath();
      if (path == null) {
        sheet.getLogger().warning("Warning: User must select a node to delete");
        // XXX add message telling users to select a node
      } else {
        Node selected = (Node) path.getLastPathComponent();
        try {
          Node parent = selected.getParent();
          if (parent != null) {
            parent.removeChild(selected);
            select(parent);
          }
        } catch (UnsupportedOperationException uox) {
          sheet.getLogger().warning("Cannot delete node: " + selected);
        }
      }
    }
  }

  /**
   * Find a new name that isn't among the used names.
   *
   * @param prefix
   * @param usedNames
   * @return
   */
  public static String unusedName(String prefix, Iterator usedNames) {
    SortedSet u = new TreeSet();
    while (usedNames.hasNext()) {
      String curr = (String) usedNames.next();
      if (curr.startsWith(prefix)) {
        String postfix = curr.substring(prefix.length());
        u.add(postfix);
      }
    }
    int count = 0;
    while (u.contains(String.valueOf(count))) {
      count++;
    }
    return prefix + count;
  }

  /** @return */
  public Node getSelectedNode() {
    int[] s = getTree().getSelectionRows();
    if (s == null || s.length == 0) {
      return null;
    } else {
      return (Node) getTree().getPathForRow(s[0]).getLastPathComponent();
    }
  }
}
/**
 * @author [email protected]
 * @since Jun 4, 2003
 */
public abstract class AbstractViperTable extends JPanel implements ViperTableTabComponent {
  private Logger logger = Logger.getLogger("edu.umd.cfar.lamp.viper.gui.table");
  private ViperViewMediator mediator;

  public abstract Descriptor getSelectedRow();

  protected JPopupMenu popup;
  private AttributeRenderer ar;
  private AttributeEditor ae;
  private TablePanel outerTablePanel;

  /**
   * Get the model of the currently selected table (since a vipertable may have more than one table
   * model, like the content pane).
   *
   * @return the table model that has the user focus
   */
  public ViperTableModel getCurrentModel() {
    TableModel mod = getTable() == null ? null : getTable().getModel();
    if (mod instanceof ViperTableModel) {
      return (ViperTableModel) getTable().getModel();
    } else {
      return null;
    }
  }

  public void setCurrentModel(ViperTableModel model) {
    getTable().setModel(model);
  }

  private ChangeListener hiddenNodesChangeListener =
      new ChangeListener() {
        public void stateChanged(ChangeEvent e) {
          AbstractViperTable.this.getTable().getTableHeader().repaint();
        }
      };

  private class ProxyTableCellRenderer implements TableCellRenderer {
    private TableCellRenderer candidate;

    public ProxyTableCellRenderer(TableCellRenderer delegate) {
      this.candidate = delegate;
    }

    /** @inheritDoc */
    public boolean equals(Object arg0) {
      return candidate.equals(arg0);
    }
    /** @inheritDoc */
    public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
      Component c =
          candidate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
      if (c instanceof JLabel && table != null) {
        ViperTableModel m = getCurrentModel();
        int modelIndex = table.convertColumnIndexToModel(column);
        AttrConfig ac = m.getAttributeForColumn(modelIndex);
        JLabel l = (JLabel) c;
        if (ac != null) {
          int visibility = mediator.getHiders().getAttrConfigVisibility(ac);
          l.setIcon(outerTablePanel.visibilityIcons[visibility]);
        } else if (m.getInternalColumn(modelIndex) == ViperTableModel.BY_VALID) {
          Config config = m.getConfig();
          int visibility = mediator.getHiders().getConfigVisibility(m.getConfig());
          if (visibility == NodeVisibilityManager.RANGE_LOCKED) {
            visibility = NodeVisibilityManager.LOCKED;
          }
          l.setIcon(outerTablePanel.visibilityIcons[visibility]);
        } else {
          l.setIcon(null);
        }
      }
      return c;
    }
    /** @inheritDoc */
    public int hashCode() {
      return candidate.hashCode();
    }
    /** @inheritDoc */
    public String toString() {
      return candidate.toString();
    }
  }

  /**
   * Adds the default renderers and editors for all known data types
   *
   * @param table
   */
  private void initAttributeTable(final EnhancedTable table) {
    ar = new AttributeRenderer(this);
    ae = new AttributeEditor(this);
    ae.setEditClickCount(2);
    TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
    table.getTableHeader().setDefaultRenderer(new ProxyTableCellRenderer(r));
    table.setDefaultRenderer(Descriptor.class, ar);
    table.setDefaultRenderer(Attribute.class, ar);
    table.setDefaultEditor(Attribute.class, ae);
    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    table.addTableListener(
        new TableListener() {
          public void contextClick(TableEvent e) {
            // TODO: Should display context menu offering: sort ascending/descending; show/hide/lock
          }

          public void actionClick(TableEvent e) {}

          public void click(TableEvent e) {
            if (e.getRow() == -1) {
              ViperTableModel m = getCurrentModel();
              int modelIndex = table.convertColumnIndexToModel(e.getColumn());
              AttrConfig ac = m.getAttributeForColumn(modelIndex);
              NodeVisibilityManager H = mediator.getHiders();
              if (ac != null) {
                int oldV = H.getAttrConfigVisibility(ac);
                H.setVisibilityByAttrConfig(ac, NodeVisibilityManager.ROTATE_VISIBILITY[oldV]);
              } else if (m.getInternalColumn(modelIndex) == ViperTableModel.BY_VALID) {
                Config config = m.getConfig();
                int oldV = H.getConfigVisibility(config);
                H.setVisibilityByConfig(
                    config, NodeVisibilityManager.ROTATE_RANGE_VISIBILITY[oldV]);
              }
            }
          }

          public void altClick(TableEvent e) {}
        });
  }

  private int rowEditPolicy = ALLOW_ROW_EDIT;

  public int getRowEditPolicy() {
    return rowEditPolicy;
  }

  public void setRowEditPolicy(int policy) {
    rowEditPolicy = policy;
  }

  public static int NO_ROW_EDIT = 0;
  public static int ALLOW_ROW_EDIT = 1;
  // added by Ping on 10/31/2000
  // for toggle through objects
  public static boolean ENABLE = true;
  public static boolean DISABLE = false;
  // Handle some of the common steps between creating the content
  // and object tables.
  public AbstractViperTable(TablePanel tp) {
    super();
    this.outerTablePanel = tp;
    setLayout(new BorderLayout());
    EnhancedTable table =
        new EnhancedTable() {
          public void changeSelection(
              int rowIndex, int columnIndex, boolean toggle, boolean extend) {
            ViperTableModel currModel = AbstractViperTable.this.getCurrentModel();
            columnIndex = convertColumnIndexToModel(columnIndex);
            AttrConfig ac = currModel.getAttributeForColumn(columnIndex);
            Descriptor d = currModel.getDescriptorAtRow(rowIndex);
            Node n = null;
            if (ac != null) {
              Attribute a = d.getAttribute(ac);
              n = a;
            } else if (currModel.getInternalColumn(columnIndex) == ViperTableModel.BY_ID) {
              n = d;
            }
            if (n != null) {
              if (extend) {
                mediator.getSelection().addNode(n);
              } else {
                mediator.getSelection().setTo(n);
              }
            }
          }

          public boolean isCellSelected(int row, int column) {
            ViperTableModel currModel = AbstractViperTable.this.getCurrentModel();
            column = convertColumnIndexToModel(column);
            AttrConfig ac = currModel.getAttributeForColumn(column);
            Descriptor d = currModel.getDescriptorAtRow(row);
            if (ac != null) {
              Attribute a = d.getAttribute(ac);
              return mediator.getSelection().isSelected(a);
            } else if (currModel.getInternalColumn(column) == ViperTableModel.BY_ID) {
              return mediator.getSelection().isSelected(d);
            }
            return false;
          }
        };
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    table.resizeAllColumnsToNaturalWidth();
    table.setCellSelectionBackground(
        table.getSelectionBackground().brighter().brighter().brighter());
    table.setCellSelectionForeground(table.getForeground().darker());
    initAttributeTable(table);
    JScrollPane scrollPane = new JScrollPane(table);
    this.add(scrollPane);
    popup = new DescPropPopup();
    popup.setInvoker(getTable());
    getTable()
        .addMouseListener(
            new MouseAdapter() {
              public void mousePressed(MouseEvent e) {
                maybeShowPopup(e);
              }

              public void mouseReleased(MouseEvent e) {
                maybeShowPopup(e);
              }
            });
  }

  protected abstract void maybeShowPopup(MouseEvent e);

  protected EnhancedTable getTable() {
    JScrollPane scrollPane = (JScrollPane) this.getComponent(0);
    return (EnhancedTable) scrollPane.getViewport().getView();
  }

  public ViperViewMediator getMediator() {
    return mediator;
  }

  public void setMediator(ViperViewMediator mediator) {
    if (this.mediator != mediator) {
      if (this.mediator != null) {
        this.mediator.getHiders().removeChangeListener(hiddenNodesChangeListener);
      }
      this.mediator = mediator;
      if (this.mediator != null) {
        this.mediator.getHiders().addChangeListener(hiddenNodesChangeListener);
      }
    }
  }

  public void scrollToAttribute(Attribute a) {
    if (!a.getDescriptor().getConfig().equals(getConfig())) {
      logger.fine("Cannot scroll to attribute that isn't attached to this type of descriptor");
      return;
    }
    int rowIndex = getCurrentModel().getRowForDescriptor(a.getDescriptor());
    int colIndex = getCurrentModel().getColumnForAttribute(a);
    JScrollPane scrollPane = (JScrollPane) this.getComponent(0);
    JViewport viewport = (JViewport) scrollPane.getViewport();
    EnhancedTable table = (EnhancedTable) viewport.getView();

    // This rectangle is relative to the table where the
    // northwest corner of cell (0,0) is always (0,0).
    Rectangle rect = table.getCellRect(rowIndex, colIndex, true);

    // The location of the viewport relative to the table
    Point pt = viewport.getViewPosition();

    // Translate the cell location so that it is relative
    // to the view, assuming the northwest corner of the
    // view is (0,0)
    rect.setLocation(rect.x - pt.x, rect.y - pt.y);

    // Scroll the area into view
    viewport.scrollRectToVisible(rect);
  }

  // XXX Move to TablePanel - here there is one copy for each descriptor
  // config
  private class DescPropPopup extends JPopupMenu {
    private JCheckBoxMenuItem v;
    private JCheckBoxMenuItem p;
    private JMenuItem delete;
    private JMenuItem duplicate;
    private JMenuItem interp;
    private JCheckBoxMenuItem wrt;
    private JMenu interpToMark;
    private JMenuItem shift;
    private JMenu shiftToMark;
    private ShiftToMarkAction stmAction;
    private InterpToMarkAction itmAction;
    private Descriptor desc;
    private Attribute attr;

    private class WithRespectToAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        if (attr == null) {
          return;
        }
        ViperViewMediator m = getMediator();
        Attribute oldWRT = m.getDisplayWRTManager().getAttribute();
        if (attr.equals(oldWRT)) {
          m.getDisplayWRTManager().setAttribute(null, null);
        } else {
          m.getDisplayWRTManager().setAttribute(attr, m.getCurrentFrame());
        }
      }
    }

    private class ValidAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        boolean makeValid = v.isSelected();
        InstantRange oldRange = (InstantRange) desc.getValidRange().clone();
        boolean frame = oldRange.isFrameBased();
        InstantInterval toAlter = getMediator().getCurrInterval(frame);
        if (!makeValid) {
          oldRange.remove(toAlter);
        } else {
          oldRange.add(toAlter);
        }
        desc.setValidRange(oldRange);
        v.setSelected(!makeValid);
      }
    }

    private class PropAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        boolean propagate = p.isSelected();
        ViperViewMediator m = getMediator();
        PropagateInterpolateModule proper = m.getPropagator();
        if (propagate) {
          proper.startPropagating(desc);
        } else {
          proper.stopPropagating(desc);
        }
        p.setSelected(proper.getPropagatingDescriptors().contains(desc));
      }
    }

    private class DeleteAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        desc.getParent().removeChild(desc);
      }
    }

    private class DuplicateAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        getMediator().duplicateDescriptor(desc);
      }
    }

    private class InterpAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        Iterator toInterp = Collections.singleton(desc).iterator();
        ViperViewMediator m = getMediator();
        InterpQuery iq = new InterpQuery(toInterp, m);
        iq.setVisible(true);
      }
    }

    private class ShiftAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        ViperViewMediator m = getMediator();
        ShiftQuery sq = new ShiftQuery(new Descriptor[] {desc}, m);
        sq.setVisible(true);
      }
    }

    private class InterpToMarkAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        Iterator toInterp = Collections.singleton(desc).iterator();
        JMenuItem jmi = (JMenuItem) e.getSource();
        Iterator marks = mediator.getMarkerModel().getMarkersWithLabel(jmi.getText());
        if (marks.hasNext()) {
          ChronicleMarker marker = (ChronicleMarker) marks.next();
          Instant to = marker.getWhen();
          Instant from = mediator.getMajorMoment();
          mediator.getPropagator().interpolateDescriptors(toInterp, from, to);
        }
      }
    }

    private class ShiftToMarkAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        JMenuItem jmi = (JMenuItem) e.getSource();
        Iterator marks = mediator.getMarkerModel().getMarkersWithLabel(jmi.getText());
        if (marks.hasNext()) {
          ChronicleMarker marker = (ChronicleMarker) marks.next();
          Instant to = marker.getWhen();
          Instant from = mediator.getMajorMoment();
          viper.api.impl.Util.shiftDescriptors(new Descriptor[] {desc}, from, to);
        }
      }
    }

    private JMenuItem occlusions;
    private TextlineOcclusionEditor occWindow = new TextlineOcclusionEditor();

    private class OccAction implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        ViperViewMediator med = getMediator();
        TextlineModel tlm = (TextlineModel) med.getAttributeValueAtCurrentFrame(attr);
        if (tlm != null) {
          occWindow.setVisible(true);
          occWindow.setModelAndRefresh(tlm, med, attr);
        }
      }
    }

    private OccAction occAction;
    private JSeparator occSeparator;

    public DescPropPopup() {
      super("Descriptor Properties");
      v = new JCheckBoxMenuItem("Valid");
      v.addActionListener(new ValidAction());
      p = new JCheckBoxMenuItem("Propagating");
      p.addActionListener(new PropAction());
      delete = new JMenuItem("Delete");
      delete.addActionListener(new DeleteAction());
      duplicate = new JMenuItem("Duplicate");
      duplicate.addActionListener(new DuplicateAction());
      interp = new JMenuItem("Interpolate...");
      interp.addActionListener(new InterpAction());
      interpToMark = new JMenu("Interpolate to Mark");
      interpToMark.setEnabled(false);
      itmAction = new InterpToMarkAction();
      shift = new JMenuItem("Shift...");
      shift.addActionListener(new ShiftAction());
      shiftToMark = new JMenu("Shift to Mark");
      shiftToMark.setEnabled(false);
      stmAction = new ShiftToMarkAction();

      occlusions = new JMenuItem("Occlusions...");
      occAction = new OccAction();
      occlusions.addActionListener(occAction);
      occSeparator = new JSeparator();

      wrt = new JCheckBoxMenuItem("Display with Respect To", false);
      wrt.addActionListener(new WithRespectToAction());

      add(occlusions);
      add(occSeparator);
      add(v);
      add(p);
      add(occSeparator);
      add(delete);
      add(duplicate);
      add(occSeparator);
      add(interp);
      add(interpToMark);
      add(occSeparator);
      add(shift);
      add(shiftToMark);
      add(occSeparator);
      add(wrt);
    }

    public void show(Component invoker, int x, int y) {
      ViperViewMediator mediator = getMediator();
      Point pnt = new Point(x, y);
      EnhancedTable tab = getTable();
      int row = tab.rowAtPoint(pnt);
      desc = getCurrentModel().getDescriptorAtRow(row);
      int col = tab.columnAtPoint(pnt);
      Object cellValue = tab.getValueAt(row, col);
      if (cellValue instanceof Attribute) {
        attr = (Attribute) cellValue;

        // hide the "Occlusions..." option when we're not dealing with a Textline object
        boolean isTextline = attr.getAttrConfig().getAttrType().endsWith("textline");
        occlusions.setVisible(isTextline);
        occSeparator.setVisible(isTextline);

        Instant now = mediator.getCurrentFrame();
        if (now == null) {
          mediator.getDisplayWRTManager().setAttribute(null, null);
          wrt.setEnabled(false);
          wrt.setSelected(false);
        } else {
          boolean isDwrt = attr == mediator.getDisplayWRTManager().getAttribute();
          boolean dwrtable =
              (attr.getAttrValueAtInstant(now) instanceof HasCentroid
                  && attr.getDescriptor().getValidRange().contains(now));
          wrt.setEnabled(dwrtable);
          wrt.setSelected(isDwrt);
        }
      } else {
        attr = null;
        wrt.setEnabled(false);
        wrt.setSelected(false);
      }
      if (null != desc) {
        PropagateInterpolateModule proper = getMediator().getPropagator();
        p.setSelected(proper.isPropagatingThis(desc));
        v.setSelected(mediator.isThisValidNow(desc));
        resetMarks();
        super.show(invoker, x, y);
      }
    }

    private void resetMarks() {
      interpToMark.removeAll();
      shiftToMark.removeAll();
      Iterator marks = mediator.getMarkerModel().getLabels().iterator();
      boolean hasMark = false;
      while (marks.hasNext()) {
        String mark = (String) marks.next();
        if (!ChronicleViewer.CURR_FRAME_LABEL.equals(mark)) {
          JMenuItem mi = new JMenuItem(mark);
          mi.addActionListener(itmAction);
          interpToMark.add(mi);
          mi = new JMenuItem(mark);
          mi.addActionListener(stmAction);
          shiftToMark.add(mi);
          hasMark = true;
        }
      }
      shiftToMark.setEnabled(hasMark);
      interpToMark.setEnabled(hasMark);
    }
  }

  public abstract void redoSelectionModel();

  public abstract void redoDataModel();

  public abstract Config getConfig();

  public void redoPropagateModel() {
    ViperTableModel m = (ViperTableModel) AbstractViperTable.this.getTable().getModel();
    m.fireTableDataChanged();
  }
}
public class PrintfEditor extends JDialog implements EDPEditor, ConfigParamListener {
  protected PrintfTemplate originalTemplate;
  protected PrintfTemplate editableTemplate;
  private EDPCellData m_data;
  private HashMap paramKeys;
  private HashMap matchesKeys = new HashMap();
  static char[] RESERVED_CHARS = {'[', '\\', '^', '$', '.', '|', '?', '*', '+', '(', ')'};
  static String RESERVED_STRING = new String(RESERVED_CHARS);
  static SimpleAttributeSet PLAIN_ATTR = new SimpleAttributeSet();

  static {
    StyleConstants.setForeground(PLAIN_ATTR, Color.black);
    StyleConstants.setBold(PLAIN_ATTR, false);
    StyleConstants.setFontFamily(PLAIN_ATTR, "Helvetica");
    StyleConstants.setFontSize(PLAIN_ATTR, 14);
  }

  int numParameters = 0;

  JPanel printfPanel = new JPanel();
  ButtonGroup buttonGroup = new ButtonGroup();
  JPanel buttonPanel = new JPanel();
  JButton cancelButton = new JButton();
  JButton saveButton = new JButton();
  JLabel formatLabel = new JLabel();
  FlowLayout flowLayout1 = new FlowLayout();
  JTextArea formatTextArea = new JTextArea();
  JPanel parameterPanel = new JPanel();
  JLabel parameterLabel = new JLabel();
  JTextArea parameterTextArea = new JTextArea();
  JButton insertButton = new JButton();
  JComboBox paramComboBox = new JComboBox();
  GridBagLayout gridBagLayout1 = new GridBagLayout();
  ButtonGroup buttonGroup1 = new ButtonGroup();

  TitledBorder titledBorder2;
  JComboBox matchComboBox = new JComboBox();
  JButton insertMatchButton = new JButton();
  JPanel matchPanel = new JPanel();
  JPanel InsertPanel = new JPanel();
  GridLayout gridLayout1 = new GridLayout();
  GridBagLayout gridBagLayout2 = new GridBagLayout();
  GridBagLayout gridBagLayout3 = new GridBagLayout();
  JTabbedPane printfTabPane = new JTabbedPane();
  JTextPane editorPane = new JTextPane();
  JScrollPane editorPanel = new JScrollPane();
  int selectedPane = 0;
  private boolean m_isCrawlRuleEditor = false;
  private static final String STRING_LITERAL = "String Literal";

  protected static Logger logger = Logger.getLogger("PrintfEditor");

  public PrintfEditor(Frame frame, String title) {
    super(frame, title, false);

    originalTemplate = new PrintfTemplate();
    editableTemplate = new PrintfTemplate();
    try {
      jbInit();
      pack();
      initMatches();
    } catch (Exception exc) {
      String logMessage = "Could not set up the printf editor";
      logger.critical(logMessage, exc);
      JOptionPane.showMessageDialog(frame, logMessage, "Printf Editor", JOptionPane.ERROR_MESSAGE);
    }
  }

  private void initMatches() {
    matchesKeys.put(STRING_LITERAL, "");
    matchesKeys.put("Any number", "[0-9]+");
    matchesKeys.put("Anything", ".*");
    matchesKeys.put("Start", "^");
    matchesKeys.put("End", "$");
    matchesKeys.put("Single path component", "[^/]+");

    for (Iterator it = matchesKeys.keySet().iterator(); it.hasNext(); ) {
      matchComboBox.addItem(it.next());
    }
  }

  private void jbInit() throws Exception {

    saveButton.setText("Save");
    saveButton.addActionListener(new PrintfTemplateEditor_saveButton_actionAdapter(this));
    cancelButton.setText("Cancel");
    cancelButton.addActionListener(new PrintfTemplateEditor_cancelButton_actionAdapter(this));
    this.setTitle(this.getTitle() + " Template Editor");
    printfPanel.setLayout(gridBagLayout1);
    formatLabel.setFont(new java.awt.Font("DialogInput", 0, 12));
    formatLabel.setText("Format String:");
    buttonPanel.setLayout(flowLayout1);
    printfPanel.setBorder(BorderFactory.createEtchedBorder());
    printfPanel.setMinimumSize(new Dimension(100, 160));
    printfPanel.setPreferredSize(new Dimension(380, 160));
    parameterPanel.setLayout(gridBagLayout2);
    parameterLabel.setText("Parameters:");
    parameterLabel.setFont(new java.awt.Font("DialogInput", 0, 12));
    parameterTextArea.setMinimumSize(new Dimension(100, 25));
    parameterTextArea.setPreferredSize(new Dimension(200, 25));
    parameterTextArea.setEditable(true);
    parameterTextArea.setText("");
    insertButton.setMaximumSize(new Dimension(136, 20));
    insertButton.setMinimumSize(new Dimension(136, 20));
    insertButton.setPreferredSize(new Dimension(136, 20));
    insertButton.setToolTipText(
        "insert the format in the format string and add parameter to list.");
    insertButton.setText("Insert Parameter");
    insertButton.addActionListener(new PrintfTemplateEditor_insertButton_actionAdapter(this));
    formatTextArea.setMinimumSize(new Dimension(100, 25));
    formatTextArea.setPreferredSize(new Dimension(200, 15));
    formatTextArea.setText("");
    parameterPanel.setBorder(null);
    parameterPanel.setMinimumSize(new Dimension(60, 40));
    parameterPanel.setPreferredSize(new Dimension(300, 40));
    insertMatchButton.addActionListener(
        new PrintfTemplateEditor_insertMatchButton_actionAdapter(this));
    insertMatchButton.setText("Insert Match");
    insertMatchButton.setToolTipText(
        "insert the match in the format string and add parameter to list.");
    insertMatchButton.setPreferredSize(new Dimension(136, 20));
    insertMatchButton.setMinimumSize(new Dimension(136, 20));
    insertMatchButton.setMaximumSize(new Dimension(136, 20));
    matchPanel.setPreferredSize(new Dimension(300, 40));
    matchPanel.setBorder(null);
    matchPanel.setMinimumSize(new Dimension(60, 60));
    matchPanel.setLayout(gridBagLayout3);
    InsertPanel.setLayout(gridLayout1);
    gridLayout1.setColumns(1);
    gridLayout1.setRows(2);
    gridLayout1.setVgap(0);
    InsertPanel.setBorder(BorderFactory.createEtchedBorder());
    InsertPanel.setMinimumSize(new Dimension(100, 100));
    InsertPanel.setPreferredSize(new Dimension(380, 120));
    editorPane.setText("");
    editorPane.addKeyListener(new PrintfEditor_editorPane_keyAdapter(this));
    printfTabPane.addChangeListener(new PrintfEditor_printfTabPane_changeAdapter(this));
    parameterPanel.add(
        insertButton,
        new GridBagConstraints(
            1,
            0,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.NONE,
            new Insets(8, 6, 13, 8),
            0,
            10));
    parameterPanel.add(
        paramComboBox,
        new GridBagConstraints(
            0,
            0,
            1,
            1,
            1.0,
            0.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.HORIZONTAL,
            new Insets(8, 8, 13, 0),
            258,
            11));
    paramComboBox.setRenderer(new MyCellRenderer());
    InsertPanel.add(matchPanel, null);
    InsertPanel.add(parameterPanel, null);
    buttonPanel.add(cancelButton, null);
    buttonPanel.add(saveButton, null);
    this.getContentPane().add(printfTabPane, BorderLayout.NORTH);
    this.getContentPane().add(InsertPanel, BorderLayout.CENTER);
    matchPanel.add(
        insertMatchButton,
        new GridBagConstraints(
            1,
            0,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.NONE,
            new Insets(8, 6, 13, 8),
            0,
            10));
    matchPanel.add(
        matchComboBox,
        new GridBagConstraints(
            0,
            0,
            1,
            1,
            1.0,
            0.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.HORIZONTAL,
            new Insets(8, 8, 13, 0),
            258,
            11));
    printfPanel.add(
        parameterLabel,
        new GridBagConstraints(
            0,
            2,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(7, 5, 0, 5),
            309,
            0));
    printfPanel.add(
        formatLabel,
        new GridBagConstraints(
            0,
            0,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(4, 5, 0, 5),
            288,
            0));
    printfPanel.add(
        formatTextArea,
        new GridBagConstraints(
            0,
            1,
            1,
            1,
            1.0,
            1.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.BOTH,
            new Insets(6, 5, 0, 5),
            300,
            34));
    printfPanel.add(
        parameterTextArea,
        new GridBagConstraints(
            0,
            3,
            1,
            1,
            1.0,
            1.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.BOTH,
            new Insets(6, 5, 6, 5),
            300,
            34));
    printfTabPane.addTab("Editor View", null, editorPanel, "View in Editor");
    printfTabPane.addTab("Printf View", null, printfPanel, "Vies as Printf");
    editorPane.setCharacterAttributes(PLAIN_ATTR, true);
    editorPane.addStyle("PLAIN", editorPane.getLogicalStyle());
    editorPanel.getViewport().add(editorPane, null);
    this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
    buttonGroup.add(cancelButton);
  }
  /** notifiyParamsChanged */
  public void notifiyParamsChanged() {
    updateParams(m_data);
  }

  /**
   * setEDPData
   *
   * @param data EDPCellData
   */
  public void setCellData(EDPCellData data) {
    m_data = data;
    paramKeys = data.getPlugin().getPrintfDescrs(!m_isCrawlRuleEditor);
    data.getPlugin().addParamListener(this);
    setTemplate((PrintfTemplate) data.getData());
    m_isCrawlRuleEditor = data.getKey().equals(DefinableArchivalUnit.KEY_AU_CRAWL_RULES);
    // initialize the combobox
    updateParams(data);
    if (m_isCrawlRuleEditor) {
      matchPanel.setVisible(true);
    } else {
      matchPanel.setVisible(false);
    }
  }

  void saveButton_actionPerformed(ActionEvent e) {
    updateEditableTemplate(selectedPane);
    originalTemplate.setFormat(editableTemplate.m_format);
    originalTemplate.setTokens(editableTemplate.m_tokens);
    m_data.updateTemplateData(originalTemplate);
    setVisible(false);
  }

  void cancelButton_actionPerformed(ActionEvent e) {
    setVisible(false);
  }

  void printfTabPane_stateChanged(ChangeEvent e) {
    updateEditableTemplate(selectedPane);
    selectedPane = printfTabPane.getSelectedIndex();
    updatePane(selectedPane);
  }

  void updateEditableTemplate(int pane) {
    switch (pane) {
      case 0: // use the editor to update the template
        updateTemplateFromEditor(editableTemplate);
        break;
      case 1: // use the printf text areas to update the template.
        updateTemplateFromPrintf();
        break;
    }
  }

  void insertButton_actionPerformed(ActionEvent e) {
    Object selected = paramComboBox.getSelectedItem();
    ConfigParamDescr descr;
    String key;
    int type = 0;
    String format = "";
    if (selected instanceof ConfigParamDescr) {
      descr = (ConfigParamDescr) selected;
      key = descr.getKey();
      type = descr.getType();
      switch (type) {
        case ConfigParamDescr.TYPE_STRING:
        case ConfigParamDescr.TYPE_URL:
        case ConfigParamDescr.TYPE_BOOLEAN:
          format = "%s";
          break;
        case ConfigParamDescr.TYPE_INT:
        case ConfigParamDescr.TYPE_LONG:
        case ConfigParamDescr.TYPE_POS_INT:
          NumericPaddingDialog dialog = new NumericPaddingDialog();
          Point pos = this.getLocationOnScreen();
          dialog.setLocation(pos.x, pos.y);
          dialog.pack();
          dialog.setVisible(true);
          StringBuilder fbuf = new StringBuilder("%");
          int width = dialog.getPaddingSize();
          boolean is_zero = dialog.useZero();
          if (width > 0) {
            fbuf.append(".");
            if (is_zero) {
              fbuf.append(0);
            }
            fbuf.append(width);
          }
          if (type == ConfigParamDescr.TYPE_LONG) {
            fbuf.append("ld");
          } else {
            fbuf.append("d");
          }
          format = fbuf.toString();
          break;
        case ConfigParamDescr.TYPE_YEAR:
          if (key.startsWith(DefinableArchivalUnit.PREFIX_AU_SHORT_YEAR)) {
            format = "%02d";
          } else {
            format = "%d";
          }
          break;
        case ConfigParamDescr.TYPE_RANGE:
        case ConfigParamDescr.TYPE_NUM_RANGE:
        case ConfigParamDescr.TYPE_SET:
          format = "%s";
          break;
      }
      if (selectedPane == 0) {
        insertParameter(descr, format, editorPane.getSelectionStart());
      } else if (selectedPane == 1) {
        // add the combobox data value to the edit box
        int pos = formatTextArea.getCaretPosition();
        formatTextArea.insert(format, pos);

        pos = parameterTextArea.getCaretPosition();
        parameterTextArea.insert(", " + key, pos);
      }
    } else {
      key = selected.toString();
      format =
          escapePrintfChars(
              (String)
                  JOptionPane.showInputDialog(
                      this,
                      "Enter the string you wish to input",
                      "String Literal Input",
                      JOptionPane.OK_CANCEL_OPTION));
      if (StringUtil.isNullString(format)) {
        return;
      }
      if (selectedPane == 0) {
        insertText(format, PLAIN_ATTR, editorPane.getSelectionStart());
      } else if (selectedPane == 1) {
        // add the combobox data value to the edit box
        formatTextArea.insert(format, formatTextArea.getCaretPosition());
      }
    }
  }

  void insertMatchButton_actionPerformed(ActionEvent e) {
    String key = (String) matchComboBox.getSelectedItem();
    String format = (String) matchesKeys.get(key);
    if (key.equals(STRING_LITERAL)) {
      format =
          escapeReservedChars(
              (String)
                  JOptionPane.showInputDialog(
                      this,
                      "Enter the string you wish to match",
                      "String Literal Input",
                      JOptionPane.OK_CANCEL_OPTION));
      if (StringUtil.isNullString(format)) {
        return;
      }
    }
    if (selectedPane == 0) {
      insertText(format, PLAIN_ATTR, editorPane.getSelectionStart());
    } else {
      // add the combobox data value to the edit box
      int pos = formatTextArea.getCaretPosition();
      formatTextArea.insert(format, pos);
    }
  }

  void editorPane_keyPressed(KeyEvent e) {
    StyledDocument doc = editorPane.getStyledDocument();
    int pos = editorPane.getCaretPosition();
    int code = e.getKeyCode();
    Element el;
    switch (code) {
      case KeyEvent.VK_BACK_SPACE:
      case KeyEvent.VK_DELETE:
      case KeyEvent.VK_LEFT:
      case KeyEvent.VK_KP_LEFT:
        if (pos == 0) return;
        // we want to get the element to the left of position.
        el = doc.getCharacterElement(pos - 1);
        break;
      case KeyEvent.VK_RIGHT:
      case KeyEvent.VK_KP_RIGHT:
        // we want to get the element to the right of position.
        el = doc.getCharacterElement(pos + 1);
        break;
      default:
        return; // bail we don't handle it.
    }
    AttributeSet attr = el.getAttributes();
    String el_name = (String) attr.getAttribute(StyleConstants.NameAttribute);
    int el_range = el.getEndOffset() - el.getStartOffset() - 1;
    if (el_name.startsWith("Parameter") && StyleConstants.getComponent(attr) != null) {
      try {
        switch (code) {
          case KeyEvent.VK_BACK_SPACE:
          case KeyEvent.VK_DELETE:
            doc.remove(el.getStartOffset(), el_range);
            break;
          case KeyEvent.VK_LEFT:
          case KeyEvent.VK_KP_LEFT:
            editorPane.setCaretPosition(pos - el_range);
            break;
          case KeyEvent.VK_RIGHT:
          case KeyEvent.VK_KP_RIGHT:
            editorPane.setCaretPosition(pos + (el_range));
            break;
        }
      } catch (BadLocationException ex) {
      }
    }
  }

  private void insertParameter(ConfigParamDescr descr, String format, int pos) {
    try {
      StyledDocument doc = (StyledDocument) editorPane.getDocument();

      // The component must first be wrapped in a style
      Style style = doc.addStyle("Parameter-" + numParameters, null);
      JLabel label = new JLabel(descr.getDisplayName());
      label.setAlignmentY(0.8f); // make sure we line up
      label.setFont(new Font("Helvetica", Font.PLAIN, 14));
      label.setForeground(Color.BLUE);
      label.setName(descr.getKey());
      label.setToolTipText("key: " + descr.getKey() + "    format: " + format);
      StyleConstants.setComponent(style, label);
      doc.insertString(pos, format, style);
      numParameters++;
    } catch (BadLocationException e) {
    }
  }

  private void insertText(String text, AttributeSet set, int pos) {
    try {
      editorPane.getDocument().insertString(pos, text, set);
    } catch (BadLocationException ex) {
    }
  }

  private void appendText(String text, AttributeSet set) {
    insertText(text, set, editorPane.getDocument().getLength());
  }

  private void updateTemplateFromPrintf() {
    String format = formatTextArea.getText();
    String parameters = parameterTextArea.getText();
    editableTemplate.setFormat(format);
    editableTemplate.setParameters(parameters);
  }

  private void updateTemplateFromEditor(PrintfTemplate template) {
    ArrayList params = new ArrayList();
    String format = null;
    int text_length = editorPane.getDocument().getLength();
    try {
      format = editorPane.getDocument().getText(0, text_length);
    } catch (BadLocationException ex1) {
    }
    Element section_el = editorPane.getDocument().getDefaultRootElement();
    // Get number of paragraphs.
    int num_para = section_el.getElementCount();
    for (int p_count = 0; p_count < num_para; p_count++) {
      Element para_el = section_el.getElement(p_count);
      // Enumerate the content elements
      int num_cont = para_el.getElementCount();
      for (int c_count = 0; c_count < num_cont; c_count++) {
        Element content_el = para_el.getElement(c_count);
        AttributeSet attr = content_el.getAttributes();
        // Get the name of the style applied to this content element; may be null
        String sn = (String) attr.getAttribute(StyleConstants.NameAttribute);
        // Check if style name match
        if (sn != null && sn.startsWith("Parameter")) {
          // we extract the label.
          JLabel l = (JLabel) StyleConstants.getComponent(attr);
          if (l != null) {
            params.add(l.getName());
          }
        }
      }
    }

    template.setFormat(format);
    template.setTokens(params);
  }

  protected void setTemplate(PrintfTemplate template) {
    originalTemplate = template;
    editableTemplate.setFormat(template.m_format);
    editableTemplate.setTokens(template.m_tokens);
    updatePane(selectedPane);
  }

  private void updateParams(EDPCellData data) {
    paramComboBox.removeAllItems();
    paramKeys = data.getPlugin().getPrintfDescrs(!m_isCrawlRuleEditor);
    if (!m_isCrawlRuleEditor) {
      paramComboBox.addItem(STRING_LITERAL);
    }

    for (Iterator it = paramKeys.values().iterator(); it.hasNext(); ) {
      ConfigParamDescr descr = (ConfigParamDescr) it.next();
      int type = descr.getType();
      if (!m_isCrawlRuleEditor
          && (type == ConfigParamDescr.TYPE_SET || type == ConfigParamDescr.TYPE_RANGE)) continue;
      paramComboBox.addItem(descr);
    }
    paramComboBox.setEnabled(true);
    paramComboBox.setSelectedIndex(0);
    paramComboBox.setToolTipText("Select a parameter to insert into the format string");
    insertButton.setEnabled(true);
  }

  /**
   * updatePane
   *
   * @param sel int
   */
  private void updatePane(int sel) {
    switch (sel) {
      case 0: // editor view
        updateEditorView();
        break;
      case 1: // printf view
        updatePrintfView();
        break;
    }
  }

  private void updatePrintfView() {
    formatTextArea.setText(editableTemplate.m_format);
    parameterTextArea.setText(editableTemplate.getTokenString());
  }

  private void updateEditorView() {
    editorPane.setText("");
    numParameters = 0;
    try {
      java.util.List elements = editableTemplate.getPrintfElements();
      for (Iterator it = elements.iterator(); it.hasNext(); ) {
        PrintfUtil.PrintfElement el = (PrintfUtil.PrintfElement) it.next();
        if (el.getFormat().equals(PrintfUtil.PrintfElement.FORMAT_NONE)) {
          appendText(el.getElement(), PLAIN_ATTR);
        } else {
          insertParameter(
              (ConfigParamDescr) paramKeys.get(el.getElement()),
              el.getFormat(),
              editorPane.getDocument().getLength());
        }
      }
    } catch (Exception ex) {
      JOptionPane.showMessageDialog(
          this,
          "Invalid Format: " + ex.getMessage(),
          "Invalid Printf Format",
          JOptionPane.ERROR_MESSAGE);

      selectedPane = 1;
      printfTabPane.setSelectedIndex(selectedPane);
      updatePane(selectedPane);
    }
  }

  /**
   * Return a copy of the string with all reserved regexp chars escaped by backslash.
   *
   * @param str the string to add escapes to
   * @return String return a string with escapes or "" if str is null
   */
  private String escapeReservedChars(String str) {
    if (str == null) return "";
    StringBuilder sb = new StringBuilder();
    for (int ci = 0; ci < str.length(); ci++) {
      char ch = str.charAt(ci);
      if (RESERVED_STRING.indexOf(ch) >= 0) {
        sb.append('\\');
      }
      sb.append(ch);
    }
    return escapePrintfChars(sb.toString());
  }

  private String escapePrintfChars(String str) {
    if (str == null) return "";
    StringBuilder sb = new StringBuilder();
    for (int ci = 0; ci < str.length(); ci++) {
      char ch = str.charAt(ci);
      if (ch == '%') {
        sb.append('%');
      }
      sb.append(ch);
    }
    return sb.toString();
  }
}
Exemple #15
0
/**
 * The <tt>CallManager</tt> is the one that handles calls. It contains also the "Call" and "Hangup"
 * buttons panel. Here are handles incoming and outgoing calls from and to the call operation set.
 *
 * @author Yana Stamcheva
 */
public class CallManager extends JPanel
    implements ActionListener, CallListener, ListSelectionListener, ChangeListener {
  private Logger logger = Logger.getLogger(CallManager.class.getName());

  private CallComboBox phoneNumberCombo;

  private JPanel comboPanel = new JPanel(new BorderLayout());

  private JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));

  private JLabel callViaLabel = new JLabel(Messages.getI18NString("callVia").getText() + " ");

  private JPanel callViaPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 4));

  private AccountSelectorBox accountSelectorBox;

  private SIPCommButton callButton =
      new SIPCommButton(
          ImageLoader.getImage(ImageLoader.CALL_BUTTON_BG),
          ImageLoader.getImage(ImageLoader.CALL_ROLLOVER_BUTTON_BG),
          null,
          ImageLoader.getImage(ImageLoader.CALL_BUTTON_PRESSED_BG));

  private SIPCommButton hangupButton =
      new SIPCommButton(
          ImageLoader.getImage(ImageLoader.HANGUP_BUTTON_BG),
          ImageLoader.getImage(ImageLoader.HANGUP_ROLLOVER_BUTTON_BG),
          null,
          ImageLoader.getImage(ImageLoader.HANGUP_BUTTON_PRESSED_BG));

  private SIPCommButton minimizeButton =
      new SIPCommButton(
          ImageLoader.getImage(ImageLoader.CALL_PANEL_MINIMIZE_BUTTON),
          ImageLoader.getImage(ImageLoader.CALL_PANEL_MINIMIZE_ROLLOVER_BUTTON));

  private SIPCommButton restoreButton =
      new SIPCommButton(
          ImageLoader.getImage(ImageLoader.CALL_PANEL_RESTORE_BUTTON),
          ImageLoader.getImage(ImageLoader.CALL_PANEL_RESTORE_ROLLOVER_BUTTON));

  private JPanel minimizeButtonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));

  private MainFrame mainFrame;

  private Hashtable activeCalls = new Hashtable();

  private boolean isCallMetaContact;

  private Hashtable removeCallTimers = new Hashtable();

  private ProtocolProviderService selectedCallProvider;

  /**
   * Creates an instance of <tt>CallManager</tt>.
   *
   * @param mainFrame The main application window.
   */
  public CallManager(MainFrame mainFrame) {
    super(new BorderLayout());

    this.mainFrame = mainFrame;

    this.phoneNumberCombo = new CallComboBox(this);

    this.accountSelectorBox = new AccountSelectorBox(this);

    this.buttonsPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));

    this.comboPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 0, 5));

    this.init();
  }

  /** Initializes and constructs this panel. */
  private void init() {
    this.phoneNumberCombo.setEditable(true);

    this.callViaPanel.add(callViaLabel);
    this.callViaPanel.add(accountSelectorBox);

    this.comboPanel.add(phoneNumberCombo, BorderLayout.CENTER);

    this.callButton.setName("call");
    this.hangupButton.setName("hangup");
    this.minimizeButton.setName("minimize");
    this.restoreButton.setName("restore");

    this.minimizeButton.setToolTipText(
        Messages.getI18NString("hideCallPanel").getText() + " Ctrl - H");
    this.restoreButton.setToolTipText(
        Messages.getI18NString("showCallPanel").getText() + " Ctrl - H");

    this.callButton.addActionListener(this);
    this.hangupButton.addActionListener(this);
    this.minimizeButton.addActionListener(this);
    this.restoreButton.addActionListener(this);

    this.buttonsPanel.add(callButton);
    this.buttonsPanel.add(hangupButton);

    this.callButton.setEnabled(false);

    this.hangupButton.setEnabled(false);

    this.add(minimizeButtonPanel, BorderLayout.SOUTH);

    this.setCallPanelVisible(ConfigurationManager.isCallPanelShown());
  }

  /**
   * Handles the <tt>ActionEvent</tt> generated when user presses one of the buttons in this panel.
   */
  public void actionPerformed(ActionEvent evt) {
    JButton button = (JButton) evt.getSource();
    String buttonName = button.getName();

    if (buttonName.equals("call")) {
      Component selectedPanel = mainFrame.getSelectedTab();

      // call button is pressed over an already open call panel
      if (selectedPanel != null
          && selectedPanel instanceof CallPanel
          && ((CallPanel) selectedPanel).getCall().getCallState()
              == CallState.CALL_INITIALIZATION) {

        NotificationManager.stopSound(NotificationManager.BUSY_CALL);
        NotificationManager.stopSound(NotificationManager.INCOMING_CALL);

        CallPanel callPanel = (CallPanel) selectedPanel;

        Iterator participantPanels = callPanel.getParticipantsPanels();

        while (participantPanels.hasNext()) {
          CallParticipantPanel panel = (CallParticipantPanel) participantPanels.next();

          panel.setState("Connecting");
        }

        Call call = callPanel.getCall();

        answerCall(call);
      }
      // call button is pressed over the call list
      else if (selectedPanel != null
          && selectedPanel instanceof CallListPanel
          && ((CallListPanel) selectedPanel).getCallList().getSelectedIndex() != -1) {

        CallListPanel callListPanel = (CallListPanel) selectedPanel;

        GuiCallParticipantRecord callRecord =
            (GuiCallParticipantRecord) callListPanel.getCallList().getSelectedValue();

        String stringContact = callRecord.getParticipantName();

        createCall(stringContact);
      }
      // call button is pressed over the contact list
      else if (selectedPanel != null && selectedPanel instanceof ContactListPanel) {
        // call button is pressed when a meta contact is selected
        if (isCallMetaContact) {
          Object[] selectedContacts =
              mainFrame.getContactListPanel().getContactList().getSelectedValues();

          Vector telephonyContacts = new Vector();

          for (int i = 0; i < selectedContacts.length; i++) {

            Object o = selectedContacts[i];

            if (o instanceof MetaContact) {

              Contact contact =
                  ((MetaContact) o).getDefaultContact(OperationSetBasicTelephony.class);

              if (contact != null) telephonyContacts.add(contact);
              else {
                new ErrorDialog(
                        this.mainFrame,
                        Messages.getI18NString("warning").getText(),
                        Messages.getI18NString(
                                "contactNotSupportingTelephony",
                                new String[] {((MetaContact) o).getDisplayName()})
                            .getText())
                    .showDialog();
              }
            }
          }

          if (telephonyContacts.size() > 0) createCall(telephonyContacts);

        } else if (!phoneNumberCombo.isComboFieldEmpty()) {

          // if no contact is selected checks if the user has chosen
          // or has
          // writen something in the phone combo box

          String stringContact = phoneNumberCombo.getEditor().getItem().toString();

          createCall(stringContact);
        }
      } else if (selectedPanel != null && selectedPanel instanceof DialPanel) {
        String stringContact = phoneNumberCombo.getEditor().getItem().toString();
        createCall(stringContact);
      }
    } else if (buttonName.equalsIgnoreCase("hangup")) {
      Component selectedPanel = this.mainFrame.getSelectedTab();

      if (selectedPanel != null && selectedPanel instanceof CallPanel) {

        NotificationManager.stopSound(NotificationManager.BUSY_CALL);
        NotificationManager.stopSound(NotificationManager.INCOMING_CALL);
        NotificationManager.stopSound(NotificationManager.OUTGOING_CALL);

        CallPanel callPanel = (CallPanel) selectedPanel;

        Call call = callPanel.getCall();

        if (removeCallTimers.containsKey(callPanel)) {
          ((Timer) removeCallTimers.get(callPanel)).stop();
          removeCallTimers.remove(callPanel);
        }

        removeCallPanel(callPanel);

        if (call != null) {
          ProtocolProviderService pps = call.getProtocolProvider();

          OperationSetBasicTelephony telephony = mainFrame.getTelephonyOpSet(pps);

          Iterator participants = call.getCallParticipants();

          while (participants.hasNext()) {
            try {
              // now we hang up the first call participant in the
              // call
              telephony.hangupCallParticipant((CallParticipant) participants.next());
            } catch (OperationFailedException e) {
              logger.error("Hang up was not successful: " + e);
            }
          }
        }
      }
    } else if (buttonName.equalsIgnoreCase("minimize")) {
      JCheckBoxMenuItem hideCallPanelItem =
          mainFrame.getMainMenu().getViewMenu().getHideCallPanelItem();

      if (!hideCallPanelItem.isSelected()) hideCallPanelItem.setSelected(true);

      this.setCallPanelVisible(false);
    } else if (buttonName.equalsIgnoreCase("restore")) {

      JCheckBoxMenuItem hideCallPanelItem =
          mainFrame.getMainMenu().getViewMenu().getHideCallPanelItem();

      if (hideCallPanelItem.isSelected()) hideCallPanelItem.setSelected(false);

      this.setCallPanelVisible(true);
    }
  }

  /** Hides the panel containing call and hangup buttons. */
  public void setCallPanelVisible(boolean isVisible) {
    if (isVisible) {
      this.add(comboPanel, BorderLayout.NORTH);
      this.add(buttonsPanel, BorderLayout.CENTER);

      this.minimizeButtonPanel.removeAll();
      this.minimizeButtonPanel.add(minimizeButton);
    } else {
      this.remove(comboPanel);
      this.remove(buttonsPanel);

      this.minimizeButtonPanel.removeAll();
      this.minimizeButtonPanel.add(restoreButton);

      if (mainFrame.isVisible())
        this.mainFrame.getContactListPanel().getContactList().requestFocus();
    }

    if (ConfigurationManager.isCallPanelShown() != isVisible)
      ConfigurationManager.setShowCallPanel(isVisible);

    this.mainFrame.validate();
  }

  /**
   * Adds the given call account to the list of call via accounts.
   *
   * @param pps the protocol provider service corresponding to the account
   */
  public void addCallAccount(ProtocolProviderService pps) {
    if (accountSelectorBox.getAccountsNumber() > 0) {
      this.comboPanel.add(callViaPanel, BorderLayout.SOUTH);
    }
    accountSelectorBox.addAccount(pps);
  }

  /**
   * Removes the account corresponding to the given protocol provider from the call via selector
   * box.
   *
   * @param pps the protocol provider service to remove
   */
  public void removeCallAccount(ProtocolProviderService pps) {
    this.accountSelectorBox.removeAccount(pps);

    if (accountSelectorBox.getAccountsNumber() < 2) {
      this.comboPanel.remove(callViaPanel);
    }
  }

  /**
   * Returns TRUE if the account corresponding to the given protocol provider is already contained
   * in the call via selector box, otherwise returns FALSE.
   *
   * @param pps the protocol provider service for the account
   * @return TRUE if the account corresponding to the given protocol provider is already contained
   *     in the call via selector box, otherwise returns FALSE
   */
  public boolean containsCallAccount(ProtocolProviderService pps) {
    return accountSelectorBox.containsAccount(pps);
  }

  /**
   * Updates the call via account status.
   *
   * @param pps the protocol provider service for the account
   */
  public void updateCallAccountStatus(ProtocolProviderService pps) {
    accountSelectorBox.updateAccountStatus(pps);
  }

  /**
   * Returns the account selector box.
   *
   * @return the account selector box.
   */
  public AccountSelectorBox getAccountSelectorBox() {
    return accountSelectorBox;
  }

  /**
   * Sets the protocol provider to use for a call.
   *
   * @param provider the protocol provider to use for a call.
   */
  public void setCallProvider(ProtocolProviderService provider) {
    this.selectedCallProvider = provider;
  }

  /**
   * Implements CallListener.incomingCallReceived. When a call is received creates a call panel and
   * adds it to the main tabbed pane and plays the ring phone sound to the user.
   */
  public void incomingCallReceived(CallEvent event) {
    Call sourceCall = event.getSourceCall();

    CallPanel callPanel = new CallPanel(this, sourceCall, GuiCallParticipantRecord.INCOMING_CALL);

    mainFrame.addCallPanel(callPanel);

    if (mainFrame.getState() == JFrame.ICONIFIED) mainFrame.setState(JFrame.NORMAL);

    if (!mainFrame.isVisible()) mainFrame.setVisible(true);

    mainFrame.toFront();

    this.callButton.setEnabled(true);
    this.hangupButton.setEnabled(true);

    NotificationManager.fireNotification(
        NotificationManager.INCOMING_CALL,
        null,
        "Incoming call recived from: " + sourceCall.getCallParticipants().next());

    activeCalls.put(sourceCall, callPanel);

    this.setCallPanelVisible(true);
  }

  /**
   * Implements CallListener.callEnded. Stops sounds that are playing at the moment if there're any.
   * Removes the call panel and disables the hangup button.
   */
  public void callEnded(CallEvent event) {
    Call sourceCall = event.getSourceCall();

    NotificationManager.stopSound(NotificationManager.BUSY_CALL);
    NotificationManager.stopSound(NotificationManager.INCOMING_CALL);
    NotificationManager.stopSound(NotificationManager.OUTGOING_CALL);

    if (activeCalls.get(sourceCall) != null) {
      CallPanel callPanel = (CallPanel) activeCalls.get(sourceCall);

      this.removeCallPanelWait(callPanel);
    }
  }

  public void outgoingCallCreated(CallEvent event) {}

  /**
   * Removes the given call panel tab.
   *
   * @param callPanel the CallPanel to remove
   */
  public void removeCallPanelWait(CallPanel callPanel) {
    Timer timer = new Timer(5000, new RemoveCallPanelListener(callPanel));

    this.removeCallTimers.put(callPanel, timer);

    timer.setRepeats(false);
    timer.start();
  }

  /**
   * Removes the given call panel tab.
   *
   * @param callPanel the CallPanel to remove
   */
  private void removeCallPanel(CallPanel callPanel) {
    if (callPanel.getCall() != null && activeCalls.contains(callPanel.getCall())) {
      this.activeCalls.remove(callPanel.getCall());
    }

    mainFrame.removeCallPanel(callPanel);
    updateButtonsStateAccordingToSelectedPanel();
  }

  /** Removes the given CallPanel from the main tabbed pane. */
  private class RemoveCallPanelListener implements ActionListener {
    private CallPanel callPanel;

    public RemoveCallPanelListener(CallPanel callPanel) {
      this.callPanel = callPanel;
    }

    public void actionPerformed(ActionEvent e) {
      removeCallPanel(callPanel);
    }
  }

  /**
   * Implements ListSelectionListener.valueChanged. Enables or disables call and hangup buttons
   * depending on the selection in the contactlist.
   */
  public void valueChanged(ListSelectionEvent e) {
    Object o = mainFrame.getContactListPanel().getContactList().getSelectedValue();

    if ((e.getFirstIndex() != -1 || e.getLastIndex() != -1) && (o instanceof MetaContact)) {
      setCallMetaContact(true);

      // Switch automatically to the appropriate pps in account selector
      // box and enable callButton if telephony is supported.
      Contact contact = ((MetaContact) o).getDefaultContact(OperationSetBasicTelephony.class);

      if (contact != null) {
        callButton.setEnabled(true);

        if (contact.getProtocolProvider().isRegistered())
          getAccountSelectorBox().setSelected(contact.getProtocolProvider());
      } else {
        callButton.setEnabled(false);
      }
    } else if (phoneNumberCombo.isComboFieldEmpty()) {
      callButton.setEnabled(false);
    }
  }

  /**
   * Implements ChangeListener.stateChanged. Enables the hangup button if ones selects a tab in the
   * main tabbed pane that contains a call panel.
   */
  public void stateChanged(ChangeEvent e) {
    this.updateButtonsStateAccordingToSelectedPanel();

    Component selectedPanel = mainFrame.getSelectedTab();
    if (selectedPanel == null || !(selectedPanel instanceof CallPanel)) {
      Iterator callPanels = activeCalls.values().iterator();

      while (callPanels.hasNext()) {
        CallPanel callPanel = (CallPanel) callPanels.next();

        callPanel.removeDialogs();
      }
    }
  }

  /** Updates call and hangup buttons' states aa */
  private void updateButtonsStateAccordingToSelectedPanel() {
    Component selectedPanel = mainFrame.getSelectedTab();
    if (selectedPanel != null && selectedPanel instanceof CallPanel) {
      this.hangupButton.setEnabled(true);
    } else {
      this.hangupButton.setEnabled(false);
    }
  }

  /**
   * Returns the call button.
   *
   * @return the call button
   */
  public SIPCommButton getCallButton() {
    return callButton;
  }

  /**
   * Returns the hangup button.
   *
   * @return the hangup button
   */
  public SIPCommButton getHangupButton() {
    return hangupButton;
  }

  /**
   * Returns the main application frame. Meant to be used from the contained components that do not
   * have direct access to the MainFrame.
   *
   * @return the main application frame
   */
  public MainFrame getMainFrame() {
    return mainFrame;
  }

  /**
   * Returns the combo box, where user enters the phone number to call to.
   *
   * @return the combo box, where user enters the phone number to call to.
   */
  public JComboBox getCallComboBox() {
    return phoneNumberCombo;
  }

  /**
   * Answers the given call.
   *
   * @param call the call to answer
   */
  public void answerCall(Call call) {
    new AnswerCallThread(call).start();
  }

  /**
   * Returns TRUE if this call is a call to an internal meta contact from the contact list,
   * otherwise returns FALSE.
   *
   * @return TRUE if this call is a call to an internal meta contact from the contact list,
   *     otherwise returns FALSE
   */
  public boolean isCallMetaContact() {
    return isCallMetaContact;
  }

  /**
   * Sets the isCallMetaContact variable to TRUE or FALSE. This defines if this call is a call to a
   * given meta contact selected from the contact list or a call to an external contact or phone
   * number.
   *
   * @param isCallMetaContact TRUE to define this call as a call to an internal meta contact and
   *     FALSE to define it as a call to an external contact or phone number.
   */
  public void setCallMetaContact(boolean isCallMetaContact) {
    this.isCallMetaContact = isCallMetaContact;
  }

  /**
   * Creates a call to the contact represented by the given string.
   *
   * @param contact the contact to call to
   */
  public void createCall(String contact) {
    CallPanel callPanel = new CallPanel(this, contact);

    mainFrame.addCallPanel(callPanel);

    new CreateCallThread(contact, callPanel).start();
  }

  /**
   * Creates a call to the given list of contacts.
   *
   * @param contacts the list of contacts to call to
   */
  public void createCall(Vector contacts) {
    CallPanel callPanel = new CallPanel(this, contacts);

    mainFrame.addCallPanel(callPanel);

    new CreateCallThread(contacts, callPanel).start();
  }

  /** Creates a call from a given Contact or a given String. */
  private class CreateCallThread extends Thread {
    Vector contacts;

    CallPanel callPanel;

    String stringContact;

    OperationSetBasicTelephony telephony;

    public CreateCallThread(String contact, CallPanel callPanel) {
      this.stringContact = contact;
      this.callPanel = callPanel;

      if (selectedCallProvider != null)
        telephony = mainFrame.getTelephonyOpSet(selectedCallProvider);
    }

    public CreateCallThread(Vector contacts, CallPanel callPanel) {
      this.contacts = contacts;
      this.callPanel = callPanel;

      if (selectedCallProvider != null)
        telephony = mainFrame.getTelephonyOpSet(selectedCallProvider);
    }

    public void run() {
      if (telephony == null) return;

      Call createdCall = null;

      if (contacts != null) {
        Contact contact = (Contact) contacts.get(0);

        // NOTE: The multi user call is not yet implemented!
        // We just get the first contact and create a call for him.
        try {
          createdCall = telephony.createCall(contact);
        } catch (OperationFailedException e) {
          logger.error("The call could not be created: " + e);

          callPanel.getParticipantPanel(contact.getDisplayName()).setState(e.getMessage());

          removeCallPanelWait(callPanel);
        }

        // If the call is successfully created we set the created
        // Call instance to the already existing CallPanel and we
        // add this call to the active calls.
        if (createdCall != null) {
          callPanel.setCall(createdCall, GuiCallParticipantRecord.OUTGOING_CALL);

          activeCalls.put(createdCall, callPanel);
        }
      } else {
        try {
          createdCall = telephony.createCall(stringContact);
        } catch (ParseException e) {
          logger.error("The call could not be created: " + e);

          callPanel.getParticipantPanel(stringContact).setState(e.getMessage());

          removeCallPanelWait(callPanel);
        } catch (OperationFailedException e) {
          logger.error("The call could not be created: " + e);

          callPanel.getParticipantPanel(stringContact).setState(e.getMessage());

          removeCallPanelWait(callPanel);
        }

        // If the call is successfully created we set the created
        // Call instance to the already existing CallPanel and we
        // add this call to the active calls.
        if (createdCall != null) {
          callPanel.setCall(createdCall, GuiCallParticipantRecord.OUTGOING_CALL);

          activeCalls.put(createdCall, callPanel);
        }
      }
    }
  }

  /** Answers all call participants in the given call. */
  private class AnswerCallThread extends Thread {
    private Call call;

    public AnswerCallThread(Call call) {
      this.call = call;
    }

    public void run() {
      ProtocolProviderService pps = call.getProtocolProvider();

      Iterator participants = call.getCallParticipants();

      while (participants.hasNext()) {
        CallParticipant participant = (CallParticipant) participants.next();

        OperationSetBasicTelephony telephony = mainFrame.getTelephonyOpSet(pps);

        try {
          telephony.answerCallParticipant(participant);
        } catch (OperationFailedException e) {
          logger.error(
              "Could not answer to : " + participant + " caused by the following exception: " + e);
        }
      }
    }
  }
}
Exemple #16
0
  /**
   * Handles the <tt>ActionEvent</tt> generated when user presses one of the buttons in this panel.
   */
  public void actionPerformed(ActionEvent evt) {
    JButton button = (JButton) evt.getSource();
    String buttonName = button.getName();

    if (buttonName.equals("call")) {
      Component selectedPanel = mainFrame.getSelectedTab();

      // call button is pressed over an already open call panel
      if (selectedPanel != null
          && selectedPanel instanceof CallPanel
          && ((CallPanel) selectedPanel).getCall().getCallState()
              == CallState.CALL_INITIALIZATION) {

        NotificationManager.stopSound(NotificationManager.BUSY_CALL);
        NotificationManager.stopSound(NotificationManager.INCOMING_CALL);

        CallPanel callPanel = (CallPanel) selectedPanel;

        Iterator participantPanels = callPanel.getParticipantsPanels();

        while (participantPanels.hasNext()) {
          CallParticipantPanel panel = (CallParticipantPanel) participantPanels.next();

          panel.setState("Connecting");
        }

        Call call = callPanel.getCall();

        answerCall(call);
      }
      // call button is pressed over the call list
      else if (selectedPanel != null
          && selectedPanel instanceof CallListPanel
          && ((CallListPanel) selectedPanel).getCallList().getSelectedIndex() != -1) {

        CallListPanel callListPanel = (CallListPanel) selectedPanel;

        GuiCallParticipantRecord callRecord =
            (GuiCallParticipantRecord) callListPanel.getCallList().getSelectedValue();

        String stringContact = callRecord.getParticipantName();

        createCall(stringContact);
      }
      // call button is pressed over the contact list
      else if (selectedPanel != null && selectedPanel instanceof ContactListPanel) {
        // call button is pressed when a meta contact is selected
        if (isCallMetaContact) {
          Object[] selectedContacts =
              mainFrame.getContactListPanel().getContactList().getSelectedValues();

          Vector telephonyContacts = new Vector();

          for (int i = 0; i < selectedContacts.length; i++) {

            Object o = selectedContacts[i];

            if (o instanceof MetaContact) {

              Contact contact =
                  ((MetaContact) o).getDefaultContact(OperationSetBasicTelephony.class);

              if (contact != null) telephonyContacts.add(contact);
              else {
                new ErrorDialog(
                        this.mainFrame,
                        Messages.getI18NString("warning").getText(),
                        Messages.getI18NString(
                                "contactNotSupportingTelephony",
                                new String[] {((MetaContact) o).getDisplayName()})
                            .getText())
                    .showDialog();
              }
            }
          }

          if (telephonyContacts.size() > 0) createCall(telephonyContacts);

        } else if (!phoneNumberCombo.isComboFieldEmpty()) {

          // if no contact is selected checks if the user has chosen
          // or has
          // writen something in the phone combo box

          String stringContact = phoneNumberCombo.getEditor().getItem().toString();

          createCall(stringContact);
        }
      } else if (selectedPanel != null && selectedPanel instanceof DialPanel) {
        String stringContact = phoneNumberCombo.getEditor().getItem().toString();
        createCall(stringContact);
      }
    } else if (buttonName.equalsIgnoreCase("hangup")) {
      Component selectedPanel = this.mainFrame.getSelectedTab();

      if (selectedPanel != null && selectedPanel instanceof CallPanel) {

        NotificationManager.stopSound(NotificationManager.BUSY_CALL);
        NotificationManager.stopSound(NotificationManager.INCOMING_CALL);
        NotificationManager.stopSound(NotificationManager.OUTGOING_CALL);

        CallPanel callPanel = (CallPanel) selectedPanel;

        Call call = callPanel.getCall();

        if (removeCallTimers.containsKey(callPanel)) {
          ((Timer) removeCallTimers.get(callPanel)).stop();
          removeCallTimers.remove(callPanel);
        }

        removeCallPanel(callPanel);

        if (call != null) {
          ProtocolProviderService pps = call.getProtocolProvider();

          OperationSetBasicTelephony telephony = mainFrame.getTelephonyOpSet(pps);

          Iterator participants = call.getCallParticipants();

          while (participants.hasNext()) {
            try {
              // now we hang up the first call participant in the
              // call
              telephony.hangupCallParticipant((CallParticipant) participants.next());
            } catch (OperationFailedException e) {
              logger.error("Hang up was not successful: " + e);
            }
          }
        }
      }
    } else if (buttonName.equalsIgnoreCase("minimize")) {
      JCheckBoxMenuItem hideCallPanelItem =
          mainFrame.getMainMenu().getViewMenu().getHideCallPanelItem();

      if (!hideCallPanelItem.isSelected()) hideCallPanelItem.setSelected(true);

      this.setCallPanelVisible(false);
    } else if (buttonName.equalsIgnoreCase("restore")) {

      JCheckBoxMenuItem hideCallPanelItem =
          mainFrame.getMainMenu().getViewMenu().getHideCallPanelItem();

      if (hideCallPanelItem.isSelected()) hideCallPanelItem.setSelected(false);

      this.setCallPanelVisible(true);
    }
  }
/**
 * A property sheet, allowing the user to edit different properties. The default implementation uses
 * the javabean standard naming conventions to extract property names and types. The user/system can
 * override this with the application preferences.
 */
public class PropertySheet extends JScrollPane {
  private DescriberBasedProperties props;
  private Logger logger = Logger.getLogger("edu.umd.cfar.lamp.apploader.propertysheets");

  /**
   * Gets the data model associated with the property sheet.
   *
   * @return the table model
   */
  private MyTableModel getTableModel() {
    return (MyTableModel) getTable().getModel();
  }

  /**
   * Gets the table contained within the property sheet. I'm not sure that this is the best way to
   * present properties, and may stop using tables in the future.
   *
   * @return the table
   */
  public EnhancedTable getTable() {
    return (EnhancedTable) getViewport().getView();
  }

  private class MyTableModel extends AbstractTableModel {
    /** @return 2 */
    public int getColumnCount() {
      return 2;
    }
    /** @return the number of properties */
    public int getRowCount() {
      return props.size();
    }
    /**
     * Gets the property descriptor for the row.
     *
     * @param r the row number (0-indexed)
     * @return the corresponding property
     */
    public InstancePropertyDescriptor getRow(int r) {
      return (InstancePropertyDescriptor) props.get(r);
    }

    /**
     * Determines if the value at a cell is editable
     *
     * @param rowIndex the property
     * @param columnIndex whether the property name (column zero) or property value (column one)
     * @return true, if the corresponding property is settable and the column index is 1
     */
    public boolean isCellEditable(int rowIndex, int columnIndex) {
      InstancePropertyDescriptor row = getRow(rowIndex);
      if (columnIndex == 0) {
        return false;
      } else if (columnIndex == 1) {
        return row.isSettable(props.getObject());
      } else {
        throw new IndexOutOfBoundsException("Not a valid cell: " + rowIndex + "x" + columnIndex);
      }
    }

    /**
     * Gets the appropriate property name or property value.
     *
     * @param rowIndex the row corresponding to a property
     * @param columnIndex either the name column (zero) or value column (one)
     * @return the name or value of the appropriate property
     */
    public Object getValueAt(int rowIndex, int columnIndex) {
      InstancePropertyDescriptor row = getRow(rowIndex);
      if (columnIndex == 0) {
        return row.getName();
      } else if (columnIndex == 1) {
        return row;
      } else {
        throw new IndexOutOfBoundsException("Not a valid cell: " + rowIndex + "x" + columnIndex);
      }
    }

    /**
     * Either "property" or "value". XXX: this should be localizable.
     *
     * @param columnIndex either the name column (zero) or value column (one)
     * @return "property" or "value"
     */
    public String getColumnName(int columnIndex) {
      if (columnIndex == 0) {
        return "Property";
      } else if (columnIndex == 1) {
        return "Value";
      } else {
        throw new IndexOutOfBoundsException("Not a valid column: " + columnIndex);
      }
    }

    /**
     * Class corresponding to the column
     *
     * @param columnIndex either the name column (zero) or value column (one)
     * @return <code>String.class</code> or <code>{@link InstancePropertyDescriptor}.class</code>
     */
    public Class getColumnClass(int columnIndex) {
      if (columnIndex == 0) {
        return String.class;
      } else if (columnIndex == 1) {
        return InstancePropertyDescriptor.class;
      } else {
        throw new IndexOutOfBoundsException("Not a valid column: " + columnIndex);
      }
    }

    /**
     * Sets the appropriate property value, if possible. Otherwise, this silently fails.
     *
     * @param value the new value for the appropriate property
     * @param rowIndex the row corresponding to a property
     * @param columnIndex only the value column (column one) works
     */
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
      if (columnIndex == 1) {
        InstancePropertyDescriptor row = getRow(rowIndex);
        if (row.isSettable(props.getObject())) {
          row.applySetter(props.getObject(), value);
        }
      }
    }

    /**
     * Gets the primary property table corresponding to this model.
     *
     * @return the table
     */
    public EnhancedTable getTable() {
      return (EnhancedTable) getViewport().getView();
    }
  }

  /** Create a new, empty property sheet. */
  public PropertySheet() {
    super(new EnhancedTable());
    this.getPreferredSize();
    props = new ForClassPropertyList();

    // Add bean change event listener
    props.addChangeListener(
        new ChangeListener() {
          public void stateChanged(ChangeEvent e) {
            // XXX Should I fire a 'stop editing' event here?
            refresh();
          }
        });

    // Add table
    JTable table = getTable();
    MyTableModel tableModel = new MyTableModel();
    table.setModel(tableModel);
    table.setDefaultRenderer(InstancePropertyDescriptor.class, new MyCellRenderer());
    table.setDefaultEditor(InstancePropertyDescriptor.class, new MyCellEditor());
  }

  private class MyCellRenderer implements TableCellRenderer {
    private JComponent lastEditor;
    /**
     * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable,
     *     java.lang.Object, boolean, boolean, int, int)
     */
    public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
      InstancePropertyDescriptor v = (InstancePropertyDescriptor) value;
      try {
        lastEditor = v.getRenderer(props.getObject(), props.getPrefs().getCore());
        return lastEditor;
      } catch (PreferenceException e) {
        e.printStackTrace();
        return null;
      }
    }
  }

  private class MyCellEditor extends AbstractCellEditor implements TableCellEditor {
    private CellEditor lastEditor;
    /** @see javax.swing.CellEditor#getCellEditorValue() */
    public Object getCellEditorValue() {
      if (lastEditor != null) {
        return lastEditor.getCellEditorValue();
      }
      return null;
    }

    /**
     * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable,
     *     java.lang.Object, boolean, int, int)
     */
    public Component getTableCellEditorComponent(
        JTable table, Object value, boolean isSelected, int row, int column) {
      InstancePropertyDescriptor v = (InstancePropertyDescriptor) value;
      JComponent c;
      try {
        c = v.getEditor(props.getObject(), props.getPrefs().getCore());
        lastEditor = (CellEditor) c;
        return c;
      } catch (PreferenceException e) {
        e.printStackTrace();
        return null;
      }
    }
  }

  /**
   * Gets the preference manager associated with this property sheet.
   *
   * @return the preference manager
   */
  public PrefsManager getPrefs() {
    return props.getPrefs();
  }

  /**
   * Sets the preference manager associated with this property sheet. This is necessary for
   * localization and determining extended properties.
   *
   * @param manager the preference manager
   */
  public void setPrefs(PrefsManager manager) {
    props.setPrefs(manager);
  }

  /** Sort the descriptors by their display name using the current lexicographical ordering. */
  private static class PropertySorter implements Comparator {
    /**
     * Sort the descriptors by their display name using the current lexicographical ordering
     *
     * @param a a property descriptor
     * @param b the other ObjectPropertyDescriptor
     * @return <code>getName().compareto(b.getName())</code>
     */
    public int compare(Object a, Object b) {
      InstancePropertyDescriptor A = (InstancePropertyDescriptor) a;
      InstancePropertyDescriptor B = (InstancePropertyDescriptor) b;

      return A.getName().compareTo(B.getName());
    }
  }

  static final PropertySorter SORT_BY_PROPERTY_NAME = new PropertySorter();

  /**
   * Set the subject bean to check for properties.
   *
   * @param o the subject bean
   */
  public void setObject(Object o) {
    if (o != props.getObject()) {
      if (getTable().isEditing()) {
        getTable().editingStopped(new ChangeEvent(this));
      }
      getTable().editingCanceled(new ChangeEvent(this));
      props.setObject(o);
      getTableModel().fireTableStructureChanged();
      getTable().setRowHeightToMaximumPreferredHeight();
    }
  }

  /**
   * Gets the bound subject bean.
   *
   * @return the subject
   */
  public Object getObject() {
    return props.getObject();
  }

  /** Refresh the properties from the bound object. */
  public void refresh() {
    props.refresh();
    getTableModel().fireTableDataChanged();
  }

  /** @return */
  public Logger getLogger() {
    return logger;
  }

  /** @param logger */
  public void setLogger(Logger logger) {
    this.logger = logger;
  }
}
Exemple #18
0
/**
 * @author Lyubomir Marinov
 * @author Damian Minkov
 * @author Yana Stamcheva
 */
public class MediaConfiguration {
  /** The <tt>Logger</tt> used by the <tt>MediaConfiguration</tt> class for logging output. */
  private static final Logger logger = Logger.getLogger(MediaConfiguration.class);

  /** The <tt>MediaService</tt> implementation used by <tt>MediaConfiguration</tt>. */
  private static final MediaServiceImpl mediaService = NeomediaActivator.getMediaServiceImpl();

  /** The preferred width of all panels. */
  private static final int WIDTH = 350;

  /**
   * Indicates if the Devices settings configuration tab should be disabled, i.e. not visible to the
   * user.
   */
  private static final String DEVICES_DISABLED_PROP =
      "net.java.sip.communicator.impl.neomedia.devicesconfig.DISABLED";

  /**
   * Indicates if the Audio/Video encodings configuration tab should be disabled, i.e. not visible
   * to the user.
   */
  private static final String ENCODINGS_DISABLED_PROP =
      "net.java.sip.communicator.impl.neomedia.encodingsconfig.DISABLED";

  /**
   * Indicates if the Video/More Settings configuration tab should be disabled, i.e. not visible to
   * the user.
   */
  private static final String VIDEO_MORE_SETTINGS_DISABLED_PROP =
      "net.java.sip.communicator.impl.neomedia.videomoresettingsconfig.DISABLED";

  /**
   * Returns the audio configuration panel.
   *
   * @return the audio configuration panel
   */
  public static Component createAudioConfigPanel() {
    return createControls(DeviceConfigurationComboBoxModel.AUDIO);
  }

  /**
   * Returns the video configuration panel.
   *
   * @return the video configuration panel
   */
  public static Component createVideoConfigPanel() {
    return createControls(DeviceConfigurationComboBoxModel.VIDEO);
  }

  private static void createAudioPreview(
      final AudioSystem audioSystem,
      final JComboBox comboBox,
      final SoundLevelIndicator soundLevelIndicator) {
    final ActionListener captureComboActionListener =
        new ActionListener() {
          private final SimpleAudioLevelListener audioLevelListener =
              new SimpleAudioLevelListener() {
                public void audioLevelChanged(int level) {
                  soundLevelIndicator.updateSoundLevel(level);
                }
              };

          private AudioMediaDeviceSession deviceSession;

          private final BufferTransferHandler transferHandler =
              new BufferTransferHandler() {
                public void transferData(PushBufferStream stream) {
                  try {
                    stream.read(transferHandlerBuffer);
                  } catch (IOException ioe) {
                  }
                }
              };

          private final Buffer transferHandlerBuffer = new Buffer();

          public void actionPerformed(ActionEvent event) {
            setDeviceSession(null);

            CaptureDeviceInfo cdi;

            if (comboBox == null) {
              cdi = soundLevelIndicator.isShowing() ? audioSystem.getCaptureDevice() : null;
            } else {
              Object selectedItem =
                  soundLevelIndicator.isShowing() ? comboBox.getSelectedItem() : null;

              cdi =
                  (selectedItem instanceof DeviceConfigurationComboBoxModel.CaptureDevice)
                      ? ((DeviceConfigurationComboBoxModel.CaptureDevice) selectedItem).info
                      : null;
            }

            if (cdi != null) {
              for (MediaDevice md : mediaService.getDevices(MediaType.AUDIO, MediaUseCase.ANY)) {
                if (md instanceof AudioMediaDeviceImpl) {
                  AudioMediaDeviceImpl amd = (AudioMediaDeviceImpl) md;

                  if (cdi.equals(amd.getCaptureDeviceInfo())) {
                    try {
                      MediaDeviceSession deviceSession = amd.createSession();
                      boolean setDeviceSession = false;

                      try {
                        if (deviceSession instanceof AudioMediaDeviceSession) {
                          setDeviceSession((AudioMediaDeviceSession) deviceSession);
                          setDeviceSession = true;
                        }
                      } finally {
                        if (!setDeviceSession) deviceSession.close();
                      }
                    } catch (Throwable t) {
                      if (t instanceof ThreadDeath) throw (ThreadDeath) t;
                    }
                    break;
                  }
                }
              }
            }
          }

          private void setDeviceSession(AudioMediaDeviceSession deviceSession) {
            if (this.deviceSession == deviceSession) return;

            if (this.deviceSession != null) {
              try {
                this.deviceSession.close();
              } finally {
                this.deviceSession.setLocalUserAudioLevelListener(null);
                soundLevelIndicator.resetSoundLevel();
              }
            }

            this.deviceSession = deviceSession;

            if (this.deviceSession != null) {
              this.deviceSession.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW));
              this.deviceSession.setLocalUserAudioLevelListener(audioLevelListener);
              this.deviceSession.start(MediaDirection.SENDONLY);

              try {
                DataSource dataSource = this.deviceSession.getOutputDataSource();

                dataSource.connect();

                PushBufferStream[] streams = ((PushBufferDataSource) dataSource).getStreams();

                for (PushBufferStream stream : streams) stream.setTransferHandler(transferHandler);

                dataSource.start();
              } catch (Throwable t) {
                if (t instanceof ThreadDeath) throw (ThreadDeath) t;
                else setDeviceSession(null);
              }
            }
          }
        };

    if (comboBox != null) comboBox.addActionListener(captureComboActionListener);

    soundLevelIndicator.addHierarchyListener(
        new HierarchyListener() {
          public void hierarchyChanged(HierarchyEvent event) {
            if ((event.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
              SwingUtilities.invokeLater(
                  new Runnable() {
                    public void run() {
                      captureComboActionListener.actionPerformed(null);
                    }
                  });
            }
          }
        });
  }
  /**
   * Creates the UI controls which are to control the details of a specific <tt>AudioSystem</tt>.
   *
   * @param audioSystem the <tt>AudioSystem</tt> for which the UI controls to control its details
   *     are to be created
   * @param container the <tt>JComponent</tt> into which the UI controls which are to control the
   *     details of the specified <tt>audioSystem</tt> are to be added
   */
  public static void createAudioSystemControls(AudioSystem audioSystem, JComponent container) {
    GridBagConstraints constraints = new GridBagConstraints();

    constraints.anchor = GridBagConstraints.NORTHWEST;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.weighty = 0;

    int audioSystemFeatures = audioSystem.getFeatures();
    boolean featureNotifyAndPlaybackDevices =
        ((audioSystemFeatures & AudioSystem.FEATURE_NOTIFY_AND_PLAYBACK_DEVICES) != 0);

    constraints.gridx = 0;
    constraints.insets = new Insets(3, 0, 3, 3);
    constraints.weightx = 0;

    constraints.gridy = 0;
    container.add(
        new JLabel(getLabelText(DeviceConfigurationComboBoxModel.AUDIO_CAPTURE)), constraints);
    if (featureNotifyAndPlaybackDevices) {
      constraints.gridy = 2;
      container.add(
          new JLabel(getLabelText(DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK)), constraints);
      constraints.gridy = 3;
      container.add(
          new JLabel(getLabelText(DeviceConfigurationComboBoxModel.AUDIO_NOTIFY)), constraints);
    }

    constraints.gridx = 1;
    constraints.insets = new Insets(3, 3, 3, 0);
    constraints.weightx = 1;

    JComboBox captureCombo = null;

    if (featureNotifyAndPlaybackDevices) {
      captureCombo = new JComboBox();
      captureCombo.setEditable(false);
      captureCombo.setModel(
          new DeviceConfigurationComboBoxModel(
              captureCombo,
              mediaService.getDeviceConfiguration(),
              DeviceConfigurationComboBoxModel.AUDIO_CAPTURE));
      constraints.gridy = 0;
      container.add(captureCombo, constraints);
    }

    int anchor = constraints.anchor;
    SoundLevelIndicator capturePreview =
        new SoundLevelIndicator(
            SimpleAudioLevelListener.MIN_LEVEL, SimpleAudioLevelListener.MAX_LEVEL);

    constraints.anchor = GridBagConstraints.CENTER;
    constraints.gridy = (captureCombo == null) ? 0 : 1;
    container.add(capturePreview, constraints);
    constraints.anchor = anchor;

    constraints.gridy = GridBagConstraints.RELATIVE;

    if (featureNotifyAndPlaybackDevices) {
      JComboBox playbackCombo = new JComboBox();

      playbackCombo.setEditable(false);
      playbackCombo.setModel(
          new DeviceConfigurationComboBoxModel(
              captureCombo,
              mediaService.getDeviceConfiguration(),
              DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK));
      container.add(playbackCombo, constraints);

      JComboBox notifyCombo = new JComboBox();

      notifyCombo.setEditable(false);
      notifyCombo.setModel(
          new DeviceConfigurationComboBoxModel(
              captureCombo,
              mediaService.getDeviceConfiguration(),
              DeviceConfigurationComboBoxModel.AUDIO_NOTIFY));
      container.add(notifyCombo, constraints);
    }

    if ((AudioSystem.FEATURE_ECHO_CANCELLATION & audioSystemFeatures) != 0) {
      final SIPCommCheckBox echoCancelCheckBox =
          new SIPCommCheckBox(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.ECHOCANCEL"));

      /*
       * First set the selected one, then add the listener in order to
       * avoid saving the value when using the default one and only
       * showing to user without modification.
       */
      echoCancelCheckBox.setSelected(mediaService.getDeviceConfiguration().isEchoCancel());
      echoCancelCheckBox.addItemListener(
          new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
              mediaService.getDeviceConfiguration().setEchoCancel(echoCancelCheckBox.isSelected());
            }
          });
      container.add(echoCancelCheckBox, constraints);
    }

    if ((AudioSystem.FEATURE_DENOISE & audioSystemFeatures) != 0) {
      final SIPCommCheckBox denoiseCheckBox =
          new SIPCommCheckBox(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.DENOISE"));

      /*
       * First set the selected one, then add the listener in order to
       * avoid saving the value when using the default one and only
       * showing to user without modification.
       */
      denoiseCheckBox.setSelected(mediaService.getDeviceConfiguration().isDenoise());
      denoiseCheckBox.addItemListener(
          new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
              mediaService.getDeviceConfiguration().setDenoise(denoiseCheckBox.isSelected());
            }
          });
      container.add(denoiseCheckBox, constraints);
    }

    createAudioPreview(audioSystem, captureCombo, capturePreview);
  }

  /**
   * Creates basic controls for a type (AUDIO or VIDEO).
   *
   * @param type the type.
   * @return the build Component.
   */
  public static Component createBasicControls(final int type) {
    final JComboBox deviceComboBox = new JComboBox();

    deviceComboBox.setEditable(false);
    deviceComboBox.setModel(
        new DeviceConfigurationComboBoxModel(
            deviceComboBox, mediaService.getDeviceConfiguration(), type));

    JLabel deviceLabel = new JLabel(getLabelText(type));

    deviceLabel.setDisplayedMnemonic(getDisplayedMnemonic(type));
    deviceLabel.setLabelFor(deviceComboBox);

    final Container devicePanel = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));

    devicePanel.setMaximumSize(new Dimension(WIDTH, 25));
    devicePanel.add(deviceLabel);
    devicePanel.add(deviceComboBox);

    final JPanel deviceAndPreviewPanel = new TransparentPanel(new BorderLayout());
    int preferredDeviceAndPreviewPanelHeight;

    switch (type) {
      case DeviceConfigurationComboBoxModel.AUDIO:
        preferredDeviceAndPreviewPanelHeight = 225;
        break;
      case DeviceConfigurationComboBoxModel.VIDEO:
        preferredDeviceAndPreviewPanelHeight = 305;
        break;
      default:
        preferredDeviceAndPreviewPanelHeight = 0;
        break;
    }
    if (preferredDeviceAndPreviewPanelHeight > 0)
      deviceAndPreviewPanel.setPreferredSize(
          new Dimension(WIDTH, preferredDeviceAndPreviewPanelHeight));
    deviceAndPreviewPanel.add(devicePanel, BorderLayout.NORTH);

    final ActionListener deviceComboBoxActionListener =
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            boolean revalidateAndRepaint = false;

            for (int i = deviceAndPreviewPanel.getComponentCount() - 1; i >= 0; i--) {
              Component c = deviceAndPreviewPanel.getComponent(i);

              if (c != devicePanel) {
                deviceAndPreviewPanel.remove(i);
                revalidateAndRepaint = true;
              }
            }

            Component preview = null;

            if ((deviceComboBox.getSelectedItem() != null) && deviceComboBox.isShowing()) {
              preview =
                  createPreview(type, deviceComboBox, deviceAndPreviewPanel.getPreferredSize());
            }

            if (preview != null) {
              deviceAndPreviewPanel.add(preview, BorderLayout.CENTER);
              revalidateAndRepaint = true;
            }

            if (revalidateAndRepaint) {
              deviceAndPreviewPanel.revalidate();
              deviceAndPreviewPanel.repaint();
            }
          }
        };

    deviceComboBox.addActionListener(deviceComboBoxActionListener);
    /*
     * We have to initialize the controls to reflect the configuration
     * at the time of creating this instance. Additionally, because the
     * video preview will stop when it and its associated controls
     * become unnecessary, we have to restart it when the mentioned
     * controls become necessary again. We'll address the two goals
     * described by pretending there's a selection in the video combo
     * box when the combo box in question becomes displayable.
     */
    deviceComboBox.addHierarchyListener(
        new HierarchyListener() {
          public void hierarchyChanged(HierarchyEvent event) {
            if ((event.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
              SwingUtilities.invokeLater(
                  new Runnable() {
                    public void run() {
                      deviceComboBoxActionListener.actionPerformed(null);
                    }
                  });
            }
          }
        });

    return deviceAndPreviewPanel;
  }

  /**
   * Creates all the controls (including encoding) for a type(AUDIO or VIDEO)
   *
   * @param type the type.
   * @return the build Component.
   */
  private static Component createControls(int type) {
    ConfigurationService cfg = NeomediaActivator.getConfigurationService();
    SIPCommTabbedPane container = new SIPCommTabbedPane();
    ResourceManagementService res = NeomediaActivator.getResources();

    if ((cfg == null) || !cfg.getBoolean(DEVICES_DISABLED_PROP, false)) {
      container.insertTab(
          res.getI18NString("impl.media.configform.DEVICES"),
          null,
          createBasicControls(type),
          null,
          0);
    }
    if ((cfg == null) || !cfg.getBoolean(ENCODINGS_DISABLED_PROP, false)) {
      container.insertTab(
          res.getI18NString("impl.media.configform.ENCODINGS"),
          null,
          new PriorityTable(
              new EncodingConfigurationTableModel(mediaService.getEncodingConfiguration(), type),
              100),
          null,
          1);
    }
    if ((type == DeviceConfigurationComboBoxModel.VIDEO)
        && ((cfg == null) || !cfg.getBoolean(VIDEO_MORE_SETTINGS_DISABLED_PROP, false))) {
      container.insertTab(
          res.getI18NString("impl.media.configform.VIDEO_MORE_SETTINGS"),
          null,
          createVideoAdvancedSettings(),
          null,
          2);
    }
    return container;
  }

  /**
   * Creates preview for the (video) device in the video container.
   *
   * @param device the device
   * @param videoContainer the video container
   * @throws IOException a problem accessing the device
   * @throws MediaException a problem getting preview
   */
  private static void createVideoPreview(CaptureDeviceInfo device, JComponent videoContainer)
      throws IOException, MediaException {
    videoContainer.removeAll();

    videoContainer.revalidate();
    videoContainer.repaint();

    if (device == null) return;

    for (MediaDevice mediaDevice : mediaService.getDevices(MediaType.VIDEO, MediaUseCase.ANY)) {
      if (((MediaDeviceImpl) mediaDevice).getCaptureDeviceInfo().equals(device)) {
        Dimension videoContainerSize = videoContainer.getPreferredSize();
        Component preview =
            (Component)
                mediaService.getVideoPreviewComponent(
                    mediaDevice, videoContainerSize.width, videoContainerSize.height);

        if (preview != null) videoContainer.add(preview);
        break;
      }
    }
  }

  /**
   * Create preview component.
   *
   * @param type type
   * @param comboBox the options.
   * @param prefSize the preferred size
   * @return the component.
   */
  private static Component createPreview(int type, final JComboBox comboBox, Dimension prefSize) {
    JComponent preview = null;

    if (type == DeviceConfigurationComboBoxModel.AUDIO) {
      Object selectedItem = comboBox.getSelectedItem();

      if (selectedItem instanceof AudioSystem) {
        AudioSystem audioSystem = (AudioSystem) selectedItem;

        if (!NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase(audioSystem.getLocatorProtocol())) {
          preview = new TransparentPanel(new GridBagLayout());
          createAudioSystemControls(audioSystem, preview);
        }
      }
    } else if (type == DeviceConfigurationComboBoxModel.VIDEO) {
      JLabel noPreview =
          new JLabel(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.NO_PREVIEW"));

      noPreview.setHorizontalAlignment(SwingConstants.CENTER);
      noPreview.setVerticalAlignment(SwingConstants.CENTER);

      preview = createVideoContainer(noPreview);
      preview.setPreferredSize(prefSize);

      Object selectedItem = comboBox.getSelectedItem();
      CaptureDeviceInfo device = null;
      if (selectedItem instanceof DeviceConfigurationComboBoxModel.CaptureDevice)
        device = ((DeviceConfigurationComboBoxModel.CaptureDevice) selectedItem).info;

      Exception exception;
      try {
        createVideoPreview(device, preview);
        exception = null;
      } catch (IOException ex) {
        exception = ex;
      } catch (MediaException ex) {
        exception = ex;
      }
      if (exception != null) {
        logger.error("Failed to create preview for device " + device, exception);
        device = null;
      }
    }

    return preview;
  }

  /**
   * Creates the video container.
   *
   * @param noVideoComponent the container component.
   * @return the video container.
   */
  private static JComponent createVideoContainer(Component noVideoComponent) {
    return new VideoContainer(noVideoComponent, false);
  }

  /**
   * The mnemonic for a type.
   *
   * @param type audio or video type.
   * @return the mnemonic.
   */
  private static char getDisplayedMnemonic(int type) {
    switch (type) {
      case DeviceConfigurationComboBoxModel.AUDIO:
        return NeomediaActivator.getResources().getI18nMnemonic("impl.media.configform.AUDIO");
      case DeviceConfigurationComboBoxModel.VIDEO:
        return NeomediaActivator.getResources().getI18nMnemonic("impl.media.configform.VIDEO");
      default:
        throw new IllegalArgumentException("type");
    }
  }

  /**
   * A label for a type.
   *
   * @param type the type.
   * @return the label.
   */
  private static String getLabelText(int type) {
    switch (type) {
      case DeviceConfigurationComboBoxModel.AUDIO:
        return NeomediaActivator.getResources().getI18NString("impl.media.configform.AUDIO");
      case DeviceConfigurationComboBoxModel.AUDIO_CAPTURE:
        return NeomediaActivator.getResources().getI18NString("impl.media.configform.AUDIO_IN");
      case DeviceConfigurationComboBoxModel.AUDIO_NOTIFY:
        return NeomediaActivator.getResources().getI18NString("impl.media.configform.AUDIO_NOTIFY");
      case DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK:
        return NeomediaActivator.getResources().getI18NString("impl.media.configform.AUDIO_OUT");
      case DeviceConfigurationComboBoxModel.VIDEO:
        return NeomediaActivator.getResources().getI18NString("impl.media.configform.VIDEO");
      default:
        throw new IllegalArgumentException("type");
    }
  }

  /**
   * Creates the video advanced settings.
   *
   * @return video advanced settings panel.
   */
  private static Component createVideoAdvancedSettings() {
    ResourceManagementService resources = NeomediaActivator.getResources();

    final DeviceConfiguration deviceConfig = mediaService.getDeviceConfiguration();

    TransparentPanel centerPanel = new TransparentPanel(new GridBagLayout());
    centerPanel.setMaximumSize(new Dimension(WIDTH, 150));

    JButton resetDefaultsButton =
        new JButton(resources.getI18NString("impl.media.configform.VIDEO_RESET"));
    JPanel resetButtonPanel = new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
    resetButtonPanel.add(resetDefaultsButton);

    final JPanel centerAdvancedPanel = new TransparentPanel(new BorderLayout());
    centerAdvancedPanel.add(centerPanel, BorderLayout.NORTH);
    centerAdvancedPanel.add(resetButtonPanel, BorderLayout.SOUTH);

    GridBagConstraints constraints = new GridBagConstraints();
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.anchor = GridBagConstraints.NORTHWEST;
    constraints.insets = new Insets(5, 5, 0, 0);
    constraints.gridx = 0;
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.gridy = 0;

    centerPanel.add(
        new JLabel(resources.getI18NString("impl.media.configform.VIDEO_RESOLUTION")), constraints);
    constraints.gridy = 1;
    constraints.insets = new Insets(0, 0, 0, 0);
    final JCheckBox frameRateCheck =
        new SIPCommCheckBox(resources.getI18NString("impl.media.configform.VIDEO_FRAME_RATE"));
    centerPanel.add(frameRateCheck, constraints);
    constraints.gridy = 2;
    constraints.insets = new Insets(5, 5, 0, 0);
    centerPanel.add(
        new JLabel(resources.getI18NString("impl.media.configform.VIDEO_PACKETS_POLICY")),
        constraints);

    constraints.weightx = 1;
    constraints.gridx = 1;
    constraints.gridy = 0;
    constraints.insets = new Insets(5, 0, 0, 5);
    Object[] resolutionValues = new Object[DeviceConfiguration.SUPPORTED_RESOLUTIONS.length + 1];
    System.arraycopy(
        DeviceConfiguration.SUPPORTED_RESOLUTIONS,
        0,
        resolutionValues,
        1,
        DeviceConfiguration.SUPPORTED_RESOLUTIONS.length);
    final JComboBox sizeCombo = new JComboBox(resolutionValues);
    sizeCombo.setRenderer(new ResolutionCellRenderer());
    sizeCombo.setEditable(false);
    centerPanel.add(sizeCombo, constraints);

    // default value is 20
    final JSpinner frameRate = new JSpinner(new SpinnerNumberModel(20, 5, 30, 1));
    frameRate.addChangeListener(
        new ChangeListener() {
          public void stateChanged(ChangeEvent e) {
            deviceConfig.setFrameRate(
                ((SpinnerNumberModel) frameRate.getModel()).getNumber().intValue());
          }
        });
    constraints.gridy = 1;
    constraints.insets = new Insets(0, 0, 0, 5);
    centerPanel.add(frameRate, constraints);

    frameRateCheck.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            if (frameRateCheck.isSelected()) {
              deviceConfig.setFrameRate(
                  ((SpinnerNumberModel) frameRate.getModel()).getNumber().intValue());
            } else // unlimited framerate
            deviceConfig.setFrameRate(-1);

            frameRate.setEnabled(frameRateCheck.isSelected());
          }
        });

    final JSpinner videoMaxBandwidth =
        new JSpinner(
            new SpinnerNumberModel(deviceConfig.getVideoMaxBandwidth(), 1, Integer.MAX_VALUE, 1));
    videoMaxBandwidth.addChangeListener(
        new ChangeListener() {
          public void stateChanged(ChangeEvent e) {
            deviceConfig.setVideoMaxBandwidth(
                ((SpinnerNumberModel) videoMaxBandwidth.getModel()).getNumber().intValue());
          }
        });
    constraints.gridx = 1;
    constraints.gridy = 2;
    constraints.insets = new Insets(0, 0, 5, 5);
    centerPanel.add(videoMaxBandwidth, constraints);

    resetDefaultsButton.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            // reset to defaults
            sizeCombo.setSelectedIndex(0);
            frameRateCheck.setSelected(false);
            frameRate.setEnabled(false);
            frameRate.setValue(20);
            // unlimited framerate
            deviceConfig.setFrameRate(-1);
            videoMaxBandwidth.setValue(DeviceConfiguration.DEFAULT_VIDEO_MAX_BANDWIDTH);
          }
        });

    // load selected value or auto
    Dimension videoSize = deviceConfig.getVideoSize();

    if ((videoSize.getHeight() != DeviceConfiguration.DEFAULT_VIDEO_HEIGHT)
        && (videoSize.getWidth() != DeviceConfiguration.DEFAULT_VIDEO_WIDTH))
      sizeCombo.setSelectedItem(deviceConfig.getVideoSize());
    else sizeCombo.setSelectedIndex(0);
    sizeCombo.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            Dimension selectedVideoSize = (Dimension) sizeCombo.getSelectedItem();

            if (selectedVideoSize == null) {
              // the auto value, default one
              selectedVideoSize =
                  new Dimension(
                      DeviceConfiguration.DEFAULT_VIDEO_WIDTH,
                      DeviceConfiguration.DEFAULT_VIDEO_HEIGHT);
            }
            deviceConfig.setVideoSize(selectedVideoSize);
          }
        });

    frameRateCheck.setSelected(
        deviceConfig.getFrameRate() != DeviceConfiguration.DEFAULT_VIDEO_FRAMERATE);
    frameRate.setEnabled(frameRateCheck.isSelected());

    if (frameRate.isEnabled()) frameRate.setValue(deviceConfig.getFrameRate());

    return centerAdvancedPanel;
  }

  /** Renders the available resolutions in the combo box. */
  private static class ResolutionCellRenderer extends DefaultListCellRenderer {
    /**
     * The serialization version number of the <tt>ResolutionCellRenderer</tt> class. Defined to the
     * value of <tt>0</tt> because the <tt>ResolutionCellRenderer</tt> instances do not have state
     * of their own.
     */
    private static final long serialVersionUID = 0L;

    /**
     * Sets readable text describing the resolution if the selected value is null we return the
     * string "Auto".
     *
     * @param list
     * @param value
     * @param index
     * @param isSelected
     * @param cellHasFocus
     * @return Component
     */
    @Override
    public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
      // call super to set backgrounds and fonts
      super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);

      // now just change the text
      if (value == null) setText("Auto");
      else if (value instanceof Dimension) {
        Dimension d = (Dimension) value;

        setText(((int) d.getWidth()) + "x" + ((int) d.getHeight()));
      }
      return this;
    }
  }
}
Exemple #19
0
/** Denotes a front-end controller for the client. */
public final class ClientController implements ActionProvider, CaptureCallback, AnalysisCallback {
  // INNER TYPES

  /** Provides a default tool context implementation. */
  static final class DefaultToolContext implements ToolContext {
    // VARIABLES

    private final int startSampleIdx;
    private final int endSampleIdx;

    // CONSTRUCTORS

    /**
     * Creates a new DefaultToolContext instance.
     *
     * @param aStartSampleIdx the starting sample index;
     * @param aEndSampleIdx the ending sample index.
     */
    public DefaultToolContext(final int aStartSampleIdx, final int aEndSampleIdx) {
      this.startSampleIdx = aStartSampleIdx;
      this.endSampleIdx = aEndSampleIdx;
    }

    /** @see nl.lxtreme.ols.api.tools.ToolContext#getEndSampleIndex() */
    @Override
    public int getEndSampleIndex() {
      return this.endSampleIdx;
    }

    /** @see nl.lxtreme.ols.api.tools.ToolContext#getLength() */
    @Override
    public int getLength() {
      return Math.max(0, this.endSampleIdx - this.startSampleIdx);
    }

    /** @see nl.lxtreme.ols.api.tools.ToolContext#getStartSampleIndex() */
    @Override
    public int getStartSampleIndex() {
      return this.startSampleIdx;
    }
  }

  // CONSTANTS

  private static final Logger LOG = Logger.getLogger(ClientController.class.getName());

  // VARIABLES

  private final ActionManager actionManager;
  private final BundleContext bundleContext;
  private final DataContainer dataContainer;
  private final EventListenerList evenListeners;
  private final ProjectManager projectManager;
  private final Host host;

  private MainFrame mainFrame;

  private volatile DeviceController currentDevCtrl;

  // CONSTRUCTORS

  /** Creates a new ClientController instance. */
  public ClientController(
      final BundleContext aBundleContext, final Host aHost, final ProjectManager aProjectManager) {
    this.bundleContext = aBundleContext;
    this.host = aHost;
    this.projectManager = aProjectManager;

    this.dataContainer = new DataContainer(this.projectManager);
    this.actionManager = new ActionManager();
    this.evenListeners = new EventListenerList();

    fillActionManager(this.actionManager);
  }

  // METHODS

  /**
   * Adds a cursor change listener.
   *
   * @param aListener the listener to add, cannot be <code>null</code>.
   */
  public void addCursorChangeListener(final DiagramCursorChangeListener aListener) {
    this.evenListeners.add(DiagramCursorChangeListener.class, aListener);
  }

  /**
   * Adds the given device controller to this controller.
   *
   * @param aDeviceController the device controller to add, cannot be <code>null</code>.
   */
  public void addDevice(final DeviceController aDeviceController) {
    if (this.mainFrame != null) {
      if (this.mainFrame.addDeviceMenuItem(aDeviceController)) {
        this.currentDevCtrl = aDeviceController;
      }
    }

    updateActions();
  }

  /**
   * Adds the given exporter to this controller.
   *
   * @param aExporter the exporter to add, cannot be <code>null</code>.
   */
  public void addExporter(final Exporter aExporter) {
    if (this.mainFrame != null) {
      this.mainFrame.addExportMenuItem(aExporter.getName());
    }

    updateActions();
  }

  /**
   * Adds the given tool to this controller.
   *
   * @param aTool the tool to add, cannot be <code>null</code>.
   */
  public void addTool(final Tool aTool) {
    if (this.mainFrame != null) {
      this.mainFrame.addToolMenuItem(aTool.getName());
    }

    updateActions();
  }

  /** @see nl.lxtreme.ols.api.tools.AnalysisCallback#analysisAborted(java.lang.String) */
  @Override
  public void analysisAborted(final String aReason) {
    setStatus("Analysis aborted! " + aReason);

    updateActions();
  }

  /**
   * @see
   *     nl.lxtreme.ols.api.tools.AnalysisCallback#analysisComplete(nl.lxtreme.ols.api.data.CapturedData)
   */
  @Override
  public void analysisComplete(final CapturedData aNewCapturedData) {
    if (aNewCapturedData != null) {
      this.dataContainer.setCapturedData(aNewCapturedData);
    }
    if (this.mainFrame != null) {
      repaintMainFrame();
    }

    setStatus("");
    updateActions();
  }

  /** Cancels the current capturing (if in progress). */
  public void cancelCapture() {
    final DeviceController deviceController = getDeviceController();
    if (deviceController == null) {
      return;
    }

    deviceController.cancel();
  }

  /** @see nl.lxtreme.ols.api.devices.CaptureCallback#captureAborted(java.lang.String) */
  @Override
  public void captureAborted(final String aReason) {
    setStatus("Capture aborted! " + aReason);
    updateActions();
  }

  /**
   * @see
   *     nl.lxtreme.ols.api.devices.CaptureCallback#captureComplete(nl.lxtreme.ols.api.data.CapturedData)
   */
  @Override
  public void captureComplete(final CapturedData aCapturedData) {
    setCapturedData(aCapturedData);

    setStatus("Capture finished at {0,date,medium} {0,time,medium}.", new Date());

    updateActions();
  }

  /**
   * Captures the data of the current device controller.
   *
   * @param aParent the parent window to use, can be <code>null</code>.
   * @return <code>true</code> if the capture succeeded, <code>false</code> otherwise.
   * @throws IOException in case of I/O problems.
   */
  public boolean captureData(final Window aParent) {
    final DeviceController devCtrl = getDeviceController();
    if (devCtrl == null) {
      return false;
    }

    try {
      if (devCtrl.setupCapture(aParent)) {
        setStatus(
            "Capture from {0} started at {1,date,medium} {1,time,medium} ...",
            devCtrl.getName(), new Date());

        devCtrl.captureData(this);
        return true;
      }

      return false;
    } catch (IOException exception) {
      captureAborted("I/O problem: " + exception.getMessage());

      // Make sure to handle IO-interrupted exceptions properly!
      if (!HostUtils.handleInterruptedException(exception)) {
        exception.printStackTrace();
      }

      return false;
    } finally {
      updateActions();
    }
  }

  /** @see nl.lxtreme.ols.api.devices.CaptureCallback#captureStarted(int, int, int) */
  @Override
  public synchronized void captureStarted(
      final int aSampleRate, final int aChannelCount, final int aChannelMask) {
    final Runnable runner =
        new Runnable() {
          @Override
          public void run() {
            updateActions();
          }
        };

    if (SwingUtilities.isEventDispatchThread()) {
      runner.run();
    } else {
      SwingUtilities.invokeLater(runner);
    }
  }

  /** Clears all current cursors. */
  public void clearAllCursors() {
    for (int i = 0; i < CapturedData.MAX_CURSORS; i++) {
      this.dataContainer.setCursorPosition(i, null);
    }
    fireCursorChangedEvent(0, -1); // removed...

    updateActions();
  }

  /** Clears the current device controller. */
  public void clearDeviceController() {
    this.currentDevCtrl = null;
  }

  /**
   * Clears the current project, and start over as it were a new project, in which no captured data
   * is shown.
   */
  public void createNewProject() {
    this.projectManager.createNewProject();

    if (this.mainFrame != null) {
      this.mainFrame.repaint();
    }

    updateActions();
  }

  /** Exits the client application. */
  public void exit() {
    if (this.host != null) {
      this.host.exit();
    }
  }

  /**
   * Exports the current diagram to the given exporter.
   *
   * @param aExporter the exporter to export to, cannot be <code>null</code>.
   * @param aOutputStream the output stream to write the export to, cannot be <code>null</code>.
   * @throws IOException in case of I/O problems.
   */
  public void exportTo(final Exporter aExporter, final OutputStream aOutputStream)
      throws IOException {
    if (this.mainFrame != null) {
      aExporter.export(this.dataContainer, this.mainFrame.getDiagramScrollPane(), aOutputStream);
    }
  }

  /** @see nl.lxtreme.ols.client.ActionProvider#getAction(java.lang.String) */
  public Action getAction(final String aID) {
    return this.actionManager.getAction(aID);
  }

  /** @return the dataContainer */
  public DataContainer getDataContainer() {
    return this.dataContainer;
  }

  /**
   * Returns the current device controller.
   *
   * @return the current device controller, can be <code>null</code>.
   */
  public DeviceController getDeviceController() {
    return this.currentDevCtrl;
  }

  /**
   * Returns all current tools known to the OSGi framework.
   *
   * @return a collection of tools, never <code>null</code>.
   */
  public final Collection<DeviceController> getDevices() {
    final List<DeviceController> tools = new ArrayList<DeviceController>();
    synchronized (this.bundleContext) {
      try {
        final ServiceReference[] serviceRefs =
            this.bundleContext.getAllServiceReferences(DeviceController.class.getName(), null);
        for (ServiceReference serviceRef : serviceRefs) {
          tools.add((DeviceController) this.bundleContext.getService(serviceRef));
        }
      } catch (InvalidSyntaxException exception) {
        throw new RuntimeException(exception);
      }
    }
    return tools;
  }

  /**
   * Returns the exporter with the given name.
   *
   * @param aName the name of the exporter to return, cannot be <code>null</code>.
   * @return the exporter with the given name, can be <code>null</code> if no such exporter is
   *     found.
   * @throws IllegalArgumentException in case the given name was <code>null</code> or empty.
   */
  public Exporter getExporter(final String aName) throws IllegalArgumentException {
    if ((aName == null) || aName.trim().isEmpty()) {
      throw new IllegalArgumentException("Name cannot be null or empty!");
    }

    try {
      final ServiceReference[] serviceRefs =
          this.bundleContext.getAllServiceReferences(Exporter.class.getName(), null);
      final int count = (serviceRefs == null) ? 0 : serviceRefs.length;

      for (int i = 0; i < count; i++) {
        final Exporter exporter = (Exporter) this.bundleContext.getService(serviceRefs[i]);

        if (aName.equals(exporter.getName())) {
          return exporter;
        }
      }

      return null;
    } catch (InvalidSyntaxException exception) {
      throw new RuntimeException("getExporter failed!", exception);
    }
  }

  /**
   * Returns the names of all current available exporters.
   *
   * @return an array of exporter names, never <code>null</code>, but can be empty.
   */
  public String[] getExporterNames() {
    try {
      final ServiceReference[] serviceRefs =
          this.bundleContext.getAllServiceReferences(Exporter.class.getName(), null);
      final int count = serviceRefs == null ? 0 : serviceRefs.length;

      final String[] result = new String[count];

      for (int i = 0; i < count; i++) {
        final Exporter exporter = (Exporter) this.bundleContext.getService(serviceRefs[i]);

        result[i] = exporter.getName();
        this.bundleContext.ungetService(serviceRefs[i]);
      }

      return result;
    } catch (InvalidSyntaxException exception) {
      throw new RuntimeException("getAllExporterNames failed!", exception);
    }
  }

  /**
   * Returns the current project's filename.
   *
   * @return a project filename, as file object, can be <code>null</code>.
   */
  public File getProjectFilename() {
    return this.projectManager.getCurrentProject().getFilename();
  }

  /**
   * Returns all current tools known to the OSGi framework.
   *
   * @return a collection of tools, never <code>null</code>.
   */
  public final Collection<Tool> getTools() {
    final List<Tool> tools = new ArrayList<Tool>();
    synchronized (this.bundleContext) {
      try {
        final ServiceReference[] serviceRefs =
            this.bundleContext.getAllServiceReferences(Tool.class.getName(), null);
        for (ServiceReference serviceRef : serviceRefs) {
          tools.add((Tool) this.bundleContext.getService(serviceRef));
        }
      } catch (InvalidSyntaxException exception) {
        throw new RuntimeException(exception);
      }
    }
    return tools;
  }

  /**
   * Goes to the current cursor position of the cursor with the given index.
   *
   * @param aCursorIdx the index of the cursor to go to, >= 0 && < 10.
   */
  public void gotoCursorPosition(final int aCursorIdx) {
    if ((this.mainFrame != null) && this.dataContainer.isCursorsEnabled()) {
      final Long cursorPosition = this.dataContainer.getCursorPosition(aCursorIdx);
      if (cursorPosition != null) {
        this.mainFrame.gotoPosition(cursorPosition.longValue());
      }
    }
  }

  /** Goes to the current cursor position of the first available cursor. */
  public void gotoFirstAvailableCursor() {
    if ((this.mainFrame != null) && this.dataContainer.isCursorsEnabled()) {
      for (int c = 0; c < CapturedData.MAX_CURSORS; c++) {
        if (this.dataContainer.isCursorPositionSet(c)) {
          final Long cursorPosition = this.dataContainer.getCursorPosition(c);
          if (cursorPosition != null) {
            this.mainFrame.gotoPosition(cursorPosition.longValue());
          }
          break;
        }
      }
    }
  }

  /** Goes to the current cursor position of the last available cursor. */
  public void gotoLastAvailableCursor() {
    if ((this.mainFrame != null) && this.dataContainer.isCursorsEnabled()) {
      for (int c = CapturedData.MAX_CURSORS - 1; c >= 0; c--) {
        if (this.dataContainer.isCursorPositionSet(c)) {
          final Long cursorPosition = this.dataContainer.getCursorPosition(c);
          if (cursorPosition != null) {
            this.mainFrame.gotoPosition(cursorPosition.longValue());
          }
          break;
        }
      }
    }
  }

  /** Goes to the position of the trigger. */
  public void gotoTriggerPosition() {
    if ((this.mainFrame != null) && this.dataContainer.hasTriggerData()) {
      final long position = this.dataContainer.getTriggerPosition();
      this.mainFrame.gotoPosition(position);
    }
  }

  /**
   * Returns whether there is a device selected or not.
   *
   * @return <code>true</code> if there is a device selected, <code>false</code> if no device is
   *     selected.
   */
  public synchronized boolean isDeviceSelected() {
    return this.currentDevCtrl != null;
  }

  /**
   * Returns whether the current device is setup at least once.
   *
   * @return <code>true</code> if the current device is setup, <code>false</code> otherwise.
   * @see #isDeviceSelected()
   */
  public synchronized boolean isDeviceSetup() {
    return (this.currentDevCtrl != null) && this.currentDevCtrl.isSetup();
  }

  /**
   * Returns whether or not the current project is changed.
   *
   * @return <code>true</code> if the current project is changed, <code>false</code> if the current
   *     project is not changed.
   */
  public boolean isProjectChanged() {
    return this.projectManager.getCurrentProject().isChanged();
  }

  /**
   * Loads an OLS data file from the given file.
   *
   * @param aFile the file to load as OLS data, cannot be <code>null</code>.
   * @throws IOException in case of I/O problems.
   */
  public void openDataFile(final File aFile) throws IOException {
    final FileReader reader = new FileReader(aFile);

    try {
      final Project tempProject = this.projectManager.createTemporaryProject();
      OlsDataHelper.read(tempProject, reader);

      setChannelLabels(tempProject.getChannelLabels());
      setCapturedData(tempProject.getCapturedData());
      setCursorData(tempProject.getCursorPositions(), tempProject.isCursorsEnabled());
    } finally {
      reader.close();

      zoomToFit();

      updateActions();
    }
  }

  /**
   * Opens the project denoted by the given file.
   *
   * @param aFile the project file to open, cannot be <code>null</code>.
   * @throws IOException in case of I/O problems.
   */
  public void openProjectFile(final File aFile) throws IOException {
    FileInputStream fis = new FileInputStream(aFile);

    this.projectManager.loadProject(fis);

    final Project project = this.projectManager.getCurrentProject();
    project.setFilename(aFile);

    zoomToFit();
  }

  /**
   * Removes the cursor denoted by the given cursor index.
   *
   * @param aCursorIdx the index of the cursor to remove, >= 0 && < 10.
   */
  public void removeCursor(final int aCursorIdx) {
    if (this.mainFrame != null) {
      this.dataContainer.setCursorPosition(aCursorIdx, null);
      fireCursorChangedEvent(aCursorIdx, -1); // removed...
    }

    updateActions();
  }

  /**
   * Removes a cursor change listener.
   *
   * @param aListener the listener to remove, cannot be <code>null</code>.
   */
  public void removeCursorChangeListener(final DiagramCursorChangeListener aListener) {
    this.evenListeners.remove(DiagramCursorChangeListener.class, aListener);
  }

  /**
   * Removes the given device from the list of devices.
   *
   * @param aDeviceController the device to remove, cannot be <code>null</code>.
   */
  public void removeDevice(final DeviceController aDeviceController) {
    if (this.currentDevCtrl == aDeviceController) {
      this.currentDevCtrl = null;
    }

    if (this.mainFrame != null) {
      this.mainFrame.removeDeviceMenuItem(aDeviceController.getName());
    }

    updateActions();
  }

  /**
   * Removes the given exporter from the list of exporters.
   *
   * @param aExporter the exporter to remove, cannot be <code>null</code>.
   */
  public void removeExporter(final Exporter aExporter) {
    if (this.mainFrame != null) {
      this.mainFrame.removeExportMenuItem(aExporter.getName());
    }

    updateActions();
  }

  /**
   * Removes the given tool from the list of tools.
   *
   * @param aTool the tool to remove, cannot be <code>null</code>.
   */
  public void removeTool(final Tool aTool) {
    if (this.mainFrame != null) {
      this.mainFrame.removeToolMenuItem(aTool.getName());
    }

    updateActions();
  }

  /**
   * Repeats the capture with the current settings.
   *
   * @param aParent the parent window to use, can be <code>null</code>.
   */
  public boolean repeatCaptureData(final Window aParent) {
    final DeviceController devCtrl = getDeviceController();
    if (devCtrl == null) {
      return false;
    }

    try {
      setStatus(
          "Capture from {0} started at {1,date,medium} {1,time,medium} ...",
          devCtrl.getName(), new Date());

      devCtrl.captureData(this);

      return true;
    } catch (IOException exception) {
      captureAborted("I/O problem: " + exception.getMessage());

      exception.printStackTrace();

      // Make sure to handle IO-interrupted exceptions properly!
      HostUtils.handleInterruptedException(exception);

      return false;
    } finally {
      updateActions();
    }
  }

  /**
   * Runs the tool denoted by the given name.
   *
   * @param aToolName the name of the tool to run, cannot be <code>null</code>;
   * @param aParent the parent window to use, can be <code>null</code>.
   */
  public void runTool(final String aToolName, final Window aParent) {
    if (LOG.isLoggable(Level.INFO)) {
      LOG.log(Level.INFO, "Running tool: \"{0}\" ...", aToolName);
    }

    final Tool tool = findToolByName(aToolName);
    if (tool == null) {
      JOptionPane.showMessageDialog(
          aParent, "No such tool found: " + aToolName, "Error ...", JOptionPane.ERROR_MESSAGE);
    } else {
      final ToolContext context = createToolContext();
      tool.process(aParent, this.dataContainer, context, this);
    }

    updateActions();
  }

  /** @see nl.lxtreme.ols.api.devices.CaptureCallback#samplesCaptured(java.util.List) */
  @Override
  public void samplesCaptured(final List<Sample> aSamples) {
    if (this.mainFrame != null) {
      this.mainFrame.sampleCaptured(aSamples);
    }
    updateActions();
  }

  /**
   * Saves an OLS data file to the given file.
   *
   * @param aFile the file to save the OLS data to, cannot be <code>null</code>.
   * @throws IOException in case of I/O problems.
   */
  public void saveDataFile(final File aFile) throws IOException {
    final FileWriter writer = new FileWriter(aFile);
    try {
      final Project tempProject = this.projectManager.createTemporaryProject();
      tempProject.setCapturedData(this.dataContainer);

      OlsDataHelper.write(tempProject, writer);
    } finally {
      writer.flush();
      writer.close();
    }
  }

  /**
   * Saves the current project to the given file.
   *
   * @param aFile the file to save the project information to, cannot be <code>null</code>.
   * @throws IOException in case of I/O problems.
   */
  public void saveProjectFile(final String aName, final File aFile) throws IOException {
    FileOutputStream out = null;
    try {
      final Project project = this.projectManager.getCurrentProject();
      project.setFilename(aFile);
      project.setName(aName);

      out = new FileOutputStream(aFile);
      this.projectManager.saveProject(out);
    } finally {
      HostUtils.closeResource(out);
    }
  }

  /**
   * Sets whether or not cursors are enabled.
   *
   * @param aState <code>true</code> if the cursors should be enabled, <code>false</code> otherwise.
   */
  public void setCursorMode(final boolean aState) {
    this.dataContainer.setCursorEnabled(aState);
    // Reflect the change directly on the diagram...
    repaintMainFrame();

    updateActions();
  }

  /**
   * Sets the cursor position of the cursor with the given index.
   *
   * @param aCursorIdx the index of the cursor to set, >= 0 && < 10;
   * @param aLocation the mouse location on screen where the cursor should become, cannot be <code>
   *     null</code>.
   */
  public void setCursorPosition(final int aCursorIdx, final Point aLocation) {
    // Implicitly enable cursor mode, the user already had made its
    // intensions clear that he want to have this by opening up the
    // context menu anyway...
    setCursorMode(true);

    if (this.mainFrame != null) {
      // Convert the mouse-position to a sample index...
      final long sampleIdx = this.mainFrame.convertMousePositionToSampleIndex(aLocation);

      this.dataContainer.setCursorPosition(aCursorIdx, Long.valueOf(sampleIdx));

      fireCursorChangedEvent(aCursorIdx, aLocation.x);
    }

    updateActions();
  }

  /**
   * Sets the current device controller to the given value.
   *
   * @param aDeviceName the name of the device controller to set, cannot be <code>null</code>.
   */
  public synchronized void setDeviceController(final String aDeviceName) {
    if (LOG.isLoggable(Level.INFO)) {
      final String name = (aDeviceName == null) ? "no device" : aDeviceName;
      LOG.log(Level.INFO, "Setting current device controller to: \"{0}\" ...", name);
    }

    final Collection<DeviceController> devices = getDevices();
    for (DeviceController device : devices) {
      if (aDeviceName.equals(device.getName())) {
        this.currentDevCtrl = device;
      }
    }

    updateActions();
  }

  /** @param aMainFrame the mainFrame to set */
  public void setMainFrame(final MainFrame aMainFrame) {
    if (this.mainFrame != null) {
      this.projectManager.removePropertyChangeListener(this.mainFrame);
    }
    if (aMainFrame != null) {
      this.projectManager.addPropertyChangeListener(aMainFrame);
    }

    this.mainFrame = aMainFrame;
  }

  /**
   * Sets a status message.
   *
   * @param aMessage the message to set;
   * @param aMessageArgs the (optional) message arguments.
   */
  public final void setStatus(final String aMessage, final Object... aMessageArgs) {
    if (this.mainFrame != null) {
      this.mainFrame.setStatus(aMessage, aMessageArgs);
    }
  }

  /** Shows the "about OLS" dialog on screen. the parent window to use, can be <code>null</code>. */
  public void showAboutBox() {
    MainFrame.showAboutBox(this.host.getVersion());
  }

  /**
   * Shows a dialog with all running OSGi bundles.
   *
   * @param aOwner the owning window to use, can be <code>null</code>.
   */
  public void showBundlesDialog(final Window aOwner) {
    BundlesDialog dialog = new BundlesDialog(aOwner, this.bundleContext);
    if (dialog.showDialog()) {
      dialog.dispose();
      dialog = null;
    }
  }

  /**
   * Shows the label-editor dialog on screen.
   *
   * <p>Display the diagram labels dialog. Will block until the dialog is closed again.
   *
   * @param aParent the parent window to use, can be <code>null</code>.
   */
  public void showLabelsDialog(final Window aParent) {
    if (this.mainFrame != null) {
      DiagramLabelsDialog dialog =
          new DiagramLabelsDialog(aParent, this.dataContainer.getChannelLabels());
      if (dialog.showDialog()) {
        final String[] channelLabels = dialog.getChannelLabels();
        setChannelLabels(channelLabels);
      }

      dialog.dispose();
      dialog = null;
    }
  }

  /**
   * Shows the settings-editor dialog on screen.
   *
   * <p>Display the diagram settings dialog. Will block until the dialog is closed again.
   *
   * @param aParent the parent window to use, can be <code>null</code>.
   */
  public void showModeSettingsDialog(final Window aParent) {
    if (this.mainFrame != null) {
      ModeSettingsDialog dialog = new ModeSettingsDialog(aParent, getDiagramSettings());
      if (dialog.showDialog()) {
        updateDiagramSettings(dialog.getDiagramSettings());
      }

      dialog.dispose();
      dialog = null;
    }
  }

  /** @param aOwner */
  public void showPreferencesDialog(final Window aParent) {
    GeneralSettingsDialog dialog = new GeneralSettingsDialog(aParent, getDiagramSettings());
    if (dialog.showDialog()) {
      updateDiagramSettings(dialog.getDiagramSettings());
    }

    dialog.dispose();
    dialog = null;
  }

  /** @see nl.lxtreme.ols.api.ProgressCallback#updateProgress(int) */
  @Override
  public void updateProgress(final int aPercentage) {
    if (this.mainFrame != null) {
      this.mainFrame.setProgress(aPercentage);
    }
  }

  /** Zooms in to the maximum zoom level. */
  public void zoomDefault() {
    if (this.mainFrame != null) {
      this.mainFrame.zoomDefault();
    }

    updateActions();
  }

  /** Zooms in with a factor of 2.0. */
  public void zoomIn() {
    if (this.mainFrame != null) {
      this.mainFrame.zoomIn();
    }

    updateActions();
  }

  /** Zooms out with a factor of 2.0. */
  public void zoomOut() {
    if (this.mainFrame != null) {
      this.mainFrame.zoomOut();
    }

    updateActions();
  }

  /** Zooms to fit the diagram to the current window dimensions. */
  public void zoomToFit() {
    if (this.mainFrame != null) {
      this.mainFrame.zoomToFit();
    }

    updateActions();
  }

  /**
   * Returns the current main frame.
   *
   * @return the main frame, can be <code>null</code>.
   */
  final MainFrame getMainFrame() {
    return this.mainFrame;
  }

  /**
   * Creates the tool context denoting the range of samples that should be analysed by a tool.
   *
   * @return a tool context, never <code>null</code>.
   */
  private ToolContext createToolContext() {
    int startOfDecode = -1;
    int endOfDecode = -1;

    final int dataLength = this.dataContainer.getValues().length;
    if (this.dataContainer.isCursorsEnabled()) {
      if (this.dataContainer.isCursorPositionSet(0)) {
        final Long cursor1 = this.dataContainer.getCursorPosition(0);
        startOfDecode = this.dataContainer.getSampleIndex(cursor1.longValue()) - 1;
      }
      if (this.dataContainer.isCursorPositionSet(1)) {
        final Long cursor2 = this.dataContainer.getCursorPosition(1);
        endOfDecode = this.dataContainer.getSampleIndex(cursor2.longValue()) + 1;
      }
    } else {
      startOfDecode = 0;
      endOfDecode = dataLength;
    }

    startOfDecode = Math.max(0, startOfDecode);
    if ((endOfDecode < 0) || (endOfDecode >= dataLength)) {
      endOfDecode = dataLength - 1;
    }

    return new DefaultToolContext(startOfDecode, endOfDecode);
  }

  /** @param aActionManager */
  private void fillActionManager(final ActionManager aActionManager) {
    aActionManager.add(new NewProjectAction(this));
    aActionManager.add(new OpenProjectAction(this));
    aActionManager.add(new SaveProjectAction(this)).setEnabled(false);
    aActionManager.add(new SaveProjectAsAction(this)).setEnabled(false);
    aActionManager.add(new OpenDataFileAction(this));
    aActionManager.add(new SaveDataFileAction(this)).setEnabled(false);
    aActionManager.add(new ExitAction(this));

    aActionManager.add(new CaptureAction(this));
    aActionManager.add(new CancelCaptureAction(this)).setEnabled(false);
    aActionManager.add(new RepeatCaptureAction(this)).setEnabled(false);

    aActionManager.add(new ZoomInAction(this)).setEnabled(false);
    aActionManager.add(new ZoomOutAction(this)).setEnabled(false);
    aActionManager.add(new ZoomDefaultAction(this)).setEnabled(false);
    aActionManager.add(new ZoomFitAction(this)).setEnabled(false);

    aActionManager.add(new GotoTriggerAction(this)).setEnabled(false);
    for (int c = 0; c < CapturedData.MAX_CURSORS; c++) {
      aActionManager.add(new GotoNthCursorAction(this, c)).setEnabled(false);
    }
    aActionManager.add(new GotoFirstCursorAction(this)).setEnabled(false);
    aActionManager.add(new GotoLastCursorAction(this)).setEnabled(false);
    aActionManager.add(new ClearCursors(this)).setEnabled(false);
    aActionManager.add(new SetCursorModeAction(this));
    for (int c = 0; c < CapturedData.MAX_CURSORS; c++) {
      aActionManager.add(new SetCursorAction(this, c));
    }

    aActionManager.add(new ShowGeneralSettingsAction(this));
    aActionManager.add(new ShowModeSettingsAction(this));
    aActionManager.add(new ShowDiagramLabelsAction(this));

    aActionManager.add(new HelpAboutAction(this));
    aActionManager.add(new ShowBundlesAction(this));
  }

  /**
   * Searches for the tool with the given name.
   *
   * @param aToolName the name of the tool to search for, cannot be <code>null</code>.
   * @return the tool with the given name, can be <code>null</code> if no such tool can be found.
   */
  private Tool findToolByName(final String aToolName) {
    Tool tool = null;

    final Collection<Tool> tools = getTools();
    for (Tool _tool : tools) {
      if (aToolName.equals(_tool.getName())) {
        tool = _tool;
        break;
      }
    }
    return tool;
  }

  /**
   * @param aCursorIdx
   * @param aMouseXpos
   */
  private void fireCursorChangedEvent(final int aCursorIdx, final int aMouseXpos) {
    final DiagramCursorChangeListener[] listeners =
        this.evenListeners.getListeners(DiagramCursorChangeListener.class);
    for (final DiagramCursorChangeListener listener : listeners) {
      if (aMouseXpos >= 0) {
        listener.cursorChanged(aCursorIdx, aMouseXpos);
      } else {
        listener.cursorRemoved(aCursorIdx);
      }
    }
  }

  /**
   * Returns the current diagram settings.
   *
   * @return the current diagram settings, can be <code>null</code> if there is no main frame to
   *     take the settings from.
   */
  private DiagramSettings getDiagramSettings() {
    return this.mainFrame != null ? this.mainFrame.getDiagramSettings() : null;
  }

  /** Dispatches a request to repaint the entire main frame. */
  private void repaintMainFrame() {
    SwingUtilities.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            ClientController.this.mainFrame.repaint();
          }
        });
  }

  /**
   * Sets the captured data and zooms the view to show all the data.
   *
   * @param aCapturedData the new captured data to set, cannot be <code>null</code>.
   */
  private void setCapturedData(final CapturedData aCapturedData) {
    this.dataContainer.setCapturedData(aCapturedData);

    if (this.mainFrame != null) {
      this.mainFrame.zoomToFit();
    }
  }

  /**
   * Set the channel labels.
   *
   * @param aChannelLabels the channel labels to set, cannot be <code>null</code>.
   */
  private void setChannelLabels(final String[] aChannelLabels) {
    if (aChannelLabels != null) {
      this.dataContainer.setChannelLabels(aChannelLabels);
      this.mainFrame.setChannelLabels(aChannelLabels);
    }
  }

  /**
   * @param aCursorData the cursor positions to set, cannot be <code>null</code>;
   * @param aCursorsEnabled <code>true</code> if cursors should be enabled, <code>false</code> if
   *     they should be disabled.
   */
  private void setCursorData(final Long[] aCursorData, final boolean aCursorsEnabled) {
    this.dataContainer.setCursorEnabled(aCursorsEnabled);
    for (int i = 0; i < CapturedData.MAX_CURSORS; i++) {
      this.dataContainer.setCursorPosition(i, aCursorData[i]);
    }
  }

  /** Synchronizes the state of the actions to the current state of this host. */
  private void updateActions() {
    final DeviceController currentDeviceController = getDeviceController();

    final boolean deviceControllerSet = currentDeviceController != null;
    final boolean deviceCapturing = deviceControllerSet && currentDeviceController.isCapturing();
    final boolean deviceSetup =
        deviceControllerSet && !deviceCapturing && currentDeviceController.isSetup();

    getAction(CaptureAction.ID).setEnabled(deviceControllerSet);
    getAction(CancelCaptureAction.ID).setEnabled(deviceCapturing);
    getAction(RepeatCaptureAction.ID).setEnabled(deviceSetup);

    final boolean projectChanged = this.projectManager.getCurrentProject().isChanged();
    final boolean projectSavedBefore =
        this.projectManager.getCurrentProject().getFilename() != null;
    final boolean dataAvailable = this.dataContainer.hasCapturedData();

    getAction(SaveProjectAction.ID).setEnabled(projectChanged);
    getAction(SaveProjectAsAction.ID).setEnabled(projectSavedBefore && projectChanged);
    getAction(SaveDataFileAction.ID).setEnabled(dataAvailable);

    getAction(ZoomInAction.ID).setEnabled(dataAvailable);
    getAction(ZoomOutAction.ID).setEnabled(dataAvailable);
    getAction(ZoomDefaultAction.ID).setEnabled(dataAvailable);
    getAction(ZoomFitAction.ID).setEnabled(dataAvailable);

    final boolean triggerEnable = dataAvailable && this.dataContainer.hasTriggerData();
    getAction(GotoTriggerAction.ID).setEnabled(triggerEnable);

    // Update the cursor actions accordingly...
    final boolean enableCursors = dataAvailable && this.dataContainer.isCursorsEnabled();

    for (int c = 0; c < CapturedData.MAX_CURSORS; c++) {
      final boolean enabled = enableCursors && this.dataContainer.isCursorPositionSet(c);
      getAction(GotoNthCursorAction.getID(c)).setEnabled(enabled);
    }

    getAction(GotoFirstCursorAction.ID).setEnabled(enableCursors);
    getAction(GotoLastCursorAction.ID).setEnabled(enableCursors);

    getAction(SetCursorModeAction.ID).setEnabled(dataAvailable);
    getAction(SetCursorModeAction.ID)
        .putValue(Action.SELECTED_KEY, Boolean.valueOf(this.dataContainer.isCursorsEnabled()));

    boolean anyCursorSet = false;
    for (int c = 0; c < CapturedData.MAX_CURSORS; c++) {
      final boolean cursorPositionSet = this.dataContainer.isCursorPositionSet(c);
      anyCursorSet |= cursorPositionSet;

      final Action action = getAction(SetCursorAction.getCursorId(c));
      action.setEnabled(dataAvailable);
      action.putValue(Action.SELECTED_KEY, Boolean.valueOf(cursorPositionSet));
    }

    getAction(ClearCursors.ID).setEnabled(enableCursors && anyCursorSet);
  }

  /**
   * Should be called after the diagram settings are changed. This method will cause the settings to
   * be set on the main frame and writes them to the preference store.
   *
   * @param aSettings the (new/changed) diagram settings to set, cannot be <code>null</code>.
   */
  private void updateDiagramSettings(final DiagramSettings aSettings) {
    if (this.mainFrame != null) {
      this.mainFrame.setDiagramSettings(aSettings);
      repaintMainFrame();
    }
  }
}
Exemple #20
0
/** A Swing frame that can be used to test the Cobra HTML rendering engine. */
public class TestFrame extends JFrame {
  private static final Logger logger = Logger.getLogger(TestFrame.class.getName());
  private final SimpleHtmlRendererContext rcontext;
  private final JTree tree;
  private final HtmlPanel htmlPanel;
  private final JTextArea textArea;
  private final JTextField addressField;

  public TestFrame() throws HeadlessException {
    this("");
  }

  public TestFrame(String title) throws HeadlessException {
    super(title);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container contentPane = this.getContentPane();
    contentPane.setLayout(new BorderLayout());
    JPanel topPanel = new JPanel();
    topPanel.setLayout(new BorderLayout());
    JPanel bottomPanel = new JPanel();
    bottomPanel.setLayout(new BorderLayout());
    final JTextField textField = new JTextField();
    this.addressField = textField;
    JButton button = new JButton("Parse & Render");
    final JTabbedPane tabbedPane = new JTabbedPane();
    final JTree tree = new JTree();
    final JScrollPane scrollPane = new JScrollPane(tree);

    this.tree = tree;

    contentPane.add(topPanel, BorderLayout.NORTH);
    contentPane.add(bottomPanel, BorderLayout.CENTER);

    topPanel.add(new JLabel("URL: "), BorderLayout.WEST);
    topPanel.add(textField, BorderLayout.CENTER);
    topPanel.add(button, BorderLayout.EAST);

    bottomPanel.add(tabbedPane, BorderLayout.CENTER);

    final HtmlPanel panel = new HtmlPanel();
    panel.addSelectionChangeListener(
        new SelectionChangeListener() {
          public void selectionChanged(SelectionChangeEvent event) {
            if (logger.isLoggable(Level.INFO)) {
              logger.info("selectionChanged(): selection node: " + panel.getSelectionNode());
            }
          }
        });
    this.htmlPanel = panel;
    UserAgentContext ucontext = new SimpleUserAgentContext();
    this.rcontext = new LocalHtmlRendererContext(panel, ucontext);

    final JTextArea textArea = new JTextArea();
    this.textArea = textArea;
    textArea.setEditable(false);
    final JScrollPane textAreaSp = new JScrollPane(textArea);

    tabbedPane.addTab("HTML", panel);
    tabbedPane.addTab("Tree", scrollPane);
    tabbedPane.addTab("Source", textAreaSp);
    tabbedPane.addChangeListener(
        new ChangeListener() {
          public void stateChanged(ChangeEvent e) {
            Component component = tabbedPane.getSelectedComponent();
            if (component == scrollPane) {
              tree.setModel(new NodeTreeModel(panel.getRootNode()));
            } else if (component == textAreaSp) {
              textArea.setText(rcontext.getSourceCode());
            }
          }
        });

    button.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            process(textField.getText());
          }
        });
  }

  public HtmlRendererContext getHtmlRendererContext() {
    return this.rcontext;
  }

  public void navigate(String uri) {
    this.addressField.setText(uri);
    this.process(uri);
  }

  // /home/jean/Área de Trabalho/Link para Dropbox/workspace/GSPAnalyzer/grails app
  // examples/rgms-master/grails-app/views/bookChapter/show.gsp
  private void process(String uri) {
    try {
      URL url;
      try {
        url = new URL(uri);
      } catch (java.net.MalformedURLException mfu) {
        int idx = uri.indexOf(':');
        if (idx == -1 || idx == 1) {
          // try file
          url = new URL("file:" + uri);
        } else {
          throw mfu;
        }
      }
      // Call SimpleHtmlRendererContext.navigate()
      // which implements incremental rendering.
      this.rcontext.navigate(url, null);
    } catch (Exception err) {
      logger.log(Level.SEVERE, "Error trying to load URI=[" + uri + "].", err);
    }
  }

  private class LocalHtmlRendererContext extends SimpleHtmlRendererContext {
    public LocalHtmlRendererContext(HtmlPanel contextComponent, UserAgentContext ucontext) {
      super(contextComponent, ucontext);
    }

    public HtmlRendererContext open(
        URL url, String windowName, String windowFeatures, boolean replace) {
      TestFrame frame = new TestFrame("Cobra Test Tool");
      frame.setSize(600, 400);
      frame.setExtendedState(TestFrame.NORMAL);
      frame.setVisible(true);
      HtmlRendererContext ctx = frame.getHtmlRendererContext();
      ctx.setOpener(this);
      frame.navigate(url.toExternalForm());
      return ctx;
    }
  }
}
  public QSAdminGUI(QSAdminMain qsadminMain, JFrame parentFrame) {
    this.parentFrame = parentFrame;
    Container cp = this;
    qsadminMain.setGUI(this);
    cp.setLayout(new BorderLayout(5, 5));
    headerPanel = new HeaderPanel(qsadminMain, parentFrame);
    mainCommandPanel = new MainCommandPanel(qsadminMain);
    cmdConsole = new CmdConsole(qsadminMain);
    propertiePanel = new PropertiePanel(qsadminMain);

    if (headerPanel == null
        || mainCommandPanel == null
        || cmdConsole == null
        || propertiePanel == null) {
      throw new RuntimeException("Loading of one of gui component failed.");
    }

    headerPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
    cp.add(headerPanel, BorderLayout.NORTH);
    JScrollPane propertieScrollPane = new JScrollPane(propertiePanel);
    // JScrollPane commandScrollPane = new JScrollPane(mainCommandPanel);
    JSplitPane splitPane =
        new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, mainCommandPanel, cmdConsole);
    splitPane.setOneTouchExpandable(false);
    splitPane.setDividerLocation(250);
    // splitPane.setDividerLocation(0.70);

    tabbedPane = new JTabbedPane(JTabbedPane.TOP);
    tabbedPane.addTab("Main", ball, splitPane, "Main Commands");
    tabbedPane.addTab("Get/Set", ball, propertieScrollPane, "Properties Panel");

    QSAdminPluginConfig qsAdminPluginConfig = null;
    PluginPanel pluginPanel = null;
    // -- start of loadPlugins
    try {
      File xmlFile = null;
      ClassLoader classLoader = null;
      Class mainClass = null;

      File file = new File(pluginDir);
      File dirs[] = null;

      if (file.canRead()) dirs = file.listFiles(new DirFileList());

      for (int i = 0; dirs != null && i < dirs.length; i++) {
        xmlFile = new File(dirs[i].getAbsolutePath() + File.separator + "plugin.xml");
        if (xmlFile.canRead()) {
          qsAdminPluginConfig = PluginConfigReader.read(xmlFile);
          if (qsAdminPluginConfig.getActive().equals("yes")
              && qsAdminPluginConfig.getType().equals("javax.swing.JPanel")) {
            classLoader = ClassUtil.getClassLoaderFromJars(dirs[i].getAbsolutePath());
            mainClass = classLoader.loadClass(qsAdminPluginConfig.getMainClass());
            logger.fine("Got PluginMainClass " + mainClass);
            pluginPanel = (PluginPanel) mainClass.newInstance();
            if (JPanel.class.isInstance(pluginPanel) == true) {
              logger.info("Loading plugin : " + qsAdminPluginConfig.getName());
              pluginPanelMap.put("" + (2 + i), pluginPanel);
              plugins.add(pluginPanel);
              tabbedPane.addTab(
                  qsAdminPluginConfig.getName(),
                  ball,
                  (JPanel) pluginPanel,
                  qsAdminPluginConfig.getDesc());
              pluginPanel.setQSAdminMain(qsadminMain);
              pluginPanel.init();
            }
          } else {
            logger.info(
                "Plugin "
                    + dirs[i]
                    + " is disabled so skipping "
                    + qsAdminPluginConfig.getActive()
                    + ":"
                    + qsAdminPluginConfig.getType());
          }
        } else {
          logger.info("No plugin configuration found in " + xmlFile + " so skipping");
        }
      }
    } catch (Exception e) {
      logger.warning("Error loading plugin : " + e);
      logger.fine("StackTrace:\n" + MyString.getStackTrace(e));
    }
    // -- end of loadPlugins

    tabbedPane.addChangeListener(
        new ChangeListener() {
          int selected = -1;
          int oldSelected = -1;

          public void stateChanged(ChangeEvent e) {
            // if plugin
            selected = tabbedPane.getSelectedIndex();
            if (selected >= 2) {
              ((PluginPanel) pluginPanelMap.get("" + selected)).activated();
            }
            if (oldSelected >= 2) {
              ((PluginPanel) pluginPanelMap.get("" + oldSelected)).deactivated();
            }
            oldSelected = selected;
          }
        });

    // tabbedPane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    cp.add(tabbedPane, BorderLayout.CENTER);

    buildMenu();
  }
 /** Logs the interaction, Type can be S - Server Sent C - Client Sent */
 public void logComand(String command, char type) {
   logger.info("For[" + type + "] " + command);
 }
/**
 * The advanced configuration panel.
 *
 * @author Yana Stamcheva
 */
public class AdvancedConfigurationPanel extends TransparentPanel
    implements ConfigurationForm, ConfigurationContainer, ServiceListener, ListSelectionListener {
  /** Serial version UID. */
  private static final long serialVersionUID = 0L;

  /** The <tt>Logger</tt> used by this <tt>AdvancedConfigurationPanel</tt> for logging output. */
  private final Logger logger = Logger.getLogger(AdvancedConfigurationPanel.class);

  /** The configuration list. */
  private final JList configList = new JList();

  /** The center panel. */
  private final JPanel centerPanel = new TransparentPanel(new BorderLayout());

  /** Creates an instance of the <tt>AdvancedConfigurationPanel</tt>. */
  public AdvancedConfigurationPanel() {
    super(new BorderLayout(10, 0));

    initList();

    centerPanel.setPreferredSize(new Dimension(500, 500));

    add(centerPanel, BorderLayout.CENTER);
  }

  /** Initializes the config list. */
  private void initList() {
    configList.setModel(new DefaultListModel());
    configList.setCellRenderer(new ConfigListCellRenderer());
    configList.addListSelectionListener(this);
    configList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    JScrollPane configScrollList = new JScrollPane();

    configScrollList.getVerticalScrollBar().setUnitIncrement(30);

    configScrollList.getViewport().add(configList);

    add(configScrollList, BorderLayout.WEST);

    String osgiFilter =
        "(" + ConfigurationForm.FORM_TYPE + "=" + ConfigurationForm.ADVANCED_TYPE + ")";
    ServiceReference[] confFormsRefs = null;
    try {
      confFormsRefs =
          AdvancedConfigActivator.bundleContext.getServiceReferences(
              ConfigurationForm.class.getName(), osgiFilter);
    } catch (InvalidSyntaxException ex) {
    }

    if (confFormsRefs != null) {
      for (int i = 0; i < confFormsRefs.length; i++) {
        ConfigurationForm form =
            (ConfigurationForm) AdvancedConfigActivator.bundleContext.getService(confFormsRefs[i]);

        if (form.isAdvanced()) this.addConfigForm(form);
      }
    }
  }

  /**
   * Shows on the right the configuration form given by the given <tt>ConfigFormDescriptor</tt>.
   *
   * @param configForm the configuration form to show
   */
  private void showFormContent(ConfigurationForm configForm) {
    this.centerPanel.removeAll();

    JComponent configFormPanel = (JComponent) configForm.getForm();

    configFormPanel.setOpaque(false);

    this.centerPanel.add(configFormPanel, BorderLayout.CENTER);

    this.centerPanel.revalidate();
    this.centerPanel.repaint();
  }

  /**
   * Handles registration of a new configuration form.
   *
   * @param event the <tt>ServiceEvent</tt> that notified us
   */
  public void serviceChanged(ServiceEvent event) {
    Object sService = AdvancedConfigActivator.bundleContext.getService(event.getServiceReference());

    // we don't care if the source service is not a configuration form
    if (!(sService instanceof ConfigurationForm)) return;

    ConfigurationForm configForm = (ConfigurationForm) sService;

    /*
     * This AdvancedConfigurationPanel is an advanced ConfigurationForm so
     * don't try to add it to itself.
     */
    if ((configForm == this) || !configForm.isAdvanced()) return;

    switch (event.getType()) {
      case ServiceEvent.REGISTERED:
        if (logger.isInfoEnabled())
          logger.info("Handling registration of a new Configuration Form.");

        this.addConfigForm(configForm);
        break;

      case ServiceEvent.UNREGISTERING:
        this.removeConfigForm(configForm);
        break;
    }
  }

  /**
   * Adds a new <tt>ConfigurationForm</tt> to this list.
   *
   * @param configForm The <tt>ConfigurationForm</tt> to add.
   */
  public void addConfigForm(ConfigurationForm configForm) {
    if (configForm == null) throw new IllegalArgumentException("configForm");

    DefaultListModel listModel = (DefaultListModel) configList.getModel();

    int i = 0;
    int count = listModel.getSize();
    int configFormIndex = configForm.getIndex();
    for (; i < count; i++) {
      ConfigurationForm form = (ConfigurationForm) listModel.get(i);

      if (configFormIndex < form.getIndex()) break;
    }
    listModel.add(i, configForm);
  }

  /**
   * Implements <code>ApplicationWindow.show</code> method.
   *
   * @param isVisible specifies whether the frame is to be visible or not.
   */
  @Override
  public void setVisible(boolean isVisible) {
    if (isVisible && configList.getSelectedIndex() < 0) {
      this.configList.setSelectedIndex(0);
    }
    super.setVisible(isVisible);
  }

  /**
   * Removes a <tt>ConfigurationForm</tt> from this list.
   *
   * @param configForm The <tt>ConfigurationForm</tt> to remove.
   */
  public void removeConfigForm(ConfigurationForm configForm) {
    DefaultListModel listModel = (DefaultListModel) configList.getModel();

    for (int count = listModel.getSize(), i = count - 1; i >= 0; i--) {
      ConfigurationForm form = (ConfigurationForm) listModel.get(i);

      if (form.equals(configForm)) {
        listModel.remove(i);
        /*
         * TODO We may just consider not allowing duplicates on addition
         * and then break here.
         */
      }
    }
  }

  /** A custom cell renderer that represents a <tt>ConfigurationForm</tt>. */
  private class ConfigListCellRenderer extends DefaultListCellRenderer {
    /** Serial version UID. */
    private static final long serialVersionUID = 0L;

    private boolean isSelected = false;

    private final Color selectedColor =
        new Color(
            AdvancedConfigActivator.getResources().getColor("service.gui.LIST_SELECTION_COLOR"));

    /**
     * Creates an instance of <tt>ConfigListCellRenderer</tt> and specifies that this renderer is
     * transparent.
     */
    public ConfigListCellRenderer() {
      this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      this.setOpaque(false);
    }

    /**
     * Returns the component representing the cell given by parameters.
     *
     * @param list the parent list
     * @param value the value of the cell
     * @param index the index of the cell
     * @param isSelected indicates if the cell is selected
     * @param cellHasFocus indicates if the cell has the focus
     * @return the component representing the cell
     */
    public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
      ConfigurationForm configForm = (ConfigurationForm) value;

      this.isSelected = isSelected;
      this.setText(configForm.getTitle());

      return this;
    }

    /**
     * Paint a background for all groups and a round blue border and background when a cell is
     * selected.
     *
     * @param g the <tt>Graphics</tt> object
     */
    public void paintComponent(Graphics g) {
      Graphics g2 = g.create();
      try {
        internalPaintComponent(g2);
      } finally {
        g2.dispose();
      }
      super.paintComponent(g);
    }

    /**
     * Paint a background for all groups and a round blue border and background when a cell is
     * selected.
     *
     * @param g the <tt>Graphics</tt> object
     */
    private void internalPaintComponent(Graphics g) {
      AntialiasingManager.activateAntialiasing(g);

      Graphics2D g2 = (Graphics2D) g;

      if (isSelected) {
        g2.setColor(selectedColor);
        g2.fillRect(0, 0, this.getWidth(), this.getHeight());
      }
    }
  }

  /**
   * Called when user selects a component in the list of configuration forms.
   *
   * @param e the <tt>ListSelectionEvent</tt>
   */
  public void valueChanged(ListSelectionEvent e) {
    if (!e.getValueIsAdjusting()) {
      ConfigurationForm configForm = (ConfigurationForm) configList.getSelectedValue();

      if (configForm != null) showFormContent(configForm);
    }
  }

  /**
   * Selects the given <tt>ConfigurationForm</tt>.
   *
   * @param configForm the <tt>ConfigurationForm</tt> to select
   */
  public void setSelected(ConfigurationForm configForm) {
    configList.setSelectedValue(configForm, true);
  }

  /**
   * Returns the title of the form.
   *
   * @return the title of the form
   */
  public String getTitle() {
    return AdvancedConfigActivator.getResources().getI18NString("service.gui.ADVANCED");
  }

  /**
   * Returns the icon of the form.
   *
   * @return a byte array containing the icon of the form
   */
  public byte[] getIcon() {
    return AdvancedConfigActivator.getResources()
        .getImageInBytes("plugin.advancedconfig.PLUGIN_ICON");
  }

  /**
   * Returns the form component.
   *
   * @return the form component
   */
  public Object getForm() {
    return this;
  }

  /**
   * Returns the index of the form in its parent container.
   *
   * @return the index of the form in its parent container
   */
  public int getIndex() {
    return 300;
  }

  /**
   * Indicates if the form is an advanced form.
   *
   * @return <tt>true</tt> to indicate that this is an advanced form, otherwise returns
   *     <tt>false</tt>
   */
  public boolean isAdvanced() {
    return false;
  }

  /**
   * Validates the currently selected configuration form. This method is meant to be used by
   * configuration forms the re-validate when a new component has been added or size has changed.
   */
  public void validateCurrentForm() {}
}
public class JungGraphObserver implements Control, HyphaDataListener, HyphaLinkListener {
  private static final String PAR_HYPHADATA_PROTO = "network.node.hyphadata_proto";
  private static final String PAR_HYPHALINK_PROTO = "network.node.hyphalink_proto";
  private static final String PAR_MYCOCAST_PROTO = "network.node.mycocast_proto";
  private static final String PAR_WALK_DELAY = "walk_delay";

  private static Logger log = Logger.getLogger(JungGraphObserver.class.getName());

  private static final String PAR_PERIOD = "period";
  private static int period;
  private static int walkDelay;

  private final String name;
  private final int hyphadataPid;
  private final int hyphalinkPid;
  private final int mycocastPid;

  // private static Lock = new ReentrantLock();

  private static MycoGraph graph = new MycoGraph();
  private static VisualizationViewer<MycoNode, MycoEdge> visualizer;

  private static Set<ChangeListener> changeListeners;

  // private class TypePredicate extends Predicate<{

  // }

  public static void addChangeListener(ChangeListener cl) {
    changeListeners.add(cl);
  }

  public static void removeChangeListener(ChangeListener cl) {
    if (changeListeners.contains(cl)) {
      changeListeners.remove(cl);
    }
  }

  private static Thread mainThread;
  public static boolean stepBlocked = false;
  public static boolean noBlock = true;
  public static boolean walking = false;

  public JungGraphObserver(String name) {
    this.name = name;
    this.hyphadataPid = Configuration.getPid(PAR_HYPHADATA_PROTO);
    this.hyphalinkPid = Configuration.getPid(PAR_HYPHALINK_PROTO);
    this.mycocastPid = Configuration.getPid(PAR_MYCOCAST_PROTO);
    this.period = Configuration.getInt(name + "." + PAR_PERIOD);

    this.walkDelay = Configuration.getInt(name + "." + PAR_WALK_DELAY);
    mainThread = Thread.currentThread();
    this.changeListeners = new HashSet<ChangeListener>();

    visualizer = null;

    // HyphaData.addHyphaDataListener(this);
    // HyphaLink.addHyphaLinkListener(this);
  }

  public static void setVisualizer(VisualizationViewer<MycoNode, MycoEdge> visualizer) {
    JungGraphObserver.visualizer = visualizer;
    addChangeListener(visualizer);
  }

  public static MycoGraph getGraph() {
    return graph;
  }

  public void nodeStateChanged(MycoNode n, HyphaType t, HyphaType oldState) {
    if (t != HyphaType.DEAD) {
      if (!graph.containsVertex(n)) {
        graph.addVertex(n);
      }
    } else {
      if (graph.containsVertex(n)) {
        graph.removeVertex(n);
      }
    }
  }

  public void linkAdded(MycoNode a, MycoNode b) {
    if (graph.findEdge(a, b) == null) {
      MycoEdge edge = new MycoEdge();
      graph.addEdge(edge, a, b, EdgeType.DIRECTED);
    }
  }

  public void linkRemoved(MycoNode a, MycoNode b) {
    MycoEdge edge = graph.findEdge(a, b);
    while (edge != null) {
      graph.removeEdge(edge);
      edge = graph.findEdge(a, b);
    }
  }

  public boolean execute() {
    if (CDState.getCycle() % period != 0) return false;

    MycoCast mycocast = (MycoCast) Network.get(0).getProtocol(mycocastPid);

    int bio = mycocast.countBiomass();
    int ext = mycocast.countExtending();
    int bra = mycocast.countBranching();
    int imm = mycocast.countImmobile();

    // Update vertices
    Set<MycoNode> activeNodes = new HashSet<MycoNode>();
    for (int i = 0; i < Network.size(); i++) {
      MycoNode n = (MycoNode) Network.get(i);
      activeNodes.add(n);
      HyphaData data = n.getHyphaData();
      // if (data.isBiomass()) { continue; }
      if (graph.containsVertex(n)) {
        graph.removeVertex(n);
      }
      if (!graph.containsVertex(n)) {
        graph.addVertex(n);
      }
    }
    Set<MycoNode> jungNodes = new HashSet<MycoNode>(graph.getVertices());
    jungNodes.removeAll(activeNodes);

    for (MycoNode n : jungNodes) {
      graph.removeVertex(n);
    }

    // Update edges
    for (int i = 0; i < Network.size(); i++) {
      MycoNode n = (MycoNode) Network.get(i);
      HyphaData data = n.getHyphaData();
      HyphaLink link = n.getHyphaLink();

      synchronized (graph) {

        // We now add in all links and tune out display in Visualizer
        java.util.List<MycoNode> neighbors = (java.util.List<MycoNode>) link.getNeighbors();

        //// Adding only links to hypha thins out links to biomass
        //    (java.util.List<MycoNode>) link.getHyphae();

        Collection<MycoNode> jungNeighbors = graph.getNeighbors(n);

        // Remove edges from Jung graph that are not in peersim graph
        for (MycoNode o : jungNeighbors) {
          if (!neighbors.contains(o)) {
            MycoEdge edge = graph.findEdge(n, o);
            while (edge != null) {
              graph.removeEdge(edge);
              edge = graph.findEdge(n, o);
            }
          }
        }

        // Add missing edges to Jung graph that are in peersim graph
        for (MycoNode o : neighbors) {
          if (graph.findEdge(n, o) == null) {
            MycoEdge edge = new MycoEdge();
            graph.addEdge(edge, n, o, EdgeType.DIRECTED);
          }
        }
      }

      // log.finest("VERTICES: " + graph.getVertices());
      // log.finest("EDGES: " + graph.getEdges());
    }

    for (ChangeListener cl : changeListeners) {
      cl.stateChanged(new ChangeEvent(graph));
    }
    if (walking) {
      try {
        Thread.sleep(walkDelay);
      } catch (InterruptedException e) {
      }
      stepBlocked = false;
    }

    try {
      while (stepBlocked && !noBlock) {
        synchronized (JungGraphObserver.class) {
          JungGraphObserver.class.wait();
        }
      }
    } catch (InterruptedException e) {
      stepBlocked = true;
    }
    stepBlocked = true;
    // System.out.println(graph.toString());
    return false;
  }

  public static synchronized void stepAction() {
    walking = false;
    stepBlocked = false;
    noBlock = false;
    JungGraphObserver.class.notifyAll();
  }

  public static synchronized void walkAction() {
    walking = true;
    stepBlocked = false;
    noBlock = false;
    JungGraphObserver.class.notifyAll();
  }

  public static synchronized void pauseAction() {
    walking = false;
    stepBlocked = true;
    noBlock = false;
  }

  public static synchronized void runAction() {
    walking = false;
    stepBlocked = false;
    noBlock = true;
    JungGraphObserver.class.notifyAll();
  }
}